thug/Code/Sk/Objects/skater.cpp
2016-02-14 08:39:12 +11:00

2639 lines
84 KiB
C++

/*****************************************************************************
** **
** Neversoft Entertainment **
** **
** Copyright (C) 1999 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: PS2 **
** **
** Module: Objects (OBJ) **
** **
** File name: skater.cpp **
** **
** Created: 01/25/00 **
** **
** Description: Skater **
**
****************************************************************************/
// start autoduck documentation
// @DOC skater
// @module skater | None
// @subindex Scripting Database
// @index script | skater
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <core/defines.h>
#include <core/singleton.h>
#include <core/math.h>
#include <core/math/slerp.h>
#include <sys/timer.h>
#include <sys/sioman.h>
#include <gel/objtrack.h>
#include <gel/assman/assman.h>
#include <gel/collision/collcache.h>
#include <gel/inpman.h>
#include <gel/mainloop.h>
#include <gel/environment/terrain.h>
#include <gel/soundfx/soundfx.h>
#include <gel/net/client/netclnt.h>
#include <gel/net/server/netserv.h>
#include <gel/object/compositeobjectmanager.h>
#include <gel/components/animationcomponent.h>
#include <gel/components/lockobjcomponent.h>
#include <gel/components/modelcomponent.h>
#include <gel/components/motioncomponent.h>
#include <gel/components/shadowcomponent.h>
#include <gel/components/skeletoncomponent.h>
#include <gel/components/specialitemcomponent.h>
#include <gel/components/suspendcomponent.h>
#include <gel/components/trickcomponent.h>
#include <gel/components/nodearraycomponent.h>
#include <gel/components/railmanagercomponent.h>
#include <gel/components/skitchcomponent.h>
#include <gel/components/cameracomponent.h>
#include <gel/components/skatercameracomponent.h>
#include <gel/components/vibrationcomponent.h>
#include <gel/components/proximtriggercomponent.h>
#include <gel/components/triggercomponent.h>
#include <gel/components/inputcomponent.h>
#include <gel/components/collisioncomponent.h>
#include <gel/components/walkcomponent.h>
#include <gel/components/movablecontactcomponent.h>
#include <gel/components/ribboncomponent.h>
#include <gel/components/statsmanagercomponent.h>
#include <gel/components/walkcameracomponent.h>
#ifdef TESTING_GUNSLINGER
#include <gel/components/ridercomponent.h>
#include <gel/components/weaponcomponent.h>
#endif
#include <gfx/camera.h>
#include <gfx/shadow.h>
#include <gfx/debuggfx.h> // for debug lines
#include <gfx/gfxutils.h>
#include <gfx/nxmodel.h>
#include <gfx/nxlight.h>
#include <gfx/nxlightman.h>
#include <gfx/2D/ScreenElemMan.h>
#include <gfx/2D/SpriteElement.h>
#include <gfx/2D/ScreenElement2.h>
#include <gfx/skeleton.h>
#include <gfx/nx.h> // for sGetMovableObjects
#include <gfx/NxMiscFX.h>
#include <sk/modules/skate/skate.h> // for SKATE_TYPE_*
#include <sk/modules/FrontEnd/FrontEnd.h>
#include <sk/modules/skate/competition.h> // for CCompetition
#include <sk/modules/skate/gamemode.h>
#include <sk/modules/skate/goalmanager.h> // for special goal
#include <sk/modules/skate/CreateATrick.h>
#include <sk/ParkEditor2/ParkEd.h>
#include <sk/objects/crown.h>
#include <sk/objects/moviecam.h>
#include <sk/objects/proxim.h>
#include <sk/objects/rail.h>
#include <sk/objects/objecthook.h>
#include <sk/objects/restart.h>
#include <sk/objects/skater.h>
#include <sk/objects/skaterprofile.h>
#include <sk/objects/skatercareer.h>
#include <sk/objects/playerprofilemanager.h>
#include <sk/components/skaterstancepanelcomponent.h>
#include <sk/components/skaterloopingsoundcomponent.h>
#include <sk/components/skatersoundcomponent.h>
#include <sk/components/skatergapcomponent.h>
#include <sk/components/skaterrotatecomponent.h>
#include <sk/components/skaterphysicscontrolcomponent.h>
#include <sk/components/skaterlocalnetlogiccomponent.h>
#include <sk/components/skaternonlocalnetlogiccomponent.h>
#include <sk/components/skaterscorecomponent.h>
#include <sk/components/skatermatrixqueriescomponent.h>
#include <sk/components/skaterfloatingnamecomponent.h>
#include <sk/components/skaterstatehistorycomponent.h>
#include <sk/components/skatercorephysicscomponent.h>
#include <sk/components/skateradjustphysicscomponent.h>
#include <sk/components/skaterfinalizephysicscomponent.h>
#include <sk/components/skatercleanupstatecomponent.h>
#include <sk/components/skaterendruncomponent.h>
#include <sk/components/skaterbalancetrickcomponent.h>
#include <sk/components/skaterflipandrotatecomponent.h>
#include <sk/components/skaterstatecomponent.h>
#include <sk/components/skaterruntimercomponent.h>
#include <sk/engine/feeler.h>
#include <sk/engine/contact.h>
#include <sk/gamenet/gamenet.h>
#include <sk/scripting/cfuncs.h>
#include <sys/profiler.h>
#include <sys/replay/replay.h>
#include <core/math/geometry.h>
#include <gel/music/music.h>
#include <gel/collision/collision.h>
#include <gel/scripting/symboltable.h>
#include <gel/scripting/script.h>
#include <gel/scripting/struct.h>
#include <gel/scripting/array.h>
#include <gel/scripting/component.h>
#include <gel/scripting/vecpair.h>
#include <gel/scripting/checksum.h>
#include <sk/scripting/nodearray.h>
#ifdef __PLAT_NGC__
#include "gfx/ngc/nx/nx_init.h"
#endif // __PLAT_NGC__
#define FLAGEXCEPTION(X) SelfEvent(X)
////////////////////////////////////////////////////////////////////////
inline void dodgy_test()
{
// Mdl::Skate * skate_mod = Mdl::Skate::Instance();
// if (skate_mod->GetSkater(0))
// {
// skate_mod->GetSkater(0)->DodgyTest();
// }
}
/*****************************************************************************
** Externals **
*****************************************************************************/
extern uint64 Gfx_LastVBlank;
namespace Gfx
{
void DebuggeryLines_CleanUp( void ); // just for debugging
}
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** DBG Defines **
*****************************************************************************/
// All the CSkater code sits in the Obj namespace, along with other objects,
// like peds and cars
namespace Obj
{
bool DebugSkaterScripts=false; // Set to true to dump out a lot of info about the skater's script
// generally you would set it with the script command SkaterDebugOn/Off
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/////////////////////////////////////////////////////////////////////////////
// Physics patching, so physics vars can come from different structs
// or globals, in a nice relaxed manner
Script::CStruct * get_physics_struct()
{
// if (Script::GetInteger(CRCD(0x9e86d1c1,"use_bike_physics")))
// {
// return Script::GetStructure(CRCD(0x9d728121,"bike_physics"));
// }
// else if (Script::GetInteger(CRCD(0x9ae06a83,"use_walk_physics")))
// {
// return Script::GetStructure(CRCD(0x8cbc89dd,"skater_physics"));
// }
// else
// {
return Script::GetStructure(CRCD(0x8cbc89dd,"skater_physics"));
// }
}
float GetPhysicsFloat(uint32 id, Script::EAssertType assert)
{
Script::CStruct *p_struct = get_physics_struct();
float x;
if (p_struct->GetFloat(id,&x))
{
return x;
}
return Script::GetFloat(id,assert);
}
int GetPhysicsInt(uint32 id, Script::EAssertType assert)
{
Script::CStruct *p_struct = get_physics_struct();
int x;
if (p_struct->GetInteger(id,&x))
{
return x;
}
return Script::GetInteger(id,assert);
}
// End of physics patching
/////////////////////////////////////////////////////////////////////////////
// This Test generally not called
// can stick code in here that will be called from dodgy_test
// whcih gets called from every printf
// generaly you'd have printfs enabled via something like DEBUG_POSITION
void CSkater::DodgyTest()
{
CFeeler feeler;
feeler.SetEnd(m_pos);
feeler.SetStart(m_pos + Mth::Vector(0.0f,100.0f,0.0f,0.0f));
if (feeler.GetCollision())
{
# if !defined( __PLAT_NGC__ ) || ( defined( __PLAT_NGC__ ) && !defined( __NOPT_FINAL__ ) )
float above = feeler.GetPoint()[Y] - m_pos[Y];
printf(" collision %.2f above me, normal = (%.2f,%.2f,%.2f)\n",above,feeler.GetNormal()[X],feeler.GetNormal()[Y],feeler.GetNormal()[Z]);
#endif // __NOPT_FINAL__
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
// K: This is a factored out code snippet that is used quite a bit.
// It get's a pointer to this skater's score object and asserts if it's NULL.
Mdl::Score *CSkater::GetScoreObject()
{
Dbg_Assert(mp_skater_score_component);
return mp_skater_score_component->GetScore();
}
// Just move the skater to the correct position and orientation for
// this restart point
// used to set intial position of other skaters on clients
void CSkater::MoveToRestart(int node)
{
Dbg_Assert(mp_skater_core_physics_component);
m_matrix.Ident();
Script::CStruct *pNode = NULL;
if (node >= 0)
{
Script::CArray *pNodeArray=Script::GetArray(CRCD(0xc472ecc5,"NodeArray"));
pNode=pNodeArray->GetStructure(node);
Dbg_MsgAssert(pNode,( "null restart"));
SkateScript::GetPosition( node, &m_pos );
#ifdef CHEAT_RUBBER
m_rubber_pos = m_pos;
m_rubber_vel.Set();
#endif
m_old_pos = m_pos;
mp_skater_core_physics_component->m_safe_pos = m_pos;
SetTeleported();
Mth::Vector angles;
SkateScript::GetAngles(pNode, &angles);
m_matrix.SetFromAngles(angles);
mp_skater_core_physics_component->ResetLerpingMatrix();
mp_skater_core_physics_component->m_display_normal = mp_skater_core_physics_component->m_last_display_normal = mp_skater_core_physics_component->m_current_normal = m_matrix[Y];
#ifdef DEBUG_DISPLAY_MATRIX
dodgy_test(); printf("%d: Setting display_matrix[Y][Y] to %f, [X][X] to %f\n",__LINE__,mp_skater_core_physics_component->m_lerping_display_matrix[Y][Y],mp_skater_core_physics_component->m_lerping_display_matrix[X][X]);
#endif
// set the shadow to stick to his feet, assuming we are on the ground
// Note: These are used by the simple shadow, not the detailed one.
Dbg_Assert(mp_shadow_component)
mp_shadow_component->SetShadowPos( m_pos );
mp_shadow_component->SetShadowNormal( m_matrix[Y] );
// update for the camera
m_display_matrix = mp_skater_core_physics_component->m_lerping_display_matrix;
}
}
void CSkater::SkipToRestart(int node, bool walk)
{
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
# ifdef DEBUG_TRIGGERS
dodgy_test(); printf("SkipToRestart(%d)\n",node);
# endif
GetSkaterPhysicsControlComponent()->NotifyReset();
if( m_local_client )
{
// The Skater might have been in the middle of a move that disabled his input, so re-enable it
// and also enable the camera control
mp_input_component->EnableInput();
// Also player should ot be paused
UnPause();
if (mp_stats_manager_component)
{
mp_stats_manager_component->m_restarted_this_frame = true;
}
/*
// If the player had locked the camera in lookaround, clear it back.
if ( mp_skaterCamera )
{
mp_skaterCamera->ClearLookaroundLock();
}
*/
//printf ("STUBBED: Skater.cpp line %d - not clearing lookaroundlock\n",__LINE__);
// Reset the skater back to a collidable state
if( gamenet_man->InNetGame())
{
CFuncs::ScriptNotifyBailDone( NULL, NULL );
mp_skater_core_physics_component->SetFlagFalse( IS_BAILING );
}
}
if (mp_vibration_component)
{
mp_vibration_component->Reset();
}
if (node != -1)
{
MoveToRestart(node);
}
ResetPhysics(walk);
dodgy_test(); //printf("Setting animation flipped to %d in SkipToRestart\n",mp_skater_core_physics_component->GetFlag(FLIPPED));
if (IsLocalClient())
{
// reset any flippedness of animation
GetSkaterFlipAndRotateComponent()->ApplyFlipState();
}
// Only local skaters should run the script
if( m_local_client )
{
if (!m_viewing_mode)
{
UpdateCameras( true );
Obj::CCompositeObject *p_obj = GetCamera();
if (p_obj)
{
p_obj->Update(); // Not the best way of doing it...
}
}
if (node != -1)
{
Script::CStruct *pNode = NULL;
Script::CArray *pNodeArray=Script::GetArray(CRCD(0xc472ecc5,"NodeArray"));
pNode=pNodeArray->GetStructure(node);
// Now run any TriggerScript associated with this node
uint32 script;
if (pNode->GetChecksum(0x2ca8a299,&script))
{
# ifdef DEBUG_TRIGGERS
dodgy_test(); printf("%d: Restart Node Script triggered, script name %s, node %d\n",(int)Tmr::GetVblanks(),(char*)Script::FindChecksumName(script),node);
# endif
SpawnAndRunScript(script,node);
}
}
}
SetTeleported();
if( ( skate_mod->GetGameMode()->GetNameChecksum() == CRCD(0x6c5ff266,"netctf") ) ||
( skate_mod->GetGameMode()->GetNameChecksum() == CRCD(0x6ef8fda0,"netking") ) ||
( skate_mod->GetGameMode()->GetNameChecksum() == CRCD(0x5d32129c,"king") ))
{
Net::Client* client;
GameNet::PlayerInfo* player;
Net::MsgDesc msg_desc;
client = gamenet_man->GetClient( m_skater_number );
Dbg_Assert( client );
player = gamenet_man->GetPlayerByObjectID( GetID());
Dbg_Assert( player );
player->MarkAsRestarting();
msg_desc.m_Id = GameNet::MSG_ID_MOVED_TO_RESTART;
msg_desc.m_Queue = Net::QUEUE_SEQUENCED;
msg_desc.m_GroupId = GameNet::vSEQ_GROUP_PLAYER_MSGS;
client->EnqueueMessageToServer( &msg_desc );
}
}
//////////////////////////////////////////////////////////////////////////
// START of "Stat" code
float CSkater::GetStat(EStat stat)
{
float value;
float override;
Mdl::Skate* skate_mod = Mdl::Skate::Instance();
override = skate_mod->GetStatOverride();
if (override != 0.0f)
{
value = override;
}
else
{
if (m_stat[stat] == -1.0f)
{
value = GetPhysicsFloat(CRCD(0x6357d57c,"Skater_Default_Stats"));
}
else
{
value = m_stat[stat];
}
}
// In a network game, always set stats to 10
// if( GameNet::Manager::Instance()->InNetGame() )
// {
// value = 10.0f;
// }
if( GameNet::Manager::Instance()->InNetGame())
{
GameNet::PlayerInfo* player;
player = GameNet::Manager::Instance()->GetPlayerByObjectID( GetID());
if( player )
{
if( player->IsKing())
{
value = 1.0f;
}
else if( player->HasCTFFlag())
{
value = 6.0f;
}
else
{
value = 10.0f;
}
}
else
{
value = 10.0f;
}
}
else if( CFuncs::ScriptInSplitScreenGame( NULL, NULL ))
{
GameNet::PlayerInfo* player;
player = GameNet::Manager::Instance()->GetPlayerByObjectID( GetID());
if( player )
{
if( player->IsKing())
{
value = 1.0f;
}
}
}
if( GameNet::Manager::Instance()->InNetGame())
{
GameNet::PlayerInfo* player;
player = GameNet::Manager::Instance()->GetPlayerByObjectID( GetID());
if( player )
{
if( player->IsKing())
{
value = 1.0f;
}
else if( player->HasCTFFlag())
{
value = 6.0f;
}
else
{
value = 10.0f;
}
}
else
{
value = 10.0f;
}
}
else if( CFuncs::ScriptInSplitScreenGame( NULL, NULL ))
{
GameNet::PlayerInfo* player;
player = GameNet::Manager::Instance()->GetPlayerByObjectID( GetID());
if( player )
{
if( player->IsKing())
{
value = 1.0f;
}
}
}
if (CHEAT_STATS_13)
{
value = 15.0f;
}
Dbg_Assert(mp_skater_score_component);
if (mp_skater_score_component->GetScore()->GetSpecialState())
{
value += 3.0f;
}
return value;
}
void CSkater::SetStat(EStat stat, float value)
{
// factor in the handicap if any...
if ( CFuncs::ScriptInSplitScreenGame( NULL, NULL ) )
{
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
value += skate_mod->GetHandicap( m_id );
// clamp it to the min, max values
if ( value > 10.0f ) value = 10.0f;
if ( value < 0.0f ) value = 0.0f;
}
m_stat[stat] = value;
}
// Gets a stat value given a pointer to the stat structure.
float CSkater::GetScriptedStat(Script::CStruct *pSS)
{
Script::CPair range;
Script::CPair switch_range;
int stat;
float limit;
Dbg_MsgAssert(pSS,("NULL pSS sent to GetScriptedStat"));
if (!pSS->GetPair(NONAME,&range))
{
Dbg_MsgAssert(0,("range pair not found in structure."));
}
float stat_value;
if (!pSS->GetInteger(NONAME,&stat))
{
stat_value = 10.0f; // default to 10 if no stats
}
else
{
stat_value = GetStat((CSkater::EStat)stat);
}
float lower = range.mX;
float upper = range.mY;
float len = upper - lower;
float value = lower + (len * stat_value / 10);
if (mp_skater_core_physics_component->IsSwitched()) // if skating in switch stance
{
if (pSS->GetPair(0x9016b4e7,&switch_range)) // switch
{
float switch_stat = GetStat(STATS_SWITCH); // returns 0..13
float mult = switch_range.mX + (switch_range.mY - switch_range.mX) * switch_stat/10.0f;
if (mult <0.0f) mult = 0.0f;
if (mult >1.0f) mult = 1.0f; // this ensures we are never Better in switch
value *= mult;
}
}
Game::GOAL_MANAGER_DIFFICULTY_LEVEL level = Mdl::Skate::Instance()->GetGoalManager()->GetDifficultyLevel();
if (level != Game::GOAL_MANAGER_DIFFICULTY_MEDIUM)
{
Script::CPair diff;
if (pSS->GetPair(CRCD(0xba8fb854,"diff"),&diff))
{
if (level == Game::GOAL_MANAGER_DIFFICULTY_LOW)
{
value *= diff.mX;
}
else if (level == Game::GOAL_MANAGER_DIFFICULTY_HIGH)
{
value *= diff.mY;
}
}
}
// if there is a limit, then clamp the value to it
// accounting for the direction of the range, this may be a high limit
// or a low limit, but applies to the value for higher values of stat_value.
// so if lower > upper, then it's a low limit
if (pSS->GetFloat(0x8069179f/*"limit"*/,&limit))
{
if (lower < upper)
{
if (value > limit)
{
value = limit;
}
}
else
{
if (value < limit)
{
value = limit;
}
}
}
else
{
// there is no limit, so we do nothing.
}
return value;
}
// Gets a stat value given the name of the stat, where the stat is defined as a global structure.
float CSkater::GetScriptedStat(const uint32 checksum)
{
// Get the structure that contains the range, stat and limit
Script::CStruct *pSS = NULL;
Script::CStruct *pPhysics;
// Try to get it from the skater/biker physics structure first
pPhysics = get_physics_struct();
if (! pPhysics->GetStructure(checksum,&pSS))
{
pSS= Script::GetStructure(checksum);
}
Dbg_MsgAssert(pSS, ("State %s not found", Script::FindChecksumName(checksum)));
// These asserts are also in the other GetScriptedStat,
// but included here too so that it can print the name of the structure.
#ifdef __NOPT_ASSERT__
Script::CPair range;
if (!pSS->GetPair(NONAME,&range))
{
Dbg_MsgAssert(0,("range pair not found in %s.",Script::FindChecksumName(checksum)));
}
int stat;
if (!pSS->GetInteger(NONAME,&stat))
{
Dbg_MsgAssert(0,("stat not found in %s.",Script::FindChecksumName(checksum)));
}
#endif
return GetScriptedStat(pSS);
}
// Gets a stat value given the name of the stat, where the stat is defined as a global structure.
// Gets a stat value given the name of the stat within a structure pSetOfStats.
// This is used in manual.cpp.
// Different sets of control & wobble stats are stored in structures in physics.q
float CSkater::GetScriptedStat(uint32 Checksum, Script::CStruct *pSetOfStats)
{
Dbg_MsgAssert(pSetOfStats,("NULL pSetOfStats."));
Script::CStruct *pSS=NULL;
pSetOfStats->GetStructure(Checksum,&pSS);
Dbg_MsgAssert(pSS,("Could not find stat called %s in pSetOfStats",Script::FindChecksumName(Checksum)));
return GetScriptedStat(pSS);
}
// END of "Stat" code
/////////////////////////////////////////////////////////////////////////////
void CSkater::MoveToRandomRestart( void )
{
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
int node, retry;
// Try to go to a different restart point than last time. But still, limit
// the number of retries just in case there is only one restart node in the level
retry = 0;
do
{
node = skate_mod->find_restart_node( Mth::Rnd( Mdl::Skate::vMAX_SKATERS ));
retry++;
} while(( node == m_last_restart_node ) && ( retry < 20 ));
m_last_restart_node = node;
Dbg_Printf( "In MoveToRandomRestart: Node %d\n", node );
if (node != -1)
{
SkipToRestart(node);
}
}
void CSkater::UpdateCameras( bool instantly )
{
// printf ("%d: SUTUBBBEDDDDDDDDDDDDDDDDDDDDDDDD UpdateCameras(%d)\n",__LINE__,instantly);
if (instantly)
{
SetTeleported( false );
}
}
void CSkater::UpdateCamera( bool instantly )
{
// printf ("%d: SUTUBBBEDDDDDDDDDDDDDDDDDDDDDDDD UpdateCamera(%d)\n",__LINE__,instantly);
if (instantly)
{
SetTeleported( false );
}
}
Gfx::Camera* CSkater::GetActiveCamera( void )
{
return Nx::CViewportManager::sGetActiveCamera(m_skater_number);
}
CCompositeObject* CSkater::GetCamera()
{
uint32 camera_name = CRCD(0x967c138c,"SkaterCam0");
if (m_skater_number == 1)
{
camera_name = CRCD(0xe17b231a,"SkaterCam1");
}
return static_cast< CCompositeObject* >(CCompositeObjectManager::Instance()->GetObjectByID(camera_name));
}
void CSkater::SetViewMode( EViewMode view_mode )
{
Mdl::FrontEnd* front = Mdl::FrontEnd::Instance();
//HUD::PanelMgr* panel_mgr = HUD::PanelMgr::Instance();
if( m_viewing_mode == view_mode )
{
return;
}
// don't want to do it to skaters that don't have this component
// (which would be the nonlocal skaters)
if (!GetSkaterPhysicsControlComponent())
{
return;
}
m_viewing_mode = view_mode;
switch ( m_viewing_mode )
{
// Normal skaing around with camera
case GAMEPLAY_SKATER_ACTIVE:
{
// Regular gameplay, panel and console on
if (GetPhysicsInt(CRCD(0x9816e1e3,"ScreenShotMode")))
{
dodgy_test(); printf("UnPausing game\n");
front->PauseGame(false);
}
}
break;
// select+X pressed once, skater is frozen
case VIEWER_SKATER_PAUSED:
{
if (GetPhysicsInt(CRCD(0x9816e1e3,"ScreenShotMode")))
{
dodgy_test(); printf("Freezing game\n");
front->PauseGame(true);
}
else
{
GetSkaterPhysicsControlComponent()->SuspendPhysics(true);
}
}
break;
// select+X pressed again, skater skates around
case VIEWER_SKATER_ACTIVE:
{
// pause the game, turn off console
if (GetPhysicsInt(CRCD(0x9816e1e3,"ScreenShotMode")))
{
// Dan: should we skip VIEWER_SKATER_ACTIVE then ScreenShotMode is true?
}
else
{
GetSkaterPhysicsControlComponent()->SuspendPhysics(false);
}
}
break;
default:
Dbg_Assert( 0 );
}
}
void CSkater::Pause()
{
if (!mPaused && m_local_client )
{
MARK;
// Pause the base object
CMovingObject::Pause();
// Switch off the meters. They will come back on by themselves when the skater is unpaused
// and his logic is called again.
Dbg_Assert(mp_skater_score_component) // Might not have a panel in the front end
// NOTE: These two lines make the balance meter vanish in "Screenshot" mode
// But are needed for regular game pausing
mp_skater_score_component->GetScore()->SetBalanceMeter(false);
mp_skater_score_component->GetScore()->SetManualMeter(false);
Script::RunScript(CRCD(0x1277e3fd,"pause_run_timer"), NULL);
// Pause the input device (such as vibrations)
if (mp_input_component)
{
mp_input_component->PauseDevice();
}
// Pause the game sounds
Sfx::CSfxManager * sfx_manager = Sfx::CSfxManager::Instance();
sfx_manager->PauseSounds();
}
}
void CSkater::UnPause()
{
if (mPaused && m_local_client)
{
MARK;
CMovingObject::UnPause();
if (mp_input_component)
{
mp_input_component->UnPauseDevice();
}
CSkaterLoopingSoundComponent *p_sound_loop_component = GetSkaterLoopingSoundComponent();
if (p_sound_loop_component)
{
p_sound_loop_component->UnPause();
}
}
}
// Ken: Factored this out so that the replay code can call it too.
void CSkater::UpdateShadow(const Mth::Vector& pos, const Mth::Matrix& matrix)
{
#ifndef __PLAT_NGPS__
static Mth::Vector ground_dir( 0.8f, -0.8f, 0.3f );
static Mth::Vector air_dir( 0.0f, -1.0f, 0.0f );
// If lights are active, set the ground direction to be that of the primary light.
if( GetModel())
{
Nx::CModelLights *p_lights = GetModel()->GetModelLights();
if( p_lights )
{
ground_dir = p_lights->GetLightDirection( 0 ) * -1.0f;
if( ground_dir[Y] > -0.65f )
{
// Lighting direction is too shallow, leading to overly extended shadows. Limit direction.
// In the new vector, we know we want the [Y] component to be -0.65, so it follows that we
// want ( [X]^2 + [Z]^2 ) to be ( 1.0 - ( -0.65 ^2 )), or 0.5775. First, figure out the
// current value of ( [X]^2 + [Z]^2 ).
float xz_squared = ( ground_dir[X] * ground_dir[X] ) + ( ground_dir[Z] * ground_dir[Z] );
float multiple = sqrtf( 0.5775f / xz_squared );
ground_dir[X] = ground_dir[X] * multiple;
ground_dir[Y] = -0.65f;
ground_dir[Z] = ground_dir[Z] * multiple;
}
}
}
bool ground = true;
if( mp_skater_physics_control_component && ( mp_skater_physics_control_component->IsSkating()))
{
ground = mp_skater_core_physics_component->GetState() == GROUND;
}
else if( mp_walk_component )
{
ground = mp_walk_component->GetState() != CWalkComponent::WALKING_AIR;
}
// Interpolate between the two shadow directions based on Skater state.
if( ground )
{
m_air_timer = ( m_air_timer > 0 ) ? ( m_air_timer - 1 ) : 0;
}
else
{
m_air_timer = ( m_air_timer < 16 ) ? ( m_air_timer + 1 ) : 16;
}
Mth::Vector dir = Mth::Lerp(ground_dir, air_dir, m_air_timer * (1.0f / 16.0f));
// Mth::Vector dir = ground_dir + (( air_dir - ground_dir ) * ((float)m_air_timer / 16.0f ));
mp_shadow_component->SetShadowDirection( dir );
#ifdef __PLAT_NGC__
NxNgc::EngineGlobals.skater_shadow_dir.x = dir[X];
NxNgc::EngineGlobals.skater_shadow_dir.y = dir[Y];
NxNgc::EngineGlobals.skater_shadow_dir.z = dir[Z];
NxNgc::EngineGlobals.skater_height = GetSkaterStateComponent()->GetHeight();
#endif // __PLAT_NGC__
#endif
/*
GJ: The following has been moved to CShadowComponent::Update()
Mth::Vector shadow_target_pos = pos + ( matrix.GetUp() * 36.0f );
if ( pShadowComponent->mp_shadow )
{
if (pShadowComponent->mp_shadow->GetShadowType()==Gfx::vSIMPLE_SHADOW)
{
pShadowComponent->mp_shadow->UpdatePosition(m_shadow_pos,m_matrix,pShadowComponent->m_shadow_normal);
}
else
{
pShadowComponent->mp_shadow->UpdatePosition(shadow_target_pos); // at this point m_pos is the same as m_pos
}
}
*/
}
// K: Added for use by replay code so that it can playback pad vibrations
SIO::Device *CSkater::GetDevice()
{
// Stubbed for now
// Dbg_MsgAssert(m_input_handler,("NULL m_input_handler"));
// Dbg_MsgAssert(m_input_handler->m_Device,("NULL m_input_handler->m_Device ?"));
// return m_input_handler->m_Device;
return NULL;
}
int CSkater::GetHeapIndex( void )
{
return m_heap_index;
}
/*****************************************************************************
** Public Functions **
*****************************************************************************/
CSkater::CSkater ( int player_num, CBaseManager* p_obj_manager, bool local_client, int obj_id,
int heap_num, bool should_tristrip ) : m_link_node( this ), m_local_client( local_client )
{
m_type = SKATE_TYPE_SKATER;
m_in_world = false;
m_heap_index = heap_num;
m_id = obj_id;
// Mick: Set up the Skater and Skater2 aliases
// Note we use heap_num rather than player_num, as player_num is unreliable in network games
if (heap_num == 0)
{
Obj::CTracker::Instance()->AddAlias(CRCD(0x5b8ab877,"Skater"),this);
}
if (heap_num == 1)
{
Obj::CTracker::Instance()->AddAlias(CRCD(0x6ed3fa7,"Skater2"),this);
}
// low priority (but not lower than cameras) ensures that moving objects we may skate on or
// cars we may drive will be updated before the skater each frame
m_node.SetPri(-500);
p_obj_manager->RegisterObject(*this);
m_skater_number = player_num;
DUMPI(m_skater_number);
DUMPI(m_id);
SetProfileColor(0x00c0c0); // yellow = skater
mp_animation_component=NULL;
mp_model_component=NULL;
mp_shadow_component=NULL;
mp_trick_component=NULL;
mp_vibration_component=NULL;
mp_input_component=NULL;
mp_skater_sound_component=NULL;
mp_skater_gap_component=NULL;
mp_skater_score_component=NULL;
mp_skater_core_physics_component=NULL;
mp_stats_manager_component=NULL;
mp_walk_component=NULL;
mp_skater_physics_control_component=NULL;
// create the following components before CMovingObject creates components
Script::CStruct* component_struct = new Script::CStruct;
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERSTATE);
CreateComponentFromStructure(component_struct);
if (m_local_client)
{
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_INPUT);
CreateComponentFromStructure(component_struct);
mp_input_component = GetInputComponent();
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERSCORE);
CreateComponentFromStructure(component_struct);
mp_skater_score_component = GetSkaterScoreComponent();
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERMATRIXQUERIES);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_TRICK);
CreateComponentFromStructure(component_struct);
mp_trick_component = GetTrickComponent();
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERPHYSICSCONTROL);
CreateComponentFromStructure(component_struct);
mp_skater_physics_control_component=GetSkaterPhysicsControlComponent();
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERCOREPHYSICS);
CreateComponentFromStructure(component_struct);
mp_skater_core_physics_component = GetSkaterCorePhysicsComponent();
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERROTATE);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERGAP);
CreateComponentFromStructure(component_struct);
mp_skater_gap_component = GetSkaterGapComponent();
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERADJUSTPHYSICS);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_TRIGGER);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERFINALIZEPHYSICS);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERCLEANUPSTATE);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_WALK);
CreateComponentFromStructure(component_struct);
mp_walk_component = GetWalkComponent();
# ifdef TESTING_GUNSLINGER
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_RIDER);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_WEAPON);
CreateComponentFromStructure(component_struct);
# endif
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERLOCALNETLOGIC);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERENDRUN);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERBALANCETRICK);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERLOOPINGSOUND);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_STATSMANAGER);
CreateComponentFromStructure(component_struct);
mp_stats_manager_component = GetStatsManagerComponent();
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_MOVABLECONTACT);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERRUNTIMER);
CreateComponentFromStructure(component_struct);
}
else
{
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERSCORE);
CreateComponentFromStructure(component_struct);
mp_skater_score_component = GetSkaterScoreComponent();
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERNONLOCALNETLOGIC);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERCLEANUPSTATE);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERFLOATINGNAME);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERENDRUN);
CreateComponentFromStructure(component_struct);
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERLOOPINGSOUND);
CreateComponentFromStructure(component_struct);
}
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERSTATEHISTORY);
CreateComponentFromStructure(component_struct);
mp_skater_state_history_component = GetSkaterStateHistoryComponent();
component_struct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_SKATERFLIPANDROTATE);
CreateComponentFromStructure(component_struct);
delete component_struct;
}
void CSkater::Construct ( Obj::CSkaterProfile* pSkaterProfile)
{
// only skater 0 should update the camera in the
// skateshop (otherwise, reloading skater 1 would
// cause a momentary flicker)
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
bool should_create_cam = ( !skate_mod->GetGameMode()->IsFrontEnd() ) || ( m_skater_number == 0 );
if( m_local_client && should_create_cam )
{
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().SkaterInfoHeap());
uint32 name = CRCD(0x967c138c,"SkaterCam0");
if (m_skater_number == 1)
{
name = CRCD(0xe17b231a,"SkaterCam1");
}
CCompositeObject *p_cam_object = (CCompositeObject*)CCompositeObjectManager::Instance()->GetObjectByID(name);
if (p_cam_object)
{
// Camera already exists, was being used as an observer camera,
// so just attache it back to this skater
GetSkaterCameraComponentFromObject(p_cam_object)->SetSkater( this );
GetWalkCameraComponentFromObject(p_cam_object)->SetSkater( this );
}
else
{
// Add the parameters for the skater camera component
// so it can get me as the target
Script::CStruct * p_component_params = new Script::CStruct;
p_component_params->AddChecksum(CRCD(0x4c48da58,"CameraTarget"), GetID());
// p_component_params->AddChecksum(CRCD(0x1313e3c,"ProximTriggerTarget"), GetID());
p_component_params->AddChecksum(CRCD(0xa1dc81f9,"name"),name);
p_cam_object = CCompositeObjectManager::Instance()->CreateCompositeObjectFromNode(
Script::GetArray("skatercam_composite_structure"),p_component_params);
delete p_component_params;
}
GetWalkComponent()->SetAssociatedCamera(p_cam_object);
CFuncs::SetActiveCamera(name, m_skater_number, false);
#if 0
// proximtrigger components are deprecated
// point the viewer camera's proximity trigger at the skater
// if it exists, which it might not, if the viewer is not active (Like for the XBox)
CObject* p_viewer_cam = CCompositeObjectManager::Instance()->GetObjectByID(CRCD(0xeb17151b,"viewer_cam"));
if (p_viewer_cam)
{
GetProximTriggerComponentFromObject(static_cast< CCompositeObject* >(p_viewer_cam))->SetScriptTarget(this);
}
#endif
// Lock the object so it won't get deleted.
p_cam_object->SetLockOn();
// Set default mode, so "behind" etc, is set tosomething sensible
GetSkaterCameraComponentFromObject(p_cam_object)->SetMode(CSkaterCameraComponent::SKATERCAM_MODE_NORMAL_MEDIUM, 0.0f);
/*
CCameraComponent *p_cam_component = new CCameraComponent();
CSkaterCameraComponent *p_skatercam_component = new CSkaterCameraComponent();
// We want the CameraComponent processed *after* the SkaterCameraComponent.
p_cam_object->AddComponent( p_skatercam_component );
p_cam_object->AddComponent( p_cam_component );
p_skatercam_component->InitFromStructure( NULL );
p_cam_component->InitFromStructure( NULL );
p_skatercam_component->SetSkater( this );
*/
Mem::Manager::sHandle().PopContext();
}
// Set up the AI script.
Dbg_MsgAssert(mp_script==NULL,("mp_script not NULL?"));
mp_script=new Script::CScript;
// SkaterInit used to be run there --------------> *
Script::CStruct* pSkaterInfoParams = Script::GetStructure(CRCD(0x962e5cf7,"skater_asset_info"));
uint32 skeleton_name = CRCD(0x5a9d2a0a,"human");
if (pSkaterInfoParams)
{
pSkaterInfoParams->GetChecksum("skater_skeleton",&skeleton_name,Script::NO_ASSERT);
}
//--------------------------------------------------------
// components need to be created in a specific
// order... the model needs to come as late as
// possible, so that all the other components can
// play around with its display matrix. (maybe
// should have some kind of priority system for
// components)?
MovingObjectCreateComponents();
Dbg_MsgAssert( !GetAnimationComponent(), ( "Animation component already exists" ) );
Script::CStruct* pAnimationStruct = new Script::CStruct;
pAnimationStruct->AddChecksum( CRCD(0xb6015ea8,"component"), CRC_ANIMATION );
pAnimationStruct->AddChecksum( CRCD(0x5b8c6dc2,"AnimEventTableName"), CRCD(0x3fec31a6,"SkaterAnimEventTable") );
CreateComponentFromStructure(pAnimationStruct, NULL);
delete pAnimationStruct;
mp_animation_component = GetAnimationComponent();
Dbg_MsgAssert( !GetSkeletonComponent(), ( "Skeleton component already exists" ) );
Script::CStruct* pSkeletonStruct = new Script::CStruct;
pSkeletonStruct->AddChecksum( CRCD(0xb6015ea8,"component"), CRC_SKELETON );
pSkeletonStruct->AddChecksum( CRCD(0x222756d5,"skeleton"), skeleton_name );
pSkeletonStruct->AddInteger( CRCD(0xd3982061,"max_bone_skip_lod"), 0 );
CreateComponentFromStructure(pSkeletonStruct, NULL);
delete pSkeletonStruct;
#if 0
// Dan: testing
Script::CStruct* pStruct = new Script::CStruct;
pStruct->AddChecksum(CRCD(0xb6015ea8,"component"), CRC_RIBBON);
pStruct->AddChecksum(CRCD(0xcab94088,"bone"), CRCD(0x7ee14cfe,"Bone_Wrist_L"));
pStruct->AddInteger(CRCD(0x69feef91,"num_links"), 15);
pStruct->AddFloat(CRCD(0x9f4625c2,"link_length"), 5.0f);
pStruct->AddChecksum(CRCD(0x99a9b716,"color"), MAKE_RGB(0, 0, 255));
CreateComponentFromStructure(pStruct, NULL);
delete pStruct;
#endif
//--------------------------------------------------------
uint32 anim_script_name = CRCD(0x501949bd,"animload_human");
if (pSkaterInfoParams)
{
pSkaterInfoParams->GetChecksum(CRCD(0x8b7488e,"skater_anims"),&anim_script_name,Script::NO_ASSERT);
}
mp_animation_component->SetAnims( anim_script_name );
mp_animation_component->EnableBlending( true );
// Create an empty model
Dbg_MsgAssert( !GetModelComponent(), ( "Model component already exists" ) );
Script::CStruct* pModelStruct = new Script::CStruct;
pModelStruct->AddChecksum( NONAME, CRCD(0x10079f2d,"UseModelLights") );
// Enables the shadow volume on any meshes that get added in the future
int shadowVolumeEnabled = 0;
if ( m_local_client )
{
shadowVolumeEnabled = true;
}
pModelStruct->AddInteger( CRCD(0x2a1f92c0,"ShadowVolume"), shadowVolumeEnabled );
pModelStruct->AddChecksum( CRCD(0xb6015ea8,"component"), CRC_MODEL );
CreateComponentFromStructure(pModelStruct, NULL);
delete pModelStruct;
mp_model_component = GetModelComponent();
// create the model
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().SkaterGeomHeap(m_heap_index));
Ass::CAssMan * ass_man = Ass::CAssMan::Instance();
bool defaultPermanent = ass_man->GetDefaultPermanent();
ass_man->SetDefaultPermanent( false );
// load up the model from a profile
mp_model_component->InitModelFromProfile( pSkaterProfile->GetAppearance(), false, m_heap_index );
ass_man->SetDefaultPermanent( defaultPermanent );
Mem::Manager::sHandle().PopContext();
// Create Model lights
// (This has been moved to the CModelComponent)
// GetModel()->CreateModelLights();
// Nx::CModelLights *p_lights = GetModel()->GetModelLights();
// p_lights->SetPositionPointer(&m_pos);
// now that the model has been created,
// create a shadow component for the skater
Dbg_MsgAssert( !GetShadowComponent(), ( "Shadow component already exists" ) );
Script::CStruct* pShadowStruct = new Script::CStruct;
pShadowStruct->AddChecksum( CRCD(0xb6015ea8,"component"), CRC_SHADOW );
pShadowStruct->AddChecksum( CRCD(0x9ac24b18,"shadowType"), (CRCD(0x76a54cd1,"detailed")) );
CreateComponentFromStructure(pShadowStruct, NULL);
delete pShadowStruct;
mp_shadow_component = GetShadowComponent();
if ( m_local_client )
{
Dbg_MsgAssert( !GetVibrationComponent(), ( "Vibration component already exists" ) );
Script::CStruct* p_vibration_struct = new Script::CStruct;
p_vibration_struct->AddChecksum( CRCD(0xb6015ea8,"component"), CRC_VIBRATION );
CreateComponentFromStructure(p_vibration_struct, NULL);
delete p_vibration_struct;
mp_vibration_component = GetVibrationComponent();
Dbg_MsgAssert( !GetSkaterStancePanelComponent(), ( "StancePanel component already exists" ) );
Script::CStruct* p_stancepanel_struct = new Script::CStruct;
p_stancepanel_struct->AddChecksum( CRCD(0xb6015ea8,"component"), CRC_SKATERSTANCEPANEL );
CreateComponentFromStructure(p_stancepanel_struct, NULL);
delete p_stancepanel_struct;
}
else
{
mp_vibration_component = NULL;
}
if ( m_local_client )
{
Dbg_MsgAssert( !GetSkaterSoundComponent(), ( "SkaterSound component already exists" ) );
Script::CStruct* p_skater_sound_struct = new Script::CStruct;
p_skater_sound_struct->AddChecksum( CRCD(0xb6015ea8,"component"), CRC_SKATERSOUND );
CreateComponentFromStructure(p_skater_sound_struct, NULL);
delete p_skater_sound_struct;
mp_skater_sound_component = GetSkaterSoundComponent();
}
// Finalize Components
Finalize();
// Set up the controller preferences.
Dbg_MsgAssert(m_skater_number>=0 && m_skater_number<Mdl::Skate::vMAX_SKATERS,("Eh? Bad m_skater_number"));
if (IsLocalClient())
{
mp_skater_core_physics_component->m_auto_kick = skate_mod->mp_controller_preferences[m_skater_number].AutoKickOn;
mp_skater_core_physics_component->m_spin_taps = skate_mod->mp_controller_preferences[m_skater_number].SpinTapsOn;
mp_vibration_component->SetActiveState(skate_mod->mp_controller_preferences[m_skater_number].VibrationOn);
}
// Mick: Run the SkaterInit Script
// this used to be done before all the components are created, but it makes more sense to do it after
// and the old way boke after I moved the "SetSkaterCamOverride" into SkaterCameraComponent
if ( m_local_client )
{
// Start running the ground AI.
#ifdef __NOPT_ASSERT__
mp_script->SetCommentString("Created in CSkater constructor, assigned to CSkater::mp_script");
#endif
mp_script->SetScript("SkaterInit",NULL,this);
}
UpdateSkaterInfo( pSkaterProfile );
UpdateStats( pSkaterProfile );
if ( m_local_client )
{
GetSkaterSoundComponent()->SetMaxSpeed(GetScriptedStat(CRCD(0xcc5f87aa,"Skater_Max_Max_Speed_Stat")));
}
/*
// K: For the debug info above the skater.
mp_drawer=new Fnt::Drawer();
mp_drawer->SetRenderState(Image::Drawer::vRS_ZBUFFER | Image::Drawer::vRS_ALPHABLENDING);
mp_drawer->SetFont("small.fnt");
mp_drawer->SetJust(Image::vJUST_CENTER_X,Image::vJUST_CENTER_Y);
mp_drawer->SetShadowState(true,0,0);
*/
if (mp_trick_component)
{
// K: Create and fill in the trick mappings structure.
mp_trick_component->UpdateTrickMappings( pSkaterProfile );
// Initialise the event buffer.
mp_trick_component->ClearEventBuffer();
// Initialise the trick queue
mp_trick_component->ClearTrickQueue();
mp_trick_component->ClearManualTrick();
mp_trick_component->ClearExtraGrindTrick();
mp_trick_component->SetAssociatedScore(mp_skater_score_component->GetScore());
}
if (mp_skater_gap_component)
{
mp_skater_gap_component->SetAssociatedScore(mp_skater_score_component->GetScore());
}
mSparksRequireRail=true;
Obj::CCollisionComponent* p_collision_component = GetCollisionComponent();
if ( p_collision_component )
{
if (p_collision_component->GetCollision())
{
// Garrett: Make skater non-collidable for now
p_collision_component->GetCollision()->SetObjectFlags(mSD_NON_COLLIDABLE);
}
}
// Init collision cache for CFeelers
if (m_local_client)
{
// mp_collision_cache = Nx::CCollCacheManager::sCreateCollCache();
}
else
{
// mp_collision_cache = NULL;
}
// make sure it doesn't flash at the origin for a brief moment,
mp_model_component->FinalizeModelInitialization();
// this needs to happen after the m_id has been assigned
Script::RunScript( CRCD(0xae5438af,"InitSkaterParticles"), NULL, this );
// safety-check to make sure he doesn't start out in the blair witch position
// (because of our animation LOD-ing system)
// (must be done before the models get initialized)
mp_animation_component->PlaySequence(CRCD(0x1ca1ff20,"default"));
if (m_local_client)
{
// add created tricks
for (int i=0; i < Game::vMAX_CREATED_TRICKS; i++)
{
m_created_trick[i] = new Game::CCreateATrick;
}
Script::RunScript( CRCD(0xbdc1c89,"spawn_add_premade_cats_to_skater"), NULL, this );
// setup the correct physics state
CCompositeObject::CallMemberFunction(CRCD(0x5c038f9b,"SkaterPhysicsControl_SwitchWalkingToSkating"), NULL, NULL);
}
}
void CSkater::Init(Obj::CSkaterProfile* pSkaterProfile)
{
Construct(pSkaterProfile);
GameNet::Manager * gamenet_manager = GameNet::Manager::Instance();
// Note, both tasks are registered as LOW_PRIORITY, so they come after everything else
// this ensures the movement of the skater is in sync with objects the skater stands on
if( m_local_client && CFuncs::ScriptInMultiplayerGame( NULL, NULL ))
{
Net::App* client;
client = gamenet_manager->GetClient( m_skater_number );
Dbg_Assert( client );
client->m_Dispatcher.AddHandler( GameNet::MSG_ID_SCORE, Mdl::Score::s_handle_score_message, 0, this );
client->m_Dispatcher.AddHandler( GameNet::MSG_ID_SKATER_COLLIDE_WON, CSkaterStateHistoryComponent::sHandleCollision, 0, this );
client->m_Dispatcher.AddHandler( GameNet::MSG_ID_SKATER_COLLIDE_LOST, CSkaterStateHistoryComponent::sHandleCollision, 0, this );
client->m_Dispatcher.AddHandler( GameNet::MSG_ID_SKATER_PROJECTILE_HIT_TARGET, CSkaterStateHistoryComponent::sHandleProjectileHit, 0, this );
client->m_Dispatcher.AddHandler( GameNet::MSG_ID_SKATER_HIT_BY_PROJECTILE, CSkaterStateHistoryComponent::sHandleProjectileHit, 0, this );
client->m_Dispatcher.AddHandler( GameNet::MSG_ID_STEAL_MESSAGE, CSkaterLocalNetLogicComponent::sHandleStealMessage, 0, this );
}
// moved to CSkaterLocalNetLogicComponent
// m_last_update_time = 0;
Obj::CSuspendComponent* pSuspendComponent = GetSuspendComponent();
if ( pSuspendComponent )
{
pSuspendComponent->m_lod_dist[0] = 3000; // was 500, but in multi-player, we generally want to see subtle animations animating
// and in single player, you should always be close to the camera anyway
pSuspendComponent->m_lod_dist[1] = 5000; // we pretty much always want to see the other player, even at a great distance
pSuspendComponent->m_lod_dist[2] = 10000000;
pSuspendComponent->m_lod_dist[3] = 10000000;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkater::UpdateStats( CSkaterProfile* pSkaterProfile )
{
// GJ: apply the stats contained in the skater profile; we'll need
// need to override them after this function, if we're applying cheats
this->SetStat( STATS_AIR, pSkaterProfile->GetStatValue((CRCD(0x439f4704,"air"))) );
this->SetStat( STATS_RUN, pSkaterProfile->GetStatValue((CRCD(0xaf895b3f,"run"))) );
this->SetStat( STATS_OLLIE, pSkaterProfile->GetStatValue((CRCD(0x9b65d7b8,"ollie"))) );
this->SetStat( STATS_SPEED, pSkaterProfile->GetStatValue((CRCD(0xf0d90109,"speed"))) );
this->SetStat( STATS_SPIN, pSkaterProfile->GetStatValue((CRCD(0xedf5db70,"spin"))) );
this->SetStat( STATS_FLIPSPEED, pSkaterProfile->GetStatValue((CRCD(0x6dcb497c,"flip_speed"))) );
this->SetStat( STATS_SWITCH, pSkaterProfile->GetStatValue((CRCD(0x9016b4e7,"switch"))) );
this->SetStat( STATS_RAILBALANCE, pSkaterProfile->GetStatValue((CRCD(0xf73a13e3,"rail_balance"))) );
this->SetStat( STATS_LIPBALANCE, pSkaterProfile->GetStatValue((CRCD(0xae798769,"lip_balance"))) );
this->SetStat( STATS_MANUAL, pSkaterProfile->GetStatValue((CRCD(0xb1fc0722,"manual_balance"))) );
#ifdef __USER_GARY__
dodgy_test(); printf("Air %2.2f\n",GetStat(STATS_AIR));
dodgy_test(); printf("Run %2.2f\n",GetStat(STATS_RUN));
dodgy_test(); printf("Ollie %2.2f\n",GetStat(STATS_OLLIE));
dodgy_test(); printf("Speed %2.2f\n",GetStat(STATS_SPEED));
dodgy_test(); printf("Spin %2.2f\n",GetStat(STATS_SPIN));
dodgy_test(); printf("Flip %2.2f\n",GetStat(STATS_FLIPSPEED));
dodgy_test(); printf("Switch %2.2f\n",GetStat(STATS_SWITCH));
dodgy_test(); printf("Rail %2.2f\n",GetStat(STATS_RAILBALANCE));
dodgy_test(); printf("Lip %2.2f\n",GetStat(STATS_LIPBALANCE));
dodgy_test(); printf("Manual %2.2f\n",GetStat(STATS_MANUAL));
#endif
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkater::UpdateSkaterInfo( Obj::CSkaterProfile* pSkaterProfile )
{
// get some info from the skater profile
// while we still have access to it...
Dbg_MsgAssert( pSkaterProfile,( "No profile supplied" ));
m_pushStyle = pSkaterProfile->GetChecksumValue( (CRCD(0xc15dbf86,"pushstyle")) );
m_isGoofy = pSkaterProfile->GetChecksumValue( (CRCD(0x7d02bcc3,"stance")) ) == ( CRCD(0x287fcd4e,"goofy") );
m_isPro = pSkaterProfile->IsPro();
m_displayName = pSkaterProfile->GetDisplayName();
// needed for playing correct streams
pSkaterProfile->GetInfo()->GetInteger( CRCD(0x3f813177,"is_male"), &m_isMale, Script::ASSERT );
const char* pFirstName;
pSkaterProfile->GetInfo()->GetText( CRCD(0x562e3ecd,"first_name"), &pFirstName, Script::ASSERT );
Dbg_MsgAssert( strlen( pFirstName) < MAX_LEN_FIRST_NAME,
( "First name %s is too long (max = %d chars)", m_firstName, MAX_LEN_FIRST_NAME ) );
strcpy( m_firstName, pFirstName );
m_skaterNameChecksum = pSkaterProfile->GetSkaterNameChecksum();
if (IsLocalClient())
{
mp_skater_core_physics_component->SetFlag(FLIPPED, !m_isGoofy);
GetSkaterFlipAndRotateComponent()->ApplyFlipState();
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CSkater::~CSkater ( void )
{
// Taken care of by the shadow component's destructor
// Obj::CShadowComponent* pShadowComponent = GetShadowComponent();
// if ( pShadowComponent )
// {
// pShadowComponent->SwitchOffShadow();
// }
// if (mp_collision_cache)
// {
// Nx::CCollCacheManager::sDestroyCollCache(mp_collision_cache);
// }
// We must unpause the controller before we destruct ourselves. Otherwise, the
// paused/unpaused toggle will become out of sync with any future skater which
// uses this controller.
if (mPaused && m_local_client && mp_input_component)
{
mp_input_component->GetDevice()->UnPause();
mp_input_component->GetDevice()->StopAllVibrationIncludingSaved();
}
DeleteResources();
Script::RunScript( CRCD(0xf429e0ac,"DestroySkaterParticles"), NULL, this );
for (int i=0; i < Game::vMAX_CREATED_TRICKS; i++)
{
delete m_created_trick[i];
}
// (Mick) If there is a camera still associated with this skater, then delete it
// this will be either SkaterCam0 or SkaterCam1, and only on local clients
// (Steve) only delete player 2's camera. For now, at least, player 1's camera
// is persistent because it is used in observer mode
if (IsLocalClient() && ( m_skater_number == 1 ))
{
CCompositeObject *p_cam = GetCamera();
if (p_cam)
{
//delete p_cam;
p_cam->MarkAsDead();
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
// Reset skater state (physics, score, et al.), such as when you're retrying
void CSkater::Reset()
{
// MARK;
Dbg_Assert(mp_skater_score_component);
mp_skater_score_component->Reset();
// clear max times (records) for the various balance tricks
Dbg_Assert(GetSkaterBalanceTrickComponent());
GetSkaterBalanceTrickComponent()->ClearMaxTimes();
ResetAnimation();
Dbg_Assert(mp_skater_core_physics_component);
int i;
for ( i = 0; i < NUM_ESKATERFLAGS; i++ )
{
mp_skater_core_physics_component->SetFlag( ( ESkaterFlag )i, true );
mp_skater_core_physics_component->SetFlag( ( ESkaterFlag )i, false );
}
// Reset the pad:
Dbg_Assert(mp_input_component);
mp_input_component->GetControlPad().Reset();
}
// DeleteResources will delete things the skater has allocated that
// we do not want to stick around when we do a cleanup of everything else
// we should really split the skater into temporary and permanent parts
void CSkater::DeleteResources(void)
{
if (IsLocalClient())
{
mp_skater_gap_component->ClearActiveGaps();
GetSkaterBalanceTrickComponent()->ClearBalanceParameters();
}
// we don't want to carry over special items
// from one level to another (they would
// fragment memory anyway)
Obj::CSpecialItemComponent* pSpecialItemComponent = GetSpecialItemComponent();
Dbg_Assert(pSpecialItemComponent);
pSpecialItemComponent->DestroyAllSpecialItems();
// need to get rid of any animations
// that the skater is currently playing,
// or else there will be CBlendChannels
// fragmenting the bottom-up heap.
mp_animation_component->Reset();
#ifdef __SCRIPT_EVENT_TABLE__
if (mp_script)
{
delete mp_script;
mp_script = NULL;
}
#else
// Clear the event receiver associated with this objects
// They will get set up again next time we add or remove one
mp_event_handler_table->unregister_all(this);
#endif
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkater::ResetStates()
{
Dbg_Assert( IsLocalClient());
GetSkaterPhysicsControlComponent()->SuspendPhysics(false);
GetSkaterFlipAndRotateComponent()->Reset();
// #ifdef __PLAT_NGC__
// mDoDeferredRotateAfter=false;
// mDeferredFlipAndRotate=false;
// #endif
// Ken stuff, reset other misc stuff such as the event buffer, trick queue, blaa blaa
// GetExceptionComponent()->ClearExceptions();
Dbg_Assert( mp_trick_component );
mp_trick_component->ClearQueueTricksArrays();
mp_trick_component->ClearManualTrick();
mp_trick_component->ClearExtraGrindTrick();
mp_trick_component->ClearEventBuffer();
mp_trick_component->ClearTrickQueue();
mp_trick_component->ClearMiscellaneous();
GetSkaterStateComponent()->Reset();
// If set this will make the call to UpdateModel() use the display matrix flipped.
// Used when running the lip-trick out-anim, to stop it appearing flipped until
// the anim has finished.
mp_model_component->mFlipDisplayMatrix=false;
// Make sure the meters are off.
Dbg_Assert( mp_skater_score_component )
mp_skater_score_component->GetScore()->SetBalanceMeter(false);
mp_skater_score_component->GetScore()->SetManualMeter(false);
// Reset the panel
// Mdl::Score *pScore=GetScoreObject();
// pScore->BailRequest(); // effectively cancels the current score pot
// Reset doing-trick flag so that he doesn't bail on the drop-in if he died whilst
// doing a trick.
if (mp_vibration_component)
{
mp_vibration_component->StopAllVibration();
}
// set the shadow to stick to his feet, assuming we are on the ground
// Note: These are used by the simple shadow, not the detailed one.
mp_shadow_component->SetShadowPos( m_pos );
mp_shadow_component->SetShadowNormal( m_matrix[Y] );
mSparksRequireRail=true;
GetSkaterStancePanelComponent()->Reset();
}
void CSkater::ResetAnimation()
{
Dbg_Assert( IsLocalClient());
// Put the board orientation back to normal
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
Net::Client* client;
client = gamenet_man->GetClient( GetHeapIndex());
Dbg_Assert( client );
CSkaterFlipAndRotateComponent* p_flip_and_rotate_component = GetSkaterFlipAndRotateComponent();
p_flip_and_rotate_component->RotateSkateboard(GetID(), false, client->m_Timestamp, IsLocalClient());
p_flip_and_rotate_component->ApplyFlipState();
// Make sure the board is visible
mp_model_component->HideGeom( CRCD(0xa7a9d4b8,"board"), false, IsLocalClient() );
/*
// Make sure all atomics are visible
// (GJ: Not really sure why the previous board unhiding is still necessary)
pModelComponent->HideGeom((CRCD(0xc4e78e22,"all")), false, IsLocalClient());
// unhiding all the atomics will conflict with the "invisible" cheat
*/
// getting into certain physics states
// will reset the animation, so we want to
// make sure we've always got some animation
// to be playing...
mp_animation_component->Reset();
// GJ: don't start playing a new animation, because
// it's possible that the animations have been unloaded
// mp_animation_component->PlaySequence( CRCD(0x1ca1ff20,"default") );
// mp_animation_component->SetLoopingType( Gfx::LOOPING_CYCLE, true );
}
void CSkater::ResetInitScript(bool walk, bool in_cleanup)
{
// Mick: Finally update the "SkaterInit" script, so it does any flag clearing that
// is needed by the game
// we do this now, otherwise some other script could issue a MakeSkaterGoto, and clear this script
// so it would never get run.
if ( !mp_script )
{
mp_script = new Script::CScript;
}
Script::CStruct* p_params = NULL;
if (walk || in_cleanup)
{
p_params = new Script::CStruct;
if (walk)
{
p_params->AddChecksum(NO_NAME, CRCD(0x726e85aa,"Walk"));
}
if (in_cleanup)
{
p_params->AddChecksum(NO_NAME, CRCD(0x7b738580,"InCleanup"));
}
}
mp_script->SetScript(CRCD(0xe740f458,"SkaterInit"), p_params, this);
if( IsLocalClient())
{
mp_script->Update();
}
if (p_params)
{
delete p_params;
}
}
// Reset physics flags, position, velocity, etc...
void CSkater::ResetPhysics(bool walk, bool in_cleanup)
{
// MARK;
Dbg_Assert( IsLocalClient());
// Massive function to reset all skater's members so that
// replay becomes deterministicalistic
// ResetEverything( );
// switch back to walking
if (mp_skater_physics_control_component->IsWalking())
{
Script::CStruct* p_params = new Script::CStruct;
p_params->AddChecksum(CRCD(0x91d0d784, "NewScript"), CRCD(0x1dde4804, "OnGroundAi"));
JumpToScript(CRCD(0x93a4e402, "Switch_OnGroundAI"), p_params);
delete p_params;
}
// make sure the OnExitRun script gets run before DeleteResources clears the script
if (mp_script && mp_script->GetOnExitScriptChecksum())
{
uint32 on_exit_script_name_checksum = mp_script->GetOnExitScriptChecksum();
mp_script->SetOnExitScriptChecksum(0);
mp_script->Interrupt(on_exit_script_name_checksum);
}
mp_skater_core_physics_component->Reset();
GetSkaterCameraComponentFromObject(GetCamera())->ResetMode();
ResetStates();
DeleteResources();
ResetAnimation();
ResetInitScript(walk, in_cleanup);
GetSkaterEndRunComponent()->ClearIsEndingRun();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CSkater::SkaterEquals( Script::CStruct* pStructure )
{
// TODO: Maybe stick this data inside the skater's tags,
// so that we can create new fields without having to
// update this function?
Dbg_MsgAssert( pStructure,( "No structure supplied" ));
if ( pStructure->ContainsFlag( CRCD(0xd82f8ac8,"is_pro") ) )
{
if ( !m_isPro )
return false;
}
if ( pStructure->ContainsFlag( CRCD(0x5a3264bb,"is_custom") ) )
{
if ( m_isPro )
return false;
}
if ( pStructure->ContainsFlag( CRCD(0x3f813177,"is_male") ) )
{
if ( !m_isMale )
return false;
}
if ( pStructure->ContainsFlag( CRCD(0xe5c2f84c,"is_female") ) )
{
if ( m_isMale )
return false;
}
uint32 is_named;
if ( pStructure->GetChecksum( CRCD(0xc2e3d008,"is_named"), &is_named ) )
{
if ( is_named != m_skaterNameChecksum )
return false;
}
uint32 stance;
if ( pStructure->GetChecksum( CRCD(0x7d02bcc3,"stance"), &stance ) )
{
uint32 myStance = ( m_isGoofy ? CRCD(0x287fcd4e,"goofy") : CRCD(0xb58efc2b,"regular") );
if ( stance != myStance )
return false;
}
// if we've gotten to the end of the function,
// that means that all of the criteria matched
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CSkater::CallMemberFunction( uint32 Checksum, Script::CStruct *pParams, Script::CScript *pScript )
{
Dbg_MsgAssert(pScript,("NULL pScript"));
return _function0( Checksum, pParams, pScript );
}
bool CSkater::_function0( uint32 Checksum, Script::CStruct *pParams, Script::CScript *pScript )
{
switch (Checksum)
{
// @script | InLocalSkater | returns true if the skater is a local client
case 0x7015bc33: // IsLocalSkater
{
return IsLocalClient();
}
// @script | MoveToRandomRestart | moves the skater to a random
// restart node
case 0xbf450bab: // MoveToRandomRestart
{
MoveToRandomRestart();
break;
}
// @script | SkaterIsNamed | true if skater name matches specified name
// @uparm name | skater name
case 0x1c5612ee: // SkaterIsNamed
{
uint32 checksum;
pParams->GetChecksum( NONAME, &checksum, Script::ASSERT );
return ( checksum == m_skaterNameChecksum );
}
break;
// @script | GetCameraId | sets the skater's camera id to CameraId
case CRCC(0x97c8285a,"GetCameraId"):
{
uint32 camera_name = CRCD(0x967c138c,"SkaterCam0");
if (m_skater_number == 1)
{
camera_name = CRCD(0xe17b231a,"SkaterCam1");
}
pScript->GetParams()->AddChecksum(CRCD(0x7a039889,"CameraId"), camera_name);
break;
}
// @script | RemoveSkaterFromWorld |
case 0xbce85494: // RemoveSkaterFromWorld
{
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
skate_mod->HideSkater( this, true );
return true;
}
break;
// @script | AddSkaterToWorld |
case 0x0c09c1b7: // AddSkaterToWorld
{
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
skate_mod->HideSkater( this, false );
//AddToCurrentWorld();
return true;
}
break;
#if 0
case 0x7fa39d17: // ResetLookAround
{
Dbg_Message("Skater:ResetLookAround does not work");
if (GetSkaterCameraComponent())
{
GetSkaterCameraComponent()->ResetLookAround();
}
return true;
}
break;
#endif
case 0x72aecfc0: // ResetRigidBodyCollisionRadiusBoost
ResetRigidBodyCollisionRadiusBoost();
break;
default:
return _function1( Checksum, pParams, pScript );
break;
}
return true;
}
bool CSkater::_function1( uint32 Checksum, Script::CStruct *pParams, Script::CScript *pScript )
{
switch (Checksum)
{
/////////////////////////////////////////////////////////////////////////////////////////////
// @script | KillSkater | Killskater will reset the skater
// to a node, and set his speed to 0. If this command is
// run from a node, and that node is linked to a restart
// node, then the skater will skip to that restart node,
// and the script in that restart node will be executed
// @parmopt name | Node | | name of node to jump to
// @parmopt name | prefix | | restart at nearest node matching this prefix
// @flag RestartWalking | restart the skater in walk physics mode
case 0x1b572abf: // KillSkater
{
// default just clear skater skater
// and reset to origin
bool walk = pParams->ContainsComponentNamed(CRCD(0xd6f06bf6,"RestartWalking"));
// If there is a "node" parameter, then skip to that
// Mick, optionally add a "prefix" parameter, and skip to the nearest node that matches
// this prefix (will need a new node funtion:
// int GetNearestNodeByPrefix(const char *p_prefix, const Mth::Vector &pos)
const char *p_prefix = NULL;
uint32 prefix_name = 0;
if (!pParams->GetChecksum(CRCD(0x6c4e7971,"prefix"),&prefix_name))
{
if (pParams->GetString(CRCD(0x6c4e7971,"prefix"),&p_prefix))
{
prefix_name = Crc::GenerateCRCFromString(p_prefix);
}
}
if (prefix_name)
{
int target_node = SkateScript::GetNearestNodeByPrefix(prefix_name,m_pos);
Dbg_MsgAssert(target_node != -1,("%s\nNo restart node found with prefix 0x%x, %s",pScript->GetScriptInfo(),prefix_name, p_prefix));
SkipToRestart(target_node, walk);
break;
}
uint32 node_name=0;
if (pParams->GetChecksum(CRCD(0x7a8017ba,"Node"),&node_name))
{
int target_node = SkateScript::FindNamedNode(node_name);
Dbg_MsgAssert(target_node != -1,("%\n Tried to kill skater to non-existant node",pScript->GetScriptInfo()));
SkipToRestart(target_node, walk);
break;
}
else
{
int node = pScript->mNode;
Dbg_MsgAssert(node != -1,( "%s\nKillSkater called from non node script with no 'node' parameter",pScript->GetScriptInfo()));
{
// Otherwise, check the links to see if we are linked to a restart point
int links = SkateScript::GetNumLinks(node);
int link;
for (link = 0;link<links;link++)
{
int linked_node = SkateScript::GetLink(node,link);
if (IsRestart(linked_node))
{
// if the node is linked to a restart point
// then we just skip to that restart point
SkipToRestart(linked_node, walk);
break;
}
}
if (link == links)
{
#if 1
if (Ed::CParkEditor::Instance()->UsingCustomPark()) // is it a custom park???
{
Mdl::Skate* skate_mod = Mdl::Skate::Instance();
skate_mod->skip_to_restart_point( this, -1, walk ); // just skip to standard restart node
}
else
#endif
{
Dbg_MsgAssert(0,( "%s\nKillSkater called, but node %d not linked to restart",pScript->GetScriptInfo(),node));
}
}
}
}
break;
}
// @script | SparksOn | turn sparks on
// @flag RailNotRequired |
case 0xe62f94a2: // SparksOn
Replay::WriteSparksOn();
Script::RunScript( CRCD(0xaf4475de,"sparks_on"), pParams, this );
mSparksRequireRail=true;
mSparksOn=true;
if (pParams->ContainsFlag("RailNotRequired"))
{
mSparksRequireRail=false;
}
break;
// @script | SparksOff | turn sparks off
case 0x5436a335: // SparksOff
Replay::WriteSparksOff();
Script::RunScript( CRCD(0x0dccf5c3,"sparks_off"), pParams, this );
mSparksOn=false;
mSparksRequireRail=true;
break;
// @script | BloodOff | turn blood off
// @parm string | bone | bone name
case 0xc67c18d7: // BloodOff
{
const char* p_bone_name;
if (!pParams->GetText( CRCD(0xcab94088,"bone"), &p_bone_name ))
{
Dbg_MsgAssert(0,("%s\nBloodOff requires a bone name"));
return 0;
}
// nothing doing......
break;
}
// @script | Die | can't be called on the player
case 0xc6870028:// "Die"
Dbg_MsgAssert( 0,( "\n%s\nDie can't be called on the player.\nIs somebody putting 'Die' in a trigger script?", pScript->GetScriptInfo( ) ));
break;
// @script | ShouldMongo | true if should mongo
case 0x3e8eb713: // ShouldMongo
{
if( !IsLocalClient())
{
return false;
}
switch ( m_pushStyle )
{
case vALWAYS_MONGO:
return true;
break;
case vMONGO_WHEN_SWITCH:
return ( mp_skater_core_physics_component->IsSwitched() );
break;
case vNEVER_MONGO:
default:
return false;
break;
}
}
break;
// @script | SetCustomRestart | Skater command to set the current position as the "custom restart point"
// and also to query or clear the status of this restart, based on:
// @flag set | set the restart
// @flag clear | clear the restart
// if no flags are passed, then it will return true if restart point is valid
case 0x42832375: // SetCustomRestart
{
if (pParams->ContainsFlag(CRCD(0x19ebda23,"set")))
{
m_restart_valid = true;
m_restart_pos = m_pos;
m_restart_matrix = m_matrix;
m_restart_walking = mp_skater_physics_control_component->IsWalking();
}
else if (pParams->ContainsFlag(CRCD(0x1a4e0ef9,"clear")))
{
m_restart_valid = false;
break;
}
else
{
return m_restart_valid;
}
//break;
}
// Note: Intentional fallthrough! We want setting the point to have the same effect as skipping to it
// @script | SkipToCustomRestart | Skater command to jump to previously set custom restart
case 0x5a3c19e9: // SkipToCustomRestart
{
SkipToRestart(-1, m_restart_walking);
m_pos = m_restart_pos;
DUMP_SPOSITION
#ifdef DEBUG_POSITION
dodgy_test(); printf("%d: Position = (%.2f,%.2f,%.2f)\n",__LINE__,m_pos[X],m_pos[Y],m_pos[Z]);
#endif
m_matrix = m_restart_matrix;
mp_skater_core_physics_component->m_safe_pos = m_pos; // for uberfrig
m_old_pos = m_pos; // ensure we don't get any nasty triggerings....
SetTeleported();
mp_skater_core_physics_component->ResetLerpingMatrix();
#ifdef DEBUG_DISPLAY_MATRIX
dodgy_test(); printf("%d: Setting display_matrix[Y][Y] to %f, [X][X] to %f\n",__LINE__,mp_skater_core_physics_component->m_lerping_display_matrix[Y][Y],mp_skater_core_physics_component->m_lerping_display_matrix[X][X]);
#endif
mp_skater_core_physics_component->m_display_normal = mp_skater_core_physics_component->m_last_display_normal = mp_skater_core_physics_component->m_current_normal = m_matrix[Y];
// set the shadow to stick to his feet, assuming we are on the ground
// Note: These are used by the simple shadow, not the detailed one.
mp_shadow_component->SetShadowPos( m_pos );
mp_shadow_component->SetShadowNormal( m_matrix[Y] );
break;
}
// @script | GetStat | Get a stat value in the float stat_value, so it can be used in a script expression
// @parm int | Stat | index of stat in stat array, see
case 0x7915aa31: // GetStat
{
int stat;
pParams->GetInteger(CRCD(0xdf4700de,"Stat"),&stat,true);
pScript->GetParams()->AddFloat(CRCD(0x8eaf7add,"stat_value"),GetStat((EStat)stat));
break;
}
// @script | GetScriptedStat | Get a stat value in the float stat_value
// parameters are as used in physics.q
// and you would generally pass in a structure, like Skater_Max_Speed_Stat
// rather than the individual values
case 0x9abe8a21: // GetScriptedStat
{
// Script::PrintContents(pParams);
Script::CStruct *p_struct = NULL;
pParams->GetStructure(NONAME,&p_struct,true);
pScript->GetParams()->AddFloat(CRCD(0x8eaf7add,"stat_value"),GetScriptedStat(p_struct));
break;
}
// @script | GetSkaterNumber | Gets the skater number, and puts it into a parameter called
// SkaterNumber
case 0xf4c52f72: // GetSkaterNumber
{
pScript->GetParams()->AddInteger(CRCD(0xf3cf5755,"SkaterNumber"),m_skater_number);
break;
}
case 0xd38e8b6c: // PlaceBeforeCamera
{
if ( GetActiveCamera() )
{
Mth::Vector &cam_pos = GetActiveCamera()->GetPos();
Mth::Matrix &cam_mat = GetActiveCamera()->GetMatrix();
m_matrix.Ident();
m_pos = cam_pos;
m_pos[Y] += FEET( 0 );
m_pos -= cam_mat[Z] * FEET( 12 );
DUMP_SPOSITION
m_old_pos = m_pos; // MoveToRestart
mp_skater_core_physics_component->m_safe_pos = m_pos; // MoveToRestart
m_matrix = cam_mat;
m_matrix[Z] = -m_matrix[Z];
m_matrix[X] = -m_matrix[X];
mp_skater_core_physics_component->ResetLerpingMatrix();
#ifdef DEBUG_DISPLAY_MATRIX
dodgy_test(); printf("%d: Setting display_matrix[Y][Y] to %f, [X][X] to %f\n",__LINE__,mp_skater_core_physics_component->m_lerping_display_matrix[Y][Y],mp_skater_core_physics_component->m_lerping_display_matrix[X][X]);
#endif
mp_skater_core_physics_component->m_display_normal = mp_skater_core_physics_component->m_last_display_normal = mp_skater_core_physics_component->m_current_normal = m_matrix[Y];
// set the shadow to stick to his feet, assuming we are on the ground
// Note: These are used by the simple shadow, not the detailed one.
mp_shadow_component->SetShadowPos( m_pos );
mp_shadow_component->SetShadowNormal( m_matrix[Y] );
// update these for the camera
m_vel = -cam_mat[Z];
m_vel[Y] = 0;
m_vel.Normalize(10);
UpdateCamera(true); // re-snap the camera to the correct position
#ifdef DEBUG_VELOCITY
dodgy_test(); printf("%d: Velocity = (%.2f,%.2f,%.2f) (%f)\n",__LINE__,m_vel[X],m_vel[Y],m_vel[Z],m_vel.Length());
#endif
}
}
break;
Dbg_MsgAssert(0,("Forgot a break?"));
default:
return CMovingObject::CallMemberFunction( Checksum, pParams, pScript );
break;
}
return true;
}
// End of CallMemberFunction
void CSkater::SparksOn()
{
Dbg_Assert( 0 );
// GJ: It would be nice to keep all the spark logic in
// script, but it requires some skater state info in C
// (like the mSparksRequireRail). Eventually, we should
// move this all to script, instead of calling the following
// script from C code.
Script::RunScript( CRCD(0xaf4475de,"sparks_on"), NULL, this );
mSparksOn = true;
}
void CSkater::SparksOff()
{
// GJ: It would be nice to keep all the spark logic in
// script, but it requires some skater state info in C
// (like the mSparksRequireRail). Eventually, we should
// move this all to script, instead of calling the following
// script from C code.
if ( mSparksOn )
{
Replay::WriteSparksOff();
Script::RunScript( CRCD(0x430efc31,"TurnOffSkaterSparks"), NULL, this );
mSparksOn=false;
}
}
// Used by the MakeSkaterGoto script function in cfuncs.cpp
// Causes the skater to jump to the specified script straight away.
void CSkater::JumpToScript(uint32 ScriptChecksum, Script::CStruct *pParams)
{
Dbg_Assert(IsLocalClient());
// Dbg_MsgAssert(mp_script,("NULL mp_script"));
if ( !mp_script )
{
mp_script = new Script::CScript;
}
GetSkaterFlipAndRotateComponent()->DoAnyFlipRotateOrBoardRotateAfters(); // <- See huge comment above definition of this function.
mp_script->SetScript(ScriptChecksum,pParams,this);
mp_script->Update();
}
void CSkater::JumpToScript(const char *pScriptName, Script::CStruct *pParams)
{
JumpToScript(Script::GenerateCRC(pScriptName),pParams);
}
Mth::Matrix& CSkater::GetDisplayMatrix( void )
{
return mp_skater_core_physics_component->m_lerping_display_matrix;
}
void CSkater::SetDisplayMatrix( Mth::Matrix& matrix )
{
mp_skater_core_physics_component->m_lerping_display_matrix = matrix;
}
Lst::Node< CSkater >* CSkater::GetLinkNode( void )
{
return &m_link_node;
}
void CSkater::Resync( void )
{
if (!m_local_client)
{
GetSkaterNonLocalNetLogicComponent()->Resync();
}
mp_skater_state_history_component->ResetPosHistory();
//mp_skater_state_history_component->ResetAnimHistory();
//mp_skater_state_history_component->SetLatestAnimTimestamp( 0 );
}
void CSkater::RemoveFromCurrentWorld( void )
{
if (IsLocalClient())
{
GetSkaterLoopingSoundComponent()->StopLoopingSound();
}
mp_shadow_component->SwitchOffShadow();
Hide( true );
m_in_world = false;
}
void CSkater::AddToCurrentWorld ( void )
{
mp_shadow_component->SwitchOnSkaterShadow();
Hide( false );
m_in_world = true;
}
bool CSkater::IsInWorld( void )
{
return m_in_world;
}
const char* CSkater::GetDisplayName()
{
// set the player's display name for rankings screen,
// "You got bitch-slapped by X" messages, etc.
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
if( gamenet_man->InNetGame() )
{
GameNet::PlayerInfo* pInfo = gamenet_man->GetPlayerByObjectID( m_id );
Dbg_Assert( pInfo );
// (Mick) don't assign it to m_displayName, as that can cause memory allocations
// and fragments the heap
// ensure you set the appropiate context if you want to do this.
//m_displayName = pInfo->m_Name;
return pInfo->m_Name;
}
return m_displayName.getString();
}
void CSkater::AddCATInfo(Script::CStruct *pStuff)
{
Dbg_MsgAssert(pStuff,("NULL pStuff"));
Script::CArray *p_tricks=new Script::CArray;
p_tricks->SetSizeAndType(Game::vMAX_CREATED_TRICKS,ESYMBOLTYPE_STRUCTURE);
for (int i=0; i<Game::vMAX_CREATED_TRICKS; ++i)
{
Script::CStruct *p_new_trick_struct=new Script::CStruct;
p_new_trick_struct->AddStructure(CRCD(0x26a7cadf,"other"),m_created_trick[i]->mp_other_params);
p_new_trick_struct->AddArray(CRCD(0x6b19fc8f,"animations"),m_created_trick[i]->mp_animations);
p_new_trick_struct->AddArray(CRCD(0x2e628ee6,"rotations"),m_created_trick[i]->mp_rotations);
//Script::PrintContents( p_new_trick_struct );
p_tricks->SetStructure(i,p_new_trick_struct);
}
pStuff->AddArrayPointer(CRCD(0x1e26fd3e,"Tricks"),p_tricks);
}
void CSkater::LoadCATInfo(Script::CStruct *pStuff)
{
printf("LoadCATInfo was called\n");
Dbg_MsgAssert(pStuff,("NULL pStuff"));
Script::CArray *pCATInfo=NULL;
pStuff->GetArray(CRCD(0x1e26fd3e,"tricks"),&pCATInfo);
Dbg_Assert( m_created_trick[1] );
for (int i=0; i<Game::vMAX_CREATED_TRICKS; ++i)
{
Script::CStruct *pTemp=NULL;
pTemp = pCATInfo->GetStructure(i);
// other params
Script::CStruct *p_other_params=NULL;
pTemp->GetStructure(CRCD(0x26a7cadf,"other"),&p_other_params,Script::ASSERT);
m_created_trick[i]->mp_other_params->AppendStructure( p_other_params );
// animations
Script::CArray *p_animation_info=NULL;
pTemp->GetArray(CRCD(0x6b19fc8f,"animations"),&p_animation_info,Script::ASSERT);
Script::CopyArray( m_created_trick[i]->mp_animations, p_animation_info );
// rotations
Script::CArray *p_rotation_info=NULL;
pTemp->GetArray(CRCD(0x2e628ee6,"rotations"),&p_rotation_info,Script::ASSERT);
Script::CopyArray( m_created_trick[i]->mp_rotations, p_rotation_info );
//Script::PrintContents( m_created_trick[i]->mp_other_params );
//Script::PrintContents( m_created_trick[i]->mp_rotations );
}
Script::RunScript(CRCD(0x33fe5817,"kill_load_premade_cats"), NULL);
}
void CSkater::AddStatGoalInfo(Script::CStruct *pStuff)
{
Dbg_MsgAssert(pStuff,("NULL pStuff"));
Script::CArray *p_stat_goals=new Script::CArray;
p_stat_goals->SetSizeAndType(Obj::NUM_STATS_GOALS,ESYMBOLTYPE_INTEGER);
for (int i=0; i<Obj::NUM_STATS_GOALS; ++i)
{
p_stat_goals->SetInteger(i,mp_stats_manager_component->StatGoalGetStatus(i));
}
pStuff->AddArrayPointer(CRCD(0x44b66a9f,"StatGoals"),p_stat_goals);
}
void CSkater::LoadStatGoalInfo(Script::CStruct *pStuff)
{
Dbg_MsgAssert(pStuff,("NULL pStuff"));
// Reset Stats Goals and set to proper difficulty
Script::CStruct* p_params = NULL;
mp_stats_manager_component->RefreshFromStructure(p_params);
Script::CArray *pStatGoalInfo=NULL;
pStuff->GetArray(CRCD(0x44b66a9f,"StatGoals"),&pStatGoalInfo);
for (int i=0; i<Obj::NUM_STATS_GOALS; ++i)
{
mp_stats_manager_component->StatGoalSetStatus(i,pStatGoalInfo->GetInteger(i));
}
}
void CSkater::AddChapterStatusInfo(Script::CStruct *pStuff)
{
Dbg_MsgAssert(pStuff,("NULL pStuff"));
pStuff->AddArray(CRCD(0x8e8ee0c0,"ChapterStatus"),Script::GetArray( CRCD(0xdfa17d68,"CHAPTER_STATUS"), Script::ASSERT ));
}
void CSkater::LoadChapterStatusInfo(Script::CStruct *pStuff)
{
Dbg_MsgAssert(pStuff,("NULL pStuff"));
uint32 Name = Script::GenerateCRC("ChapterStatus");
Script::CArray *pChapterStatusInfo=NULL;
pStuff->GetArray(Name,&pChapterStatusInfo);
Script::CopyArray(Script::GetArray( CRCD(0xdfa17d68,"CHAPTER_STATUS"), Script::ASSERT ), pChapterStatusInfo);
}
} // namespace Obj