Example #1
0
void G_AwardPlayerPickup( edict_t *self, edict_t *item )
{
    if( GS_RaceGametype() ) //racesow: no awards for item timings; will be included in basewsw
        return;

	if( !item )
		return;

	// MH control
	if( item->item->tag == HEALTH_MEGA )
	{
		self->r.client->resp.awardInfo.mh_control_award++;
		if( self->r.client->resp.awardInfo.mh_control_award % 5 == 0 )
			G_PlayerAward( self, S_COLOR_CYAN "Mega-Health Control!" );
	}

	// UH control
	if( item->item->tag == HEALTH_ULTRA )
	{
		self->r.client->resp.awardInfo.uh_control_award++;
		if( self->r.client->resp.awardInfo.uh_control_award % 5 == 0 )
			G_PlayerAward( self, S_COLOR_CYAN "Ultra-Health Control!" );
	}

	// RA control
	if( item->item->tag == ARMOR_RA )
	{
		self->r.client->resp.awardInfo.ra_control_award++;
		if( self->r.client->resp.awardInfo.ra_control_award % 5 == 0 )
			G_PlayerAward( self, S_COLOR_CYAN "Red Armor Control!" );
	}
}
Example #2
0
/*
* W_Plasma_Backtrace
*/
void W_Plasma_Backtrace( edict_t *ent, const vec3_t start )
{
	trace_t	tr;
	vec3_t oldorigin;
	vec3_t mins = { -2, -2, -2 }, maxs = { 2, 2, 2 };

	if( GS_RaceGametype() )
		return;

	VectorCopy( ent->s.origin, oldorigin );
	VectorCopy( start, ent->s.origin );

	do
	{
		G_Trace4D( &tr, ent->s.origin, mins, maxs, oldorigin, ent, ( CONTENTS_BODY|CONTENTS_CORPSE ), ent->timeDelta );

		VectorCopy( tr.endpos, ent->s.origin );

		if( tr.ent == -1 )
			break;
		if( tr.allsolid || tr.startsolid )
			W_Touch_Plasma( ent, &game.edicts[tr.ent], NULL, 0 );
		else if( tr.fraction != 1.0 )
			W_Touch_Plasma( ent, &game.edicts[tr.ent], &tr.plane, tr.surfFlags );
		else
			break;
	} while( ent->r.inuse && ent->s.type == ET_PLASMA && !VectorCompare( ent->s.origin, oldorigin ) );

	if( ent->r.inuse && ent->s.type == ET_PLASMA )
		VectorCopy( oldorigin, ent->s.origin );
}
Example #3
0
/*
* W_Fire_LinearProjectile - Spawn a generic linear projectile without a model, touch func, sound nor mod
*/
static edict_t *W_Fire_LinearProjectile( 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 timeDelta )
{
	edict_t	*projectile;
	vec3_t dir;

	projectile = G_Spawn();
	VectorCopy( start, projectile->s.origin );
	VectorCopy( start, projectile->s.old_origin );
	VectorCopy( start, projectile->olds.origin );

	VectorCopy( angles, projectile->s.angles );
	AngleVectors( angles, dir, NULL, NULL );
	VectorScale( dir, speed, projectile->velocity );
	GS_SnapVelocity( projectile->velocity );

	projectile->movetype = MOVETYPE_LINEARPROJECTILE;
	projectile->s.linearProjectile = qtrue;

	projectile->r.solid = SOLID_YES;
	projectile->r.clipmask = ( !GS_RaceGametype() ) ? MASK_SHOT : MASK_SOLID;

	projectile->r.svflags = SVF_PROJECTILE;
	// enable me when drawing exception is added to cgame
	projectile->r.svflags |= SVF_TRANSMITORIGIN2;
	VectorClear( projectile->r.mins );
	VectorClear( projectile->r.maxs );
	projectile->s.modelindex = 0;
	projectile->r.owner = self;
	projectile->s.ownerNum = ENTNUM( self );
	projectile->touch = W_Touch_Projectile; //generic one. Should be replaced after calling this func
	projectile->nextThink = level.time + timeout;
	projectile->think = G_FreeEdict;
	projectile->classname = NULL; // should be replaced after calling this func.
	projectile->style = 0;
	projectile->s.sound = 0;
	projectile->timeStamp = level.time;
	projectile->s.linearProjectileTimeStamp = game.serverTime;
	projectile->timeDelta = timeDelta;

	projectile->projectileInfo.minDamage = min( minDamage, damage );
	projectile->projectileInfo.maxDamage = damage;
	projectile->projectileInfo.minKnockback = min( minKnockback, maxKnockback );
	projectile->projectileInfo.maxKnockback = maxKnockback;
	projectile->projectileInfo.stun = stun;
	projectile->projectileInfo.radius = radius;

	GClip_LinkEntity( projectile );

	// update some data required for the transmission
	VectorCopy( projectile->velocity, projectile->s.linearProjectileVelocity );
	projectile->s.team = self->s.team;
	projectile->s.modelindex2 = ( abs( timeDelta ) > 255 ) ? 255 : (unsigned int)abs( timeDelta );
	return projectile;
}
Example #4
0
/*
* Touch_Item
*/
void Touch_Item( edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags )
{
	bool taken;
	const gsitem_t *item = ent->item;

	if( !other->r.client || G_ISGHOSTING( other ) )
		return;

	if( !( other->r.client->ps.pmove.stats[PM_STAT_FEATURES] & PMFEAT_ITEMPICK ) )
		return;

	if( !item || !( item->flags & ITFLAG_PICKABLE ) )
		return; // not a grabbable item

	if( !G_Gametype_CanPickUpItem( item ) )
		return;

	taken = G_PickupItem( other, item, ent->spawnflags, ent->count, ent->invpak );

	if( !( ent->spawnflags & ITEM_TARGETS_USED ) )
	{
		G_UseTargets( ent, other );
		ent->spawnflags |= ITEM_TARGETS_USED;
	}

	if( !taken )
		return;

	if( ent->spawnflags & ITEM_TIMED )
		ent->r.owner = other;

	// flash the screen
	G_AddPlayerStateEvent( other->r.client, PSEV_PICKUP, ( item->flags & IT_WEAPON ? item->tag : 0 ) );

	G_AwardPlayerPickup( other, ent );

	// for messages
	other->r.client->teamstate.last_pickup = ent;

	// show icon and name on status bar
	other->r.client->ps.stats[STAT_PICKUP_ITEM] = item->tag;
	other->r.client->resp.pickup_msg_time = level.time + 3000;

	if( ent->attenuation )
		Touch_ItemSound( other, item );

	if( !( ent->spawnflags & DROPPED_ITEM ) && G_Gametype_CanRespawnItem( item ) )
	{
		if( (item->type & IT_WEAPON ) && GS_RaceGametype() )
			return; // weapons stay in race
		SetRespawn( ent, G_Gametype_RespawnTimeForItem( item ) );
		return;
	}
	G_FreeEdict( ent );
}
Example #5
0
/*
* W_Fire_TossProjectile - Spawn a generic projectile without a model, touch func, sound nor mod
*/
static edict_t *W_Fire_TossProjectile( 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 timeDelta )
{
	edict_t	*projectile;
	vec3_t dir;

	projectile = G_Spawn();
	VectorCopy( start, projectile->s.origin );
	VectorCopy( start, projectile->s.old_origin );
	VectorCopy( start, projectile->olds.origin );

	VectorCopy( angles, projectile->s.angles );
	AngleVectors( angles, dir, NULL, NULL );
	VectorScale( dir, speed, projectile->velocity );
	GS_SnapVelocity( projectile->velocity );

	projectile->movetype = MOVETYPE_BOUNCEGRENADE;

	// make missile fly through players in race
	if( GS_RaceGametype() )
		projectile->r.clipmask = MASK_SOLID;
	else
		projectile->r.clipmask = MASK_SHOT;

	projectile->r.solid = SOLID_YES;
	projectile->r.svflags = SVF_PROJECTILE;
	VectorClear( projectile->r.mins );
	VectorClear( projectile->r.maxs );
	//projectile->s.modelindex = trap_ModelIndex ("models/objects/projectile/plasmagun/proj_plasmagun2.md3");
	projectile->s.modelindex = 0;
	projectile->r.owner = self;
	projectile->touch = W_Touch_Projectile; //generic one. Should be replaced after calling this func
	projectile->nextThink = level.time + timeout;
	projectile->think = G_FreeEdict;
	projectile->classname = NULL; // should be replaced after calling this func.
	projectile->style = 0;
	projectile->s.sound = 0;
	projectile->timeStamp = level.time;
	projectile->timeDelta = timeDelta;
	projectile->s.team = self->s.team;

	projectile->projectileInfo.minDamage = min( minDamage, damage );
	projectile->projectileInfo.maxDamage = damage;
	projectile->projectileInfo.minKnockback = min( minKnockback, maxKnockback );
	projectile->projectileInfo.maxKnockback = maxKnockback;
	projectile->projectileInfo.stun = stun;
	projectile->projectileInfo.radius = radius;

	GClip_LinkEntity( projectile );

	return projectile;
}
Example #6
0
/*
* Items may be spawned above other entities and they need them spawned before
*/
void G_Items_FinishSpawningItems( void )
{
	int num_timers, num_opts;
	edict_t *ent;
	edict_t *ops[MAX_EDICTS];

	num_timers = num_opts = 0;
	for( ent = game.edicts + 1 + gs.maxclients; ENTNUM( ent ) < game.numentities; ent++ )
	{
		if( !ent->r.inuse || !ent->item || ent->s.type != ET_ITEM )
			continue;

		Finish_SpawningItem( ent );

		// spawned inside solid
		if( !ent->r.inuse )
			continue;

		if( G_ItemTimerNeeded( ent->item ) && !GS_RaceGametype() ) //racesow: no item timers; will be included in basewsw if not, use the AS fix from ticket #246#comment:6
		{
			if( Spawn_ItemTimer( ent ) )
				num_timers++;
		}
		else if( G_ItemTimerUnimportant( ent->item ) )
		{
			ops[num_opts++] = ent;
		}
	}

	ops[num_opts] = NULL;

	// if there are less timers than MAX_IMPORTANT_ITEMS_THRESHOLD, spawn
	// timers for less important items
	if( num_timers < MAX_IMPORTANT_ITEMS_THRESHOLD && !GS_RaceGametype() ) //racesow: no item timers; will be included in basewsw
	{
		for( ; num_opts > 0; num_opts-- )
			Spawn_ItemTimer( ops[num_opts-1] );
	}
}
Example #7
0
/*
* ClientDisconnect
* Called when a player drops from the server.
* Will not be called between levels.
*/
void ClientDisconnect( edict_t *ent, const char *reason )
{
	int team;

	if( !ent->r.client || !ent->r.inuse )
		return;

	// always report in RACE mode
	if( GS_RaceGametype() 
		|| ( ent->r.client->team != TEAM_SPECTATOR && ( GS_MatchState() == MATCH_STATE_PLAYTIME || GS_MatchState() == MATCH_STATE_POSTMATCH ) ) )
		G_AddPlayerReport( ent, GS_MatchState() == MATCH_STATE_POSTMATCH );

	for( team = TEAM_PLAYERS; team < GS_MAX_TEAMS; team++ )
		G_Teams_UnInvitePlayer( team, ent );

	if( !level.gametype.disableObituaries || !(ent->r.svflags & SVF_FAKECLIENT ) )
	{
		if( !reason )
			G_PrintMsg( NULL, "%s" S_COLOR_WHITE " disconnected\n", ent->r.client->netname );
		else
			G_PrintMsg( NULL, "%s" S_COLOR_WHITE " disconnected (%s" S_COLOR_WHITE ")\n", ent->r.client->netname, reason );
	}

	// send effect
	if( ent->s.team > TEAM_SPECTATOR )
		G_TeleportEffect( ent, false );

	ent->r.client->team = TEAM_SPECTATOR;
	G_ClientRespawn( ent, true ); // respawn as ghost
	ent->movetype = MOVETYPE_NOCLIP; // allow freefly

	// let the gametype scripts know this client just disconnected
	G_Gametype_ScoreEvent( ent->r.client, "disconnect", NULL );

	G_FreeAI( ent );
	AI_EnemyRemoved( ent );

	ent->r.inuse = false;
	ent->r.svflags = SVF_NOCLIENT;

	memset( ent->r.client, 0, sizeof( *ent->r.client ) );
	ent->r.client->ps.playerNum = PLAYERNUM( ent );

	trap_ConfigString( CS_PLAYERINFOS+PLAYERNUM( ent ), "" );
	GClip_UnlinkEntity( ent );

	G_Match_CheckReadys();
}
Example #8
0
/*
* Cmd_Kill_f
*/
static void Cmd_Kill_f( edict_t *ent )
{
	if( ent->r.solid == SOLID_NOT )
		return;

	// can suicide after 5 seconds
	if( level.time < ent->r.client->resp.timeStamp + ( GS_RaceGametype() ? 1000 : 5000 ) )
		return;

	ent->flags &= ~FL_GODMODE;
	ent->health = 0;
	meansOfDeath = MOD_SUICIDE;

	// wsw : pb : fix /kill command
	G_Killed( ent, ent, ent, 100000, vec3_origin, MOD_SUICIDE );
}
Example #9
0
void G_AwardPlayerPickup( edict_t *self, edict_t *item )
{
    if( GS_RaceGametype() ) //racesow: no awards for item timings; will be included in basewsw //FIXME: Doesn't seem like it was included ... -K1ll
        return;

    if( !item )
        return;

    // MH control
    if( item->item->tag == HEALTH_MEGA )
    {
        self->r.client->level.stats.mh_taken++;
        self->r.client->resp.awardInfo.mh_control_award++;
        if( self->r.client->resp.awardInfo.mh_control_award % 5 == 0 )
            G_PlayerAward( self, S_COLOR_CYAN "Mega-Health Control!" );
    }

    // UH control
    else if( item->item->tag == HEALTH_ULTRA )
    {
        self->r.client->level.stats.uh_taken++;
        self->r.client->resp.awardInfo.uh_control_award++;
        if( self->r.client->resp.awardInfo.uh_control_award % 5 == 0 )
            G_PlayerAward( self, S_COLOR_CYAN "Ultra-Health Control!" );
    }

    // RA control
    else if( item->item->tag == ARMOR_RA )
    {
        self->r.client->level.stats.ra_taken++;
        self->r.client->resp.awardInfo.ra_control_award++;
        if( self->r.client->resp.awardInfo.ra_control_award % 5 == 0 )
            G_PlayerAward( self, S_COLOR_CYAN "Red Armor Control!" );
    }

    // Other items counts
    else if( item->item->tag == ARMOR_GA )
        self->r.client->level.stats.ga_taken++;
    else if( item->item->tag == ARMOR_YA )
        self->r.client->level.stats.ya_taken++;
    else if( item->item->tag == POWERUP_QUAD )
        self->r.client->level.stats.quads_taken++;
    else if( item->item->tag == POWERUP_REGEN )
        self->r.client->level.stats.regens_taken++;
    else if( item->item->tag == POWERUP_SHELL )
        self->r.client->level.stats.shells_taken++;
}
Example #10
0
/*
* G_TriggerWait
* 
* Called always when using a trigger that supports wait flag
* Returns true if the trigger shouldn't be activated
*/
static bool G_TriggerWait( edict_t *ent, edict_t *other )
{
	if( GS_RaceGametype() )
	{
		if( other->trigger_entity == ent && other->trigger_timeout && other->trigger_timeout >= level.time )
			return true;

		other->trigger_entity = ent;
		other->trigger_timeout = level.time + 1000 * ent->wait;
		return false;
	}

	if( ent->timeStamp >= level.time )
		return true;

	// the wait time has passed, so set back up for another activation
	ent->timeStamp = level.time + ( ent->wait * 1000 );
	return false;
}
Example #11
0
/*
* 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 );
}
Example #12
0
/*
* Pickup_Weapon
*/
bool Pickup_Weapon( edict_t *other, const gsitem_t *item, int flags, int ammo_count )
{
	int ammo_tag;
	gs_weapon_definition_t *weapondef;

	weapondef = GS_GetWeaponDef( item->tag );

	if( !(flags & DROPPED_ITEM) )
	{
		// weapons stay in race
		if( GS_RaceGametype() && ( other->r.client->ps.inventory[item->tag] != 0 ) )
			return false;
	}

	other->r.client->ps.inventory[item->tag]++;

	// never allow the player to carry more than 2 copies of the same weapon
	if( other->r.client->ps.inventory[item->tag] > item->inventory_max )
		other->r.client->ps.inventory[item->tag] = item->inventory_max;

	if( !(flags & DROPPED_ITEM) )
	{
		// give them some ammo with it
		ammo_tag = item->ammo_tag;
		if( ammo_tag )
			Add_Ammo( other->r.client, GS_FindItemByTag( ammo_tag ), weapondef->firedef.weapon_pickup, true );
	}
	else
	{    
		// it's a dropped weapon
		ammo_tag = item->ammo_tag;
		if( ammo_count && ammo_tag )
			Add_Ammo( other->r.client, GS_FindItemByTag( ammo_tag ), ammo_count, true );
	}

	return true;
}
Example #13
0
/*
* 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 );
	}
}
Example #14
0
/*
* G_Match_LaunchState
*/
void G_Match_LaunchState( int matchState )
{
	static bool advance_queue = false;

	if( game.asEngine != NULL )
	{
		// give the gametype a chance to refuse the state change, or to set up things for it
		if( !GT_asCallMatchStateFinished( matchState ) )
			return;
	}
	else
	{
		// There isn't any script, run generic fuction
		if( !G_Gametype_GENERIC_MatchStateFinished( matchState ) )
			return;
	}

	GS_GamestatSetFlag( GAMESTAT_FLAG_MATCHEXTENDED, false );
	GS_GamestatSetFlag( GAMESTAT_FLAG_WAITING, false );
	
	if( matchState == MATCH_STATE_POSTMATCH ) {
		level.finalMatchDuration = game.serverTime - GS_MatchStartTime();
	}

    if( ( matchState == MATCH_STATE_POSTMATCH && GS_RaceGametype() )
        || ( matchState != MATCH_STATE_POSTMATCH && gs.gameState.stats[GAMESTAT_MATCHSTATE] == MATCH_STATE_POSTMATCH ) )
	{
		// entering postmatch in race or leaving postmatch in normal gt
		G_Match_SendReport();
		trap_MM_GameState( false );
	}

	switch( matchState )
	{
	default:
	case MATCH_STATE_WARMUP:
		{
			advance_queue = false;
			level.forceStart = false;

			gs.gameState.stats[GAMESTAT_MATCHSTATE] = MATCH_STATE_WARMUP;
			gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)( fabs( g_warmup_timelimit->value * 60 ) * 1000 );
			gs.gameState.longstats[GAMELONG_MATCHSTART] = game.serverTime;

			// race has playtime in warmup too, so flag the matchmaker about this
			if( GS_RaceGametype() )
				trap_MM_GameState( true );

			break;
		}

	case MATCH_STATE_COUNTDOWN:
		{
			advance_queue = true;

			gs.gameState.stats[GAMESTAT_MATCHSTATE] = MATCH_STATE_COUNTDOWN;
			gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)( fabs( g_countdown_time->value ) * 1000 );
			gs.gameState.longstats[GAMELONG_MATCHSTART] = game.serverTime;

			break;
		}

	case MATCH_STATE_PLAYTIME:
		{
			// ch : should clear some statcollection memory from warmup?

			advance_queue = true; // shouldn't be needed here
			level.forceStart = false;

			gs.gameState.stats[GAMESTAT_MATCHSTATE] = MATCH_STATE_PLAYTIME;
			gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)( fabs( 60 * g_timelimit->value )*1000 );
			gs.gameState.longstats[GAMELONG_MATCHSTART] = game.serverTime;

			// request a new match UUID
			trap_ConfigString( CS_MATCHUUID, "" );

			// tell matchmaker that the game is on, so if
			// client disconnects before SendReport, it is flagged
			// as 'purgable' on MM side
			trap_MM_GameState( true );
		}
		break;

	case MATCH_STATE_POSTMATCH:
		{
			gs.gameState.stats[GAMESTAT_MATCHSTATE] = MATCH_STATE_POSTMATCH;
			gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)fabs( g_postmatch_timelimit->value * 1000 ); // postmatch time in seconds
			gs.gameState.longstats[GAMELONG_MATCHSTART] = game.serverTime;

			G_Timeout_Reset();
			level.teamlock = false;
			level.forceExit = false;

			G_Match_Autorecord_Stats();
		}
		break;

	case MATCH_STATE_WAITEXIT:
		{
			if( advance_queue )
			{
				G_Teams_AdvanceChallengersQueue();
				advance_queue = true;
			}

			gs.gameState.stats[GAMESTAT_MATCHSTATE] = MATCH_STATE_WAITEXIT;
			gs.gameState.longstats[GAMELONG_MATCHDURATION] = 25000;
			gs.gameState.longstats[GAMELONG_MATCHSTART] = game.serverTime;

			level.exitNow = false;
		}
		break;
	}

	// give the gametype the chance to setup for the new state

	if( game.asEngine != NULL )
		GT_asCallMatchStateStarted();
	else
		G_Gametype_GENERIC_MatchStateStarted();

	G_UpdatePlayersMatchMsgs();
}
Example #15
0
/*
* G_UpdateServerInfo
* update the cvars which show the match state at server browsers
*/
static void G_UpdateServerInfo( void )
{
	// g_match_time
	if( GS_MatchState() <= MATCH_STATE_WARMUP )
	{
		trap_Cvar_ForceSet( "g_match_time", "Warmup" );
	}
	else if( GS_MatchState() == MATCH_STATE_COUNTDOWN )
	{
		trap_Cvar_ForceSet( "g_match_time", "Countdown" );
	}
	else if( GS_MatchState() == MATCH_STATE_PLAYTIME )
	{
		// partly from G_GetMatchState
		char extra[MAX_INFO_VALUE];
		int clocktime, timelimit, mins, secs;

		if( GS_MatchDuration() )
			timelimit = ( ( GS_MatchDuration() ) * 0.001 ) / 60;
		else
			timelimit = 0;

		clocktime = (float)( game.serverTime - GS_MatchStartTime() ) * 0.001f;

		if( clocktime <= 0 )
		{
			mins = 0;
			secs = 0;
		}
		else
		{
			mins = clocktime / 60;
			secs = clocktime - mins * 60;
		}

		extra[0] = 0;
		if( GS_MatchExtended() )
		{
			if( timelimit )
				Q_strncatz( extra, " overtime", sizeof( extra ) );
			else
				Q_strncatz( extra, " suddendeath", sizeof( extra ) );
		}
		if( GS_MatchPaused() )
			Q_strncatz( extra, " (in timeout)", sizeof( extra ) );

		if( timelimit )
			trap_Cvar_ForceSet( "g_match_time", va( "%02i:%02i / %02i:00%s", mins, secs, timelimit, extra ) );
		else
			trap_Cvar_ForceSet( "g_match_time", va( "%02i:%02i%s", mins, secs, extra ) );
	}
	else
	{
		trap_Cvar_ForceSet( "g_match_time", "Finished" );
	}

	// g_match_score
	if( GS_MatchState() >= MATCH_STATE_PLAYTIME && GS_TeamBasedGametype() )
	{
		char score[MAX_INFO_STRING];

		score[0] = 0;
		Q_strncatz( score, va( " %s: %i", GS_TeamName( TEAM_ALPHA ), teamlist[TEAM_ALPHA].stats.score ), sizeof( score ) );
		Q_strncatz( score, va( " %s: %i", GS_TeamName( TEAM_BETA ), teamlist[TEAM_BETA].stats.score ), sizeof( score ) );

		if( strlen( score ) >= MAX_INFO_VALUE ) {
			// prevent "invalid info cvar value" flooding
			score[0] = '\0';
		}
		trap_Cvar_ForceSet( "g_match_score", score );
	}
	else
	{
		trap_Cvar_ForceSet( "g_match_score", "" );
	}

	// g_needpass
	if( password->modified )
	{
		if( password->string && strlen( password->string ) )
		{
			trap_Cvar_ForceSet( "g_needpass", "1" );
		}
		else
		{
			trap_Cvar_ForceSet( "g_needpass", "0" );
		}
		password->modified = false;
	}

	// g_gametypes_available
	if( g_votable_gametypes->modified || g_disable_vote_gametype->modified )
	{
		if( g_disable_vote_gametype->integer || !g_votable_gametypes->string || !strlen( g_votable_gametypes->string ) )
		{
			trap_Cvar_ForceSet( "g_gametypes_available", "" );
		}
		else
		{
			char *votable;
			char *name;
			size_t len;
			int count;

			len = 0;

			for( count = 0; ( name = G_ListNameForPosition( g_gametypes_list->string, count, CHAR_GAMETYPE_SEPARATOR ) ) != NULL; count++ )
			{
				if( G_Gametype_IsVotable( name ) )
					len += strlen( name ) + 1;
			}

			len++;
			votable = ( char * )G_Malloc( len );
			votable[0] = 0;

			for( count = 0; ( name = G_ListNameForPosition( g_gametypes_list->string, count, CHAR_GAMETYPE_SEPARATOR ) ) != NULL; count++ )
			{
				if( G_Gametype_IsVotable( name ) )
				{
					Q_strncatz( votable, name, len );
					Q_strncatz( votable, " ", len );
				}
			}

			//votable[ strlen( votable )-2 ] = 0; // remove the last space
			trap_Cvar_ForceSet( "g_gametypes_available", votable );
			G_Free( votable );
		}

		g_votable_gametypes->modified = false;
		g_disable_vote_gametype->modified = false;
	}

	if( GS_RaceGametype() ) {
		trap_Cvar_ForceSet( "g_race_gametype", "1" );
	}
	else {
		trap_Cvar_ForceSet( "g_race_gametype", "0" );
	}
}
Example #16
0
/*
* G_FireWeapon
*/
void G_FireWeapon( edict_t *ent, int parm )
{
	gs_weapon_definition_t *weapondef;
	firedef_t *firedef;
	edict_t *projectile;
	vec3_t origin, angles;
	vec3_t viewoffset = { 0, 0, 0 };
	int ucmdSeed;
	// racesow
	float prestep;
	// !racesow

	weapondef = GS_GetWeaponDef( ( parm & ~EV_INVERSE ) );
	firedef = ( parm & EV_INVERSE ) ? &weapondef->firedef : &weapondef->firedef_weak;

	// find this shot projection source
	if( ent->r.client )
	{
		viewoffset[2] += ent->r.client->ps.viewheight;
		VectorCopy( ent->r.client->ps.viewangles, angles );
		is_quad = ( ent->r.client->ps.inventory[POWERUP_QUAD] > 0 );
		ucmdSeed = ent->r.client->ucmd.serverTimeStamp & 255;
	}
	else
	{
		VectorCopy( ent->s.angles, angles );
		is_quad = qfalse;
		ucmdSeed = rand() & 255;
	}

	VectorAdd( ent->s.origin, viewoffset, origin );

	// racesow
	prestep=g_projectile_prestep->value;
	// !racesow

	// shoot 

	projectile = NULL;

	switch( weapondef->weapon_id )
	{
	default:
	case WEAP_NONE:
		break;

	case WEAP_GUNBLADE:
		if( firedef->fire_mode == FIRE_MODE_STRONG )
			projectile = G_Fire_Gunblade_Blast( origin, angles, firedef, ent, ucmdSeed );
		else
			projectile = G_Fire_Gunblade_Knife( origin, angles, firedef, ent );
		break;

	case WEAP_MACHINEGUN:
		projectile = G_Fire_Machinegun( origin, angles, firedef, ent, ucmdSeed );
		break;

	case WEAP_RIOTGUN:
		projectile = G_Fire_Riotgun( origin, angles, firedef, ent, ucmdSeed );
		break;

	case WEAP_GRENADELAUNCHER:
		projectile = G_Fire_Grenade( origin, angles, firedef, ent, ucmdSeed );
		// racesow
		if( GS_RaceGametype() )
			//prestep/=2; // racesow 0.42 had default prestep=48 and genade prestep=24
			prestep=trap_Cvar_Get( "rs_grenade_prestep", "90", CVAR_ARCHIVE )->integer;
		// !racesow
		break;

	case WEAP_ROCKETLAUNCHER:
		projectile = G_Fire_Rocket( origin, angles, firedef, ent, ucmdSeed );
		// racesow
		if( GS_RaceGametype() )
			//prestep=0; // racesow 0.42 had rocket prestep=0
			prestep=trap_Cvar_Get( "rs_rocket_prestep", "90", CVAR_ARCHIVE )->integer;
		// !racesow
		break;
	case WEAP_PLASMAGUN:
		projectile = G_Fire_Plasma( origin, angles, firedef, ent, ucmdSeed );
		// racesow
		if( GS_RaceGametype() )
			//prestep*=2/3; // racesow 0.42 had plasma prestep=32
			prestep=trap_Cvar_Get( "rs_plasma_prestep", "90", CVAR_ARCHIVE )->integer;
		// !racesow
		break;

	case WEAP_LASERGUN:
		projectile = G_Fire_Lasergun( origin, angles, firedef, ent, ucmdSeed );
		break;

	case WEAP_ELECTROBOLT:
		projectile = G_Fire_StrongBolt( origin, angles, firedef, ent, ucmdSeed );
		break;

	case WEAP_INSTAGUN:
		projectile = G_Fire_Instagun( origin, angles, firedef, ent, ucmdSeed );
		break;
	}

	// add stats
	if( ent->r.client && weapondef->weapon_id != WEAP_NONE ) 
		ent->r.client->level.stats.accuracy_shots[firedef->ammo_id - AMMO_GUNBLADE] += firedef->projectile_count;

	if( projectile )
	{
		//if( projectile->s.linearProjectile ) // convert distance to time for linear projectiles
		//	G_ProjectileTimePrestep( projectile, 1000.0f * ( g_projectile_prestep->value / VectorLengthFast( projectile->velocity ) ) );
		//else
			//G_ProjectileDistancePrestep( projectile, g_projectile_prestep->value ); //racesow Seems like this was added in warsow 0.7 -K1ll
		// racesow: modified prestep
		G_ProjectileDistancePrestep( projectile, prestep );
		// !racesow
	}

	// racesow: enable skipping no_antilag if rs_rocket_antilag is 1
	if ( GS_RaceGametype() && ((trap_Cvar_Get( "rs_rocket_antilag", "0", CVAR_ARCHIVE )->integer==1 && projectile->s.type == ET_ROCKET)))
		return;
	// !racesow

#ifdef NO_ROCKET_ANTILAG
	// hack for disabling antilag on rockets
	if( projectile && (projectile->s.type == ET_ROCKET || projectile->s.type == ET_PLASMA) )//racesow
	{
		int timeOffset;

		timeOffset = -projectile->timeDelta;
		projectile->timeDelta = 0;
		if( projectile->s.linearProjectile )
			projectile->s.modelindex2 = 0;

		// racesow: testing .42 time prestep function, because im really not sure it is equivalent to the .5 one; the difference is not that major anyway..
		//  G_ProjectileTimePrestep( projectile, timeOffset );
		rs_TimeDeltaPrestepProjectile(projectile,-timeOffset);
		// !racesow
	}
#endif
}
Example #17
0
/*
* CopyToBodyQue
*/
static edict_t *CopyToBodyQue( edict_t *ent, edict_t *attacker, int damage )
{
	edict_t	*body;
	int contents;

	if( GS_RaceGametype() )
		return NULL;

	contents = G_PointContents( ent->s.origin );
	if( contents & CONTENTS_NODROP )
		return NULL;

	G_Client_UnlinkBodies( ent );

	// grab a body que and cycle to the next one
	body = &game.edicts[gs.maxclients + level.body_que + 1];
	level.body_que = ( level.body_que + 1 ) % BODY_QUEUE_SIZE;

	// send an effect on the removed body
	if( body->s.modelindex && body->s.type == ET_CORPSE )
		ThrowSmallPileOfGibs( body, 10 );

	GClip_UnlinkEntity( body );

	memset( body, 0, sizeof( edict_t ) ); //clean up garbage

	//init body edict
	G_InitEdict( body );
	body->classname = "body";
	body->health = ent->health;
	body->mass = ent->mass;
	body->r.owner = ent->r.owner;
	body->s.type = ent->s.type;
	body->s.team = ent->s.team;
	body->s.effects = 0;
	body->r.svflags = SVF_CORPSE;
	body->r.svflags &= ~SVF_NOCLIENT;
	body->activator = ent;
	if( g_deadbody_followkiller->integer )
		body->enemy = attacker;

	//use flat yaw
	body->s.angles[PITCH] = 0;
	body->s.angles[ROLL] = 0;
	body->s.angles[YAW] = ent->s.angles[YAW];
	body->s.modelindex2 = 0; // <-  is bodyOwner when in ET_CORPSE, but not in ET_GENERIC or ET_PLAYER
	body->s.weapon = 0;

	//copy player position and box size
	VectorCopy( ent->s.old_origin, body->s.old_origin );
	VectorCopy( ent->s.origin, body->s.origin );
	VectorCopy( ent->s.origin, body->olds.origin );
	VectorCopy( ent->r.mins, body->r.mins );
	VectorCopy( ent->r.maxs, body->r.maxs );
	VectorCopy( ent->r.absmin, body->r.absmin );
	VectorCopy( ent->r.absmax, body->r.absmax );
	VectorCopy( ent->r.size, body->r.size );
	VectorCopy( ent->velocity, body->velocity );
	body->r.maxs[2] = body->r.mins[2] + 8;

	body->r.solid = SOLID_YES;
	body->takedamage = DAMAGE_YES;
	body->r.clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
	body->movetype = MOVETYPE_TOSS;
	body->die = body_die;
	body->think = body_think; // body self destruction countdown

	if( ent->health < GIB_HEALTH
		|| meansOfDeath == MOD_ELECTROBOLT_S /* electrobolt always gibs */ )
	{
		ThrowSmallPileOfGibs( body, damage );

		// reset gib impulse
		VectorClear( body->velocity );
		ThrowClientHead( body, damage ); // sets ET_GIB

		body->s.frame = 0;
		body->nextThink = level.time + 3000 + random() * 3000;
		body->deadflag = DEAD_DEAD;
	}
	else if( ent->s.type == ET_PLAYER )
	{
		// copy the model
		body->s.type = ET_CORPSE;
		body->s.modelindex = ent->s.modelindex;
		body->s.bodyOwner = ent->s.number; // bodyOwner is the same as modelindex2
		body->s.skinnum = ent->s.skinnum;
		body->s.teleported = true;

		// launch the death animation on the body
		{
			static int i;
			i = ( i+1 )%3;
			G_AddEvent( body, EV_DIE, i, true );
			switch( i )
			{
			default:
			case 0:
				body->s.frame = ( ( BOTH_DEAD1&0x3F )|( BOTH_DEAD1&0x3F )<<6|( 0 &0xF )<<12 );
				break;
			case 1:
				body->s.frame = ( ( BOTH_DEAD2&0x3F )|( BOTH_DEAD2&0x3F )<<6|( 0 &0xF )<<12 );
				break;
			case 2:
				body->s.frame = ( ( BOTH_DEAD3&0x3F )|( BOTH_DEAD3&0x3F )<<6|( 0 &0xF )<<12 );
				break;
			}
		}

		body->think = body_ready;
		body->takedamage = DAMAGE_NO;
		body->r.solid = SOLID_NOT;
		body->nextThink = level.time + 500; // make damageable in 0.5 seconds
	}
	else // wasn't a player, just copy it's model
	{
		VectorClear( body->velocity );
		body->s.modelindex = ent->s.modelindex;
		body->s.frame = ent->s.frame;
		body->nextThink = level.time + 5000 + random()*10000;
	}

	GClip_LinkEntity( body );
	return body;
}
Example #18
0
/*
* G_SplashFrac
*/
void G_SplashFrac( const vec3_t origin, const vec3_t mins, const vec3_t maxs, const vec3_t point, float maxradius, vec3_t pushdir, float *kickFrac, float *dmgFrac )
{
#define VERTICALBIAS 0.65f // 0...1
#define CAPSULEDISTANCE
#define SPLASH_HDIST_CLAMP 53
	vec3_t boxcenter = { 0, 0, 0 };
	vec3_t hitpoint, vec;
	float distance;
	int i;
	float innerradius;
	float outerradius;
	float refdistance;

	if( maxradius <= 0 )
	{
		if( kickFrac )
			*kickFrac = 0;
		if( dmgFrac )
			*dmgFrac = 0;
		if( pushdir )
			VectorClear( pushdir );
		return;
	}

	VectorCopy( point, hitpoint );

	innerradius = ( maxs[0] + maxs[1] - mins[0] - mins[1] ) * 0.25;
	outerradius = ( sqrt( maxs[0]*maxs[0] + maxs[1]*maxs[1] ) + sqrt( mins[0]*mins[0] + mins[1]*mins[1] ) ) * 0.5;

#ifdef CAPSULEDISTANCE
	// Find the distance to the closest point in the capsule contained in the player bbox
	// modify the origin so the inner sphere acts as a capsule
	VectorCopy( origin, boxcenter );
	boxcenter[2] = hitpoint[2];
	clamp( boxcenter[2], ( origin[2] + mins[2] ) + innerradius, ( origin[2] + maxs[2] ) - innerradius );
#else
	// find center of the box
	for( i = 0; i < 3; i++ )
		boxcenter[i] = origin[i] + ( 0.5f * ( maxs[i] + mins[i] ) );
#endif

	// find push intensity
	distance = DistanceFast( boxcenter, hitpoint );

	if( distance >= maxradius )
	{
		if( kickFrac )
			*kickFrac = 0;
		if( dmgFrac )
			*dmgFrac = 0;
		if( pushdir )
			VectorClear( pushdir );
		return;
	}

	refdistance = innerradius;
	if( refdistance >= maxradius )
	{
		if( kickFrac )
			*kickFrac = 0;
		if( dmgFrac )
			*dmgFrac = 0;
		if( pushdir )
			VectorClear( pushdir );
		return;
	}

	maxradius -= refdistance;
	distance -= refdistance;
	if( distance < 0 )
		distance = 0;

	distance = maxradius - distance;
	clamp( distance, 0, maxradius );

	if( dmgFrac )
	{
		// soft sin curve
		*dmgFrac = sin( DEG2RAD( ( distance / maxradius ) * 80 ) );
		clamp( *dmgFrac, 0.0f, 1.0f );
	}

	if( kickFrac )
	{
		// linear kick fraction
		float kick = ( distance / maxradius );

		// half linear half exponential
		//*kickFrac =  ( kick + ( kick * kick ) ) * 0.5f;

		// linear
		*kickFrac = kick;

		clamp( *kickFrac, 0.0f, 1.0f );
	}

	//if( dmgFrac && kickFrac )
	//	G_Printf( "SPLASH: dmgFrac %.2f kickFrac %.2f\n", *dmgFrac, *kickFrac );

	// find push direction

	if( pushdir )
	{
#ifdef CAPSULEDISTANCE
		// find real center of the box again
		for( i = 0; i < 3; i++ )
			boxcenter[i] = origin[i] + ( 0.5f * ( maxs[i] + mins[i] ) );
#endif

#ifdef VERTICALBIAS
		// move the center up for the push direction
		if( ( origin[2] + maxs[2] > boxcenter[2] ) && !GS_RaceGametype())// racesow don't do this in racesow
			boxcenter[2] += VERTICALBIAS * ( ( origin[2] + maxs[2] ) - boxcenter[2] );
#endif // VERTICALBIAS

#ifdef SPLASH_HDIST_CLAMP
		// if pushed from below, hack the hitpoint to limit the side push direction
		if( hitpoint[2] < boxcenter[2] && SPLASH_HDIST_CLAMP > 0 )
		{
			// do not allow the hitpoint to be further away
			// than SPLASH_HDIST_CLAMP in the horizontal axis
			vec[0] = hitpoint[0];
			vec[1] = hitpoint[1];
			vec[2] = boxcenter[2];

			if( DistanceFast( boxcenter, vec ) > SPLASH_HDIST_CLAMP )
			{
				VectorSubtract( vec, boxcenter, pushdir );
				VectorNormalizeFast( pushdir );
				VectorMA( boxcenter, SPLASH_HDIST_CLAMP, pushdir, hitpoint );
				hitpoint[2] = point[2]; // restore the original hitpoint height
			}
		}
#endif // SPLASH_HDIST_CLAMP

		VectorSubtract( boxcenter, hitpoint, pushdir );
		VectorNormalizeFast( pushdir );
	}

#undef VERTICALBIAS
#undef CAPSULEDISTANCE
#undef SPLASH_HDIST_CLAMP
}
Example #19
0
/*
* 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 );
}
Example #20
0
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
}
Example #21
0
/*
* 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;
	}
}