Quake DeveLS - Decoy 2

Author: John Rittenhouse
Difficulty: Medium

Let's Do It...

The original decoy tutorial posted on QDeveLS is written so as you might as well write a new monster so here is a easier one that does it in a different way. Remember +'s are lines to add in!

Go to the bottom of the edict_t defination and add the code below needed at the bottom.

        gitem_t         *item;                  // for bonus items

        // common data blocks
        moveinfo_t              moveinfo;
        monsterinfo_t   monsterinfo;    
        
        +edict_t *decoy; //JR  Decoy Edict
What we have just done is create the decoy's edict so we can have decoy. Now lets work on the commands for activating him and other stuff. Add a new file to your project called "decoy.c". And add this code into it at the top of the new file.
        +#include "g_local.h"
        +#include "m_player.h"
        +#define newDecoy self->decoy
        +int i;
        +int huh;
        +void SP_Decoy (edict_t *self);
        +void func_explosive_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
What we have done is declare the declarations for this file not too hard. Now we will add the spawning code, which is the most important part. We are going to do something not too hard here now,
        +void SP_Decoy (edict_t *self)
+{
+       if ( newDecoy ) 
+       {  
        +               G_FreeEdict(newDecoy);    
+               newDecoy = NULL;
+               gi.centerprintf (self,"Holo decoy off!\n");
        +
        +               return; 
+       }
        +       gi.bprintf (PRINT_HIGH, "Holo Decoy on.\n");
+       newDecoy = G_Spawn ();
+       VectorCopy(self->s.origin,newDecoy->s.origin);
        +       newDecoy->classname="decoy";
+       newDecoy->takedamage=DAMAGE_AIM;
        +       newDecoy->movetype= MOVETYPE_TOSS;
+       newDecoy->mass = 200;
        +       newDecoy->solid = SOLID_BBOX;
+       newDecoy->deadflag =DEAD_NO;
        +       newDecoy->clipmask = MASK_PLAYERSOLID;
+       newDecoy->model = self->model;
        +       newDecoy->s.modelindex = self->s.modelindex;
+       newDecoy->s.modelindex2 = self->s.modelindex2;
+       newDecoy->s.frame =0;
        +       newDecoy->s.renderfx |= RF_TRANSLUCENT;
+       newDecoy->waterlevel = 0;
+       newDecoy->watertype=0;
+       newDecoy->health= 20;
        +       newDecoy->max_health =20;
+       newDecoy->gib_health = -80;
        +       newDecoy->pain= decoy_pain;
+       newDecoy->think = Decoy_Think;
        +       newDecoy->nextthink =level.time + .1;
+       newDecoy->delay = level.time + 300;
+       newDecoy->die = decoy_die;
        +       newDecoy->owner = self;
+       newDecoy->dmg = 100;
        +       newDecoy->dmg_radius = 100;
        +       
+       VectorSet (newDecoy->mins, -16, -16, -24);
        +       VectorSet (newDecoy->maxs, 16, 16, 32);
+       VectorClear (newDecoy->velocity);
+       gi.linkentity (newDecoy);
+       gi.centerprintf (self,"New decoy set!\n");
+}
This code here starts the new decoy. THe next is the rest of the code its fairly simple also
        +void decoyAI_RunFrames(edict_t *self, int start, int end)
        +{
        +       if(self->s.frame s.frame++;
        +       }
        +       else
        +       {
        +               self->s.frame = start;
        +       }
        +}
        +void decoy_pain (edict_t *self, edict_t *other, float kick, int damage)
        +{
        +       decoyAI_RunFrames(self, FRAME_pain101, FRAME_pain104);
        +}
        +

        +void decoy_explode (edict_t *ent)
        +{
        +       
        +       vec3_t          origin;
        +
        +       
        +
        +       //FIXME: if we are onground then raise our Z just a bit since we are a point?
        +       T_RadiusDamage(ent, ent->owner, ent->dmg, NULL, ent->dmg_radius,0);
        +       VectorMA (ent->s.origin, -.02, ent->velocity, origin);
        +       gi.WriteByte (svc_temp_entity); 
        +       if (ent->waterlevel)
        +       {       
        +               if (ent->groundentity)
        +                       gi.WriteByte (TE_GRENADE_EXPLOSION_WATER);
        +               else
        +                       gi.WriteByte (TE_ROCKET_EXPLOSION_WATER);
        +       }
        +       else
        +       {       
        +               if (ent->groundentity)
        +                       gi.WriteByte (TE_GRENADE_EXPLOSION);
        +               else
        +                       gi.WriteByte (TE_ROCKET_EXPLOSION);
        +       }
        +       gi.WritePosition (ent->s.origin);
        +       gi.multicast (ent->s.origin, MULTICAST_PVS);
        +
        +       
        +}      
        +void Decoy_Think (edict_t *ent)
        +{
        +               edict_t *blip = NULL;
        +
        +               if (level.time >ent->delay)
        +               {
        +                       decoy_explode(ent);
        +                       return;
        +               }
        +               ent->think = Decoy_Think;
        +               while ((blip = findradius (blip, ent->s.origin, 100)) != NULL)
        +               {       
        +
        +                       if (!(blip->svflags & SVF_MONSTER) && !blip->client)
        +                               continue;
        +                       if (blip == ent->owner)
        +                               continue;
        +                       if (blip->health <= 0)
        +                               continue;
        +                       if (!visible(ent, blip))
        +                               continue;
        +                       ent->think = decoy_explode;
        +                       break;
        +               }
        +       switch (i)
        +       {
        +       case 0:
        +               decoyAI_RunFrames(ent,FRAME_flip01-1,FRAME_flip12);
        +               break;
        +       case 1:
        +               decoyAI_RunFrames(ent,FRAME_salute01-1,FRAME_salute11);
        +               break;
        +       case 2:
        +               decoyAI_RunFrames(ent, FRAME_taunt01-1, FRAME_taunt17);
        +               break;
        +
        +case 3:
        +               decoyAI_RunFrames(ent,FRAME_wave01-1,FRAME_wave11);
        +               break;
        +       case 4:
        +       default:
        +               decoyAI_RunFrames(ent,FRAME_point01-1,FRAME_point12);
        +               break;
        +       }
        +       if (huh == 20)
        +       {
        +               i = random()*5;
        +               huh = 0;
        +       }
        +       huh = huh + 1;
        +
        +               ent->nextthink = level.time + .1;
        +}
