コード例 #1
0
ファイル: g_arenas.c プロジェクト: pelya/openarena-vm
static gentity_t *SpawnModelOnVictoryPad( gentity_t *pad, vec3_t offset, gentity_t *ent, int place ) {
    gentity_t	*body;
    vec3_t		vec;
    vec3_t		f, r, u;

    body = G_Spawn();
    if ( !body ) {
        G_Printf( S_COLOR_RED "ERROR: out of gentities\n" );
        return NULL;
    }

    body->classname = ent->client->pers.netname;
    body->client = ent->client;
    body->s = ent->s;
    body->s.eType = ET_PLAYER;		// could be ET_INVISIBLE
    body->s.eFlags = 0;				// clear EF_TALK, etc
    body->s.powerups = 0;			// clear powerups
    body->s.loopSound = 0;			// clear lava burning
    body->s.number = body - g_entities;
    body->timestamp = level.time;
    body->physicsObject = qtrue;
    body->physicsBounce = 0;		// don't bounce
    body->s.event = 0;
    body->s.pos.trType = TR_STATIONARY;
    body->s.groundEntityNum = ENTITYNUM_WORLD;
    body->s.legsAnim = LEGS_IDLE;
    body->s.torsoAnim = TORSO_STAND;
    if( body->s.weapon == WP_NONE ) {
        body->s.weapon = WP_MACHINEGUN;
    }
    if( body->s.weapon == WP_GAUNTLET) {
        body->s.torsoAnim = TORSO_STAND2;
    }
    body->s.event = 0;
    body->r.svFlags = ent->r.svFlags;
    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);
    body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
    body->r.contents = CONTENTS_BODY;
    body->r.ownerNum = ent->r.ownerNum;
    body->takedamage = qfalse;

    VectorSubtract( level.intermission_origin, pad->r.currentOrigin, vec );
    vectoangles( vec, body->s.apos.trBase );
    body->s.apos.trBase[PITCH] = 0;
    body->s.apos.trBase[ROLL] = 0;

    AngleVectors( body->s.apos.trBase, f, r, u );
    VectorMA( pad->r.currentOrigin, offset[0], f, vec );
    VectorMA( vec, offset[1], r, vec );
    VectorMA( vec, offset[2], u, vec );

    G_SetOrigin( body, vec );

    trap_LinkEntity (body);

    body->count = place;

    return body;
}
コード例 #2
0
ファイル: g_weapon.c プロジェクト: Clever-Boy/entityplus
void weapon_railgun_fire (gentity_t *ent) {
    vec3_t		end;
    trace_t		trace;
    gentity_t	*tent;
    gentity_t	*traceEnt;
    int			damage;
    int			i;
    int			hits;
    int			unlinked;
    int			passent;
    gentity_t	*unlinkedEntities[MAX_RAIL_HITS];

    damage = 100 * s_quadFactor;

    VectorMA (muzzle, 8192, forward, end);

    // trace only against the solids, so the railgun will go through people
    unlinked = 0;
    hits = 0;
    passent = ent->s.number;
    do {
        trap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT );
        if ( trace.entityNum >= ENTITYNUM_MAX_NORMAL ) {
            break;
        }
        traceEnt = &g_entities[ trace.entityNum ];
        if ( traceEnt->takedamage ) {
            if( LogAccuracyHit( traceEnt, ent ) ) {
                hits++;
            }
            G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
        }
        if ( trace.contents & CONTENTS_SOLID ) {
            break;		// we hit something solid enough to stop the beam
        }
        // unlink this entity, so the next trace will go past it
        trap_UnlinkEntity( traceEnt );
        unlinkedEntities[unlinked] = traceEnt;
        unlinked++;
    } while ( unlinked < MAX_RAIL_HITS );

    // link back in any entities we unlinked
    for ( i = 0 ; i < unlinked ; i++ ) {
        trap_LinkEntity( unlinkedEntities[i] );
    }

    // the final trace endpos will be the terminal point of the rail trail

    // snap the endpos to integers to save net bandwidth, but nudged towards the line
    SnapVectorTowards( trace.endpos, muzzle );

    // send railgun beam effect
    tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );

    // set player number for custom colors on the railtrail
    tent->s.clientNum = ent->s.clientNum;

    VectorCopy( muzzle, tent->s.origin2 );
    // move origin a bit to come closer to the drawn gun muzzle
    VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
    VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );

    // no explosion at end if SURF_NOIMPACT, but still make the trail
    if ( trace.surfaceFlags & SURF_NOIMPACT ) {
        tent->s.eventParm = 255;	// don't make the explosion at the end
    } else {
        tent->s.eventParm = DirToByte( trace.plane.normal );
    }
    tent->s.clientNum = ent->s.clientNum;

    // give the shooter a reward sound if they have made two railgun hits in a row
    if ( hits == 0 ) {
        // complete miss
        ent->client->accurateCount = 0;
    } else {
        // check for "impressive" reward sound
        ent->client->accurateCount += hits;
        ent->client->accuracy_hits++;
    }

}
コード例 #3
0
/*
=============
CopyToBodyQue

A player is respawning, so make an entity that looks
just like the existing corpse to leave behind.
=============
*/
void CopyToBodyQue( gentity_t *ent ) {
#ifdef MISSIONPACK
	gentity_t	*e;
	int i;
#endif
	gentity_t		*body;
	int			contents;

	trap_UnlinkEntity (ent);

	// if client is in a nodrop area, don't leave the body
	contents = trap_PointContents( ent->s.origin, -1 );
	if ( contents & CONTENTS_NODROP ) {
		return;
	}

	// grab a body que and cycle to the next one
	body = level.bodyQue[ level.bodyQueIndex ];
	level.bodyQueIndex = (level.bodyQueIndex + 1) % BODY_QUEUE_SIZE;

	body->s = ent->s;
	body->s.eFlags = EF_DEAD;		// clear EF_TALK, etc
#ifdef MISSIONPACK
	if ( ent->s.eFlags & EF_KAMIKAZE ) {
		body->s.eFlags |= EF_KAMIKAZE;

		// check if there is a kamikaze timer around for this owner
		for (i = 0; i < MAX_GENTITIES; i++) {
			e = &g_entities[i];
			if (!e->inuse)
				continue;
			if (e->activator != ent)
				continue;
			if (strcmp(e->classname, "kamikaze timer"))
				continue;
			e->activator = body;
			break;
		}
	}
#endif
	body->s.powerups = 0;	// clear powerups
	body->s.loopSound = 0;	// clear lava burning
	body->s.number = body - g_entities;
	body->timestamp = level.time;
	body->physicsObject = qtrue;
	body->physicsBounce = 0;		// don't bounce
	if ( body->s.groundEntityNum == ENTITYNUM_NONE ) {
		body->s.pos.trType = TR_GRAVITY;
		body->s.pos.trTime = level.time;
		VectorCopy( ent->client->ps.velocity, body->s.pos.trDelta );
	} else {
		body->s.pos.trType = TR_STATIONARY;
	}
	body->s.event = 0;

	// change the animation to the last-frame only, so the sequence
	// doesn't repeat anew for the body
	switch ( body->s.legsAnim & ~ANIM_TOGGLEBIT ) {
	case BOTH_DEATH1:
	case BOTH_DEAD1:
		body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD1;
		break;
	case BOTH_DEATH2:
	case BOTH_DEAD2:
		body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD2;
		break;
	case BOTH_DEATH3:
	case BOTH_DEAD3:
	default:
		body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD3;
		break;
	}

	body->r.svFlags = ent->r.svFlags;
	VectorCopy (ent->s.mins, body->s.mins);
	VectorCopy (ent->s.maxs, body->s.maxs);
	VectorCopy (ent->r.absmin, body->r.absmin);
	VectorCopy (ent->r.absmax, body->r.absmax);

	body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
	body->s.contents = CONTENTS_CORPSE;
	body->r.ownerNum = ent->s.number;

	body->nextthink = level.time + 5000;
	body->think = BodySink;

	body->die = body_die;

	// don't take more damage if already gibbed
	if ( ent->health <= GIB_HEALTH ) {
		body->takedamage = qfalse;
	} else {
		body->takedamage = qtrue;
	}


	VectorCopy ( body->s.pos.trBase, body->r.currentOrigin );
	trap_LinkEntity (body);
}
コード例 #4
0
ファイル: g_misc.c プロジェクト: Boothand/Birdbones
//QED comment is in bg_misc
//------------------------------------------------------------
void SP_misc_shield_floor_unit( gentity_t *ent )
{
	vec3_t dest;
	trace_t tr;

	if (g_gametype.integer != GT_CTF &&
		g_gametype.integer != GT_CTY)
	{
		G_FreeEntity( ent );
		return;
	}

	VectorSet( ent->r.mins, -16, -16, 0 );
	VectorSet( ent->r.maxs, 16, 16, 40 );

	ent->s.origin[2] += 0.1;
	ent->r.maxs[2] -= 0.1;

	VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
	trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
	if ( tr.startsolid )
	{
		G_Printf ("SP_misc_shield_floor_unit: misc_shield_floor_unit startsolid at %s\n", vtos(ent->s.origin));
		G_FreeEntity( ent );
		return;
	}

	//add the 0.1 back after the trace
	ent->r.maxs[2] += 0.1;

	// allow to ride movers
	ent->s.groundEntityNum = tr.entityNum;

	G_SetOrigin( ent, tr.endpos );

	if (!ent->health)
	{
		ent->health = 60;
	}

	if (!ent->model || !ent->model[0])
	{
		ent->model = "/models/items/a_shield_converter.md3";
	}

	ent->s.modelindex = G_ModelIndex( ent->model );

	ent->s.eFlags = 0;
	ent->r.svFlags |= SVF_PLAYER_USABLE;
	ent->r.contents = CONTENTS_SOLID;
	ent->clipmask = MASK_SOLID;

	EnergyShieldStationSettings(ent);

	ent->boltpoint4 = ent->count; //initial value
	ent->think = check_recharge;
	ent->nextthink = level.time + STATION_RECHARGE_TIME;

	ent->use = shield_power_converter_use;

	VectorCopy( ent->s.angles, ent->s.apos.trBase );
	trap_LinkEntity (ent);

	G_SoundIndex("sound/interface/shieldcon_run.wav");
	G_SoundIndex("sound/interface/shieldcon_done.mp3");
	G_SoundIndex("sound/interface/shieldcon_empty.mp3");
}
コード例 #5
0
/*
 ================
 G_MissileImpact

 ================
 */
