#include "g_local.h" #include "m_player.h" #include "bot_procs.h" #define newTurret self->turret1 #define newTurret2 self->turret1->turret2 #define Level1Idle 0 #define Level1StartFirst 1 #define Level1StartEnd 2 #define Level1AttackFirst 3 #define Level1AttackEnd 6 #define Level23Idle 0 #define Level23AttackFirst 1 #define Level23AttackEnd 2 #define StatusIdle 0 #define StatusStart 1 #define StatusAttack 2 #define DIRECTION_LEFT 1 #define DIRECTION_CENTER 2 #define DIRECTION_RIGHT 3 #define LEVEL1_DAMAGE 6 #define LEVEL2_DAMAGE 8 #define LEVEL3_DAMAGE 12 #define max(a,b) (((a) > (b)) ? (a) : (b)) void BecomeExplosion1 (edict_t *self); void SP_Turret (edict_t *self); //void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread); void TurretFire1(edict_t *self); void turret_self_remove(edict_t *ent); void turret_remove(edict_t *ent); void SentryReload(edict_t *ent, pmenu_t *p); void SentryUpgrade(edict_t *ent, pmenu_t *p); void SentryRepair(edict_t *ent, pmenu_t *p); int PlayerChangeScore(edict_t *self, int points); //Add or subtract ammo from sentry gun void UpdateSentryAmmo(edict_t *ent, int change_amt) { ent->light_level += change_amt; if (ent->light_level == 25) { safe_cprintf(ent->creator, PRINT_HIGH, "Warning: Your sentry gun is low on ammo.\n"); } } void turret_fire_rocket (edict_t *ent, int direction) { vec3_t forward, right, start, target, dir; if(ent->light_level<1) return; UpdateSentryAmmo(ent, -1); AngleVectors (ent->s.angles, forward, right, NULL); if (direction == DIRECTION_LEFT) { start[0] = ent->s.origin[0] + forward[0] * 3 + right[0] * -0.5; start[1] = ent->s.origin[1] + forward[1] * 3 + right[1] * -0.5; start[2] = ent->s.origin[2] + forward[2] * 3 + right[2] * -0.5 +4; } else if (direction == DIRECTION_CENTER) { start[0] = ent->s.origin[0] + forward[0] * 3 ; start[1] = ent->s.origin[1] + forward[1] * 3 ; start[2] = ent->s.origin[2] + forward[2] * 3+4; } else // Right { start[0] = ent->s.origin[0] + forward[0] * 3 + right[0] * 0.5; start[1] = ent->s.origin[1] + forward[1] * 3 + right[1] * 0.5; start[2] = ent->s.origin[2] + forward[2] * 3 + right[2] * 0.5+4; } // calc direction to where we targetd VectorMA (ent->enemy->s.origin, -0.05, ent->enemy->velocity, target); VectorSubtract (target, start, dir); VectorNormalize (dir); fire_rocket (ent, start, dir, 25, 650, 25, 25, MOD_SENTRY_ROCKET); // send muzzle flash gi.WriteByte (svc_muzzleflash); gi.WriteShort (ent - g_edicts); gi.WriteByte (MZ_SHOTGUN ); gi.multicast (start, MULTICAST_PVS); // gi.sound(ent, CHAN_VOICE, gi.soundindex("boss3/xfire.wav"), 1, ATTN_NORM, 0); } //New turret bullet firing code. Replaces fire_bullet and fire_rail //Fires at ent->enemy //direction = 1 (left), 2 (center), 3 (right) void turret_fire_bullet (edict_t *ent, int direction) { vec3_t forward, right, start, target, dir; vec3_t from; vec3_t end; trace_t tr; edict_t *ignore; int mask; qboolean water; int kick = 0; int mod = MOD_SENTRY; int damage; float chance_of_hit; float maxvelocity; float r; if (wfdebug) gi.dprintf("turret_fire_bullet\n"); if(ent->light_level<1) //do we have ammo? return; if (!ent->enemy) return; UpdateSentryAmmo(ent, -1); //Calculate starting position AngleVectors (ent->s.angles, forward, right, NULL); if (direction == DIRECTION_LEFT) { start[0] = ent->s.origin[0] + forward[0] * 3 + right[0] * -0.5; start[1] = ent->s.origin[1] + forward[1] * 3 + right[1] * -0.5; start[2] = ent->s.origin[2] + forward[2] * 3 + right[2] * -0.5 +4; } else if (direction == DIRECTION_CENTER) { start[0] = ent->s.origin[0] + forward[0] * 3 ; start[1] = ent->s.origin[1] + forward[1] * 3 ; start[2] = ent->s.origin[2] + forward[2] * 3+4; } else // Right { start[0] = ent->s.origin[0] + forward[0] * 3 + right[0] * 0.5; start[1] = ent->s.origin[1] + forward[1] * 3 + right[1] * 0.5; start[2] = ent->s.origin[2] + forward[2] * 3 + right[2] * 0.5+4; } // calc direction to where we targetd VectorMA (ent->enemy->s.origin, -0.05, ent->enemy->velocity, target); //Adjust for height // target[2] += ent->enemy->viewheight/1.5; VectorSubtract (target, start, dir); VectorNormalize (dir); VectorMA (start, 8192, dir, end); VectorCopy (start, from); ignore = ent; water = false; mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA; tr = gi.trace (from, NULL, NULL, end, ignore, mask); if (tr.contents & (CONTENTS_SLIME|CONTENTS_LAVA)) { mask &= ~(CONTENTS_SLIME|CONTENTS_LAVA); water = true; } //Do damage //Damage based on sentry level chance_of_hit = 1; if (ent->count == 1) { damage = LEVEL1_DAMAGE; chance_of_hit = .85; } else if (ent->count == 2) { damage = LEVEL2_DAMAGE; chance_of_hit = .90; } else if (ent->count == 3) { damage = LEVEL3_DAMAGE; chance_of_hit = .95; } else { damage = 1; //don't know what level it is chance_of_hit = 1.0; //always hit } //Moving reduces chance of being hit maxvelocity = max( abs (ent->enemy->velocity[0]), abs (ent->enemy->velocity[1]) ); if (maxvelocity >= 320) //wierd setting for grappling { chance_of_hit = chance_of_hit * .65; } else if (maxvelocity >= 250) //running { chance_of_hit = chance_of_hit * .74; } else if (maxvelocity >= 150) //walking { chance_of_hit = chance_of_hit * .90; } r = random(); if (wfdebug) gi.dprintf("chance =%f, rnd = %f, takedamage? %d\n", chance_of_hit, r, ent->enemy->takedamage); if ((ent->enemy->takedamage) && (r <= chance_of_hit)) // T_Damage (ent->enemy, ent, ent->creator, dir, tr.endpos, tr.plane.normal, damage, 0, 0, MOD_SENTRY); T_Damage (ent->enemy, ent, ent, dir, tr.endpos, tr.plane.normal, damage, 0, 0, MOD_SENTRY); //Do gunshot effect gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_GUNSHOT); gi.WritePosition (tr.endpos); gi.WriteDir (tr.plane.normal); gi.multicast (tr.endpos, MULTICAST_PVS); if (ent->client) PlayerNoise(ent, tr.endpos, PNOISE_IMPACT); // send muzzle flash gi.WriteByte (svc_muzzleflash); gi.WriteShort (ent - g_edicts); gi.WriteByte (MZ_SHOTGUN ); gi.multicast (start, MULTICAST_PVS); // gi.sound(ent, CHAN_VOICE, gi.soundindex("boss3/xfire.wav"), 1, ATTN_NORM, 0); } void TurretAnimate(edict_t *ent) { if(ent->count==1) { if(ent->delay==StatusIdle) { ent->s.frame = Level1Idle; return; } else if(ent->delay==StatusStart) { if(ent->s.frame == Level1StartEnd) { ent->delay=StatusAttack; ent->s.frame=Level1AttackFirst; return; } else if(ent->s.frame==Level1Idle) { ent->s.frame = Level1StartFirst; return; } else if(ent->s.frame==Level1StartFirst) { ent->s.frame++; return; } else { ent->s.frame = Level1Idle; return; } } else { if(ent->delay==StatusAttack) { if(ent->s.frame==Level1AttackEnd) { ent->s.frame--; return; } else { ent->s.frame++; return; } } } } else { if(ent->delay ==StatusIdle) { ent->s.frame = Level23Idle; return; } else { if(ent->s.frame==Level23AttackEnd) { ent->s.frame = Level23AttackFirst; return; } ent->s.frame++; return; } } } void FireTurretLeft(edict_t *ent) { float f; if (wfdebug) gi.dprintf("Sentry Fire Left\n"); //Fire bullet. For level 3 sentry's, fire rocket every 10th round f = ent->light_level / 10; if (((f * 10) == ent->light_level) && (ent->count == 3)) turret_fire_rocket (ent, DIRECTION_LEFT); else turret_fire_bullet (ent, DIRECTION_LEFT); } void FireTurretCenter(edict_t *ent) { float f; if (wfdebug) gi.dprintf("Sentry Fire Center\n"); //Fire bullet. For level 3 sentry's, fire rocket every 10th round f = ent->light_level / 10; if (((f * 10) == ent->light_level) && (ent->count == 3)) turret_fire_rocket (ent, DIRECTION_CENTER); else turret_fire_bullet (ent, DIRECTION_CENTER); } void FireTurretRight(edict_t *ent) { float f; if (wfdebug) gi.dprintf("Sentry Fire Right\n"); //Fire bullet. For level 3 sentry's, fire rocket every 10th round f = ent->light_level / 10; if (((f * 10) == ent->light_level) && (ent->count == 3)) turret_fire_rocket (ent, DIRECTION_RIGHT); else turret_fire_bullet (ent, DIRECTION_RIGHT); } void Turret_Think(edict_t *self) { static char Sentry[32]; static char Armor[32]; static char Ammo[32]; static char Level[32]; int range; int light_level; int max_dist; edict_t *blip; float dist; int contents; int ideal_yaw = 0; vec3_t v; trace_t tr; // gitem_t *ammo; // int max; float checkyaw; blip = NULL; //If there is no client attached to this turret any more, it should be removed //from the game if (!self->creator) //There is no creator { turret_self_remove(self); } if (!self->creator->client) //Creator isn't a client { turret_self_remove(self); } //Make sure that the creator of this sentry gun also has an //entry that points back to this sentry if (!self->creator->sentry) //creator doesn't know about this sentry { turret_self_remove(self); } if (self->creator->sentry != self) //creator has a different sentry { turret_self_remove(self); } //If sentry or stand is in something solid, remove it contents = (int)gi.pointcontents(self->s.origin); if (contents & CONTENTS_SOLID) { safe_cprintf(self->creator, PRINT_HIGH, "Your sentry was in a bad map position, so it was removed.\n"); turret_self_remove(self); return; } if (self->sentry) //stand { contents = (int)gi.pointcontents(self->sentry->s.origin); if (contents & CONTENTS_SOLID) { safe_cprintf(self->creator, PRINT_HIGH, "Your sentry stand in a bad map position so it was removed.\n"); turret_self_remove(self); return; } } /*if (self->light_level!=self->gib_health) { if (self->PlasmaDelaygib_health; if (self->count==3) self->PlasmaDelay = level.time +0.1; else if (self->count==2) self->PlasmaDelay = level.time +0.2; else self->PlasmaDelay = level.time +0.4; self->light_level++; if (self->light_level > max) self->light_level = max; //GREGG gi.sound(self, CHAN_ITEM, gi.soundindex("misc/w_pkup.wav"), 1, ATTN_NORM, 0); } }*/ //Play sound if we are ready /* --self->turretsoundcountdown; if (self->turretsoundcountdown<=0) { //Play a sound if (self->count == 1) gi.sound(self, CHAN_VOICE, gi.soundindex("medic/medsrch1.wav"), 1, ATTN_NORM, 0); else if (self->count == 2) gi.sound(self, CHAN_VOICE, gi.soundindex("floater/fltatck2.wav"), 1, ATTN_NORM, 0); else if (self->count == 3) gi.sound(self, CHAN_VOICE, gi.soundindex("tank/tnkatck4.wav"), 1, ATTN_NORM, 0); self->turretsoundcountdown = 110; //same as 11 seconds } */ // if (self->turretsoundcountdown == 40)//back to ambient sound // self->s.sound = gi.soundindex ("world/amb3.wav"); if (self->count == 1) { range = 500; light_level = 10; max_dist = 300; } else if (self->count == 2) { range = 800; light_level = 7; max_dist = 500; } else if (self->count == 3) { range = 900; light_level = 4; max_dist = 700; } // Don't shoot frozen, dead, or non visible enemies if ((self->enemy) && ((self->enemy->health <= 0) || (!visible(self, self->enemy)) || (self->enemy->frozen))) { self->enemy = NULL; } if (!self->enemy) { // If we are going back to idle from some other status, // copy the angles back to original /* if (self->delay != StatusIdle) { VectorCopy (self->orig_angles , self->s.angles); self->sentrydelay =level.time+1; } */ self->delay=StatusIdle; while (blip = findradius (blip, self->s.origin, range)) { if (!blip->inuse) continue; if (!(blip->svflags & SVF_MONSTER) && !blip->client) { //allow it to shoot decoys if (strcmp(blip->classname, "decoy") ) continue; //not a decoy } if (strcmp(blip->classname, "hook") == 0 ) continue; //not a grapple if (blip->solid == SOLID_NOT) continue; //don't see observers if (blip->health <= 0) continue; if (blip->frozen) continue; // if (blip == self->creator) //wont work for anarchy mode // continue; if (blip->disguised) continue; if ((blip->wf_team == self->wf_team) && (((int)wfflags->value & WF_ALLOW_FRIENDLY_FIRE)==0)) // if (blip->wf_team == self->wf_team) continue; // if (blip->light_level < light_level) // continue; tr = gi.trace (self->s.origin, NULL, NULL, blip->s.origin, self, MASK_SOLID); if (tr.fraction != 1.0) continue; //Check the angle. /* VectorSubtract (blip->s.origin, self->s.origin, v); self->ideal_yaw = vectoyaw(v); checkyaw = anglemod(self->s.angles[YAW]) - self->ideal_yaw; if (checkyaw < -25 || checkyaw > 25) continue; VectorSubtract (self->s.origin, blip->s.origin, v); */ dist = VectorLength(v); if (!visible(self, blip) && dist > max_dist) continue; self->enemy = blip; } } else { VectorSubtract (self->enemy->s.origin, self->s.origin, v); self->ideal_yaw = vectoyaw(v); M_ChangeYaw(self); checkyaw = anglemod(self->s.angles[YAW])-self->ideal_yaw; if (checkyaw>-25 && checkyaw<25) { if (self->light_level>0) { if (visible(self, self->enemy)) { if (self->s.frame != 1) { if (self->delay==StatusIdle) self->delay = StatusStart; if (self->count == 1) { if(self->s.frame == 3) FireTurretRight(self); if( (self->s.frame == 1) || (self->s.frame ==5) ) FireTurretLeft(self); } else if (self->count == 2) { FireTurretCenter(self); } else if (self->count == 3) { //Maybe this will reduce lag // FireTurretRight(self); // FireTurretLeft(self); FireTurretCenter(self); } } } else { self->delay=StatusIdle; self->enemy=NULL; } } } else { self->delay=StatusIdle; self->enemy=NULL; } } //Move the stand? (GREGG) if (self->sentry) VectorCopy(self->s.origin,self->sentry->s.origin); // Move the sentry to stay with stand (TeT) // if (self->sentry) // VectorCopy(self->sentry->s.origin, self->s.origin); TurretAnimate(self); self->nextthink = level.time + 0.1; if(self->delay==StatusIdle) { if(self->sentrydelayPlasmaDelay) self->PlasmaDelay=0; else self->PlasmaDelay=1; gi.sound(self, CHAN_VOICE, gi.soundindex("misc/comp_up.wav"), 0.1, ATTN_NORM, 0); self->sentrydelay=level.time + 2; } if(self->PlasmaDelay) self->s.angles[YAW]+=3.5; else self->s.angles[YAW]-=3.5; if(self->s.angles[YAW]<0) self->s.angles[YAW]+=360; else if(self->s.angles[YAW]>360) self->s.angles[YAW]-=360; } //if(self->healthmax_health) // self->health++; } //Ent = turret entity void turret_self_remove(edict_t *ent) { //Clear client's pointer to sentry gun if (ent->creator) ent->creator->sentry = NULL; //first free stand if (ent->sentry) G_FreeEdict(ent->sentry); //Then free the sentry gun BecomeExplosion1 (ent); // G_FreeEdict(ent); } //Ent = Player entity void turret_remove(edict_t *ent) { if (ent->sentry) { //42 ebc safe_cprintf(ent, PRINT_HIGH, "Sentry Gun off.\n"); //First free the stand if (ent->sentry->sentry) { G_FreeEdict(ent->sentry->sentry); ent->sentry->sentry = NULL; } //Then free the sentry gun BecomeExplosion1 (ent->sentry); // G_FreeEdict(ent->sentry); ent->sentry = NULL; if (ent->client->oldplayer) G_FreeEdict(ent->client->oldplayer); return; } } void turret_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { vec3_t origin; char *name1; char *name2; //42 sebc edict_t *blip = NULL; int i; //42 bot sentry clear itemnode owner if (self->creator->bot_client) for (i=1, blip=g_edicts+i ; i < globals.num_edicts ; i++,blip++) { if (blip->owner == self->creator) { if (!strcmp(blip->classname, "item_sentryspot") ) { blip->owner = NULL; } } } //42 end clear item owner safe_cprintf(self->creator, PRINT_HIGH, "Sentry Gun Destroyed.\n"); //Give a frag to the attacker if (attacker->client && attacker->wf_team != self->wf_team) { PlayerChangeScore(attacker,CTF_SENTRY_POINTS); name1 = attacker->client->pers.netname; if (self->creator->client) name2 = self->creator->client->pers.netname; else name2 = "unknown player"; my_bprintf(PRINT_HIGH, "%s destroyed %s's sentry gun.\n", name1, name2); } VectorCopy (self->s.origin,origin); origin[2]+= 0.5; self->takedamage = DAMAGE_NO; gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_EXPLOSION1); gi.WritePosition (origin); gi.multicast (origin, MULTICAST_PVS); turret_self_remove(self); } void SentryReload(edict_t *ent, pmenu_t *p) { int max, armorfill; float dist; vec3_t distance; if (!ent->selectedsentry) return; distance[0]=ent->s.origin[0] - ent->selectedsentry->s.origin[0]; distance[1]=ent->s.origin[1] - ent->selectedsentry->s.origin[1]; distance[2]=ent->s.origin[2] - ent->selectedsentry->s.origin[2]; dist=VectorLength(distance); if(dist>100) { safe_cprintf(ent, PRINT_HIGH, "Sentry too far away.\n"); PMenu_Close(ent); return; } if (ent->selectedsentry->light_level!=ent->selectedsentry->gib_health) { max = ent->selectedsentry->gib_health; armorfill=ent->selectedsentry->gib_health-ent->selectedsentry->light_level; if(armorfill>75) armorfill=75; // if(armorfill>25) // armorfill=25; if (ent->client->pers.inventory[ITEM_INDEX(FindItem("Bullets"))] < 25) { safe_cprintf(ent, PRINT_HIGH, "You need 25 Bullets to reload the sentry gun.\n"); if (ent->selectedsentry) gi.sound(ent->selectedsentry, CHAN_VOICE, gi.soundindex("misc/keytry.wav"), 1, ATTN_NORM, 0); PMenu_Close(ent); return; } //25 player bullets will give 75 bullets to sentry gun (Gregg) // if(armorfill > ent->client->pers.inventory[ITEM_INDEX(FindItem("Bullets"))]) // armorfill = ent->client->pers.inventory[ITEM_INDEX(FindItem("Bullets"))]; UpdateSentryAmmo(ent->selectedsentry, armorfill); // ent->selectedsentry->light_level += armorfill; ent->client->pers.inventory[ITEM_INDEX(FindItem("Bullets"))] -= 25; if (ent->selectedsentry->light_level > max) ent->selectedsentry->light_level = max; gi.sound(ent->selectedsentry, CHAN_ITEM, gi.soundindex("misc/w_pkup.wav"), 1, ATTN_NORM, 0); } PMenu_Close(ent); } void AddArmorToSentry(edict_t *ent, int amt) { int max, armor; if (ent->health < ent->max_health) { max = ent->max_health; //How much armor is needed? armor = ent->max_health - ent->health; if (amt < armor) armor = amt; else armor = 0; ent->health+= armor; if (ent->health > max) ent->health = max; if (ent->selectedsentry) gi.sound(ent->selectedsentry, CHAN_ITEM, gi.soundindex("misc/w_pkup.wav"), 1, ATTN_NORM, 0); } } void SentryRepair(edict_t *ent, pmenu_t *p) { int max, armor; int cells, maxcells, currcells; float dist; vec3_t distance; if (!ent->selectedsentry) return; distance[0]=ent->s.origin[0] - ent->selectedsentry->s.origin[0]; distance[1]=ent->s.origin[1] - ent->selectedsentry->s.origin[1]; distance[2]=ent->s.origin[2] - ent->selectedsentry->s.origin[2]; dist=VectorLength(distance); if(dist>100) { safe_cprintf(ent, PRINT_HIGH, "Sentry too far away.\n"); PMenu_Close(ent); return; } if (ent->selectedsentry->healthselectedsentry->max_health) { max = ent->selectedsentry->max_health; //How much armor is needed? armor = ent->selectedsentry->max_health - ent->selectedsentry->health; //Can't give more than 100 points armor in one shot if(armor > 100) armor=100; //Each cell gives 4 points armor currcells = ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))]; maxcells = armor / 4; if (currcells ==0) { safe_cprintf(ent, PRINT_HIGH, "You need Cells to repair the sentry gun.\n"); if (ent->selectedsentry) gi.sound(ent->selectedsentry, CHAN_VOICE, gi.soundindex("misc/keytry.wav"), 1, ATTN_NORM, 0); PMenu_Close(ent); return; } //If we don't have enough cells, adjust the amount of armor to give if(currcells < maxcells) { cells = currcells; armor = cells * 4; } else { cells = maxcells; } ent->selectedsentry->health+= armor; ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] -= cells; if (ent->selectedsentry->health > max) ent->selectedsentry->health = max; gi.sound(ent->selectedsentry, CHAN_ITEM, gi.soundindex("misc/w_pkup.wav"), 1, ATTN_NORM, 0); } PMenu_Close(ent); } void SentryUpgrade(edict_t *ent, pmenu_t *p) { float dist; vec3_t distance; if (!ent->selectedsentry) return; distance[0]=ent->s.origin[0] - ent->selectedsentry->s.origin[0]; distance[1]=ent->s.origin[1] - ent->selectedsentry->s.origin[1]; distance[2]=ent->s.origin[2] - ent->selectedsentry->s.origin[2]; dist=VectorLength(distance); if(dist>100) { safe_cprintf(ent, PRINT_HIGH, "Sentry too far away.\n"); PMenu_Close(ent); return; } if (ent->selectedsentry->count == 3) { safe_cprintf(ent, PRINT_HIGH, "Sentry gun already at level 3\n"); return; } if (ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] < 60) { safe_cprintf(ent, PRINT_HIGH, "You need 60 cells to upgrade sentry gun.\n"); PMenu_Close(ent); return; } if (ent->selectedsentry->count < 3) ent->selectedsentry->count++; ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] -= 60; if (ent->selectedsentry->count == 2) { ent->selectedsentry->health= 200; ent->selectedsentry->max_health =200; ent->selectedsentry -> s.modelindex = gi.modelindex ("models/sentry/turret2/tris.md2"); ent->selectedsentry->delay = StatusIdle; ent->selectedsentry->s.frame = 0; ent->selectedsentry->yaw_speed = 40; ent->selectedsentry->gib_health = 150;//Max Ammo ent->selectedsentry->light_level = 150; //ent->selectedsentry->turretsoundcountdown = 0; gi.sound(ent->selectedsentry, CHAN_VOICE, gi.soundindex("misc/pc_up.wav"), 1, ATTN_NORM, 0); } if (ent->selectedsentry->count == 3) { ent->selectedsentry->health= 300; ent->selectedsentry->max_health = 300; ent->selectedsentry -> s.modelindex = gi.modelindex ("models/sentry/turret3/tris.md2"); ent->selectedsentry->delay = StatusIdle; ent->selectedsentry->s.frame = 0; ent->selectedsentry->yaw_speed = 45; ent->selectedsentry->gib_health = 225;//Max Ammo ent->selectedsentry->light_level = 225; //ent->selectedsentry->turretsoundcountdown = 0; gi.sound(ent->selectedsentry, CHAN_VOICE, gi.soundindex("misc/pc_up.wav"), 1, ATTN_NORM, 0); } PMenu_Close(ent); } void Sentry_Touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) { if (other->client) other->selectedsentry = ent; //Skip if they already have a menu up if ((other->client) && (other->client->menu)) return; if(other->sentrydelay>level.time) return; //Only show menu a max of every 1 second //Only allow team mates access to menu if (!other->bot_client)//42 if (other->client && (other->wf_team == ent->wf_team) && (other->client->player_special & SPECIAL_SENTRY_GUN)) { PMenu_Close(other); sprintf(other->client->wfsentrystr[0], "*%s's Sentry", ent->standowner->client->pers.netname); sprintf(other->client->wfsentrystr[1], " Armor:%d/%d", ent->health, ent->max_health); sprintf(other->client->wfsentrystr[2], " Ammo:%d/%d", ent->light_level,ent->gib_health); sprintf(other->client->wfsentrystr[3], " Level:%d", ent->count); other->client->sentrymenu[0].text = other->client->wfsentrystr[0]; other->client->sentrymenu[0].SelectFunc = NULL; other->client->sentrymenu[0].align = PMENU_ALIGN_CENTER; other->client->sentrymenu[0].arg = 0; other->client->sentrymenu[1].text = other->client->wfsentrystr[1]; other->client->sentrymenu[1].SelectFunc = NULL; other->client->sentrymenu[1].align = PMENU_ALIGN_LEFT; other->client->sentrymenu[1].arg = 0; other->client->sentrymenu[2].text = other->client->wfsentrystr[2]; other->client->sentrymenu[2].SelectFunc = NULL; other->client->sentrymenu[2].align = PMENU_ALIGN_LEFT; other->client->sentrymenu[2].arg = 0; other->client->sentrymenu[3].text = other->client->wfsentrystr[3]; other->client->sentrymenu[3].SelectFunc = NULL; other->client->sentrymenu[3].align = PMENU_ALIGN_LEFT; other->client->sentrymenu[3].arg = 0; other->client->sentrymenu[4].text = "1. Upgrade"; other->client->sentrymenu[4].SelectFunc = SentryUpgrade; other->client->sentrymenu[4].align = PMENU_ALIGN_LEFT; other->client->sentrymenu[4].arg = 0; other->client->sentrymenu[5].text = "2. Repair"; other->client->sentrymenu[5].SelectFunc = SentryRepair; other->client->sentrymenu[5].align = PMENU_ALIGN_LEFT; other->client->sentrymenu[5].arg = 0; other->client->sentrymenu[6].text = "3. Reload"; other->client->sentrymenu[6].SelectFunc = SentryReload; other->client->sentrymenu[6].align = PMENU_ALIGN_LEFT; other->client->sentrymenu[6].arg = 0; // other->selectedsentry = ent->standowner->sentry; other->selectedsentry = ent; PMenu_Open(other, other->client->sentrymenu, -1, sizeof(other->client->sentrymenu) / sizeof(pmenu_t), true, false); other->sentrydelay = level.time + 3; //Set timeout for menu (4 seconds) if (other->client->menu) other->client->menu->MenuTimeout = level.time + 4; } } //Stand think function void Stand_Think (edict_t *ent) { //For some reason, entity needs a think function if (ent->health <= 0) G_FreeEdict(ent); else ent->nextthink = level.time + 5.0; } //Build the turret void place_turret (edict_t *ent) { vec3_t forward,up,right,wallp, pos,try1,try2,try3,try4; edict_t *blip = NULL; int cells; trace_t tr; edict_t *sentrystand; int armor; int armorindex; // valid ent ? if ((!ent->client) || (ent->health<=0)) return; if (ent->sentry) { turret_remove(ent); if (ent->client->oldplayer) G_FreeEdict(ent->client->oldplayer); return; } // cells for sentry gun ? if ((int)wfflags->value & WF_ANARCHY) { armor = 150; armorindex = ArmorIndex (ent); if (ent->client->pers.inventory[armorindex] < armor) { safe_cprintf(ent, PRINT_HIGH, "You need %d points of armor to create sentry gun.\n", armor); return; } } else { cells = 50; if (ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] < cells) { safe_cprintf(ent, PRINT_HIGH, "You need %d cells to create sentry gun.\n", cells); return; } } // Setup "little look" to close wall VectorCopy(ent->s.origin,wallp); // Cast along view angle AngleVectors (ent->client->v_angle, forward, right, up); // Setup end point pos[0]=ent->s.origin[0]+forward[0]*75; pos[1]=ent->s.origin[1]+forward[1]*75; pos[2]=ent->s.origin[2]+forward[2]*75+30; wallp[0]=ent->s.origin[0]+forward[0]*150; wallp[1]=ent->s.origin[1]+forward[1]*150; wallp[2]=ent->s.origin[2]+forward[2]*150+30; try1[0]=ent->s.origin[0]+forward[0]*150+right[0]*20; try1[1]=ent->s.origin[1]+forward[1]*150+right[1]*20; try1[2]=ent->s.origin[2]+forward[2]*150+30+right[2]*20; try2[0]=ent->s.origin[0]+forward[0]*150+right[0]*-20; try2[1]=ent->s.origin[1]+forward[1]*150+right[1]*-20; try2[2]=ent->s.origin[2]+forward[2]*150+30+right[2]*-20; try3[0]=ent->s.origin[0]+forward[0]*75+right[0]*20; try3[1]=ent->s.origin[1]+forward[1]*75+right[1]*20; try3[2]=ent->s.origin[2]+forward[2]*75+30+right[2]*20; try4[0]=ent->s.origin[0]+forward[0]*75+right[0]*-20; try4[1]=ent->s.origin[1]+forward[1]*75+right[1]*-20; try4[2]=ent->s.origin[2]+forward[2]*75+30+right[2]*-20; // trace tr = gi.trace (ent->s.origin, NULL, NULL, wallp, ent, MASK_SOLID); // Line complete ? (ie. no collision) if (tr.fraction != 1.0) {//42 ebc safe_cprintf (ent, PRINT_HIGH, "Not enough room.\n"); return; } wallp[2]+=22; tr = gi.trace (pos, NULL, NULL, wallp, ent, MASK_SOLID); // Line complete ? (ie. no collision) if (tr.fraction != 1.0) { safe_cprintf (ent, PRINT_HIGH, "Not enough room. Try aiming lower\n"); return; } wallp[2]-=40; tr = gi.trace (pos, NULL, NULL, wallp, ent, MASK_SOLID); // Line complete ? (ie. no collision) if (tr.fraction != 1.0) { safe_cprintf (ent, PRINT_HIGH, "Not enough room. Try aiming higher\n"); return; } // trace tr = gi.trace (ent->s.origin, NULL, NULL, try1, ent, MASK_SOLID); if (tr.fraction != 1.0) { safe_cprintf (ent, PRINT_HIGH, "Not enough room.\n"); return; } // trace tr = gi.trace (ent->s.origin, NULL, NULL, try2, ent, MASK_SOLID); if (tr.fraction != 1.0) { safe_cprintf (ent, PRINT_HIGH, "Not enough room.\n"); return; } // trace tr = gi.trace (ent->s.origin, NULL, NULL, try3, ent, MASK_SOLID); if (tr.fraction != 1.0) { safe_cprintf (ent, PRINT_HIGH, "Not enough room.\n"); return; } // trace tr = gi.trace (ent->s.origin, NULL, NULL, try4, ent, MASK_SOLID); if (tr.fraction != 1.0) { safe_cprintf (ent, PRINT_HIGH, "Not enough room.\n"); return; } // Hit sky ? if ((tr.surface) && (tr.surface->flags & SURF_SKY)) return; while (blip = findradius (blip, pos, 50)) { if ( (!strcmp(blip->classname, "item_flag_team1") ) || (!strcmp(blip->classname, "item_flag_team2") ) || (!strcmp(blip->classname, "worldspawn") ) || (!strcmp(blip->classname, "info_player_start") ) || (!strcmp(blip->classname, "info_player_deathmatch") ) || (!strcmp(blip->classname, "item_flagreturn_team1") ) || (!strcmp(blip->classname, "item_flagreturn_team2") ) || (!strcmp(blip->classname, "misc_teleporter_dest") ) || (!strcmp(blip->classname, "info_teleport_destination") ) ) { safe_cprintf (ent, PRINT_HIGH, "Too Close to Items.\n"); return ; } } if ((int)wfflags->value & WF_ANARCHY) { ent->client->pers.inventory[armorindex] -= armor; } else { ent->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] -= cells; } safe_cprintf(ent, PRINT_HIGH, "Sentry Gun on.\n"); ent->sentry = G_Spawn(); //ent->sentry->s.sound = gi.soundindex ("world/amb3.wav"); //ent->sentry->turretsoundcountdown = 0; VectorClear (ent->sentry->mins); VectorClear (ent->sentry->maxs); VectorCopy (pos, ent->sentry->s.origin); ent->sentry ->s.angles[0]=0; // ent->sentry -> movetype = MOVETYPE_STEP; // ent->sentry -> clipmask = MASK_SHOT; ent->sentry -> movetype = MOVETYPE_TOSS; ent->sentry -> clipmask = MASK_PLAYERSOLID; ent->sentry->mass = 400; ent->s.renderfx=RF_FRAMELERP|RF_TRANSLUCENT|RF_GLOW; //grenade -> solid = SOLID_NOT; ent->sentry->solid = SOLID_BBOX; //GR - reduce size of bounding box since I reduced size of model // VectorSet(ent->sentry->mins, -95,-44,-80); // VectorSet(ent->sentry->maxs, 57, 41, 24); VectorSet(ent->sentry->mins, -50,-20,-40); VectorSet(ent->sentry->maxs, 30, 21, 22); ent->sentry->takedamage=DAMAGE_YES; ent->sentry -> s.modelindex = gi.modelindex ("models/sentry/turret1/tris.md2"); ent->sentry -> creator = ent; ent->sentry ->sentrydelay =level.time + 1; ent->sentry->standowner=ent; ent->sentry->think = Turret_Think; // ent->sentry->nextthink = level.time + 0.1; ent->sentry->nextthink = level.time + 2.0; ent->sentry->touch = Sentry_Touch; ent->sentry->die = turret_die; ent->sentry->health= 80; ent->sentry->max_health = 100; ent->sentry->count = 1; ent->sentry->s.sound = gi.soundindex ("weapons/rg_hum.wav"); //ent->sentry->noise_index2 = gi.soundindex ("weapons/rg_hum.wav"); ent->sentry->attenuation =1; ent->sentry->volume = 0.5; ent->sentry->classname = "SentryGun"; ent->sentry->noteamdamage = true; //Don't let teammates damage it ent->sentry->yaw_speed = 35; ent->sentry->gib_health = 75;//Max Ammo ent->sentry->light_level = 75;//Ammo Total ent->sentry->delay=StatusIdle; if ((int)wfflags->value & WF_ANARCHY) { ent->sentry->wf_team = 0; //fire at anybody ent->sentry->count = 3; ent->sentry->health= 300; ent->sentry->max_health = 300; ent->sentry -> s.modelindex = gi.modelindex ("models/sentry/turret3/tris.md2"); ent->sentry->s.frame = 0; ent->sentry->yaw_speed = 45; ent->sentry->gib_health = 225;//Max Ammo ent->sentry->light_level = 225; gi.sound(ent->sentry, CHAN_VOICE, gi.soundindex("misc/pc_up.wav"), 1, ATTN_NORM, 0); } else ent->sentry->wf_team = ent->wf_team; gi.linkentity (ent->sentry); if (wfdebug) { ent->sentry->s.modelindex2 = gi.modelindex ("models/stand/tris.md2"); ent->sentry->sentry = NULL; } else { sentrystand = G_Spawn(); VectorClear (sentrystand->mins); VectorClear (sentrystand->maxs); VectorCopy (pos,sentrystand->s.origin); sentrystand->s.angles[0]=0; sentrystand->movetype = MOVETYPE_TOSS; sentrystand->mass = 400; //grenade -> solid = SOLID_NOT; sentrystand->solid = SOLID_NOT; VectorSet(sentrystand->mins, -45,-15,-40); VectorSet(sentrystand->maxs, 25, 18, 18); botDebugPrint("mins: %s\n", vtos(sentrystand->mins)); botDebugPrint("mins: %s\n", vtos(ent->sentry->s.origin)); botDebugPrint("mins: %s\n", vtos(sentrystand->s.origin)); botDebugPrint("mins: %s\n", vtos(ent->sentry->s.angles)); botDebugPrint("mins: %s\n", vtos(sentrystand->s.angles)); sentrystand->takedamage=DAMAGE_NO; sentrystand->health = 10; sentrystand->s.modelindex = gi.modelindex ("models/stand/tris.md2"); sentrystand->classname = "SentryStand"; sentrystand->creator = ent->sentry; sentrystand->standowner = ent; sentrystand->wf_team = ent->wf_team; // sentrystand->touch = Sentry_Touch;//Touching it will then pop up a menu sentrystand->noteamdamage = true; //Don't let teammates damage it sentrystand->think = Stand_Think; sentrystand->nextthink = level.time + 0.5; gi.linkentity (sentrystand); ent->sentry->sentry = sentrystand; } } void UpgradeSentry(edict_t *self) { edict_t *blip; trace_t tr; qboolean found; blip = NULL; found = false; // while (blip = findradius (blip, self->s.origin, 2048)) while (blip = findradius (blip, self->s.origin, 128)) { if (Q_stricmp("SentryGun", blip->classname)) continue; if (!self->bot_client) if (self->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] < 60) {//42 ebc safe_cprintf(self, PRINT_HIGH, "You need 60 cells to upgrade sentry gun.\n"); return; } found = true; tr = gi.trace (self->s.origin, NULL, NULL, blip->s.origin, self, MASK_SOLID); if (tr.fraction != 1.0) continue; if (blip->creator != self) continue; if (blip->count == 3)//42 sbc safe_cprintf(self, PRINT_HIGH, "Sentry gun already at level 3\n"); if (blip->count < 3) blip->count++; if(!self->bot_client)//42 self->client->pers.inventory[ITEM_INDEX(FindItem("Cells"))] -= 60; if (blip->count == 2) { blip->health= 200; blip->max_health =200; blip -> s.modelindex = gi.modelindex ("models/sentry/turret2/tris.md2"); blip->delay = StatusIdle; blip->s.frame = 0; blip->yaw_speed = 40; blip->gib_health = 150;//Max Ammo blip->light_level = 150;//5/99 suggest removing this whole section and rework/use sentryupdate() //blip->turretsoundcountdown = 110; gi.sound(self, CHAN_VOICE, gi.soundindex("misc/pc_up.wav"), 1, ATTN_NORM, 0); } if (blip->count == 3) { blip->health= 300; blip->max_health =300; blip -> s.modelindex = gi.modelindex ("models/sentry/turret3/tris.md2"); blip->delay = StatusIdle; blip->s.frame = 0; blip->yaw_speed = 45; blip->gib_health = 225;//Max Ammo blip->light_level = 225;//5/99 suggest removing this whole section and rework/use sentryupdate() //blip->turretsoundcountdown = 110; gi.sound(self, CHAN_VOICE, gi.soundindex("misc/pc_up.wav"), 1, ATTN_NORM, 0); } } if (found == false)//42 sbc safe_cprintf(self, PRINT_HIGH, "Sorry, you aren't close enough.\n"); } //test_Sentry() - see if there is a sentry close enough to work on //Returns 0 if sentry does not exist or is too far away //Returns 1 if sentry exists and is close enough int test_Sentry (edict_t *ent) { float dist; float tdist; edict_t *sentry; vec3_t distance; edict_t *blip; if (!ent->sentry) { safe_cprintf(ent, PRINT_HIGH, "Sentry not found.\n"); return 0; } blip = NULL; dist = 0; sentry = NULL; while (blip = findradius (blip, ent->s.origin, 100)) { if (strcmp(blip->classname, "SentryGun")) continue; //Not a sentry gun distance[0]=ent->s.origin[0] - blip->s.origin[0]; distance[1]=ent->s.origin[1] - blip->s.origin[1]; distance[2]=ent->s.origin[2] - blip->s.origin[2]; tdist=VectorLength(distance); if ((dist == 0) || (tdist < dist)) { dist = tdist; sentry = blip; } } if(dist>100 || sentry == NULL) { safe_cprintf(ent, PRINT_HIGH, "Sentry too far away.\n"); return 0; } else { ent->selectedsentry = sentry; return 1; } } void cmd_Sentry (edict_t *ent) { char *string; string=gi.args(); if (!ent->client) return; //argument = "build", "remove", "upgrade", "repair" and "reload" if (Q_stricmp ( string, "build") == 0) { if (!ent->sentry) place_turret(ent); else safe_cprintf(ent, PRINT_HIGH, "Sentry already exists.\n"); } else if (Q_stricmp ( string, "remove") == 0) { if (ent->sentry) turret_remove(ent); else safe_cprintf(ent, PRINT_HIGH, "Sentry not found.\n"); } else if (Q_stricmp ( string, "upgrade") == 0) { if (test_Sentry(ent)) SentryUpgrade(ent, NULL); } else if (Q_stricmp ( string, "repair") == 0) { if (test_Sentry(ent)) SentryRepair(ent, NULL); } else if (Q_stricmp ( string, "reload") == 0) { if (test_Sentry(ent)) SentryReload(ent, NULL); } //Otherwise toggle on/off else if (Q_stricmp ( string, "") == 0) { place_turret(ent); } else safe_cprintf(ent, PRINT_HIGH, "Invalid sentry command.\n"); }