dhewm3-sdk/d3xp/Item.cpp
dhewg afebd7e1e5 Untangle the epic precompiled.h mess
Don't include the lazy precompiled.h everywhere, only what's
required for the compilation unit.
platform.h needs to be included instead to provide all essential
defines and types.
All includes use the relative path to the neo or the game
specific root.
Move all idlib related includes from idlib/Lib.h to precompiled.h.
precompiled.h still exists for the MFC stuff in tools/.
Add some missing header guards.
2018-08-20 01:46:28 +02:00

2168 lines
51 KiB
C++

/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "sys/platform.h"
#include "renderer/RenderSystem.h"
#include "gamesys/SysCvar.h"
#include "Player.h"
#include "Fx.h"
#include "SmokeParticles.h"
#include "Item.h"
/*
===============================================================================
idItem
===============================================================================
*/
const idEventDef EV_DropToFloor( "<dropToFloor>" );
const idEventDef EV_RespawnItem( "respawn" );
const idEventDef EV_RespawnFx( "<respawnFx>" );
const idEventDef EV_GetPlayerPos( "<getplayerpos>" );
const idEventDef EV_HideObjective( "<hideobjective>", "e" );
const idEventDef EV_CamShot( "<camshot>" );
CLASS_DECLARATION( idEntity, idItem )
EVENT( EV_DropToFloor, idItem::Event_DropToFloor )
EVENT( EV_Touch, idItem::Event_Touch )
EVENT( EV_Activate, idItem::Event_Trigger )
EVENT( EV_RespawnItem, idItem::Event_Respawn )
EVENT( EV_RespawnFx, idItem::Event_RespawnFx )
END_CLASS
/*
================
idItem::idItem
================
*/
idItem::idItem() {
spin = false;
inView = false;
inViewTime = 0;
lastCycle = 0;
lastRenderViewTime = -1;
itemShellHandle = -1;
shellMaterial = NULL;
orgOrigin.Zero();
canPickUp = true;
fl.networkSync = true;
}
/*
================
idItem::~idItem
================
*/
idItem::~idItem() {
// remove the highlight shell
if ( itemShellHandle != -1 ) {
gameRenderWorld->FreeEntityDef( itemShellHandle );
}
}
/*
================
idItem::Save
================
*/
void idItem::Save( idSaveGame *savefile ) const {
savefile->WriteVec3( orgOrigin );
savefile->WriteBool( spin );
savefile->WriteBool( pulse );
savefile->WriteBool( canPickUp );
savefile->WriteMaterial( shellMaterial );
savefile->WriteBool( inView );
savefile->WriteInt( inViewTime );
savefile->WriteInt( lastCycle );
savefile->WriteInt( lastRenderViewTime );
}
/*
================
idItem::Restore
================
*/
void idItem::Restore( idRestoreGame *savefile ) {
savefile->ReadVec3( orgOrigin );
savefile->ReadBool( spin );
savefile->ReadBool( pulse );
savefile->ReadBool( canPickUp );
savefile->ReadMaterial( shellMaterial );
savefile->ReadBool( inView );
savefile->ReadInt( inViewTime );
savefile->ReadInt( lastCycle );
savefile->ReadInt( lastRenderViewTime );
itemShellHandle = -1;
}
/*
================
idItem::UpdateRenderEntity
================
*/
bool idItem::UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) const {
if ( lastRenderViewTime == renderView->time ) {
return false;
}
lastRenderViewTime = renderView->time;
// check for glow highlighting if near the center of the view
idVec3 dir = renderEntity->origin - renderView->vieworg;
dir.Normalize();
float d = dir * renderView->viewaxis[0];
// two second pulse cycle
float cycle = ( renderView->time - inViewTime ) / 2000.0f;
if ( d > 0.94f ) {
if ( !inView ) {
inView = true;
if ( cycle > lastCycle ) {
// restart at the beginning
inViewTime = renderView->time;
cycle = 0.0f;
}
}
} else {
if ( inView ) {
inView = false;
lastCycle = ceil( cycle );
}
}
// fade down after the last pulse finishes
if ( !inView && cycle > lastCycle ) {
renderEntity->shaderParms[4] = 0.0f;
} else {
// pulse up in 1/4 second
cycle -= (int)cycle;
if ( cycle < 0.1f ) {
renderEntity->shaderParms[4] = cycle * 10.0f;
} else if ( cycle < 0.2f ) {
renderEntity->shaderParms[4] = 1.0f;
} else if ( cycle < 0.3f ) {
renderEntity->shaderParms[4] = 1.0f - ( cycle - 0.2f ) * 10.0f;
} else {
// stay off between pulses
renderEntity->shaderParms[4] = 0.0f;
}
}
// update every single time this is in view
return true;
}
/*
================
idItem::ModelCallback
================
*/
bool idItem::ModelCallback( renderEntity_t *renderEntity, const renderView_t *renderView ) {
const idItem *ent;
// this may be triggered by a model trace or other non-view related source
if ( !renderView ) {
return false;
}
ent = static_cast<idItem *>(gameLocal.entities[ renderEntity->entityNum ]);
if ( !ent ) {
gameLocal.Error( "idItem::ModelCallback: callback with NULL game entity" );
}
return ent->UpdateRenderEntity( renderEntity, renderView );
}
/*
================
idItem::Think
================
*/
void idItem::Think( void ) {
if ( thinkFlags & TH_THINK ) {
if ( spin ) {
idAngles ang;
idVec3 org;
ang.pitch = ang.roll = 0.0f;
ang.yaw = ( gameLocal.time & 4095 ) * 360.0f / -4096.0f;
SetAngles( ang );
float scale = 0.005f + entityNumber * 0.00001f;
org = orgOrigin;
org.z += 4.0f + cos( ( gameLocal.time + 2000 ) * scale ) * 4.0f;
SetOrigin( org );
}
}
Present();
}
/*
================
idItem::Present
================
*/
void idItem::Present( void ) {
idEntity::Present();
if ( !fl.hidden && pulse ) {
// also add a highlight shell model
renderEntity_t shell;
shell = renderEntity;
// we will mess with shader parms when the item is in view
// to give the "item pulse" effect
shell.callback = idItem::ModelCallback;
shell.entityNum = entityNumber;
shell.customShader = shellMaterial;
if ( itemShellHandle == -1 ) {
itemShellHandle = gameRenderWorld->AddEntityDef( &shell );
} else {
gameRenderWorld->UpdateEntityDef( itemShellHandle, &shell );
}
}
}
/*
================
idItem::Spawn
================
*/
void idItem::Spawn( void ) {
idStr giveTo;
idEntity * ent;
float tsize;
if ( spawnArgs.GetBool( "dropToFloor" ) ) {
PostEventMS( &EV_DropToFloor, 0 );
}
if ( spawnArgs.GetFloat( "triggersize", "0", tsize ) ) {
GetPhysics()->GetClipModel()->LoadModel( idTraceModel( idBounds( vec3_origin ).Expand( tsize ) ) );
GetPhysics()->GetClipModel()->Link( gameLocal.clip );
}
if ( spawnArgs.GetBool( "start_off" ) ) {
GetPhysics()->SetContents( 0 );
Hide();
} else {
GetPhysics()->SetContents( CONTENTS_TRIGGER );
}
giveTo = spawnArgs.GetString( "owner" );
if ( giveTo.Length() ) {
ent = gameLocal.FindEntity( giveTo );
if ( !ent ) {
gameLocal.Error( "Item couldn't find owner '%s'", giveTo.c_str() );
}
PostEventMS( &EV_Touch, 0, ent, 0 );
}
#ifdef CTF
// idItemTeam does not rotate and bob
if ( spawnArgs.GetBool( "spin" ) || (gameLocal.isMultiplayer && !this->IsType( idItemTeam::Type ) ) ) {
spin = true;
BecomeActive( TH_THINK );
}
#else
if ( spawnArgs.GetBool( "spin" ) || gameLocal.isMultiplayer ) {
spin = true;
BecomeActive( TH_THINK );
}
#endif
//pulse = !spawnArgs.GetBool( "nopulse" );
//temp hack for tim
pulse = false;
orgOrigin = GetPhysics()->GetOrigin();
canPickUp = !( spawnArgs.GetBool( "triggerFirst" ) || spawnArgs.GetBool( "no_touch" ) );
inViewTime = -1000;
lastCycle = -1;
itemShellHandle = -1;
shellMaterial = declManager->FindMaterial( "itemHighlightShell" );
}
/*
================
idItem::GetAttributes
================
*/
void idItem::GetAttributes( idDict &attributes ) {
int i;
const idKeyValue *arg;
for( i = 0; i < spawnArgs.GetNumKeyVals(); i++ ) {
arg = spawnArgs.GetKeyVal( i );
if ( arg->GetKey().Left( 4 ) == "inv_" ) {
attributes.Set( arg->GetKey().Right( arg->GetKey().Length() - 4 ), arg->GetValue() );
}
}
}
/*
================
idItem::GiveToPlayer
================
*/
bool idItem::GiveToPlayer( idPlayer *player ) {
if ( player == NULL ) {
return false;
}
if ( spawnArgs.GetBool( "inv_carry" ) ) {
return player->GiveInventoryItem( &spawnArgs );
}
return player->GiveItem( this );
}
/*
================
idItem::Pickup
================
*/
bool idItem::Pickup( idPlayer *player ) {
if ( !GiveToPlayer( player ) ) {
return false;
}
if ( gameLocal.isServer ) {
ServerSendEvent( EVENT_PICKUP, NULL, false, -1 );
}
// play pickup sound
StartSound( "snd_acquire", SND_CHANNEL_ITEM, 0, false, NULL );
// trigger our targets
ActivateTargets( player );
// clear our contents so the object isn't picked up twice
GetPhysics()->SetContents( 0 );
// hide the model
Hide();
// add the highlight shell
if ( itemShellHandle != -1 ) {
gameRenderWorld->FreeEntityDef( itemShellHandle );
itemShellHandle = -1;
}
float respawn = spawnArgs.GetFloat( "respawn" );
bool dropped = spawnArgs.GetBool( "dropped" );
bool no_respawn = spawnArgs.GetBool( "no_respawn" );
if ( gameLocal.isMultiplayer && respawn == 0.0f ) {
respawn = 20.0f;
}
if ( respawn && !dropped && !no_respawn ) {
const char *sfx = spawnArgs.GetString( "fxRespawn" );
if ( sfx && *sfx ) {
PostEventSec( &EV_RespawnFx, respawn - 0.5f );
}
PostEventSec( &EV_RespawnItem, respawn );
} else if ( !spawnArgs.GetBool( "inv_objective" ) && !no_respawn ) {
// give some time for the pickup sound to play
// FIXME: Play on the owner
if ( !spawnArgs.GetBool( "inv_carry" ) ) {
PostEventMS( &EV_Remove, 5000 );
}
}
BecomeInactive( TH_THINK );
return true;
}
/*
================
idItem::ClientPredictionThink
================
*/
void idItem::ClientPredictionThink( void ) {
// only think forward because the state is not synced through snapshots
if ( !gameLocal.isNewFrame ) {
return;
}
Think();
}
/*
================
idItem::WriteFromSnapshot
================
*/
void idItem::WriteToSnapshot( idBitMsgDelta &msg ) const {
msg.WriteBits( IsHidden(), 1 );
}
/*
================
idItem::ReadFromSnapshot
================
*/
void idItem::ReadFromSnapshot( const idBitMsgDelta &msg ) {
if ( msg.ReadBits( 1 ) ) {
Hide();
} else {
Show();
}
}
/*
================
idItem::ClientReceiveEvent
================
*/
bool idItem::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
switch( event ) {
case EVENT_PICKUP: {
// play pickup sound
StartSound( "snd_acquire", SND_CHANNEL_ITEM, 0, false, NULL );
// hide the model
Hide();
// remove the highlight shell
if ( itemShellHandle != -1 ) {
gameRenderWorld->FreeEntityDef( itemShellHandle );
itemShellHandle = -1;
}
return true;
}
case EVENT_RESPAWN: {
Event_Respawn();
return true;
}
case EVENT_RESPAWNFX: {
Event_RespawnFx();
return true;
}
default: {
return idEntity::ClientReceiveEvent( event, time, msg );
}
}
return false;
}
/*
================
idItem::Event_DropToFloor
================
*/
void idItem::Event_DropToFloor( void ) {
trace_t trace;
// don't drop the floor if bound to another entity
if ( GetBindMaster() != NULL && GetBindMaster() != this ) {
return;
}
gameLocal.clip.TraceBounds( trace, renderEntity.origin, renderEntity.origin - idVec3( 0, 0, 64 ), renderEntity.bounds, MASK_SOLID | CONTENTS_CORPSE, this );
SetOrigin( trace.endpos );
}
/*
================
idItem::Event_Touch
================
*/
void idItem::Event_Touch( idEntity *other, trace_t *trace ) {
if ( !other->IsType( idPlayer::Type ) ) {
return;
}
if ( !canPickUp ) {
return;
}
Pickup( static_cast<idPlayer *>(other) );
}
/*
================
idItem::Event_Trigger
================
*/
void idItem::Event_Trigger( idEntity *activator ) {
if ( !canPickUp && spawnArgs.GetBool( "triggerFirst" ) ) {
canPickUp = true;
return;
}
if ( activator && activator->IsType( idPlayer::Type ) ) {
Pickup( static_cast<idPlayer *>( activator ) );
}
}
/*
================
idItem::Event_Respawn
================
*/
void idItem::Event_Respawn( void ) {
if ( gameLocal.isServer ) {
ServerSendEvent( EVENT_RESPAWN, NULL, false, -1 );
}
BecomeActive( TH_THINK );
Show();
inViewTime = -1000;
lastCycle = -1;
GetPhysics()->SetContents( CONTENTS_TRIGGER );
SetOrigin( orgOrigin );
StartSound( "snd_respawn", SND_CHANNEL_ITEM, 0, false, NULL );
CancelEvents( &EV_RespawnItem ); // don't double respawn
}
/*
================
idItem::Event_RespawnFx
================
*/
void idItem::Event_RespawnFx( void ) {
if ( gameLocal.isServer ) {
ServerSendEvent( EVENT_RESPAWNFX, NULL, false, -1 );
}
const char *sfx = spawnArgs.GetString( "fxRespawn" );
if ( sfx && *sfx ) {
idEntityFx::StartFx( sfx, NULL, NULL, this, true );
}
}
/*
===============================================================================
idItemPowerup
===============================================================================
*/
/*
===============
idItemPowerup
===============
*/
CLASS_DECLARATION( idItem, idItemPowerup )
END_CLASS
/*
================
idItemPowerup::idItemPowerup
================
*/
idItemPowerup::idItemPowerup() {
time = 0;
type = 0;
}
/*
================
idItemPowerup::Save
================
*/
void idItemPowerup::Save( idSaveGame *savefile ) const {
savefile->WriteInt( time );
savefile->WriteInt( type );
}
/*
================
idItemPowerup::Restore
================
*/
void idItemPowerup::Restore( idRestoreGame *savefile ) {
savefile->ReadInt( time );
savefile->ReadInt( type );
}
/*
================
idItemPowerup::Spawn
================
*/
void idItemPowerup::Spawn( void ) {
time = spawnArgs.GetInt( "time", "30" );
type = spawnArgs.GetInt( "type", "0" );
}
/*
================
idItemPowerup::GiveToPlayer
================
*/
bool idItemPowerup::GiveToPlayer( idPlayer *player ) {
if ( player->spectating ) {
return false;
}
player->GivePowerUp( type, time * 1000 );
return true;
}
#ifdef CTF
/*
===============================================================================
idItemTeam
Used for flags in Capture the Flag
===============================================================================
*/
// temporarely removed these events
const idEventDef EV_FlagReturn( "flagreturn", "e" );
const idEventDef EV_TakeFlag( "takeflag", "e" );
const idEventDef EV_DropFlag( "dropflag", "d" );
const idEventDef EV_FlagCapture( "flagcapture" );
CLASS_DECLARATION( idItem, idItemTeam )
EVENT( EV_FlagReturn, idItemTeam::Event_FlagReturn )
EVENT( EV_TakeFlag, idItemTeam::Event_TakeFlag )
EVENT( EV_DropFlag, idItemTeam::Event_DropFlag )
EVENT( EV_FlagCapture, idItemTeam::Event_FlagCapture )
END_CLASS
/*
===============
idItemTeam::idItemTeam
===============
*/
idItemTeam::idItemTeam() {
team = -1;
carried = false;
dropped = false;
lastDrop = 0;
itemGlowHandle = -1;
skinDefault = NULL;
skinCarried = NULL;
scriptTaken = NULL;
scriptDropped = NULL;
scriptReturned = NULL;
scriptCaptured = NULL;
lastNuggetDrop = 0;
nuggetName = 0;
}
/*
===============
idItemTeam::~idItemTeam
===============
*/
idItemTeam::~idItemTeam() {
FreeLightDef();
}
/*
===============
idItemTeam::Spawn
===============
*/
void idItemTeam::Spawn( void ) {
team = spawnArgs.GetInt( "team" );
returnOrigin = GetPhysics()->GetOrigin() + idVec3( 0, 0, 20 );
returnAxis = GetPhysics()->GetAxis();
BecomeActive( TH_THINK );
const char * skinName;
skinName = spawnArgs.GetString( "skin", "" );
if ( skinName[0] )
skinDefault = declManager->FindSkin( skinName );
skinName = spawnArgs.GetString( "skin_carried", "" );
if ( skinName[0] )
skinCarried = declManager->FindSkin( skinName );
nuggetName = spawnArgs.GetString( "nugget_name", "" );
if ( !nuggetName[0] ) {
nuggetName = NULL;
}
scriptTaken = LoadScript( "script_taken" );
scriptDropped = LoadScript( "script_dropped" );
scriptReturned = LoadScript( "script_returned" );
scriptCaptured = LoadScript( "script_captured" );
/* Spawn attached dlight */
/*
idDict args;
idVec3 lightOffset( 0.0f, 20.0f, 0.0f );
// Set up the flag's dynamic light
memset( &itemGlow, 0, sizeof( itemGlow ) );
itemGlow.axis = mat3_identity;
itemGlow.lightRadius.x = 128.0f;
itemGlow.lightRadius.y = itemGlow.lightRadius.z = itemGlow.lightRadius.x;
itemGlow.noShadows = true;
itemGlow.pointLight = true;
itemGlow.shaderParms[ SHADERPARM_RED ] = 0.0f;
itemGlow.shaderParms[ SHADERPARM_GREEN ] = 0.0f;
itemGlow.shaderParms[ SHADERPARM_BLUE ] = 0.0f;
itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 0.0f;
// Select a shader based on the team
if ( team == 0 )
itemGlow.shader = declManager->FindMaterial( "lights/redflag" );
else
itemGlow.shader = declManager->FindMaterial( "lights/blueflag" );
*/
idMoveableItem::Spawn();
physicsObj.SetContents( 0 );
physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP );
physicsObj.SetGravity( idVec3( 0, 0, spawnArgs.GetInt("gravity", "-30" ) ) );
}
/*
===============
idItemTeam::LoadScript
===============
*/
function_t * idItemTeam::LoadScript( const char * script ) {
function_t * function = NULL;
idStr funcname = spawnArgs.GetString( script, "" );
if ( funcname.Length() ) {
function = gameLocal.program.FindFunction( funcname );
if ( function == NULL ) {
#ifdef _DEBUG
gameLocal.Warning( "idItemTeam '%s' at (%s) calls unknown function '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() );
#endif
}
}
return function;
}
/*
===============
idItemTeam::Think
===============
*/
void idItemTeam::Think( void ) {
idMoveableItem::Think();
TouchTriggers();
// TODO : only update on updatevisuals
/*idVec3 offset( 0.0f, 0.0f, 20.0f );
itemGlow.origin = GetPhysics()->GetOrigin() + offset;
if ( itemGlowHandle == -1 ) {
itemGlowHandle = gameRenderWorld->AddLightDef( &itemGlow );
} else {
gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );
}*/
#if 1
// should only the server do this?
if ( gameLocal.isServer && nuggetName && carried && ( !lastNuggetDrop || (gameLocal.time - lastNuggetDrop) > spawnArgs.GetInt("nugget_frequency") ) ) {
SpawnNugget( GetPhysics()->GetOrigin() );
lastNuggetDrop = gameLocal.time;
}
#endif
// return dropped flag after si_flagDropTimeLimit seconds
if ( dropped && !carried && lastDrop != 0 && (gameLocal.time - lastDrop) > ( si_flagDropTimeLimit.GetInteger()*1000 ) ) {
Return(); // return flag after 30 seconds on ground
return;
}
}
/*
===============
idItemTeam::Pickup
===============
*/
bool idItemTeam::Pickup( idPlayer *player ) {
if ( !gameLocal.mpGame.IsGametypeFlagBased() ) /* CTF */
return false;
if ( gameLocal.mpGame.GetGameState() == idMultiplayerGame::WARMUP ||
gameLocal.mpGame.GetGameState() == idMultiplayerGame::COUNTDOWN )
return false;
// wait 2 seconds after drop before beeing picked up again
if ( lastDrop != 0 && (gameLocal.time - lastDrop) < spawnArgs.GetInt("pickupDelay", "500") )
return false;
if ( carried == false && player->team != this->team ) {
PostEventMS( &EV_TakeFlag, 0, player );
return true;
} else if ( carried == false && dropped == true && player->team == this->team ) {
gameLocal.mpGame.PlayerScoreCTF( player->entityNumber, 5 );
// return flag
PostEventMS( &EV_FlagReturn, 0, player );
return false;
}
return false;
}
/*
===============
idItemTeam::ClientReceiveEvent
===============
*/
bool idItemTeam::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
gameLocal.DPrintf("ClientRecieveEvent: %i\n", event );
switch ( event ) {
case EVENT_TAKEFLAG: {
idPlayer * player = static_cast<idPlayer *>(gameLocal.entities[ msg.ReadBits( GENTITYNUM_BITS ) ]);
if ( player == NULL ) {
gameLocal.Warning( "NULL player takes flag?\n" );
return false;
}
Event_TakeFlag( player );
}
return true;
case EVENT_DROPFLAG : {
bool death = bool( msg.ReadBits( 1 ) == 1 );
Event_DropFlag( death );
}
return true;
case EVENT_FLAGRETURN : {
Hide();
FreeModelDef();
FreeLightDef();
Event_FlagReturn();
}
return true;
case EVENT_FLAGCAPTURE : {
Hide();
FreeModelDef();
FreeLightDef();
Event_FlagCapture();
}
return true;
};
return false;
}
/*
================
idItemTeam::Drop
================
*/
void idItemTeam::Drop( bool death )
{
// PostEventMS( &EV_DropFlag, 0, int(death == true) );
// had to remove the delayed drop because of drop flag on disconnect
Event_DropFlag( death );
}
/*
================
idItemTeam::Return
================
*/
void idItemTeam::Return( idPlayer * player )
{
if ( team != 0 && team != 1 )
return;
// PostEventMS( &EV_FlagReturn, 0 );
Event_FlagReturn();
}
/*
================
idItemTeam::Capture
================
*/
void idItemTeam::Capture( void )
{
if ( team != 0 && team != 1 )
return;
PostEventMS( &EV_FlagCapture, 0 );
}
/*
================
idItemTeam::PrivateReturn
================
*/
void idItemTeam::PrivateReturn( void )
{
Unbind();
if ( gameLocal.isServer && carried && !dropped ) {
int playerIdx = gameLocal.mpGame.GetFlagCarrier( 1-team );
if ( playerIdx != -1 ) {
idPlayer * player = static_cast<idPlayer*>( gameLocal.entities[ playerIdx ] );
player->carryingFlag = false;
} else {
gameLocal.Warning( "BUG: carried flag has no carrier before return" );
}
}
dropped = false;
carried = false;
SetOrigin( returnOrigin );
SetAxis( returnAxis );
trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), mat3_identity );
SetSkin( skinDefault );
// Turn off the light
/*itemGlow.shaderParms[ SHADERPARM_RED ] = 0.0f;
itemGlow.shaderParms[ SHADERPARM_GREEN ] = 0.0f;
itemGlow.shaderParms[ SHADERPARM_BLUE ] = 0.0f;
itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 0.0f;
if ( itemGlowHandle != -1 )
gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );*/
GetPhysics()->SetLinearVelocity( idVec3(0, 0, 0) );
GetPhysics()->SetAngularVelocity( idVec3(0, 0, 0) );
}
/*
================
idItemTeam::Event_TakeFlag
================
*/
void idItemTeam::Event_TakeFlag( idPlayer * player ) {
gameLocal.DPrintf("Event_TakeFlag()!\n");
if ( gameLocal.isServer ) {
idBitMsg msg;
byte msgBuf[MAX_EVENT_PARAM_SIZE];
// Send the event
msg.Init( msgBuf, sizeof( msgBuf ) );
msg.BeginWriting();
msg.WriteBits( player->entityNumber, GENTITYNUM_BITS );
ServerSendEvent( EVENT_TAKEFLAG, &msg, false, -1 );
gameLocal.mpGame.PlayTeamSound( player->team, SND_FLAG_TAKEN_THEIRS );
gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_TAKEN_YOURS );
gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGTAKEN, team, player->entityNumber );
// dont drop a nugget RIGHT away
lastNuggetDrop = gameLocal.time - gameLocal.random.RandomInt( 1000 );
}
BindToJoint( player, g_flagAttachJoint.GetString(), true );
idVec3 origin( g_flagAttachOffsetX.GetFloat(), g_flagAttachOffsetY.GetFloat(), g_flagAttachOffsetZ.GetFloat() );
idAngles angle( g_flagAttachAngleX.GetFloat(), g_flagAttachAngleY.GetFloat(), g_flagAttachAngleZ.GetFloat() );
SetAngles( angle );
SetOrigin( origin );
// Turn the light on
/*itemGlow.shaderParms[ SHADERPARM_RED ] = 1.0f;
itemGlow.shaderParms[ SHADERPARM_GREEN ] = 1.0f;
itemGlow.shaderParms[ SHADERPARM_BLUE ] = 1.0f;
itemGlow.shaderParms[ SHADERPARM_ALPHA ] = 1.0f;
if ( itemGlowHandle != -1 )
gameRenderWorld->UpdateLightDef( itemGlowHandle, &itemGlow );*/
if ( scriptTaken ) {
idThread *thread = new idThread();
thread->CallFunction( scriptTaken, false );
thread->DelayedStart( 0 );
}
dropped = false;
carried = true;
player->carryingFlag = true;
SetSkin( skinCarried );
UpdateVisuals();
UpdateGuis();
if ( gameLocal.isServer ) {
if ( team == 0 )
gameLocal.mpGame.player_red_flag = player->entityNumber;
else
gameLocal.mpGame.player_blue_flag = player->entityNumber;
}
}
/*
================
idItemTeam::Event_DropFlag
================
*/
void idItemTeam::Event_DropFlag( bool death ) {
gameLocal.DPrintf("Event_DropFlag()!\n");
if ( gameLocal.isServer ) {
idBitMsg msg;
byte msgBuf[MAX_EVENT_PARAM_SIZE];
// Send the event
msg.Init( msgBuf, sizeof( msgBuf ) );
msg.BeginWriting();
msg.WriteBits( death, 1 );
ServerSendEvent( EVENT_DROPFLAG, &msg, false, -1 );
if ( gameLocal.mpGame.IsFlagMsgOn() ) {
gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_DROPPED_THEIRS );
gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_DROPPED_YOURS );
gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGDROP, team );
}
}
lastDrop = gameLocal.time;
BecomeActive( TH_THINK );
Show();
if ( death )
GetPhysics()->SetLinearVelocity( idVec3(0, 0, 0) );
else
GetPhysics()->SetLinearVelocity( idVec3(0, 0, 20) );
GetPhysics()->SetAngularVelocity( idVec3(0, 0, 0) );
// GetPhysics()->SetLinearVelocity( ( GetPhysics()->GetLinearVelocity() * GetBindMaster()->GetPhysics()->GetAxis() ) + GetBindMaster()->GetPhysics()->GetLinearVelocity() );
if ( GetBindMaster() ) {
const idBounds bounds = GetPhysics()->GetBounds();
idVec3 origin = GetBindMaster()->GetPhysics()->GetOrigin() + idVec3(0, 0, ( bounds[1].z-bounds[0].z )*0.6f );
Unbind();
SetOrigin( origin );
}
idAngles angle = GetPhysics()->GetAxis().ToAngles();
angle.roll = 0;
angle.pitch = 0;
SetAxis( angle.ToMat3() );
dropped = true;
carried = false;
if ( scriptDropped ) {
idThread *thread = new idThread();
thread->CallFunction( scriptDropped, false );
thread->DelayedStart( 0 );
}
SetSkin( skinDefault );
UpdateVisuals();
UpdateGuis();
if ( gameLocal.isServer ) {
if ( team == 0 )
gameLocal.mpGame.player_red_flag = -1;
else
gameLocal.mpGame.player_blue_flag = -1;
}
}
/*
================
idItemTeam::Event_FlagReturn
================
*/
void idItemTeam::Event_FlagReturn( idPlayer * player ) {
gameLocal.DPrintf("Event_FlagReturn()!\n");
if ( gameLocal.isServer ) {
ServerSendEvent( EVENT_FLAGRETURN, NULL, false, -1 );
if ( gameLocal.mpGame.IsFlagMsgOn() ) {
gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_RETURN );
gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_RETURN );
int entitynum = 255;
if ( player ) {
entitynum = player->entityNumber;
}
gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGRETURN, team, entitynum );
}
}
BecomeActive( TH_THINK );
Show();
PrivateReturn();
if ( scriptReturned ) {
idThread *thread = new idThread();
thread->CallFunction( scriptReturned, false );
thread->DelayedStart( 0 );
}
UpdateVisuals();
UpdateGuis();
// Present();
if ( gameLocal.isServer ) {
if ( team == 0 )
gameLocal.mpGame.player_red_flag = -1;
else
gameLocal.mpGame.player_blue_flag = -1;
}
}
/*
================
idItemTeam::Event_FlagCapture
================
*/
void idItemTeam::Event_FlagCapture( void ) {
gameLocal.DPrintf("Event_FlagCapture()!\n");
if ( gameLocal.isServer ) {
ServerSendEvent( EVENT_FLAGCAPTURE, NULL, false, -1 );
gameLocal.mpGame.PlayTeamSound( 1-team, SND_FLAG_CAPTURED_THEIRS );
gameLocal.mpGame.PlayTeamSound( team, SND_FLAG_CAPTURED_YOURS );
gameLocal.mpGame.TeamScoreCTF( 1-team, 1 );
int playerIdx = gameLocal.mpGame.GetFlagCarrier( 1-team );
if ( playerIdx != -1 ) {
gameLocal.mpGame.PlayerScoreCTF( playerIdx, 10 );
} else {
playerIdx = 255;
}
gameLocal.mpGame.PrintMessageEvent( -1, idMultiplayerGame::MSG_FLAGCAPTURE, team, playerIdx );
}
BecomeActive( TH_THINK );
Show();
PrivateReturn();
if ( scriptCaptured ) {
idThread *thread = new idThread();
thread->CallFunction( scriptCaptured, false );
thread->DelayedStart( 0 );
}
UpdateVisuals();
UpdateGuis();
if ( gameLocal.isServer ) {
if ( team == 0 )
gameLocal.mpGame.player_red_flag = -1;
else
gameLocal.mpGame.player_blue_flag = -1;
}
}
/*
================
idItemTeam::FreeLightDef
================
*/
void idItemTeam::FreeLightDef( void ) {
if ( itemGlowHandle != -1 ) {
gameRenderWorld->FreeLightDef( itemGlowHandle );
itemGlowHandle = -1;
}
}
/*
================
idItemTeam::SpawnNugget
================
*/
void idItemTeam::SpawnNugget( idVec3 pos ) {
idAngles angle( gameLocal.random.RandomInt(spawnArgs.GetInt("nugget_pitch", "30")), gameLocal.random.RandomInt(spawnArgs.GetInt("nugget_yaw", "360" )), 0 );
float velocity = float(gameLocal.random.RandomInt( 40 )+15);
velocity *= spawnArgs.GetFloat("nugget_velocity", "1" );
idEntity * ent = idMoveableItem::DropItem( nuggetName, pos, GetPhysics()->GetAxis(), angle.ToMat3()*idVec3(velocity, velocity, velocity), 0, spawnArgs.GetInt("nugget_removedelay") );
idPhysics_RigidBody * physics = static_cast<idPhysics_RigidBody *>( ent->GetPhysics() );
if ( physics && physics->IsType( idPhysics_RigidBody::Type ) ) {
physics->DisableImpact();
}
}
/*
================
idItemTeam::Event_FlagCapture
================
*/
void idItemTeam::WriteToSnapshot( idBitMsgDelta &msg ) const {
msg.WriteBits( carried, 1 );
msg.WriteBits( dropped, 1 );
WriteBindToSnapshot( msg );
idMoveableItem::WriteToSnapshot( msg );
}
/*
================
idItemTeam::ReadFromSnapshot
================
*/
void idItemTeam::ReadFromSnapshot( const idBitMsgDelta &msg ) {
carried = msg.ReadBits( 1 ) == 1;
dropped = msg.ReadBits( 1 ) == 1;
ReadBindFromSnapshot( msg );
if ( msg.HasChanged() )
{
UpdateGuis();
if ( carried == true )
SetSkin( skinCarried );
else
SetSkin( skinDefault );
}
idMoveableItem::ReadFromSnapshot( msg );
}
/*
================
idItemTeam::UpdateGuis
Update all client's huds wrt the flag status.
================
*/
void idItemTeam::UpdateGuis( void ) {
idPlayer *player;
for ( int i = 0; i < gameLocal.numClients; i++ ) {
player = static_cast<idPlayer *>( gameLocal.entities[ i ] );
if ( player == NULL || player->hud == NULL )
continue;
player->hud->SetStateInt( "red_flagstatus", gameLocal.mpGame.GetFlagStatus( 0 ) );
player->hud->SetStateInt( "blue_flagstatus", gameLocal.mpGame.GetFlagStatus( 1 ) );
player->hud->SetStateInt( "red_team_score", gameLocal.mpGame.GetFlagPoints( 0 ) );
player->hud->SetStateInt( "blue_team_score", gameLocal.mpGame.GetFlagPoints( 1 ) );
}
}
/*
================
idItemTeam::Present
================
*/
void idItemTeam::Present( void ) {
// hide the flag for localplayer if in first person
if ( carried && GetBindMaster() ) {
idPlayer * player = static_cast<idPlayer *>( GetBindMaster() );
if ( player == gameLocal.GetLocalPlayer() && !pm_thirdPerson.GetBool() ) {
FreeModelDef();
BecomeActive( TH_UPDATEVISUALS );
return;
}
}
idEntity::Present();
}
#endif
/*
===============================================================================
idObjective
===============================================================================
*/
CLASS_DECLARATION( idItem, idObjective )
EVENT( EV_Activate, idObjective::Event_Trigger )
EVENT( EV_HideObjective, idObjective::Event_HideObjective )
EVENT( EV_GetPlayerPos, idObjective::Event_GetPlayerPos )
EVENT( EV_CamShot, idObjective::Event_CamShot )
END_CLASS
/*
================
idObjective::idObjective
================
*/
idObjective::idObjective() {
playerPos.Zero();
}
/*
================
idObjective::Save
================
*/
void idObjective::Save( idSaveGame *savefile ) const {
savefile->WriteVec3( playerPos );
}
/*
================
idObjective::Restore
================
*/
void idObjective::Restore( idRestoreGame *savefile ) {
savefile->ReadVec3( playerPos );
}
/*
================
idObjective::Spawn
================
*/
void idObjective::Spawn( void ) {
Hide();
if ( cvarSystem->GetCVarBool( "com_makingBuild") ) {
PostEventMS( &EV_CamShot, 250 );
}
}
/*
================
idObjective::Event_Screenshot
================
*/
void idObjective::Event_CamShot( ) {
const char *camName;
idStr shotName = gameLocal.GetMapName();
shotName.StripFileExtension();
shotName += "/";
shotName += spawnArgs.GetString( "screenshot" );
shotName.SetFileExtension( ".tga" );
if ( spawnArgs.GetString( "camShot", "", &camName ) ) {
idEntity *ent = gameLocal.FindEntity( camName );
if ( ent && ent->cameraTarget ) {
const renderView_t *view = ent->cameraTarget->GetRenderView();
renderView_t fullView = *view;
fullView.width = SCREEN_WIDTH;
fullView.height = SCREEN_HEIGHT;
#ifdef _D3XP
// HACK : always draw sky-portal view if there is one in the map, this isn't real-time
if ( gameLocal.portalSkyEnt.GetEntity() && g_enablePortalSky.GetBool() ) {
renderView_t portalView = fullView;
portalView.vieworg = gameLocal.portalSkyEnt.GetEntity()->GetPhysics()->GetOrigin();
// setup global fixup projection vars
if ( 1 ) {
int vidWidth, vidHeight;
idVec2 shiftScale;
renderSystem->GetGLSettings( vidWidth, vidHeight );
float pot;
int temp;
int w = vidWidth;
for (temp = 1 ; temp < w ; temp<<=1) {
}
pot = (float)temp;
shiftScale.x = (float)w / pot;
int h = vidHeight;
for (temp = 1 ; temp < h ; temp<<=1) {
}
pot = (float)temp;
shiftScale.y = (float)h / pot;
fullView.shaderParms[4] = shiftScale.x;
fullView.shaderParms[5] = shiftScale.y;
}
gameRenderWorld->RenderScene( &portalView );
renderSystem->CaptureRenderToImage( "_currentRender" );
}
#endif
// draw a view to a texture
renderSystem->CropRenderSize( 256, 256, true );
gameRenderWorld->RenderScene( &fullView );
renderSystem->CaptureRenderToFile( shotName );
renderSystem->UnCrop();
}
}
}
/*
================
idObjective::Event_Trigger
================
*/
void idObjective::Event_Trigger( idEntity *activator ) {
idPlayer *player = gameLocal.GetLocalPlayer();
if ( player ) {
//Pickup( player );
if ( spawnArgs.GetString( "inv_objective", NULL ) ) {
if ( player && player->hud ) {
idStr shotName = gameLocal.GetMapName();
shotName.StripFileExtension();
shotName += "/";
shotName += spawnArgs.GetString( "screenshot" );
shotName.SetFileExtension( ".tga" );
player->hud->SetStateString( "screenshot", shotName );
player->hud->SetStateString( "objective", "1" );
player->hud->SetStateString( "objectivetext", spawnArgs.GetString( "objectivetext" ) );
player->hud->SetStateString( "objectivetitle", spawnArgs.GetString( "objectivetitle" ) );
player->GiveObjective( spawnArgs.GetString( "objectivetitle" ), spawnArgs.GetString( "objectivetext" ), shotName );
// a tad slow but keeps from having to update all objectives in all maps with a name ptr
for( int i = 0; i < gameLocal.num_entities; i++ ) {
if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idObjectiveComplete::Type ) ) {
if ( idStr::Icmp( spawnArgs.GetString( "objectivetitle" ), gameLocal.entities[ i ]->spawnArgs.GetString( "objectivetitle" ) ) == 0 ){
gameLocal.entities[ i ]->spawnArgs.SetBool( "objEnabled", true );
break;
}
}
}
PostEventMS( &EV_GetPlayerPos, 2000 );
}
}
}
}
/*
================
idObjective::Event_GetPlayerPos
================
*/
void idObjective::Event_GetPlayerPos() {
idPlayer *player = gameLocal.GetLocalPlayer();
if ( player ) {
playerPos = player->GetPhysics()->GetOrigin();
PostEventMS( &EV_HideObjective, 100, player );
}
}
/*
================
idObjective::Event_HideObjective
================
*/
void idObjective::Event_HideObjective(idEntity *e) {
idPlayer *player = gameLocal.GetLocalPlayer();
if ( player ) {
idVec3 v = player->GetPhysics()->GetOrigin() - playerPos;
if ( v.Length() > 64.0f ) {
player->HideObjective();
PostEventMS( &EV_Remove, 0 );
} else {
PostEventMS( &EV_HideObjective, 100, player );
}
}
}
/*
===============================================================================
idVideoCDItem
===============================================================================
*/
CLASS_DECLARATION( idItem, idVideoCDItem )
END_CLASS
/*
================
idVideoCDItem::Spawn
================
*/
void idVideoCDItem::Spawn( void ) {
}
/*
================
idVideoCDItem::GiveToPlayer
================
*/
bool idVideoCDItem::GiveToPlayer( idPlayer *player ) {
idStr str = spawnArgs.GetString( "video" );
if ( player && str.Length() ) {
player->GiveVideo( str, &spawnArgs );
}
return true;
}
/*
===============================================================================
idPDAItem
===============================================================================
*/
CLASS_DECLARATION( idItem, idPDAItem )
END_CLASS
/*
================
idPDAItem::GiveToPlayer
================
*/
bool idPDAItem::GiveToPlayer(idPlayer *player) {
const char *str = spawnArgs.GetString( "pda_name" );
if ( player ) {
player->GivePDA( str, &spawnArgs );
}
return true;
}
/*
===============================================================================
idMoveableItem
===============================================================================
*/
CLASS_DECLARATION( idItem, idMoveableItem )
EVENT( EV_DropToFloor, idMoveableItem::Event_DropToFloor )
EVENT( EV_Gib, idMoveableItem::Event_Gib )
END_CLASS
/*
================
idMoveableItem::idMoveableItem
================
*/
idMoveableItem::idMoveableItem() {
trigger = NULL;
smoke = NULL;
smokeTime = 0;
#ifdef _D3XP
nextSoundTime = 0;
#endif
#ifdef CTF
repeatSmoke = false;
#endif
}
/*
================
idMoveableItem::~idMoveableItem
================
*/
idMoveableItem::~idMoveableItem() {
if ( trigger ) {
delete trigger;
}
}
/*
================
idMoveableItem::Save
================
*/
void idMoveableItem::Save( idSaveGame *savefile ) const {
savefile->WriteStaticObject( physicsObj );
savefile->WriteClipModel( trigger );
savefile->WriteParticle( smoke );
savefile->WriteInt( smokeTime );
#ifdef _D3XP
savefile->WriteInt( nextSoundTime );
#endif
}
/*
================
idMoveableItem::Restore
================
*/
void idMoveableItem::Restore( idRestoreGame *savefile ) {
savefile->ReadStaticObject( physicsObj );
RestorePhysics( &physicsObj );
savefile->ReadClipModel( trigger );
savefile->ReadParticle( smoke );
savefile->ReadInt( smokeTime );
#ifdef _D3XP
savefile->ReadInt( nextSoundTime );
#endif
}
/*
================
idMoveableItem::Spawn
================
*/
void idMoveableItem::Spawn( void ) {
idTraceModel trm;
float density, friction, bouncyness, tsize;
idStr clipModelName;
idBounds bounds;
#ifdef _D3XP
SetTimeState ts( timeGroup );
#endif
// create a trigger for item pickup
spawnArgs.GetFloat( "triggersize", "16.0", tsize );
trigger = new idClipModel( idTraceModel( idBounds( vec3_origin ).Expand( tsize ) ) );
trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
trigger->SetContents( CONTENTS_TRIGGER );
// check if a clip model is set
spawnArgs.GetString( "clipmodel", "", clipModelName );
if ( !clipModelName[0] ) {
clipModelName = spawnArgs.GetString( "model" ); // use the visual model
}
// load the trace model
if ( !collisionModelManager->TrmFromModel( clipModelName, trm ) ) {
gameLocal.Error( "idMoveableItem '%s': cannot load collision model %s", name.c_str(), clipModelName.c_str() );
return;
}
// if the model should be shrinked
if ( spawnArgs.GetBool( "clipshrink" ) ) {
trm.Shrink( CM_CLIP_EPSILON );
}
// get rigid body properties
spawnArgs.GetFloat( "density", "0.5", density );
density = idMath::ClampFloat( 0.001f, 1000.0f, density );
spawnArgs.GetFloat( "friction", "0.05", friction );
friction = idMath::ClampFloat( 0.0f, 1.0f, friction );
spawnArgs.GetFloat( "bouncyness", "0.6", bouncyness );
bouncyness = idMath::ClampFloat( 0.0f, 1.0f, bouncyness );
// setup the physics
physicsObj.SetSelf( this );
physicsObj.SetClipModel( new idClipModel( trm ), density );
physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
physicsObj.SetAxis( GetPhysics()->GetAxis() );
physicsObj.SetBouncyness( bouncyness );
physicsObj.SetFriction( 0.6f, 0.6f, friction );
physicsObj.SetGravity( gameLocal.GetGravity() );
physicsObj.SetContents( CONTENTS_RENDERMODEL );
physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP );
SetPhysics( &physicsObj );
smoke = NULL;
smokeTime = 0;
#ifdef _D3XP
nextSoundTime = 0;
#endif
const char *smokeName = spawnArgs.GetString( "smoke_trail" );
if ( *smokeName != '\0' ) {
smoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
smokeTime = gameLocal.time;
BecomeActive( TH_UPDATEPARTICLES );
}
#ifdef CTF
repeatSmoke = spawnArgs.GetBool( "repeatSmoke", "0" );
#endif
}
/*
================
idMoveableItem::Think
================
*/
void idMoveableItem::Think( void ) {
RunPhysics();
if ( thinkFlags & TH_PHYSICS ) {
// update trigger position
trigger->Link( gameLocal.clip, this, 0, GetPhysics()->GetOrigin(), mat3_identity );
}
if ( thinkFlags & TH_UPDATEPARTICLES ) {
if ( !gameLocal.smokeParticles->EmitSmoke( smoke, smokeTime, gameLocal.random.CRandomFloat(), GetPhysics()->GetOrigin(), GetPhysics()->GetAxis(), timeGroup /*_D3XP*/ ) ) {
#ifdef CTF
if ( !repeatSmoke ) {
smokeTime = 0;
BecomeInactive( TH_UPDATEPARTICLES );
} else {
smokeTime = gameLocal.time;
}
#else
smokeTime = 0;
BecomeInactive( TH_UPDATEPARTICLES );
#endif
}
}
Present();
}
#ifdef _D3XP
/*
=================
idMoveableItem::Collide
=================
*/
bool idMoveableItem::Collide( const trace_t &collision, const idVec3 &velocity ) {
float v, f;
v = -( velocity * collision.c.normal );
if ( v > 80 && gameLocal.time > nextSoundTime ) {
f = v > 200 ? 1.0f : idMath::Sqrt( v - 80 ) * 0.091f;
if ( StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, false, NULL ) ) {
// don't set the volume unless there is a bounce sound as it overrides the entire channel
// which causes footsteps on ai's to not honor their shader parms
SetSoundVolume( f );
}
nextSoundTime = gameLocal.time + 500;
}
return false;
}
#endif
/*
================
idMoveableItem::Pickup
================
*/
bool idMoveableItem::Pickup( idPlayer *player ) {
bool ret = idItem::Pickup( player );
if ( ret ) {
trigger->SetContents( 0 );
}
return ret;
}
/*
================
idMoveableItem::DropItem
================
*/
idEntity *idMoveableItem::DropItem( const char *classname, const idVec3 &origin, const idMat3 &axis, const idVec3 &velocity, int activateDelay, int removeDelay ) {
idDict args;
idEntity *item;
args.Set( "classname", classname );
args.Set( "dropped", "1" );
// we sometimes drop idMoveables here, so set 'nodrop' to 1 so that it doesn't get put on the floor
args.Set( "nodrop", "1" );
if ( activateDelay ) {
args.SetBool( "triggerFirst", true );
}
gameLocal.SpawnEntityDef( args, &item );
if ( item ) {
// set item position
item->GetPhysics()->SetOrigin( origin );
item->GetPhysics()->SetAxis( axis );
item->GetPhysics()->SetLinearVelocity( velocity );
item->UpdateVisuals();
if ( activateDelay ) {
item->PostEventMS( &EV_Activate, activateDelay, item );
}
if ( !removeDelay ) {
removeDelay = 5 * 60 * 1000;
}
// always remove a dropped item after 5 minutes in case it dropped to an unreachable location
item->PostEventMS( &EV_Remove, removeDelay );
}
return item;
}
/*
================
idMoveableItem::DropItems
The entity should have the following key/value pairs set:
"def_drop<type>Item" "item def"
"drop<type>ItemJoint" "joint name"
"drop<type>ItemRotation" "pitch yaw roll"
"drop<type>ItemOffset" "x y z"
"skin_drop<type>" "skin name"
To drop multiple items the following key/value pairs can be used:
"def_drop<type>Item<X>" "item def"
"drop<type>Item<X>Joint" "joint name"
"drop<type>Item<X>Rotation" "pitch yaw roll"
"drop<type>Item<X>Offset" "x y z"
where <X> is an aribtrary string.
================
*/
void idMoveableItem::DropItems( idAnimatedEntity *ent, const char *type, idList<idEntity *> *list ) {
const idKeyValue *kv;
const char *skinName, *c, *jointName;
idStr key, key2;
idVec3 origin;
idMat3 axis;
idAngles angles;
const idDeclSkin *skin;
jointHandle_t joint;
idEntity *item;
// drop all items
kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sItem", type ), NULL );
while ( kv ) {
c = kv->GetKey().c_str() + kv->GetKey().Length();
if ( idStr::Icmp( c - 5, "Joint" ) != 0 && idStr::Icmp( c - 8, "Rotation" ) != 0 ) {
key = kv->GetKey().c_str() + 4;
key2 = key;
key += "Joint";
key2 += "Offset";
jointName = ent->spawnArgs.GetString( key );
joint = ent->GetAnimator()->GetJointHandle( jointName );
if ( !ent->GetJointWorldTransform( joint, gameLocal.time, origin, axis ) ) {
gameLocal.Warning( "%s refers to invalid joint '%s' on entity '%s'\n", key.c_str(), jointName, ent->name.c_str() );
origin = ent->GetPhysics()->GetOrigin();
axis = ent->GetPhysics()->GetAxis();
}
if ( g_dropItemRotation.GetString()[0] ) {
angles.Zero();
sscanf( g_dropItemRotation.GetString(), "%f %f %f", &angles.pitch, &angles.yaw, &angles.roll );
} else {
key = kv->GetKey().c_str() + 4;
key += "Rotation";
ent->spawnArgs.GetAngles( key, "0 0 0", angles );
}
axis = angles.ToMat3() * axis;
origin += ent->spawnArgs.GetVector( key2, "0 0 0" );
item = DropItem( kv->GetValue(), origin, axis, vec3_origin, 0, 0 );
if ( list && item ) {
list->Append( item );
}
}
kv = ent->spawnArgs.MatchPrefix( va( "def_drop%sItem", type ), kv );
}
// change the skin to hide all items
skinName = ent->spawnArgs.GetString( va( "skin_drop%s", type ) );
if ( skinName[0] ) {
skin = declManager->FindSkin( skinName );
ent->SetSkin( skin );
}
}
/*
======================
idMoveableItem::WriteToSnapshot
======================
*/
void idMoveableItem::WriteToSnapshot( idBitMsgDelta &msg ) const {
physicsObj.WriteToSnapshot( msg );
}
/*
======================
idMoveableItem::ReadFromSnapshot
======================
*/
void idMoveableItem::ReadFromSnapshot( const idBitMsgDelta &msg ) {
physicsObj.ReadFromSnapshot( msg );
if ( msg.HasChanged() ) {
UpdateVisuals();
}
}
/*
============
idMoveableItem::Gib
============
*/
void idMoveableItem::Gib( const idVec3 &dir, const char *damageDefName ) {
// spawn smoke puff
const char *smokeName = spawnArgs.GetString( "smoke_gib" );
if ( *smokeName != '\0' ) {
const idDeclParticle *smoke = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, smokeName ) );
gameLocal.smokeParticles->EmitSmoke( smoke, gameLocal.time, gameLocal.random.CRandomFloat(), renderEntity.origin, renderEntity.axis, timeGroup /*_D3XP*/ );
}
// remove the entity
PostEventMS( &EV_Remove, 0 );
}
/*
================
idMoveableItem::Event_DropToFloor
================
*/
void idMoveableItem::Event_DropToFloor( void ) {
// the physics will drop the moveable to the floor
}
/*
============
idMoveableItem::Event_Gib
============
*/
void idMoveableItem::Event_Gib( const char *damageDefName ) {
Gib( idVec3( 0, 0, 1 ), damageDefName );
}
/*
===============================================================================
idMoveablePDAItem
===============================================================================
*/
CLASS_DECLARATION( idMoveableItem, idMoveablePDAItem )
END_CLASS
/*
================
idMoveablePDAItem::GiveToPlayer
================
*/
bool idMoveablePDAItem::GiveToPlayer(idPlayer *player) {
const char *str = spawnArgs.GetString( "pda_name" );
if ( player ) {
player->GivePDA( str, &spawnArgs );
}
return true;
}
/*
===============================================================================
idItemRemover
===============================================================================
*/
CLASS_DECLARATION( idEntity, idItemRemover )
EVENT( EV_Activate, idItemRemover::Event_Trigger )
END_CLASS
/*
================
idItemRemover::Spawn
================
*/
void idItemRemover::Spawn( void ) {
}
/*
================
idItemRemover::RemoveItem
================
*/
void idItemRemover::RemoveItem( idPlayer *player ) {
const char *remove;
remove = spawnArgs.GetString( "remove" );
player->RemoveInventoryItem( remove );
}
/*
================
idItemRemover::Event_Trigger
================
*/
void idItemRemover::Event_Trigger( idEntity *activator ) {
if ( activator->IsType( idPlayer::Type ) ) {
RemoveItem( static_cast<idPlayer *>(activator) );
}
}
/*
===============================================================================
idObjectiveComplete
===============================================================================
*/
CLASS_DECLARATION( idItemRemover, idObjectiveComplete )
EVENT( EV_Activate, idObjectiveComplete::Event_Trigger )
EVENT( EV_HideObjective, idObjectiveComplete::Event_HideObjective )
EVENT( EV_GetPlayerPos, idObjectiveComplete::Event_GetPlayerPos )
END_CLASS
/*
================
idObjectiveComplete::idObjectiveComplete
================
*/
idObjectiveComplete::idObjectiveComplete() {
playerPos.Zero();
}
/*
================
idObjectiveComplete::Save
================
*/
void idObjectiveComplete::Save( idSaveGame *savefile ) const {
savefile->WriteVec3( playerPos );
}
/*
================
idObjectiveComplete::Restore
================
*/
void idObjectiveComplete::Restore( idRestoreGame *savefile ) {
savefile->ReadVec3( playerPos );
}
/*
================
idObjectiveComplete::Spawn
================
*/
void idObjectiveComplete::Spawn( void ) {
spawnArgs.SetBool( "objEnabled", false );
Hide();
}
/*
================
idObjectiveComplete::Event_Trigger
================
*/
void idObjectiveComplete::Event_Trigger( idEntity *activator ) {
if ( !spawnArgs.GetBool( "objEnabled" ) ) {
return;
}
idPlayer *player = gameLocal.GetLocalPlayer();
if ( player ) {
RemoveItem( player );
if ( spawnArgs.GetString( "inv_objective", NULL ) ) {
if ( player->hud ) {
player->hud->SetStateString( "objective", "2");
player->hud->SetStateString( "objectivetext", spawnArgs.GetString( "objectivetext" ) );
#ifdef _D3XP
player->hud->SetStateString( "objectivecompletetitle", spawnArgs.GetString( "objectivetitle" ) );
#else
player->hud->SetStateString( "objectivetitle", spawnArgs.GetString( "objectivetitle" ) );
#endif
player->CompleteObjective( spawnArgs.GetString( "objectivetitle" ) );
PostEventMS( &EV_GetPlayerPos, 2000 );
}
}
}
}
/*
================
idObjectiveComplete::Event_GetPlayerPos
================
*/
void idObjectiveComplete::Event_GetPlayerPos() {
idPlayer *player = gameLocal.GetLocalPlayer();
if ( player ) {
playerPos = player->GetPhysics()->GetOrigin();
PostEventMS( &EV_HideObjective, 100, player );
}
}
/*
================
idObjectiveComplete::Event_HideObjective
================
*/
void idObjectiveComplete::Event_HideObjective( idEntity *e ) {
idPlayer *player = gameLocal.GetLocalPlayer();
if ( player ) {
idVec3 v = player->GetPhysics()->GetOrigin();
v -= playerPos;
if ( v.Length() > 64.0f ) {
player->hud->HandleNamedEvent( "closeObjective" );
PostEventMS( &EV_Remove, 0 );
} else {
PostEventMS( &EV_HideObjective, 100, player );
}
}
}