This is all the code for frames and stuff. Now for the death function. Its an another simple thing.
        +void decoy_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
        +{
        +       int i;
        +       gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
        +       for(i=0; i<4; i++)
        +                       ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
        +
        +       self->takedamage = DAMAGE_NO;
        +       
        +       gi.WriteByte (svc_temp_entity); 
        +       gi.WriteByte (TE_BFG_EXPLOSION);
        +       gi.WritePosition (self->s.origin);
        +       gi.multicast (self->s.origin, MULTICAST_PVS);
        +       
        +       SP_Decoy (self->owner);
        +       G_FreeEdict(self);
        +}
Alright now so you can turn it on and off. put this code into the command part of cmd_c.
else if (Q_stricmp (cmd, "weapprev") == 0)
                Cmd_WeapPrev_f (ent);
        else if (Q_stricmp (cmd, "weapnext") == 0)
                Cmd_WeapNext_f (ent);
        else if (Q_stricmp (cmd, "weaplast") == 0)
                Cmd_WeapLast_f (ent);
        +else if (Q_stricmp(cmd, "decoy") == 0 )
        +       SP_Decoy (ent);
Put at the top of the file this code.
        +void SP_Decoy(edict_t *self);
That wasn't too hard now was it. I used this code for my mod Star Troopers at http//www.captured.com/startc/

John Rittenhouse .

This site, and all content and graphics displayed on it,
are ©opyrighted to the Quake DeveLS team. All rights received.
Got a suggestion? Comment? Question? Hate mail? Send it to us!
Oh yeah, this site is best viewed in 16 Bit or higher, with the resolution on 800*600.
Thanks to Planet Quake for their great help and support with hosting.
Best viewed with Netscape 4