/***************************************************************************** ** ** ** 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef TESTING_GUNSLINGER #include #include #endif #include #include #include // for debug lines #include #include #include #include #include #include #include #include #include // for sGetMovableObjects #include #include // for SKATE_TYPE_* #include #include // for CCompetition #include #include // for special goal #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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_numberm_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;linkUsingCustomPark()) // 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; iAddStructure(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; iGetStructure(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; iSetInteger(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; iStatGoalSetStatus(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