/* =============== CheckGrabAttack =============== */ void CheckGrabAttack( gentity_t *ent ) { trace_t tr; vec3_t end, dir; gentity_t *traceEnt; // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); VectorMA( muzzle, LEVEL1_GRAB_RANGE, forward, end ); trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); if( tr.surfaceFlags & SURF_NOIMPACT ) return; traceEnt = &g_entities[ tr.entityNum ]; if( !traceEnt->takedamage ) return; if( traceEnt->client ) { if( traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) return; if( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 ) return; if( !( traceEnt->client->ps.stats[ STAT_STATE ] & SS_GRABBED ) ) { AngleVectors( traceEnt->client->ps.viewangles, dir, NULL, NULL ); traceEnt->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir ); //event for client side grab effect G_AddPredictableEvent( ent, EV_LEV1_GRAB, 0 ); } traceEnt->client->ps.stats[ STAT_STATE ] |= SS_GRABBED; if( ent->client->ps.weapon == WP_ALEVEL1 ) traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_TIME; else if( ent->client->ps.weapon == WP_ALEVEL1_UPG ) traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_U_TIME; } else if( traceEnt->s.eType == ET_BUILDABLE && traceEnt->s.modelindex == BA_H_MGTURRET ) { if( !traceEnt->lev1Grabbed ) G_AddPredictableEvent( ent, EV_LEV1_GRAB, 0 ); traceEnt->lev1Grabbed = qtrue; traceEnt->lev1GrabTime = level.time; } }
void trigger_push_touch( gentity_t *self, gentity_t *other, trace_t *trace ) { if ( ( self->spawnflags & 4 ) && other->r.svFlags & SVF_CASTAI ) { return; } if ( !other->client ) { return; } if ( other->client->ps.pm_type != PM_NORMAL ) { return; } if ( other->client->ps.powerups[PW_FLIGHT] ) { return; } //----(SA) commented out as we have no hook // if (other->client && other->client->hook) // Weapon_HookFree(other->client->hook); if ( other->client->ps.velocity[2] < 100 ) { // don't play the event sound again if we are in a fat trigger G_AddPredictableEvent( other, EV_JUMP_PAD, 0 ); } VectorCopy( self->s.origin2, other->client->ps.velocity ); if ( self->spawnflags & 2 ) { G_FreeEntity( self ); } }
void heal_touch(gentity_t * self, gentity_t * other, trace_t * trace) { int i, clientcount = 0; gentity_t *touchClients[MAX_CLIENTS]; int healvalue; memset(touchClients, 0, sizeof(touchClients)); if(!other->client) { return; } if(self->timestamp > level.time) { return; } self->timestamp = level.time + 1000; for(i = 0; i < level.numConnectedClients; i++) { int j = level.sortedClients[i]; if(level.clients[j].ps.stats[STAT_MAX_HEALTH] > g_entities[j].health && trap_EntityContactCapsule(g_entities[j].r.absmin, g_entities[j].r.absmax, self) && G_IsAllowedHeal(&g_entities[j])) { touchClients[clientcount] = &g_entities[j]; clientcount++; } } if(clientcount == 0) { return; } for(i = 0; i < clientcount; i++) { healvalue = min(touchClients[i]->client->ps.stats[STAT_MAX_HEALTH] - touchClients[i]->health, self->damage); if(self->health != -9999) { healvalue = min(healvalue, self->health); } if(healvalue <= 0) { continue; } touchClients[i]->health += healvalue; // add the medicheal event (to get sound, etc.) G_AddPredictableEvent(other, EV_ITEM_PICKUP, BG_FindItemForClassName("item_health_cabinet") - bg_itemlist); if(self->health != -9999) { self->health -= healvalue; } } }
void ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace ) { int i, clientcount = 0, count; gentity_t* touchClients[MAX_CLIENTS]; memset(touchClients, 0, sizeof(touchClients)); if( other->client == NULL ) { return; } // flags is for the last entity number that got ammo if ( self->timestamp > level.time ) { return; } self->timestamp = level.time + 1000; for( i = 0; i < level.numConnectedClients; i++ ) { int j = level.sortedClients[i]; if( trap_EntityContactCapsule( g_entities[j].r.absmin, g_entities[j].r.absmax, self ) && G_IsAllowedAmmo( &g_entities[j] ) ) { touchClients[clientcount] = &g_entities[j]; clientcount++; } } if(clientcount == 0) { return; } // Gordon: if low, just give out what's left if(self->health == -9999) { count = clientcount; } else { count = min(clientcount, self->health / (float)self->damage ); } for( i = 0; i < count; i++) { int ammoAdded = qfalse; // self->damage contains the amount of ammo to add ammoAdded = AddMagicAmmo(touchClients[i], self->damage); if (ammoAdded) { // add the ammo pack event (to get sound, etc.) G_AddPredictableEvent( touchClients[i], EV_ITEM_PICKUP, BG_FindItem("Ammo Pack")-bg_itemlist ); if (self->health != -9999) { // reduce the ammount of available ammo by the added clip number self->health -= self->damage; // G_Printf("%i clips left\n", self->health ); } } } }
/* =============== 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 ) ) { 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 ); }
/* =========== 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, gentity_t *spawn, vec3_t origin, vec3_t angles ) { 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 = NULL; int flags; int savedPing; int teamLocal; int eventSequence; char userinfo[ MAX_INFO_STRING ]; vec3_t up = { 0.0f, 0.0f, 1.0f }; int maxAmmo, maxClips; weapon_t weapon; index = ent - g_entities; client = ent->client; teamLocal = client->pers.teamSelection; //if client is dead and following teammate, stop following before spawning if( client->sess.spectatorClient != -1 ) { client->sess.spectatorClient = -1; client->sess.spectatorState = SPECTATOR_FREE; } // only start client if chosen a class and joined a team if( client->pers.classSelection == PCL_NONE && teamLocal == TEAM_NONE ) client->sess.spectatorState = SPECTATOR_FREE; else if( client->pers.classSelection == PCL_NONE ) client->sess.spectatorState = SPECTATOR_LOCKED; // if client is dead and following teammate, stop following before spawning if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) G_StopFollowing( ent ); if( origin != NULL ) VectorCopy( origin, spawn_origin ); if( angles != NULL ) VectorCopy( angles, spawn_angles ); // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if( client->sess.spectatorState != SPECTATOR_NOT ) { if( teamLocal == TEAM_NONE ) spawnPoint = G_SelectSpectatorSpawnPoint( spawn_origin, spawn_angles ); else if( teamLocal == TEAM_ALIENS ) spawnPoint = G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles ); else if( teamLocal == TEAM_HUMANS ) spawnPoint = G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles ); } else { if( spawn == NULL ) { G_Error( "ClientSpawn: spawn is NULL\n" ); return; } spawnPoint = spawn; if( ent != spawn ) { //start spawn animation on spawnPoint G_SetBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue ); if( spawnPoint->buildableTeam == TEAM_ALIENS ) spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME; else if( spawnPoint->buildableTeam == TEAM_HUMANS ) spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME; } } // toggle the teleport bit so the client knows to not lerp flags = ( ent->client->ps.eFlags & EF_TELEPORT_BIT ) ^ EF_TELEPORT_BIT; G_UnlaggedClear( ent ); // clear everything but the persistant data saved = client->pers; savedSess = client->sess; savedPing = client->ps.ping; for( i = 0; i < MAX_PERSISTANT; i++ ) persistant[ i ] = client->ps.persistant[ i ]; eventSequence = client->ps.eventSequence; memset( client, 0, sizeof( *client ) ); client->pers = saved; client->sess = savedSess; client->ps.ping = savedPing; 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_SPECSTATE ] = client->sess.spectatorState; client->airOutTime = level.time + 12000; trap_GetUserinfo( index, userinfo, sizeof( userinfo ) ); client->ps.eFlags = flags; //Com_Printf( "ent->client->pers->pclass = %i\n", ent->client->pers.classSelection ); 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; // calculate each client's acceleration ent->evaluateAcceleration = qtrue; client->ps.stats[ STAT_MISC ] = 0; client->ps.eFlags = flags; client->ps.clientNum = index; BG_ClassBoundingBox( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, NULL, NULL, NULL ); if( client->sess.spectatorState == SPECTATOR_NOT ) client->ps.stats[ STAT_MAX_HEALTH ] = BG_Class( ent->client->pers.classSelection )->health; else client->ps.stats[ STAT_MAX_HEALTH ] = 100; // clear entity values if( ent->client->pers.classSelection == PCL_HUMAN ) { BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats ); weapon = client->pers.humanItemSelection; } else if( client->sess.spectatorState == SPECTATOR_NOT ) weapon = BG_Class( ent->client->pers.classSelection )->startWeapon; else weapon = WP_NONE; maxAmmo = BG_Weapon( weapon )->maxAmmo; maxClips = BG_Weapon( weapon )->maxClips; client->ps.stats[ STAT_WEAPON ] = weapon; client->ps.ammo = maxAmmo; client->ps.clips = maxClips; // We just spawned, not changing weapons client->ps.persistant[ PERS_NEWWEAPON ] = 0; ent->client->ps.stats[ STAT_CLASS ] = ent->client->pers.classSelection; ent->client->ps.stats[ STAT_TEAM ] = ent->client->pers.teamSelection; ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE; ent->client->ps.stats[ STAT_STATE ] = 0; VectorSet( ent->client->ps.grapplePoint, 0.0f, 0.0f, 1.0f ); // health will count down towards max_health ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25; //if evolving scale health if( ent == spawn ) { ent->health *= ent->client->pers.evolveHealthFraction; client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction; } //clear the credits array for( i = 0; i < MAX_CLIENTS; i++ ) ent->credits[ i ] = 0; client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX; G_SetOrigin( ent, spawn_origin ); VectorCopy( spawn_origin, client->ps.origin ); #define UP_VEL 150.0f #define F_VEL 50.0f //give aliens some spawn velocity if( client->sess.spectatorState == SPECTATOR_NOT && client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) { if( ent == spawn ) { //evolution particle system G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) ); } else { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); if( spawnPoint->s.origin2[ 2 ] > 0.0f ) { vec3_t forward, dir; AngleVectors( spawn_angles, forward, NULL, NULL ); VectorScale( forward, F_VEL, forward ); VectorAdd( spawnPoint->s.origin2, forward, dir ); VectorNormalize( dir ); VectorScale( dir, UP_VEL, client->ps.velocity ); } G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 ); } } else if( client->sess.spectatorState == SPECTATOR_NOT && client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); } // 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 ); G_SetClientViewAngle( ent, spawn_angles ); if( client->sess.spectatorState == SPECTATOR_NOT ) { trap_LinkEntity( ent ); // force the base weapon up if( client->pers.teamSelection == TEAM_HUMANS ) G_ForceWeaponChange( ent, weapon ); client->ps.weaponstate = WEAPON_READY; } // 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; ent->nextRegenTime = 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 ) MoveClientToIntermission( ent ); else { // fire the targets of the spawn point if( !spawn ) G_UseTargets( spawnPoint, ent ); client->ps.weapon = client->ps.stats[ STAT_WEAPON ]; } // 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( client->sess.spectatorState == SPECTATOR_NOT ) { BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); trap_LinkEntity( ent ); } // must do this here so the number of active clients is calculated CalculateRanks( ); // run the presend to set anything else ClientEndFrame( ent ); // clear entity state values BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); client->pers.infoChangeTime = level.time; }
/* =============== Touch_Item =============== */ void Touch_Item( gentity_t *ent, gentity_t *other, trace_t *trace ) { int respawn; int makenoise = EV_ITEM_PICKUP; // 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 < 1 ) { 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 ) ) { return; } G_LogPrintf( "Item: %i %s\n", other->s.number, ent->item->classname ); // call the item-specific pickup function switch ( ent->item->giType ) { case IT_WEAPON: respawn = Pickup_Weapon( ent, other ); break; case IT_AMMO: respawn = Pickup_Ammo( ent, other ); 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 ); break; case IT_TEAM: respawn = Pickup_Team( ent, other ); break; case IT_HOLDABLE: respawn = Pickup_Holdable( ent, other ); break; case IT_KEY: respawn = Pickup_Key( ent, other ); break; case IT_TREASURE: respawn = Pickup_Treasure( ent, other ); break; case IT_CLIPBOARD: respawn = Pickup_Clipboard( ent, other ); // send the event to the client to request that the UI draw a popup // (specified by the configstring in ent->s.density). //G_AddEvent( other, EV_POPUP, ent->s.density); //if(ent->key) //G_AddEvent( other, EV_GIVEPAGE, ent->key ); break; default: return; } if ( !respawn ) { return; } // play sounds if ( ent->noise_index ) { // (SA) 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 recieved makenoise = EV_ITEM_PICKUP_QUIET; G_AddEvent( other, EV_GENERAL_SOUND, ent->noise_index ); } // send the pickup event if ( other->client->pers.predictItemPickup ) { G_AddPredictableEvent( other, makenoise, ent->s.modelindex ); } else { G_AddEvent( other, makenoise, ent->s.modelindex ); } // powerup pickups are global broadcasts if ( ent->item->giType == IT_POWERUP || ent->item->giType == IT_TEAM ) { // (SA) probably need to check for IT_KEY here too... (coop?) 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; // (SA) set if we want this to only go to the pickup 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->flags |= FL_NODRAW; //ent->r.svFlags |= SVF_NOCLIENT; ent->s.eFlags |= EF_NODRAW; ent->r.contents = 0; ent->unlinkAfterEvent = qtrue; return; } // wait of -2 will respawn but not be available for pickup anymore // (partial use things that leave a spent modle (ex. plate for turkey) if ( respawn == RESPAWN_PARTIAL_DONE ) { ent->s.density = ( 1 << 9 ); // (10 bits of data transmission for density) ent->active = qtrue; // re-activate trap_LinkEntity( ent ); return; } if ( respawn == RESPAWN_PARTIAL ) { // multi-stage health ent->s.density--; if ( ent->s.density ) { // still not completely used up ( (SA) this will change to == 0 and stage 1 will be a destroyable item (plate/etc.) ) ent->active = qtrue; // re-activate trap_LinkEntity( ent ); 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->flags |= FL_NODRAW; //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 ); }
/* =========== ClientSpawn Called every time a client is placed fresh in the world: after the first ClientBegin, and after each respawn and evolve Initializes all non-persistent parts of playerState ============ */ void ClientSpawn( gentity_t *ent, gentity_t *spawn, const vec3_t origin, const vec3_t angles ) { int index; vec3_t spawn_origin, spawn_angles; gclient_t *client; int i; clientPersistant_t saved; clientSession_t savedSess; bool savedNoclip, savedCliprcontents; int persistant[ MAX_PERSISTANT ]; gentity_t *spawnPoint = nullptr; int flags; int savedPing; int teamLocal; int eventSequence; char userinfo[ MAX_INFO_STRING ]; vec3_t up = { 0.0f, 0.0f, 1.0f }; int maxAmmo, maxClips; weapon_t weapon; ClientSpawnCBSE(ent, ent == spawn); index = ent - g_entities; client = ent->client; teamLocal = client->pers.team; //if client is dead and following teammate, stop following before spawning if ( client->sess.spectatorClient != -1 ) { client->sess.spectatorClient = -1; client->sess.spectatorState = SPECTATOR_FREE; } // only start client if chosen a class and joined a team if ( client->pers.classSelection == PCL_NONE && teamLocal == TEAM_NONE ) { client->sess.spectatorState = SPECTATOR_FREE; } else if ( client->pers.classSelection == PCL_NONE ) { client->sess.spectatorState = SPECTATOR_LOCKED; } // if client is dead and following teammate, stop following before spawning if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) { G_StopFollowing( ent ); } if ( origin != nullptr ) { VectorCopy( origin, spawn_origin ); } if ( angles != nullptr ) { VectorCopy( angles, spawn_angles ); } // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if ( client->sess.spectatorState != SPECTATOR_NOT ) { if ( teamLocal == TEAM_NONE ) { spawnPoint = G_SelectSpectatorSpawnPoint( spawn_origin, spawn_angles ); } else if ( teamLocal == TEAM_ALIENS ) { spawnPoint = G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles ); } else if ( teamLocal == TEAM_HUMANS ) { spawnPoint = G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles ); } } else { if ( spawn == nullptr ) { Com_Error(errorParm_t::ERR_DROP, "ClientSpawn: spawn is NULL" ); } spawnPoint = spawn; if ( spawnPoint->s.eType == entityType_t::ET_BUILDABLE ) { G_SetBuildableAnim( spawnPoint, BANIM_SPAWN1, true ); if ( spawnPoint->buildableTeam == TEAM_ALIENS ) { spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME; } else if ( spawnPoint->buildableTeam == TEAM_HUMANS ) { spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME; } } } // toggle the teleport bit so the client knows to not lerp flags = ( ent->client->ps.eFlags & EF_TELEPORT_BIT ) ^ EF_TELEPORT_BIT; G_UnlaggedClear( ent ); // clear everything but the persistent data saved = client->pers; savedSess = client->sess; savedPing = client->ps.ping; savedNoclip = client->noclip; savedCliprcontents = client->cliprcontents; for ( i = 0; i < MAX_PERSISTANT; i++ ) { persistant[ i ] = client->ps.persistant[ i ]; } eventSequence = client->ps.eventSequence; memset( client, 0, sizeof( *client ) ); client->pers = saved; client->sess = savedSess; client->ps.ping = savedPing; client->noclip = savedNoclip; client->cliprcontents = savedCliprcontents; 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_SPECSTATE ] = client->sess.spectatorState; client->airOutTime = level.time + 12000; trap_GetUserinfo( index, userinfo, sizeof( userinfo ) ); client->ps.eFlags = flags; //Log::Notice( "ent->client->pers->pclass = %i\n", ent->client->pers.classSelection ); ent->s.groundEntityNum = ENTITYNUM_NONE; ent->client = &level.clients[ index ]; ent->classname = S_PLAYER_CLASSNAME; if ( client->noclip ) { client->cliprcontents = CONTENTS_BODY; } else { ent->r.contents = CONTENTS_BODY; } ent->clipmask = MASK_PLAYERSOLID; ent->die = G_PlayerDie; ent->waterlevel = 0; ent->watertype = 0; ent->flags &= FL_GODMODE | FL_NOTARGET; // calculate each client's acceleration ent->evaluateAcceleration = true; client->ps.stats[ STAT_MISC ] = 0; client->ps.eFlags = flags; client->ps.clientNum = index; BG_ClassBoundingBox( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, nullptr, nullptr, nullptr ); // clear entity values if ( ent->client->pers.classSelection == PCL_HUMAN_NAKED ) { BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats ); weapon = client->pers.humanItemSelection; } else if ( client->sess.spectatorState == SPECTATOR_NOT ) { weapon = BG_Class( ent->client->pers.classSelection )->startWeapon; } else { weapon = WP_NONE; } maxAmmo = BG_Weapon( weapon )->maxAmmo; maxClips = BG_Weapon( weapon )->maxClips; client->ps.stats[ STAT_WEAPON ] = weapon; client->ps.ammo = maxAmmo; client->ps.clips = maxClips; // We just spawned, not changing weapons client->ps.persistant[ PERS_NEWWEAPON ] = 0; client->ps.persistant[ PERS_TEAM ] = client->pers.team; // TODO: Check whether stats can be cleared at once instead of per field client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX; client->ps.stats[ STAT_FUEL ] = JETPACK_FUEL_MAX; client->ps.stats[ STAT_CLASS ] = ent->client->pers.classSelection; client->ps.stats[ STAT_BUILDABLE ] = BA_NONE; client->ps.stats[ STAT_PREDICTION ] = 0; client->ps.stats[ STAT_STATE ] = 0; VectorSet( client->ps.grapplePoint, 0.0f, 0.0f, 1.0f ); //clear the credits array // TODO: Handle in HealthComponent or ClientComponent. for ( i = 0; i < MAX_CLIENTS; i++ ) { ent->credits[ i ].value = 0.0f; ent->credits[ i ].time = 0; ent->credits[ i ].team = TEAM_NONE; } G_SetOrigin( ent, spawn_origin ); VectorCopy( spawn_origin, client->ps.origin ); //give aliens some spawn velocity if ( client->sess.spectatorState == SPECTATOR_NOT && client->pers.team == TEAM_ALIENS ) { if ( ent == spawn ) { //evolution particle system G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) ); } else { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); if ( spawnPoint->s.origin2[ 2 ] > 0.0f ) { vec3_t forward, dir; AngleVectors( spawn_angles, forward, nullptr, nullptr ); VectorAdd( spawnPoint->s.origin2, forward, dir ); VectorNormalize( dir ); VectorScale( dir, BG_Class( ent->client->pers.classSelection )->jumpMagnitude, client->ps.velocity ); } G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 ); } } else if ( client->sess.spectatorState == SPECTATOR_NOT && client->pers.team == TEAM_HUMANS ) { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); } // 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 ); G_SetClientViewAngle( ent, spawn_angles ); if ( client->sess.spectatorState == SPECTATOR_NOT ) { trap_LinkEntity( ent ); // force the base weapon up if ( client->pers.team == TEAM_HUMANS ) { G_ForceWeaponChange( ent, weapon ); } client->ps.weaponstate = WEAPON_READY; } // 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; ent->nextRegenTime = level.time; client->inactivityTime = level.time + g_inactivity.integer * 1000; usercmdClearButtons( client->latched_buttons ); // set default animations client->ps.torsoAnim = TORSO_STAND; client->ps.legsAnim = LEGS_IDLE; if ( level.intermissiontime ) { MoveClientToIntermission( ent ); } else { // fire the targets of the spawn point if ( !spawn && spawnPoint ) { G_EventFireEntity( spawnPoint, ent, ON_SPAWN ); } // 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 ( BG_InventoryContainsWeapon( i, client->ps.stats ) ) { client->ps.weapon = i; break; } } } // 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 ( client->sess.spectatorState == SPECTATOR_NOT ) { BG_PlayerStateToEntityState( &client->ps, &ent->s, true ); VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); trap_LinkEntity( ent ); } // must do this here so the number of active clients is calculated CalculateRanks(); // run the presend to set anything else ClientEndFrame( ent ); // clear entity state values BG_PlayerStateToEntityState( &client->ps, &ent->s, true ); client->pers.infoChangeTime = level.time; // (re)tag the client for its team Beacon::DeleteTags( ent ); Beacon::Tag( ent, (team_t)ent->client->ps.persistant[ PERS_TEAM ], true ); }
/* =============== Touch_Item =============== */ void Touch_Item(gentity_t * ent, gentity_t * other, trace_t * trace) { int respawn; qboolean predict; int bandolierFactor; //Makro - some checks if (other == NULL || ent == NULL) return; if (!other->client) return; if (other->health < 1) return; // dead people can't pickup //Makro - even more bot hacks ! //this way, we can remove the item from the bot's library for a few seconds //so bots won't get stuck in a loop between 2 items if ((ent->r.svFlags & MASK_BOTHACK) == MASK_BOTHACK) { if (ent->nextthink < level.time) { ent->nextthink = level.time + 45 * 1000; } return; } // the same pickup rules are used for client side and server side if (!BG_CanItemBeGrabbed(g_gametype.integer, &ent->s, &other->client->ps)) return; predict = other->client->pers.predictItemPickup; if (other->client->ps.stats[STAT_HOLDABLE_ITEM] & (1 << HI_BANDOLIER)) bandolierFactor = 2; else bandolierFactor = 1; //Elder: should check if the item was recently thrown ... if it was, then //don't allow it to be picked up ... or something like that // call the item-specific pickup function switch (ent->item->giType) { case IT_WEAPON: switch (ent->item->giTag) { //Blaze: Check to see if we already have the weapon, //If not so check and see if we have less then full ammo, if so pick up gun //Elder's version: //Accumulators (e.g. knife, grenade): if you have the weap AND the max limit, leave //Pistols: if you have akimbos AND max clips, leave //Akimbos: shouldn't pick them up b/c they shouldn't be dropped //Specials: if you have more than/equal to limit (remember bando later), leave case WP_KNIFE: if (((other->client->ps.stats[STAT_WEAPONS] & (1 << WP_KNIFE)) == (1 << WP_KNIFE)) && (other->client->ps.ammo[ent->item->giTag] >= RQ3_KNIFE_MAXCLIP * bandolierFactor)) return; break; case WP_GRENADE: if (((other->client->ps.stats[STAT_WEAPONS] & (1 << WP_GRENADE)) == (1 << WP_GRENADE)) && (other->client->ps.ammo[ent->item->giTag] >= RQ3_GRENADE_MAXCLIP * bandolierFactor)) return; break; case WP_PISTOL: //Elder: always have pistol - but extra ones give akimbo or clips if (((other->client->ps.stats[STAT_WEAPONS] & (1 << WP_AKIMBO)) == (1 << WP_AKIMBO)) && other->client->numClips[WP_PISTOL] >= RQ3_PISTOL_MAXCLIP * bandolierFactor) { //leave if we have max clips and akimbos return; } break; case WP_M3: case WP_HANDCANNON: case WP_MP5: case WP_M4: case WP_SSG3000: //Elder: check to see if it's in mid-air or over the limit if (other->client->uniqueWeapons >= g_RQ3_maxWeapons.integer + (bandolierFactor - 1) || ent->s.pos.trDelta[2] != 0) return; // Paril: fix/workaround for 4085 // don't pick up dupe special weapons even if we could. if ((other->client->ps.stats[STAT_WEAPONS] & (1 << ent->item->giTag)) == (1 << ent->item->giTag)) return; break; case WP_AKIMBO: default: //Elder: shouldn't be here G_Printf("Touch_Item received invalid IT_WEAPON giTag: %d\n", ent->item->giTag); return; break; } respawn = Pickup_Weapon(ent, other, bandolierFactor); //Elder: added pistol and knife condition if (ent->item->giTag == WP_GRENADE || ent->item->giTag == WP_PISTOL || ent->item->giTag == WP_KNIFE) { respawn = 30; } else { //Elder: moved here respawn = -1; //Dont respawn weapons } // predict = qfalse; break; case IT_AMMO: switch (ent->item->giTag) { //Blaze: dont pick up the clip if we already have all the clips we can have case WP_KNIFE: if (other->client->numClips[ent->item->giTag] >= 0) return; //No clips for knifes break; case WP_PISTOL: if (other->client->numClips[ent->item->giTag] >= RQ3_PISTOL_MAXCLIP * bandolierFactor) return; break; case WP_M3: if (other->client->numClips[ent->item->giTag] >= RQ3_M3_MAXCLIP * bandolierFactor) return; break; case WP_HANDCANNON: if (other->client->numClips[ent->item->giTag] >= RQ3_HANDCANNON_MAXCLIP * bandolierFactor) return; break; case WP_MP5: if (other->client->numClips[ent->item->giTag] >= RQ3_MP5_MAXCLIP * bandolierFactor) return; break; case WP_M4: if (other->client->numClips[ent->item->giTag] >= RQ3_M4_MAXCLIP * bandolierFactor) return; break; case WP_SSG3000: if (other->client->numClips[ent->item->giTag] >= RQ3_SSG3000_MAXCLIP * bandolierFactor) return; break; case WP_AKIMBO: if (other->client->numClips[ent->item->giTag] >= RQ3_AKIMBO_MAXCLIP * bandolierFactor) return; break; case WP_GRENADE: if (other->client->numClips[ent->item->giTag] >= 0) return; //no clips for grenades break; } respawn = Pickup_Ammo(ent, other, bandolierFactor); 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; case IT_TEAM: // NiceAss: can't pick it up if it's in mid-flight (someone dropped it) if (ent->s.pos.trDelta[2] != 0.0f) return; respawn = Pickup_Team(ent, other); break; case IT_HOLDABLE: //Elder: check to see if it's in mid-air if (other->client->uniqueItems >= g_RQ3_maxItems.integer || ent->s.pos.trDelta[2] != 0) return; 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); }
/* =============== CheckGrabAttack =============== */ void CheckGrabAttack( gentity_t *ent ) { trace_t tr; vec3_t end, dir; gentity_t *traceEnt; // set aiming directions AngleVectors( ent->client->ps.viewangles, forward, right, up ); CalcMuzzlePoint( ent, forward, right, up, muzzle ); if ( ent->client->ps.weapon == WP_ALEVEL1 ) { VectorMA( muzzle, LEVEL1_GRAB_RANGE, forward, end ); } else if ( ent->client->ps.weapon == WP_ALEVEL1_UPG ) { VectorMA( muzzle, LEVEL1_GRAB_U_RANGE, forward, end ); } trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); if ( tr.surfaceFlags & SURF_NOIMPACT ) { return; } traceEnt = &g_entities[ tr.entityNum ]; if ( !traceEnt->takedamage ) { return; } if ( traceEnt->client ) { if ( traceEnt->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) { return; } if ( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 ) { return; } if ( !( traceEnt->client->ps.stats[ STAT_STATE ] & SS_GRABBED ) ) { AngleVectors( traceEnt->client->ps.viewangles, dir, NULL, NULL ); traceEnt->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir ); //event for client side grab effect G_AddPredictableEvent( ent, EV_LEV1_GRAB, 0 ); } traceEnt->client->ps.stats[ STAT_STATE ] |= SS_GRABBED; if ( ent->client->ps.weapon == WP_ALEVEL1 ) { traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_TIME; // Update the last combat time. ent->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME; traceEnt->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME; } else if ( ent->client->ps.weapon == WP_ALEVEL1_UPG ) { traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_U_TIME; // Update the last combat time. ent->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME; traceEnt->client->lastCombatTime = level.time + LEVEL1_GRAB_TIME; } } }
/* =============== Touch_Item =============== */ void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) { int respawn; qboolean predict; //instant gib if ((g_instantgib.integer || g_rockets.integer || g_gametype.integer == GT_CTF_ELIMINATION || g_elimination_allgametypes.integer) && ent->item->giType != IT_TEAM) return; //Cannot touch flag before round starts if(g_gametype.integer == GT_CTF_ELIMINATION && level.roundNumber != level.roundNumberStarted) return; //Cannot take ctf elimination oneway if(g_gametype.integer == GT_CTF_ELIMINATION && g_elimination_ctf_oneway.integer!=0 && ( (other->client->sess.sessionTeam==TEAM_BLUE && (level.eliminationSides+level.roundNumber)%2 == 0 ) || (other->client->sess.sessionTeam==TEAM_RED && (level.eliminationSides+level.roundNumber)%2 != 0 ) )) return; if (g_gametype.integer == GT_ELIMINATION || g_gametype.integer == GT_LMS) return; //nothing to pick up in elimination 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 ) ) { return; } //In double DD we cannot "pick up" a flag we already got if(g_gametype.integer == GT_DOUBLE_D) { if( strcmp(ent->classname, "team_CTF_redflag") == 0 ) if(other->client->sess.sessionTeam == level.pointStatusA) return; if( strcmp(ent->classname, "team_CTF_blueflag") == 0 ) if(other->client->sess.sessionTeam == level.pointStatusB) 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; case IT_PERSISTANT_POWERUP: respawn = Pickup_PersistantPowerup(ent, other); break; case IT_TEAM: respawn = Pickup_Team(ent, other); //If touching a team item remove spawnprotection if(other->client->spawnprotected) other->client->spawnprotected = qfalse; 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 ); }
void explodedretch(gentity_t *ent) { int i; int entityList[ MAX_GENTITIES ]; vec3_t range; vec3_t mins, maxs; int num; gentity_t *enemy; float creepSize = (float)650; int freezedcounter = 0; //gentity_t *gren; if(ent->client->ps.persistant[ PERS_CREDIT ] < 1) //Neeeddd fix <3 { trap_SendServerCommand( ent-g_entities, "print \"^5Overmind: ^7You need 1 evos to explode.\n\"" ); } else { ent->client->ps.persistant[ PERS_CREDIT ] -= 1; G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, 0 ); G_RadiusDamage( ent->r.currentOrigin, ent, 200, 200, ent, MOD_GRENADE); G_Damage( ent, ent, ent, NULL, NULL, 10000, 0, MOD_UNKNOWN ); //Slow down enemy around. VectorSet( range, creepSize, creepSize, creepSize ); VectorAdd( ent->s.origin, range, maxs ); VectorSubtract( ent->s.origin, range, mins ); //find enemys around me num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); for( i = 0; i < num; i++ ) { enemy = &g_entities[ entityList[ i ] ]; if( enemy->flags & FL_NOTARGET ) continue; if( enemy->client && (enemy->client->ps.stats[ STAT_PTEAM ] != ent->client->ps.stats[ STAT_PTEAM ] ) && G_Visible( ent, enemy ) ) { //enemy->client->ps.stats[ STAT_STATE ] |= SS_CREEPSLOWED; enemy->client->ps.stats[ STAT_STATE ] |= SS_ICEWAVED; enemy->client->lastCreepSlowTime = level.time + 5000; freezedcounter++; //G_SelectiveRadiusDamage( ent->s.pos.trBase, ent, (float)dmg, (float)500, ent, MOD_SLOWBLOB, ent->client->ps.stats[ STAT_PTEAM ] ); } } if(ent->client){ //29 Freezing Field Icewave over 5 enemies in 1 icewave if(ent->client->pers.badges[ 29 ] != 1 && freezedcounter >= 5) { ent->client->pers.badgeupdate[29] = 1; ent->client->pers.badges[29] = 1; G_WinBadge( ent, 29 ); } } } /* if(ent->client->pers.teamSelection != PTE_HUMANS && ent->client->pers.teamSelection != PTE_ALIENS ) { trap_SendServerCommand( ent-g_entities, va( "print \"^1You must be on a team\n\"" ) ); return qfalse; } if(ent->client->pers.classSelection == PCL_NONE) { trap_SendServerCommand( ent-g_entities, va( "print \"^1You must be alive\n\"" ) ); return qfalse; } if(ent->client->pers.energy >= 500) { if(ent->client->pers.teamSelection == PTE_HUMANS) { dmg = 3; } if(ent->client->pers.teamSelection == PTE_ALIENS) { dmg = 1; } ent->client->pers.energy-= 500; G_AddEvent( ent, EV_ALIEN_BUILDABLE_EXPLOSION, 0 ); VectorSet( range, creepSize, creepSize, creepSize ); VectorAdd( ent->s.origin, range, maxs ); VectorSubtract( ent->s.origin, range, mins ); //find enemys around me num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); for( i = 0; i < num; i++ ) { enemy = &g_entities[ entityList[ i ] ]; if( enemy->flags & FL_NOTARGET ) continue; if( enemy->client && (enemy->client->ps.stats[ STAT_PTEAM ] != ent->client->ps.stats[ STAT_PTEAM ] ) && G_Visible( ent, enemy ) ) { //enemy->client->ps.stats[ STAT_STATE ] |= SS_CREEPSLOWED; enemy->client->ps.stats[ STAT_STATE ] |= SS_ICEWAVED; enemy->client->lastCreepSlowTime = level.time + 5000; //G_SelectiveRadiusDamage( ent->s.pos.trBase, ent, (float)dmg, (float)500, ent, MOD_SLOWBLOB, ent->client->ps.stats[ STAT_PTEAM ] ); } } return qtrue; }*/ }
virtual void execute( GameEntity *other, trace_t *trace ) { int respawn; bool predict; GameEntity* self = self_; // Since we may delete our current think() if( !other->client_ ) return; if( other->health_ < 1 ) return; // dead people can't pickup if( other->client_->ps_.pm_type == PM_SPECTATOR ) return; // the same pickup rules are used for client side and server side if ( !BG_CanItemBeGrabbed( g_gametype.integer, &self->s, &other->client_->ps_, other->client_->vehicle_ ) ) return; G_LogPrintf( "Item: %i %s\n", other->s.number, self->item_->classname ); predict = other->client_->pers_.predictItemPickup_; // call the item-specific pickup function switch( self->item_->giType ) { case IT_AMMO: respawn = Pickup_Ammo(self, other); break; case IT_HEALTH: respawn = Pickup_Health(self, other); break; case IT_FUEL: respawn = Pickup_Fuel(self, other); break; case IT_TEAM: respawn = Pickup_Team(self, other); break; default: return; } if ( !respawn ) return; // play the normal pickup sound if( predict ) G_AddPredictableEvent( other, EV_ITEM_PICKUP, self->s.modelindex ); else G_AddEvent( other, EV_ITEM_PICKUP, self->s.modelindex, true ); // powerup pickups are global broadcasts if( self->item_->giType == IT_TEAM) { // if we want the global sound to play if( !self->speed_ ) { GameEntity *te; te = G_TempEntity( self->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP ); te->s.eventParm = self->s.modelindex; te->r.svFlags |= SVF_BROADCAST; } else { GameEntity *te; te = G_TempEntity( self->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP ); te->s.eventParm = self->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 (self, other); // wait of -1 will not respawn if( self->wait_ == -1 ) { self->r.svFlags |= SVF_NOCLIENT; self->s.eFlags |= EF_NODRAW; self->r.contents = 0; self->unlinkAfterEvent_ = true; return; } // non zero wait overrides respawn time if( self->wait_ ) respawn = self->wait_; // random can be used to vary the respawn time if( self->random_ ) { respawn += crandom() * self->random_; if ( respawn < 1 ) respawn = 1; } // dropped items will not respawn if( self->flags_ & FL_DROPPED_ITEM ) self->freeAfterEvent_ = true; // picked up items still stay around, they just don't // draw anything. This allows respawnable items // to be placed on movers. self->r.svFlags |= SVF_NOCLIENT; self->s.eFlags |= EF_NODRAW; self->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 ) { self->nextthink_ = 0; self->setThink(0); } else { self->nextthink_ = theLevel.time_ + respawn * 1000; self->setThink(new Think_RespawnItem); } SV_LinkEntity( self ); }
void heal_touch(gentity_t *self, gentity_t *other, trace_t *trace) { int i, j, clientcount = 0; gentity_t *touchClients[MAX_CLIENTS]; int healvalue; memset(touchClients, 0, sizeof(gentity_t *) * MAX_CLIENTS); if (!other->client) { return; } if (self->timestamp > level.time) { return; } self->timestamp = level.time + 1000; for (i = 0; i < level.numConnectedClients; i++) { j = level.sortedClients[i]; if (trap_EntityContactCapsule(g_entities[j].r.absmin, g_entities[j].r.absmax, self) && G_IsAllowedHeal(&g_entities[j])) { touchClients[clientcount] = &g_entities[j]; clientcount++; } } if (clientcount == 0) { return; } for (i = 0; i < clientcount; i++) { if (touchClients[i]->client->sess.playerType == PC_MEDIC) { healvalue = MIN((int)(touchClients[i]->client->ps.stats[STAT_MAX_HEALTH] * 1.12) - touchClients[i]->health, self->damage); } else { healvalue = MIN(touchClients[i]->client->ps.stats[STAT_MAX_HEALTH] - touchClients[i]->health, self->damage); } if (self->health != -9999) { healvalue = MIN(healvalue, self->health); } if (healvalue <= 0) { continue; } touchClients[i]->health += healvalue; // add the medicheal event (to get sound, etc.) G_AddPredictableEvent(other, EV_ITEM_PICKUP, BG_GetItem(ITEM_HEALTH_CABINET) - bg_itemlist); if (self->health != -9999) { self->health -= healvalue; } } }
/* =========== 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, gentity_t *spawn, vec3_t origin, vec3_t angles ) { 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 = NULL, *event; int flags; int savedPing; int teamLocal; int eventSequence; char userinfo[ MAX_INFO_STRING ]; vec3_t up = { 0.0f, 0.0f, 1.0f }, implant_dir, implant_angles, spawnPoint_velocity; int maxAmmo, maxClips; weapon_t weapon; qboolean fromImplant = qfalse, hatchingFailed = qfalse; index = ent - g_entities; client = ent->client; teamLocal = client->pers.teamSelection; //if client is dead and following teammate, stop following before spawning if( client->sess.spectatorClient != -1 ) { client->sess.spectatorClient = -1; client->sess.spectatorState = SPECTATOR_FREE; } // only start client if chosen a class and joined a team if( client->pers.classSelection == PCL_NONE && teamLocal == TEAM_NONE ) client->sess.spectatorState = SPECTATOR_FREE; else if( client->pers.classSelection == PCL_NONE ) client->sess.spectatorState = SPECTATOR_LOCKED; // if client is dead and following teammate, stop following before spawning if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) G_StopFollowing( ent ); if( origin != NULL ) VectorCopy( origin, spawn_origin ); if( angles != NULL ) VectorCopy( angles, spawn_angles ); // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if( client->sess.spectatorState != SPECTATOR_NOT ) { if( teamLocal == TEAM_NONE ) spawnPoint = G_SelectSpectatorSpawnPoint( spawn_origin, spawn_angles ); else if( teamLocal == TEAM_ALIENS ) spawnPoint = G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles ); else if( teamLocal == TEAM_HUMANS ) spawnPoint = G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles ); } else { if( spawn == NULL ) { G_Error( "ClientSpawn: spawn is NULL\n" ); return; } spawnPoint = spawn; if( ent != spawn ) { if( !spawnPoint->client ) //might be a human { //start spawn animation on spawnPoint G_SetBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue ); if( spawnPoint->buildableTeam == TEAM_ALIENS ) spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME; else if( spawnPoint->buildableTeam == TEAM_HUMANS ) spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME; } else { qboolean crouch; int i; float zoffs = 0.0f; trace_t tr; vec3_t neworigin, mins, maxs; fromImplant = qtrue; //spawning from a human // move the origin a bit on the Z axis so the aliens jumps out of the chest, not knees // also prevents grangers from getting stuck in ceilings and floors crouch = spawnPoint->client->ps.pm_flags & PMF_DUCKED; switch( client->pers.classSelection ) { case PCL_ALIEN_BUILDER0: if( !crouch ) zoffs = 19.0f; else zoffs = -4.0f; break; case PCL_ALIEN_BUILDER0_UPG: if( !crouch ) zoffs = 16.5f; else zoffs = -4.0f; break; case PCL_ALIEN_LEVEL0: if( !crouch ) zoffs = 15.0f; else zoffs = -9.1f; break; } spawn_origin[ 2 ] += zoffs; // check if the spot would block BG_ClassBoundingBox( client->pers.classSelection, mins, maxs, NULL, NULL, NULL ); trap_Trace( &tr, spawn_origin, mins, maxs, spawn_origin, spawnPoint->s.number, MASK_PLAYERSOLID ); // try to unblock the player if( tr.startsolid ) { Com_Printf("DEBUG: player is stuck!\n"); for( i = 0; i < 16*2; i++ ) { float a, r; VectorCopy( spawn_origin, neworigin ); a = (float)i / 16.0f * 2.0f * M_PI; #define fmod(a,n) ((a)-(n)*floor((a)/(n))) r = ( i < 16 ? 5.5f : 11.0f ) * 1.0f / cos( fmod( a+0.25f*M_PI, 0.5f*M_PI ) - 0.25f*M_PI ); neworigin[ 0 ] += cos( a ) * r; neworigin[ 1 ] += sin( a ) * r; trap_Trace( &tr, neworigin, mins, maxs, neworigin, spawnPoint->s.number, MASK_PLAYERSOLID ); if( !tr.startsolid ) { Com_Printf("DEBUG: player position fixed at iteration %i\n",i); VectorCopy( neworigin, spawn_origin ); break; } } } //reward the player that implanted this one if( spawnPoint->client->impregnatedBy >= 0 ) { gentity_t *granger; granger = &g_entities[ spawnPoint->client->impregnatedBy ]; G_AddCreditToClient( granger->client, ALIEN_IMPREGNATION_REWARD, qtrue ); AddScore( granger, ALIEN_IMPREGNATION_REWARD_SCORE ); } // kill the human, set up angles and velocity for the new alien if( !BG_InventoryContainsUpgrade( UP_BATTLESUIT, spawnPoint->client->ps.stats ) //humans without battlesuits always die || spawnPoint->client->ps.stats[ STAT_HEALTH ] < ALIEN_HATCHING_MAX_BATTLESUIT_HEALTH ) //battlesuits survive if high hp { //save viewangles and spawn velocity for velocity calculation VectorCopy( spawnPoint->client->ps.viewangles, implant_angles ); AngleVectors( implant_angles, implant_dir, NULL, NULL ); VectorCopy( spawnPoint->client->ps.velocity, spawnPoint_velocity ); //fire a nice chest exploding effect event = G_TempEntity( spawnPoint->s.pos.trBase, EV_ALIEN_HATCH ); VectorCopy( implant_dir, event->s.angles ); //kill the player G_Damage( spawnPoint, NULL, ent, NULL, NULL, spawnPoint->client->ps.stats[ STAT_HEALTH ], DAMAGE_NO_ARMOR, MOD_ALIEN_HATCH ); } else //human survives { //clear impregnation so the human won't explode again spawnPoint->client->isImpregnated = qfalse; spawnPoint->client->isImplantMature = qfalse; //make a sound event = G_TempEntity( spawnPoint->s.pos.trBase, EV_ALIEN_HATCH_FAILURE ); //damage the human G_Damage( spawnPoint, NULL, ent, NULL, NULL, ALIEN_FAILED_HATCH_DAMAGE, DAMAGE_NO_ARMOR, MOD_ALIEN_HATCH ); //kill the newly spawned alien VectorCopy( spawnPoint->client->ps.viewangles, implant_angles ); implant_dir[0] = 0.0f; implant_dir[1] = 0.0f; implant_dir[2] = 0.0f; hatchingFailed = qtrue; } } } } // toggle the teleport bit so the client knows to not lerp flags = ( ent->client->ps.eFlags & EF_TELEPORT_BIT ) ^ EF_TELEPORT_BIT; G_UnlaggedClear( ent ); // clear everything but the persistant data saved = client->pers; savedSess = client->sess; savedPing = client->ps.ping; for( i = 0; i < MAX_PERSISTANT; i++ ) persistant[ i ] = client->ps.persistant[ i ]; eventSequence = client->ps.eventSequence; memset( client, 0, sizeof( *client ) ); client->pers = saved; client->sess = savedSess; client->ps.ping = savedPing; 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_SPECSTATE ] = client->sess.spectatorState; client->airOutTime = level.time + 12000; trap_GetUserinfo( index, userinfo, sizeof( userinfo ) ); client->ps.eFlags = flags; //Com_Printf( "ent->client->pers->pclass = %i\n", ent->client->pers.classSelection ); 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; // calculate each client's acceleration ent->evaluateAcceleration = qtrue; client->ps.stats[ STAT_MISC ] = 0; client->buildTimer = 0; client->ps.eFlags = flags; client->ps.clientNum = index; BG_ClassBoundingBox( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, NULL, NULL, NULL ); if( client->sess.spectatorState == SPECTATOR_NOT ) client->ps.stats[ STAT_MAX_HEALTH ] = BG_Class( ent->client->pers.classSelection )->health; else client->ps.stats[ STAT_MAX_HEALTH ] = 100; // clear entity values if( ent->client->pers.classSelection == PCL_HUMAN ) { BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats ); weapon = client->pers.humanItemSelection; } else if( client->sess.spectatorState == SPECTATOR_NOT ) weapon = BG_Class( ent->client->pers.classSelection )->startWeapon; else weapon = WP_NONE; maxAmmo = BG_Weapon( weapon )->maxAmmo; maxClips = BG_Weapon( weapon )->maxClips; client->ps.stats[ STAT_WEAPON ] = weapon; client->ps.ammo = maxAmmo; client->ps.clips = maxClips; // We just spawned, not changing weapons client->ps.persistant[ PERS_NEWWEAPON ] = 0; ent->client->ps.stats[ STAT_CLASS ] = ent->client->pers.classSelection; ent->client->ps.stats[ STAT_TEAM ] = ent->client->pers.teamSelection; ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE; ent->client->ps.stats[ STAT_STATE ] = 0; VectorSet( ent->client->ps.grapplePoint, 0.0f, 0.0f, 1.0f ); // health will count down towards max_health ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25; //if evolving scale health if( ent == spawn ) { ent->health *= ent->client->pers.evolveHealthFraction; client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction; } //clear the credits array for( i = 0; i < MAX_CLIENTS; i++ ) ent->credits[ i ] = 0; client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX; //never impregnated after respawning client->isImpregnated = qfalse; client->isImplantMature = qfalse; G_SetOrigin( ent, spawn_origin ); VectorCopy( spawn_origin, client->ps.origin ); #define UP_VEL 150.0f #define F_VEL 50.0f //give aliens some spawn velocity if( client->sess.spectatorState == SPECTATOR_NOT && client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) { if( ent == spawn ) { //evolution particle system G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) ); } else if( !fromImplant ) //regular egg { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); if( spawnPoint->s.origin2[ 2 ] > 0.0f ) { vec3_t forward, dir; AngleVectors( spawn_angles, forward, NULL, NULL ); VectorScale( forward, F_VEL, forward ); VectorAdd( spawnPoint->s.origin2, forward, dir ); VectorNormalize( dir ); VectorScale( dir, UP_VEL, client->ps.velocity ); } G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 ); } else //implanted egg { VectorCopy( implant_angles, spawn_angles ); VectorScale( implant_dir, ALIEN_HATCHING_VELOCITY, client->ps.velocity ); VectorAdd( client->ps.velocity, spawnPoint_velocity, client->ps.velocity ); } } else if( client->sess.spectatorState == SPECTATOR_NOT && client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); } // 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 ); G_SetClientViewAngle( ent, spawn_angles ); if( client->sess.spectatorState == SPECTATOR_NOT ) { trap_LinkEntity( ent ); // force the base weapon up if( client->pers.teamSelection == TEAM_HUMANS ) G_ForceWeaponChange( ent, weapon ); client->ps.weaponstate = WEAPON_READY; } // 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; ent->nextRegenTime = 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 ) MoveClientToIntermission( ent ); else { // fire the targets of the spawn point if( !spawn ) 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( BG_InventoryContainsWeapon( i, client->ps.stats ) ) { client->ps.weapon = i; break; } } } client->lastRantBombTime = level.time; // 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( client->sess.spectatorState == SPECTATOR_NOT ) { BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); trap_LinkEntity( ent ); } // must do this here so the number of active clients is calculated CalculateRanks( ); // run the presend to set anything else ClientEndFrame( ent ); // clear entity state values BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); // kill him instantly after respawning if hatching failed if( fromImplant && hatchingFailed ) { VectorCopy( spawnPoint->client->ps.velocity, client->ps.velocity ); client->ps.stats[ STAT_HEALTH ] = ent->health = 0; player_die( ent, NULL, spawnPoint, 0, MOD_ALIEN_HATCH_FAILED ); } }
/* =============== Touch_Item =============== */ void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) { int respawn; if (!other->client) return; if (other->health < 1) return; // dead people can't pickup // RPG-X: Marcin: Press USE to pick up items. - 03/12/2008 if ( !(other->client->pers.cmd.buttons & BUTTON_USE) || other->client->pressedUse == qtrue) { return; } else { other->client->pressedUse = qtrue; } // If ghosted, then end the ghost-ness in favor of the pickup. //RPG-X: RedTechie - Keep ghost all the time /*if (other->client->ps.powerups[PW_GHOST] >= level.time) { other->client->ps.powerups[PW_GHOST] = 0; // Unghost the player. This }*/ // the same pickup rules are used for client side and server side if ( !BG_CanItemBeGrabbed( &ent->s, &other->client->ps, Max_Weapon(other->client->ps.weapon) ) && IsAdmin( other ) == qfalse ) { return; } numTotalDropped--; G_LogPrintf( "Item: %i %s\n", other->s.number, ent->item->classname ); // call the item-specific pickup function switch( ent->item->giType ) { case IT_WEAPON: respawn = Pickup_Weapon(ent, other); break; case IT_AMMO: respawn = Pickup_Ammo(ent, other); 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); break; 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 ( other->client->pers.predictItemPickup ) { 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) { gentity_t *te; te = G_TempEntity( ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP ); te->s.eventParm = ent->s.modelindex; // tell us which client fired off this global sound te->s.otherEntityNum = other->s.number; te->r.svFlags |= SVF_BROADCAST; } // fire item targets G_UseTargets (ent, other); if ( rpg_weaponsStay.integer == 1 && IsAdmin( ent->parent ) == qtrue && IsAdmin( other ) == qfalse ) { return; } if ( ent->item->giTag == WP_3 ) { Padd_Remove( ent ); } // 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. if (ent->item->giType==IT_WEAPON || ent->item->giType==IT_POWERUP) { ent->s.eFlags |= EF_ITEMPLACEHOLDER; } else { // this line used to prevent items that were picked up from being drawn, but we now want to draw the techy grid thing instead ent->s.eFlags |= EF_NODRAW; ent->r.svFlags |= SVF_NOCLIENT; } 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 ); }