#include "precompiled.h" #pragma hdrstop #include "../Game_local.h" #include "../client/ClientModel.h" class repairBotArm_t { public: jointHandle_t joint; int repairTime; bool repairing; rvClientEffectPtr effectRepair; rvClientEffectPtr effectImpact; int periodicEndTime; repairBotArm_t () { periodicEndTime = -1; } void Save ( idSaveGame* savefile ) const; void Restore ( idRestoreGame* savefile ); }; class rvMonsterRepairBot : public idAI { public: CLASS_PROTOTYPE( rvMonsterRepairBot ); rvMonsterRepairBot ( void ); void InitSpawnArgsVariables( void ); void Spawn ( void ); void Save ( idSaveGame *savefile ) const; void Restore ( idRestoreGame *savefile ); virtual void Think ( void ); virtual void GetDebugInfo ( debugInfoProc_t proc, void* userData ); protected: virtual bool CheckActions ( void ); virtual void OnDeath ( void ); int repairEndTime; float repairEffectDist; repairBotArm_t armLeft; repairBotArm_t armRight; private: void UpdateRepairs ( repairBotArm_t& arm ); void StopRepairs ( repairBotArm_t& arm ); // Leg states stateResult_t State_Legs_Move ( const stateParms_t& parms ); stateResult_t State_TorsoAction_Repair ( const stateParms_t& parms ); stateResult_t State_TorsoAction_RepairDone ( const stateParms_t& parms ); CLASS_STATES_PROTOTYPE ( rvMonsterRepairBot ); }; CLASS_DECLARATION( idAI, rvMonsterRepairBot ) END_CLASS /* ================ rvMonsterRepairBot::rvMonsterRepairBot ================ */ rvMonsterRepairBot::rvMonsterRepairBot ( ) { } void rvMonsterRepairBot::InitSpawnArgsVariables( void ) { armLeft.joint = animator.GetJointHandle ( spawnArgs.GetString ( "joint_arm_left", "l_fx" ) ); armRight.joint = animator.GetJointHandle ( spawnArgs.GetString ( "joint_arm_right", "r_fx" ) ); repairEffectDist = spawnArgs.GetFloat( "repairEffectDist", "64" ); } /* ================ rvMonsterRepairBot::Spawn ================ */ void rvMonsterRepairBot::Spawn ( void ) { InitSpawnArgsVariables(); } /* ================ rvMonsterRepairBot::CheckActions ================ */ bool rvMonsterRepairBot::CheckActions ( void ) { return false; } /* ================ rvMonsterRepairBot::OnDeath ================ */ void rvMonsterRepairBot::OnDeath ( void ) { StopRepairs ( armLeft ); StopRepairs ( armRight ); gameLocal.PlayEffect( spawnArgs, "fx_death", GetPhysics()->GetOrigin(), viewAxis ); idAI::OnDeath ( ); } /* ================ rvMonsterRepairBot::Save ================ */ void rvMonsterRepairBot::Save( idSaveGame *savefile ) const { savefile->WriteInt ( repairEndTime ); armLeft.Save ( savefile ); armRight.Save ( savefile ); } /* ================ rvMonsterRepairBot::Restore ================ */ void rvMonsterRepairBot::Restore( idRestoreGame *savefile ) { savefile->ReadInt ( repairEndTime ); armLeft.Restore ( savefile ); armRight.Restore ( savefile ); InitSpawnArgsVariables(); } /* ================ rvMonsterRepairBot::Think ================ */ void rvMonsterRepairBot::Think ( void ) { idAI::Think ( ); // Update repair effects? (dont worry about stopping them, the state ending will do so) UpdateRepairs ( armLeft ); UpdateRepairs ( armRight ); } /* ================ rvMonsterRepairBot::UpdateRepairs ================ */ void rvMonsterRepairBot::UpdateRepairs ( repairBotArm_t& arm ) { trace_t tr; idVec3 origin; idMat3 axis; if ( arm.joint == INVALID_JOINT ) { return; } if ( gameLocal.time > repairEndTime ) { StopRepairs ( arm ) ; return; } // If the repair time has been crossed we need to start/stop the repairs if ( gameLocal.time > arm.repairTime ) { if ( arm.repairing ) { StopRepairs ( arm ); arm.repairTime = gameLocal.time + gameLocal.random.RandomInt ( 500 ); arm.repairing = false; } else { arm.repairTime = gameLocal.time + gameLocal.random.RandomInt ( 2500 ); arm.repairing = true; } } if ( !arm.repairing ) { return; } // Left repair effect GetJointWorldTransform ( arm.joint, gameLocal.time, origin, axis ); gameLocal.TracePoint ( this, tr, origin, origin + axis[0] * repairEffectDist, MASK_SHOT_RENDERMODEL, this ); if ( tr.fraction >= 1.0f ) { StopRepairs ( arm ); } else { // Start the repair effect if not already started if ( !arm.effectRepair ) { arm.effectRepair = PlayEffect ( "fx_repair", arm.joint, true ); } // If the repair effect is running then set its end origin if ( arm.effectRepair ) { arm.effectRepair->SetEndOrigin ( tr.endpos ); } // Start the impact effect if ( !arm.effectImpact ) { arm.effectImpact = PlayEffect ( "fx_repair_impact", tr.endpos, tr.c.normal.ToMat3(), true ); } else { // Calculate the local origin and axis from the given globals idVec3 localOrigin = (tr.endpos - renderEntity.origin) * renderEntity.axis.Transpose ( ); idMat3 localAxis = tr.c.normal.ToMat3 ();// * renderEntity.axis.Transpose(); arm.effectImpact->SetOrigin ( localOrigin ); arm.effectImpact->SetAxis ( localAxis ); } if( gameLocal.GetTime() > arm.periodicEndTime ) {// FIXME: Seems dumb to keep banging on this if the fx isn't defined. gameLocal.PlayEffect( spawnArgs, "fx_repair_impact_periodic", tr.endpos, tr.c.normal.ToMat3() ); arm.periodicEndTime = gameLocal.GetTime() + SEC2MS( rvRandom::flrand(spawnArgs.GetVec2("impact_fx_delay_range", "1 1")) ); } } } /* ================ rvMonsterRepairBot::StopRepairs ================ */ void rvMonsterRepairBot::StopRepairs ( repairBotArm_t& arm ) { if ( arm.effectImpact ) { arm.effectImpact->Stop ( ); arm.effectImpact = NULL; } if ( arm.effectRepair ) { arm.effectRepair->Stop ( ); arm.effectRepair = NULL; } arm.periodicEndTime = -1; } /* ================ rvMonsterRepairBot::GetDebugInfo ================ */ void rvMonsterRepairBot::GetDebugInfo ( debugInfoProc_t proc, void* userData ) { // Base class first idAI::GetDebugInfo ( proc, userData ); } /* =============================================================================== States =============================================================================== */ CLASS_STATES_DECLARATION ( rvMonsterRepairBot ) STATE ( "Legs_Move", rvMonsterRepairBot::State_Legs_Move ) STATE ( "TorsoAction_Repair", rvMonsterRepairBot::State_TorsoAction_Repair ) STATE ( "TorsoAction_RepairDone", rvMonsterRepairBot::State_TorsoAction_RepairDone ) END_CLASS_STATES /* ================ rvMonsterRepairBot::State_Legs_Move ================ */ stateResult_t rvMonsterRepairBot::State_Legs_Move ( const stateParms_t& parms ) { enum { STAGE_START, STAGE_START_WAIT, STAGE_MOVE, STAGE_MOVE_WAIT, STAGE_STOP, STAGE_STOP_WAIT }; switch ( parms.stage ) { case STAGE_START: PlayAnim ( ANIMCHANNEL_LEGS, "idle_to_run", 4 ); return SRESULT_STAGE ( STAGE_START_WAIT ); case STAGE_START_WAIT: if ( AnimDone ( ANIMCHANNEL_LEGS, 4 ) ) { return SRESULT_STAGE ( STAGE_MOVE ); } return SRESULT_WAIT; case STAGE_MOVE: PlayCycle ( ANIMCHANNEL_LEGS, "run", 4 ); return SRESULT_STAGE ( STAGE_MOVE_WAIT ); case STAGE_MOVE_WAIT: if ( !move.fl.moving || !CanMove() ) { return SRESULT_STAGE ( STAGE_STOP ); } return SRESULT_WAIT; case STAGE_STOP: PlayAnim ( ANIMCHANNEL_LEGS, "run_to_idle", 4 ); return SRESULT_STAGE ( STAGE_STOP_WAIT ); case STAGE_STOP_WAIT: if ( AnimDone ( ANIMCHANNEL_LEGS, 4 ) ) { PostAnimState ( ANIMCHANNEL_LEGS, "Legs_Idle", 4 ); return SRESULT_DONE; } return SRESULT_WAIT; } return SRESULT_ERROR; } /* ================ rvMonsterRepairBot::State_TorsoAction_Repair ================ */ stateResult_t rvMonsterRepairBot::State_TorsoAction_Repair ( const stateParms_t& parms ) { enum { STAGE_INIT, STAGE_REPAIR, }; switch ( parms.stage ) { case STAGE_INIT: DisableAnimState ( ANIMCHANNEL_LEGS ); PlayCycle ( ANIMCHANNEL_TORSO, "repair", 4 ); repairEndTime = gameLocal.time + SEC2MS(scriptedActionEnt->spawnArgs.GetInt ( "duration", "5" ) ); PostAnimState ( ANIMCHANNEL_TORSO, "TorsoAction_RepairDone", 0, 0, SFLAG_ONCLEAR ); return SRESULT_STAGE(STAGE_REPAIR); case STAGE_REPAIR: if ( gameLocal.time > repairEndTime ) { return SRESULT_DONE; } return SRESULT_WAIT; } return SRESULT_ERROR; } /* ================ rvMonsterRepairBot::State_TorsoAction_RepairDone ================ */ stateResult_t rvMonsterRepairBot::State_TorsoAction_RepairDone ( const stateParms_t& parms ) { StopRepairs ( armLeft ); StopRepairs ( armRight ); return SRESULT_DONE; } /* ================ repairBotArm_t::Save ================ */ void repairBotArm_t::Save ( idSaveGame* savefile ) const { savefile->WriteInt ( repairTime ); savefile->WriteBool ( repairing ); effectRepair.Save ( savefile ); effectImpact.Save ( savefile ); savefile->WriteInt ( periodicEndTime ); } /* ================ repairBotArm_t::Restore ================ */ void repairBotArm_t::Restore ( idRestoreGame* savefile ) { savefile->ReadInt ( repairTime ); savefile->ReadBool ( repairing ); effectRepair.Restore ( savefile ); effectImpact.Restore ( savefile ); savefile->ReadInt ( periodicEndTime ); }