#include "g_local.h" #include "m_player.h" //EVERYTHING IN HERE WAS DONE BY PSYCHOSPAZ #define START_OFF 1 #define GRAPPLESPEED 2000 #define SINKAMT 1 #define CLIMBSPEED 400 #define WALLRUNSPEED 400 #define TAZERLENGTHSP 800 #define TAZERLENGTH 400 #define GRAPPLESTYPE 1 #define FRAME_FIRE_FIRST 10 #define FRAME_IDLE_FIRST 10 #define FRAME_DEACTIVATE_FIRST 10 void Weapon_Generic_2 (edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent)); void check_dodge (edict_t *self, vec3_t start, vec3_t dir, int speed); void target_laser_use (edict_t *self, edict_t *other, edict_t *activator); void target_laser_on (edict_t *self); void target_laser_off (edict_t *self); void FadeSink (edict_t *ent); void AddKick (edict_t *ent, vec3_t forward, int amt); static void P_ProjectSource (gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result) { vec3_t _distance; VectorCopy (distance, _distance); if (client->pers.hand == LEFT_HANDED) _distance[1] *= -1; else if (client->pers.hand == CENTER_HANDED) _distance[1] = 0; G_ProjectSource (point, _distance, forward, right, result); } void CleanUpEnt (edict_t *self) { if (self->shadow) G_FreeEdict(self->shadow); if (self->reflection) { if (self->reflection->client) free(self->reflection->client); G_FreeEdict(self->reflection); } } /* ================= FADING FX ================= */ void FadedOut (edict_t *ent) { //This is for clients that dissapear //I use sprites so that invisible polys wont build up //This reduces server lag... edict_t * other; int j; if (ent->reflection) { if (ent->reflection->client) free(ent->reflection->client); G_FreeEdict(ent->reflection); } if (ent->shadow) G_FreeEdict(ent->shadow); ent->floater = 0; ent->s.renderfx = RF_BEAM; ent->s.modelindex = gi.modelindex ("sprites/s_bubble.sp2"); G_FreeEdict(ent); for (j = 1; j <= game.maxclients; j++) { other = &g_edicts[j]; if (!other->client) continue; if (!other->viewcam_on) continue; if (!other->killer) continue; if (other->killer==ent) other->killer=NULL; } } void FadeDieEnd (edict_t *ent) { ent->s.renderfx=0; ent->s.effects=EF_SPHERETRANS; ent->think=FadedOut; ent->nextthink=level.time+0.5; } void FadeDie (edict_t *ent) { ent->s.renderfx=RF_TRANSLUCENT; ent->think=FadeDieEnd; ent->nextthink=level.time+0.5; } void FadeDieSinkEnd (edict_t *ent) { ent->s.origin[2]-=SINKAMT; ent->s.renderfx=0; ent->s.effects=EF_SPHERETRANS; ent->think=FadeSink; ent->nextthink=level.time+0.1; } void FadeSink (edict_t *ent) { ent->phase++; ent->s.origin[2]-=SINKAMT; ent->think=FadeSink; if (ent->phase==4) ent->think=FadeDieSinkEnd; if (ent->phase==10) ent->think=FadedOut; ent->nextthink=level.time+0.1; } void FadeDieSink (edict_t *ent) { ent->s.origin[2]-=SINKAMT; ent->s.renderfx=RF_TRANSLUCENT; ent->think=FadeSink; ent->nextthink=level.time+0.1; ent->phase=0; } /* ==================== PUNCH / JUMP KICK!!! ==================== */ void ClientHit (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int isInAir) { vec3_t from; vec3_t end; vec3_t tempAim; trace_t tr; edict_t *ignore; int mask; qboolean water; int hitwall=0; VectorNormalize(aimdir); VectorMA (start, MELEE_DISTANCE/2, aimdir, end); VectorCopy (start, from); ignore = self; water = false; mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA; tr = gi.trace (from, NULL, NULL, end, ignore, mask); if ((tr.ent != self) && (tr.ent->takedamage)) { T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_PUNCH); gi.sound(self, CHAN_AUTO, gi.soundindex("infantry/melee2.wav"), 0.75, ATTN_IDLE, 0); if ((tr.ent->client)||(tr.ent->svflags & SVF_MONSTER)) { gi.sound(self, CHAN_AUTO, gi.soundindex("chick/chkatck4.wav"), 0.75, ATTN_IDLE, 0); } } else { if ((self->waterlevel<3)&&!(tr.contents & MASK_WATER)) { if ((int)(random()*2)==1) gi.sound(self, CHAN_AUTO, gi.soundindex("gladiator/melee3.wav"), 0.75, ATTN_IDLE, 0); else gi.sound(self, CHAN_AUTO, gi.soundindex("mutant/mutatck1.wav"), 0.75, ATTN_IDLE, 0); } else { if ((int)(random()*2)==1) gi.sound(self, CHAN_AUTO, gi.soundindex("player/wade1.wav"), 0.6, ATTN_IDLE, 0); else gi.sound(self, CHAN_AUTO, gi.soundindex("player/wade3.wav"), 0.6, ATTN_IDLE, 0); } if (!((tr.surface) && (tr.surface->flags & SURF_SKY))) if (tr.fraction < 1.0) if (strncmp (tr.surface->name, "sky", 3) != 0) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_CHAINFIST_SMOKE); gi.WritePosition (tr.endpos); gi.unicast (self, 0); gi.sound(self, CHAN_AUTO, gi.soundindex("infantry/melee2.wav"), 0.45, ATTN_IDLE, 0); gi.sound(self, CHAN_AUTO, gi.soundindex("chick/chkatck4.wav"), 0.3, ATTN_IDLE, 0); hitwall=1; } } if (self->waterlevel>2) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BUBBLETRAIL); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (self->s.origin, MULTICAST_PHS); if ((int)(random()*4)==1) if (!hitwall) SP_Bubble (self, tr.endpos); } if (self->client->ps.pmove.pm_flags & PMF_DUCKED) { self->client->anim_priority = ANIM_ATTACK; self->s.frame = FRAME_crattak1-1; self->client->anim_end = FRAME_crattak3; } else if (self->groundentity) { self->client->anim_priority = ANIM_REVERSE; self->s.frame = FRAME_point12; self->client->anim_end = FRAME_point08; } else { self->client->anim_priority = ANIM_ATTACK; self->s.frame = FRAME_attack1; self->client->anim_end = FRAME_attack4; } } void fire_kick (edict_t *ent, vec3_t start, vec3_t aimdir) { vec3_t dir; vec3_t from; vec3_t end; trace_t tr; edict_t *ignore; int mask; int kick = 10; int damage = 30+((int)random()*35); int isInAir = 0; if (!ent->groundentity) isInAir = 1; ClientHit (ent, start, aimdir, damage, kick, isInAir); } void weapon_kick_fire (edict_t *ent) { vec3_t start; vec3_t forward, right; vec3_t offset; int LeftRight= 10*ent->client->hitmode; AngleVectors (ent->client->v_angle, forward, right, NULL); VectorScale (forward, 0, ent->client->kick_origin); ent->client->kick_angles[0] = 0; if (ent->client->hitmode==1) { ent->client->hitmode=-1; } else ent->client->hitmode=1; VectorSet(offset, 0, LeftRight, ent->viewheight); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); fire_kick (ent, start, forward); } /* ==================== SMACL WITH GUN !!! ==================== */ void SmackHit (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int isInAir) { vec3_t from; vec3_t end; vec3_t tempAim, tempVel; trace_t tr; edict_t *ignore; int mask; qboolean water; int hitwall=0; int Hit_Distance; Hit_Distance = (isInAir) ? MELEE_DISTANCE : MELEE_DISTANCE * 0.75; VectorMA (start, Hit_Distance, aimdir, end); //if (isInAir) // VectorMA (start, MELEE_DISTANCE*(2/3), aimdir, end); VectorCopy (start, from); ignore = self; water = false; mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA; tr = gi.trace (from, NULL, NULL, end, ignore, mask); if ((tr.ent != self) && (tr.ent->takedamage)) { T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, (!isInAir)?MOD_SMACK:MOD_KICK); gi.sound(self, CHAN_AUTO, gi.soundindex("infantry/melee2.wav"), 0.75, ATTN_IDLE, 0); if ((tr.ent->client)||(tr.ent->svflags & SVF_MONSTER)) { gi.sound(self, CHAN_AUTO, gi.soundindex("chick/chkatck4.wav"), 0.75, ATTN_IDLE, 0); } if (isInAir) { VectorCopy (aimdir, tempVel); VectorNormalize (tempVel); VectorScale (tempVel, -300, tempVel); tempVel[2] = 400; VectorCopy (tempVel, self->velocity); self->client->stunts=10; } if (!isInAir && tr.ent->health>0) { //bat em away VectorCopy (aimdir, tempVel); VectorNormalize (tempVel); VectorScale (tempVel, 400, tempVel); tempVel[2]=200; tr.ent->groundentity=NULL; VectorAdd(tr.ent->velocity, tempVel, tr.ent->velocity); } } else { if (!isInAir) if (((self->waterlevel<3)&&!(tr.contents & MASK_WATER))&&!sv_waterlevel->value) { if ((int)(random()*2)==1) gi.sound(self, CHAN_AUTO, gi.soundindex("gladiator/melee3.wav"), 0.85, ATTN_IDLE, 0); else gi.sound(self, CHAN_AUTO, gi.soundindex("mutant/mutatck1.wav"), 0.85, ATTN_IDLE, 0); } else { if ((int)(random()*2)==1) gi.sound(self, CHAN_AUTO, gi.soundindex("player/wade1.wav"), 0.6, ATTN_IDLE, 0); else gi.sound(self, CHAN_AUTO, gi.soundindex("player/wade3.wav"), 0.6, ATTN_IDLE, 0); } if (!((tr.surface) && (tr.surface->flags & SURF_SKY))) if (tr.fraction < 1.0) if (strncmp (tr.surface->name, "sky", 3) != 0) { if (isInAir) { // wall push kick VectorCopy (tr.plane.normal, tempVel); VectorNormalize (tempVel); VectorScale (tempVel, 300, tempVel); tempVel[2] = 400; VectorCopy (tempVel, self->velocity); self->client->stunts=10; gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_CHAINFIST_SMOKE); gi.WritePosition (tr.endpos); gi.unicast (self, 0); gi.sound(self, CHAN_AUTO, gi.soundindex("infantry/melee2.wav"), 0.3, ATTN_IDLE, 0); gi.sound(self, CHAN_AUTO, gi.soundindex("chick/chkatck4.wav"), 0.4, ATTN_IDLE, 0); hitwall=1; } else { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_CHAINFIST_SMOKE); gi.WritePosition (tr.endpos); gi.unicast (self, 0); gi.sound(self, CHAN_AUTO, gi.soundindex("infantry/melee2.wav"), 0.3, ATTN_IDLE, 0); gi.sound(self, CHAN_AUTO, gi.soundindex("chick/chkatck4.wav"), 0.4, ATTN_IDLE, 0); hitwall=1; } } } if (self->waterlevel>2) { if ((int)(random()*4)==1) if (!hitwall) SP_Bubble (self, tr.endpos); } } void fire_smack (edict_t *ent, vec3_t start, vec3_t aimdir) { int kick = 10; int damage = 50+((int)(random()*50)); SmackHit (ent, start, aimdir, damage, kick, 0); } /* ==================== WALL CRAWLING!!! ==================== */ void ClimbWall (edict_t *ent) { vec3_t start; vec3_t forward, right; vec3_t offset; vec3_t from; vec3_t end; vec3_t tempAim, tempVel; trace_t tr; edict_t *ignore; int mask; qboolean water; int max = 40; int min = -90; int climbingspeed; AngleVectors (ent->client->v_angle, forward, right, NULL); VectorScale (forward, 0, ent->client->kick_origin); ent->client->kick_angles[0] = 0; VectorSet(offset, 0, 0, ent->viewheight-5); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); VectorMA (start, MELEE_DISTANCE*0.5, forward, end); VectorCopy (start, from); tr = gi.trace (from, NULL, NULL, end, ent, MASK_SHOT); //climbing code here with wall check... if (ent->client->aquasuit) climbingspeed=CLIMBSPEED; else climbingspeed=CLIMBSPEED*0.75; // return; //climbingspeed=0; if ((ent->client->v_angle[PITCH]>max)||(ent->client->v_angle[PITCH]flags & SURF_SKY))) if (tr.fraction < 1.0) { VectorClear (ent->velocity); ent->client->climbing = 1; ent->groundentity = NULL; VectorCopy (tr.plane.normal, tempVel); VectorNormalize (tempVel); VectorScale (tempVel, -100, tempVel); VectorCopy(tempVel, ent->velocity); ent->velocity[2]=climbingspeed; VectorCopy (ent->s.angles, tempVel); VectorNormalize (tempVel); VectorScale (tempVel, CLIMBSPEED/2, tempVel); VectorAdd(tempVel, ent->velocity,ent->velocity); if (!(level.framenum%2)) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_CHAINFIST_SMOKE); gi.WritePosition (tr.endpos); gi.unicast (ent, 0); gi.sound(ent, CHAN_AUTO, gi.soundindex("infantry/melee2.wav"), 0.2, ATTN_IDLE, 0); gi.sound(ent, CHAN_AUTO, gi.soundindex("chick/chkatck4.wav"), 0.15, ATTN_IDLE, 0); } } /* gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BFG_LASER); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (start, MULTICAST_PHS); //*/ } void WallRunRight (edict_t *ent) { vec3_t start, forward, right, left, offset, from, back; vec3_t end, tempAim, tempVel, dir; trace_t tr; edict_t *ignore; int mask; qboolean water; int RunSpeed = WALLRUNSPEED; AngleVectors (ent->client->v_angle, forward, right, NULL); VectorScale (forward, 0, ent->client->kick_origin); ent->client->kick_angles[0] = 0; VectorSet(offset, 0, 0, ent->viewheight-5); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); VectorScale(right,-1,left); VectorScale(forward, -1, back); VectorMA (start, MELEE_DISTANCE, right, end); VectorCopy (start, from); tr = gi.trace (from, NULL, NULL, end, ent, MASK_SHOT); if (!((tr.surface) && (tr.surface->flags & SURF_SKY))) if (tr.fraction < 1.0) { if (ent->Move_up) { gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 0.75, ATTN_NORM, 0); PlayerNoise(ent, ent->s.origin, PNOISE_SELF); VectorClear (ent->velocity); VectorCopy (left, tempVel); VectorNormalize (tempVel); VectorScale (tempVel, 300, tempVel); VectorCopy (forward, tempAim); VectorNormalize (tempAim); VectorScale (tempAim, 400, tempAim); VectorAdd(tempAim, tempVel, ent->velocity); ent->velocity[2] = 200; } else { ent->client->wallrunning = 1; ent->groundentity = NULL; VectorCopy (tr.plane.normal, tempVel); VectorNormalize (tempVel); VectorScale (tempVel, -100, tempVel); VectorClear (ent->velocity); if (!(level.framenum%4)) { ent->s.event = EV_FOOTSTEP; gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_CHAINFIST_SMOKE); gi.WritePosition (tr.endpos); gi.unicast (ent, 0); } VectorNormalize(forward); VectorNormalize(back); VectorScale(forward, RunSpeed, forward); VectorScale(back, RunSpeed, back); if (ent->Move_side>0) //right { ent->velocity[2]+= RunSpeed/2; } else if (ent->Move_side<0) //left { ent->velocity[2]-= RunSpeed/2; } if (ent->Move_forward>0) //for { VectorAdd(forward, ent->velocity, ent->velocity); } else if (ent->Move_forward<0) //back { VectorAdd(back, ent->velocity, ent->velocity); } } } } void WallRunLeft (edict_t *ent) { vec3_t start, forward, right, left, offset, from, back; vec3_t end, tempAim, tempVel, dir; trace_t tr; edict_t *ignore; int mask; qboolean water; int RunSpeed = WALLRUNSPEED; AngleVectors (ent->client->v_angle, forward, right, NULL); VectorScale (forward, 0, ent->client->kick_origin); ent->client->kick_angles[0] = 0; VectorSet(offset, 0, 0, ent->viewheight-5); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); VectorScale(right,-1,left); VectorScale(forward, -1, back); VectorMA (start, MELEE_DISTANCE, left, end); VectorCopy (start, from); tr = gi.trace (from, NULL, NULL, end, ent, MASK_SHOT); if (!((tr.surface) && (tr.surface->flags & SURF_SKY))) if (tr.fraction < 1.0) { if (ent->Move_up) { gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 0.75, ATTN_NORM, 0); PlayerNoise(ent, ent->s.origin, PNOISE_SELF); VectorClear (ent->velocity); VectorCopy (right, tempVel); VectorNormalize (tempVel); VectorScale (tempVel, 300, tempVel); VectorCopy (forward, tempAim); VectorNormalize (tempAim); VectorScale (tempAim, 400, tempAim); VectorAdd(tempAim, tempVel, ent->velocity); ent->velocity[2] = 200; } else { ent->client->wallrunning = -1; ent->groundentity = NULL; VectorCopy (tr.plane.normal, tempVel); VectorNormalize (tempVel); VectorScale (tempVel, -100, tempVel); VectorClear (ent->velocity); if (!(level.framenum%4)) { ent->s.event = EV_FOOTSTEP; gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_CHAINFIST_SMOKE); gi.WritePosition (tr.endpos); gi.unicast (ent, 0); } VectorNormalize(forward); VectorNormalize(back); VectorScale(forward, RunSpeed, forward); VectorScale(back, RunSpeed, back); if (ent->Move_side>0) //right { ent->velocity[2]-= RunSpeed/2; } else if (ent->Move_side<0) //left { ent->velocity[2]+= RunSpeed/2; } if (ent->Move_forward>0) //for { VectorAdd(forward, ent->velocity, ent->velocity); } else if (ent->Move_forward<0) //back { VectorAdd(back, ent->velocity, ent->velocity); } } } } /* ================= C-4 ================= */ void weapon_c4_fire (edict_t *ent) { vec3_t offset; vec3_t forward, right; vec3_t start; vec3_t aim; int damage = 2500; float timer; int speed; float radius; ent->client->kami=0; radius = 400; VectorSet(offset, 8, 8, ent->viewheight); AngleVectors (ent->client->v_angle, forward, right, NULL); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); timer = 10; speed = 400; fire_c4 (ent, start, forward, damage, speed, timer, radius, 0); } /* ================= laser and flashlight base ================= */ void light_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { G_FreeEdict (self); } void flashlight_on (edict_t *self, vec3_t start) { edict_t *bolt; int i; bolt = G_Spawn(); bolt->svflags = SVF_DEADMONSTER; VectorCopy (start, bolt->s.origin); VectorCopy (start, bolt->s.old_origin); bolt->movetype = MOVETYPE_NONE; bolt->clipmask = MASK_SHOT; bolt->solid = SOLID_BBOX; bolt->s.frame = 1; bolt->s.renderfx = RF_BEAM; //make brighter and bigger if client has cells to tap!! bolt->s.effects = EF_PLASMA; VectorClear (bolt->mins); VectorClear (bolt->maxs); bolt->s.modelindex = gi.modelindex ("sprites/s_bubble.sp2"); bolt->owner = self; bolt->nextthink = level.time; bolt->think = G_FreeEdict; bolt->classname = "bolt"; gi.linkentity (bolt); } void l_ball_on (edict_t *self, vec3_t start, int color) { edict_t *bolt; trace_t tr; bolt = G_Spawn(); bolt->svflags = SVF_DEADMONSTER; VectorCopy (start, bolt->s.origin); VectorCopy (start, bolt->s.old_origin); bolt->movetype = MOVETYPE_NONE; bolt->clipmask = MASK_SHOT; bolt->solid = SOLID_BBOX; VectorClear (bolt->mins); VectorClear (bolt->maxs); bolt->s.modelindex = gi.modelindex ("models/objects/flash/tris.md2"); bolt->s.frame = 0; if (color==RF_SHELL_GREEN) bolt->s.frame = 1; //bolt->s.effects = EF_COLOR_SHELL; bolt->s.effects|= EF_SPHERETRANS; bolt->s.renderfx = color; //bolt->s.renderfx|= RF_BEAM; bolt->owner = self; bolt->nextthink = level.time; bolt->think = G_FreeEdict; bolt->classname = "bolt"; gi.linkentity (bolt); } void FireLaser (edict_t *ent, vec3_t end, vec3_t start, vec3_t aimdir, int color, int width, int dmg) { edict_t *beam; beam = G_Spawn(); beam->movetype = MOVETYPE_NONE; beam->activator = beam; //ent; beam->solid = SOLID_NOT; beam->s.renderfx = RF_BEAM|RF_TRANSLUCENT; beam->s.modelindex = 1; beam->classname = "laser_sight_beam"; beam->s.frame = width; //width beam->owner = beam; beam->s.skinnum = color; //color beam->dmg = dmg; beam->think = G_FreeEdict; beam->delay = level.time; beam->flamed = ent; if (beam->dmg<1) beam->lt_on = 123; VectorCopy(end, beam->end_pt); // Set orgin of laser to point of contact with wall VectorCopy(start, beam->s.origin); // convert normal at point of contact to laser angles vectoangles(aimdir, beam->s.angles); // setup laser movedir (projection of laser) G_SetMovedir (beam->s.angles, beam->movedir); VectorSet (beam->mins, -1, -1, -1); VectorSet (beam->maxs, 1, 1, 1); gi.linkentity (beam); target_laser_on (beam); } static void flashlight (edict_t *ent, vec3_t start, vec3_t aimdir) { vec3_t from; vec3_t end; trace_t tr; edict_t *ignore; int mask; int distance = (ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))])? 1000: 500; VectorMA (start, distance, aimdir, end); VectorCopy (start, from); ignore = ent; mask = CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER; //mask= MASK_SOLID; tr = gi.trace (from, NULL, NULL, end, ignore, mask); if (tr.ent) if (tr.ent->client) if(tr.ent->client->aquasuit) tr.ent->s.renderfx |= RF_TRANSLUCENT; if (ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_FLASHLIGHT); gi.WritePosition (tr.endpos); gi.WriteShort (ent - g_edicts); gi.multicast (tr.endpos, MULTICAST_PVS); if (level.framenum%15==0) ent->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]--; } else flashlight_on (ent, tr.endpos); } static void laser_ball (edict_t *ent, vec3_t start, vec3_t aimdir) { vec3_t from; vec3_t end; trace_t tr; edict_t *ignore; int mask, color; ent->client->laser_targeted = NULL; VectorMA (start, 8192, aimdir, end); VectorCopy (start, from); ignore = ent; mask= MASK_SHOT; tr = gi.trace (from, NULL, NULL, end, ignore, mask); if (!((tr.surface) && (tr.surface->flags & SURF_SKY))) if (tr.fraction < 1.0) if (strncmp (tr.surface->name, "sky", 3) != 0) { color = RF_SHELL_RED; if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client)) if ((tr.ent->takedamage) && (tr.ent != ent->owner)) if (tr.ent->health>0) { color = RF_SHELL_GREEN; ent->client->laser_targeted = tr.ent; } l_ball_on (ent, tr.endpos, color); } VectorCopy (tr.endpos, ent->client->laser_ptr); } static void laser (edict_t *ent, vec3_t start, vec3_t aimdir, int color_num, int width, int dmg) { vec3_t from; vec3_t end; vec3_t strt; trace_t tr; edict_t *ignore; int mask; int color[] = { 0xf2f2f0f0, 0xd0d1d2d3, 0xf3f3f1f1, 0xdcdddedf, 0xe0e1e2e3, 0x80818283, 0x70717273, 0x90919293, 0xb0b1b2b3, 0x40414243, 0xe2e5e3e6, 0xd0f1d3f3, 0xf2f3f0f1, 0xf3f2f1f0, 0xdad0dcd2, 0xd0dad2dc }; VectorMA (start, 8192, aimdir, end); VectorCopy (start, from); ignore = ent; mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA; tr = gi.trace (from, NULL, NULL, end, ignore, mask); VectorCopy (tr.endpos, from); VectorCopy (start, strt); VectorCopy (tr.endpos, ent->client->laser_ptr); FireLaser (ent, tr.endpos, strt, aimdir, color[color_num], width, dmg); } static void laser_bfg (edict_t *ent, vec3_t start, vec3_t aimdir) { vec3_t from; vec3_t end; trace_t tr; edict_t *ignore; int mask; VectorMA (start, 8192, aimdir, end); VectorCopy (start, from); ignore = ent; mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA; tr = gi.trace (from, NULL, NULL, end, ignore, mask); VectorCopy (tr.endpos, from); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BFG_LASER); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (start, MULTICAST_PHS); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BUBBLETRAIL); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (tr.endpos, MULTICAST_PHS); } static void lame_laser (edict_t *ent, vec3_t start, vec3_t aimdir) { vec3_t from; vec3_t end; trace_t tr; edict_t *ignore; int mask; VectorMA (start, 8192, aimdir, end); VectorCopy (start, from); ignore = ent; mask = MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA; tr = gi.trace (from, NULL, NULL, end, ignore, mask); VectorCopy (tr.endpos, from); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BFG_LASER); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (tr.endpos, MULTICAST_PHS); } /* ================= fire_flashlight fire_laser ================= */ void fire_flashlight (edict_t *self, vec3_t start, vec3_t aimdir) { flashlight (self, start, aimdir); } void fire_laser_ball (edict_t *self, vec3_t start, vec3_t aimdir) { laser_ball (self, start, aimdir); } void fire_laser (edict_t *self, vec3_t start, vec3_t aimdir, int color, int width, int dmg) { //laser (self, start, aimdir, color_num, width) laser (self, start, aimdir, color, width, dmg); } /* ====================================================================== FLASHLIGHT AND LASER SIGHT REAL USE ====================================================================== */ void weapon_flashlight_fire (edict_t *ent) { vec3_t start; vec3_t forward, right; vec3_t offset; AngleVectors (ent->client->v_angle, forward, right, NULL); VectorScale (forward, 0, ent->client->kick_origin); ent->client->kick_angles[0] = 0; VectorSet(offset, 0, 7, ent->viewheight-8); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); fire_flashlight (ent, start, forward); } void weapon_fire_laser_bfg_dmg (edict_t *self, vec3_t start, vec3_t aimdir, int damage) { vec3_t from; vec3_t end; trace_t tr; edict_t *ignore; int mask; qboolean water; int effect, effect2; int kick = 1000; VectorMA (start, 8192, aimdir, end); VectorCopy (start, from); ignore = self; 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; } else { if ((tr.ent != self) && (tr.ent->takedamage)) T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_BFG_LASER); } if (!((tr.surface) && (tr.surface->flags & SURF_SKY))) if (tr.fraction < 1.0) if (strncmp (tr.surface->name, "sky", 3) != 0) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_CHAINFIST_SMOKE); gi.WritePosition (tr.endpos); gi.unicast (self, 0); } } void weapon_fire_laser_bfg (edict_t *ent) { vec3_t start, xStart, xFwd; vec3_t forward, right; vec3_t offset; int damage; AngleVectors (ent->client->v_angle, forward, right, NULL); VectorScale (forward, 0, ent->client->kick_origin); ent->client->kick_angles[0] = 0; VectorSet(offset, 10, 8, ent->viewheight-10); //VectorSet(offset, 0, 7, ent->viewheight-8); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); VectorCopy(start, xStart); VectorCopy(forward, xFwd); damage = 50+((int)(ent->client->bfg_firing)*50); weapon_fire_laser_bfg_dmg (ent, xStart, xFwd, damage); if (sv_laser_type->value>0) { if (ent->bfg_laser_type==BFG_LASER_RED) { if (ent->client->bfg_firing>7) { fire_laser (ent, xStart, xFwd, 3, 2, 0); fire_laser (ent, xStart, xFwd, 10, 4, 0); fire_laser (ent, xStart, xFwd, 9,6, 0); fire_laser (ent, xStart, xFwd, 0, 8, 0); } else if (ent->client->bfg_firing>5) { fire_laser (ent, xStart, xFwd, 10, 2, 0); fire_laser (ent, xStart, xFwd, 9,4, 0); fire_laser (ent, xStart, xFwd, 0 ,6, 0); } else if (ent->client->bfg_firing>2) { fire_laser (ent, xStart, xFwd, 9, 2, 0); fire_laser (ent, xStart, xFwd, 0, 4, 0); } else { fire_laser (ent, xStart, xFwd, 0, 2, 0); } } else if (ent->bfg_laser_type==BFG_LASER_BLUE) { if (ent->client->bfg_firing>7) { fire_laser (ent, xStart, xFwd, 5, 2, 0); fire_laser (ent, xStart, xFwd, 8, 4, 0); fire_laser (ent, xStart, xFwd, 6,6, 0); fire_laser (ent, xStart, xFwd, 2, 8, 0); } else if (ent->client->bfg_firing>5) { fire_laser (ent, xStart, xFwd, 8, 2, 0); fire_laser (ent, xStart, xFwd, 6,4, 0); fire_laser (ent, xStart, xFwd, 2 ,6, 0); } else if (ent->client->bfg_firing>2) { fire_laser (ent, xStart, xFwd, 6, 2, 0); fire_laser (ent, xStart, xFwd, 2, 4, 0); } else { fire_laser (ent, xStart, xFwd, 2, 2, 0); } } else if (ent->bfg_laser_type==BFG_LASER_GREEN) { if (ent->client->bfg_firing>7) { fire_laser (ent, xStart, xFwd, 15, 2, 0); fire_laser (ent, xStart, xFwd, 14, 4, 0); fire_laser (ent, xStart, xFwd, 7,6, 0); fire_laser (ent, xStart, xFwd, 1, 8, 0); } else if (ent->client->bfg_firing>5) { fire_laser (ent, xStart, xFwd, 14, 2, 0); fire_laser (ent, xStart, xFwd, 7,4, 0); fire_laser (ent, xStart, xFwd, 1 ,6, 0); } else if (ent->client->bfg_firing>2) { fire_laser (ent, xStart, xFwd, 7, 2, 0); fire_laser (ent, xStart, xFwd, 1, 4, 0); } else { fire_laser (ent, xStart, xFwd, 1, 2, 0); } } } else { laser_bfg (ent, xStart, xFwd); } } void weapon_fire_laser (edict_t *ent) { vec3_t start, xStart, xFwd; vec3_t forward, right; vec3_t offset; int LASERWIDTH = 2; AngleVectors (ent->client->v_angle, forward, right, NULL); VectorScale (forward, 0, ent->client->kick_origin); ent->client->kick_angles[0] = 0; VectorSet(offset, 10, 8, ent->viewheight-10); //VectorSet(offset, 0, 7, ent->viewheight-8); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); VectorCopy(start, xStart); VectorCopy(forward, xFwd); if (ent->client->weaphold==4&&!ent->client->mach_set) xFwd[2]+= (ent->client->machinegun_shots)*0.025 ; /*// Laser Beam Color Codes 0 Laser_Red 0xf2f2f0f0 // bright red 1 Laser_Green 0xd0d1d2d3 // bright green 2 Laser_Blue 0xf3f3f1f1 // bright blue 3 Laser_Yellow 0xdcdddedf // bright yellow 4 Laser_YellowS 0xe0e1e2e3 // yellow strobe 5 Laser_DkPurple 0x80818283 // dark purple 6 Laser_LtBlue 0x70717273 // light blue 7 Laser_Green2 0x90919293 // different green 8 Laser_Purple 0xb0b1b2b3 // purple 9 Laser_Red2 0x40414243 // different red 10 Laser_Orange 0xe2e5e3e6 // orange 11 Laser_Mix 0xd0f1d3f3 // mixture 12 Laser_RedBlue 0xf2f3f0f1 // inner = red, outer = blue 13 Laser_BlueRed 0xf3f2f1f0 // inner = blue, outer = red 14 Laser_GreenY 0xdad0dcd2 // inner = green, outer = yellow 15 Laser_YellowG 0xd0dad2dc // inner = yellow, outer = green //*/ //fire_laser self, start, aimdir, color, width, dmg) if (ent->client->pers.weapon==NULL) { return; } if (!sv_serversideonly->value) { vec3_t end, forward, right, start, offset = {0, 0, ent->viewheight}; trace_t tr; switch (ent->client->weaphold) { case 1: //blaster case 2: //shotgun case 3: //super shotgun case 4: //machinegun case 9: //railgun case 7: //rocket - dumb fire case 11: //rocket - homing break; default: ent->client->lasersight_dot = NULL; return; break; } AngleVectors (ent->client->v_angle, forward, right, NULL); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); VectorMA(start, 8096, forward, end); tr = gi.trace(start, NULL, NULL, end, ent, MASK_SHOT); VectorNegate(forward, forward); VectorMA(tr.endpos, 10, forward, end); if (tr.surface && (tr.surface->flags & SURF_SKY)) { ent->client->lasersight_dot = NULL; return; } if (!ent->client->lasersight_dot) ent->client->lasersight_dot = G_Spawn(); ent->client->lasersight_dot->s.modelindex = gi.modelindex("sprites/s_reddot.sp2"); ent->client->lasersight_dot->s.renderfx = RF_TRANSLUCENT; ent->client->lasersight_dot->clipmask = 0; ent->client->lasersight_dot->movetype = MOVETYPE_NONE; ent->client->lasersight_dot->solid = SOLID_NOT; ent->client->lasersight_dot->nextthink = level.time + FRAMETIME*2; ent->client->lasersight_dot->think = G_FreeEdict; VectorCopy (end, ent->client->lasersight_dot->s.origin); VectorCopy (end, ent->client->lasersight_dot->s.old_origin); VectorMA(ent->client->lasersight_dot->s.origin, 20, forward, ent->client->laser_ptr); if (ent->client->weaphold==11) { if (tr.ent && (tr.ent->svflags & SVF_MONSTER) || (tr.ent->client)) ent->client->lasersight_dot->s.frame = 2; else ent->client->lasersight_dot->s.frame = 1; } else ent->client->lasersight_dot->s.frame = 0; gi.linkentity (ent->client->lasersight_dot); return; } if (ent->client->weaphold==11) { fire_laser_ball (ent, xStart, xFwd); return; } if (sv_laser_type->value==2||sv_laser_type->value==3) { if (coop->value || deathmatch->value || true) { switch (ent->client->weaphold) { case 0: //hand grenade break; case 1: //blaster fire_laser (ent, xStart, xFwd, 0, LASERWIDTH, 0); break; case 2: //shotgun fire_laser (ent, xStart, xFwd, 0, LASERWIDTH, 0); break; case 3: //super shotgun fire_laser (ent, xStart, xFwd, 0, LASERWIDTH, 0); break; case 4: //machinegun fire_laser (ent, xStart, xFwd, 0, LASERWIDTH, 0); break; case 5: //chaingun fire_laser (ent, xStart, xFwd, 0, LASERWIDTH, 0); break; case 6: //grenade launcher break; case 7: //rocket launcher break; case 8: //hyperblaster break; case 9: //railgun fire_laser (ent, xStart, xFwd, 0, LASERWIDTH, 0); break; case 10: //bfg break; default: break; } } } else if (sv_laser_type->value!=1) { lame_laser (ent, xStart, xFwd); } if (sv_laser_type->value==1||sv_laser_type->value==3) if (ent->client->weaphold==1||ent->client->weaphold==2||ent->client->weaphold==3|| ent->client->weaphold==5||ent->client->weaphold==9) fire_laser_ball (ent, xStart, xFwd); } /* ====================================================================== GRAPPLING HOOK - MY CODE !!! ====================================================================== */ void makeLink(vec3_t dir, vec3_t origin, char * model, int frame, int up, int side, int roll) { vec3_t point; edict_t *link; link = G_Spawn(); VectorCopy (dir, point); point[PITCH]+= up ;// up / down point[YAW] += side ;// left / right point[ROLL] += roll ;// fall over VectorCopy (origin, link->s.origin); vectoangles (point, link->s.angles); gi.setmodel (link, model); link->s.frame = frame; link->s.skinnum = 0; link->movetype = MOVETYPE_NONE; link->solid = SOLID_NOT; link->think = G_FreeEdict; link->nextthink = level.time + FRAMETIME; link->classname = "chain_link"; link->takedamage = DAMAGE_NO; gi.linkentity (link); } void DrawChain( vec3_t start, vec3_t end2) { trace_t tr; vec3_t temp, dir, end; int SegmentLength=100; int length, i=0; VectorCopy(end2, end); VectorSubtract(end, start, temp); length = abs(VectorLength(temp)); VectorCopy(temp, dir); VectorNormalize (dir); while ( (i*SegmentLength)owner->s.origin, NULL, NULL, ent->s.origin, ent->owner, MASK_SHOT); ent->think = grapple_done; ent->nextthink = level.time; if (ent->grapple==LITHIUM_GRAPPLE) { ent->owner->client->grapple=0; G_FreeEdict (ent); return; } if (ent->linkedto) { ent->linkedto->s.origin[0]=ent->s.origin[0]; ent->linkedto->s.origin[1]=ent->s.origin[1]; ent->linkedto->s.origin[2]=ent->s.origin[2]; } VectorSubtract (ent->owner->s.origin, ent->s.origin, dir); if (VectorLength(dir)<250) speed_mult*=0.5; if (VectorLength(dir)<75) { ent->owner->client->grapple=0; G_FreeEdict (ent); return; } else { gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/mach1.wav"), 1, ATTN_NORM, 0); } VectorNormalize (dir); vectoangles (dir, ent->s.angles); VectorClear (ent->velocity); VectorScale (dir, GRAPPLESPEED*speed_mult, ent->velocity); ent->timer++; if (ent->timer>10) // if a second has passed... { ent->owner->client->grapple=0; G_FreeEdict (ent); return; } if (ent->owner->health<=0) { ent->owner->client->grapple=0; G_FreeEdict (ent); return; } if (ent->grappleType==GRAPPLE_ROPE) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_MEDIC_CABLE_ATTACK); gi.WriteShort (ent->owner - g_edicts); gi.WritePosition (ent->owner->s.origin); gi.WritePosition (ent->s.origin); gi.multicast (ent->owner->s.origin, MULTICAST_PVS); } else if (ent->grappleType==GRAPPLE_LASER) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BFG_LASER); gi.WritePosition (ent->owner->s.origin); gi.WritePosition (tr.endpos); gi.multicast (tr.endpos, MULTICAST_PHS); } else if (ent->grappleType==GRAPPLE_CHAIN) { DrawChain(ent->owner->s.origin, tr.endpos); } else if (ent->grappleType==GRAPPLE_SHIP2) { DrawShip2(ent->owner->s.origin, tr.endpos); } else if (ent->grappleType==GRAPPLE_SHIP1) { DrawShip1(ent->owner->s.origin, tr.endpos); } } void grapple_touch_null (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { } void grapple_think (edict_t *ent) { trace_t tr; //!! tr = gi.trace (ent->owner->s.origin, NULL, NULL, ent->s.origin, ent->owner, MASK_SHOT); ent->think = grapple_think; ent->nextthink = level.time; if (ent->grapple==PSYCHOMOD_GRAPPLE) if (tr.fraction < 1.0) if (tr.ent != ent) { ent->touch = grapple_touch_null; ent->owner->client->grapple=2; ent->think = grapple_done; ent->movetype = MOVETYPE_FLYMISSILE; ent->solid = SOLID_NOT; ent->timer = 0; } if (ent->owner->client->grapple!=1) { ent->touch = grapple_touch_null; ent->owner->client->grapple=2; ent->think = grapple_done; ent->movetype = MOVETYPE_FLYMISSILE; ent->solid = SOLID_NOT; ent->timer = 0; } if (ent->owner->health<=0) { G_FreeEdict (ent); return; } // VectorSubtract (tr.endpos, start, dir); // VectorNormalize (dir); //add some grav //ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME * 0.25; if (ent->grappleType==GRAPPLE_ROPE) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_MEDIC_CABLE_ATTACK); gi.WriteShort (ent->owner - g_edicts); gi.WritePosition (ent->owner->s.origin); gi.WritePosition (ent->s.origin); gi.multicast (ent->owner->s.origin, MULTICAST_PVS); } else if (ent->grappleType==GRAPPLE_LASER) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BFG_LASER); gi.WritePosition (ent->owner->s.origin); gi.WritePosition (tr.endpos); gi.multicast (tr.endpos, MULTICAST_PHS); } else if (ent->grappleType==GRAPPLE_CHAIN) { DrawChain(ent->owner->s.origin, tr.endpos); } else if (ent->grappleType==GRAPPLE_SHIP2) { DrawShip2(ent->owner->s.origin, tr.endpos); } else if (ent->grappleType==GRAPPLE_SHIP1) { DrawShip1(ent->owner->s.origin, tr.endpos); } } void grapple_linked (edict_t *ent) { vec3_t dir, dir2, lastvel; trace_t tr; //!! int speed=GRAPPLESPEED*.5; tr = gi.trace (ent->owner->s.origin, NULL, NULL, ent->s.origin, ent->owner, MASK_SHOT); ent->think = grapple_linked; ent->nextthink = level.time; VectorSubtract (ent->s.origin, ent->owner->s.origin, dir); if (VectorLength(dir)<30) { speed*=0.25; VectorScale (ent->owner->velocity, 0.25, lastvel); } else if (VectorLength(dir)<60) { speed*=0.5; VectorScale (ent->owner->velocity, 0.5, lastvel); } else if (VectorLength(dir)<90) { speed*=0.75; gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/mach1.wav"), 1, ATTN_NORM, 0); VectorScale (ent->owner->velocity, 0.75, lastvel); } else { gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/mach1.wav"), 1, ATTN_NORM, 0); VectorScale (ent->owner->velocity, 1, lastvel); } VectorNormalize (dir); if (ent->owner->grapple==ROPE_GRAPPLE) { speed*=0.25; VectorScale (dir, speed, dir2); VectorAdd (lastvel, dir2, ent->owner->velocity); //*/ } else if (ent->owner->grapple==PSYCHOMOD_GRAPPLE||ent->owner->grapple==LITHIUM_GRAPPLE) { VectorScale (dir, speed, ent->owner->velocity); } if (ent->grapple==PSYCHOMOD_GRAPPLE) if (tr.fraction < 1.0) if (tr.ent != ent) { ent->touch = grapple_touch_null; ent->owner->client->grapple=2; ent->think = grapple_done; ent->movetype = MOVETYPE_FLYMISSILE; ent->solid = SOLID_NOT; ent->clipmask = 0; ent->timer = 0; } if (ent->owner->client->grapple!=1) { ent->touch = grapple_touch_null; ent->owner->client->grapple=2; ent->think = grapple_done; ent->movetype = MOVETYPE_FLYMISSILE; ent->solid = SOLID_NOT; ent->clipmask = 0; ent->timer = 0; } if (ent->owner->health<=0) { ent->owner->client->grapple=0; G_FreeEdict (ent); return; } //add some grav //ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME * 0.01; if (ent->grappleType==GRAPPLE_ROPE) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_MEDIC_CABLE_ATTACK); gi.WriteShort (ent->owner - g_edicts); gi.WritePosition (ent->owner->s.origin); gi.WritePosition (ent->s.origin); gi.multicast (ent->owner->s.origin, MULTICAST_PVS); } else if (ent->grappleType==GRAPPLE_LASER) { gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BFG_LASER); gi.WritePosition (ent->owner->s.origin); gi.WritePosition (tr.endpos); gi.multicast (tr.endpos, MULTICAST_PHS); } else if (ent->grappleType==GRAPPLE_CHAIN) { DrawChain(ent->owner->s.origin, tr.endpos); } else if (ent->grappleType==GRAPPLE_SHIP2) { DrawShip2(ent->owner->s.origin, tr.endpos); } else if (ent->grappleType==GRAPPLE_SHIP1) { DrawShip1(ent->owner->s.origin, tr.endpos); } } void grapple_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { // int mod; if (other == self->owner) return; if (surf && (surf->flags & SURF_SKY)) { self->touch = grapple_touch_null; self->owner->client->grapple=2; self->think = grapple_done; self->movetype = MOVETYPE_FLYMISSILE; self->solid = SOLID_NOT; self->timer = 0; return; } if (self->owner->client) PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT); if (other->takedamage) { T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 0, 0, MOD_GRAPPLE); self->touch = grapple_touch_null; self->owner->client->grapple=2; self->think = grapple_done; self->movetype = MOVETYPE_FLYMISSILE; self->solid = SOLID_NOT; self->timer = 0; self->linkedto=NULL; } else if (other->item) { self->linkedto=other; self->touch = grapple_touch_null; self->owner->client->grapple=2; self->think = grapple_done; self->movetype = MOVETYPE_FLYMISSILE; self->solid = SOLID_NOT; self->timer = 0; } else { self->linkedto=NULL; gi.sound (self, CHAN_VOICE, gi.soundindex ("weapons/grenlb1b.wav"), 1, ATTN_NORM, 0); self->movetype= MOVETYPE_NONE; self->think = grapple_linked; self->nextthink = level.time; } } void fire_grapple (edict_t *self, vec3_t start, vec3_t dir, int speed) { edict_t *bolt; trace_t tr; VectorNormalize (dir); bolt = G_Spawn(); bolt->svflags = SVF_DEADMONSTER;; VectorCopy (start, bolt->s.origin); VectorCopy (start, bolt->s.old_origin); vectoangles (dir, bolt->s.angles); VectorScale (dir, speed, bolt->velocity); bolt->movetype = MOVETYPE_FLYMISSILE; bolt->clipmask = MASK_SHOT; bolt->solid = SOLID_BBOX; bolt->s.modelindex = gi.modelindex ("models/objects/debris2/tris.md2"); // if (self->grappleType==GRAPPLE_CHAIN) // bolt->s.modelindex = gi.modelindex ("models/objects/gibs/head/tris.md2"); VectorClear (bolt->mins); VectorClear (bolt->maxs); bolt->owner = self; bolt->touch = grapple_touch; bolt->nextthink = level.time; bolt->think = grapple_think; bolt->dmg = 34; bolt->classname = "bolt"; bolt->grapple=self->grapple; bolt->grappleType = self->grappleType; bolt->IsGrapple = 1; if (self->grappleType==GRAPPLE_LASER) { bolt->s.effects|= EF_SPHERETRANS; bolt->s.renderfx = RF_SHELL_GREEN; } if (self->grappleType==GRAPPLE_SHIP2 || self->grappleType==GRAPPLE_SHIP1) { bolt->s.renderfx = RF_BEAM; } bolt->spawnflags = 1; gi.linkentity (bolt); self->client->grapple_on=bolt; if (self->client) check_dodge (self, bolt->s.origin, dir, speed); tr = gi.trace (self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT); if (tr.fraction < 1.0) { VectorMA (bolt->s.origin, -10, dir, bolt->s.origin); bolt->touch (bolt, tr.ent, NULL, NULL); } } void weapon_fire_grapple (edict_t *ent) { vec3_t start; vec3_t forward, right; vec3_t offset; if (ent->client->resp.spectator) return; AngleVectors (ent->client->v_angle, forward, right, NULL); VectorScale (forward, 0, ent->client->kick_origin); ent->client->kick_angles[0] = 0; //VectorSet(offset, 0, 7, ent->viewheight-8); //VectorSet(offset, 20, -8, ent->viewheight-10); VectorSet(offset, 20, 0, ent->viewheight-10); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); fire_grapple (ent, start, forward, GRAPPLESPEED); gi.sound(ent, CHAN_AUTO, gi.soundindex("weapons/hgrent1a.wav"), 1, ATTN_NORM, 0); if (!ent->grapple) ent->grapple=PSYCHOMOD_GRAPPLE; } /* ====================================================================== MAGIC FOR BATTLESUIT SECONDARY FIRE!!! ====================================================================== */ void fire_magic (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick) { vec3_t from; vec3_t end; trace_t tr; edict_t *ignore; int mask; qboolean water; if ((self->health-=10)<=0) { self->flags &= ~FL_GODMODE; self->health = 0; meansOfDeath = MOD_SUICIDE; self->health=-1; player_die (self, self, self, 100, vec3_origin); } VectorMA (start, 8192, aimdir, end); VectorCopy (start, from); ignore = self; 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; } else { if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client) || (tr.ent->solid == SOLID_BBOX)) ignore = tr.ent; else ignore = NULL; if ((tr.ent != self) && (tr.ent->takedamage)) { int health = tr.ent->health; T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_MAGIC); if (tr.ent->health<=0 && health>0 && (tr.ent->client||tr.ent->svflags&SVF_MONSTER)) { VectorCopy (tr.ent->s.origin, self->s.origin); VectorCopy (tr.ent->s.origin, self->s.old_origin); // clear the velocity and hold them in place briefly VectorClear (tr.ent->velocity); gi.sound(tr.ent, CHAN_VOICE, gi.soundindex("chick/chkatck4.wav"), 1, ATTN_NORM, 0); gi.sound(tr.ent, CHAN_WEAPON, gi.soundindex("world/flesh1.wav"), 1, ATTN_NORM, 0); gi.sound(tr.ent, CHAN_ITEM, gi.soundindex("world/flesh2.wav"), 1, ATTN_NORM, 0); gi.sound(tr.ent, CHAN_BODY, gi.soundindex("makron/brain1.wav"), 1, ATTN_NORM, 0); KillBox (tr.ent); } } } // send gun puff / flash gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BUBBLETRAIL); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (self->s.origin, MULTICAST_PHS); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BUBBLETRAIL); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (self->s.origin, MULTICAST_PHS); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_BUBBLETRAIL2); gi.WritePosition (start); gi.WritePosition (tr.endpos); gi.multicast (self->s.origin, MULTICAST_PHS); } void fireMagic (edict_t *ent) { vec3_t start; vec3_t forward, right; vec3_t offset; vec3_t offset2, start2; float i; AngleVectors (ent->client->v_angle, forward, right, NULL); VectorScale (forward, -3, ent->client->kick_origin); ent->client->kick_angles[0] = -3; VectorSet(offset, 0, 7, ent->viewheight-8); VectorSet(offset2, 30, 6, ent->viewheight-2); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); P_ProjectSource (ent->client, ent->s.origin, offset2, forward, right, start2); fire_magic (ent, start, forward, 50, 50); gi.sound(ent, CHAN_AUTO, gi.soundindex("hover/hovatck1.wav"), 1.0, ATTN_IDLE, 0); ent->s.frame = FRAME_attack1-1; ent->client->anim_end = FRAME_attack8; } /* ====================================================================== Make Gas come... ====================================================================== */ void GasLive(edict_t * ent) { ent->s.frame = ent->timer; if (!ent->timer) G_FreeEdict(ent); ent->nextthink = level.time; ent->think = GasLive; ent->timer--; } void spawnGas(vec3_t start) { edict_t *bolt; trace_t tr; bolt = G_Spawn(); bolt->svflags = SVF_DEADMONSTER; VectorCopy (start, bolt->s.origin); VectorCopy (start, bolt->s.old_origin); bolt->movetype = MOVETYPE_FLY; bolt->clipmask = CONTENTS_AREAPORTAL; //MASK_SHOT; bolt->solid = SOLID_NOT; VectorClear (bolt->mins); VectorClear (bolt->maxs); bolt->s.modelindex = gi.modelindex ("models/objects/r_explode/tris.md2"); bolt->s.frame = 1; bolt->s.skinnum = 6; // bolt->s.effects = EF_SPHERETRANS; bolt->s.renderfx=RF_TRANSLUCENT; bolt->s.effects = EF_COLOR_SHELL | EF_SPHERETRANS; // bolt->s.renderfx = RF_SHELL_GREEN|RF_SHELL_RED|RF_SHELL_BLUE; bolt->nextthink = level.time; bolt->think = GasLive; bolt->classname = "bolt"; bolt->timer = 15; gi.linkentity (bolt); bolt->velocity[0]=40-random()*80; bolt->velocity[1]=40-random()*80; bolt->velocity[2]=30-random()*60; } /* ====================================================================== TAZER FOR SECONDAY RAIL FIRE ====================================================================== */ int tazerLength() { if (!deathmatch->value&&!coop->value) return TAZERLENGTHSP; return TAZERLENGTH; } void tazer_linked (edict_t *ent); void TazerLinkThink (edict_t *ent) { if (gi.pointcontents (ent->s.origin) & MASK_WATER) { gi.sound(ent, CHAN_AUTO, gi.soundindex("world/spark1.wav"), 0.3, ATTN_NORM, 0); T_RadiusDamageDischarge(ent, ent, 1, ent->owner, 300, MOD_DISCHARGE); } G_FreeEdict(ent); } void makeTazerLink(edict_t *ent, vec3_t dir, vec3_t origin, char * model, int framenum, int effect) { vec3_t point; edict_t *link; link = G_Spawn(); VectorCopy (dir, point); VectorCopy (origin, link->s.origin); vectoangles (point, link->s.angles); gi.setmodel (link, model); link->s.renderfx = RF_FULLBRIGHT; link->s.effects = EF_PLASMA; link->s.frame = 0; link->s.skinnum = effect; link->movetype = MOVETYPE_NONE; link->solid = SOLID_NOT; link->think = TazerLinkThink; link->nextthink = level.time + FRAMETIME; link->classname = "tazer_link"; link->takedamage = DAMAGE_YES; link->owner = ent->owner; gi.linkentity (link); if (effect==1) { link->s.renderfx = RF_FULLBRIGHT; link->s.effects = EF_FLAG2; } if (sv_serversideonly->value) { link->s.renderfx = effect; link->s.effects = EF_PLASMA; link->s.frame = 0; link->s.skinnum = 0; if (effect==RF_SHELL_BLUE) link->s.effects |= EF_FLAG2; } } void DrawTazer( edict_t *ent, vec3_t start, vec3_t end2) { trace_t tr; vec3_t temp, dir, end; int SegmentLength=30; int length, i=0; int effect; VectorCopy(end2, end); VectorSubtract(end, start, temp); length = abs(VectorLength(temp)); VectorCopy(temp, dir); VectorNormalize (dir); if (ent->phase<=0) ent->phase=4; while ( (i*SegmentLength)value) { if (ent->think==tazer_linked) { effect = 0; if ((int)(i+ent->phase)%5==0) effect = 1; } else effect = 0; } else { if (ent->think==tazer_linked) { effect = RF_SHELL_BLUE|RF_SHELL_GREEN|RF_SHELL_RED; if ((int)(i+ent->phase)%5==0) effect = RF_SHELL_BLUE; } else effect = RF_SHELL_BLUE|RF_SHELL_GREEN|RF_SHELL_RED; } VectorMA (start, SegmentLength*i, dir, end); tr = gi.trace (start, NULL, NULL, end, NULL, MASK_SHOT); if (i!=0 && i!=(length/SegmentLength) ) makeTazerLink(ent, dir, tr.endpos, "models/objects/tazer/tris.md2", i, effect); i++; } if (i==1) { VectorMA (start, (length*0.5), dir, end); tr = gi.trace (start, NULL, NULL, end, NULL, MASK_SHOT); makeTazerLink(ent, dir, tr.endpos, "models/objects/tazer/tris.md2", i, effect); } ent->phase--; } void tazer_done (edict_t *ent) { float speed_mult = 1; vec3_t dir, offset, start, forward, right; trace_t tr; //!! VectorSet(offset, 0, 7, ent->owner->viewheight-8); AngleVectors (ent->owner->client->v_angle, forward, right, NULL); P_ProjectSource (ent->owner->client, ent->owner->s.origin, offset, forward, right, start); tr = gi.trace (start, NULL, NULL, ent->s.origin, ent->owner, MASK_SHOT); ent->owner->client->ps.gunframe++; ent->think = tazer_done; ent->nextthink = level.time; VectorSubtract (start, ent->s.origin, dir); if (VectorLength(dir)<250) speed_mult*=0.5; if (VectorLength(dir)<75) { ent->owner->client->tazer=0; G_FreeEdict (ent); return; } else { //gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/mach1.wav"), 0.5, ATTN_NORM, 0); } VectorNormalize (dir); vectoangles (dir, ent->s.angles); VectorClear (ent->velocity); VectorScale (dir, GRAPPLESPEED*speed_mult, ent->velocity); ent->timer++; if (ent->timer>10) // if a second has passed... { ent->owner->client->tazer=0; G_FreeEdict (ent); return; } if (ent->owner->health<=0) { ent->owner->client->tazer=0; G_FreeEdict (ent); return; } DrawTazer(ent, start, tr.endpos); } void tazer_touch_null (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { } void tazer_think (edict_t *ent) { vec3_t dir, offset, start, forward, right; trace_t tr; //!! VectorSet(offset, 0, 7, ent->owner->viewheight-8); AngleVectors (ent->owner->client->v_angle, forward, right, NULL); P_ProjectSource (ent->owner->client, ent->owner->s.origin, offset, forward, right, start); tr = gi.trace (ent->owner->s.origin, NULL, NULL, ent->s.origin, ent->owner, MASK_SHOT); ent->think = tazer_think; ent->nextthink = level.time; VectorSubtract (start, ent->s.origin, dir); if (rand()>0.7) gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/spark1.wav"), 0.1, ATTN_NORM, 0); else if (rand()>0.7) gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/spark2.wav"), 0.1, ATTN_NORM, 0); else gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/spark3.wav"), 0.1, ATTN_NORM, 0); if (rand()>0.7) gi.sound(ent->linkedto, CHAN_AUTO, gi.soundindex("world/spark1.wav"), 0.1, ATTN_NORM, 0); else if (rand()>0.7) gi.sound(ent->linkedto, CHAN_AUTO, gi.soundindex("world/spark2.wav"), 0.1, ATTN_NORM, 0); else gi.sound(ent->linkedto, CHAN_AUTO, gi.soundindex("world/spark3.wav"), 0.1, ATTN_NORM, 0); if (tr.ent) if (tr.ent->takedamage) { ent->touch = tazer_touch_null; ent->linkedto=tr.ent; ent->movetype= MOVETYPE_NONE; ent->solid = SOLID_NOT; ent->timer = 0; ent->think = tazer_linked; ent->nextthink = level.time; DrawTazer(ent, start, tr.endpos); return; } if (tr.fraction < 1.0) if (tr.ent != ent) { ent->touch = tazer_touch_null; ent->owner->client->tazer=2; ent->think = tazer_done; ent->movetype = MOVETYPE_FLYMISSILE; ent->solid = SOLID_NOT; ent->timer = 0; gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/airhiss1.wav"), 1, ATTN_NORM, 0); } if ((VectorLength(dir)>tazerLength())||(ent->owner->client->tazer==10)) { ent->touch = tazer_touch_null; ent->owner->client->tazer=2; ent->think = tazer_done; ent->movetype = MOVETYPE_FLYMISSILE; ent->solid = SOLID_NOT; ent->timer = 0; gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/airhiss1.wav"), 1, ATTN_NORM, 0); } if (ent->owner->health<=0) { G_FreeEdict (ent); return; } DrawTazer(ent, start, tr.endpos); } void tazer_linked (edict_t *ent) { vec3_t dir, dir2, offset, start, forward, right; trace_t tr; VectorSet(offset, 0, 7, ent->owner->viewheight-8); AngleVectors (ent->owner->client->v_angle, forward, right, NULL); P_ProjectSource (ent->owner->client, ent->owner->s.origin, offset, forward, right, start); // tr = gi.trace (start, NULL, NULL, ent->linkedto->s.origin, ent->owner, CONTENTS_SOLID|CONTENTS_MONSTER); VectorCopy(ent->linkedto->s.origin, ent->s.origin); VectorSubtract (start, ent->s.origin, dir); ent->think = tazer_linked; ent->nextthink = level.time; if (tr.ent&&(tr.ent != ent->linkedto)) { ent->linkedto=tr.ent; ent->timer = 0; } //* else if (tr.fraction < 1.0) { if (tr.ent != ent->linkedto) { ent->touch = tazer_touch_null; ent->owner->client->tazer=2; ent->think = tazer_done; ent->movetype = MOVETYPE_FLYMISSILE; ent->solid = SOLID_NOT; ent->clipmask = 0; ent->timer = 0; gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/airhiss1.wav"), 1, ATTN_NORM, 0); } } //*/ /* if (tr.ent != ent) { ent->touch = tazer_touch_null; ent->owner->client->tazer=2; ent->think = tazer_done; ent->movetype = MOVETYPE_FLYMISSILE; ent->solid = SOLID_NOT; ent->clipmask = 0; ent->timer = 0; } //*/ if ((ent->linkedto->health<=0)||(VectorLength(dir)>tazerLength())||(ent->owner->client->tazer==10) || (ent->owner->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]<=0)) { ent->touch = tazer_touch_null; ent->owner->client->tazer=2; ent->think = tazer_done; ent->movetype = MOVETYPE_FLYMISSILE; ent->solid = SOLID_NOT; ent->clipmask = 0; ent->timer = 0; gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/airhiss1.wav"), 1, ATTN_NORM, 0); } //****ADD SOUND*** if (rand()>0.7) gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/spark1.wav"), 0.8, ATTN_NORM, 0); else if (rand()>0.7) gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/spark2.wav"), 0.9, ATTN_NORM, 0); else gi.sound(ent->owner, CHAN_AUTO, gi.soundindex("world/spark3.wav"), 0.8, ATTN_NORM, 0); if (rand()>0.7) gi.sound(ent->linkedto, CHAN_AUTO, gi.soundindex("world/spark1.wav"), 0.5, ATTN_NORM, 0); else if (rand()>0.7) gi.sound(ent->linkedto, CHAN_AUTO, gi.soundindex("world/spark2.wav"), 0.4, ATTN_NORM, 0); else gi.sound(ent->linkedto, CHAN_AUTO, gi.soundindex("world/spark3.wav"), 0.5, ATTN_NORM, 0); ent->linkedto->velocity[0]*=0.1; ent->linkedto->velocity[1]*=0.1; T_Damage (ent->linkedto, ent, ent->owner, ent->velocity, ent->s.origin, ent->s.origin, ent->dmg, 0, 0, MOD_TAZER); if (ent->timer==2) { if (!((int)dmflags->value & DF_INFINITE_AMMO)) ent->owner->client->pers.inventory[ITEM_INDEX(FindItem("cells"))]--; ent->timer=0; } else ent->timer++; if (ent->owner->health<=0) { ent->owner->client->tazer=0; G_FreeEdict (ent); return; } //add some grav //ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME * 0.01; DrawTazer(ent, start, tr.endpos); } void tazer_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { // int mod; if (other == self->owner) return; if (surf && (surf->flags & SURF_SKY)) { self->touch = tazer_touch_null; self->owner->client->tazer=2; self->think = tazer_done; self->movetype = MOVETYPE_FLYMISSILE; self->solid = SOLID_NOT; self->timer = 0; gi.sound(self->owner, CHAN_AUTO, gi.soundindex("world/airhiss1.wav"), 1, ATTN_NORM, 0); return; } if (self->owner->client) PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT); if (other->takedamage&&((other->client)||(other->svflags & SVF_MONSTER))) { self->touch = tazer_touch_null; self->linkedto=other; self->movetype= MOVETYPE_NONE; self->solid = SOLID_NOT; self->timer = 0; self->think = tazer_linked; self->nextthink = level.time; } else if (other->takedamage) { self->touch = tazer_touch_null; T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 0, 0, MOD_TAZER); } else { self->touch = tazer_touch_null; // self->owner->client->tazer=2; // self->think = tazer_done; // self->movetype = MOVETYPE_FLYMISSILE; self->movetype = MOVETYPE_NONE; self->solid = SOLID_NOT; self->timer = 0; } } void fire_tazer (edict_t *self, vec3_t start, vec3_t dir, int speed) { edict_t *bolt; trace_t tr; VectorNormalize (dir); bolt = G_Spawn(); bolt->svflags = SVF_DEADMONSTER;; VectorCopy (start, bolt->s.origin); VectorCopy (start, bolt->s.old_origin); vectoangles (dir, bolt->s.angles); VectorScale (dir, speed, bolt->velocity); bolt->movetype = MOVETYPE_FLYMISSILE; bolt->clipmask = MASK_SHOT; bolt->solid = SOLID_BBOX; bolt->s.modelindex = gi.modelindex ("models/objects/debris2/tris.md2"); VectorClear (bolt->mins); VectorClear (bolt->maxs); bolt->owner = self; bolt->touch = tazer_touch; bolt->nextthink = level.time; bolt->think = tazer_think; bolt->dmg = 15; bolt->classname = "bolt"; bolt->IsTazer = 1; // bolt->s.effects = EF_SPHERETRANS; // bolt->s.renderfx = RF_SHELL_BLUE|RF_SHELL_GREEN|RF_SHELL_RED; bolt->s.renderfx = RF_BEAM; bolt->spawnflags = 1; gi.linkentity (bolt); self->client->tazer_on=bolt; if (self->client) check_dodge (self, bolt->s.origin, dir, speed); tr = gi.trace (self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT); if (tr.fraction < 1.0) { VectorMA (bolt->s.origin, -10, dir, bolt->s.origin); bolt->touch (bolt, tr.ent, NULL, NULL); } } //******************************************************* // // MY HARDCORE CUSTOM FLIGHT CODE -- PSYCHOSPAZ // //******************************************************* void flight_check (edict_t * ent) { int i; if (ent->client->grapple_on) if (ent->client->grapple_on->think==grapple_linked) return; if (sv_waterlevel->value||(ent->client->goggles && ent->waterlevel>1)||(ent->client->jets)) { vec3_t temp, tempSide, tempSmokeDir, tempUp; vec3_t SidMove, ForMove; int speedMax = abs(ent->Move_forward)/400; int speedMult = 20; int MaxSpeed = 200; int i, rollMax; int RollAdd = 2; if (sv_waterlevel->value) { speedMult = 20; MaxSpeed = 300; } else if (ent->client->goggles && ent->waterlevel>1) { speedMult = 50; MaxSpeed = 400; } else if (ent->client->jets) { speedMult = 50; MaxSpeed = 500; } speedMax *= MaxSpeed; AngleVectors (ent->client->v_angle, temp, tempSide, tempUp); VectorNormalize (temp); VectorNormalize (tempSide), VectorNormalize (tempUp); for (i=0; i<3;i++) { SidMove[i] = 0; ForMove[i] = 0; } if (ent->Move_side!=0) // rolling side to side visually with strafe buttons { rollMax = ( abs(ent->Move_side)>200 ) ? 16 : 8; if (ent->Move_side<0) ent->client->flightRoll-=RollAdd; if (ent->Move_side>0) ent->client->flightRoll+=RollAdd; if (ent->client->flightRoll>rollMax) ent->client->flightRoll=rollMax; if (ent->client->flightRoll<-rollMax) ent->client->flightRoll=-rollMax; VectorScale(tempSide, ent->Move_side ,tempSide); ent->client->kick_angles[ROLL] += ent->client->flightRoll; for (i=0; i<3;i++) SidMove[i] += 0.75*tempSide[i]*(0.5+(abs(ent->client->flightRoll*2)/rollMax)*0.5); } else { for (i=0; iclient->flightRoll>0) ent->client->flightRoll--; if (ent->client->flightRoll<0) ent->client->flightRoll++; } if (ent->client->flightRoll!=0) ent->client->kick_angles[ROLL] += ent->client->flightRoll; for (i=0; i<3;i++) SidMove[i] += 0.75*tempSide[i]*(0.5+(abs(ent->client->flightRoll*2)/16)*0.5); } if (ent->Move_forward!=0) { ent->client->lastSpeed += ( ent->Move_forward>0 ) ? speedMult : -speedMult; if (ent->client->lastSpeed>speedMax) ent->client->lastSpeed=speedMax; if (ent->client->lastSpeed<-speedMax) ent->client->lastSpeed=-speedMax; VectorScale(temp, ent->client->lastSpeed ,temp); for (i=0; i<3;i++) ForMove[i] = temp[i]; } else { for (i=0; iclient->lastSpeed>0) ent->client->lastSpeed--; if (ent->client->lastSpeed<0) ent->client->lastSpeed++; } VectorScale(temp, ent->client->lastSpeed ,temp); for (i=0; i<3;i++) ForMove[i] = temp[i]; } ent->velocity[2] = 0; VectorAdd (SidMove, ForMove, ent->velocity); if (ent->Move_up!=0) { ent->client->lastSpeedUp += ( ent->Move_up>0 ) ? speedMult: -speedMult; if (ent->client->lastSpeedUp>MaxSpeed) ent->client->lastSpeedUp=MaxSpeed; if (ent->client->lastSpeedUp<-MaxSpeed) ent->client->lastSpeedUp=-MaxSpeed; VectorScale(tempUp, ent->client->lastSpeedUp ,tempUp); } else { for (i=0; iclient->lastSpeedUp>0) ent->client->lastSpeedUp--; if (ent->client->lastSpeedUp<0) ent->client->lastSpeedUp++; } VectorScale(tempUp, ent->client->lastSpeedUp ,tempUp); } VectorAdd (tempUp, ent->velocity, ent->velocity); if (sv_waterlevel->value && sv_serversideonly->value) if (VectorLength(ent->velocity)>20) { //ADD SWIM FX for (i=0; i<3;i++) tempSmokeDir[i] = -ent->velocity[i]; //MAKE BUBBLES ETC gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_STEAM); gi.WriteShort ((short int)-1); gi.WriteByte (1 + VectorLength(ent->velocity) / 5); //Amount gi.WritePosition (ent->s.origin); gi.WriteDir (tempSmokeDir); gi.WriteByte (7); //color gi.WriteShort ( 10 + VectorLength(ent->velocity) / 5); //speed gi.multicast (ent->s.origin, MULTICAST_PVS); //DONE } if (ent->client->goggles && ent->waterlevel>1) if (VectorLength(ent->velocity)>20) { //ADD SWIM FX for (i=0; i<3;i++) tempSmokeDir[i] = -ent->velocity[i]; //MAKE BUBBLES ETC gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_STEAM); gi.WriteShort ((short int)-1); gi.WriteByte (1 + VectorLength(ent->velocity) / 7); //Amount gi.WritePosition (ent->s.origin); gi.WriteDir (tempSmokeDir); gi.WriteByte (7); //color gi.WriteShort ( 10 + VectorLength(ent->velocity) / 7); //speed gi.multicast (ent->s.origin, MULTICAST_PVS); //DONE } if (ent->client->jets) { //ADD FLIGHT FX gi.sound(ent, CHAN_ITEM, gi.soundindex("weapons/rockfly.wav"), (double)((ent->client->aquasuit)?.2:.4 + (VectorLength(ent->velocity)/2000)), ATTN_NORM, 0); for (i=0; i<3;i++) tempSmokeDir[i] = -ent->velocity[i]; //MAKE SMOKE gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_STEAM); gi.WriteShort ((short int)-1); gi.WriteByte (10 + VectorLength(ent->velocity) / 10); //Amount gi.WritePosition (ent->s.origin); gi.WriteDir (tempSmokeDir); gi.WriteByte (224); //color gi.WriteShort ( 10 + VectorLength(ent->velocity) / 10); //speed gi.multicast (ent->s.origin, MULTICAST_PVS); //DONE } } else if (ent->waterlevel>1) { vec3_t tempSmokeDir; int i, rollMax; int RollAdd = 2; //if (ent->Move_side!=0) // rolling side to side visually with strafe buttons // ent->client->kick_angles[ROLL] += ( ent->Move_side>0 ) ? 5: -5; if (ent->Move_side!=0) // rolling side to side visually with strafe buttons { rollMax = ( abs(ent->Move_side)>200 ) ? 10 : 5; if (ent->Move_side<0) ent->client->flightRoll-=RollAdd; if (ent->Move_side>0) ent->client->flightRoll+=RollAdd; //this checks to see if im at limit or over if (ent->client->flightRoll>rollMax) ent->client->flightRoll-=RollAdd; if (ent->client->flightRoll<-rollMax) ent->client->flightRoll+=RollAdd; //this checks to see if im still pushing limit if (ent->client->flightRoll>rollMax) ent->client->flightRoll-=RollAdd; if (ent->client->flightRoll<-rollMax) ent->client->flightRoll+=RollAdd; ent->client->kick_angles[ROLL] += ent->client->flightRoll; } else { for (i=0; i<2; i++) { if (ent->client->flightRoll>0) ent->client->flightRoll-=RollAdd; if (ent->client->flightRoll<0) ent->client->flightRoll+=RollAdd; } if (ent->client->flightRoll!=0) ent->client->kick_angles[ROLL] += ent->client->flightRoll; } if (VectorLength(ent->velocity)>20 && sv_serversideonly->value) { //ADD SWIM FX for (i=0; i<3;i++) tempSmokeDir[i] = -ent->velocity[i]; //MAKE BUBBLES ETC gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_STEAM); gi.WriteShort ((short int)-1); gi.WriteByte (1 + VectorLength(ent->velocity) / 4); //Amount gi.WritePosition (ent->s.origin); gi.WriteDir (tempSmokeDir); gi.WriteByte (7); //color gi.WriteShort ( 10 + VectorLength(ent->velocity) / 4); //speed gi.multicast (ent->s.origin, MULTICAST_PVS); //DONE } } else { for (i=0; i<10; i++) { ent->client->flightRoll+=(ent->client->flightRoll==0)?0:(ent->client->flightRoll<0)? 1:-1; ent->client->lastSpeedUp+=(ent->client->lastSpeedUp==0)?0:(ent->client->lastSpeedUp<0)? 1:-1; ent->client->lastSpeed+=(ent->client->lastSpeed==0)?0:(ent->client->lastSpeed<0)? 1:-1; } } } //******************************************************* // // HUGE ASS EXPLOSION // //******************************************************* void splash_think (edict_t *ent) { ent->nextthink = level.time; if (ent->s.frame++>6) G_FreeEdict(ent); } void bigExplosion(vec3_t start, vec3_t dir, int skin) { if (!sv_serversideonly->value) { edict_t *splash; splash = G_Spawn(); VectorCopy (start, splash->s.origin); vectoangles (dir, splash->s.angles); splash->movetype = MOVETYPE_NONE; splash->solid = SOLID_NOT; VectorClear (splash->velocity); VectorClear (splash->mins); VectorClear (splash->maxs); splash->s.modelindex = gi.modelindex ("models/objects/ion_explode/tris.md2"); splash->s.skinnum = skin; splash->s.frame = 0; splash->s.effects = EF_PLASMA | EF_SPHERETRANS; splash->s.renderfx = RF_FULLBRIGHT; gi.positioned_sound (start, splash, CHAN_AUTO, gi.soundindex("world/explode_1.wav"), 1, ATTN_NORM, 0); gi.positioned_sound (start, splash, CHAN_AUTO, gi.soundindex("world/explode_2.wav"), 1, ATTN_NORM, 0); splash->think = splash_think; splash->nextthink = level.time; splash->classname = "splash"; gi.linkentity (splash); } else { int Explosion_Type = (sv_waterlevel->value||(gi.pointcontents (start) & MASK_WATER)) ? TE_ROCKET_EXPLOSION_WATER : TE_ROCKET_EXPLOSION; vec3_t end, dir; int distance = 50; //at start gi.WriteByte (svc_temp_entity); gi.WriteByte (Explosion_Type); gi.WritePosition (start); gi.multicast (start, MULTICAST_PVS); //top middle dir[1]=0; dir[0]=0; dir[2]=1; VectorMA (start, distance, dir, end); gi.WriteByte (svc_temp_entity); gi.WriteByte (Explosion_Type); gi.WritePosition (end); gi.multicast (end, MULTICAST_PVS); //middle +1 dir[0]=0; dir[1]=1; dir[2]=0; VectorMA (start, distance, dir, end); gi.WriteByte (svc_temp_entity); gi.WriteByte (Explosion_Type); gi.WritePosition (end); gi.multicast (end, MULTICAST_PVS); dir[0]=1; dir[1]=0; dir[2]=0; VectorMA (start, distance, dir, end); gi.WriteByte (svc_temp_entity); gi.WriteByte (Explosion_Type); gi.WritePosition (end); gi.multicast (end, MULTICAST_PVS); dir[0]=1; dir[1]=1; dir[2]=0; VectorMA (start, distance, dir, end); gi.WriteByte (svc_temp_entity); gi.WriteByte (Explosion_Type); gi.WritePosition (end); gi.multicast (end, MULTICAST_PVS); //middle -1 dir[0]=0; dir[1]=-1; dir[2]=0; VectorMA (start, distance, dir, end); gi.WriteByte (svc_temp_entity); gi.WriteByte (Explosion_Type); gi.WritePosition (end); gi.multicast (end, MULTICAST_PVS); dir[0]=-1; dir[1]=0; dir[2]=0; VectorMA (start, distance, dir, end); gi.WriteByte (svc_temp_entity); gi.WriteByte (Explosion_Type); gi.WritePosition (end); gi.multicast (end, MULTICAST_PVS); dir[0]=-1; dir[1]=-1; dir[2]=0; VectorMA (start, distance, dir, end); gi.WriteByte (svc_temp_entity); gi.WriteByte (Explosion_Type); gi.WritePosition (end); gi.multicast (end, MULTICAST_PVS); //bottom middle dir[0]=0; dir[1]=0; dir[2]=-1; VectorMA (start, distance, dir, end); gi.WriteByte (svc_temp_entity); gi.WriteByte (Explosion_Type); gi.WritePosition (end); gi.multicast (end, MULTICAST_PVS); } } void PlayerID (edict_t *ent) { char string[1024]; vec3_t start, forward, end; trace_t tr; int offset = 0; VectorCopy(ent->s.origin, start); start[2] += ent->viewheight; AngleVectors(ent->client->v_angle, forward, NULL, NULL); VectorMA(start, 8192, forward, end); tr = gi.trace(start, NULL, NULL, end, ent, MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA); if ((level.framenum-ent->client->resp.enterframe)>5) if ( (level.framenum-ent->client->resp.enterframe)/10 <= ent->client->MotdTime ) { if ( (level.framenum-ent->client->resp.enterframe)/10 > ent->client->MotdTime-0.5) { ent->client->showinventory = false; ent->client->showscores = false; ent->client->showhelp = false; ent->client->ps.stats[STAT_LAYOUTS] = 0; } else { if (!(level.framenum % ent->client->MOTDrotChange)) PrintMOTDmsg (ent); ent->client->showinventory = false; ent->client->showhelp = true; ent->client->showscores = false; ent->client->ps.stats[STAT_LAYOUTS] |= 1; } return; } if (!ent->Player_ID) return; if (ent->client->showscores) return; if (tr.ent->client) { if (tr.ent->health<0) Com_sprintf (string, sizeof(string), "xv 0 yv %i cstring2 \"%s\" " "xv 0 yv %i cstring2 \"%s\" ", offset, make_green("- Dead -"), offset+10, make_white(tr.ent->client->pers.netname)); else if (OnSameTeam (ent, tr.ent) || (coop->value&&sv_teams->value)) Com_sprintf (string, sizeof(string), "xv 0 yv %i cstring2 \"%s\" " "xv 0 yv %i cstring2 \"%s\" " "xv 0 yv %i cstring2 \"%s%i\" ", offset, make_green("- Friend -"), offset+10, make_white(tr.ent->client->pers.netname), offset+20, make_green("health: "), tr.ent->health); else Com_sprintf (string, sizeof(string), "xv 0 yv %i cstring2 \"%s\" " "xv 0 yv %i cstring2 \"%s\" ", offset, make_green("- Enemy -"), offset+10, make_white(tr.ent->client->pers.netname)); ent->client->showhelp = true; ent->client->ps.stats[STAT_LAYOUTS] |= 1; } else if ((tr.ent->svflags & SVF_MONSTER) && (tr.ent->classname)) { qboolean ishuman = !Q_stricmp (tr.ent->classname, "misc_insane"); Com_sprintf (string, sizeof(string), "xv 0 yv %i cstring2 \"%s\" " "xv 0 yv %i cstring2 \"%s\" ", offset, make_green((tr.ent->health<=0)?"- Dead -":(ishuman)?"- Friend -":"- Monster -"), offset+10, make_white( (!Q_stricmp (tr.ent->classname, "monster_berserk"))? "Berserker" : (!Q_stricmp (tr.ent->classname, "monster_gladiator"))? "Gladiator" : (!Q_stricmp (tr.ent->classname, "monster_gunner"))? "Pyro Gunner" : (!Q_stricmp (tr.ent->classname, "monster_infantry"))? "Elite Infantry" : (!Q_stricmp (tr.ent->classname, "monster_soldier_light"))? "Light Soldier" : (!Q_stricmp (tr.ent->classname, "monster_soldier"))? "Soldier" : (!Q_stricmp (tr.ent->classname, "monster_soldier_ss"))? "Elite Soldier" : (!Q_stricmp (tr.ent->classname, "turret_driver"))? "Gunner Infantry" : (!Q_stricmp (tr.ent->classname, "monster_medic"))? "Medic" : (!Q_stricmp (tr.ent->classname, "monster_chick"))? "Strogg Cyber-Female" : (!Q_stricmp (tr.ent->classname, "monster_brain"))? "Guardian" : (!Q_stricmp (tr.ent->classname, "monster_mutant"))? "Mutant" : (!Q_stricmp (tr.ent->classname, "monster_flyer"))? "Sentinel" : (!Q_stricmp (tr.ent->classname, "monster_floater"))? "Brain" : (!Q_stricmp (tr.ent->classname, "monster_flipper"))? "Pirhanna" : (!Q_stricmp (tr.ent->classname, "monster_hover"))? "Air Gunner" : (!Q_stricmp (tr.ent->classname, "monster_parasite"))? "Parasite" : (!Q_stricmp (tr.ent->classname, "monster_tank"))? "Ground Tank" : (!Q_stricmp (tr.ent->classname, "monster_tank_commander"))? "Tank Commander" : (!Q_stricmp (tr.ent->classname, "monster_supertank"))? "Super Ground Tank" : (!Q_stricmp (tr.ent->classname, "monster_boss2"))? "Air Tank" : (!Q_stricmp (tr.ent->classname, "monster_boss3_stand"))? "Strogg Makron" : (!Q_stricmp (tr.ent->classname, "monster_makron"))? "Strogg Makron" : (!Q_stricmp (tr.ent->classname, "monster_jorg"))? "Strogg Jorg" : (!Q_stricmp (tr.ent->classname, "misc_insane"))? "Human Soldier" : (!Q_stricmp (tr.ent->classname, "misc_deadsoldier"))? "Human Soldier" : (!Q_stricmp (tr.ent->classname, "monster_turret_driver"))? "Turret Commander" : tr.ent->classname) ); ent->client->showhelp = true; ent->client->ps.stats[STAT_LAYOUTS] |= 1; } else if (!Q_stricmp (tr.ent->classname, "misc_easterchick") || !Q_stricmp (tr.ent->classname, "misc_easterchick2")|| !Q_stricmp (tr.ent->classname, "misc_eastertank")) { Com_sprintf (string, sizeof(string), "xv 0 yv %i cstring2 \"%s\" " "xv 0 yv %i cstring2 \"%s\" ", offset, make_green("- Monster -"), offset+10, make_white( (!Q_stricmp (tr.ent->classname, "misc_easterchick"))? "Strogg Whore" : (!Q_stricmp (tr.ent->classname, "misc_easterchick2"))? "Strogg Whore" : (!Q_stricmp (tr.ent->classname, "misc_eastertank"))? "Strogg Pimp Tank" : tr.ent->classname)); ent->client->showhelp = true; ent->client->ps.stats[STAT_LAYOUTS] |= 1; } else if (tr.ent->PlayerDeadName) { Com_sprintf (string, sizeof(string), "xv 0 yv %i cstring2 \"%s\" " "xv 0 yv %i cstring2 \"%s\" ", offset, make_green("- Dead -"), offset+10, make_white(tr.ent->PlayerDeadName)); ent->client->showhelp = true; ent->client->ps.stats[STAT_LAYOUTS] |= 1; } else { ent->client->showhelp = false; return; } gi.WriteByte (svc_layout); gi.WriteString (string); gi.unicast (ent, true); } #define SLOWCHANGE 100; #define SLOWMIN 100 #define SLOWMAX 500 void MakeSlowMo (edict_t *ent) { char msg[100]; int slow_target, oldGameSlowMoValue = GameSlowMoValue; if (!sv_matrix->value && !GameSlowMo) return; if (ent->health<=0 || ent->client->resp.bullettime==B_TIME_MIN) slow_target=0; else if (abs(ent->client->stunts)==1 || abs(ent->client->stunts)==2) slow_target=SLOWMAX; else if ((ent->client->latched_buttons|ent->client->buttons)&BUTTON_USE) slow_target=SLOWMAX; else slow_target=0; if (GameSlowMoValueslow_target) GameSlowMoValue=slow_target; } else if (GameSlowMoValue>slow_target) { GameSlowMoValue -= SLOWCHANGE; if (GameSlowMoValueSLOWMAX) GameSlowMoValue=SLOWMAX; if (GameSlowMoValue==300) { if (slow_target) gi.sound(ent, CHAN_AUTO, gi.soundindex("*jump1.wav"), 0.75, ATTN_IDLE, 0); else gi.sound(ent, CHAN_AUTO, gi.soundindex("*jump1.wav"), 0.75, ATTN_IDLE, 0); } if (oldGameSlowMoValue!=GameSlowMoValue) { if (GameSlowMoValue>=SLOWMIN) { Com_sprintf (msg, sizeof(msg), "fixedtime 1;cl_maxfps %i", GameSlowMoValue); stuffcmd (ent, msg); } else { stuffcmd (ent, "fixedtime 0;cl_maxfps 90"); } } GameSlowMo = (slow_target==SLOWMAX); } void CheckStunt(edict_t * ent) { vec3_t forward, strafe, up, start, vel; int DiveSpeed = 400; qboolean MovingNotBack = (ent->Move_forward>0); AngleVectors (ent->client->v_angle, forward, strafe, up); VectorNormalize (forward); VectorNormalize (strafe); VectorCopy(ent->velocity, vel); vel[2]=0; VectorCopy(ent->s.origin, start); start[2]+=ent->viewheight/2; if (sv_waterlevel->value ||ent->waterlevel || (ent->client->grapple_on && ent->client->grapple==2) || ent->client->jets || !sv_stunts->value || ent->health<=0) return; if (ent->client->stunts==0) { if (ent->groundentity) { if (ent->Move_up<0) { ent->client->stunts = (ent->Move_forward>0)? -70 :(ent->Move_forward<0)? -90 : (ent->Move_side>0)? -20 :(ent->Move_side<0)? -50: 0; } } else { if (!abs(ent->Move_forward)&&!abs(ent->Move_side)) ClimbWall (ent); if (!ent->client->aquasuit) { if (!ent->client->climbing&&MovingNotBack&&VectorLength(vel)>300) WallRunLeft (ent); if (!ent->client->climbing&&!abs(ent->client->wallrunning)&&MovingNotBack&&VectorLength(vel)>300) WallRunRight (ent); } if (!ent->client->climbing&&!abs(ent->client->wallrunning)&&ent->Move_up>0) { ent->client->stunts=9; SmackHit (ent, start, forward, 20+((int)(random()*10)), 50, 1); } } } else if (!ent->groundentity&&(ent->Move_up>0)&&(ent->client->stunts==9)) SmackHit (ent, start, forward, 20+((int)(random()*10)), 50, 1); } void CheckDiveGlassBreak (edict_t * ent) { vec3_t start, forward, end; trace_t tr; int LENGTH = 50; if (VectorLength(ent->velocity)<200) return; //AngleVectors(ent->velocity, forward, NULL, NULL); VectorCopy(ent->s.origin,start); VectorCopy(ent->velocity,forward); VectorNormalize(forward); VectorMA(start, LENGTH, forward, end); tr = gi.trace(start, NULL, NULL, end, ent, MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA); if (tr.contents & CONTENTS_WINDOW) if (tr.ent->health>0) if (tr.ent->health<50) { T_Damage (tr.ent,ent,ent,forward,tr.endpos,tr.plane.normal, tr.ent->health+1, 0,0,MOD_UNKNOWN); } } void AddReflection(edict_t *ent) { gclient_t *cl; int length; trace_t tr; vec3_t end, start; VectorSet(end, 0, 0, -1); VectorMA (ent->s.origin, 1024, end, end); tr = gi.trace (ent->s.origin, NULL, NULL, end, ent, MASK_SOLID); VectorSubtract(ent->s.origin, tr.endpos, end); length = VectorLength(end); VectorSet(end, 0, 0, -1); if (tr.fraction!=1 && tr.contents&CONTENTS_WINDOW) { if (!ent->reflection) { ent->reflection = G_Spawn(); ent->reflection->movetype = MOVETYPE_NONE; ent->reflection->solid = SOLID_NOT; ent->reflection->classname = "reflection"; ent->reflection->takedamage = DAMAGE_NO; } if (ent->client && !ent->reflection->client) { cl = (gclient_t *)malloc(sizeof(gclient_t)); ent->reflection->client = cl; } if (ent->client && ent->reflection->client) { ent->reflection->client->pers = ent->client->pers; ent->reflection->s = ent->s; ent->reflection->s.number = ent->reflection - g_edicts; } ent->reflection->s.modelindex = ent->s.modelindex; ent->reflection->s.modelindex2 = ent->s.modelindex2; ent->reflection->s.modelindex3 = ent->s.modelindex3; ent->reflection->s.modelindex4 = ent->s.modelindex4; ent->reflection->s.skinnum = ent->s.skinnum; ent->reflection->s.frame = ent->s.frame; ent->reflection->s.renderfx = ent->s.renderfx; ent->reflection->s.effects = ent->s.effects; ent->reflection->s.renderfx &= ~RF_IR_VISIBLE; VectorCopy (ent->s.angles, ent->reflection->s.angles); ent->reflection->s.angles[0]+=180; ent->reflection->s.angles[1]+=180; VectorMA (tr.endpos, length, end, ent->reflection->s.origin); ent->reflection->s.origin[2] -= 10; VectorCopy(ent->reflection->s.origin, ent->reflection->s.old_origin); gi.linkentity (ent->reflection); } else if (ent->reflection) { if (ent->reflection->client) free (ent->reflection->client); gi.unlinkentity (ent->reflection); G_FreeEdict(ent->reflection); ent->reflection = NULL; } } void AddShadow(edict_t *ent) { int length; trace_t tr; vec3_t end, start; if (sv_serversideonly->value) return; VectorSet(end, 0, 0, -1); VectorMA (ent->s.origin, 500, end, end); tr = gi.trace (ent->s.origin, NULL, NULL, end, ent, CONTENTS_SOLID); VectorSubtract(ent->s.origin, tr.endpos, end); length = VectorLength(end); if (tr.fraction!=1) { if (!ent->shadow) ent->shadow = G_Spawn(); VectorCopy (tr.endpos, ent->shadow->s.origin); ent->shadow->s.modelindex = gi.modelindex("models/objects/shadow/tris.md2"); ent->shadow->movetype = MOVETYPE_NONE; ent->shadow->solid = SOLID_NOT; ent->shadow->classname = "shadow"; ent->shadow->takedamage = DAMAGE_NO; ent->shadow->s.renderfx = RF_TRANSLUCENT; ent->shadow->s.skinnum = length/100; VectorCopy (ent->shadow->s.origin, ent->shadow->s.old_origin); VectorCopy (tr.endpos, ent->shadow->s.origin); vectoanglenormaled (tr.plane.normal, 0, ent->shadow->s.angles); gi.linkentity (ent->shadow); } else if (ent->shadow) { gi.unlinkentity (ent->shadow); G_FreeEdict(ent->shadow); ent->shadow = NULL; } }