void
G_MissileImpact(gentity_t *ent, trace_t *trace)
{
  gentity_t *other, *attacker;
  vec3_t dir;

  other = &g_entities[trace->entityNum];
  attacker = &g_entities[ent->r.ownerNum];

  if (ent->s.weapon == WP_MINE)
  {
    G_BounceMissile(ent, trace);

    //only play a sound if requested
    if (!(ent->s.eFlags & EF_NO_BOUNCE_SOUND))
      G_AddEvent(ent, EV_GRENADE_BOUNCE, 0);

    return;
  }
  else if (!other->takedamage && (ent->s.eFlags & (EF_BOUNCE | EF_BOUNCE_HALF)))
  {
    G_BounceMissile(ent, trace);

    //only play a sound if requested
    if (!(ent->s.eFlags & EF_NO_BOUNCE_SOUND))
      G_AddEvent(ent, EV_GRENADE_BOUNCE, 0);

    return;
  }

  if (!strcmp(ent->classname, "grenade"))
  {
    //grenade doesn't explode on impact
    G_BounceMissile(ent, trace);

    //only play a sound if requested
    if (!(ent->s.eFlags & EF_NO_BOUNCE_SOUND))
      G_AddEvent(ent, EV_GRENADE_BOUNCE, 0);

    return;
  }
  else if (!strcmp(ent->classname, "lockblob"))
  {
    if (other->client && other->client->ps.stats[STAT_PTEAM] == PTE_HUMANS)
    {
      other->client->ps.stats[STAT_STATE] |= SS_BLOBLOCKED;
      other->client->lastLockTime = level.time;
      AngleVectors(other->client->ps.viewangles, dir, NULL, NULL);
      other->client->ps.stats[STAT_VIEWLOCK] = DirToByte(dir);
    }
  }
  else if (!strcmp(ent->classname, "slowblob"))
  {
    if (other->client && other->client->ps.stats[STAT_PTEAM] == PTE_HUMANS)
    {
      other->client->ps.stats[STAT_STATE] |= SS_SLOWLOCKED;
      other->client->lastSlowTime = level.time;
      AngleVectors(other->client->ps.viewangles, dir, NULL, NULL);
      other->client->ps.stats[STAT_VIEWLOCK] = DirToByte(dir);
    }
  }
  else if (!strcmp(ent->classname, "hive"))
  {
    if (other->s.eType == ET_BUILDABLE && other->s.modelindex == BA_A_HIVE)
    {
      if (!ent->parent)
        G_Printf(S_COLOR_YELLOW "WARNING: hive entity has no parent in G_MissileImpact\n");
      else
        ent->parent->active = qfalse;

      G_FreeEntity(ent);
      return;
    }
    else
    {
      //prevent collision with the client when returning
      ent->r.ownerNum = other->s.number;

      ent->think = AHive_ReturnToHive;
      ent->nextthink = level.time + FRAMETIME;

      //      //only damage humans
      //      if (other->client && other->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS)
      //        returnAfterDamage = qtrue;
      //      else
      //        return;
    }
  }

  // impact damage
  if (other->takedamage)
  {
    // FIXME: wrong damage direction?
    if (ent->damage)
    {
      vec3_t velocity;

      BG_EvaluateTrajectoryDelta(&ent->s.pos, level.time, velocity);
      if (VectorLength(velocity) == 0)
        velocity[2] = 1; // stepped on a grenade

      G_Damage(other, ent, attacker, velocity, ent->s.origin, ent->damage, 0, ent->methodOfDeath);
    }
  }

  //  if (returnAfterDamage)
  //    return;

  // is it cheaper in bandwidth to just remove this ent and create a new
  // one, rather than changing the missile into the explosion?

  if (other->takedamage && other->client)
  {
    G_AddEvent(ent, EV_MISSILE_HIT, DirToByte(trace->plane.normal));
    ent->s.otherEntityNum = other->s.number;
  }
  else if (trace->surfaceFlags & SURF_METALSTEPS)
    G_AddEvent(ent, EV_MISSILE_MISS_METAL, DirToByte(trace->plane.normal));
  else
  {
    if (other->r.svFlags & SVF_BOT)
    {
      G_AddEvent(ent, EV_MISSILE_HIT, DirToByte(trace->plane.normal));
      if(ent->s.weapon == WP_AXE && ent->s.generic1 == WPM_SECONDARY)
      {
        return;
      }
    }
    else
    {
      G_AddEvent(ent, EV_MISSILE_MISS, DirToByte(trace->plane.normal));
    }
  }

  ent->freeAfterEvent = qtrue;

  // change over to a normal entity right at the point of impact
  ent->s.eType = ET_GENERAL;

  SnapVectorTowards(trace->endpos, ent->s.pos.trBase); // save net bandwidth

  G_SetOrigin(ent, trace->endpos);

  // splash damage (doesn't apply to person directly hit)
  if (ent->splashDamage)
    G_RadiusDamage(trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius, other, ent->splashMethodOfDeath);

  trap_LinkEntity(ent);
}
コード例 #6
0
ファイル: g_items.c プロジェクト: ElderPlayerX/Invasion
/*
================
LaunchItem

Spawns an item and tosses it forward
================
*/
gentity_t *LaunchItem(gitem_t *item, vec3_t origin, vec3_t velocity, qboolean DontFree)
{
	gentity_t	*dropped;

	dropped = G_Spawn();

	dropped->s.eType = ET_ITEM;
	dropped->s.modelindex = item - bg_itemlist;	// store item number in modelindex
	dropped->s.modelindex2 = 1; // This is non-zero is it's a dropped item

	dropped->classname = item->classname;
	dropped->item = item;
	VectorSet (dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
	VectorSet (dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
	dropped->r.contents = CONTENTS_TRIGGER;

	dropped->touch = Touch_Item;

	G_SetOrigin(dropped, origin);
	dropped->s.pos.trType = TR_GRAVITY;
	dropped->s.pos.trTime = level.time;
	VectorCopy(velocity, dropped->s.pos.trDelta);

	dropped->s.eFlags |= EF_BOUNCE_HALF;
#ifdef MISSIONPACK
	if ((g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF)
		&& item->giType == IT_TEAM)
	{ // Special case for CTF flags
#else
	if (g_gametype.integer >= GT_CTF && item->giType == IT_TEAM)
	{
			// Special case for CTF flags
#endif
		if (g_gametype.integer == GT_INVASION)
		{
			dropped->nextthink = 0;							//Too: don't bring back dropped flag
		}
		else
		{
			dropped->think = Team_DroppedFlagThink;
			dropped->nextthink = level.time + 30000;
		}

		Team_CheckDroppedItem(dropped);
	}
	else if (DontFree)
	{
		dropped->s.eFlags |= EF_NODRAW;
		dropped->r.svFlags |= SVF_NOCLIENT;
		dropped->touch = Touch_Item_Dummy;
		dropped->think = Touch_Item_On;
		dropped->nextthink = level.time + 700;
	}
	else
	{ // auto-remove after 30 seconds
		dropped->think = G_FreeEntity;
		dropped->nextthink = level.time + 30000;
	}

	dropped->flags = FL_DROPPED_ITEM;

	trap_LinkEntity (dropped);

	return dropped;
}

/*
================
Drop_Item

Spawns an item and tosses it forward
================
*/
gentity_t *Drop_Item(gentity_t *ent, gitem_t *item, float angle, qboolean DontFree)
{
	vec3_t	velocity;
	vec3_t	angles;

	VectorCopy(ent->s.apos.trBase, angles);
	angles[YAW] += angle;
	angles[PITCH] = 0;	// always forward

	AngleVectors(angles, velocity, NULL, NULL);
	VectorScale(velocity, 150, velocity);
	velocity[2] += 200 + crandom() * 50;

	//if (g_gametype.integer == GT_CTF)
	//	DontFree = qfalse;

	return LaunchItem(item, ent->s.pos.trBase, velocity, DontFree);
}
コード例 #7
0
ファイル: g_misc.c プロジェクト: Boothand/Birdbones
void HolocronThink(gentity_t *ent)
{
	if (ent->pos2[0] && (!ent->enemy || !ent->enemy->client || ent->enemy->health < 1))
	{
		if (ent->enemy && ent->enemy->client)
		{
			HolocronRespawn(ent);
			VectorCopy(ent->enemy->client->ps.origin, ent->s.pos.trBase);
			VectorCopy(ent->enemy->client->ps.origin, ent->s.origin);
			VectorCopy(ent->enemy->client->ps.origin, ent->r.currentOrigin);
			//copy to person carrying's origin before popping out of them
			HolocronPopOut(ent);
			ent->enemy->client->ps.holocronsCarried[ent->count] = 0;
			ent->enemy = NULL;
			
			goto justthink;
		}
	}
	else if (ent->pos2[0] && ent->enemy && ent->enemy->client)
	{
		ent->pos2[1] = level.time + HOLOCRON_RESPAWN_TIME;
	}

	if (ent->enemy && ent->enemy->client)
	{
		if (!ent->enemy->client->ps.holocronsCarried[ent->count])
		{
			ent->enemy->client->ps.holocronCantTouch = ent->s.number;
			ent->enemy->client->ps.holocronCantTouchTime = level.time + 5000;

			HolocronRespawn(ent);
			VectorCopy(ent->enemy->client->ps.origin, ent->s.pos.trBase);
			VectorCopy(ent->enemy->client->ps.origin, ent->s.origin);
			VectorCopy(ent->enemy->client->ps.origin, ent->r.currentOrigin);
			//copy to person carrying's origin before popping out of them
			HolocronPopOut(ent);
			ent->enemy = NULL;

			goto justthink;
		}

		if (!ent->enemy->inuse || (ent->enemy->client && ent->enemy->client->ps.fallingToDeath))
		{
			if (ent->enemy->inuse && ent->enemy->client)
			{
				ent->enemy->client->ps.holocronBits &= ~(1 << ent->count);
				ent->enemy->client->ps.holocronsCarried[ent->count] = 0;
			}
			ent->enemy = NULL;
			HolocronRespawn(ent);
			VectorCopy(ent->s.origin2, ent->s.pos.trBase);
			VectorCopy(ent->s.origin2, ent->s.origin);
			VectorCopy(ent->s.origin2, ent->r.currentOrigin);

			ent->s.pos.trTime = level.time;

			ent->pos2[0] = 0;

			trap_LinkEntity(ent);

			goto justthink;
		}
	}

	if (ent->pos2[0] && ent->pos2[1] < level.time)
	{ //isn't in original place and has been there for (HOLOCRON_RESPAWN_TIME) seconds without being picked up, so respawn
		VectorCopy(ent->s.origin2, ent->s.pos.trBase);
		VectorCopy(ent->s.origin2, ent->s.origin);
		VectorCopy(ent->s.origin2, ent->r.currentOrigin);

		ent->s.pos.trTime = level.time;

		ent->pos2[0] = 0;

		trap_LinkEntity(ent);
	}

justthink:
	ent->nextthink = level.time + 50;

	if (ent->s.pos.trDelta[0] || ent->s.pos.trDelta[1] || ent->s.pos.trDelta[2])
	{
		G_RunObject(ent);
	}
}
コード例 #8
0
void G_PlayerDie( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int meansOfDeath )
{
	gentity_t *ent;
	int       anim;
	int       killer;
	int       i;
	const char *killerName, *obit;

	const gentity_t *assistantEnt;
	int             assistant = ENTITYNUM_NONE;
	const char      *assistantName = nullptr;
	team_t          assistantTeam = TEAM_NONE;

	if ( self->client->ps.pm_type == PM_DEAD )
	{
		return;
	}

	if ( level.intermissiontime )
	{
		return;
	}

	self->client->ps.pm_type = PM_DEAD;
	self->suicideTime = 0;

	if ( attacker )
	{
		killer = attacker->s.number;

		if ( attacker->client )
		{
			killerName = attacker->client->pers.netname;
		}
		else
		{
			killerName = "<world>";
		}
	}
	else
	{
		killer = ENTITYNUM_WORLD;
		killerName = "<world>";
	}

	assistantEnt = G_FindKillAssist( self, attacker, &assistantTeam );

	if ( assistantEnt )
	{
		assistant = assistantEnt->s.number;

		if ( assistantEnt->client )
		{
			assistantName = assistantEnt->client->pers.netname;
		}
	}

	if ( meansOfDeath < 0 || meansOfDeath >= (int) ARRAY_LEN( modNames ) )
	{
		// fall back on the number
		obit = va( "%d", meansOfDeath );
	}
	else
	{
		obit = modNames[ meansOfDeath ];
	}

	if ( assistant != ENTITYNUM_NONE )
	{
		G_LogPrintf( "Die: %d %d %s %d %d: %s^* killed %s^*; %s^* assisted",
		             killer,
		             ( int )( self - g_entities ),
		             obit,
		             assistant,
		             assistantTeam,
			     killerName,
			     self->client->pers.netname,
			     assistantName );
	}
	else
	{
		G_LogPrintf( "Die: %d %d %s: %s^* killed %s",
		             killer,
		             ( int )( self - g_entities ),
		             obit,
		             killerName,
		             self->client->pers.netname );
	}

	// deactivate all upgrades
	for ( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
	{
		BG_DeactivateUpgrade( i, self->client->ps.stats );
	}

	// broadcast the death event to everyone
	ent = G_NewTempEntity( self->r.currentOrigin, EV_OBITUARY );
	ent->s.eventParm = meansOfDeath;
	ent->s.otherEntityNum = self->s.number;
	ent->s.otherEntityNum2 = killer;
	ent->s.otherEntityNum3 = assistant;
	ent->s.generic1 = assistantTeam;
	ent->r.svFlags = SVF_BROADCAST; // send to everyone

	if ( attacker && attacker->client )
	{
		if ( ( attacker == self || G_OnSameTeam( self, attacker ) ) )
		{
			//punish team kills and suicides
			if ( attacker->client->pers.team == TEAM_ALIENS )
			{
				G_AddCreditToClient( attacker->client, -ALIEN_TK_SUICIDE_PENALTY, true );
				G_AddCreditsToScore( attacker, -ALIEN_TK_SUICIDE_PENALTY );
			}
			else if ( attacker->client->pers.team == TEAM_HUMANS )
			{
				G_AddCreditToClient( attacker->client, -HUMAN_TK_SUICIDE_PENALTY, true );
				G_AddCreditsToScore( attacker, -HUMAN_TK_SUICIDE_PENALTY );
			}
		}
		else if ( g_showKillerHP.integer )
		{
			trap_SendServerCommand( self - g_entities, va( "print_tr %s %s %3i", QQ( N_("Your killer, $1$^7, had $2$ HP.\n") ),
			                        Quote( killerName ),
			                        (int)std::ceil(attacker->entity->Get<HealthComponent>()->Health()) ) );
		}
	}
	else if ( attacker->s.eType != entityType_t::ET_BUILDABLE )
	{
		if ( self->client->pers.team == TEAM_ALIENS )
		{
			G_AddCreditsToScore( self, -ALIEN_TK_SUICIDE_PENALTY );
		}
		else if ( self->client->pers.team == TEAM_HUMANS )
		{
			G_AddCreditsToScore( self, -HUMAN_TK_SUICIDE_PENALTY );
		}
	}

	// give credits for killing this player
	G_RewardAttackers( self );

	ScoreboardMessage( self );  // show scores

	// send updated scores to any clients that are following this one,
	// or they would get stale scoreboards
	for ( i = 0; i < level.maxclients; i++ )
	{
		gclient_t *client;

		client = &level.clients[ i ];

		if ( client->pers.connected != CON_CONNECTED )
		{
			continue;
		}

		if ( client->sess.spectatorState == SPECTATOR_NOT )
		{
			continue;
		}

		if ( client->sess.spectatorClient == self->s.number )
		{
			ScoreboardMessage( g_entities + i );
		}
	}

	VectorCopy( self->s.origin, self->client->pers.lastDeathLocation );

	self->s.weapon = WP_NONE;
	if ( self->client->noclip )
	{
		self->client->cliprcontents = CONTENTS_CORPSE;
	}
	else
	{
		self->r.contents = CONTENTS_CORPSE;
	}

	self->s.angles[ PITCH ] = 0;
	self->s.angles[ ROLL ] = 0;
	self->s.angles[ YAW ] = self->s.apos.trBase[ YAW ];
	LookAtKiller( self, inflictor, attacker );

	VectorCopy( self->s.angles, self->client->ps.viewangles );

	self->s.loopSound = 0;

	self->r.maxs[ 2 ] = -8;

	// don't allow respawn until the death anim is done
	// g_forcerespawn may force spawning at some later time
	self->client->respawnTime = level.time + 1700;

	// clear misc
	memset( self->client->ps.misc, 0, sizeof( self->client->ps.misc ) );

	{
		static int i;

		if ( !( self->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
		{
			switch ( i )
			{
				case 0:
					anim = BOTH_DEATH1;
					break;

				case 1:
					anim = BOTH_DEATH2;
					break;

				case 2:
				default:
					anim = BOTH_DEATH3;
					break;
			}
		}
		else
		{
			switch ( i )
			{
				case 0:
					anim = NSPA_DEATH1;
					break;

				case 1:
					anim = NSPA_DEATH2;
					break;

				case 2:
				default:
					anim = NSPA_DEATH3;
					break;
			}
		}

		self->client->ps.legsAnim =
		  ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;

		if ( !( self->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
		{
			self->client->ps.torsoAnim =
			  ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
		}

		// use own entityid if killed by non-client to prevent uint8_t overflow
		G_AddEvent( self, EV_DEATH1 + i,
		            ( killer < MAX_CLIENTS ) ? killer : self - g_entities );

		// globally cycle through the different death animations
		i = ( i + 1 ) % 3;
	}

	Beacon::DetachTags( self );

	trap_LinkEntity( self );

	self->client->pers.infoChangeTime = level.time;
}
コード例 #9
0
ファイル: g_turret.c プロジェクト: erfg12/clanmod-jka
//-----------------------------------------------------
qboolean turret_base_spawn_top( gentity_t *base )
{
	vec3_t		org;
	int			t;

	gentity_t *top = G_Spawn();
	if ( !top )
	{
		return qfalse;
	}

	top->s.modelindex = G_ModelIndex( "models/map_objects/hoth/turret_top_new.md3" );
	top->s.modelindex2 = G_ModelIndex( "models/map_objects/hoth/turret_top.md3" );
	G_SetAngles( top, base->s.angles );
	VectorCopy( base->s.origin, org );
	org[2] += 128;
	G_SetOrigin( top, org );

	base->r.ownerNum = top->s.number;
	top->r.ownerNum = base->s.number;

	if ( base->team && base->team[0] && //g_gametype.integer == GT_SIEGE &&
		!base->teamnodmg)
	{
		base->teamnodmg = atoi(base->team);
	}
	base->team = NULL;
	top->teamnodmg = base->teamnodmg;
	top->alliedTeam = base->alliedTeam;

	base->s.eType = ET_GENERAL;

	// Set up our explosion effect for the ExplodeDeath code....
	G_EffectIndex( "turret/explode" );
	G_EffectIndex( "sparks/spark_exp_nosnd" );
	G_EffectIndex( "turret/hoth_muzzle_flash" );

	// this is really the pitch angle.....
	top->speed = 0;

	// this is a random time offset for the no-enemy-search-around-mode
	top->count = random() * 9000;

	if ( !base->health )
	{
		base->health = 3000;
	}
	top->health = base->health;

	G_SpawnInt( "showhealth", "0", &t );

	if (t)
	{ //a non-0 maxhealth value will mean we want to show the health on the hud
		top->maxHealth = base->health; //acts as "maxhealth"
		G_ScaleNetHealth(top);

		base->maxHealth = base->health;
		G_ScaleNetHealth(base);
	}

	base->takedamage = qtrue;
	base->pain = TurretBasePain;
	base->die = bottom_die;

	//design specified shot speed
	G_SpawnFloat( "shotspeed", "1100", &base->mass );
	top->mass = base->mass;

	//even if we don't want to show health, let's at least light the crosshair up properly over ourself
	if ( !top->s.teamowner )
	{
		top->s.teamowner = top->alliedTeam;
	}

	base->alliedTeam = top->alliedTeam;
	base->s.teamowner = top->s.teamowner;

	base->s.shouldtarget = qtrue;
	top->s.shouldtarget = qtrue;

	//link them to each other
	base->target_ent = top;
	top->target_ent = base;

	//top->s.owner = MAX_CLIENTS; //not owned by any client

	// search radius
	if ( !base->radius )
	{
		base->radius = 1024;
	}
	top->radius = base->radius;

	// How quickly to fire
	if ( !base->wait )
	{
		base->wait = 300 + random() * 55;
	}
	top->wait = base->wait;

	if ( !base->splashDamage )
	{
		base->splashDamage = 300;
	}
	top->splashDamage = base->splashDamage;

	if ( !base->splashRadius )
	{
		base->splashRadius = 128;
	}
	top->splashRadius = base->splashRadius;

	// how much damage each shot does
	if ( !base->damage )
	{
		base->damage = 100;
	}
	top->damage = base->damage;

	// how fast it turns
	if ( !base->speed )
	{
		base->speed = 20;
	}
	top->speed = base->speed;

	VectorSet( top->r.maxs, 48.0f, 48.0f, 16.0f );
	VectorSet( top->r.mins, -48.0f, -48.0f, 0.0f );
	// Precache moving sounds
	//G_SoundIndex( "sound/chars/turret/startup.wav" );
	//G_SoundIndex( "sound/chars/turret/shutdown.wav" );
	//G_SoundIndex( "sound/chars/turret/ping.wav" );
	G_SoundIndex( "sound/vehicles/weapons/hoth_turret/turn.wav" );
	top->genericValue13 = G_EffectIndex( "turret/hoth_muzzle_flash" );
	top->genericValue14 = G_EffectIndex( "turret/hoth_shot" );
	top->genericValue15 = G_EffectIndex( "turret/hoth_impact" );

	top->r.contents = CONTENTS_BODY;

	//base->max_health = base->health;
	top->takedamage = qtrue;
	top->pain = TurretPain;
	top->die  = auto_turret_die;

	top->material = MAT_METAL;
	//base->r.svFlags |= SVF_NO_TELEPORT|SVF_NONNPC_ENEMY|SVF_SELF_ANIMATING;

	// Register this so that we can use it for the missile effect
	RegisterItem( BG_FindItemForWeapon( WP_EMPLACED_GUN ));

	// But set us as a turret so that we can be identified as a turret
	top->s.weapon = WP_EMPLACED_GUN;

	trap_LinkEntity( top );
	return qtrue;
}
コード例 #10
0
void G_RunMissile( gentity_t *ent )
{
	vec3_t   origin;
	trace_t  tr;
	int      passent;
	bool impact = false;

	// get current position
	BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );

	// ignore interactions with the missile owner
	passent = ent->r.ownerNum;

	// general trace to see if we hit anything at all
	trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs,
	            origin, passent, ent->clipmask, 0 );

	if ( tr.startsolid || tr.allsolid )
	{
		tr.fraction = 0.0f;
		VectorCopy( ent->r.currentOrigin, tr.endpos );
	}

	if ( tr.fraction < 1.0f )
	{
		if ( !ent->pointAgainstWorld || (tr.contents & CONTENTS_BODY) )
		{
			// We hit an entity or we don't care
			impact = true;
		}
		else
		{
			trap_Trace( &tr, ent->r.currentOrigin, nullptr, nullptr, origin,
			            passent, ent->clipmask, 0 );

			if ( tr.fraction < 1.0f )
			{
				// Hit the world with point trace
				impact = true;
			}
			else
			{
				if ( tr.contents & CONTENTS_BODY )
				{
					// Hit an entity
					impact = true;
				}
				else
				{
					trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs,
					            origin, passent, CONTENTS_BODY, 0 );

					if ( tr.fraction < 1.0f )
					{
						impact = true;
					}
				}
			}
		}
	}

	VectorCopy( tr.endpos, ent->r.currentOrigin );

	if ( impact )
	{
		// Never explode or bounce when hitting the sky.
		if ( tr.surfaceFlags & SURF_NOIMPACT )
		{
			G_FreeEntity( ent );

			return;
		}

		// Check for impact damage and effects.
		MissileImpact( ent, &tr );

		// Check if the entity was freed during impact.
		if ( !ent->inuse )
		{
			return;
		}

		// HACK: The missile has turned into an explosion and will free itself later.
		//       See MissileImpact for more.
		if ( ent->s.eType != ET_MISSILE )
		{
			return;
		}
	}

	ent->r.contents = CONTENTS_SOLID; //trick trap_LinkEntity into...
	trap_LinkEntity( ent );
	ent->r.contents = 0; //...encoding bbox information

	if ( ent->flightSplashDamage )
	{
		G_RadiusDamage( tr.endpos, ent->parent, ent->flightSplashDamage, ent->flightSplashRadius,
		                ent->parent, 0, ent->splashMethodOfDeath );
	}

	// check think function after bouncing
	G_RunThink( ent );
}
コード例 #11
0
ファイル: g_weapon.c プロジェクト: eserozvataf/q3now
void weapon_railgun_fire (gentity_t *ent) {
	vec3_t		end;
#ifdef MISSIONPACK
	vec3_t impactpoint, bouncedir;
#endif
	trace_t		trace;
	gentity_t	*tent;
	gentity_t	*traceEnt;
	int			damage;
	int			i;
	int			hits;
	int			unlinked;
	int			passent;
	gentity_t	*unlinkedEntities[MAX_RAIL_HITS];

	damage = 100 * s_quadFactor;

	VectorMA (muzzle, 8192, forward, end);

	// trace only against the solids, so the railgun will go through people
	unlinked = 0;
	hits = 0;
	passent = ent->s.number;
	do {
		trap_Trace (&trace, muzzle, NULL, NULL, end, passent, MASK_SHOT );
		if ( trace.entityNum >= ENTITYNUM_MAX_NORMAL ) {
			break;
		}
		traceEnt = &g_entities[ trace.entityNum ];
		if ( traceEnt->takedamage ) {
#ifdef MISSIONPACK
			if ( traceEnt->client && traceEnt->client->invulnerabilityTime > level.time ) {
				if ( G_InvulnerabilityEffect( traceEnt, forward, trace.endpos, impactpoint, bouncedir ) ) {
					G_BounceProjectile( muzzle, impactpoint, bouncedir, end );
					// snap the endpos to integers to save net bandwidth, but nudged towards the line
					SnapVectorTowards( trace.endpos, muzzle );
					// send railgun beam effect
					tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );
					// set player number for custom colors on the railtrail
					tent->s.clientNum = ent->s.clientNum;
					VectorCopy( muzzle, tent->s.origin2 );
					// move origin a bit to come closer to the drawn gun muzzle
					VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
					VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );
					tent->s.eventParm = 255;	// don't make the explosion at the end
					//
					VectorCopy( impactpoint, muzzle );
					// the player can hit him/herself with the bounced rail
					passent = ENTITYNUM_NONE;
				}
			}
			else {
				if( LogAccuracyHit( traceEnt, ent ) ) {
					hits++;
				}
				G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
			}
#else
				if( LogAccuracyHit( traceEnt, ent ) ) {
					hits++;
				}
				G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_RAILGUN);
#endif
		}
		if ( trace.contents & CONTENTS_SOLID ) {
			break;		// we hit something solid enough to stop the beam
		}
		// unlink this entity, so the next trace will go past it
		trap_UnlinkEntity( traceEnt );
		unlinkedEntities[unlinked] = traceEnt;
		unlinked++;
	} while ( unlinked < MAX_RAIL_HITS );

	// link back in any entities we unlinked
	for ( i = 0 ; i < unlinked ; i++ ) {
		trap_LinkEntity( unlinkedEntities[i] );
	}

	// the final trace endpos will be the terminal point of the rail trail

	// snap the endpos to integers to save net bandwidth, but nudged towards the line
	SnapVectorTowards( trace.endpos, muzzle );

	// send railgun beam effect
	tent = G_TempEntity( trace.endpos, EV_RAILTRAIL );

	// set player number for custom colors on the railtrail
	tent->s.clientNum = ent->s.clientNum;

	VectorCopy( muzzle, tent->s.origin2 );
	// move origin a bit to come closer to the drawn gun muzzle
	VectorMA( tent->s.origin2, 4, right, tent->s.origin2 );
	VectorMA( tent->s.origin2, -1, up, tent->s.origin2 );

	// no explosion at end if SURF_NOIMPACT, but still make the trail
	if ( trace.surfaceFlags & SURF_NOIMPACT ) {
		tent->s.eventParm = 255;	// don't make the explosion at the end
	} else {
		tent->s.eventParm = DirToByte( trace.plane.normal );
	}
	tent->s.clientNum = ent->s.clientNum;

	// give the shooter a reward sound if they have made two railgun hits in a row
	if ( hits == 0 ) {
		// complete miss
		ent->client->accurateCount = 0;
	} else {
		// check for "impressive" reward sound
		ent->client->accurateCount += hits;
		if ( ent->client->accurateCount >= 2 ) {
			ent->client->accurateCount -= 1;
			ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
			// add the sprite over the player's head
			ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
			ent->client->ps.eFlags |= EF_AWARD_IMPRESSIVE;
			ent->client->rewardTime = level.time + REWARD_SPRITE_TIME;
		}
		ent->client->accuracy_hits++;
	}

}
コード例 #12
0
static void MissileImpact( gentity_t *ent, trace_t *trace )
{
	int       dirAsByte, impactFlags;
	const missileAttributes_t *ma = BG_Missile( ent->s.modelindex );
	gentity_t *hitEnt   = &g_entities[ trace->entityNum ];
	gentity_t *attacker = &g_entities[ ent->r.ownerNum ];

	// Returns whether damage and hit effects should be done and played.
	std::function<int(gentity_t*, trace_t*, gentity_t*)> impactFunc;

	// Check for bounce.
	if ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) &&
	     !HasComponents<HealthComponent>(*hitEnt->entity) )
	{
		BounceMissile( ent, trace );

		if ( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
		{
			G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
		}

		return;
	}

	// Call missile specific impact functions.
	switch( ent->s.modelindex )
	{
		case MIS_GRENADE:      impactFunc = ImpactGrenade;     break;
		case MIS_FIREBOMB:     impactFunc = ImpactGrenade;     break;
		case MIS_FLAMER:       impactFunc = ImpactFlamer;      break;
		case MIS_FIREBOMB_SUB: impactFunc = ImpactFirebombSub; break;
		case MIS_LOCKBLOB:     impactFunc = ImpactLockblock;   break;
		case MIS_SLOWBLOB:     impactFunc = ImpactSlowblob;    break;
		case MIS_HIVE:         impactFunc = ImpactHive;        break;
		default:               impactFunc = DefaultImpactFunc; break;
	}

	impactFlags = impactFunc( ent, trace, hitEnt );

	// Deal impact damage.
	if ( !( impactFlags & MIF_NO_DAMAGE ) )
	{
		if ( ent->damage && G_Alive( hitEnt ) )
		{
			vec3_t dir;

			BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, dir );

			if ( VectorNormalize( dir ) == 0 )
			{
				dir[ 2 ] = 1; // stepped on a grenade
			}

			int dflags = 0;
			if ( !ma->doLocationalDamage ) dflags |= DAMAGE_NO_LOCDAMAGE;
			if ( ma->doKnockback )         dflags |= DAMAGE_KNOCKBACK;

			hitEnt->entity->Damage(ent->damage * MissileTimeDmgMod(ent), attacker,
			                       Vec3::Load(trace->endpos), Vec3::Load(dir), dflags,
			                       (meansOfDeath_t)ent->methodOfDeath);
		}

		// splash damage (doesn't apply to person directly hit)
		if ( ent->splashDamage )
		{
			G_RadiusDamage( trace->endpos, ent->parent,
			                ent->splashDamage * MissileTimeSplashDmgMod( ent ),
			                ent->splashRadius, hitEnt, ( ma->doKnockback ? DAMAGE_KNOCKBACK : 0 ),
			                ent->splashMethodOfDeath );
		}
	}

	// Play hit effects and remove the missile.
	if ( !( impactFlags & MIF_NO_EFFECT ) )
	{
		// Use either the trajectory direction or the surface normal for the hit event.
		if ( ma->impactFlightDirection )
		{
			vec3_t trajDir;
			BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, trajDir );
			VectorNormalize( trajDir );
			dirAsByte = DirToByte( trajDir );
		}
		else
		{
			dirAsByte = DirToByte( trace->plane.normal );
		}

		// Add hit event.
		if ( HasComponents<HealthComponent>(*hitEnt->entity) )
		{
			G_AddEvent( ent, EV_MISSILE_HIT_ENTITY, dirAsByte );

			ent->s.otherEntityNum = hitEnt->s.number;
		}
		else if ( trace->surfaceFlags & SURF_METAL )
		{
			G_AddEvent( ent, EV_MISSILE_HIT_METAL, dirAsByte );
		}
		else
		{
			G_AddEvent( ent, EV_MISSILE_HIT_ENVIRONMENT, dirAsByte );
		}

		ent->freeAfterEvent = true;

		// HACK: Change over to a general entity at the point of impact.
		ent->s.eType = ET_GENERAL;

		// Prevent map models from appearing at impact point.
		ent->s.modelindex = 0;

		// Save net bandwith.
		G_SnapVectorTowards( trace->endpos, ent->s.pos.trBase );

		G_SetOrigin( ent, trace->endpos );

		trap_LinkEntity( ent );
	}
	// If no impact happened, check if we should continue or free ourselves.
	else if ( !( impactFlags & MIF_NO_FREE ) )
	{
		G_FreeEntity( ent );
	}
}
コード例 #13
0
ファイル: g_combat.c プロジェクト: chrisballinger/tremulous
/*
==================
player_die
==================
*/
void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath )
{
  gentity_t *ent;
  int       anim;
  int       killer;
  int       i;
  char      *killerName, *obit;

  if( self->client->ps.pm_type == PM_DEAD )
    return;

  if( level.intermissiontime )
    return;

  self->client->ps.pm_type = PM_DEAD;
  self->suicideTime = 0;

  if( attacker )
  {
    killer = attacker->s.number;

    if( attacker->client )
      killerName = attacker->client->pers.netname;
    else
      killerName = "<world>";
  }
  else
  {
    killer = ENTITYNUM_WORLD;
    killerName = "<world>";
  }

  if( meansOfDeath < 0 || meansOfDeath >= ARRAY_LEN( modNames ) )
    // fall back on the number
    obit = va( "%d", meansOfDeath );
  else
    obit = modNames[ meansOfDeath ];

  G_LogPrintf( "Die: %d %d %s: %s" S_COLOR_WHITE " killed %s\n",
    killer,
    (int)( self - g_entities ),
    obit,
    killerName,
    self->client->pers.netname );

  // deactivate all upgrades
  for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
    BG_DeactivateUpgrade( i, self->client->ps.stats );

  // broadcast the death event to everyone
  ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
  ent->s.eventParm = meansOfDeath;
  ent->s.otherEntityNum = self->s.number;
  ent->s.otherEntityNum2 = killer;
  ent->r.svFlags = SVF_BROADCAST; // send to everyone

  self->enemy = attacker;
  self->client->ps.persistant[ PERS_KILLED ]++;

  if( attacker && attacker->client )
  {
    attacker->client->lastkilled_client = self->s.number;

    if( ( attacker == self || OnSameTeam( self, attacker ) ) && meansOfDeath != MOD_HSPAWN )
    {
      //punish team kills and suicides
      if( attacker->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
      {
        G_AddCreditToClient( attacker->client, -ALIEN_TK_SUICIDE_PENALTY, qtrue );
        AddScore( attacker, -ALIEN_TK_SUICIDE_PENALTY );
      }
      else if( attacker->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
      {
        G_AddCreditToClient( attacker->client, -HUMAN_TK_SUICIDE_PENALTY, qtrue );
        AddScore( attacker, -HUMAN_TK_SUICIDE_PENALTY );
      }
    }
  }
  else if( attacker->s.eType != ET_BUILDABLE )
  {
    if( self->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
      AddScore( self, -ALIEN_TK_SUICIDE_PENALTY );
    else if( self->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
      AddScore( self, -HUMAN_TK_SUICIDE_PENALTY );
  }

  // give credits for killing this player
  G_RewardAttackers( self );

  ScoreboardMessage( self );    // show scores

  // send updated scores to any clients that are following this one,
  // or they would get stale scoreboards
  for( i = 0 ; i < level.maxclients ; i++ )
  {
    gclient_t *client;

    client = &level.clients[ i ];
    if( client->pers.connected != CON_CONNECTED )
      continue;

    if( client->sess.spectatorState == SPECTATOR_NOT )
      continue;

    if( client->sess.spectatorClient == self->s.number )
      ScoreboardMessage( g_entities + i );
  }

  VectorCopy( self->s.origin, self->client->pers.lastDeathLocation );

  self->takedamage = qfalse; // can still be gibbed

  self->s.weapon = WP_NONE;
  self->r.contents = CONTENTS_CORPSE;

  self->s.angles[ PITCH ] = 0;
  self->s.angles[ ROLL ] = 0;
  self->s.angles[ YAW ] = self->s.apos.trBase[ YAW ];
  LookAtKiller( self, inflictor, attacker );

  VectorCopy( self->s.angles, self->client->ps.viewangles );

  self->s.loopSound = 0;

  self->r.maxs[ 2 ] = -8;

  // don't allow respawn until the death anim is done
  // g_forcerespawn may force spawning at some later time
  self->client->respawnTime = level.time + 1700;

  // clear misc
  memset( self->client->ps.misc, 0, sizeof( self->client->ps.misc ) );

  {
    // normal death
    static int i;

    if( !( self->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
    {
      switch( i )
      {
        case 0:
          anim = BOTH_DEATH1;
          break;
        case 1:
          anim = BOTH_DEATH2;
          break;
        case 2:
        default:
          anim = BOTH_DEATH3;
          break;
      }
    }
    else
    {
      switch( i )
      {
        case 0:
          anim = NSPA_DEATH1;
          break;
        case 1:
          anim = NSPA_DEATH2;
          break;
        case 2:
        default:
          anim = NSPA_DEATH3;
          break;
      }
    }

    self->client->ps.legsAnim =
      ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;

    if( !( self->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
    {
      self->client->ps.torsoAnim =
        ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
    }

    // use own entityid if killed by non-client to prevent uint8_t overflow
    G_AddEvent( self, EV_DEATH1 + i,
      ( killer < MAX_CLIENTS ) ? killer : self - g_entities );

    // globally cycle through the different death animations
    i = ( i + 1 ) % 3;
  }

  trap_LinkEntity( self );

  self->client->pers.infoChangeTime = level.time;
}
コード例 #14
0
ファイル: g_combat.c プロジェクト: mecwerks/revamp
/*
==================
player_die
==================
*/
void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
	static int	rndAnim;
	gentity_t	*ent;
	int			anim;
	int			contents;
	int			killer;
	int			i;
	char		*killerName, *obit;
	qboolean	gibPlayer;
	qboolean	headshot = qfalse;

	if ( self->player->ps.pm_type == PM_DEAD ) {
		return;
	}

	if ( level.intermissiontime ) {
		return;
	}

	// make sure the body shows up in the player's current position
	G_UnTimeShiftClient( self );

	// check for an almost capture
	CheckAlmostCapture( self, attacker );
	// check for a player that almost brought in cubes
	CheckAlmostScored( self, attacker );

	if (self->player && self->player->hook) {
		Weapon_HookFree(self->player->hook);
	}
#ifdef MISSIONPACK
	if ((self->player->ps.eFlags & EF_TICKING) && self->activator) {
		self->player->ps.eFlags &= ~EF_TICKING;
		self->activator->think = G_FreeEntity;
		self->activator->nextthink = level.time;
	}
#endif
	self->player->ps.pm_type = PM_DEAD;

	if ( attacker ) {
		killer = attacker->s.number;
		if ( attacker->player ) {
			killerName = attacker->player->pers.netname;
		} else {
			killerName = "<non-player>";
		}
	} else {
		killer = ENTITYNUM_WORLD;
		killerName = "<world>";
	}

	if ( killer < 0 || killer >= MAX_CLIENTS ) {
		killer = ENTITYNUM_WORLD;
		killerName = "<world>";
	}

	if ( meansOfDeath < 0 || meansOfDeath >= ARRAY_LEN( modNames ) ) {
		obit = "<bad obituary>";
	} else {
		obit = modNames[meansOfDeath];
	}

	G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n", 
		killer, self->s.number, meansOfDeath, killerName, 
		self->player->pers.netname, obit );

	self->enemy = attacker;

	self->player->ps.persistant[PERS_KILLED]++;

	if (attacker && attacker->player) {
		attacker->player->lastkilled_player = self->s.number;

		if ( attacker == self || OnSameTeam (self, attacker ) ) {
			if ( ((level.time - self->player->lasthurt_time) <= ASSISTED_SUICIDE_TIME) && 
				g_entities[self->player->lasthurt_player2].player && (self->player->lasthurt_player2 != self->s.number) ) 
			{
				AddScore( &g_entities[self->player->lasthurt_player2], self->r.currentOrigin, 1 );
				meansOfDeath = MOD_ASSISTED_SUICIDE;
			} else AddScore( attacker, self->r.currentOrigin, -1 );
		} else {
			AddScore( attacker, self->r.currentOrigin, 1 );

			if( meansOfDeath == MOD_GAUNTLET ) {
				
				// play humiliation on player
				attacker->player->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;

				// add the sprite over the player's head
				attacker->player->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
				attacker->player->ps.eFlags |= EF_AWARD_GAUNTLET;
				attacker->player->rewardTime = level.time + REWARD_SPRITE_TIME;

				// also play humiliation on target
				self->player->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_GAUNTLETREWARD;
			}

			// check for two kills in a short amount of time
			// if this is close enough to the last kill, give a reward sound
			if ( level.time - attacker->player->lastKillTime < CARNAGE_REWARD_TIME ) {
				// play excellent on player
				attacker->player->ps.persistant[PERS_EXCELLENT_COUNT]++;

				// add the sprite over the player's head
				attacker->player->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
				attacker->player->ps.eFlags |= EF_AWARD_EXCELLENT;
				attacker->player->rewardTime = level.time + REWARD_SPRITE_TIME;
			}
			attacker->player->lastKillTime = level.time;

		}
	} else {
		if ( ((level.time - self->player->lasthurt_time) <= ASSISTED_SUICIDE_TIME) &&
			g_entities[self->player->lasthurt_player2].player && (self->player->lasthurt_player2 != self->s.number) ) 
		{
			AddScore( &g_entities[self->player->lasthurt_player2], self->r.currentOrigin, 1 );
			meansOfDeath = MOD_ASSISTED_SUICIDE;
		} else AddScore( self, self->r.currentOrigin, -1 );
	}

	// don't send death obituary when swiching teams
	// allow mod to be changed by death type
	if (meansOfDeath != MOD_SUICIDE_TEAM_CHANGE) {
		// broadcast the death event to everyone
		ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
		ent->s.eventParm = meansOfDeath;
		ent->s.otherEntityNum = self->s.number;
		ent->s.otherEntityNum2 = killer;
		ent->r.svFlags = SVF_BROADCAST;	// send to everyone
		if (self->player && attacker->player && ((self->player->lasthurt_location & LOCATION_HEAD) ||
			(self->player->lasthurt_location & LOCATION_FACE)))
		{
			ent->s.eFlags |= EF_HEADSHOT;
			headshot = qtrue;
		}
	}

	// Add team bonuses
	Team_FragBonuses(self, inflictor, attacker);

	// if I committed suicide, the flag does not fall, it returns.
	if (meansOfDeath == MOD_SUICIDE || meansOfDeath == MOD_SUICIDE_TEAM_CHANGE) {
		if ( self->player->ps.powerups[PW_NEUTRALFLAG] ) {		// only happens in One Flag CTF
			Team_ReturnFlag( TEAM_FREE );
			self->player->ps.powerups[PW_NEUTRALFLAG] = 0;
		}
		else if ( self->player->ps.powerups[PW_REDFLAG] ) {		// only happens in standard CTF
			Team_ReturnFlag( TEAM_RED );
			self->player->ps.powerups[PW_REDFLAG] = 0;
		}
		else if ( self->player->ps.powerups[PW_BLUEFLAG] ) {	// only happens in standard CTF
			Team_ReturnFlag( TEAM_BLUE );
			self->player->ps.powerups[PW_BLUEFLAG] = 0;
		}
	}

	TossPlayerItems( self );
#ifdef MISSIONPACK
	TossPlayerPersistantPowerups( self );
	if( g_gametype.integer == GT_HARVESTER ) {
		TossPlayerCubes( self );
	}
#endif

	Cmd_Score_f( self );		// show scores
	// send updated scores to any clients that are following this one,
	// or they would get stale scoreboards
	for ( i = 0 ; i < level.maxplayers ; i++ ) {
		gplayer_t	*player;

		player = &level.players[i];
		if ( player->pers.connected != CON_CONNECTED ) {
			continue;
		}
		if ( player->sess.sessionTeam != TEAM_SPECTATOR ) {
			continue;
		}
		if ( player->sess.spectatorPlayer == self->s.number ) {
			Cmd_Score_f( g_entities + i );
		}
	}

	self->takedamage = qtrue;	// can still be gibbed

	self->s.weapon = WP_NONE;
	self->s.powerups = 0;
	self->player->ps.contents = self->s.contents = CONTENTS_CORPSE;

	self->s.angles[0] = 0;
	self->s.angles[2] = 0;
	LookAtKiller (self, inflictor, attacker);

	VectorCopy( self->s.angles, self->player->ps.viewangles );

	self->s.loopSound = 0;

	self->player->ps.maxs[2] = self->s.maxs[2] = -8;

	// don't allow respawn until the death anim is done
	// g_forcerespawn may force spawning at some later time
	self->player->respawnTime = level.time + 1700;

	// remove powerups
	memset( self->player->ps.powerups, 0, sizeof(self->player->ps.powerups) );

	// never gib in a nodrop
	contents = trap_PointContents( self->r.currentOrigin, -1 );

	gibPlayer = ( (self->health <= GIB_HEALTH && !(contents & CONTENTS_NODROP)) || meansOfDeath == MOD_SUICIDE );

	if ( gibPlayer ) {
		// gib death
		GibEntity( self, qfalse );

		// do normal death for clients with gibs disable
	} else {
		if (headshot)
			gibPlayer = 3;

		// the body can still be gibbed
		self->die = body_die;

#ifdef MISSIONPACK
		if (self->s.eFlags & EF_KAMIKAZE) {
			Kamikaze_DeathTimer( self );
		}
#endif
	}

	// normal death
	switch ( rndAnim ) {
	case 0:
		anim = BOTH_DEATH1;
		break;
	case 1:
		anim = BOTH_DEATH2;
		break;
	case 2:
	default:
		anim = BOTH_DEATH3;
		break;
	}

	self->player->ps.legsAnim = 
		( ( self->player->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
	self->player->ps.torsoAnim = 
		( ( self->player->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;

	G_AddEvent( self, EV_DEATH1 + rndAnim, gibPlayer );

	if ( headshot )
		GibEntity( self, qtrue );
	else self->player->headless = qfalse;

	// globally cycle through the different death animations
	rndAnim = ( rndAnim + 1 ) % 3;

	trap_LinkEntity (self);

}
コード例 #15
0
ファイル: g_items.c プロジェクト: ElderPlayerX/Invasion
/*
===============
RespawnItem
===============
*/
void RespawnItem(gentity_t *ent)
{
	// randomly select from teamed entities
	if (ent->team)
	{
		gentity_t	*master;
		int	count;
		int choice;

		if (!ent->teammaster)
		{
			G_Error("RespawnItem: bad teammaster");
		}
		master = ent->teammaster;

		for (count = 0, ent = master; ent; ent = ent->teamchain, count++)
			;

		choice = rand() % count;

		for (count = 0, ent = master; count < choice; ent = ent->teamchain, count++)
			;
	}

	ent->r.contents = CONTENTS_TRIGGER;
	ent->s.eFlags &= ~EF_NODRAW;
	ent->r.svFlags &= ~SVF_NOCLIENT;
	trap_LinkEntity (ent);

	if (ent->item->giType == IT_POWERUP)
	{
		// play powerup spawn sound to all clients
		gentity_t	*te;

		// if the powerup respawn sound should Not be global
		if (ent->speed)
		{
			te = G_TempEntity(ent->s.pos.trBase, EV_GENERAL_SOUND);
		}
		else
		{
			te = G_TempEntity(ent->s.pos.trBase, EV_GLOBAL_SOUND);
		}
		te->s.eventParm = G_SoundIndex("sound/items/poweruprespawn.wav");
		te->r.svFlags |= SVF_BROADCAST;
	}

	if (ent->item->giType == IT_HOLDABLE && ent->item->giTag == HI_KAMIKAZE)
	{
		// play powerup spawn sound to all clients
		gentity_t	*te;

		// if the powerup respawn sound should Not be global
		if (ent->speed)
		{
			te = G_TempEntity(ent->s.pos.trBase, EV_GENERAL_SOUND);
		}
		else
		{
			te = G_TempEntity(ent->s.pos.trBase, EV_GLOBAL_SOUND);
		}
		te->s.eventParm = G_SoundIndex("sound/items/kamikazerespawn.wav");
		te->r.svFlags |= SVF_BROADCAST;
	}

	// play the normal respawn sound only to nearby clients
	G_AddEvent(ent, EV_ITEM_RESPAWN, 0);

	ent->nextthink = 0;
}
コード例 #16
0
ファイル: g_trigger.c プロジェクト: DerSaidin/OpenWolf
// Arnout: links the trigger to it's objective, determining if it's a func_explosive
// of func_constructible and spawning the right indicator
void Think_SetupObjectiveInfo(gentity_t * ent)
{

	ent->target_ent = G_FindByTargetname(NULL, ent->target);

	if(!ent->target_ent)
	{
		G_Error("'trigger_objective_info' has a missing target '%s'\n", ent->target);
	}

	if(ent->target_ent->s.eType == ET_EXPLOSIVE)
	{
		// Arnout: this is for compass usage
		if((ent->spawnflags & AXIS_OBJECTIVE) || (ent->spawnflags & ALLIED_OBJECTIVE))
		{
			gentity_t      *e;

			e = G_Spawn();

			e->r.svFlags = SVF_BROADCAST;
			e->classname = "explosive_indicator";
			if(ent->spawnflags & 8)
			{
				e->s.eType = ET_TANK_INDICATOR;
			}
			else
			{
				e->s.eType = ET_EXPLOSIVE_INDICATOR;
			}
			e->parent = ent;
			e->s.pos.trType = TR_STATIONARY;

			if(ent->spawnflags & AXIS_OBJECTIVE)
			{
				e->s.teamNum = 1;
			}
			else if(ent->spawnflags & ALLIED_OBJECTIVE)
			{
				e->s.teamNum = 2;
			}

			G_SetOrigin(e, ent->r.currentOrigin);

			e->s.modelindex2 = ent->s.teamNum;
			e->r.ownerNum = ent->s.number;
			e->think = explosive_indicator_think;
			e->nextthink = level.time + FRAMETIME;

			e->s.effect1Time = ent->target_ent->constructibleStats.weaponclass;

			if(ent->tagParent)
			{
				e->tagParent = ent->tagParent;
				Q_strncpyz(e->tagName, ent->tagName, MAX_QPATH);
			}
			else
			{
				VectorCopy(ent->r.absmin, e->s.pos.trBase);
				VectorAdd(ent->r.absmax, e->s.pos.trBase, e->s.pos.trBase);
				VectorScale(e->s.pos.trBase, 0.5, e->s.pos.trBase);
			}

			SnapVector(e->s.pos.trBase);

			trap_LinkEntity(e);

			ent->target_ent->parent = ent;
		}
	}
	else if(ent->target_ent->s.eType == ET_CONSTRUCTIBLE)
	{
		gentity_t      *constructibles[2];
		int             team[2];

		ent->target_ent->parent = ent;

		constructibles[0] = ent->target_ent;
		constructibles[1] = G_FindByTargetname(constructibles[0], ent->target);	// see if we are targetting a 2nd one for two team constructibles

		team[0] = constructibles[0]->spawnflags & AXIS_CONSTRUCTIBLE ? TEAM_AXIS : TEAM_ALLIES;

		constructibles[0]->s.otherEntityNum2 = ent->s.teamNum;

		if(constructibles[1])
		{
			team[1] = constructibles[1]->spawnflags & AXIS_CONSTRUCTIBLE ? TEAM_AXIS : TEAM_ALLIES;

			if(constructibles[1]->s.eType != ET_CONSTRUCTIBLE)
			{
				G_Error
					("'trigger_objective_info' targets multiple entities with targetname '%s', the second one isn't a 'func_constructible'\n",
					 ent->target);
			}

			if(team[0] == team[1])
			{
				G_Error
					("'trigger_objective_info' targets two 'func_constructible' entities with targetname '%s' that are constructible by the same team\n",
					 ent->target);
			}

			constructibles[1]->s.otherEntityNum2 = ent->s.teamNum;

			ent->chain = constructibles[1];
			ent->chain->parent = ent;

			constructibles[0]->chain = constructibles[1];
			constructibles[1]->chain = constructibles[0];
		}
		else
		{
			constructibles[0]->chain = NULL;
		}

		// if already constructed (in case of START_BUILT)
		if(constructibles[0]->s.angles2[1] != 0)
		{
//          trap_UnlinkEntity( ent );
//          return;
		}
		else
		{
			// Arnout: spawn a constructible icon - this is for compass usage
			gentity_t      *e;

			e = G_Spawn();

			e->r.svFlags = SVF_BROADCAST;
			e->classname = "constructible_indicator";
			if(ent->spawnflags & 8)
			{
				e->s.eType = ET_TANK_INDICATOR_DEAD;
			}
			else
			{
				e->s.eType = ET_CONSTRUCTIBLE_INDICATOR;
			}
			e->s.pos.trType = TR_STATIONARY;

			if(constructibles[1])
			{
				team[1] = constructibles[1]->spawnflags & AXIS_CONSTRUCTIBLE ? TEAM_AXIS : TEAM_ALLIES;

				// see if one of the two is still partially built (happens when a multistage destructible construction blows up for the first time)
				if(constructibles[0]->count2 && constructibles[0]->grenadeFired > 1)
				{
					e->s.teamNum = team[0];
				}
				else if(constructibles[1]->count2 && constructibles[1]->grenadeFired > 1)
				{
					e->s.teamNum = team[1];
				}
				else
				{
					e->s.teamNum = 3;	// both teams
				}
			}
			else
			{
				e->s.teamNum = team[0];
			}

			e->s.modelindex2 = ent->s.teamNum;
			e->r.ownerNum = ent->s.number;
			ent->count2 = (e - g_entities);
			e->think = constructible_indicator_think;
			e->nextthink = level.time + FRAMETIME;

			e->parent = ent;

			if(ent->tagParent)
			{
				e->tagParent = ent->tagParent;
				Q_strncpyz(e->tagName, ent->tagName, MAX_QPATH);
			}
			else
			{
				VectorCopy(ent->r.absmin, e->s.pos.trBase);
				VectorAdd(ent->r.absmax, e->s.pos.trBase, e->s.pos.trBase);
				VectorScale(e->s.pos.trBase, 0.5, e->s.pos.trBase);
			}

			SnapVector(e->s.pos.trBase);

			trap_LinkEntity(e);	// moved down
		}
		ent->touch = Touch_ObjectiveInfo;

	}
	else if(ent->target_ent->s.eType == ET_COMMANDMAP_MARKER)
	{
		ent->target_ent->parent = ent;
	}

	trap_LinkEntity(ent);
}
コード例 #17
0
ファイル: g_items.c プロジェクト: ElderPlayerX/Invasion
/*
===============
Touch_Item
===============
*/
void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace)
{
	int			respawn;
	qboolean	predict;

	if (!other->client)
		return;
	if (other->health < 1)
		return;		// dead people can't pickup

	// the same pickup rules are used for client side and server side
	if (!BG_CanItemBeGrabbed(g_gametype.integer, &ent->s, &other->client->ps, &level.InvasionInfo))
	{
		return;
	}

	G_LogPrintf("Item: %i %s\n", other->s.number, ent->item->classname);

	predict = other->client->pers.predictItemPickup;

	// call the item-specific pickup function
	switch (ent->item->giType)
	{
	case IT_WEAPON:
		respawn = Pickup_Weapon(ent, other);
//		predict = qfalse;
		break;
	case IT_AMMO:
		respawn = Pickup_Ammo(ent, other);
//		predict = qfalse;
		break;
	case IT_ARMOR:
		respawn = Pickup_Armor(ent, other);
		break;
	case IT_HEALTH:
		respawn = Pickup_Health(ent, other);
		break;
	case IT_POWERUP:
		respawn = Pickup_Powerup(ent, other);
		predict = qfalse;
		break;
#ifdef MISSIONPACK
	case IT_PERSISTANT_POWERUP:
		respawn = Pickup_PersistantPowerup(ent, other);
		break;
#endif
	case IT_TEAM:
		respawn = Pickup_Team(ent, other);
		break;
	case IT_HOLDABLE:
		respawn = Pickup_Holdable(ent, other);
		break;
	default:
		return;
	}

	if (!respawn)
	{
		return;
	}

	// play the normal pickup sound
	if (predict)
	{
		G_AddPredictableEvent(other, EV_ITEM_PICKUP, ent->s.modelindex);
	}
	else
	{
		G_AddEvent(other, EV_ITEM_PICKUP, ent->s.modelindex);
	}

	// powerup pickups are global broadcasts
	if (ent->item->giType == IT_POWERUP || ent->item->giType == IT_TEAM)
	{
		// if we want the global sound to play
		if (!ent->speed)
		{
			gentity_t	*te;

			te = G_TempEntity(ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP);
			te->s.eventParm = ent->s.modelindex;
			te->r.svFlags |= SVF_BROADCAST;
		}
		else
		{
			gentity_t	*te;

			te = G_TempEntity(ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP);
			te->s.eventParm = ent->s.modelindex;
			// only send this temp entity to a single client
			te->r.svFlags |= SVF_SINGLECLIENT;
			te->r.singleClient = other->s.number;
		}
	}

	// fire item targets
	G_UseTargets (ent, other);

	// wait of -1 will not respawn
	if (ent->wait == -1)
	{
		ent->r.svFlags |= SVF_NOCLIENT;
		ent->s.eFlags |= EF_NODRAW;
		ent->r.contents = 0;
		ent->unlinkAfterEvent = qtrue;
		return;
	}

	// non zero wait overrides respawn time
	if (ent->wait)
	{
		respawn = ent->wait;
	}

	// random can be used to vary the respawn time
	if (ent->random)
	{
		respawn += crandom() * ent->random;
		if (respawn < 1)
		{
			respawn = 1;
		}
	}

	// dropped items will not respawn
	if (ent->flags & FL_DROPPED_ITEM)
	{
		ent->freeAfterEvent = qtrue;
	}

	// picked up items still stay around, they just don't
	// draw anything.  This allows respawnable items
	// to be placed on movers.
	ent->r.svFlags |= SVF_NOCLIENT;
	ent->s.eFlags |= EF_NODRAW;
	ent->r.contents = 0;

	// ZOID
	// A negative respawn times means to never respawn this item (but don't
	// delete it).  This is used by items that are respawned by third party
	// events such as ctf flags
	if (respawn <= 0)
	{
		ent->nextthink = 0;
		ent->think = 0;
	}
	else
	{
		ent->nextthink = level.time + respawn * 1000;
		ent->think = RespawnItem;
	}
	trap_LinkEntity(ent);
}
コード例 #18
0
ファイル: g_trigger.c プロジェクト: DerSaidin/OpenWolf
void SP_trigger_objective_info( gentity_t *ent ) {
	char *scorestring;
	char* customimage;
	int cix, cia, objflags;

	if ( !ent->track )
		G_Error ("'trigger_objective_info' does not have a 'track' \n");

/*	if ( !ent->message )
		G_Error ("'trigger_objective_info' does not have a 'shortname' \n");*/

	if(ent->spawnflags & MESSAGE_OVERRIDE) {
		if ( !ent->spawnitem )
			G_Error ("'trigger_objective_info' has override flag set but no override text\n");
	}

	// Gordon: for specifying which commandmap objectives this entity "belongs" to
	G_SpawnInt( "objflags", "0", &objflags );

	if(G_SpawnString( "customimage", "", &customimage )) {		
		cix = cia = G_ShaderIndex( customimage );
	} else {
		if(G_SpawnString( "customaxisimage", "", &customimage )) {
			cix = G_ShaderIndex( customimage );
		} else {
			cix = 0;
		}

		if(G_SpawnString( "customalliesimage", "", &customimage )) {
			cia = G_ShaderIndex( customimage );
		} else if(G_SpawnString( "customalliedimage", "", &customimage )) {
			cia = G_ShaderIndex( customimage );
		} else {
			cia = 0;
		}
	}

	G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "e",	va( "%li", (long)(ent-g_entities) )			);
	G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "o",	va( "%i", objflags )				);
	G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "cix",	va( "%i", cix )						);
	G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "cia",	va( "%i", cia )						);
	G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "s",	va( "%i", ent->spawnflags )			);
	G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "n",	ent->message ? ent->message : ""	);

	if( level.numOidTriggers >= MAX_OID_TRIGGERS ) {
		G_Error ("Exceeded maximum number of 'trigger_objective_info' entities\n");
	}

	// JPW NERVE -- if this trigger has a "score" field set, then blowing up an objective
	//  inside of this field will add "score" to the right player team.  storing this 
	//  in ent->accuracy since that's unused.
	G_SpawnString ("score", "0", &scorestring);
	ent->accuracy = atof (scorestring);

	trap_SetConfigstring( CS_OID_TRIGGERS + level.numOidTriggers, ent->track );

	InitTrigger( ent );

	if( ent->s.origin[0] || ent->s.origin[1] || ent->s.origin[2] ) {
		G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "x",	va( "%i", (int)ent->s.origin[0] )	);
		G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "y",	va( "%i", (int)ent->s.origin[1] )	);
		G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "z",	va( "%i", (int)ent->s.origin[2] )	);
	} else {
		vec3_t mid;
		VectorAdd( ent->r.absmin, ent->r.absmax, mid );
		VectorScale( mid, 0.5f, mid );

		G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "x",	va( "%i", (int)mid[0] )	);
		G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "y",	va( "%i", (int)mid[1] )	);
		G_SetConfigStringValue( CS_OID_DATA + level.numOidTriggers, "z",	va( "%i", (int)mid[2] )	);
	}

	ent->s.teamNum = level.numOidTriggers++;

	// unlike other triggers, we need to send this one to the client
	ent->r.svFlags &= ~SVF_NOCLIENT;
	ent->s.eType = ET_OID_TRIGGER;

	if( !ent->target ) {
		// no target - just link and go
		trap_LinkEntity (ent);
	} else {
		// Arnout: finalize spawing on fourth frame to allow for proper linking with targets
		ent->nextthink = level.time + (3*FRAMETIME);
		ent->think = Think_SetupObjectiveInfo;
	}
}
コード例 #19
0
ファイル: g_items.c プロジェクト: ElderPlayerX/Invasion
/*
================
FinishSpawningItem

Traces down to find where an item should rest, instead of letting them
free fall from their spawn points
================
*/
void FinishSpawningItem(gentity_t *ent)
{
	trace_t		tr;
	vec3_t		dest;
	qboolean Goal = qfalse;

	ent->s.eType = ET_ITEM;
	ent->s.modelindex = ent->item - bg_itemlist;		// store item number in modelindex
	ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item

	ent->r.contents = CONTENTS_TRIGGER;
	ent->touch = Touch_Item;
	// useing an item causes it to respawn
	ent->use = Use_Item;

	if (g_gametype.integer == GT_DESTROY
		&& !Q_stricmp(ent->classname, "team_CTF_alienegg"))
	{
		ent->touch = NULL;
		ent->r.contents = CONTENTS_SOLID;
		ent->takedamage = qtrue;
		ent->die = Inv_EggDie;

		Goal = qtrue;
	}
	else
	{
		VectorSet(ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
		VectorSet(ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
	}

	if (ent->spawnflags & 1)
	{
		// suspended
		G_SetOrigin(ent, ent->s.origin);
	}
	else
	{
		// drop to floor
		VectorSet(dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096);
		trap_Trace(&tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID);
		if (tr.startsolid)
		{
			G_Printf ("FinishSpawningItem: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
			G_FreeEntity(ent);
			return;
		}

		// allow to ride movers
		ent->s.groundEntityNum = tr.entityNum;

		G_SetOrigin(ent, tr.endpos);
	}

	if (Goal)
		Inv_SetDestroyableEgg(ent);

	// team slaves and targeted items aren't present at start
	if ((ent->flags & FL_TEAMSLAVE) || ent->targetname)
	{
		ent->s.eFlags |= EF_NODRAW;
		ent->r.contents = 0;
		return;
	}

	// powerups don't spawn in for a while
	if (ent->item->giType == IT_POWERUP)
	{
		float	respawn;

		respawn = 45 + crandom() * 15;
		ent->s.eFlags |= EF_NODRAW;
		ent->r.contents = 0;
		ent->nextthink = level.time + respawn * 1000;
		ent->think = RespawnItem;
		return;
	}


	trap_LinkEntity (ent);
}
コード例 #20
0
ファイル: g_items.c プロジェクト: dstaesse/etlegacy
/**
* @brief Traces down to find where an item should rest, instead of letting them
*        free fall from their spawn points.
*/
void FinishSpawningItem(gentity_t *ent)
{
	trace_t tr;
	vec3_t  dest;
	vec3_t  maxs;

	if (ent->spawnflags & 1)     // suspended
	{
		VectorSet(ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
		VectorSet(ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
		VectorCopy(ent->r.maxs, maxs);
	}
	else
	{
		// had to modify this so that items would spawn in shelves
		VectorSet(ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, 0);
		VectorSet(ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
		VectorCopy(ent->r.maxs, maxs);
		maxs[2] /= 2;
	}

	ent->r.contents   = CONTENTS_TRIGGER | CONTENTS_ITEM;
	ent->touch        = Touch_Item_Auto;
	ent->s.eType      = ET_ITEM;
	ent->s.modelindex = ent->item - bg_itemlist;        // store item number in modelindex

	ent->s.otherEntityNum2 = 0;     // takes modelindex2's place in signaling a dropped item
	// we don't use this (yet, anyway) so I'm taking it so you can specify a model for treasure items and clipboards
	//ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item
	if (ent->model)
	{
		ent->s.modelindex2 = G_ModelIndex(ent->model);
	}

	// using an item causes it to respawn
	ent->use = Use_Item;

	// moved this up so it happens for suspended items too (and made it a function)
	G_SetAngle(ent, ent->s.angles);

	if (ent->spawnflags & 1)        // suspended
	{
		G_SetOrigin(ent, ent->s.origin);
	}
	else
	{
		VectorSet(dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096);
		trap_Trace(&tr, ent->s.origin, ent->r.mins, maxs, dest, ent->s.number, MASK_SOLID);

		if (tr.startsolid)
		{
			vec3_t temp;

			VectorCopy(ent->s.origin, temp);
			temp[2] -= ITEM_RADIUS;

			VectorSet(dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096);
			trap_Trace(&tr, temp, ent->r.mins, maxs, dest, ent->s.number, MASK_SOLID);
		}

		if (tr.startsolid)
		{
			G_Printf("FinishSpawningItem: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
			G_FreeEntity(ent);
			return;
		}

		// allow to ride movers
		ent->s.groundEntityNum = tr.entityNum;

		G_SetOrigin(ent, tr.endpos);
	}

	if (ent->spawnflags & 2)          // spin
	{
		ent->s.eFlags |= EF_SPINNING;
	}

	// team slaves and targeted items aren't present at start
	if ((ent->flags & FL_TEAMSLAVE) || ent->targetname)
	{
		ent->flags |= FL_NODRAW;
		//ent->s.eFlags |= EF_NODRAW;
		ent->r.contents = 0;
		return;
	}

	// health/ammo can potentially be multi-stage (multiple use)
	if (ent->item->giType == IT_HEALTH || ent->item->giType == IT_AMMO)
	{
		int i;

		// having alternate models defined in bg_misc.c for a health or ammo item specify it as "multi-stage"
		// - left-hand operand of comma expression has no effect
		// initial line: for(i=0;i<4,ent->item->world_model[i];i++) {}
		for (i = 0; i < 4 && ent->item->world_model[i] ; i++)
		{
		}

		ent->s.density = i - 1;   // store number of stages in 'density' for client (most will have '1')
	}

	trap_LinkEntity(ent);
}
コード例 #21
0
ファイル: g_misc.c プロジェクト: Boothand/Birdbones
void SP_misc_holocron(gentity_t *ent)
{
	vec3_t dest;
	trace_t tr;

	if (g_gametype.integer != GT_HOLOCRON)
	{
		G_FreeEntity(ent);
		return;
	}

	if (HasSetSaberOnly())
	{
		if (ent->count == FP_SABERATTACK ||
			ent->count == FP_SABERDEFEND ||
			ent->count == FP_SABERTHROW)
		{ //having saber holocrons in saber only mode is pointless
			G_FreeEntity(ent);
			return;
		}
	}

	ent->s.isJediMaster = qtrue;

	VectorSet( ent->r.maxs, 8, 8, 8 );
	VectorSet( ent->r.mins, -8, -8, -8 );

	ent->s.origin[2] += 0.1;
	ent->r.maxs[2] -= 0.1;

	VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
	trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
	if ( tr.startsolid )
	{
		G_Printf ("SP_misc_holocron: misc_holocron startsolid at %s\n", vtos(ent->s.origin));
		G_FreeEntity( ent );
		return;
	}

	//add the 0.1 back after the trace
	ent->r.maxs[2] += 0.1;

	// allow to ride movers
//	ent->s.groundEntityNum = tr.entityNum;

	G_SetOrigin( ent, tr.endpos );

	if (ent->count < 0)
	{
		ent->count = 0;
	}

	if (ent->count >= NUM_FORCE_POWERS)
	{
		ent->count = NUM_FORCE_POWERS-1;
	}
/*
	if (g_forcePowerDisable.integer &&
		(g_forcePowerDisable.integer & (1 << ent->count)))
	{
		G_FreeEntity(ent);
		return;
	}
*/
	//No longer doing this, causing too many complaints about accidentally setting no force powers at all
	//and starting a holocron game (making it basically just FFA)

	ent->enemy = NULL;

	ent->s.eFlags = EF_BOUNCE_HALF;

	ent->s.modelindex = (ent->count - 128);//G_ModelIndex(holocronTypeModels[ent->count]);
	ent->s.eType = ET_HOLOCRON;
	ent->s.pos.trType = TR_GRAVITY;
	ent->s.pos.trTime = level.time;

	ent->r.contents = CONTENTS_TRIGGER;
	ent->clipmask = MASK_SOLID;

	ent->s.trickedentindex4 = ent->count;

	if (forcePowerDarkLight[ent->count] == FORCE_DARKSIDE)
	{
		ent->s.trickedentindex3 = 1;
	}
	else if (forcePowerDarkLight[ent->count] == FORCE_LIGHTSIDE)
	{
		ent->s.trickedentindex3 = 2;
	}
	else
	{
		ent->s.trickedentindex3 = 3;
	}

	ent->physicsObject = qtrue;

	VectorCopy(ent->s.pos.trBase, ent->s.origin2); //remember the spawn spot

	ent->touch = HolocronTouch;

	trap_LinkEntity(ent);

	ent->think = HolocronThink;
	ent->nextthink = level.time + 50;
}
コード例 #22
0
ファイル: g_items.c プロジェクト: dstaesse/etlegacy
/**
* @brief Run item.
*/
void G_RunItem(gentity_t *ent)
{
	vec3_t  origin;
	trace_t tr;
	int     contents;
	int     mask;

	// if groundentity has been set to -1, it may have been pushed off an edge
	if (ent->s.groundEntityNum == -1)
	{
		if (ent->s.pos.trType != TR_GRAVITY)
		{
			ent->s.pos.trType = TR_GRAVITY;
			ent->s.pos.trTime = level.time;
		}
	}

	if (ent->s.pos.trType == TR_STATIONARY || ent->s.pos.trType == TR_GRAVITY_PAUSED) // check think function
	{
		G_RunThink(ent);
		return;
	}

	if (ent->s.pos.trType == TR_LINEAR && (!ent->clipmask && !ent->r.contents))
	{
		// check think function
		G_RunThink(ent);
		return;
	}

	// get current position
	BG_EvaluateTrajectory(&ent->s.pos, level.time, origin, qfalse, ent->s.effect2Time);

	// trace a line from the previous position to the current position
	if (ent->clipmask)
	{
		mask = ent->clipmask;
	}
	else
	{
		mask = MASK_SOLID;
	}
	trap_Trace(&tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin,
	           ent->r.ownerNum, mask);

	if (ent->isProp && ent->takedamage)
	{
		G_RunItemProp(ent, origin);
	}

	VectorCopy(tr.endpos, ent->r.currentOrigin);

	if (tr.startsolid)
	{
		tr.fraction = 0;
	}

	trap_LinkEntity(ent);   // FIXME: avoid this for stationary?

	// check think function
	G_RunThink(ent);

	if (tr.fraction == 1)
	{
		return;
	}

	// if it is in a nodrop volume, remove it
	contents = trap_PointContents(ent->r.currentOrigin, -1);
	if (contents & CONTENTS_NODROP)
	{
		if (ent->item && ent->item->giType == IT_TEAM)
		{
			Team_ReturnFlag(ent);
		}
		else
		{
			G_FreeEntity(ent);
		}
		return;
	}

	G_BounceItem(ent, &tr);
}
コード例 #23
0
ファイル: g_misc.c プロジェクト: OADoctor/SmokinGuns
void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) {
	gentity_t	*tent;

	// use temp events at source and destination to prevent the effect
	// from getting dropped by a second player event
#ifndef SMOKINGUNS
	if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
#else
	if ( player->client->sess.sessionTeam < TEAM_SPECTATOR ) {
#endif
		tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
		tent->s.clientNum = player->s.clientNum;

		tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN );
		tent->s.clientNum = player->s.clientNum;
	}

	// unlink to make sure it can't possibly interfere with G_KillBox
	trap_UnlinkEntity (player);

	VectorCopy ( origin, player->client->ps.origin );
	player->client->ps.origin[2] += 1;

	// spit the player out
	AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
	VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
	player->client->ps.pm_time = 160;		// hold time
	player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;

	// toggle the teleport bit so the client knows to not lerp
	player->client->ps.eFlags ^= EF_TELEPORT_BIT;

#ifdef SMOKINGUNS
//unlagged - backward reconciliation #3
	// we don't want players being backward-reconciled back through teleporters
	G_ResetHistory( player );
//unlagged - backward reconciliation #3
#endif

	// set angles
	SetClientViewAngle( player, angles );

	// kill anything at the destination
#ifndef SMOKINGUNS
	if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
#else
	if ( player->client->sess.sessionTeam < TEAM_SPECTATOR ) {
#endif
		G_KillBox (player);
#ifdef SMOKINGUNS
		// Tequila comment: G_KillBox will set dontTelefrag as needed
		if (player->client->dontTelefrag) {
#ifdef DEBUG_TELEFRAG_CASE
			G_Printf(S_COLOR_MAGENTA "TeleportPlayer: Telefrag case delayed at respawn for %s...\n",player->client->pers.netname);
#endif
			trap_SendServerCommand( player->s.clientNum, va("print \"Go away %s\n\"",player->client->pers.netname) );
			// So we will link the player entity later with normal content
			player->r.contents = 0;
		}
#endif
	}

	// save results of pmove
	BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );

	// use the precise origin for linking
	VectorCopy( player->client->ps.origin, player->r.currentOrigin );

#ifndef SMOKINGUNS
	if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
#else
	if ( player->client->sess.sessionTeam < TEAM_SPECTATOR ) {
#endif
		trap_LinkEntity (player);
	}
}


/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
Point teleporters at these.
Now that we don't have teleport destination pads, this is just
an info_notnull
*/
void SP_misc_teleporter_dest( gentity_t *ent ) {
}


#ifdef SMOKINGUNS
// Imported from WoP OpenSource project
//===========================================================

/*QUAKED misc_externalmodel (1 0 0) (-16 -16 -16) (16 16 16)
"model"		arbitrary .md3 file to display
"wait"		time in seconds before the animation begins
*/
#define ANIMATION_THINKTIME	50

static void Think_AnimationExternalmodel( gentity_t *ent ) {

	if(ent->animationEnd>ent->animationStart) {
		ent->s.frame = (int)((float)level.time*0.001f*ent->animationFPS)%(ent->animationEnd-ent->animationStart);
		ent->s.frame += ent->animationStart;

		ent->nextthink = level.time + ANIMATION_THINKTIME;
	}
}

void SP_misc_externalmodel( gentity_t *ent )
{
	ent->s.modelindex = G_ModelIndex( ent->model );
//	VectorSet (ent->mins, -16, -16, -16);
//	VectorSet (ent->maxs, 16, 16, 16);
	trap_LinkEntity (ent);

	G_SetOrigin( ent, ent->s.origin );
	VectorCopy( ent->s.angles, ent->s.apos.trBase );

	if(ent->animationEnd>ent->animationStart && ent->animationFPS>0.0f) {
		ent->think = Think_AnimationExternalmodel;

		ent->nextthink = level.time + ANIMATION_THINKTIME;

		// Tequila: Support for new entity features
		if (ent->wait>0.0f)
			ent->nextthink += (int)(ent->wait*1000);
	}
}
#endif
//===========================================================

/*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16)
"model"		arbitrary .md3 file to display
*/
void SP_misc_model( gentity_t *ent ) {

#if 0
	ent->s.modelindex = G_ModelIndex( ent->model );
	VectorSet (ent->mins, -16, -16, -16);
	VectorSet (ent->maxs, 16, 16, 16);
	trap_LinkEntity (ent);

	G_SetOrigin( ent, ent->s.origin );
	VectorCopy( ent->s.angles, ent->s.apos.trBase );
#else
	G_FreeEntity( ent );
#endif
}

//===========================================================

void locateCamera( gentity_t *ent ) {
	vec3_t		dir;
	gentity_t	*target;
	gentity_t	*owner;

	owner = G_PickTarget( ent->target );
	if ( !owner ) {
		G_Printf( "Couldn't find target for misc_portal_surface\n" );
		G_FreeEntity( ent );
		return;
	}
	ent->r.ownerNum = owner->s.number;

	// frame holds the rotate speed
	if ( owner->spawnflags & 1 ) {
		ent->s.frame = 25;
	} else if ( owner->spawnflags & 2 ) {
		ent->s.frame = 75;
	}

#ifndef SMOKINGUNS
	// swing camera ?
	if ( owner->spawnflags & 4 ) {
		// set to 0 for no rotation at all
		ent->s.powerups = 0;
	}
	else {
		ent->s.powerups = 1;
	}
#else
	// set to 0 for no rotation at all
	ent->s.powerups = 1;
#endif

	// clientNum holds the rotate offset
	ent->s.clientNum = owner->s.clientNum;

	VectorCopy( owner->s.origin, ent->s.origin2 );

	// see if the portal_camera has a target
	target = G_PickTarget( owner->target );
	if ( target ) {
		VectorSubtract( target->s.origin, owner->s.origin, dir );
		VectorNormalize( dir );
	} else {
		G_SetMovedir( owner->s.angles, dir );
	}

	ent->s.eventParm = DirToByte( dir );
}
コード例 #24
0
ファイル: g_items.c プロジェクト: dstaesse/etlegacy
/**
* @brief Action when touching an item.
*/
void Touch_Item(gentity_t *ent, gentity_t *other, trace_t *trace)
{
	int respawn;

	// only activated items can be picked up
	if (!ent->active)
	{
		return;
	}
	else
	{
		// need to set active to false if player is maxed out
		ent->active = qfalse;
	}

	if (!other->client)
	{
		return;
	}

	if (other->health <= 0)
	{
		return;     // dead people can't pickup
	}

	// the same pickup rules are used for client side and server side
	if (!BG_CanItemBeGrabbed(&ent->s, &other->client->ps, other->client->sess.skill, other->client->sess.sessionTeam))
	{
		return;
	}

	if (g_gamestate.integer == GS_PLAYING)
	{
		G_LogPrintf("Item: %i %s\n", other->s.number, ent->item->classname);
	}
	else
	{
		// Don't let them pickup winning stuff in warmup
		if (ent->item->giType != IT_WEAPON &&
		    ent->item->giType != IT_AMMO &&
		    ent->item->giType != IT_HEALTH)
		{
			return;
		}
	}

	//G_LogPrintf( "Calling item pickup function for %s\n", ent->item->classname );

	// call the item-specific pickup function
	switch (ent->item->giType)
	{
	case IT_WEAPON:
		respawn = Pickup_Weapon(ent, other);
		break;
	case IT_HEALTH:
		respawn = Pickup_Health(ent, other);
		break;
	case IT_TEAM:
		respawn = Pickup_Team(ent, other);
		break;
	default:
		return;
	}

	//G_LogPrintf( "Finished pickup function\n" );

	if (!respawn)
	{
		return;
	}

	// play sounds
	if (ent->noise_index)
	{
		// a sound was specified in the entity, so play that sound
		// (this G_AddEvent) and send the pickup as "EV_ITEM_PICKUP_QUIET"
		// so it doesn't make the default pickup sound when the pickup event is received
		G_AddEvent(other, EV_GENERAL_SOUND, ent->noise_index);
		G_AddEvent(other, EV_ITEM_PICKUP_QUIET, ent->s.modelindex);
	}
	else
	{
		G_AddEvent(other, EV_ITEM_PICKUP, ent->s.modelindex);
	}

	// powerup pickups are global broadcasts
	if (ent->item->giType == IT_TEAM)
	{
		gentity_t *te = G_TempEntity(ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP);

		te->s.eventParm = ent->s.modelindex;
		te->r.svFlags  |= SVF_BROADCAST;
	}

	//G_LogPrintf( "Firing item targets\n" );

	// fire item targets
	G_UseTargets(ent, other);

	// dropped items will not respawn
	if (ent->flags & FL_DROPPED_ITEM)
	{
		ent->freeAfterEvent = qtrue;
	}

	// picked up items still stay around, they just don't
	// draw anything.  This allows respawnable items
	// to be placed on movers.
	ent->r.svFlags |= SVF_NOCLIENT;
	ent->flags     |= FL_NODRAW;
	ent->r.contents = 0;

	// A negative respawn times means to never respawn this item (but don't
	// delete it).  This is used by items that are respawned by third party
	// events such as ctf flags
	if (respawn <= 0)
	{
		ent->nextthink = 0;
		ent->think     = 0;
	}
	else
	{
		ent->nextthink = level.time + respawn * 1000;
		ent->think     = RespawnItem;
	}
	trap_LinkEntity(ent);
}
コード例 #25
0
ファイル: g_client.c プロジェクト: kingtiger01/OpenMOHAA
/*
===========
ClientSpawn

Called every time a client is placed fresh in the world:
after the first ClientBegin, and after each respawn
Initializes all non-persistant parts of playerState
============
*/
void ClientSpawn(gentity_t *ent) {
	int		index;
	vec3_t	spawn_origin, spawn_angles;
	gclient_t	*client;
	int		i;
	clientPersistant_t	saved;
	clientSession_t		savedSess;
	int		persistant[MAX_PERSISTANT];
	gentity_t	*spawnPoint;
	int		flags;
	int		savedPing;
//	char	*savedAreaBits;
	int		accuracy_hits, accuracy_shots;
	int		eventSequence;
	char	userinfo[MAX_INFO_STRING];

	index = ent - g_entities;
	client = ent->client;

	// find a spawn point
	// do it before setting health back up, so farthest
	// ranging doesn't count this client
	if ( client->sess.sessionTeam == TEAM_SPECTATOR ) {
		spawnPoint = SelectSpectatorSpawnPoint ( 
						spawn_origin, spawn_angles);
	} else {
		do {
			// the first spawn should be at a good looking spot
			if ( !client->pers.initialSpawn && client->pers.localClient ) {
				client->pers.initialSpawn = qtrue;
				spawnPoint = SelectInitialSpawnPoint( spawn_origin, spawn_angles );
			} else {
				// don't spawn near existing origin if possible
				spawnPoint = SelectSpawnPoint ( 
					client->ps.origin, 
					spawn_origin, spawn_angles);
			}

			// Tim needs to prevent bots from spawning at the initial point
			// on q3dm0...
			if ( ( spawnPoint->flags & FL_NO_BOTS ) && ( ent->r.svFlags & SVF_BOT ) ) {
				continue;	// try again
			}
			// just to be symetric, we have a nohumans option...
			if ( ( spawnPoint->flags & FL_NO_HUMANS ) && !( ent->r.svFlags & SVF_BOT ) ) {
				continue;	// try again
			}

			break;

		} while ( 1 );
	}
	client->pers.teamState.state = TEAM_ACTIVE;

	// always clear the kamikaze flag
//	ent->s.eFlags &= ~EF_KAMIKAZE;

	// toggle the teleport bit so the client knows to not lerp
	// and never clear the voted flag
	flags = ent->s.eFlags & (EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED);
	flags ^= EF_TELEPORT_BIT;

	// clear everything but the persistant data

	saved = client->pers;
	savedSess = client->sess;
	savedPing = client->ps.ping;
//	savedAreaBits = client->areabits;
	accuracy_hits = client->accuracy_hits;
	accuracy_shots = client->accuracy_shots;

	Com_Memset (client, 0, sizeof(*client));

	client->ps.stats[STAT_ATTACKERCLIENT] = -1;
	client->ps.stats[STAT_INFOCLIENT] = -1;

	client->pers = saved;
	client->sess = savedSess;
	client->ps.ping = savedPing;
//	client->areabits = savedAreaBits;
	client->accuracy_hits = accuracy_hits;
	client->accuracy_shots = accuracy_shots;
	client->lastkilled_client = -1;

	client->airOutTime = level.time + 12000;

	trap_GetUserinfo( index, userinfo, sizeof(userinfo) );
	// set max health
	client->pers.maxHealth = atoi( Info_ValueForKey( userinfo, "handicap" ) );
	if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) {
		client->pers.maxHealth = 100;
	}
	// clear entity values
	client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
	ent->s.eFlags = flags;

	ent->s.groundEntityNum = ENTITYNUM_NONE;
	ent->client = &level.clients[index];
	ent->takedamage = qtrue;
	ent->inuse = qtrue;
	ent->classname = "player";
	ent->r.contents = CONTENTS_BODY;
	ent->clipmask = MASK_PLAYERSOLID;
	ent->die = player_die;
	ent->waterlevel = 0;
	ent->watertype = 0;
	ent->flags = 0;
	
	VectorCopy (playerMins, ent->r.mins);
	VectorCopy (playerMaxs, ent->r.maxs);

	client->ps.clientNum = index;



	// health will count down towards max_health
	ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] + 25;

	G_SetOrigin( ent, spawn_origin );
	VectorCopy( spawn_origin, client->ps.origin );

	// the respawned flag will be cleared after the attack and jump keys come up
	client->ps.pm_flags |= PMF_RESPAWNED;

	trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd );
	SetClientViewAngle( ent, spawn_angles );

	if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {

	} else {
		G_KillBox( ent );
		trap_LinkEntity (ent);

	

	}

	// don't allow full run speed for a bit
	client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
	client->ps.pm_time = 100;

	client->respawnTime = level.time;
	client->inactivityTime = level.time + g_inactivity.integer * 1000;
	client->latched_buttons = 0;

	if ( level.intermissiontime ) {
		MoveClientToIntermission( ent );
	} else {
		// fire the targets of the spawn point
		G_UseTargets( spawnPoint, ent );

	}

	// run a client frame to drop exactly to the floor,
	// initialize animations and other things
	client->ps.commandTime = level.time - 100;
	ent->client->pers.cmd.serverTime = level.time;
	ClientThink( ent-g_entities );

	// positively link the client, even if the command times are weird
	if ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
		BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
		VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );
		trap_LinkEntity( ent );
	}

	// run the presend to set anything else
	ClientEndFrame( ent );

	// clear entity state values
	BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );

	ent->s.modelindex = G_ModelIndex("models/human/coxswain.tik");
}
コード例 #26
0
ファイル: g_items.c プロジェクト: dstaesse/etlegacy
/**
* @brief Spawns an item and tosses it forward.
*/
gentity_t *LaunchItem(gitem_t *item, vec3_t origin, vec3_t velocity, int ownerNum)
{
	gentity_t *dropped = G_Spawn();
	trace_t   tr;
	vec3_t    vec, temp;

	dropped->s.eType           = ET_ITEM;
	dropped->s.modelindex      = item - bg_itemlist; // store item number in modelindex
	dropped->s.otherEntityNum2 = 1; // this is taking modelindex2's place for a dropped item

	dropped->classname = item->classname;
	dropped->item      = item;
	VectorSet(dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, 0);              // so items sit on the ground
	VectorSet(dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, 2 * ITEM_RADIUS);    // so items sit on the ground
	dropped->r.contents = CONTENTS_TRIGGER | CONTENTS_ITEM;

	dropped->clipmask = CONTENTS_SOLID | CONTENTS_MISSILECLIP;      // fix for items falling through grates

	dropped->touch = Touch_Item_Auto;

	trap_Trace(&tr, origin, dropped->r.mins, dropped->r.maxs, origin, ownerNum, MASK_SOLID);
	if (tr.startsolid)
	{
		int i;

		VectorSubtract(g_entities[ownerNum].s.origin, origin, temp);
		VectorNormalize(temp);

		for (i = 16; i <= 48; i += 16)
		{
			VectorScale(temp, i, vec);
			VectorAdd(origin, vec, origin);

			trap_Trace(&tr, origin, dropped->r.mins, dropped->r.maxs, origin, ownerNum, MASK_SOLID);
			if (!tr.startsolid)
			{
				break;
			}
		}
	}

	G_SetOrigin(dropped, origin);
	dropped->s.pos.trType = TR_GRAVITY;
	dropped->s.pos.trTime = level.time;
	VectorCopy(velocity, dropped->s.pos.trDelta);

	// set yaw to parent angles
	temp[PITCH] = 0;
	temp[YAW]   = g_entities[ownerNum].s.apos.trBase[YAW];
	temp[ROLL]  = 0;
	G_SetAngle(dropped, temp);

	dropped->s.eFlags |= EF_BOUNCE_HALF;

	if (item->giType == IT_TEAM)     // Special case for CTF flags
	{
		gentity_t *flag = &g_entities[g_entities[ownerNum].client->flagParent];

		dropped->s.otherEntityNum = g_entities[ownerNum].client->flagParent;    // store the entitynum of our original flag spawner
		dropped->s.density        = 1;
		dropped->think            = Team_DroppedFlagThink;
		dropped->nextthink        = level.time + 30000;

		if (level.gameManager)
		{
			G_Script_ScriptEvent(level.gameManager, "trigger", flag->item->giTag == PW_REDFLAG ? "allied_object_dropped" : "axis_object_dropped");
		}
		G_Script_ScriptEvent(flag, "trigger", "dropped");
	}
	else     // auto-remove after 30 seconds
	{
		dropped->think     = G_FreeEntity;
		dropped->nextthink = level.time + 30000;
	}

	dropped->flags = FL_DROPPED_ITEM;

	trap_LinkEntity(dropped);

	return dropped;
}
コード例 #27
0
/*
===========
ClientSpawn

Called every time a client is placed fresh in the world:
after the first ClientBegin, and after each respawn
Initializes all non-persistant parts of playerState
============
*/
void ClientSpawn(gentity_t *ent) {
	int		index;
	vec3_t	spawn_origin, spawn_angles;
	gclient_t	*client;
	int		i;
	clientPersistant_t	saved;
	clientSession_t		savedSess;
	int		persistant[MAX_PERSISTANT];
	gentity_t	*spawnPoint;
	gentity_t *tent;
	int		flags;
	int		savedPing;
//	char	*savedAreaBits;
	int		accuracy_hits, accuracy_shots;
	int		eventSequence;

	index = ent - g_entities;
	client = ent->client;

	VectorClear(spawn_origin);

	// find a spawn point
	// do it before setting health back up, so farthest
	// ranging doesn't count this client
	if ( client->sess.sessionTeam == TEAM_SPECTATOR ) {
		spawnPoint = SelectSpectatorSpawnPoint ( 
						spawn_origin, spawn_angles);
	} else if (g_gametype.integer >= GT_CTF ) {
		// all base oriented team games use the CTF spawn points
		spawnPoint = SelectCTFSpawnPoint ( 
						client->sess.sessionTeam, 
						client->pers.teamState.state, 
						spawn_origin, spawn_angles,
						!!(ent->r.svFlags & SVF_BOT));
	}
	else
	{
		// the first spawn should be at a good looking spot
		if ( !client->pers.initialSpawn && client->pers.localClient )
		{
			client->pers.initialSpawn = qtrue;
			spawnPoint = SelectInitialSpawnPoint(spawn_origin, spawn_angles,
							     !!(ent->r.svFlags & SVF_BOT));
		}
		else
		{
			// don't spawn near existing origin if possible
			spawnPoint = SelectSpawnPoint ( 
				client->ps.origin, 
				spawn_origin, spawn_angles, !!(ent->r.svFlags & SVF_BOT));
		}
	}
	client->pers.teamState.state = TEAM_ACTIVE;

	// always clear the kamikaze flag
	ent->s.eFlags &= ~EF_KAMIKAZE;

	// toggle the teleport bit so the client knows to not lerp
	// and never clear the voted flag
	flags = ent->client->ps.eFlags & (EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED);
	flags ^= EF_TELEPORT_BIT;

	// clear everything but the persistant data

	saved = client->pers;
	savedSess = client->sess;
	savedPing = client->ps.ping;
//	savedAreaBits = client->areabits;
	accuracy_hits = client->accuracy_hits;
	accuracy_shots = client->accuracy_shots;
	for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) {
		persistant[i] = client->ps.persistant[i];
	}
	eventSequence = client->ps.eventSequence;

	Com_Memset (client, 0, sizeof(*client));

	client->pers = saved;
	client->sess = savedSess;
	client->ps.ping = savedPing;
