 |
Wolf Planet We want you here!
|
| View previous topic :: View next topic |
| Author |
Message |
Deathshead Corporal

Joined: 18 Feb 2005 Posts: 87
|
Posted: Sun Mar 06, 2005 11:50 pm Post subject: [Tutorial]Adding a new Weapon- Spraying Shotgun |
|
|
Welcome to yet another of my tutorials. In this one, I present a new weapon- the shotgun. Along with being a usable weapon, it also possessess another special feature, but I'll explain it further down the tutorial. I will also detail adding a new ammotype for the weapon.
Credit for each part of the tutorial go to the following people: Deathshead, BrotherTank, Chris Chokan. This tutorial incorperates code from 'Working with Weapons', and is shown with the thought you are using a fresh copy of the source.
On with the Tutorial. Make backups of WL_DEF.H, WL_AGENT.C and WL_DRAW.C .
Open WL_DEF.H and add the following sprite constants:
| Code: |
//
// Shotgun Sprites
//
SPR_SHOTGUN,SPR_SHELLS,
SPR_SGUNREADY,SPR_SGUNATK1,SPR_SGUNATK2,SPR_SGUNATK3,
SPR_SGUNATK4,
|
Now search for bo_chaingun:
| Code: |
bo_machinegun,
bo_chaingun,
bo_food,
bo_fullheal,
bo_25clip,
|
Add the following two lines underneath that:
| Code: |
bo_shotgun, //define shotgun pickup
bo_shells, //define shotgun ammo pickup
|
search for 'NUMBUTTONS'. You will find:
| Code: |
#define NUMBUTTONS 8
enum {
bt_nobutton=-1,
bt_attack=0,
bt_strafe,
bt_run,
bt_use,
bt_readyknife,
bt_readypistol,
bt_readymachinegun,
bt_readychaingun
};
|
Change that to read:
| Code: |
#define NUMBUTTONS 9
enum {
bt_nobutton=-1,
bt_attack=0,
bt_strafe,
bt_run,
bt_use,
bt_readyknife,
bt_readypistol,
bt_readymachinegun,
bt_readychaingun,
bt_readyshotgun
};
|
This is added, so as to tell the engine what button is to be pressed (1-9) for each weapon.
Swapping the weapons (bt_ready***) should change the order weapons are accessed.
| Code: |
#define NUMWEAPONS 4
typedef enum {
wp_knife,
wp_pistol,
wp_machinegun,
wp_chaingun
} weapontype;
|
Change that to read:
| Code: |
#define NUMWEAPONS 5 //there are five weapons
typedef enum {
wp_knife,
wp_pistol,
wp_machinegun,
wp_chaingun,
wp_shotgun //added weapon define
} weapontype;
|
Go to the gamestate structure and delete the ammo variable (int ammo;). Now, underneath the structure, add:
| Code: |
//------------
// Ammo Structure
//------------
typedef struct
{
char ammo1; //original ammo
char ammo2; //new ammo for shotgun
//char ammo3; //extra ammo in case you want it
//char ammo4; //extra ammo in case you want it
} ammo_t;
|
Finally, go down to the WL_GAME DEFINITIONS, and locate this line:
| Code: |
extern gametype gamestate;
|
Add the following underneath it:
| Code: |
extern ammo_t ammotype;
|
What this ammotype code does, is make it easier to define ammo. Now, go through each WL_***.C file and change gamestate.ammo into ammotype.ammo1 .
With that done, Open up WL_DRAW.C and locate the following section of code:
| Code: |
int weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY,SPR_PISTOLREADY
,SPR_MACHINEGUNREADY,SPR_CHAINREADY};
|
Change it to read:
| Code: |
int weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY,SPR_PISTOLREADY
,SPR_MACHINEGUNREADY,SPR_CHAINREADY,SPR_SGUNREADY};
|
Here we see the addition of the SPR_SGUNREADY sprite. Now you can close that file. Open up WL_AGENT.C . This is where the main code will go. Search for this block:
| Code: |
struct atkinf
{
char tics,attack,frame; // attack is 1 for gun, 2 for knife
} attackinfo[4][14] =
{
{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} }, //knife
{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} }, //pistol
{ {6,0,1},{6,1,2},{6,3,3},{6,-1,4} }, //machinegun
{ {6,0,1},{6,1,2},{6,4,3},{6,-1,4} }, //chaingun
};
|
Change it to read the following:
| Code: |
struct atkinf
{
char tics,attack,frame; // attack is 1 for gun, 2 for knife
} attackinfo[NUMWEAPONS][14] = //NUMWEAPONS is number of weapons, 14 is maximum frames for each weapon.
{
{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} }, //knife
{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} }, //pistol
{ {6,0,1},{6,1,2},{6,3,3},{6,-1,4} }, //machinegun
{ {6,0,1},{6,1,2},{6,4,3},{6,-1,4} }, //chaingun
{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} }, //shotgun
};
|
Here, we have added some of the most important weapon information. To explain what this above code does, here's an explanation by BrotherTank:
| Quote: |
We have 5 weapon frames sprites for each weapon. In wl_draw.c it assumes that if you aren't firing to use the first weapon sprite, so this array holds the information telling it which weapon firing sprite to use, how long to display it, and what to make the program do while displaying that frame. We have 4 groups (1 for each firing sprite for each weapon) of 3 numbers or group.
So breaking this down we see that the first number in each group of 3 variables ("6" as set in each) refers to the number of tics in 70th's of a second that the graphic should be drawn. Each tic in the game is 1/70th of a second. The second number in each group of 3 variables refers to the value sent to the "T_Attack" routine (discussed below). And the last of the numbers in each group of 3 variables tells the wl_draw.c file which weapon firing frame to draw during the shooting process.
Numbers passed to the "T_Attack" routine via the second number in each group of 3 variables are as follows:
0 = Do Nothing - Player is waiting
1 = Shoot Single Shot
2 = Attack with knife - Call "KnifeAttack" routine
3 = Shoot Single Shot then go back two frames
4 = Shoot Multiple Shots - Rapid Fire
-1 = Stop firing - return to basic resting/holding weapon position
|
Now, I have changed [4] to [NUMWEAPONS]. Why? Because 4 is the number of weapons in WL_DEF.H, determined by the line '#define NUMWEAPONS'. So, to save time when adding more weapons in future, we make it automatically keep track of the amount of weapons.
Now for the CheckWeaponChange Routine. Here, we tell the game to see what button is pressed, then react accordingly:
| Code: |
/*
======================
=
= CheckWeaponChange
=
= Keys 1-4 change weapons
=
======================
*/
void CheckWeaponChange (void)
{
int i,buttons;
if (!gamestate.ammo) // must use knife with no ammo
return;
for (i=wp_knife ; i<=gamestate.bestweapon ; i++)
if (buttonstate[bt_readyknife+i-wp_knife])
{
gamestate.weapon = gamestate.chosenweapon = i;
DrawWeapon ();
return;
}
}
|
This is the original CheckWeaponChange Routine. Now we replace it with BrotherTank's, slightly modified:
| Code: |
/*==
==== CheckWeaponChange
==== Editted by BrotherTank/Deathshead
====
==== Number Keys 1-0 select Weapon.
==*/
void CheckWeaponChange (void)
{
int i,kbuttons[10]={sc_1,sc_2,sc_3,sc_4,sc_5,sc_6,sc_7,sc_8,sc_9,sc_0}; //ten weapon buttons
for (i=0;i<NUMWEAPONS;i++)
if ((Keyboard[kbuttons[i]]) && (i != gamestate.weapon))
{
if (buttonstate[bt_readyknife+i-wp_knife])
{
gamestate.weapon = gamestate.chosenweapon = i;
DrawWeapon ();
DrawAmmo ();
return;
}
}
}
|
Now, change the DrawWeapon Routine to read:
| Code: |
/*==
==== DrawWeapon
==== By Deathshead/BrotherTank
==*/
void DrawWeapon (void)
{
switch (gamestate.weapon)
{
case wp_knife:
StatusDrawPic (32,8,KNIFEPIC); //statusbar pic for knife
break;
case wp_pistol:
StatusDrawPic (32,8,GUNPIC); //statusbar pic for pistol
break;
case wp_machinegun:
StatusDrawPic (32,8,MACHINEGUNPIC); //statusbar pic for machinegun
break;
case wp_chaingun:
StatusDrawPic (32,8,GATLINGGUNPIC); //statusbar pic for chaingun
break;
case wp_shotgun:
StatusDrawPic (32,8,KNIFEPIC); //change this to what you want...
break;
}
}
|
Now, for this, we need to change the GiveWeapon routine to:
| Code: |
/*==
==== GiveWeapon
==== Editted by BrotherTank/Deathshead
====
==== Gives Player a weapon, with 6 ammo for that weapon.
==*/
void GiveWeapon (int weapon)
{
switch (weapon)
{
case wp_pistol:
case wp_machinegun:
case wp_chaingun:
GiveAmmo (wp_pistol,6); //give 6 pistol ammo
break;
case wp_shotgun:
GiveAmmo (wp_shotgun,6); //give 6 shotgun shells
}
if (gamestate.bestweapon<weapon)
gamestate.bestweapon = gamestate.weapon = gamestate.chosenweapon = weapon;
DrawWeapon ();
DrawAmmo ();
}
|
Now, you may notice the extra stuff inside GiveAmmo. Well, it will all be made clear in a few moments. Now, the DrawAmmo can be changed to read:
| Code: |
/*==
==== DrawAmmo
==== Editted by Deathshead
====
==== This is another variation of the original DrawAmmo
==== routine. For each weapon, the ammo variable becomes
==== the amount of ammo for the weapon. It then displays
==== the ammo onn te statusbar
==*/
void DrawAmmo (void)
{
char ammo;
switch (gamestate.weapon)
{
case wp_knife:
break; //display no ammo for knife
case wp_pistol:
case wp_machinegun:
case wp_chaingun:
ammo = ammotype.ammo1; //ammo becomes pistol ammo
break;
case wp_shotgun:
ammo = ammotype.ammo2; //ammo becomes shells
break;
}
LatchNumber (27,16,3,ammo); //display whatever ammo equals
}
|
Now, the GiveAmmo Routine. This is a modified version of the Working with Weapons routine, which allows all ammotypes to work inside it, so you don't need to create a new function for each ammo. Replace the current GiveAmmo with:
| Code: |
/*==
==== GiveAmmo
==== Editted by BrotherTank/Deathshead
====
==== This variation of GiveAmmo, will give
==== the player ammo for a weapon
==*/
void GiveAmmo (int weapon,char ammo)
{
if (!ammotype.ammo1 && !ammotype.ammo2 && !ammotype.ammo3) // knife was out
{
if (!gamestate.attackframe)
{
gamestate.weapon = gamestate.chosenweapon;
DrawWeapon ();
}
}
switch (weapon)
{
case wp_pistol:
case wp_machinegun:
case wp_chaingun:
ammotype.ammo1 += ammo;
if (ammotype.ammo1 > 99) ammotype.ammo1 = 99;
break;
case wp_shotgun:
ammotype.ammo2 += ammo;
if (ammotype.ammo2 > 50) ammotype.ammo2 = 50;
break;
}
DrawAmmo ();
}
|
Now, when calling GiveAmmo, you have to call GiveAmmo(weapon,ammo); . With this code, to give ammo to the pistol, machinegun and chaingun, you only need to write GiveAmmo (wp_pistol,ammo); . To exercise this, scroll down the GetBonus function till you find:
| Code: |
case bo_clip:
if (ammotype.ammo1 == 99)
return;
SD_PlaySound (GETAMMOSND);
GiveAmmo (8);
break;
|
This is changed to:
| Code: |
case bo_clip:
if (ammotype.ammo1 == 99)
return;
SD_PlaySound (GETAMMOSND);
GiveAmmo (wp_pistol,8);
break;
|
This is also to be done to bo_clip2, and bo_25clip if your spear user. Now, underneath the case for bo_clip2, add:
| Code: |
case bo_shells:
if (ammotype.ammo2 == 50)
return;
SD_PlaySound (GETAMMOSND);
GiveAmmo (wp_shotgun,5);
break;
case bo_shotgun:
GiveWeapon (wp_shotgun);
SD_PlaySound (GETMACHINESND);
break;
|
Now, go down to the GunAttack Function. Replace it with the following:
| Code: |
/*==
==== GunAttack
==== By Chris Chokan/Deathshead
==*/
void GunAttack (objtype *ob)
{
objtype *check,*closest,*oldclosest;
int damage;
int dx,dy,dist;
int count=0, ratio=1;
long viewdist;
switch (gamestate.weapon)
{
case wp_pistol:
SD_PlaySound (ATKPISTOLSND);
break;
case wp_machinegun:
SD_PlaySound (ATKMACHINEGUNSND);
break;
case wp_chaingun:
SD_PlaySound (ATKGATLINGSND);
break;
case wp_voodoogun:
SD_PlaySound (ATKVOODOOSND);
ratio=10;
break;
case wp_shotgun:
SD_PlaySound (ATKSKULLSND);
ratio=4;
break;
}
madenoise = true;
//
// find potential targets
//
TOP:
viewdist = 0x7fffffffl;
closest = NULL;
DrawScore();
while (1)
{
oldclosest = closest;
for (check=ob->next ; check ; check=check->next)
if ( (check->flags & FL_SHOOTABLE)
&& (check->flags & FL_VISABLE)
&& abs (check->viewx-centerx) < shootdelta*ratio
)
{
if (check->transx < viewdist)
{
viewdist = check->transx;
closest = check;
}
}
if (closest == oldclosest)
return; // no more targets, all missed
//
// trace a line from player to enemey
//
if (CheckLine(closest))
break;
}
//
// hit something
//
dx = abs(closest->tilex - player->tilex);
dy = abs(closest->tiley - player->tiley);
dist = dx>dy ? dx:dy;
if (dist<2)
damage = US_RndT() / 4;
else if (dist<4)
damage = US_RndT() / 6;
else
{
if ( (US_RndT() / 12) < dist) // missed
return;
damage = US_RndT() / 6;
}
if ((gamestate.weapon == wp_shotgun) && count < 3)
{
DamageActor (closest,damage);
count++;
goto TOP;
}
else
DamageActor (closest, damage); // Original code
}
|
Now go down to T_Attack function and look for:
| Code: |
GunAttack (ob);
ammotype.ammo1--;
DrawAmmo ();
break;
|
Change that to:
| Code: |
GunAttack (ob);
switch (gamestate.weapon)
{
case wp_pistol:
case wp_machinegun:
case wp_chaingun:
ammotype.ammo1--; //if weapon=pistol,machinegun,or chaingun, take ammo1 when shooting
break;
case wp_shotgun:
ammotype.ammo2--; //if weapon=shotgun, take ammo2 when shooting
break;
}
DrawAmmo ();
break;
|
Now, last of all (phew!), Go to WL_ACT1.C and add the following lines underneath '{SPR_STAT_26,bo_clip2},':
| Code: |
{SPR_SHOTGUN,bo_shotgun},
{SPR_SHELLS,bo_shells},
|
That concludes the code. Open up an editor, and add the sprites in the following order (after the chaingun sprites):
Shotgun Pickup
Shells
Shotgun Weapon Sprites (for holding and attacking)
Then, in the OBJDATA.WL6 of MapEdit, add these two lines:
| Code: |
0048 36aa Shotgun
0049 86ab Shells
|
This concludes my very long tutorial on adding the Spraying Shotgun. Please post your opinions on this.
Edit: Adding more comments, changed a few mistakes. If using this, please start again.
There you go
-Deathshead _________________ Myspace
VampireFreaks
Music4Life
Wolfing Time
Last edited by Deathshead on Tue Mar 08, 2005 10:09 am; edited 1 time in total |
|
| Back to top |
|
 |
