Wolf Planet Forum Index Wolf Planet
We want you here!
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

[Tutorial]Adding a new Weapon- Spraying Shotgun

 
Post new topic   Reply to topic    Wolf Planet Forum Index -> Coding Alliance
View previous topic :: View next topic  
Author Message
Deathshead
Corporal


Joined: 18 Feb 2005
Posts: 87

PostPosted: Sun Mar 06, 2005 11:50 pm    Post subject: [Tutorial]Adding a new Weapon- Spraying Shotgun Reply with quote

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
View user's profile Send private message Visit poster's website MSN Messenger
JackaL
Soldier


Joined: 17 Jan 2005
Posts: 69
Location: New Zealand

PostPosted: Mon Mar 07, 2005 4:38 am    Post subject: Reply with quote

I cant wait to try this feature!
_________________
Amohs Awamuras...Self Titled "EoD Clone"
Back to top
View user's profile Send private message Send e-mail Visit poster's website MSN Messenger
Andy3012



Joined: 05 Mar 2005
Posts: 4

PostPosted: Sat Mar 12, 2005 8:02 pm    Post subject: Reply with quote

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
View user's profile Send private message
Deathshead
Corporal


Joined: 18 Feb 2005
Posts: 87

PostPosted: Tue Mar 15, 2005 9:55 am    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website MSN Messenger
Andy3012



Joined: 05 Mar 2005
Posts: 4

PostPosted: Tue Mar 15, 2005 8:12 pm    Post subject: Reply with quote

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
View user's profile Send private message
lizardcommando
Soldier


Joined: 31 May 2005
Posts: 48

PostPosted: Sun Jun 05, 2005 12:25 am    Post subject: Reply with quote

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
View user's profile Send private message
Deathshead
Corporal


Joined: 18 Feb 2005
Posts: 87

PostPosted: Tue Jun 07, 2005 9:55 am    Post subject: Reply with quote

With the attack sprite problem, you obviously have them in the wrong order in your VSWAP.
_________________
Myspace
VampireFreaks
Music4Life
Wolfing Time
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
lizardcommando
Soldier


Joined: 31 May 2005
Posts: 48

PostPosted: Tue Jun 07, 2005 8:23 pm    Post subject: Reply with quote

Thanks. I just fixed the problem.
Back to top
View user's profile Send private message
WLHack
Newbie


Joined: 12 Jul 2005
Posts: 14

PostPosted: Fri Aug 05, 2005 1:59 pm    Post subject: Re: Adding new weapon - spraying shotgun Reply with quote

Can anyone tell how can I get rid of "Extra parameter in call to GiveAmmo" error?
Back to top
View user's profile Send private message
WLHack
Newbie


Joined: 12 Jul 2005
Posts: 14

PostPosted: Fri Aug 05, 2005 2:50 pm    Post subject: Reply with quote

Forget my last message. I found the source of the error
and succesfully removed it.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Wolf Planet Forum Index -> Coding Alliance All times are GMT
Page 1 of 1

Jump to:  

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


Powered by phpBB © 2001 phpBB Group

Chronicles phpBB2 theme by Jakob Persson (http://www.eddingschronicles.com). Stone textures by Patty Herford.