//	client->areabits = savedAreaBits;
	client->accuracy_hits = accuracy_hits;
	client->accuracy_shots = accuracy_shots;
	client->lastkilled_client = -1;

	for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) {
		client->ps.persistant[i] = persistant[i];
	}
	client->ps.eventSequence = eventSequence;
	// increment the spawncount so the client will detect the respawn
	client->ps.persistant[PERS_SPAWN_COUNT]++;
	client->ps.persistant[PERS_TEAM] = client->sess.sessionTeam;

	client->airOutTime = level.time + 12000;

	// set max health
	client->pers.maxHealth = ClientHandicap( client );
	// clear entity values
	client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;
	client->ps.eFlags = flags;
	client->ps.contents = CONTENTS_BODY;
	client->ps.capsule = qtrue;

	ent->s.groundEntityNum = ENTITYNUM_NONE;
	ent->client = &level.clients[index];
	ent->takedamage = qtrue;
	ent->inuse = qtrue;
	ent->classname = "player";
	ent->clipmask = MASK_PLAYERSOLID;
	ent->die = player_die;
	ent->waterlevel = 0;
	ent->watertype = 0;
	ent->flags = 0;
	
	VectorCopy (playerMins, client->ps.mins);
	VectorCopy (playerMaxs, client->ps.maxs);

	client->ps.clientNum = index;

	client->ps.stats[STAT_WEAPONS] = ( 1 << WP_MACHINEGUN );
	if ( g_gametype.integer == GT_TEAM ) {
		client->ps.ammo[WP_MACHINEGUN] = 50;
	} else {
		client->ps.ammo[WP_MACHINEGUN] = 100;
	}

	client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET );
	client->ps.ammo[WP_GAUNTLET] = -1;
	client->ps.ammo[WP_GRAPPLING_HOOK] = -1;

	// health will count down towards max_health
	ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] + 25;

	G_SetOrigin( ent, spawn_origin );
	VectorCopy( spawn_origin, client->ps.origin );

	// the respawned flag will be cleared after the attack and jump keys come up
	client->ps.pm_flags |= PMF_RESPAWNED;

	trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd );
	SetClientViewAngle( ent, spawn_angles );
	// don't allow full run speed for a bit
	client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
	client->ps.pm_time = 100;

	client->respawnTime = level.time;
	client->inactivityTime = level.time + g_inactivity.integer * 1000;
	client->latched_buttons = 0;

	// set default animations
	client->ps.torsoAnim = TORSO_STAND;
	client->ps.legsAnim = LEGS_IDLE;

	if (!level.intermissiontime) {
		if (ent->client->sess.sessionTeam != TEAM_SPECTATOR) {
			G_KillBox(ent);
			// force the base weapon up
			client->ps.weapon = WP_MACHINEGUN;
			client->ps.weaponstate = WEAPON_READY;
			// fire the targets of the spawn point
			G_UseTargets(spawnPoint, ent);
			// select the highest weapon number available, after any spawn given items have fired
			client->ps.weapon = 1;

			for (i = WP_NUM_WEAPONS - 1 ; i > 0 ; i--) {
				if (client->ps.stats[STAT_WEAPONS] & (1 << i)) {
					client->ps.weapon = i;
					break;
				}
			}
			// positively link the client, even if the command times are weird
			VectorCopy(ent->client->ps.origin, ent->r.currentOrigin);

			tent = G_TempEntity(ent->client->ps.origin, EV_PLAYER_TELEPORT_IN);
			tent->s.clientNum = ent->s.clientNum;

			trap_LinkEntity (ent);
		}
	} else {
		// move players to intermission
		MoveClientToIntermission(ent);
	}
	// run a client frame to drop exactly to the floor,
	// initialize animations and other things
	client->ps.commandTime = level.time - 100;
	ent->client->pers.cmd.serverTime = level.time;
	ClientThink( ent-g_entities );
	// run the presend to set anything else, follow spectators wait
	// until all clients have been reconnected after map_restart
	if ( ent->client->sess.spectatorState != SPECTATOR_FOLLOW ) {
		ClientEndFrame( ent );
	}

	// clear entity state values
	BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue );
}
コード例 #28
0
ファイル: g_items.c プロジェクト: ElderPlayerX/Invasion
/*
================
G_RunItem

================
*/
void G_RunItem(gentity_t *ent)
{
	vec3_t		origin;
	trace_t		tr;
	int			contents;
	int			mask;

	// if groundentity has been set to -1, it may have been pushed off an edge
	if (ent->s.groundEntityNum == -1)
	{
		if (ent->s.pos.trType != TR_GRAVITY)
		{
			ent->s.pos.trType = TR_GRAVITY;
			ent->s.pos.trTime = level.time;
		}
	}

	if (ent->s.pos.trType == TR_STATIONARY)
	{
		// check think function
		G_RunThink(ent);
		return;
	}

	// get current position
	BG_EvaluateTrajectory(&ent->s.pos, level.time, origin);

	// trace a line from the previous position to the current position
	if (ent->clipmask)
	{
		mask = ent->clipmask;
	}
	else
	{
		mask = MASK_PLAYERSOLID & ~CONTENTS_BODY;//MASK_SOLID;
	}
	trap_Trace(&tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin,
		ent->r.ownerNum, mask);

	VectorCopy(tr.endpos, ent->r.currentOrigin);

	if (tr.startsolid)
	{
		tr.fraction = 0;
	}

	trap_LinkEntity(ent);	// FIXME: avoid this for stationary?

	// check think function
	G_RunThink(ent);

	if (tr.fraction == 1)
	{
		return;
	}

	// if it is in a nodrop volume, remove it
	contents = trap_PointContents(ent->r.currentOrigin, -1);
	if (contents & CONTENTS_NODROP)
	{
		if (ent->item && ent->item->giType == IT_TEAM)
		{
			if (g_gametype.integer == GT_INVASION &&
				(ent->item->giTag == PW_REDFLAG || ent->item->giTag == PW_BLUEFLAG))
			{
				InvasionWin(level.AlienTeam, qtrue);
			}
			else
				Team_FreeEntity(ent);
		}
		else
		{
			G_FreeEntity(ent);
		}
		return;
	}

	G_BounceItem(ent, &tr);
}
コード例 #29
0
ファイル: g_unlagged.c プロジェクト: OpenArena/legacy
/*
=================
G_TimeShiftClient

Move a client back to where he was at the specified "time"
=================
*/
void G_TimeShiftClient( gentity_t *ent, int time, qboolean debug, gentity_t *debugger ) {
	int		j, k;
	//char msg[2048];

	// this will dump out the head index, and the time for all the stored positions
/*
	if ( debug ) {
		char	str[MAX_STRING_CHARS];

		Com_sprintf(str, sizeof(str), "print \"head: %d, %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n\"",
			ent->client->historyHead,
			ent->client->history[0].leveltime,
			ent->client->history[1].leveltime,
			ent->client->history[2].leveltime,
			ent->client->history[3].leveltime,
			ent->client->history[4].leveltime,
			ent->client->history[5].leveltime,
			ent->client->history[6].leveltime,
			ent->client->history[7].leveltime,
			ent->client->history[8].leveltime,
			ent->client->history[9].leveltime,
			ent->client->history[10].leveltime,
			ent->client->history[11].leveltime,
			ent->client->history[12].leveltime,
			ent->client->history[13].leveltime,
			ent->client->history[14].leveltime,
			ent->client->history[15].leveltime,
			ent->client->history[16].leveltime);

		trap_SendServerCommand( debugger - g_entities, str );
	}
*/

	// find two entries in the history whose times sandwich "time"
	// assumes no two adjacent records have the same timestamp
	j = k = ent->client->historyHead;
	do {
		if ( ent->client->history[j].leveltime <= time )
			break;

		k = j;
		j--;
		if ( j < 0 ) {
			j = NUM_CLIENT_HISTORY - 1;
		}
	}
	while ( j != ent->client->historyHead );

	// if we got past the first iteration above, we've sandwiched (or wrapped)
	if ( j != k ) {
		// make sure it doesn't get re-saved
		if ( ent->client->saved.leveltime != level.time ) {
			// save the current origin and bounding box
			VectorCopy( ent->r.mins, ent->client->saved.mins );
			VectorCopy( ent->r.maxs, ent->client->saved.maxs );
			VectorCopy( ent->r.currentOrigin, ent->client->saved.currentOrigin );
			ent->client->saved.leveltime = level.time;
		}

		// if we haven't wrapped back to the head, we've sandwiched, so
		// we shift the client's position back to where he was at "time"
		if ( j != ent->client->historyHead ) {
			float	frac = (float)(time - ent->client->history[j].leveltime) /
				(float)(ent->client->history[k].leveltime - ent->client->history[j].leveltime);

			// interpolate between the two origins to give position at time index "time"
			TimeShiftLerp( frac,
				ent->client->history[j].currentOrigin, ent->client->history[k].currentOrigin,
				ent->r.currentOrigin );

			// lerp these too, just for fun (and ducking)
			TimeShiftLerp( frac,
				ent->client->history[j].mins, ent->client->history[k].mins,
				ent->r.mins );

			TimeShiftLerp( frac,
				ent->client->history[j].maxs, ent->client->history[k].maxs,
				ent->r.maxs );

			/*if ( debug && debugger != NULL ) {
				// print some debugging stuff exactly like what the client does

				// it starts with "Rec:" to let you know it backward-reconciled
				Com_sprintf( msg, sizeof(msg),
					"print \"^1Rec: time: %d, j: %d, k: %d, origin: %0.2f %0.2f %0.2f\n"
					"^2frac: %0.4f, origin1: %0.2f %0.2f %0.2f, origin2: %0.2f %0.2f %0.2f\n"
					"^7level.time: %d, est time: %d, level.time delta: %d, est real ping: %d\n\"",
					time, ent->client->history[j].leveltime, ent->client->history[k].leveltime,
					ent->r.currentOrigin[0], ent->r.currentOrigin[1], ent->r.currentOrigin[2],
					frac,
					ent->client->history[j].currentOrigin[0],
					ent->client->history[j].currentOrigin[1],
					ent->client->history[j].currentOrigin[2], 
					ent->client->history[k].currentOrigin[0],
					ent->client->history[k].currentOrigin[1],
					ent->client->history[k].currentOrigin[2],
					level.time, level.time + debugger->client->frameOffset,
					level.time - time, level.time + debugger->client->frameOffset - time);

				trap_SendServerCommand( debugger - g_entities, msg );
			}*/

			// this will recalculate absmin and absmax
			trap_LinkEntity( ent );
		} else {
			// we wrapped, so grab the earliest
			VectorCopy( ent->client->history[k].currentOrigin, ent->r.currentOrigin );
			VectorCopy( ent->client->history[k].mins, ent->r.mins );
			VectorCopy( ent->client->history[k].maxs, ent->r.maxs );

			// this will recalculate absmin and absmax
			trap_LinkEntity( ent );
		}
	}
	else {
		// this only happens when the client is using a negative timenudge, because that
		// number is added to the command time

		// print some debugging stuff exactly like what the client does

		// it starts with "No rec:" to let you know it didn't backward-reconcile
		//Sago: This code looks wierd

	}
}
コード例 #30
0
/*
========================
LaunchGatling
by Spoon
========================
*/
gentity_t *LaunchGatling( gentity_t *ent ) {
	gentity_t	*gatling;
	//vec3_t	velocity;
	vec3_t	angles, origin;

	// set aiming origin
	VectorCopy( ent->client->ps.viewangles, angles );
	angles[ROLL] = 0;
	angles[PITCH] = 0;	// always forward

	VectorClear(origin);
	AngleVectors( angles, origin, NULL, NULL);
	VectorScale(origin,30,origin);
	VectorAdd(ent->s.pos.trBase, origin, origin);
	//origin[2] -= 10;

	// snap to integer coordinates for more efficient network bandwidth usage
	SnapVector( origin);

//spawning of the gatling

	gatling = G_Spawn();

	gatling->s.eType = ET_TURRET;
	gatling->classname = "gatling";

	gatling->touch = Touch_Item;

	G_SetOrigin( gatling, origin );
	gatling->s.pos.trType = TR_GRAVITY;
	gatling->s.pos.trTime = level.time;
//	VectorCopy( velocity, gatling->s.pos.trDelta );

	gatling->s.eFlags |= EF_BOUNCE_HALF;

	VectorCopy(angles, gatling->r.currentAngles);
	VectorCopy(gatling->r.currentAngles, gatling->s.apos.trBase);

	gatling->clipmask = MASK_SHOT;
	gatling->r.contents = 0; // will be set to MASK_SHOT if no player controls it
	//gatling->r.ownerNum = ent->s.number;
	//gatling->parent = ent;
	gatling->s.pos.trTime = level.time - 50;	// move a bit on the very first frame
	//VectorScale( velocity, 200, gatling->s.pos.trDelta ); // 700
	SnapVector( gatling->s.pos.trDelta );		// save net bandwidth
	gatling->physicsBounce= 0.05f;
	gatling->physicsObject = qtrue;

	//marks object as unused
	gatling->s.eventParm = -1;
	gatling->r.svFlags |= SVF_BROADCAST;

	//object thinks
	gatling->think = Gatling_Think;
	gatling->nextthink = level.time + 100;

	//add ammo into it
	gatling->count = ent->client->ps.ammo[WP_GATLING];
	// save ammo count in case player also has a gatling in his inventory
	ent->client->carriedGatlingAmmo = ent->client->ps.ammo[WP_GATLING];
	ent->client->ps.ammo[WP_GATLING] = 0;

	//build up anims
	gatling->s.time2 = level.time + TRIPOD_TIME + 4*STAGE_TIME;

	trap_LinkEntity (gatling);

	return gatling;
}