JackaL Soldier

Joined: 17 Jan 2005 Posts: 69 Location: New Zealand
|
Posted: Mon Mar 07, 2005 4:38 am Post subject: |
|
|
I cant wait to try this feature! _________________ Amohs Awamuras...Self Titled "EoD Clone" |
|
| Back to top |
|
 |
Andy3012
Joined: 05 Mar 2005 Posts: 4
|
Posted: Sat Mar 12, 2005 8:02 pm Post subject: |
|
|
i tried this tutorial but not too a fresh and one, and their was lots of errors, and warnings, in parts that i hadn't edited, but their was some to bits that i had edited, so yeh, just though i should point that out, when i compiled wl_main.c
it said that ammotype.ammo1 = START AMMO was useless or unless i was supposed to get rid of start ammo |
|
| Back to top |
|
 |
Deathshead Corporal

Joined: 18 Feb 2005 Posts: 87
|
Posted: Tue Mar 15, 2005 9:55 am Post subject: |
|
|
OK, the errors happen, I know. I did something in the Spear of Dreams source to kill this, but haven't done this in my source. Warnings don't matter, they don't wreck the game, or stop it from compiling.
Show me your NewGame routine please, then maybe I could help with that. _________________ Myspace
VampireFreaks
Music4Life
Wolfing Time |
|
| Back to top |
|
 |
