/* * W_Fire_Rocket */ edict_t *W_Fire_Rocket( edict_t *self, vec3_t start, vec3_t angles, int speed, float damage, int minKnockback, int maxKnockback, int stun, int minDamage, int radius, int timeout, int mod, int timeDelta ) { edict_t *rocket; if( GS_Instagib() ) damage = 9999; rocket = W_Fire_LinearProjectile( self, start, angles, speed, damage, minKnockback, maxKnockback, stun, minDamage, radius, timeout, timeDelta ); rocket->s.type = ET_ROCKET; //rocket trail sfx if( mod == MOD_ROCKET_S ) { rocket->s.modelindex = trap_ModelIndex( PATH_ROCKET_STRONG_MODEL ); rocket->s.effects |= EF_STRONG_WEAPON; rocket->s.sound = trap_SoundIndex( S_WEAPON_ROCKET_S_FLY ); } else { rocket->s.modelindex = trap_ModelIndex( PATH_ROCKET_WEAK_MODEL ); rocket->s.effects &= ~EF_STRONG_WEAPON; rocket->s.sound = trap_SoundIndex( S_WEAPON_ROCKET_W_FLY ); } rocket->touch = W_Touch_Rocket; rocket->think = G_FreeEdict; rocket->classname = "rocket"; rocket->style = mod; return rocket; }
/* * W_Fire_Plasma */ edict_t *W_Fire_Plasma( edict_t *self, vec3_t start, vec3_t angles, float damage, int minKnockback, int maxKnockback, int stun, int minDamage, int radius, int speed, int timeout, int mod, int timeDelta ) { edict_t *plasma; if( GS_Instagib() ) damage = 9999; plasma = W_Fire_LinearProjectile( self, start, angles, speed, damage, minKnockback, maxKnockback, stun, minDamage, radius, timeout, timeDelta ); plasma->s.type = ET_PLASMA; plasma->classname = "plasma"; plasma->style = mod; plasma->think = W_Think_Plasma; plasma->touch = W_AutoTouch_Plasma; plasma->nextThink = level.time + 1; plasma->timeout = level.time + timeout; if( mod == MOD_PLASMA_S ) { plasma->s.modelindex = trap_ModelIndex( PATH_PLASMA_STRONG_MODEL ); plasma->s.sound = trap_SoundIndex( S_WEAPON_PLASMAGUN_S_FLY ); plasma->s.effects |= EF_STRONG_WEAPON; } else { plasma->s.modelindex = trap_ModelIndex( PATH_PLASMA_WEAK_MODEL ); plasma->s.sound = trap_SoundIndex( S_WEAPON_PLASMAGUN_W_FLY ); plasma->s.effects &= ~EF_STRONG_WEAPON; } return plasma; }
/* * W_Fire_Grenade */ edict_t *W_Fire_Grenade( edict_t *self, vec3_t start, vec3_t dir, int speed, float damage, int minKnockback, int maxKnockback, int stun, int minDamage, float radius, int timeout, int mod, int timeDelta ) { edict_t *grenade; if( GS_Instagib() ) { damage = 9999; } grenade = W_Fire_TossProjectile( self, start, dir, speed, damage, minKnockback, maxKnockback, stun, minDamage, radius, timeout, timeDelta ); VectorClear( grenade->s.angles ); grenade->style = mod; grenade->s.type = ET_GRENADE; grenade->movetype = MOVETYPE_BOUNCEGRENADE; grenade->touch = W_Touch_Grenade; grenade->use = NULL; grenade->think = W_Grenade_Explode; grenade->classname = "grenade"; grenade->enemy = NULL; VectorSet( grenade->avelocity, 300, 300, 300 ); if( mod == MOD_GRENADE_S ) { grenade->s.modelindex = trap_ModelIndex( PATH_GRENADE_STRONG_MODEL ); grenade->s.effects |= EF_STRONG_WEAPON; } else { grenade->s.modelindex = trap_ModelIndex( PATH_GRENADE_WEAK_MODEL ); grenade->s.effects &= ~EF_STRONG_WEAPON; } GClip_LinkEntity( grenade ); return grenade; }
void G_Gametype_GENERIC_SetUpWarmup( void ) { level.gametype.readyAnnouncementEnabled = true; level.gametype.scoreAnnouncementEnabled = false; level.gametype.countdownEnabled = false; level.gametype.pickableItemsMask = ( level.gametype.spawnableItemsMask|level.gametype.dropableItemsMask ); if( GS_Instagib() ) level.gametype.pickableItemsMask &= ~G_INSTAGIB_NEGATE_ITEMMASK; if( GS_TeamBasedGametype() ) { bool any = false; int team; for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ ) { if( G_Teams_TeamIsLocked( team ) ) { G_Teams_UnLockTeam( team ); any = true; } } if( any ) G_PrintMsg( NULL, "Teams unlocked.\n" ); } else { if( G_Teams_TeamIsLocked( TEAM_PLAYERS ) ) { G_Teams_UnLockTeam( TEAM_PLAYERS ); G_PrintMsg( NULL, "Teams unlocked.\n" ); } } G_Teams_RemoveInvites(); }
static void G_Gametype_GENERIC_Init( void ) { trap_ConfigString( CS_GAMETYPETITLE, "Generic Deathmatch" ); trap_ConfigString( CS_GAMETYPEVERSION, "1.0" ); trap_ConfigString( CS_GAMETYPEAUTHOR, "Warsow Development Team" ); trap_Cvar_ForceSet( "g_gametype", "generic" ); level.gametype.spawnableItemsMask = ( IT_WEAPON|IT_AMMO|IT_ARMOR|IT_POWERUP|IT_HEALTH ); level.gametype.respawnableItemsMask = ( IT_WEAPON|IT_AMMO|IT_ARMOR|IT_POWERUP|IT_HEALTH ); level.gametype.dropableItemsMask = ( IT_WEAPON|IT_AMMO|IT_ARMOR|IT_POWERUP|IT_HEALTH ); level.gametype.pickableItemsMask = ( level.gametype.spawnableItemsMask|level.gametype.dropableItemsMask ); if( GS_Instagib() ) level.gametype.pickableItemsMask &= ~G_INSTAGIB_NEGATE_ITEMMASK; level.gametype.isTeamBased = false; level.gametype.isRace = false; level.gametype.isTutorial = false; level.gametype.inverseScore = false; level.gametype.hasChallengersQueue = false; level.gametype.maxPlayersPerTeam = 0; level.gametype.ammo_respawn = 20; level.gametype.armor_respawn = 25; level.gametype.weapon_respawn = 5; level.gametype.health_respawn = 25; level.gametype.powerup_respawn = 90; level.gametype.megahealth_respawn = 20; level.gametype.ultrahealth_respawn = 60; level.gametype.countdownEnabled = false; level.gametype.mathAbortDisabled = false; level.gametype.canForceModels = true; level.gametype.canShowMinimap = false; level.gametype.teamOnlyMinimap = true; level.gametype.spawnpointRadius = 256; level.gametype.canShowMinimap = false; level.gametype.teamOnlyMinimap = true; level.gametype.mmCompatible = false; if( GS_Instagib() ) level.gametype.spawnpointRadius *= 2; trap_ConfigString( CS_SCB_PLAYERTAB_LAYOUT, "%n 164 %i 64 %l 48 %p 18 %p 18" ); trap_ConfigString( CS_SCB_PLAYERTAB_TITLES, "Name Score Ping C R" ); }
void G_Gametype_GENERIC_ClientRespawn( edict_t *self, int old_team, int new_team ) { int i; gclient_t *client = self->r.client; gs_weapon_definition_t *weapondef; if( G_ISGHOSTING( self ) ) return; //give default items if( self->s.team != TEAM_SPECTATOR ) { if( GS_Instagib() ) { client->ps.inventory[WEAP_INSTAGUN] = 1; client->ps.inventory[AMMO_INSTAS] = 1; client->ps.inventory[AMMO_WEAK_INSTAS] = 1; } else { if( GS_MatchState() <= MATCH_STATE_WARMUP ) { for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ ) { if( i == WEAP_INSTAGUN ) // dont add instagun... continue; weapondef = GS_GetWeaponDef( i ); client->ps.inventory[i] = 1; if( weapondef->firedef_weak.ammo_id ) client->ps.inventory[weapondef->firedef_weak.ammo_id] = weapondef->firedef_weak.ammo_max; if( weapondef->firedef.ammo_id ) client->ps.inventory[weapondef->firedef.ammo_id] = weapondef->firedef.ammo_max; } client->resp.armor = GS_Armor_MaxCountForTag( ARMOR_YA ); } else { weapondef = GS_GetWeaponDef( WEAP_GUNBLADE ); client->ps.inventory[WEAP_GUNBLADE] = 1; client->ps.inventory[AMMO_GUNBLADE] = weapondef->firedef.ammo_max;; client->ps.inventory[AMMO_WEAK_GUNBLADE] = 0; } } } // select rocket launcher if available if( GS_CheckAmmoInWeapon( &client->ps, WEAP_ROCKETLAUNCHER ) ) client->ps.stats[STAT_PENDING_WEAPON] = WEAP_ROCKETLAUNCHER; else client->ps.stats[STAT_PENDING_WEAPON] = GS_SelectBestWeapon( &client->ps ); // add a teleportation effect if( self->r.solid != SOLID_NOT ) G_RespawnEffect( self ); }
/* * W_Fire_Grenade */ edict_t *W_Fire_Grenade( edict_t *self, vec3_t start, vec3_t angles, int speed, float damage, int minKnockback, int maxKnockback, int stun, int minDamage, float radius, int timeout, int mod, int timeDelta, qboolean aim_up ) { edict_t *grenade; static cvar_t *g_grenade_gravity = NULL; if( GS_Instagib() ) damage = 9999; if( !g_grenade_gravity ) g_grenade_gravity = trap_Cvar_Get( "g_grenade_gravity", "1.3", CVAR_DEVELOPER ); if( aim_up ) { angles[PITCH] -= 10; // aim some degrees upwards from view dir // clamp to front side of the player angles[PITCH] += -90; // rotate to make easier the check while( angles[PITCH] < -360 ) angles[PITCH] += 360; clamp( angles[PITCH], -180, 0 ); angles[PITCH] += 90; while( angles[PITCH] > 360 ) angles[PITCH] -= 360; } grenade = W_Fire_TossProjectile( self, start, angles, speed, damage, minKnockback, maxKnockback, stun, minDamage, radius, timeout, timeDelta ); VectorClear( grenade->s.angles ); grenade->style = mod; grenade->s.type = ET_GRENADE; grenade->movetype = MOVETYPE_BOUNCEGRENADE; grenade->touch = W_Touch_Grenade; grenade->use = NULL; grenade->think = W_Grenade_Explode; grenade->classname = "grenade"; grenade->gravity = g_grenade_gravity->value; grenade->enemy = NULL; if( mod == MOD_GRENADE_S ) { grenade->s.modelindex = trap_ModelIndex( PATH_GRENADE_STRONG_MODEL ); grenade->s.effects |= EF_STRONG_WEAPON; } else { grenade->s.modelindex = trap_ModelIndex( PATH_GRENADE_WEAK_MODEL ); grenade->s.effects &= ~EF_STRONG_WEAPON; } GClip_LinkEntity( grenade ); return grenade; }
/* * G_Gametype_CanRespawnItem */ bool G_Gametype_CanRespawnItem( const gsitem_t *item ) { int itemmask; if( !item ) return false; itemmask = level.gametype.respawnableItemsMask; if( GS_Instagib() ) { itemmask &= ~G_INSTAGIB_NEGATE_ITEMMASK; } return ( ( itemmask & item->type ) != 0 ) ? true : false; }
/* * W_Fire_Lasergun */ edict_t *W_Fire_Lasergun( edict_t *self, vec3_t start, vec3_t angles, float damage, int knockback, int stun, int range, int mod, int timeDelta ) { edict_t *laser; qboolean newLaser; trace_t tr; vec3_t dir; if( GS_Instagib() ) damage = 9999; laser = _FindOrSpawnLaser( self, ET_LASERBEAM, &newLaser ); if( newLaser ) { // the quad start sound is added from the server if( self->r.client && self->r.client->ps.inventory[POWERUP_QUAD] > 0 ) G_Sound( self, CHAN_AUTO, trap_SoundIndex( S_QUAD_FIRE ), ATTN_NORM ); } laser_damage = damage; laser_knockback = knockback; laser_stun = stun; laser_attackerNum = ENTNUM( self ); laser_mod = mod; laser_missed = qtrue; GS_TraceLaserBeam( &tr, start, angles, range, ENTNUM( self ), timeDelta, _LaserImpact ); laser->r.svflags |= SVF_FORCEOWNER; VectorCopy( start, laser->s.origin ); AngleVectors( angles, dir, NULL, NULL ); VectorMA( laser->s.origin, range, dir, laser->s.origin2 ); laser->think = G_Laser_Think; laser->nextThink = level.time + 100; if( laser_missed && self->r.client ) G_AwardPlayerMissedLasergun( self, mod ); // calculate laser's mins and maxs for linkEntity G_SetBoundsForSpanEntity( laser, 8 ); GClip_LinkEntity( laser ); return laser; }
/* * W_Fire_Bullet */ void W_Fire_Bullet( edict_t *self, vec3_t start, vec3_t angles, int seed, int range, int spread, float damage, int knockback, int stun, int mod, int timeDelta ) { vec3_t dir; edict_t *event; float r, u; double alpha, s; trace_t trace; int dmgflags = DAMAGE_STUN_CLAMP|DAMAGE_KNOCKBACK_SOFT; if( GS_Instagib() ) damage = 9999; AngleVectors( angles, dir, NULL, NULL ); // send the event event = G_SpawnEvent( EV_FIRE_BULLET, seed, start ); event->s.ownerNum = ENTNUM( self ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 4096, event->s.origin2 ); // DirToByte is too inaccurate event->s.weapon = WEAP_MACHINEGUN; if( mod == MOD_MACHINEGUN_S ) event->s.weapon |= EV_INVERSE; // circle shape alpha = M_PI * Q_crandom( &seed ); // [-PI ..+PI] s = fabs( Q_crandom( &seed ) ); // [0..1] r = s * cos( alpha ) * spread; u = s * sin( alpha ) * spread; GS_TraceBullet( &trace, start, dir, r, u, range, ENTNUM( self ), timeDelta ); if( trace.ent != -1 ) { if( game.edicts[trace.ent].takedamage ) { G_Damage( &game.edicts[trace.ent], self, self, dir, dir, trace.endpos, damage, knockback, stun, dmgflags, mod ); } else { if( !( trace.surfFlags & SURF_NOIMPACT ) ) { } } } }
/* * W_Fire_Electrobolt_Weak */ edict_t *W_Fire_Electrobolt_Weak( edict_t *self, vec3_t start, vec3_t angles, float speed, float damage, int minKnockback, int maxKnockback, int stun, int timeout, int mod, int timeDelta ) { edict_t *bolt; if( GS_Instagib() ) damage = 9999; // projectile, weak mode bolt = W_Fire_LinearProjectile( self, start, angles, speed, damage, minKnockback, maxKnockback, stun, 0, 0, timeout, timeDelta ); bolt->s.modelindex = trap_ModelIndex( PATH_ELECTROBOLT_WEAK_MODEL ); bolt->s.type = ET_ELECTRO_WEAK; //add particle trail and light bolt->s.ownerNum = ENTNUM( self ); bolt->touch = W_Touch_Bolt; bolt->classname = "bolt"; bolt->style = mod; bolt->s.effects &= ~EF_STRONG_WEAPON; return bolt; }
/* * W_Fire_GunbladeBlast */ edict_t *W_Fire_GunbladeBlast( edict_t *self, vec3_t start, vec3_t angles, float damage, int minKnockback, int maxKnockback, int stun, int minDamage, int radius, int speed, int timeout, int mod, int timeDelta ) { edict_t *blast; if( GS_Instagib() ) damage = 9999; blast = W_Fire_LinearProjectile( self, start, angles, speed, damage, minKnockback, maxKnockback, stun, minDamage, radius, timeout, timeDelta ); blast->s.modelindex = trap_ModelIndex( PATH_GUNBLADEBLAST_STRONG_MODEL ); blast->s.type = ET_BLASTER; blast->s.effects |= EF_STRONG_WEAPON; blast->touch = W_Touch_GunbladeBlast; blast->classname = "gunblade_blast"; blast->style = mod; blast->s.sound = trap_SoundIndex( S_WEAPON_PLASMAGUN_S_FLY ); return blast; }
void W_Fire_Riotgun( edict_t *self, vec3_t start, vec3_t fv, vec3_t rv, vec3_t uv, int seed, int range, int hspread, int vspread, int count, float damage, int knockback, int stun, int mod, int timeDelta ) { edict_t *event; int dmgflags = 0; if( GS_Instagib() ) { damage = 9999; } // send the event event = G_SpawnEvent( EV_FIRE_RIOTGUN, seed, start ); event->s.ownerNum = ENTNUM( self ); VectorCopy( fv, event->s.origin2 ); VectorCopy( rv, event->s.origin3 ); event->s.weapon = WEAP_RIOTGUN; event->s.firemode = ( mod == MOD_RIOTGUN_S ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; W_Fire_SunflowerBucket( self, start, fv, rv, uv, &seed, count, hspread, vspread, range, damage, knockback, stun, dmgflags, mod, timeDelta ); }
/* * G_Gametype_CanDropItem */ bool G_Gametype_CanDropItem( const gsitem_t *item, bool ignoreMatchState ) { int itemmask; if( !item ) return false; if( !ignoreMatchState ) { if( GS_MatchState() > MATCH_STATE_PLAYTIME ) return false; } itemmask = level.gametype.dropableItemsMask; if( GS_Instagib() ) { itemmask &= ~G_INSTAGIB_NEGATE_ITEMMASK; } return ( itemmask & item->type ) ? true : false; }
/* * SetItemNames * * Called by worldspawn */ void G_PrecacheItems( void ) { int i; gsitem_t *item; // precache item names and weapondefs for( i = 1; ( item = GS_FindItemByTag( i ) ) != NULL; i++ ) { trap_ConfigString( CS_ITEMS + i, item->name ); if( item->type & IT_WEAPON && GS_GetWeaponDef( item->tag ) ) { G_PrecacheWeapondef( i, &GS_GetWeaponDef( item->tag )->firedef ); G_PrecacheWeapondef( i, &GS_GetWeaponDef( item->tag )->firedef_weak ); } } // precache items if( GS_Instagib() ) { item = GS_FindItemByTag( WEAP_INSTAGUN ); PrecacheItem( item ); } else { for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ ) { item = GS_FindItemByTag( i ); PrecacheItem( item ); } } // Vic: precache ammo pack if it's droppable item = GS_FindItemByClassname( "item_ammopack" ); if( item && G_Gametype_CanDropItem( item, qtrue ) ) { PrecacheItem( item ); } }
/* * G_ClientThink * Client frame think, and call to execute its usercommands thinking */ void G_ClientThink( edict_t *ent ) { if( !ent || !ent->r.client ) return; if( trap_GetClientState( PLAYERNUM( ent ) ) < CS_SPAWNED ) return; ent->r.client->ps.POVnum = ENTNUM( ent ); // set self // load instashield if( GS_Instagib() && g_instashield->integer ) { if( ent->s.team >= TEAM_PLAYERS && ent->s.team < GS_MAX_TEAMS ) { if( ent->r.client->ps.inventory[POWERUP_SHELL] > 0 ) { ent->r.client->resp.instashieldCharge -= ( game.frametime * 0.001f ) * 60.0f; clamp( ent->r.client->resp.instashieldCharge, 0, INSTA_SHIELD_MAX ); if( ent->r.client->resp.instashieldCharge == 0 ) ent->r.client->ps.inventory[POWERUP_SHELL] = 0; } else { ent->r.client->resp.instashieldCharge += ( game.frametime * 0.001f ) * 20.0f; clamp( ent->r.client->resp.instashieldCharge, 0, INSTA_SHIELD_MAX ); } } } // run bots thinking with the rest of clients if( ent->r.svflags & SVF_FAKECLIENT ) { if( !ent->think && AI_GetType( ent->ai ) == AI_ISBOT ) AI_Think( ent ); } trap_ExecuteClientThinks( PLAYERNUM( ent ) ); }
void G_Gametype_GENERIC_SetUpMatch( void ) { int i; level.gametype.readyAnnouncementEnabled = false; level.gametype.scoreAnnouncementEnabled = true; level.gametype.countdownEnabled = true; level.gametype.pickableItemsMask = ( level.gametype.spawnableItemsMask|level.gametype.dropableItemsMask ); if( GS_Instagib() ) level.gametype.pickableItemsMask &= ~G_INSTAGIB_NEGATE_ITEMMASK; // clear player stats and scores, team scores and respawn clients in team lists for( i = TEAM_PLAYERS; i < GS_MAX_TEAMS; i++ ) { int j; g_teamlist_t *team = &teamlist[i]; memset( &team->stats, 0, sizeof( team->stats ) ); // respawn all clients inside the playing teams for( j = 0; j < team->numplayers; j++ ) { edict_t *ent = &game.edicts[ team->playerIndices[j] ]; G_ClientClearStats( ent ); G_ClientRespawn( ent, false ); } } // set items to be spawned with a delay G_Items_RespawnByType( IT_ARMOR, ARMOR_RA, 15 ); G_Items_RespawnByType( IT_ARMOR, ARMOR_RA, 15 ); G_Items_RespawnByType( IT_HEALTH, HEALTH_MEGA, 15 ); G_Items_RespawnByType( IT_HEALTH, HEALTH_ULTRA, 15 ); G_Items_RespawnByType( IT_POWERUP, 0, brandom( 20, 40 ) ); G_Match_FreeBodyQueue(); G_AnnouncerSound( NULL, trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_FIGHT_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, false, NULL ); G_CenterPrintMsg( NULL, "FIGHT!" ); }
/* * W_Fire_Blade */ void W_Fire_Blade( edict_t *self, int range, vec3_t start, vec3_t angles, float damage, int knockback, int stun, int mod, int timeDelta ) { edict_t *event, *other = NULL; vec3_t end; trace_t trace; int mask = MASK_SHOT; vec3_t dir; int dmgflags = 0; if( GS_Instagib() ) damage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); if( GS_RaceGametype() ) mask = MASK_SOLID; G_Trace4D( &trace, start, NULL, NULL, end, self, MASK_SHOT, timeDelta ); if( trace.ent == -1 ) //didn't touch anything return; // find out what touched other = &game.edicts[trace.ent]; if( !other->takedamage ) // it was the world { // wall impact VectorMA( trace.endpos, -0.02, dir, end ); event = G_SpawnEvent( EV_BLADE_IMPACT, 0, end ); event->s.ownerNum = ENTNUM( self ); VectorScale( trace.plane.normal, 1024, event->s.origin2 ); event->r.svflags = SVF_TRANSMITORIGIN2; return; } // it was a player G_Damage( other, self, self, dir, dir, other->s.origin, damage, knockback, stun, dmgflags, mod ); }
void W_Fire_Riotgun( edict_t *self, vec3_t start, vec3_t angles, int seed, int range, int spread, int count, float damage, int knockback, int stun, int mod, int timeDelta ) { vec3_t dir; edict_t *event; int dmgflags = 0; if( GS_Instagib() ) damage = 9999; AngleVectors( angles, dir, NULL, NULL ); // send the event event = G_SpawnEvent( EV_FIRE_RIOTGUN, seed, start ); event->s.ownerNum = ENTNUM( self ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 4096, event->s.origin2 ); // DirToByte is too inaccurate event->s.weapon = WEAP_RIOTGUN; if( mod == MOD_RIOTGUN_S ) event->s.weapon |= EV_INVERSE; G_Fire_SpiralPattern( self, start, dir, &seed, count, spread, range, damage, knockback, stun, dmgflags, mod, timeDelta ); }
/* * W_Fire_Bullet */ void W_Fire_Bullet( edict_t *self, vec3_t start, vec3_t fv, vec3_t rv, vec3_t uv, int seed, int range, int hspread, int vspread, float damage, int knockback, int stun, int mod, int timeDelta ) { edict_t *event; float r, u; double alpha, s; trace_t trace; int dmgflags = DAMAGE_STUN_CLAMP | DAMAGE_KNOCKBACK_SOFT; if( GS_Instagib() ) { damage = 9999; } // send the event event = G_SpawnEvent( EV_FIRE_BULLET, seed, start ); event->s.ownerNum = ENTNUM( self ); VectorCopy( fv, event->s.origin2 ); VectorCopy( rv, event->s.origin3 ); event->s.weapon = WEAP_MACHINEGUN; event->s.firemode = ( mod == MOD_MACHINEGUN_S ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; // circle shape alpha = M_PI * Q_crandom( &seed ); // [-PI ..+PI] s = fabs( Q_crandom( &seed ) ); // [0..1] r = s * cos( alpha ) * hspread; u = s * sin( alpha ) * vspread; GS_TraceBullet( &trace, start, fv, rv, uv, r, u, range, ENTNUM( self ), timeDelta ); if( trace.ent != -1 ) { if( game.edicts[trace.ent].takedamage ) { G_Damage( &game.edicts[trace.ent], self, self, fv, fv, trace.endpos, damage, knockback, stun, dmgflags, mod ); } else { if( !( trace.surfFlags & SURF_NOIMPACT ) ) { } } } }
/* * G_SetClientStats */ void G_SetClientStats( edict_t *ent ) { gclient_t *client = ent->r.client; int team, i; if( ent->r.client->resp.chase.active ) // in chasecam it copies the other player stats return; // // layouts // client->ps.stats[STAT_LAYOUTS] = 0; // don't force scoreboard when dead during timeout if( ent->r.client->level.showscores || GS_MatchState() >= MATCH_STATE_POSTMATCH ) client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_SCOREBOARD; if( GS_TeamBasedGametype() && !GS_InvidualGameType() ) client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_TEAMTAB; if( GS_HasChallengers() && ent->r.client->queueTimeStamp ) client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_CHALLENGER; if( GS_MatchState() <= MATCH_STATE_WARMUP && level.ready[PLAYERNUM( ent )] ) client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_READY; if( G_SpawnQueue_GetSystem( ent->s.team ) == SPAWNSYSTEM_INSTANT ) client->ps.stats[STAT_LAYOUTS] |= STAT_LAYOUT_INSTANTRESPAWN; // // team // client->ps.stats[STAT_TEAM] = client->ps.stats[STAT_REALTEAM] = ent->s.team; // // health // if( ent->s.team == TEAM_SPECTATOR ) client->ps.stats[STAT_HEALTH] = STAT_NOTSET; // no health for spectator else client->ps.stats[STAT_HEALTH] = HEALTH_TO_INT( ent->health ); client->r.frags = client->ps.stats[STAT_SCORE]; // // armor // if( GS_Instagib() ) { if( g_instashield->integer ) client->ps.stats[STAT_ARMOR] = ARMOR_TO_INT( 100.0f * ( client->resp.instashieldCharge / INSTA_SHIELD_MAX ) ); else client->ps.stats[STAT_ARMOR] = 0; } else client->ps.stats[STAT_ARMOR] = ARMOR_TO_INT( client->resp.armor ); // // pickup message // if( level.time > client->resp.pickup_msg_time ) { client->ps.stats[STAT_PICKUP_ITEM] = 0; } // // frags // if( ent->s.team == TEAM_SPECTATOR ) { client->ps.stats[STAT_SCORE] = STAT_NOTSET; // no frags for spectators } else { client->ps.stats[STAT_SCORE] = ent->r.client->level.stats.score; } // // Team scores // if( GS_TeamBasedGametype() ) { // team based i = 0; for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ ) { client->ps.stats[STAT_TEAM_ALPHA_SCORE+i] = teamlist[team].stats.score; i++; } // mark the rest as not set for(; team < GS_MAX_TEAMS; team++ ) { client->ps.stats[STAT_TEAM_ALPHA_SCORE+i] = STAT_NOTSET; i++; } } else { // not team based i = 0; for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ ) { client->ps.stats[STAT_TEAM_ALPHA_SCORE+i] = STAT_NOTSET; i++; } } // spawn system client->ps.stats[STAT_NEXT_RESPAWN] = ceil( G_SpawnQueue_NextRespawnTime( client->team ) * 0.001f ); // pointed player client->ps.stats[STAT_POINTED_TEAMPLAYER] = 0; client->ps.stats[STAT_POINTED_PLAYER] = G_FindPointedPlayer( ent ); if( client->ps.stats[STAT_POINTED_PLAYER] && GS_TeamBasedGametype() ) { edict_t *e = &game.edicts[client->ps.stats[STAT_POINTED_PLAYER]]; if( e->s.team == ent->s.team ) { int pointedhealth = HEALTH_TO_INT( e->health ); int pointedarmor = 0; int available_bits = 0; bool mega = false; if( pointedhealth < 0 ) pointedhealth = 0; if( pointedhealth > 100 ) { pointedhealth -= 100; mega = true; if( pointedhealth > 100 ) pointedhealth = 100; } pointedhealth /= 3.2; if( GS_Armor_TagForCount( e->r.client->resp.armor ) ) { pointedarmor = ARMOR_TO_INT( e->r.client->resp.armor ); } if( pointedarmor > 150 ) { pointedarmor = 150; } pointedarmor /= 5; client->ps.stats[STAT_POINTED_TEAMPLAYER] = ( ( pointedhealth &0x1F )|( pointedarmor&0x3F )<<6|( available_bits&0xF )<<12 ); if( mega ) { client->ps.stats[STAT_POINTED_TEAMPLAYER] |= 0x20; } } } // last killer. ignore world and team kills if( client->teamstate.last_killer ) { edict_t *targ = ent, *attacker = client->teamstate.last_killer; client->ps.stats[STAT_LAST_KILLER] = (attacker->r.client && !GS_IsTeamDamage( &targ->s, &attacker->s ) ? ENTNUM( attacker ) : 0); } else { client->ps.stats[STAT_LAST_KILLER] = 0; } }
edict_t *Drop_Item( edict_t *ent, const gsitem_t *item ) { edict_t *dropped; vec3_t forward, right; vec3_t offset; if( !G_Gametype_CanDropItem( item, false ) ) return NULL; dropped = G_Spawn(); dropped->classname = item->classname; dropped->item = item; dropped->spawnflags = DROPPED_ITEM; VectorCopy( item_box_mins, dropped->r.mins ); VectorCopy( item_box_maxs, dropped->r.maxs ); dropped->r.solid = SOLID_TRIGGER; dropped->movetype = MOVETYPE_TOSS; dropped->touch = drop_temp_touch; dropped->stop = AI_AddGoalEntity; dropped->r.owner = ent; dropped->r.svflags &= ~SVF_NOCLIENT; dropped->s.team = ent->s.team; dropped->s.type = ET_ITEM; dropped->s.itemNum = item->tag; dropped->s.effects = 0; // default effects are applied client side dropped->s.modelindex = trap_ModelIndex( dropped->item->world_model[0] ); dropped->s.modelindex2 = trap_ModelIndex( dropped->item->world_model[1] ); dropped->attenuation = 1; if( ent->r.client ) { trace_t trace; AngleVectors( ent->r.client->ps.viewangles, forward, right, NULL ); VectorSet( offset, 24, 0, -16 ); G_ProjectSource( ent->s.origin, offset, forward, right, dropped->s.origin ); G_Trace( &trace, ent->s.origin, dropped->r.mins, dropped->r.maxs, dropped->s.origin, ent, CONTENTS_SOLID ); VectorCopy( trace.endpos, dropped->s.origin ); dropped->spawnflags |= DROPPED_PLAYER_ITEM; // ugly hack for dropping backpacks if( item->tag == AMMO_PACK_WEAK || item->tag == AMMO_PACK_STRONG || item->tag == AMMO_PACK ) { int w; bool anything = false; for( w = WEAP_GUNBLADE + 1; w < WEAP_TOTAL; w++ ) { if( w == WEAP_INSTAGUN && !GS_Instagib() ) continue; if( item->tag == AMMO_PACK_WEAK || item->tag == AMMO_PACK ) { int weakTag = GS_FindItemByTag( w )->weakammo_tag; if( ent->r.client->ps.inventory[weakTag] > 0 ) { dropped->invpak[weakTag] = ent->r.client->ps.inventory[weakTag]; ent->r.client->ps.inventory[weakTag] = 0; anything = true; } } if( item->tag == AMMO_PACK_STRONG || item->tag == AMMO_PACK ) { int strongTag = GS_FindItemByTag( w )->ammo_tag; if( ent->r.client->ps.inventory[strongTag] ) { dropped->invpak[strongTag] = ent->r.client->ps.inventory[strongTag]; ent->r.client->ps.inventory[strongTag] = 0; anything = true; } } } if( !anything ) // if nothing was added to the pack, don't bother spawning it { G_FreeEdict( dropped ); return NULL; } } // power-ups are special if( ( item->type & IT_POWERUP ) && item->quantity ) { if( ent->r.client->ps.inventory[item->tag] ) { dropped->count = ent->r.client->ps.inventory[item->tag]; ent->r.client->ps.inventory[item->tag] = 0; } else { dropped->count = item->quantity; } } ent->r.client->teamstate.last_drop_item = item; VectorCopy( dropped->s.origin, ent->r.client->teamstate.last_drop_location ); } else { AngleVectors( ent->s.angles, forward, right, NULL ); VectorCopy( ent->s.origin, dropped->s.origin ); // ugly hack for dropping backpacks if( item->tag == AMMO_PACK_WEAK || item->tag == AMMO_PACK_STRONG || item->tag == AMMO_PACK ) { int w; for( w = WEAP_GUNBLADE + 1; w < WEAP_TOTAL; w++ ) { if( w == WEAP_INSTAGUN && !GS_Instagib() ) continue; if( item->tag == AMMO_PACK_WEAK || item->tag == AMMO_PACK ) { gsitem_t *ammo = GS_FindItemByTag( GS_FindItemByTag( w )->weakammo_tag ); if( ammo ) dropped->invpak[ammo->tag] = ammo->quantity; } if( item->tag == AMMO_PACK_STRONG || item->tag == AMMO_PACK ) { gsitem_t *ammo = GS_FindItemByTag( GS_FindItemByTag( w )->ammo_tag ); if( ammo ) dropped->invpak[ammo->tag] = ammo->quantity; } } } // power-ups are special if( ( item->type & IT_POWERUP ) && item->quantity ) { dropped->count = item->quantity; } } VectorScale( forward, 100, dropped->velocity ); dropped->velocity[2] = 300; dropped->think = drop_make_touchable; dropped->nextThink = level.time + 1000; GClip_LinkEntity( dropped ); return dropped; }
/* * G_CheckCvars * Check for cvars that have been modified and need the game to be updated */ void G_CheckCvars( void ) { if( g_antilag_maxtimedelta->modified ) { if( g_antilag_maxtimedelta->integer < 0 ) trap_Cvar_SetValue( "g_antilag_maxtimedelta", abs( g_antilag_maxtimedelta->integer ) ); g_antilag_maxtimedelta->modified = false; g_antilag_timenudge->modified = true; } if( g_antilag_timenudge->modified ) { if( g_antilag_timenudge->integer > g_antilag_maxtimedelta->integer ) trap_Cvar_SetValue( "g_antilag_timenudge", g_antilag_maxtimedelta->integer ); else if( g_antilag_timenudge->integer < -g_antilag_maxtimedelta->integer ) trap_Cvar_SetValue( "g_antilag_timenudge", -g_antilag_maxtimedelta->integer ); g_antilag_timenudge->modified = false; } if( g_warmup_timelimit->modified ) { // if we are inside timelimit period, update the endtime if( GS_MatchState() == MATCH_STATE_WARMUP ) { gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)fabs( 60.0f * 1000 * g_warmup_timelimit->integer ); } g_warmup_timelimit->modified = false; } if( g_timelimit->modified ) { // if we are inside timelimit period, update the endtime if( GS_MatchState() == MATCH_STATE_PLAYTIME && !GS_MatchExtended() ) { if( g_timelimit->value ) gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)fabs( 60.0f * 1000 * g_timelimit->value ); else gs.gameState.longstats[GAMELONG_MATCHDURATION] = 0; } g_timelimit->modified = false; } if( g_match_extendedtime->modified ) { // if we are inside extended_time period, update the endtime if( GS_MatchExtended() ) { if( g_match_extendedtime->integer ) gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)fabs( 60 * 1000 * g_match_extendedtime->value ); } g_match_extendedtime->modified = false; } if( g_allow_falldamage->modified ) { g_allow_falldamage->modified = false; } // update gameshared server settings // FIXME: This should be restructured so gameshared settings are the master settings GS_GamestatSetFlag( GAMESTAT_FLAG_INSTAGIB, ( g_instagib->integer != 0 ) ); GS_GamestatSetFlag( GAMESTAT_FLAG_FALLDAMAGE, ( g_allow_falldamage->integer != 0 ) ); GS_GamestatSetFlag( GAMESTAT_FLAG_SELFDAMAGE, ( g_allow_selfdamage->integer != 0 ) ); GS_GamestatSetFlag( GAMESTAT_FLAG_HASCHALLENGERS, ( level.gametype.hasChallengersQueue != 0 ) ); GS_GamestatSetFlag( GAMESTAT_FLAG_ISTEAMBASED, ( level.gametype.isTeamBased != 0 ) ); GS_GamestatSetFlag( GAMESTAT_FLAG_ISRACE, ( level.gametype.isRace != 0 ) ); GS_GamestatSetFlag( GAMESTAT_FLAG_COUNTDOWN, level.gametype.countdownEnabled ); GS_GamestatSetFlag( GAMESTAT_FLAG_INHIBITSHOOTING, level.gametype.shootingDisabled ); GS_GamestatSetFlag( GAMESTAT_FLAG_INFINITEAMMO, ( level.gametype.infiniteAmmo || GS_Instagib() ) != 0 ); GS_GamestatSetFlag( GAMESTAT_FLAG_CANFORCEMODELS, level.gametype.canForceModels ); GS_GamestatSetFlag( GAMESTAT_FLAG_CANSHOWMINIMAP, level.gametype.canShowMinimap ); GS_GamestatSetFlag( GAMESTAT_FLAG_TEAMONLYMINIMAP, level.gametype.teamOnlyMinimap ); GS_GamestatSetFlag( GAMESTAT_FLAG_MMCOMPATIBLE, level.gametype.mmCompatible ); GS_GamestatSetLongFlag( GAMELONG_FLAG_ISTUTORIAL, ( level.gametype.isTutorial != 0 ) ); gs.gameState.stats[GAMESTAT_MAXPLAYERSINTEAM] = level.gametype.maxPlayersPerTeam; clamp( gs.gameState.stats[GAMESTAT_MAXPLAYERSINTEAM], 0, 255 ); }
/* * ClientThink */ void ClientThink( edict_t *ent, usercmd_t *ucmd, int timeDelta ) { gclient_t *client; int i, j; static pmove_t pm; int delta, count; client = ent->r.client; client->ps.POVnum = ENTNUM( ent ); client->ps.playerNum = PLAYERNUM( ent ); // anti-lag if( ent->r.svflags & SVF_FAKECLIENT ) { client->timeDelta = 0; } else { int nudge; int fixedNudge = ( game.snapFrameTime ) * 0.5; // fixme: find where this nudge comes from. // add smoothing to timeDelta between the last few ucmds and a small fine-tuning nudge. nudge = fixedNudge + g_antilag_timenudge->integer; timeDelta += nudge; clamp( timeDelta, -g_antilag_maxtimedelta->integer, 0 ); // smooth using last valid deltas i = client->timeDeltasHead - 6; if( i < 0 ) i = 0; for( count = 0, delta = 0; i < client->timeDeltasHead; i++ ) { if( client->timeDeltas[i & G_MAX_TIME_DELTAS_MASK] < 0 ) { delta += client->timeDeltas[i & G_MAX_TIME_DELTAS_MASK]; count++; } } if( !count ) client->timeDelta = timeDelta; else { delta /= count; client->timeDelta = ( delta + timeDelta ) * 0.5; } client->timeDeltas[client->timeDeltasHead & G_MAX_TIME_DELTAS_MASK] = timeDelta; client->timeDeltasHead++; #ifdef UCMDTIMENUDGE client->timeDelta += client->pers.ucmdTimeNudge; #endif } clamp( client->timeDelta, -g_antilag_maxtimedelta->integer, 0 ); // update activity if he touched any controls if( ucmd->forwardmove != 0 || ucmd->sidemove != 0 || ucmd->upmove != 0 || ( ucmd->buttons & ~BUTTON_BUSYICON ) != 0 || client->ucmd.angles[PITCH] != ucmd->angles[PITCH] || client->ucmd.angles[YAW] != ucmd->angles[YAW] ) G_Client_UpdateActivity( client ); client->ucmd = *ucmd; // can exit intermission after two seconds, not counting postmatch if( GS_MatchState() == MATCH_STATE_WAITEXIT && ( ucmd->buttons & BUTTON_ATTACK ) && game.serverTime > GS_MatchStartTime() + 2000 ) level.exitNow = true; // (is this really needed?:only if not cared enough about ps in the rest of the code) // refresh player state position from the entity VectorCopy( ent->s.origin, client->ps.pmove.origin ); VectorCopy( ent->velocity, client->ps.pmove.velocity ); VectorCopy( ent->s.angles, client->ps.viewangles ); client->ps.pmove.gravity = level.gravity; if( GS_MatchState() >= MATCH_STATE_POSTMATCH || GS_MatchPaused() || ( ent->movetype != MOVETYPE_PLAYER && ent->movetype != MOVETYPE_NOCLIP ) ) client->ps.pmove.pm_type = PM_FREEZE; else if( ent->s.type == ET_GIB ) client->ps.pmove.pm_type = PM_GIB; else if( ent->movetype == MOVETYPE_NOCLIP || client->isTV ) client->ps.pmove.pm_type = PM_SPECTATOR; else client->ps.pmove.pm_type = PM_NORMAL; // set up for pmove memset( &pm, 0, sizeof( pmove_t ) ); pm.playerState = &client->ps; if( !client->isTV ) pm.cmd = *ucmd; if( memcmp( &client->old_pmove, &client->ps.pmove, sizeof( pmove_state_t ) ) ) pm.snapinitial = true; // perform a pmove Pmove( &pm ); // save results of pmove client->old_pmove = client->ps.pmove; // update the entity with the new position VectorCopy( client->ps.pmove.origin, ent->s.origin ); VectorCopy( client->ps.pmove.velocity, ent->velocity ); VectorCopy( client->ps.viewangles, ent->s.angles ); ent->viewheight = client->ps.viewheight; VectorCopy( pm.mins, ent->r.mins ); VectorCopy( pm.maxs, ent->r.maxs ); ent->waterlevel = pm.waterlevel; ent->watertype = pm.watertype; if( pm.groundentity == -1 ) { ent->groundentity = NULL; } else { G_AwardResetPlayerComboStats( ent ); ent->groundentity = &game.edicts[pm.groundentity]; ent->groundentity_linkcount = ent->groundentity->linkcount; } GClip_LinkEntity( ent ); GS_AddLaserbeamPoint( &ent->r.client->resp.trail, &ent->r.client->ps, ucmd->serverTimeStamp ); // Regeneration if( ent->r.client->ps.inventory[POWERUP_REGEN] > 0 && ent->health < 200) { ent->health += ( game.frametime * 0.001f ) * 10.0f; // Regen expires if health reaches 200 if ( ent->health >= 199.0f ) ent->r.client->ps.inventory[POWERUP_REGEN]--; } // fire touch functions if( ent->movetype != MOVETYPE_NOCLIP ) { edict_t *other; // touch other objects for( i = 0; i < pm.numtouch; i++ ) { other = &game.edicts[pm.touchents[i]]; for( j = 0; j < i; j++ ) { if( &game.edicts[pm.touchents[j]] == other ) break; } if( j != i ) continue; // duplicated // player can't touch projectiles, only projectiles can touch the player G_CallTouch( other, ent, NULL, 0 ); } } ent->s.weapon = GS_ThinkPlayerWeapon( &client->ps, ucmd->buttons, ucmd->msec, client->timeDelta ); if( G_IsDead( ent ) ) { if( ent->deathTimeStamp + g_respawn_delay_min->integer <= level.time ) client->resp.snap.buttons |= ucmd->buttons; } else if( client->ps.pmove.stats[PM_STAT_NOUSERCONTROL] <= 0 ) client->resp.snap.buttons |= ucmd->buttons; // trigger the instashield if( GS_Instagib() && g_instashield->integer ) { if( client->ps.pmove.pm_type == PM_NORMAL && pm.cmd.upmove < 0 && client->resp.instashieldCharge == INSTA_SHIELD_MAX && client->ps.inventory[POWERUP_SHELL] == 0 ) { client->ps.inventory[POWERUP_SHELL] = client->resp.instashieldCharge; G_Sound( ent, CHAN_AUTO, trap_SoundIndex( GS_FindItemByTag( POWERUP_SHELL )->pickup_sound ), ATTN_NORM ); } } // if( client->ps.pmove.pm_type == PM_NORMAL ) client->level.stats.had_playtime = true; // generating plrkeys (optimized for net communication) ClientMakePlrkeys( client, ucmd ); }
/* * G_Damage * targ entity that is being damaged * inflictor entity that is causing the damage * attacker entity that caused the inflictor to damage targ * example: targ=enemy, inflictor=rocket, attacker=player * * dir direction of the attack * point point at which the damage is being inflicted * normal normal vector from that point * damage amount of damage being inflicted * knockback force to be applied against targ as a result of the damage * * dflags these flags are used to control how T_Damage works */ void G_Damage( edict_t *targ, edict_t *inflictor, edict_t *attacker, const vec3_t pushdir, const vec3_t dmgdir, const vec3_t point, float damage, float knockback, float stun, int dflags, int mod ) { gclient_t *client; float take; float save; float asave; qboolean statDmg; if( !targ || !targ->takedamage ) return; if( !attacker ) { attacker = world; mod = MOD_TRIGGER_HURT; } meansOfDeath = mod; client = targ->r.client; // Cgg - race mode: players don't interact with one another if( GS_RaceGametype() ) { if( attacker->r.client && targ->r.client && attacker != targ ) return; } // push if( !( dflags & DAMAGE_NO_KNOCKBACK ) ) G_KnockBackPush( targ, attacker, pushdir, knockback, dflags ); // stun if( g_allow_stun->integer && !( dflags & (DAMAGE_NO_STUN|FL_GODMODE) ) && (int)stun > 0 && targ->r.client && targ->r.client->resp.takeStun && !GS_IsTeamDamage( &targ->s, &attacker->s ) && ( targ != attacker ) ) { if( dflags & DAMAGE_STUN_CLAMP ) { if( targ->r.client->ps.pmove.stats[PM_STAT_STUN] < (int)stun ) targ->r.client->ps.pmove.stats[PM_STAT_STUN] = (int)stun; } else targ->r.client->ps.pmove.stats[PM_STAT_STUN] += (int)stun; clamp( targ->r.client->ps.pmove.stats[PM_STAT_STUN], 0, MAX_STUN_TIME ); } // dont count self-damage cause it just adds the same to both stats statDmg = ( attacker != targ ) && ( mod != MOD_TELEFRAG ); // apply handicap on the damage given if( statDmg && attacker->r.client && !GS_Instagib() ) { // handicap is a percentage value if( attacker->r.client->handicap != 0 ) damage *= 1.0 - (attacker->r.client->handicap * 0.01f); } take = damage; save = 0; // check for cases where damage is protected if( !( dflags & DAMAGE_NO_PROTECTION ) ) { // check for godmode if( targ->flags & FL_GODMODE ) { take = 0; save = damage; } // never damage in timeout else if( GS_MatchPaused() ) { take = save = 0; } // ca has self splash damage disabled else if( ( dflags & DAMAGE_RADIUS ) && attacker == targ && !GS_SelfDamage() ) { take = save = 0; } // don't get damage from players in race else if( ( GS_RaceGametype() ) && attacker->r.client && targ->r.client && ( attacker->r.client != targ->r.client ) ) { take = save = 0; } // team damage avoidance else if( GS_IsTeamDamage( &targ->s, &attacker->s ) && !G_Gametype_CanTeamDamage( dflags ) ) { take = save = 0; } // apply warShell powerup protection else if( targ->r.client && targ->r.client->ps.inventory[POWERUP_SHELL] > 0 ) { // warshell offers full protection in instagib if( GS_Instagib() ) { take = 0; save = damage; } else { take = ( damage * 0.25f ); save = damage - take; } // todo : add protection sound } } asave = G_CheckArmor( targ, take, dflags ); take -= asave; //treat cheat/powerup savings the same as armor asave += save; // APPLY THE DAMAGES if( !take && !asave ) return; // do the damage if( take <= 0 ) return; // adding damage given/received to stats if( statDmg && attacker->r.client && !targ->deadflag && targ->movetype != MOVETYPE_PUSH && targ->s.type != ET_CORPSE ) { attacker->r.client->level.stats.total_damage_given += take + asave; teamlist[attacker->s.team].stats.total_damage_given += take + asave; if( GS_IsTeamDamage( &targ->s, &attacker->s ) ) { attacker->r.client->level.stats.total_teamdamage_given += take + asave; teamlist[attacker->s.team].stats.total_teamdamage_given += take + asave; } } G_Gametype_ScoreEvent( attacker->r.client, "dmg", va( "%i %f %i", targ->s.number, damage, attacker->s.number ) ); if( statDmg && client ) { client->level.stats.total_damage_received += take + asave; teamlist[targ->s.team].stats.total_damage_received += take + asave; if( GS_IsTeamDamage( &targ->s, &attacker->s ) ) { client->level.stats.total_teamdamage_received += take + asave; teamlist[targ->s.team].stats.total_teamdamage_received += take + asave; } } // accumulate received damage for snapshot effects { vec3_t dorigin; if( inflictor == world && mod == MOD_FALLING ) // it's fall damage targ->snap.damage_fall += take + save; if( point[0] != 0.0f || point[1] != 0.0f || point[2] != 0.0f ) VectorCopy( point, dorigin ); else VectorSet( dorigin, targ->s.origin[0], targ->s.origin[1], targ->s.origin[2] + targ->viewheight ); G_BlendFrameDamage( targ, take, &targ->snap.damage_taken, dorigin, dmgdir, targ->snap.damage_at, targ->snap.damage_dir ); G_BlendFrameDamage( targ, save, &targ->snap.damage_saved, dorigin, dmgdir, targ->snap.damage_at, targ->snap.damage_dir ); if( targ->r.client ) { if( mod != MOD_FALLING && mod != MOD_TELEFRAG && mod != MOD_SUICIDE ) { if( inflictor == world || attacker == world ) { // for world inflicted damage use always 'frontal' G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, NULL ); } else if( dflags & DAMAGE_RADIUS ) { // for splash hits the direction is from the inflictor origin G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, pushdir ); } else { // for direct hits the direction is the projectile direction G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, dmgdir ); } } } } targ->health = targ->health - take; // add damage done to stats if( !GS_IsTeamDamage( &targ->s, &attacker->s ) && statDmg && G_ModToAmmo( mod ) != AMMO_NONE && client && attacker->r.client ) { attacker->r.client->level.stats.accuracy_hits[G_ModToAmmo( mod )-AMMO_GUNBLADE]++; attacker->r.client->level.stats.accuracy_damage[G_ModToAmmo( mod )-AMMO_GUNBLADE] += damage; teamlist[attacker->s.team].stats.accuracy_hits[G_ModToAmmo( mod )-AMMO_GUNBLADE]++; teamlist[attacker->s.team].stats.accuracy_damage[G_ModToAmmo( mod )-AMMO_GUNBLADE] += damage; G_AwardPlayerHit( targ, attacker, mod ); } // accumulate given damage for hit sounds if( ( take || asave ) && targ != attacker && client && !targ->deadflag ) { if( attacker ) { if( GS_IsTeamDamage( &targ->s, &attacker->s ) ) attacker->snap.damageteam_given += take + asave; // we want to know how good our hit was, so saved also matters else attacker->snap.damage_given += take + asave; } } if( G_IsDead( targ ) ) { if( client ) targ->flags |= FL_NO_KNOCKBACK; G_Killed( targ, inflictor, attacker, HEALTH_TO_INT( take ), point, mod ); } else { G_CallPain( targ, attacker, knockback, take ); } }
void W_Fire_Electrobolt_FullInstant( edict_t *self, vec3_t start, vec3_t angles, float maxdamage, float mindamage, int maxknockback, int minknockback, int stun, int range, int minDamageRange, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event, *hit, *damaged; int mask; qboolean missed = qtrue; int dmgflags = 0; #define FULL_DAMAGE_RANGE g_projectile_prestep->value if( GS_Instagib() ) maxdamage = mindamage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; hit = damaged = NULL; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); clamp_high( minDamageRange, range ); if( minDamageRange <= FULL_DAMAGE_RANGE ) minDamageRange = FULL_DAMAGE_RANGE + 1; if( range <= FULL_DAMAGE_RANGE + 1 ) range = FULL_DAMAGE_RANGE + 1; tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched hit = &game.edicts[tr.ent]; if( hit == world ) // stop dead if hit the world break; if( hit->movetype == MOVETYPE_NONE || hit->movetype == MOVETYPE_PUSH ) break; // allow trail to go through BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( hit->s.modelindex ) ) ignore = hit; if( ( hit != self ) && ( hit->takedamage ) ) { float frac, damage, knockback, dist; dist = DistanceFast( tr.endpos, start ); if( dist <= FULL_DAMAGE_RANGE ) frac = 0.0f; else { frac = ( dist - FULL_DAMAGE_RANGE ) / (float)( minDamageRange - FULL_DAMAGE_RANGE ); clamp( frac, 0.0f, 1.0f ); } damage = maxdamage - ( ( maxdamage - mindamage ) * frac ); knockback = maxknockback - ( ( maxknockback - minknockback ) * frac ); //G_Printf( "mindamagerange %i frac %.1f damage %i\n", minDamageRange, 1.0f - frac, (int)damage ); G_Damage( hit, self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = FIRE_MODE_STRONG; if( hit->r.client ) missed = qfalse; damaged = hit; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_ELECTROTRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); event->s.firemode = FIRE_MODE_STRONG; #undef FULL_DAMAGE_RANGE }
/* * W_Fire_Electrobolt_Combined */ void W_Fire_Electrobolt_Combined( edict_t *self, vec3_t start, vec3_t angles, float maxdamage, float mindamage, float maxknockback, float minknockback, int stun, int range, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event, *hit, *damaged; int mask; qboolean missed = qtrue; int dmgflags = 0; int fireMode; #ifdef ELECTROBOLT_TEST fireMode = FIRE_MODE_WEAK; #else fireMode = FIRE_MODE_STRONG; #endif if( GS_Instagib() ) maxdamage = mindamage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; hit = damaged = NULL; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched hit = &game.edicts[tr.ent]; if( hit == world ) // stop dead if hit the world break; if( hit->movetype == MOVETYPE_NONE || hit->movetype == MOVETYPE_PUSH ) break; // allow trail to go through BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( hit->s.modelindex ) ) ignore = hit; if( ( hit != self ) && ( hit->takedamage ) ) { float frac, damage, knockback; frac = DistanceFast( tr.endpos, start ) / (float)range; clamp( frac, 0.0f, 1.0f ); damage = maxdamage - ( ( maxdamage - mindamage ) * frac ); knockback = maxknockback - ( ( maxknockback - minknockback ) * frac ); G_Damage( hit, self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = fireMode; if( hit->r.client ) missed = qfalse; damaged = hit; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_ELECTROTRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); event->s.firemode = fireMode; if( !GS_Instagib() && tr.ent == -1 ) // didn't touch anything, not even a wall { edict_t *bolt; gs_weapon_definition_t *weapondef = GS_GetWeaponDef( self->s.weapon ); // fire a weak EB from the end position bolt = W_Fire_Electrobolt_Weak( self, end, angles, weapondef->firedef_weak.speed, mindamage, minknockback, minknockback, stun, weapondef->firedef_weak.timeout, mod, timeDelta ); bolt->enemy = damaged; } }
/* * W_Fire_Instagun_Strong */ void W_Fire_Instagun( edict_t *self, vec3_t start, vec3_t angles, float damage, int knockback, int stun, int radius, int range, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event; int mask; qboolean missed = qtrue; int dmgflags = 0; if( GS_Instagib() ) damage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched if( tr.ent == world->s.number || game.edicts[tr.ent].movetype == MOVETYPE_NONE || game.edicts[tr.ent].movetype == MOVETYPE_PUSH ) { if( g_instajump->integer && self && self->r.client ) { // create a temporary inflictor entity edict_t *inflictor; inflictor = G_Spawn(); inflictor->s.solid = SOLID_NOT; inflictor->timeDelta = 0; VectorCopy( tr.endpos, inflictor->s.origin ); inflictor->s.ownerNum = ENTNUM( self ); inflictor->projectileInfo.maxDamage = 0; inflictor->projectileInfo.minDamage = 0; inflictor->projectileInfo.maxKnockback = knockback; inflictor->projectileInfo.minKnockback = 1; inflictor->projectileInfo.stun = 0; inflictor->projectileInfo.radius = radius; G_RadiusDamage( inflictor, self, &tr.plane, NULL, mod ); G_FreeEdict( inflictor ); } break; } // allow trail to go through SOLID_BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( game.edicts[tr.ent].s.modelindex ) ) ignore = &game.edicts[tr.ent]; if( ( &game.edicts[tr.ent] != self ) && ( game.edicts[tr.ent].takedamage ) ) { G_Damage( &game.edicts[tr.ent], self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_INSTA_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = FIRE_MODE_STRONG; if( game.edicts[tr.ent].r.client ) missed = qfalse; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_INSTATRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); }
/* * CG_DamageIndicatorAdd */ void CG_DamageIndicatorAdd( int damage, const vec3_t dir ) { int i; unsigned int damageTime; vec3_t playerAngles; mat3_t playerAxis; // epsilons are 30 degrees #define INDICATOR_EPSILON 0.5f #define INDICATOR_EPSILON_UP 0.85f #define TOP_BLEND 0 #define RIGHT_BLEND 1 #define BOTTOM_BLEND 2 #define LEFT_BLEND 3 float blends[4]; float forward, side; if( !cg_damage_indicator->integer ) return; playerAngles[PITCH] = 0; playerAngles[YAW] = cg.predictedPlayerState.viewangles[YAW]; playerAngles[ROLL] = 0; Matrix3_FromAngles( playerAngles, playerAxis ); if( cg_damage_indicator_time->value < 0 ) trap_Cvar_SetValue( "cg_damage_indicator_time", 0 ); Vector4Set( blends, 0, 0, 0, 0 ); damageTime = damage * cg_damage_indicator_time->value; // up and down go distributed equally to all blends and assumed when no dir is given if( !dir || VectorCompare( dir, vec3_origin ) || cg_damage_indicator->integer == 2 || GS_Instagib() || ( fabs( DotProduct( dir, &playerAxis[AXIS_UP] ) ) > INDICATOR_EPSILON_UP ) ) { blends[RIGHT_BLEND] += damageTime; blends[LEFT_BLEND] += damageTime; blends[TOP_BLEND] += damageTime; blends[BOTTOM_BLEND] += damageTime; } else { side = DotProduct( dir, &playerAxis[AXIS_RIGHT] ); if( side > INDICATOR_EPSILON ) blends[LEFT_BLEND] += damageTime; else if( side < -INDICATOR_EPSILON ) blends[RIGHT_BLEND] += damageTime; forward = DotProduct( dir, &playerAxis[AXIS_FORWARD] ); if( forward > INDICATOR_EPSILON ) blends[BOTTOM_BLEND] += damageTime; else if( forward < -INDICATOR_EPSILON ) blends[TOP_BLEND] += damageTime; } for( i = 0; i < 4; i++ ) { if( cg.damageBlends[i] < cg.time + blends[i] ) cg.damageBlends[i] = cg.time + blends[i]; } #undef TOP_BLEND #undef RIGHT_BLEND #undef BOTTOM_BLEND #undef LEFT_BLEND #undef INDICATOR_EPSILON #undef INDICATOR_EPSILON_UP }