Andy3012
Joined: 05 Mar 2005 Posts: 4
|
Posted: Tue Mar 15, 2005 8:12 pm Post subject: |
|
|
| i've already deleted it from my source, as their are other more important things i need to be working right now. If theirs time left over i will add a few fancy things like this gun. |
|
| Back to top |
|
 |
lizardcommando Soldier

Joined: 31 May 2005 Posts: 48
|
Posted: Sun Jun 05, 2005 12:25 am Post subject: |
|
|
Um, I tried out this tutorial, fixing stuff that would fit to my needs (I didn't add in the ammo types), and I'm still having problems with the source. I can see one of the attack frames inside the game! IE, instead of the pickup sprite, it's the gun animation as the pickup object! But I can actually pick up and use the gun! Unfortunately, when I switch to another gun, I can't switch back to the rifle. Another problem I'm having is that I automatically start with all the guns minus the rifle. I only want to start off with the knife and pistol.
Um, but I do have some other questions:
For the first part where mess around with the SPR_'s in WL_DEF.H (Let's use SPR_RIFLE for an example) do they have to be in the exact order? As in, do I have to add in the pick up sprites first and then the firing animation? Because this other tutorial I followed said for me to add in the firing animation first and then the pickup sprite? I had posted the link to that tutorial in my Need Help thread.
EDIT: Ok, I just changed a few things around in GFXE_WL6. I changed the LATCHPICS_NUM_END and the NUMPICS values.
I was following that one tutorial on making new guns from DieHard Wolfers to see how you add a custom status bar picture for the gun. Ok, after messing around with the GFXE_WL6, I compiled it and tested it, but all it does now is freeze at that loading screen. Goddammit, I'm having s****y luck with this.
EDIT2: Ok, I guess following that tutorial from DHW was a very bad idea. Changing the LATCHPICS_NUM_END was what was actually messing up the game! Now, All I have to do is fix the problem with the status bar rifle pic showing up as the pickup object rather than the sprite I made and being able to switch between the guns. |
|
| Back to top |
|
 |
Deathshead Corporal

Joined: 18 Feb 2005 Posts: 87
|
|
| Back to top |
|
 |
lizardcommando Soldier

Joined: 31 May 2005 Posts: 48
|
Posted: Tue Jun 07, 2005 8:23 pm Post subject: |
|
|
| Thanks. I just fixed the problem. |
|
| Back to top |
|
 |
WLHack Newbie
Joined: 12 Jul 2005 Posts: 14
|
Posted: Fri Aug 05, 2005 1:59 pm Post subject: Re: Adding new weapon - spraying shotgun |
|
|
| Can anyone tell how can I get rid of "Extra parameter in call to GiveAmmo" error? |
|
| Back to top |
|
 |
WLHack Newbie
Joined: 12 Jul 2005 Posts: 14
|
Posted: Fri Aug 05, 2005 2:50 pm Post subject: |
|
|
Forget my last message. I found the source of the error
and succesfully removed it. |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|