1512 lines
46 KiB
C++
1512 lines
46 KiB
C++
|
/*
|
||
|
** Command & Conquer Renegade(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program is free software: you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation, either version 3 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
*** Confidential - Westwood Studios ***
|
||
|
***********************************************************************************************
|
||
|
* *
|
||
|
* Project Name : Commando *
|
||
|
* *
|
||
|
* $Archive:: /Commando/Code/Combat/humanstate.cpp $*
|
||
|
* *
|
||
|
* $Author:: Patrick $*
|
||
|
* *
|
||
|
* $Modtime:: 2/26/02 11:47a $*
|
||
|
* *
|
||
|
* $Revision:: 169 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
/*
|
||
|
** Includes
|
||
|
*/
|
||
|
#include "humanstate.h"
|
||
|
#include "debug.h"
|
||
|
#include "animcontrol.h"
|
||
|
#include "humanphys.h"
|
||
|
#include "weapons.h"
|
||
|
#include "assets.h"
|
||
|
#include "combat.h"
|
||
|
#include "combat.h"
|
||
|
#include "physcoltest.h"
|
||
|
#include "pscene.h"
|
||
|
#include <stdio.h>
|
||
|
#include "timemgr.h"
|
||
|
#include "definitionclassids.h"
|
||
|
#include "pathfind.h"
|
||
|
#include "encoderlist.h"
|
||
|
#include "bitpackids.h"
|
||
|
#include "humanrecoil.h"
|
||
|
#include "globalsettings.h"
|
||
|
#include "combatchunkid.h"
|
||
|
#include "wwprofile.h"
|
||
|
#include "surfaceeffects.h"
|
||
|
#include "crandom.h"
|
||
|
#include "gametype.h"
|
||
|
#include "soldier.h"
|
||
|
#include "damage.h"
|
||
|
#include "transitioneffect.h"
|
||
|
#include "combatmaterialeffectmanager.h"
|
||
|
|
||
|
/*
|
||
|
** Static instance of HumanRecoilClass for recoil calculations
|
||
|
*/
|
||
|
static HumanRecoilClass _TheRecoiler;
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************************************
|
||
|
**
|
||
|
** HumanStateClass Implementation
|
||
|
**
|
||
|
******************************************************************************************/
|
||
|
|
||
|
HumanStateClass::HumanStateClass( void ) :
|
||
|
State( UPRIGHT ),
|
||
|
StateFlags( 0 ),
|
||
|
StateTimer( 0 ),
|
||
|
SubState( 0 ),
|
||
|
StateLocked( false ),
|
||
|
AnimControl( NULL ),
|
||
|
WeaponHoldStyle(WEAPON_HOLD_STYLE_EMPTY_HANDS),
|
||
|
HumanPhys( NULL ),
|
||
|
TurnVelocity( 0 ),
|
||
|
AimingTilt( 0 ),
|
||
|
AimingTurn( 0 ),
|
||
|
RecoilTimer( 0.0f ),
|
||
|
RecoilScale( 1.0f ),
|
||
|
LoiterDelay( 0 ),
|
||
|
LoitersAllowed( true ),
|
||
|
LegRotation( 0 ),
|
||
|
WeaponHoldTimer( 0 ),
|
||
|
NoAnimBlend( false ),
|
||
|
HumanAnimOverride( NULL ),
|
||
|
HumanLoiterCollection( NULL ),
|
||
|
WeaponFired( false )
|
||
|
{
|
||
|
Reset_Loiter_Delay();
|
||
|
}
|
||
|
|
||
|
HumanStateClass::~HumanStateClass( void )
|
||
|
{
|
||
|
if ( HumanPhys != NULL ) {
|
||
|
HumanPhys->Release_Ref();
|
||
|
HumanPhys = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Init( HumanPhysClass * human_phys )
|
||
|
{
|
||
|
WWASSERT( HumanPhys == NULL );
|
||
|
WWASSERT( human_phys != NULL );
|
||
|
|
||
|
HumanPhys = human_phys;
|
||
|
HumanPhys->Add_Ref();
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Reset( void )
|
||
|
{
|
||
|
REF_PTR_RELEASE( HumanPhys );
|
||
|
|
||
|
// Clear the sniping flag
|
||
|
if ( Get_State_Flag( SNIPING_FLAG ) ) {
|
||
|
Toggle_State_Flag( SNIPING_FLAG );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Set_Anim_Control( HumanAnimControlClass * anim_control )
|
||
|
{
|
||
|
WWASSERT( AnimControl == NULL || AnimControl == anim_control );
|
||
|
WWASSERT( anim_control != NULL );
|
||
|
AnimControl = anim_control;
|
||
|
AnimControl->Set_Model( HumanPhys->Peek_Model() );
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Set_Human_Anim_Override( const char * name )
|
||
|
{
|
||
|
HumanAnimOverride = (HumanAnimOverrideDef *)DefinitionMgrClass::Find_Typed_Definition( name,
|
||
|
CLASSID_GLOBAL_SETTINGS_DEF_HUMAN_ANIM_OVERRIDE );
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Set_Human_Anim_Override( int def_id )
|
||
|
{
|
||
|
HumanAnimOverride = (HumanAnimOverrideDef *)DefinitionMgrClass::Find_Definition( def_id );
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Set_Human_Loiter_Collection( int def_id )
|
||
|
{
|
||
|
HumanLoiterCollection = (HumanLoiterGlobalSettingsDef *)DefinitionMgrClass::Find_Definition( def_id );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** CommandoHumanState Save and Load
|
||
|
*/
|
||
|
enum {
|
||
|
CHUNKID_VARIABLES = 915991207,
|
||
|
XXX_CHUNKID_ANIM_CONTROL,
|
||
|
|
||
|
MICROCHUNKID_STATE = 1,
|
||
|
MICROCHUNKID_SUB_STATE,
|
||
|
MICROCHUNKID_STATE_LOCKED,
|
||
|
MICROCHUNKID_WEAPON_HOLD_STYLE,
|
||
|
XXXMICROCHUNKID_WEAPON_STATE,
|
||
|
MICROCHUNKID_AIMING_TILT,
|
||
|
MICROCHUNKID_AIMING_TURN,
|
||
|
MICROCHUNKID_TURN_VELOCITY,
|
||
|
MICROCHUNKID_PHYSOBJ,
|
||
|
MICROCHUNKID_LOITER_DELAY,
|
||
|
MICROCHUNKID_STATE_FLAGS,
|
||
|
MICROCHUNKID_JUMP_TM,
|
||
|
MICROCHUNKID_STATE_TIMER,
|
||
|
MICROCHUNKID_LOITERS_ALLOWED,
|
||
|
MICROCHUNKID_WEAPON_HOLD_TIMER,
|
||
|
MICROCHUNKID_HUMAN_ANIM_OVERRIDE_DEF_ID,
|
||
|
MICROCHUNKID_HUMAN_LOITER_COLLECTION_DEF_ID,
|
||
|
};
|
||
|
|
||
|
bool HumanStateClass::Save( ChunkSaveClass & csave )
|
||
|
{
|
||
|
csave.Begin_Chunk( CHUNKID_VARIABLES );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE, State );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE_FLAGS, StateFlags );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SUB_STATE, SubState );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE_LOCKED, StateLocked );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_WEAPON_HOLD_STYLE, WeaponHoldStyle );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_AIMING_TILT, AimingTilt );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_AIMING_TURN, AimingTurn );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TURN_VELOCITY, TurnVelocity );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_PHYSOBJ, HumanPhys );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_LOITER_DELAY, LoiterDelay );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_LOITERS_ALLOWED, LoitersAllowed );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_JUMP_TM, JumpTM );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE_TIMER, StateTimer );
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_WEAPON_HOLD_TIMER, WeaponHoldTimer );
|
||
|
|
||
|
if ( HumanAnimOverride != NULL ) {
|
||
|
int id = HumanAnimOverride->Get_ID();
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_HUMAN_ANIM_OVERRIDE_DEF_ID, id );
|
||
|
}
|
||
|
|
||
|
if ( HumanLoiterCollection != NULL ) {
|
||
|
int id = HumanLoiterCollection->Get_ID();
|
||
|
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_HUMAN_LOITER_COLLECTION_DEF_ID, id );
|
||
|
}
|
||
|
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
// Don't need to save AnimControl, it gets set externally
|
||
|
// We don't save recoil states
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool HumanStateClass::Load( ChunkLoadClass &cload )
|
||
|
{
|
||
|
int human_anim_override_def_id = 0;
|
||
|
int human_loiter_collection_def_id = 0;
|
||
|
|
||
|
WWASSERT( HumanPhys == NULL );
|
||
|
|
||
|
while (cload.Open_Chunk()) {
|
||
|
switch(cload.Cur_Chunk_ID()) {
|
||
|
|
||
|
case CHUNKID_VARIABLES:
|
||
|
|
||
|
WWASSERT( HumanPhys == NULL );
|
||
|
|
||
|
while (cload.Open_Micro_Chunk()) {
|
||
|
WWASSERT(SubState >= 0 && SubState <= HIGHEST_HUMAN_SUB_STATE);
|
||
|
|
||
|
switch(cload.Cur_Micro_Chunk_ID()) {
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE, State );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE_FLAGS, StateFlags );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_SUB_STATE, SubState );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE_LOCKED, StateLocked );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_WEAPON_HOLD_STYLE, WeaponHoldStyle );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_AIMING_TILT, AimingTilt );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_AIMING_TURN, AimingTurn );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_TURN_VELOCITY, TurnVelocity );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_PHYSOBJ, HumanPhys );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_LOITER_DELAY, LoiterDelay );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_LOITERS_ALLOWED, LoitersAllowed );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_JUMP_TM, JumpTM );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE_TIMER, StateTimer );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_WEAPON_HOLD_TIMER, WeaponHoldTimer );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_HUMAN_ANIM_OVERRIDE_DEF_ID, human_anim_override_def_id );
|
||
|
READ_MICRO_CHUNK( cload, MICROCHUNKID_HUMAN_LOITER_COLLECTION_DEF_ID, human_loiter_collection_def_id );
|
||
|
|
||
|
default:
|
||
|
Debug_Say(( "Unrecognized Human Variable chunkID\n" ));
|
||
|
break;
|
||
|
}
|
||
|
cload.Close_Micro_Chunk();
|
||
|
}
|
||
|
|
||
|
WWASSERT( HumanPhys != NULL );
|
||
|
|
||
|
if ( HumanPhys != NULL ) {
|
||
|
REQUEST_REF_COUNTED_POINTER_REMAP( (RefCountClass **)&HumanPhys );
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Debug_Say(( "Unrecognized Human chunkID\n" ));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
cload.Close_Chunk();
|
||
|
}
|
||
|
|
||
|
if ( human_anim_override_def_id != 0 ) {
|
||
|
Set_Human_Anim_Override( human_anim_override_def_id );
|
||
|
}
|
||
|
|
||
|
if ( human_loiter_collection_def_id != 0 ) {
|
||
|
Set_Human_Loiter_Collection( human_loiter_collection_def_id );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
void HumanStateClass::Update_Weapon( WeaponClass * weapon, bool new_weapon )
|
||
|
{
|
||
|
WWPROFILE( "Human Weapon" );
|
||
|
|
||
|
Update_Recoil(weapon);
|
||
|
|
||
|
int new_hold_style = WeaponHoldStyle;
|
||
|
|
||
|
WeaponFired = false;
|
||
|
|
||
|
if ( weapon ) {
|
||
|
|
||
|
if ( weapon->Is_Reloading() ) {
|
||
|
Raise_Weapon();
|
||
|
}
|
||
|
|
||
|
weapon->Set_Safety( WeaponHoldStyle > WEAPON_HOLD_STYLE_EMPTY_HANDS );
|
||
|
|
||
|
// Only humans can cansider weapons firing in state
|
||
|
if ( weapon->Get_Owner() &&
|
||
|
weapon->Get_Owner()->As_SoldierGameObj() &&
|
||
|
weapon->Get_Owner()->As_SoldierGameObj()->Is_Human_Controlled() ) {
|
||
|
WeaponFired = weapon->Is_Firing();
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( weapon->Is_Triggered() || new_weapon || Get_State_Flag( CROUCHED_FLAG ) ) {
|
||
|
if ( weapon->Is_Safety_Set() ) { // Don't blend anim when un-safetying
|
||
|
NoAnimBlend = true;
|
||
|
}
|
||
|
Raise_Weapon(); // Reset the drop timer
|
||
|
new_hold_style = weapon->Get_Style(); // Take the new style
|
||
|
}
|
||
|
|
||
|
if ( WeaponHoldTimer > 0 ) {
|
||
|
if ( WeaponHoldStyle > WEAPON_HOLD_STYLE_EMPTY_HANDS ) {
|
||
|
new_hold_style = weapon->Get_Style(); // Take the new style
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
new_hold_style = WEAPON_HOLD_STYLE_EMPTY_HANDS;
|
||
|
}
|
||
|
|
||
|
if ( new_hold_style == WeaponHoldStyle ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
WeaponHoldStyle = new_hold_style;
|
||
|
|
||
|
if ( !StateLocked ) {
|
||
|
Update_Animation();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Update_Aiming( float tilt, float turn )
|
||
|
{
|
||
|
if ( (AimingTilt == tilt) && (AimingTurn == turn) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
AimingTilt = tilt;
|
||
|
AimingTurn = turn;
|
||
|
|
||
|
if ( !StateLocked ) {
|
||
|
Update_Animation();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Update_Recoil(WeaponClass * weapon)
|
||
|
{
|
||
|
// Programatic Recoil System. This code needs to run once per frame.
|
||
|
if ((weapon != NULL) && (weapon->Is_Firing())) {
|
||
|
|
||
|
// Set our recoil timer and capture all of the necessary bones
|
||
|
// I'm copying all necessary data out of the weapon in case the weapon goes
|
||
|
// away before our recoil is finished.
|
||
|
RecoilTimer = weapon->Get_Recoil_Time();
|
||
|
RecoilScale = weapon->Get_Recoil_Scale();
|
||
|
if (RecoilTimer > 0.0f) {
|
||
|
RecoilScale *= 1.0f / RecoilTimer;
|
||
|
_TheRecoiler.Capture_Bones(HumanPhys->Peek_Model());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (RecoilTimer > 0.0f) {
|
||
|
|
||
|
// Apply the recoil effect.
|
||
|
Matrix3D recoil_tm(1);
|
||
|
recoil_tm.Rotate_Z( HumanPhys->Get_Facing() );
|
||
|
recoil_tm.Rotate_Y( -AimingTilt );
|
||
|
float recoil_scale = RecoilScale * RecoilTimer;
|
||
|
_TheRecoiler.Apply_Recoil( recoil_tm,HumanPhys->Peek_Model(),recoil_scale);
|
||
|
|
||
|
// Decrement the recoil timer and release the bones if it expires
|
||
|
RecoilTimer -= TimeManager::Get_Frame_Seconds();
|
||
|
if (RecoilTimer <= 0.0f) {
|
||
|
RecoilTimer = 0.0f;
|
||
|
_TheRecoiler.Release_Bones(HumanPhys->Peek_Model());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Set_State( HumanStateType state, int sub_state )
|
||
|
{
|
||
|
// Special case for death
|
||
|
if (( State == DEATH ) || ( State == DESTROY )) {
|
||
|
if ( state != DESTROY ) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( ( State != DEATH ) && ( state == DEATH ) ) {
|
||
|
StateLocked = false;
|
||
|
}
|
||
|
|
||
|
if ( StateLocked ) {
|
||
|
if ( state != DEATH ) {
|
||
|
// Temp Test
|
||
|
// Debug_Say(( "State is Locked. Can't change from %d to %d\n", State, state ));
|
||
|
// return;
|
||
|
}
|
||
|
|
||
|
#pragma MESSAGE( "StateLocked Hack" )
|
||
|
if ( !IS_SOLOPLAY ) { // E3 HACK
|
||
|
StateLocked = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( State == state && SubState == sub_state ) {
|
||
|
if (CombatManager::I_Am_Server()) {
|
||
|
Debug_Say(( "Already in this state\n" ));
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Debug_Say(( "%p Set State %d, %x from %d\n", this, state, sub_state, State ));
|
||
|
State = state;
|
||
|
SubState = sub_state;
|
||
|
StateTimer = 0;
|
||
|
|
||
|
if (( State == LADDER ) || ( State == IN_VEHICLE ) ||
|
||
|
( State == TRANSITION ) || ( State == TRANSITION_COMPLETE ) ||
|
||
|
( State == DEBUG_FLY ) ) {
|
||
|
HumanPhys->Enable_User_Control( true );
|
||
|
} else {
|
||
|
HumanPhys->Enable_User_Control( false );
|
||
|
}
|
||
|
|
||
|
// Turn off shadows in vehicles
|
||
|
#pragma message ("(gth) shadow review hacking")
|
||
|
#if 0
|
||
|
if ( State == IN_VEHICLE ) {
|
||
|
HumanPhys->Enable_Shadow_Generation( false );
|
||
|
} else {
|
||
|
HumanPhys->Enable_Shadow_Generation( true );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if ( ( State == IN_VEHICLE ) || ( State == TRANSITION ) || ( State == TRANSITION_COMPLETE ) ) {
|
||
|
HumanPhys->Set_Collision_Group( BULLET_ONLY_COLLISION_GROUP );
|
||
|
HumanPhys->Set_Immovable( true );
|
||
|
} else if ( ( State == DESTROY ) || ( State == DEATH ) ) {
|
||
|
HumanPhys->Set_Collision_Group( TERRAIN_ONLY_COLLISION_GROUP );
|
||
|
HumanPhys->Set_Immovable( true );
|
||
|
} else {
|
||
|
HumanPhys->Set_Collision_Group( SOLDIER_COLLISION_GROUP );
|
||
|
HumanPhys->Set_Immovable( false );
|
||
|
}
|
||
|
|
||
|
Update_Animation();
|
||
|
}
|
||
|
|
||
|
|
||
|
bool HumanStateClass::Is_State_Interruptable( void )
|
||
|
{
|
||
|
return (State == UPRIGHT) || (State == WOUNDED) || (State == LAND) || (State == LOITER) || (State == ANIMATION);
|
||
|
}
|
||
|
|
||
|
|
||
|
#define ADD_CASE(exp) case exp: return #exp; break;
|
||
|
const char * HumanStateClass::Get_State_Name( void )
|
||
|
{
|
||
|
switch (State) {
|
||
|
ADD_CASE(UPRIGHT);
|
||
|
ADD_CASE(LAND);
|
||
|
ADD_CASE(ANIMATION);
|
||
|
ADD_CASE(WOUNDED);
|
||
|
ADD_CASE(LOITER);
|
||
|
ADD_CASE(AIRBORNE);
|
||
|
ADD_CASE(DIVE);
|
||
|
ADD_CASE(DEATH);
|
||
|
ADD_CASE(LADDER);
|
||
|
ADD_CASE(IN_VEHICLE);
|
||
|
ADD_CASE(TRANSITION);
|
||
|
ADD_CASE(TRANSITION_COMPLETE);
|
||
|
ADD_CASE(DESTROY);
|
||
|
ADD_CASE(DEBUG_FLY);
|
||
|
ADD_CASE(ON_FIRE);
|
||
|
ADD_CASE(ON_CHEM);
|
||
|
ADD_CASE(ON_ELECTRIC);
|
||
|
ADD_CASE(ON_CNC_FIRE);
|
||
|
ADD_CASE(ON_CNC_CHEM);
|
||
|
ADD_CASE(LOCKED_ANIMATION);
|
||
|
|
||
|
default:
|
||
|
WWASSERT(0);
|
||
|
return ""; // to avoid compiler warning
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Set_Sub_State( int sub_state )
|
||
|
{
|
||
|
if ( Is_Sub_State_Adjustable() ) {
|
||
|
if ( SubState != sub_state ) {
|
||
|
WWASSERT(sub_state >= 0 && sub_state <= HIGHEST_HUMAN_SUB_STATE);
|
||
|
SubState = sub_state;
|
||
|
Update_Animation();
|
||
|
}
|
||
|
} else {
|
||
|
Debug_Say(( "Can't adjust state %s", Get_State_Name() ));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool HumanStateClass::Is_Sub_State_Adjustable( void )
|
||
|
{
|
||
|
return (State == UPRIGHT) || (State == LADDER);
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Start_Transition_Animation( const char * anim_name, bool blend )
|
||
|
{
|
||
|
if ( StateLocked ) {
|
||
|
Debug_Say(( "State is Locked. Can't Start Transition Anim %s\n", anim_name ));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//Debug_Say(("Start_Transition_Animation %s\n", anim_name));
|
||
|
|
||
|
if (( Get_State() == DEATH ) || ( Get_State() == DESTROY ) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
Set_State( TRANSITION );
|
||
|
|
||
|
float blend_time = blend ? 0.2 : 0;
|
||
|
AnimControl->Set_Animation( anim_name, blend_time );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_ONCE );
|
||
|
AnimControl->Update( 0 ); // update
|
||
|
StateLocked = true;
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Start_Scripted_Animation( const char * anim_name, bool blend, bool looping )
|
||
|
{
|
||
|
#if 0
|
||
|
if ( StateLocked ) {
|
||
|
Debug_Say(( "State is Locked. Can't Start Transition Anim %s\n", anim_name ));
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//Debug_Say(("Start_Scripted_Animation %s\n", anim_name));
|
||
|
|
||
|
// We used to not start a scripted anim when wounded, but then the scripts couldn't set
|
||
|
// up custom events well. So I am gonna try to remove the wounded check
|
||
|
// 8/17/01 Byon
|
||
|
// if (( Get_State() == DEATH ) || ( Get_State() == DESTROY ) || ( Get_State() == WOUNDED )) {
|
||
|
if (( Get_State() == DEATH ) || ( Get_State() == DESTROY ) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
Set_State( ANIMATION );
|
||
|
|
||
|
float blend_time = blend ? 0.2 : 0;
|
||
|
AnimControl->Set_Animation( anim_name, blend_time );
|
||
|
AnimControl->Set_Mode( looping ? ANIM_MODE_LOOP : ANIM_MODE_ONCE );
|
||
|
AnimControl->Update( 0 ); // update
|
||
|
StateLocked = true;
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Stop_Scripted_Animation( void )
|
||
|
{
|
||
|
if ( State != ANIMATION && State != LOCKED_ANIMATION ) {
|
||
|
// Debug_Say(( "Not in a Scripted Animation to stop\n" ));
|
||
|
|
||
|
// Better clear the locked state. This was keeping us in the place beacon mode
|
||
|
StateLocked = false;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
StateLocked = false;
|
||
|
Set_State( UPRIGHT );
|
||
|
// AnimControl->Lock_Animation();
|
||
|
}
|
||
|
|
||
|
void HumanStateClass::Force_Animation( const char * anim_name, bool blend )
|
||
|
{
|
||
|
//Debug_Say(( "Forcing Animation to %s\n", anim_name ));
|
||
|
float blend_time = blend ? 0.2 : 0;
|
||
|
AnimControl->Set_Animation( anim_name, blend_time );
|
||
|
AnimControl->Update( 0 ); // update
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
typedef enum {
|
||
|
LEG_STYLE_STAND, // A0
|
||
|
LEG_STYLE_RUN_FORWARD, // A1
|
||
|
LEG_STYLE_RUN_BACKWARD, // A2
|
||
|
LEG_STYLE_RUN_LEFT, // A3
|
||
|
LEG_STYLE_RUN_RIGHT, // A4
|
||
|
LEG_STYLE_TURN_LEFT, // A5
|
||
|
LEG_STYLE_TURN_RIGHT, // A6
|
||
|
LEG_STYLE_WALK_FORWARD, // B1
|
||
|
LEG_STYLE_WALK_BACKWARD, // B2
|
||
|
LEG_STYLE_WALK_LEFT, // B3
|
||
|
LEG_STYLE_WALK_RIGHT, // B4
|
||
|
LEG_STYLE_CROUCH, // C0
|
||
|
LEG_STYLE_CROUCH_MOVE_FORWARD, // C1
|
||
|
LEG_STYLE_CROUCH_MOVE_BACKWARD, // C2
|
||
|
LEG_STYLE_CROUCH_MOVE_LEFT, // C3
|
||
|
LEG_STYLE_CROUCH_MOVE_RIGHT, // C4
|
||
|
LEG_STYLE_CROUCH_TURN_LEFT, // C3
|
||
|
LEG_STYLE_CROUCH_TURN_RIGHT, // C4
|
||
|
LEG_STYLE_JUMP_UP, // D0
|
||
|
LEG_STYLE_JUMP_FORWARD, // D1
|
||
|
LEG_STYLE_JUMP_BACKWARD, // D2
|
||
|
LEG_STYLE_JUMP_LEFT, // D3
|
||
|
LEG_STYLE_JUMP_RIGHT, // D4
|
||
|
} HUMAN_ANIM_LEG_STYLE;
|
||
|
|
||
|
static const char * LegAnimNames[] = {
|
||
|
"A0", // LEG_STYLE_STAND,
|
||
|
"A1", // LEG_STYLE_RUN_FORWARD,
|
||
|
"A2", // LEG_STYLE_RUN_BACKWARD,
|
||
|
"A3", // LEG_STYLE_RUN_LEFT,
|
||
|
"A4", // LEG_STYLE_RUN_RIGHT,
|
||
|
"A5", // LEG_STYLE_TURN_LEFT,
|
||
|
"A6", // LEG_STYLE_TURN_RIGHT,
|
||
|
"B1", // LEG_STYLE_WALK_FORWARD,
|
||
|
"B2", // LEG_STYLE_WALK_BACKWARD,
|
||
|
"B3", // LEG_STYLE_WALK_LEFT,
|
||
|
"B4", // LEG_STYLE_WALK_RIGHT,
|
||
|
"C0", // LEG_STYLE_CROUCH,
|
||
|
"C1", // LEG_STYLE_CROUCH_MOVE_FORWARD,
|
||
|
"C2", // LEG_STYLE_CROUCH_MOVE_BACKWARD,
|
||
|
"C3", // LEG_STYLE_CROUCH_MOVE_LEFT,
|
||
|
"C4", // LEG_STYLE_CROUCH_MOVE_RIGHT,
|
||
|
"C5", // LEG_STYLE_CROUCH_TURN_LEFT,
|
||
|
"C6", // LEG_STYLE_CROUCH_TURN_RIGHT,
|
||
|
"J0", // LEG_STYLE_JUMP_UP,
|
||
|
"J1", // LEG_STYLE_JUMP_FORWARD,
|
||
|
"J2", // LEG_STYLE_JUMP_BACKWARD,
|
||
|
"J3", // LEG_STYLE_JUMP_LEFT,
|
||
|
"J4", // LEG_STYLE_JUMP_RIGHT,
|
||
|
};
|
||
|
|
||
|
static const char * _weapon_style_names[ NUM_WEAPON_HOLD_STYLES ] = {
|
||
|
"A0", //WEAPON_HOLD_STYLE_C4 = 0,
|
||
|
"A0", //WEAPON_HOLD_STYLE_NOT_USED,
|
||
|
"C2", //WEAPON_HOLD_STYLE_AT_SHOULDER, // 2
|
||
|
"D2", //WEAPON_HOLD_STYLE_AT_HIP,
|
||
|
"E2", //WEAPON_HOLD_STYLE_LAUNCHER,
|
||
|
"F2", //WEAPON_HOLD_STYLE_HANDGUN,
|
||
|
"A0", //WEAPON_HOLD_STYLE_BEACON
|
||
|
"A0", //WEAPON_HOLD_STYLE_EMPTY_HANDS,
|
||
|
"B0", //WEAPON_HOLD_STYLE_AT_CHEST,
|
||
|
"A0", //WEAPON_HOLD_STYLE_HANDS_DOWN,
|
||
|
};
|
||
|
|
||
|
static const char * _dive_anims[ 4 * 2 ] = {
|
||
|
// Forwrd Anims
|
||
|
"S_A_HUMAN.H_A_SLD1_01",
|
||
|
"S_A_HUMAN.H_A_SLD1_02",
|
||
|
|
||
|
// Backward anims
|
||
|
"S_A_HUMAN.H_A_SLD2_01",
|
||
|
"S_A_HUMAN.H_A_SLD2_02",
|
||
|
|
||
|
// Left anims
|
||
|
"S_A_HUMAN.H_A_SLD3_01",
|
||
|
"S_A_HUMAN.H_A_SLD3_02",
|
||
|
|
||
|
// Right Anims
|
||
|
"S_A_HUMAN.H_A_SLD4_01",
|
||
|
"S_A_HUMAN.H_A_SLD4_02",
|
||
|
|
||
|
};
|
||
|
|
||
|
// Weapons style, weapon action, recoil, blend, vehicle, mix/math, aiming tilt
|
||
|
void HumanStateClass::Update_Animation( void )
|
||
|
{
|
||
|
WWPROFILE( "Human Animation" );
|
||
|
|
||
|
// no updates for visceroids
|
||
|
if ( AnimControl->Get_Skeleton() == 'V' ) {
|
||
|
StateLocked = true;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( StateLocked ) {
|
||
|
// Debug_Say(( "ERROR: updating animation when locked\n" ));
|
||
|
return;
|
||
|
// if you change your animn when locked, death state may clear a scripted anim
|
||
|
}
|
||
|
|
||
|
int hold_style = WeaponHoldStyle;
|
||
|
|
||
|
// Setup animation for state, substate, weapon, tilt, etc.
|
||
|
if ( (State == UPRIGHT) || (State == AIRBORNE) ) {
|
||
|
// determine leg style
|
||
|
int leg_style = LEG_STYLE_STAND;
|
||
|
if ( State == AIRBORNE ) {
|
||
|
|
||
|
leg_style = LEG_STYLE_JUMP_UP;
|
||
|
if ( SubState & SUB_STATE_LEFT ) leg_style = LEG_STYLE_JUMP_LEFT;
|
||
|
if ( SubState & SUB_STATE_RIGHT ) leg_style = LEG_STYLE_JUMP_RIGHT;
|
||
|
if ( SubState & SUB_STATE_FORWARD ) leg_style = LEG_STYLE_JUMP_FORWARD;
|
||
|
if ( SubState & SUB_STATE_BACKWARD ) leg_style = LEG_STYLE_JUMP_BACKWARD;
|
||
|
|
||
|
} else {
|
||
|
if ( SubState & SUB_STATE_TURN_LEFT ) leg_style = LEG_STYLE_TURN_LEFT;
|
||
|
if ( SubState & SUB_STATE_TURN_RIGHT ) leg_style = LEG_STYLE_TURN_RIGHT;
|
||
|
if ( SubState & SUB_STATE_LEFT ) leg_style = LEG_STYLE_RUN_LEFT;
|
||
|
if ( SubState & SUB_STATE_RIGHT ) leg_style = LEG_STYLE_RUN_RIGHT;
|
||
|
if ( SubState & SUB_STATE_FORWARD ) leg_style = LEG_STYLE_RUN_FORWARD;
|
||
|
if ( SubState & SUB_STATE_BACKWARD ) leg_style = LEG_STYLE_RUN_BACKWARD;
|
||
|
|
||
|
if ( Get_State_Flag( CROUCHED_FLAG ) ) {
|
||
|
|
||
|
// Tend to hold at chest when crouched
|
||
|
if ( ( hold_style == WEAPON_HOLD_STYLE_HANDS_DOWN ) ||
|
||
|
( hold_style == WEAPON_HOLD_STYLE_C4 ) ||
|
||
|
( hold_style == WEAPON_HOLD_STYLE_BEACON ) ) {
|
||
|
|
||
|
hold_style = WEAPON_HOLD_STYLE_AT_CHEST;
|
||
|
}
|
||
|
|
||
|
leg_style += LEG_STYLE_CROUCH - LEG_STYLE_STAND;
|
||
|
} else if ( SubState & SUB_STATE_SLOW ) {
|
||
|
if ( ( leg_style >= LEG_STYLE_RUN_FORWARD ) &&
|
||
|
( leg_style <= LEG_STYLE_RUN_RIGHT ) ) {
|
||
|
leg_style += LEG_STYLE_WALK_FORWARD - LEG_STYLE_RUN_FORWARD;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char * leg_anim_name = LegAnimNames[ leg_style ];
|
||
|
const char * torso_anim_name = _weapon_style_names[hold_style];
|
||
|
|
||
|
bool single_anim = true;
|
||
|
|
||
|
float blend_time = 0.2f;
|
||
|
if ( NoAnimBlend ) {
|
||
|
blend_time = 0;
|
||
|
NoAnimBlend = false;
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( torso_anim_name[1] == '2' ) {
|
||
|
// Lets try aiming
|
||
|
StringClass anim1_name(0,true);
|
||
|
StringClass anim2_name(0,true);
|
||
|
StringClass anim3_name(0,true);
|
||
|
anim1_name.Format( "S_A_HUMAN.H_A_%c1%s", 'A' + hold_style, leg_anim_name );
|
||
|
anim2_name.Format( "S_A_HUMAN.H_A_%c2%s", 'A' + hold_style, leg_anim_name );
|
||
|
anim3_name.Format( "S_A_HUMAN.H_A_%c3%s", 'A' + hold_style, leg_anim_name );
|
||
|
|
||
|
// See if we have the tilting data
|
||
|
HAnimClass * anim = WW3DAssetManager::Get_Instance()->Get_HAnim( anim3_name );
|
||
|
if ( anim != NULL ) {
|
||
|
anim->Release_Ref();
|
||
|
single_anim = false;
|
||
|
|
||
|
float tilt_blend = WWMath::Clamp( (AimingTilt / DEG_TO_RADF( 65 )), -1, 1 );
|
||
|
float frame = AnimControl->Get_Frame(); // Maintain the frame number for moving
|
||
|
if ( tilt_blend < 0 ) {
|
||
|
AnimControl->Set_Animation( anim1_name, anim2_name, 1+tilt_blend, blend_time );
|
||
|
} else {
|
||
|
AnimControl->Set_Animation( anim3_name, anim2_name, 1-tilt_blend, blend_time );
|
||
|
}
|
||
|
|
||
|
AnimControl->Set_Mode( ANIM_MODE_LOOP, frame );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( single_anim ) {
|
||
|
|
||
|
StringClass anim_name(0,true);
|
||
|
anim_name.Format( "S_A_HUMAN.H_A_%s%s", torso_anim_name, leg_anim_name );
|
||
|
|
||
|
// Human Anim Override
|
||
|
if ( HumanAnimOverride != NULL ) {
|
||
|
if ( hold_style == WEAPON_HOLD_STYLE_EMPTY_HANDS ) {
|
||
|
if ( leg_style == LEG_STYLE_RUN_FORWARD ) {
|
||
|
anim_name = HumanAnimOverride->RunEmptyHands;
|
||
|
}
|
||
|
if ( leg_style == LEG_STYLE_WALK_FORWARD ) {
|
||
|
anim_name = HumanAnimOverride->WalkEmptyHands;
|
||
|
}
|
||
|
}
|
||
|
if ( hold_style == WEAPON_HOLD_STYLE_AT_CHEST ) {
|
||
|
if ( leg_style == LEG_STYLE_RUN_FORWARD ) {
|
||
|
anim_name = HumanAnimOverride->RunAtChest;
|
||
|
}
|
||
|
if ( leg_style == LEG_STYLE_WALK_FORWARD ) {
|
||
|
anim_name = HumanAnimOverride->WalkAtChest;
|
||
|
}
|
||
|
}
|
||
|
if ( hold_style == WEAPON_HOLD_STYLE_AT_HIP ) {
|
||
|
if ( leg_style == LEG_STYLE_RUN_FORWARD ) {
|
||
|
anim_name = HumanAnimOverride->RunAtHip;
|
||
|
}
|
||
|
if ( leg_style == LEG_STYLE_WALK_FORWARD ) {
|
||
|
anim_name = HumanAnimOverride->WalkAtHip;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Saftey check anim
|
||
|
// Debug_Say(( "Anim name %s\n", (const char *)anim_name ));
|
||
|
|
||
|
// float frame = AnimControl->Get_Frame(); // Maintain the frame number for moving
|
||
|
AnimControl->Set_Animation( anim_name, blend_time );
|
||
|
// AnimControl->Set_Mode( ANIM_MODE_LOOP, frame );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_LOOP );
|
||
|
}
|
||
|
|
||
|
} else if ( State == DIVE ) {
|
||
|
|
||
|
|
||
|
const char * anim_name = NULL;
|
||
|
#if 0
|
||
|
if ( SubState & SUB_STATE_LEFT ) anim_name = "S_A_HUMAN.H_A_DIV3";
|
||
|
if ( SubState & SUB_STATE_RIGHT ) anim_name = "S_A_HUMAN.H_A_DIV4";
|
||
|
if ( SubState & SUB_STATE_FORWARD ) anim_name = "S_A_HUMAN.H_A_DIV1";
|
||
|
if ( SubState & SUB_STATE_BACKWARD ) anim_name = "S_A_HUMAN.H_A_DIV2";
|
||
|
#else
|
||
|
int offset = FreeRandom.Get_Int( 2 );
|
||
|
if ( !IS_SOLOPLAY ) {
|
||
|
offset = 0;
|
||
|
}
|
||
|
if ( SubState & SUB_STATE_FORWARD ) offset += 0;
|
||
|
if ( SubState & SUB_STATE_BACKWARD ) offset += 2;
|
||
|
if ( SubState & SUB_STATE_LEFT ) offset += 4;
|
||
|
if ( SubState & SUB_STATE_RIGHT ) offset += 6;
|
||
|
anim_name = _dive_anims[offset];
|
||
|
#endif
|
||
|
|
||
|
AnimControl->Set_Animation( anim_name, 0.2f );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_ONCE );
|
||
|
StateLocked = true;
|
||
|
|
||
|
} else if ( State == LAND ) {
|
||
|
|
||
|
int dir = 0;
|
||
|
if ( SubState & SUB_STATE_LEFT ) dir = 3;
|
||
|
if ( SubState & SUB_STATE_RIGHT ) dir = 4;
|
||
|
if ( SubState & SUB_STATE_FORWARD ) dir = 1;
|
||
|
if ( SubState & SUB_STATE_BACKWARD ) dir = 2;
|
||
|
|
||
|
StringClass anim_name(0,true);
|
||
|
anim_name.Format( "S_A_HUMAN.H_A_A0L%d", dir );
|
||
|
AnimControl->Set_Animation( anim_name, 0.2f );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_ONCE );
|
||
|
|
||
|
} else if ( State == WOUNDED ) {
|
||
|
|
||
|
AnimControl->Set_Animation( Get_Wound_Anim( SubState ), 0.2f );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_ONCE );
|
||
|
|
||
|
} else if ( State == DEATH ) {
|
||
|
|
||
|
AnimControl->Set_Animation( Get_Death_Anim( SubState ), 0.2f );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_ONCE );
|
||
|
StateLocked = true;
|
||
|
|
||
|
} else if ( State == LADDER ) {
|
||
|
|
||
|
const char * anim_name = "S_A_HUMAN.H_A_412A";
|
||
|
if ( SubState & SUB_STATE_UP ) anim_name = "S_A_HUMAN.H_A_422A";
|
||
|
if ( SubState & SUB_STATE_DOWN ) anim_name = "S_A_HUMAN.H_A_432A";
|
||
|
AnimControl->Set_Animation( anim_name, 0.2f );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_LOOP );
|
||
|
|
||
|
} else if ( State == ANIMATION ) {
|
||
|
} else if ( State == LOITER ) {
|
||
|
} else if ( State == DESTROY ) {
|
||
|
} else if ( State == TRANSITION ) {
|
||
|
} else if ( State == TRANSITION_COMPLETE ) {
|
||
|
} else if ( State == ON_FIRE ) {
|
||
|
|
||
|
AnimControl->Set_Animation( "S_A_HUMAN.H_A_FLMA", 0.2f );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_LOOP );
|
||
|
|
||
|
} else if ( State == ON_CHEM ) {
|
||
|
|
||
|
AnimControl->Set_Animation( "S_A_HUMAN.h_a_6x01", 0.2f );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_LOOP );
|
||
|
|
||
|
} else if ( State == ON_CNC_FIRE ) {
|
||
|
|
||
|
AnimControl->Set_Animation( "S_A_HUMAN.H_A_FLMA", 0.2f );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_LOOP );
|
||
|
|
||
|
} else if ( State == ON_CNC_CHEM ) {
|
||
|
|
||
|
AnimControl->Set_Animation( "S_A_HUMAN.h_a_6x01", 0.2f );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_LOOP );
|
||
|
|
||
|
} else if ( State == ON_ELECTRIC ) {
|
||
|
|
||
|
AnimControl->Set_Animation( "S_A_HUMAN.h_a_6x05", 0.2f );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_LOOP );
|
||
|
|
||
|
} else if ( State == DEBUG_FLY ) {
|
||
|
|
||
|
} else {
|
||
|
Debug_Say(( "Uncoded Human State %d\n", State ));
|
||
|
AnimControl->Set_Animation( (const char *)NULL );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define MOVING_THRESHHOLD 0.2
|
||
|
//#define WALKING_THRESHHOLD 4.5
|
||
|
#define WALKING_THRESHHOLD 3.21f
|
||
|
|
||
|
void HumanStateClass::Reset_Loiter_Delay( void )
|
||
|
{
|
||
|
LoiterDelay = FreeRandom.Get_Float( 6 ) - 3;
|
||
|
}
|
||
|
|
||
|
// Must deal with LAND, ANIMATIONS, DEATH, WOUNDS, TRANSITIONS, JUMP, DEATH FALLS, LADDER
|
||
|
void HumanStateClass::Update_State( void )
|
||
|
{
|
||
|
WWPROFILE( "Human State" );
|
||
|
|
||
|
StateTimer += TimeManager::Get_Frame_Seconds();
|
||
|
|
||
|
if ( AnimControl && AnimControl->Get_Skeleton() == 'V' ) {
|
||
|
LoitersAllowed = false;
|
||
|
}
|
||
|
|
||
|
if ( State == UPRIGHT && LoitersAllowed ) {
|
||
|
|
||
|
// Don't loiter when crouched or moving
|
||
|
if ( SubState != 0 ) {
|
||
|
Reset_Loiter_Delay();
|
||
|
}
|
||
|
|
||
|
LoiterDelay += TimeManager::Get_Frame_Seconds();
|
||
|
|
||
|
HumanLoiterGlobalSettingsDef * loiter_def = HumanLoiterCollection;
|
||
|
|
||
|
if ( loiter_def == NULL ) {
|
||
|
loiter_def = HumanLoiterGlobalSettingsDef::Get_Default_Loiters();
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
// loiter based on holding a weapon
|
||
|
if ( WeaponHoldStyle == WEAPON_HOLD_STYLE_EMPTY_HANDS ) {
|
||
|
loiter_def = HumanLoiterGlobalSettingsDef::Get_Weaponless_Loiters();
|
||
|
} else {
|
||
|
loiter_def = HumanLoiterGlobalSettingsDef::Get_Weapon_Loiters();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if ( loiter_def != NULL ) {
|
||
|
if ( LoiterDelay > loiter_def->Get_Activation_Delay() ) {
|
||
|
|
||
|
Set_State( LOITER, Get_Sub_State() );
|
||
|
|
||
|
StringClass anim(loiter_def->Pick_Animation(),true);
|
||
|
// Debug_Say(( "Start loiter %s\n", anim ));
|
||
|
|
||
|
if ( !anim.Is_Empty() ) {
|
||
|
StringClass new_anim(true);
|
||
|
::Strip_Path_From_Filename( new_anim, anim );
|
||
|
// remove the .W3D
|
||
|
if ( new_anim.Get_Length() >= 5 ) {
|
||
|
new_anim.Erase( new_anim.Get_Length()-4, 4 );
|
||
|
}
|
||
|
AnimControl->Set_Animation( new_anim, 0.2f );
|
||
|
AnimControl->Set_Mode( ANIM_MODE_ONCE );
|
||
|
AnimControl->Update( 0 ); // update
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
Debug_Say(( "Failed to find Loiter Def\n" ));
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
Reset_Loiter_Delay();
|
||
|
}
|
||
|
|
||
|
// Get out of locked states
|
||
|
if ( AnimControl->Is_Complete() ) { // Time to unlock
|
||
|
// if ( StateLocked && State != LOCKED_ANIMATION ) {
|
||
|
if ( (StateLocked && State != LOCKED_ANIMATION) || (State == DEATH) ) {
|
||
|
|
||
|
StateLocked = false;
|
||
|
|
||
|
if ( State == DIVE ) {
|
||
|
Set_State( UPRIGHT );
|
||
|
} else if ( State == ANIMATION ) {
|
||
|
Set_State( UPRIGHT );
|
||
|
} else if ( State == DEATH ) {
|
||
|
|
||
|
Set_State( DESTROY );
|
||
|
TransitionEffectClass * effect = CombatMaterialEffectManager::Get_Death_Effect();
|
||
|
this->HumanPhys->Add_Effect_To_Me(effect);
|
||
|
REF_PTR_RELEASE(effect);
|
||
|
|
||
|
} else if ( State == TRANSITION ) {
|
||
|
Set_State( TRANSITION_COMPLETE );
|
||
|
} else if ( State != LOCKED_ANIMATION ) {
|
||
|
Debug_Say(( "Unsupported locked state %s\n", Get_State_Name() ));
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
// Debug_Say(( "Anim Complete %s\n", Get_State_Name() ));
|
||
|
|
||
|
if ( State == LOITER ) {
|
||
|
Set_State( UPRIGHT );
|
||
|
} else if ( State == LAND ) {
|
||
|
Set_State( UPRIGHT, Get_Sub_State() );
|
||
|
} else if ( State == WOUNDED ) {
|
||
|
Set_State( UPRIGHT );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Handle Jump and landing
|
||
|
*/
|
||
|
if ( !HumanPhys->Is_In_Contact() ) { // If I am not in contact with the ground
|
||
|
if ( State == UPRIGHT ) { // If I am currently UPRIGHT
|
||
|
Begin_Jump(); // Begin a jump
|
||
|
}
|
||
|
} else if ( State == AIRBORNE ) { // If I am in contact, and in the , I just landed
|
||
|
Complete_Jump(); // So complete the jump
|
||
|
}
|
||
|
|
||
|
if ( WeaponHoldTimer > 0 && !Get_State_Flag( CROUCHED_FLAG ) ) {
|
||
|
Reset_Loiter_Delay();
|
||
|
WeaponHoldTimer -= TimeManager::Get_Frame_Seconds();
|
||
|
if ( WeaponHoldTimer <= 0 ) {
|
||
|
if ( WeaponHoldStyle == WEAPON_HOLD_STYLE_HANDGUN ||
|
||
|
WeaponHoldStyle == WEAPON_HOLD_STYLE_C4 ||
|
||
|
WeaponHoldStyle == WEAPON_HOLD_STYLE_BEACON )
|
||
|
{
|
||
|
WeaponHoldStyle = WEAPON_HOLD_STYLE_HANDS_DOWN; // Lower the weapon
|
||
|
} else {
|
||
|
WeaponHoldStyle = WEAPON_HOLD_STYLE_AT_CHEST; // Lower the weapon
|
||
|
}
|
||
|
Update_Animation();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
void HumanStateClass::Post_Think( void )
|
||
|
{
|
||
|
// Update sub_state per movement
|
||
|
// do it for upright, land, ladder, airborne,
|
||
|
if ( Is_Sub_State_Adjustable() || Is_State_Interruptable() ) {
|
||
|
|
||
|
// Update the SubState
|
||
|
int new_sub_state = 0;
|
||
|
|
||
|
// Get our current move vector
|
||
|
Vector3 move_vector;
|
||
|
HumanPhys->Get_Animation_Move( &move_vector );
|
||
|
if ( TimeManager::Get_Frame_Seconds() > 0 ) {
|
||
|
move_vector /= TimeManager::Get_Frame_Seconds();
|
||
|
}
|
||
|
|
||
|
move_vector = HumanPhys->Get_Transform().Inverse_Rotate_Vector( move_vector );
|
||
|
|
||
|
// When walking running diagonally, use forward/backward legs.
|
||
|
// Unless you are crouched, then use straffe legs
|
||
|
float direction_ratio = 0.75f;
|
||
|
if ( Get_State_Flag( CROUCHED_FLAG ) ) {
|
||
|
direction_ratio = 2;
|
||
|
}
|
||
|
|
||
|
// Convert to SubMode
|
||
|
if ( WWMath::Fabs( move_vector[0] ) > direction_ratio * WWMath::Fabs( move_vector[1] ) ) {
|
||
|
if ( move_vector[0] > MOVING_THRESHHOLD ) new_sub_state |= SUB_STATE_FORWARD;
|
||
|
else if ( move_vector[0] < -MOVING_THRESHHOLD ) new_sub_state |= SUB_STATE_BACKWARD;
|
||
|
} else {
|
||
|
if ( move_vector[1] > MOVING_THRESHHOLD ) new_sub_state |= SUB_STATE_LEFT;
|
||
|
else if ( move_vector[1] < -MOVING_THRESHHOLD ) new_sub_state |= SUB_STATE_RIGHT;
|
||
|
}
|
||
|
|
||
|
if ( new_sub_state == 0 ) {
|
||
|
if ( move_vector[2] > MOVING_THRESHHOLD ) new_sub_state |= SUB_STATE_UP;
|
||
|
else if ( move_vector[2] < -MOVING_THRESHHOLD ) new_sub_state |= SUB_STATE_DOWN;
|
||
|
}
|
||
|
|
||
|
if ( new_sub_state != 0 ) {
|
||
|
if ( move_vector.Length() < WALKING_THRESHHOLD ) new_sub_state |= SUB_STATE_SLOW;
|
||
|
//Debug_Say(( "%f %f\n", move_vector.Length(), WALKING_THRESHHOLD ));
|
||
|
}
|
||
|
|
||
|
#if 0 // No turn anims!!!
|
||
|
// Get our current turn vector
|
||
|
if ( TurnVelocity > 0 ) new_sub_state |= SUB_STATE_TURN_LEFT;
|
||
|
else if ( TurnVelocity < 0 ) new_sub_state |= SUB_STATE_TURN_RIGHT;
|
||
|
TurnVelocity = 0;
|
||
|
#endif
|
||
|
|
||
|
// Get him out of WOUNDED, LAND, LOITER states if moving or shooting
|
||
|
if ( Is_State_Interruptable() && Get_State() != UPRIGHT ) {
|
||
|
// if ( new_sub_state != 0 || WeaponState > WeaponClass::STATE_READY ) {
|
||
|
|
||
|
if ( new_sub_state != 0 || WeaponFired ) {
|
||
|
if ( Get_State() == LAND && Get_Sub_State() == new_sub_state ) {
|
||
|
// don't interrupt lands for the same direction
|
||
|
} else {
|
||
|
// Debug_Say(( "Interrupt State %s\n", Get_State_Name() ));
|
||
|
Set_State( UPRIGHT );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( Is_Sub_State_Adjustable() ) {
|
||
|
|
||
|
if ( new_sub_state != Get_Sub_State() ) {
|
||
|
Set_Sub_State( (HumanSubStateType)new_sub_state );
|
||
|
}
|
||
|
|
||
|
|
||
|
#if 0 // Disable all leg twisting
|
||
|
|
||
|
// =================================================================== // LEG TWIST!!!!!
|
||
|
|
||
|
// Don't leg twist for crouched
|
||
|
if ( Get_State() == UPRIGHT && !Get_State_Flag( CROUCHED_FLAG ) ) {
|
||
|
|
||
|
float legs_rotation = 0;
|
||
|
|
||
|
// Compare the facing to the motion, set leg_racing to the difference
|
||
|
if ( move_vector.Length() > 0 ) {
|
||
|
float move_direction = WWMath::Atan2( -move_vector.Y, move_vector.X );
|
||
|
|
||
|
if ( new_sub_state & SUB_STATE_FORWARD ) {
|
||
|
legs_rotation = -move_direction;
|
||
|
} else if ( new_sub_state & SUB_STATE_BACKWARD ) {
|
||
|
legs_rotation = -move_direction + DEG_TO_RAD( 180 );
|
||
|
} else if ( new_sub_state & SUB_STATE_LEFT ) {
|
||
|
legs_rotation = -move_direction + DEG_TO_RAD( 270 );
|
||
|
} else if ( new_sub_state & SUB_STATE_RIGHT ) {
|
||
|
legs_rotation = -move_direction + DEG_TO_RAD( 90 );
|
||
|
}
|
||
|
|
||
|
legs_rotation = WWMath::Wrap( legs_rotation, DEG_TO_RADF( -180 ), DEG_TO_RADF( 180 ) );
|
||
|
// legs_rotation = WWMath::Clamp( legs_rotation, DEG_TO_RADF( -45 ), DEG_TO_RADF( 45 ) );
|
||
|
legs_rotation = WWMath::Clamp( legs_rotation, DEG_TO_RADF( -30 ), DEG_TO_RADF( 30 ) );
|
||
|
|
||
|
if ( WWMath::Fabs( legs_rotation ) < DEG_TO_RAD( 25 ) ) {
|
||
|
legs_rotation = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Move LegRotation toward leg_rotation
|
||
|
float rot_diff = legs_rotation - LegRotation;
|
||
|
float max_mov = DEG_TO_RAD( 180 ) * TimeManager::Get_Frame_Seconds();
|
||
|
// float max_mov = DEG_TO_RAD( 90 ) * TimeManager::Get_Frame_Seconds();
|
||
|
rot_diff = WWMath::Clamp( rot_diff, -max_mov, max_mov );
|
||
|
LegRotation += rot_diff;
|
||
|
legs_rotation = LegRotation;
|
||
|
|
||
|
// I'm making this staic for now, because all human
|
||
|
// skeletons have the bone at the same index
|
||
|
static int root_bone = -1;
|
||
|
if ( root_bone == -1 ) { // Get root bone index
|
||
|
root_bone = HumanPhys->Peek_Model()->Get_Bone_Index( "c spine" );
|
||
|
}
|
||
|
|
||
|
static int torso_bone = -1;
|
||
|
if ( torso_bone == -1 ) { // Get torso bone index
|
||
|
torso_bone = HumanPhys->Peek_Model()->Get_Bone_Index( "c spine1" );
|
||
|
}
|
||
|
|
||
|
if ( legs_rotation != 0 ) {
|
||
|
|
||
|
WWASSERT( root_bone != -1 );
|
||
|
WWASSERT( torso_bone != -1 );
|
||
|
|
||
|
if ( !HumanPhys->Peek_Model()->Is_Bone_Captured( root_bone ) ) {
|
||
|
HumanPhys->Peek_Model()->Capture_Bone( root_bone );
|
||
|
}
|
||
|
if ( !HumanPhys->Peek_Model()->Is_Bone_Captured( torso_bone ) ) {
|
||
|
HumanPhys->Peek_Model()->Capture_Bone( torso_bone );
|
||
|
}
|
||
|
|
||
|
Matrix3D root_adjust(1); // adjust it
|
||
|
root_adjust.Rotate_X( legs_rotation );
|
||
|
HumanPhys->Peek_Model()->Control_Bone( root_bone, root_adjust );
|
||
|
|
||
|
Matrix3D legs_adjust(1); // adjust it
|
||
|
legs_adjust.Rotate_X( -legs_rotation );
|
||
|
HumanPhys->Peek_Model()->Control_Bone( torso_bone, legs_adjust );
|
||
|
} else { // no adjustment, release
|
||
|
if ( HumanPhys->Peek_Model()->Is_Bone_Captured( root_bone ) ) {
|
||
|
HumanPhys->Peek_Model()->Release_Bone( root_bone );
|
||
|
}
|
||
|
if ( HumanPhys->Peek_Model()->Is_Bone_Captured( torso_bone ) ) {
|
||
|
HumanPhys->Peek_Model()->Release_Bone( torso_bone );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Scale animation speed
|
||
|
float ideal_speed = 0;
|
||
|
if ( !(new_sub_state & SUB_STATE_SLOW) ) {
|
||
|
if ( new_sub_state & SUB_STATE_FORWARD ) ideal_speed = 5.5f;
|
||
|
if ( new_sub_state & SUB_STATE_BACKWARD ) ideal_speed = 4.5f;
|
||
|
if ( new_sub_state & SUB_STATE_LEFT ) ideal_speed = 4.5f;
|
||
|
if ( new_sub_state & SUB_STATE_RIGHT ) ideal_speed = 5.5f;
|
||
|
} else {
|
||
|
if ( new_sub_state & SUB_STATE_FORWARD ) ideal_speed = 1.6f;
|
||
|
if ( new_sub_state & SUB_STATE_BACKWARD ) ideal_speed = 1.5f;
|
||
|
if ( new_sub_state & SUB_STATE_LEFT ) ideal_speed = 1.5f;
|
||
|
if ( new_sub_state & SUB_STATE_RIGHT ) ideal_speed = 1.6f;
|
||
|
}
|
||
|
|
||
|
if ( State == LADDER ) {
|
||
|
if ( new_sub_state & SUB_STATE_UP ) ideal_speed = 0.15f;
|
||
|
if ( new_sub_state & SUB_STATE_DOWN ) ideal_speed = 0.15f;
|
||
|
}
|
||
|
|
||
|
// Turning is at speed 1
|
||
|
bool turning = ( new_sub_state & (SUB_STATE_TURN_LEFT | SUB_STATE_TURN_RIGHT ) &&
|
||
|
!( new_sub_state & (SUB_STATE_FORWARD | SUB_STATE_BACKWARD )));
|
||
|
|
||
|
if ( !turning && ideal_speed != 0 ) {
|
||
|
// Get Anim_Speed_Scale
|
||
|
Vector3 vel;
|
||
|
HumanPhys->Get_Animation_Move( &vel );
|
||
|
if ( TimeManager::Get_Frame_Seconds() > 0 ) {
|
||
|
vel /= TimeManager::Get_Frame_Seconds();
|
||
|
}
|
||
|
float speed = WWMath::Clamp( vel.Length() / ideal_speed, 0.33f, 3 );
|
||
|
AnimControl->Set_Anim_Speed_Scale( speed );
|
||
|
} else {
|
||
|
AnimControl->Set_Anim_Speed_Scale( 1 );
|
||
|
}
|
||
|
|
||
|
HumanPhys->Reset_Animation_Move();
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
bool HumanStateClass::Get_Leg_Mode( void )
|
||
|
{
|
||
|
return AnimControl->Get_Progress() > 0.5f;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
struct BoneToOuchType {
|
||
|
const char * bone_name;
|
||
|
int ouch_type;
|
||
|
};
|
||
|
|
||
|
BoneToOuchType _BoneToOuchTypeList[] = {
|
||
|
{ "K_HEAD", HumanStateClass::HEAD_FROM_BEHIND },
|
||
|
{ "K_NECK", HumanStateClass::HEAD_FROM_BEHIND },
|
||
|
{ "K_CHEST", HumanStateClass::HEAD_FROM_BEHIND },
|
||
|
{ "K_ABDOMEN", HumanStateClass::TORSO_FROM_BEHIND },
|
||
|
{ "K_PELVIS", HumanStateClass::GROIN },
|
||
|
{ "K_L THIGH", HumanStateClass::LEFT_LEG_FROM_BEHIND },
|
||
|
{ "K_L CALF", HumanStateClass::LEFT_LEG_FROM_BEHIND },
|
||
|
{ "K_L FOOT", HumanStateClass::LEFT_LEG_FROM_BEHIND },
|
||
|
{ "K_L HAND", HumanStateClass::LEFT_ARM_FROM_BEHIND },
|
||
|
{ "K_L FOREARM", HumanStateClass::LEFT_ARM_FROM_BEHIND },
|
||
|
{ "K_L UPPERARM", HumanStateClass::LEFT_ARM_FROM_BEHIND },
|
||
|
{ "K_R THIGH", HumanStateClass::RIGHT_LEG_FROM_BEHIND },
|
||
|
{ "K_R CALF", HumanStateClass::RIGHT_LEG_FROM_BEHIND },
|
||
|
{ "K_R FOOT", HumanStateClass::RIGHT_LEG_FROM_BEHIND },
|
||
|
{ "K_R HAND", HumanStateClass::RIGHT_ARM_FROM_BEHIND },
|
||
|
{ "K_R FOREARM", HumanStateClass::RIGHT_ARM_FROM_BEHIND },
|
||
|
{ "K_R UPPERARM", HumanStateClass::RIGHT_ARM_FROM_BEHIND },
|
||
|
};
|
||
|
#define BONE_LIST_COUNT ( sizeof(_BoneToOuchTypeList) / sizeof(_BoneToOuchTypeList[0]) )
|
||
|
|
||
|
|
||
|
int HumanStateClass::Get_Ouch_Type( const Vector3 & direction, const char * collision_box_name )
|
||
|
{
|
||
|
// Initialize ouch_type to a default value
|
||
|
int ouch_type = TORSO_FROM_FRONT;
|
||
|
|
||
|
const char * base_name = NULL;
|
||
|
if ( collision_box_name != NULL ) {
|
||
|
base_name = ::strchr( collision_box_name, '.' );
|
||
|
} else {
|
||
|
return ouch_type;
|
||
|
}
|
||
|
|
||
|
if ( base_name != NULL ) {
|
||
|
base_name++;
|
||
|
for ( int i = 0; i < BONE_LIST_COUNT; i++ ) {
|
||
|
if ( ::strcmp( _BoneToOuchTypeList[i].bone_name, base_name ) == 0 ) {
|
||
|
ouch_type = _BoneToOuchTypeList[i].ouch_type;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( ouch_type != -1 ) {
|
||
|
// Set direction
|
||
|
Vector3 relative_direction = HumanPhys->Get_Transform().Inverse_Rotate_Vector( direction );
|
||
|
if ( ouch_type != HumanStateClass::GROIN ) { // but not for the groin shot
|
||
|
if ( relative_direction.X < 0 ) {
|
||
|
ouch_type += 1;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
Debug_Say(( "Bad human collision box name %s\n", collision_box_name ));
|
||
|
}
|
||
|
|
||
|
return ouch_type;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
const char * _WoundAnims[] =
|
||
|
{
|
||
|
"S_A_HUMAN.H_A_811A", // HEAD_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_812A", // HEAD_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_821A", // TORSO_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_822A", // TORSO_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_831A", // LEFT_ARM_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_832A", // LEFT_ARM_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_841A", // RIGHT_ARM_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_842A", // RIGHT_ARM_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_851A", // LEFT_LEG_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_852A", // LEFT_LEG_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_861A", // RIGHT_LEG_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_862A", // RIGHT_LEG_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_871A", // GROIN,
|
||
|
};
|
||
|
|
||
|
const char * HumanStateClass::Get_Wound_Anim( int ouch_type )
|
||
|
{
|
||
|
return _WoundAnims[ ouch_type ];
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
const char * _DeathAnims[] =
|
||
|
{
|
||
|
"S_A_HUMAN.H_A_622A", // HEAD_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_635A", // HEAD_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_622A", // TORSO_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_632A", // TORSO_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_623A", // LEFT_ARM_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_634A", // LEFT_ARM_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_624A", // RIGHT_ARM_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_633A", // RIGHT_ARM_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_623A", // LEFT_LEG_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_634A", // LEFT_LEG_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_624A", // RIGHT_LEG_FROM_BEHIND,
|
||
|
"S_A_HUMAN.H_A_633A", // RIGHT_LEG_FROM_FRONT,
|
||
|
"S_A_HUMAN.H_A_612A", // GROIN,
|
||
|
"S_A_HUMAN.H_A_FLMB", // ON_FIRE,
|
||
|
"S_A_HUMAN.H_A_FLMB", // ON_CHEM,
|
||
|
"S_A_HUMAN.H_A_FLMB", // ON_ELECTRIC,
|
||
|
"S_A_HUMAN.H_A_FLMB", // ON_CNC_FIRE,
|
||
|
"S_A_HUMAN.H_A_FLMB", // ON_CNC_CHEM,
|
||
|
};
|
||
|
|
||
|
const char * HumanStateClass::Get_Death_Anim( int ouch_type )
|
||
|
{
|
||
|
WWASSERT( ouch_type <= OUCH_SUPER_FIRE );
|
||
|
return _DeathAnims[ ouch_type ];
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
void HumanStateClass::Set_Precision(void)
|
||
|
{
|
||
|
cEncoderList::Set_Precision(BITPACK_HUMAN_STATE, 0, (int) HIGHEST_HUMAN_STATE);
|
||
|
cEncoderList::Set_Precision(BITPACK_HUMAN_SUB_STATE, 0, (int) HIGHEST_HUMAN_SUB_STATE);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
*/
|
||
|
void HumanStateClass::Get_Information( StringClass & string )
|
||
|
{
|
||
|
StringClass temp(0,true);
|
||
|
temp.Format( "%s\n", Get_State_Name() );
|
||
|
string += temp;
|
||
|
|
||
|
AnimControl->Get_Information( string );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Begin_Jump is called when we first become airborne
|
||
|
*/
|
||
|
void HumanStateClass::Begin_Jump( void )
|
||
|
{
|
||
|
// Store some information about the jump
|
||
|
JumpTM = HumanPhys->Get_Transform();
|
||
|
|
||
|
// Set my state to Jump, with a direction of my current relative velocity
|
||
|
Vector3 move_vector;
|
||
|
HumanPhys->Get_Velocity( &move_vector );
|
||
|
move_vector = HumanPhys->Get_Transform().Inverse_Rotate_Vector( move_vector );
|
||
|
int sub_state = 0;
|
||
|
if ( move_vector[0] > MOVING_THRESHHOLD ) sub_state |= SUB_STATE_FORWARD;
|
||
|
else if ( move_vector[0] < -MOVING_THRESHHOLD ) sub_state |= SUB_STATE_BACKWARD;
|
||
|
if ( move_vector[1] > MOVING_THRESHHOLD ) sub_state |= SUB_STATE_LEFT;
|
||
|
else if ( move_vector[1] < -MOVING_THRESHHOLD ) sub_state |= SUB_STATE_RIGHT;
|
||
|
|
||
|
Set_State( AIRBORNE, sub_state );
|
||
|
|
||
|
// Whenever a jump starts, play a jump surface effect
|
||
|
Matrix3D tm = HumanPhys->Get_Transform();
|
||
|
int ground_type = HumanPhys->Get_Contact_Surface_Type();
|
||
|
SurfaceEffectsManager::Apply_Effect( ground_type, SurfaceEffectsManager::HITTER_TYPE_FOOTSTEP_JUMP, tm );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Complete_Jump is called when we land
|
||
|
*/
|
||
|
void HumanStateClass::Complete_Jump( void )
|
||
|
{
|
||
|
Vector3 fall = JumpTM.Get_Translation() - HumanPhys->Get_Transform().Get_Translation();
|
||
|
GlobalSettingsDef * settings = GlobalSettingsDef::Get_Global_Settings();
|
||
|
// Debug_Say(( "Fall Distance %f\n", fall.Z ));
|
||
|
|
||
|
bool add_portal = true;
|
||
|
|
||
|
//
|
||
|
// Don't do this in the level editor
|
||
|
//
|
||
|
#ifndef PARAM_EDITING_ON
|
||
|
|
||
|
if ( fall.Z > settings->Get_Falling_Damage_Min_Distance() ) {
|
||
|
add_portal = false;
|
||
|
float scale = (fall.Z - settings->Get_Falling_Damage_Min_Distance()) /
|
||
|
(settings->Get_Falling_Damage_Max_Distance() - settings->Get_Falling_Damage_Min_Distance());
|
||
|
scale = WWMath::Clamp( scale, 0, 1 );
|
||
|
|
||
|
// (gth) don't take damage when falling onto an elevator (because we have
|
||
|
// super-fast elevators...)
|
||
|
if ( (HumanPhys->Peek_Ground_Object() != NULL) &&
|
||
|
(HumanPhys->Peek_Ground_Object()->As_ElevatorPhysClass() != NULL))
|
||
|
{
|
||
|
Debug_Say(( "Fell onto an elevator, no damage!\n", scale ));
|
||
|
scale = 0.0f;
|
||
|
}
|
||
|
|
||
|
Debug_Say(( "Fall Damage Scale %f\n", scale ));
|
||
|
|
||
|
SoldierGameObj * owner = (SoldierGameObj *)HumanPhys->Get_Observer();
|
||
|
if ( owner != NULL ) {
|
||
|
DefenseObjectClass * defense = owner->Get_Defense_Object();
|
||
|
float damage = defense->Get_Health_Max();
|
||
|
|
||
|
// AI's get notified
|
||
|
// if ( !owner->Is_Human_Controlled() ) {
|
||
|
const GameObjObserverList & observer_list = owner->Get_Observers();
|
||
|
for( int index = 0; index < observer_list.Count(); index++ ) {
|
||
|
observer_list[ index ]->Custom( owner, CUSTOM_EVENT_FALLING_DAMAGE, damage*scale, NULL );
|
||
|
}
|
||
|
// }
|
||
|
|
||
|
// All get the damage
|
||
|
OffenseObjectClass offense( damage, settings->Get_Falling_Damage_Warhead(), NULL );
|
||
|
owner->Apply_Damage_Extended( offense, scale, fall, NULL );
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif // PARAM_EDITING_ON
|
||
|
|
||
|
// Find the sector the human jumped from and the sector the human jumped to.
|
||
|
/*Vector3 curr_pos = HumanPhys->Get_Position ();
|
||
|
PathfindSectorClass *start_sector = PathfindClass::Get_Instance ()->Find_Sector (JumpTM.Get_Translation (), 2.0F);
|
||
|
PathfindSectorClass *end_sector = PathfindClass::Get_Instance ()->Find_Sector (curr_pos, 2.0F);
|
||
|
|
||
|
// Make a temporary pathfind connection between these sectors (if necessary)
|
||
|
if (add_portal && start_sector != NULL && end_sector != NULL && start_sector != end_sector) {
|
||
|
PathfindClass::Get_Instance ()->Add_Temporary_Portal (start_sector, end_sector, JumpTM.Get_Translation (), curr_pos);
|
||
|
}*/
|
||
|
|
||
|
// Set me state to Land, with a direction of my current velocity
|
||
|
Vector3 move_vector;
|
||
|
HumanPhys->Get_Velocity( &move_vector );
|
||
|
move_vector = HumanPhys->Get_Transform().Inverse_Rotate_Vector( move_vector );
|
||
|
int sub_state = 0;
|
||
|
if ( move_vector[0] > MOVING_THRESHHOLD ) sub_state |= SUB_STATE_FORWARD;
|
||
|
else if ( move_vector[0] < -MOVING_THRESHHOLD ) sub_state |= SUB_STATE_BACKWARD;
|
||
|
if ( move_vector[1] > MOVING_THRESHHOLD ) sub_state |= SUB_STATE_LEFT;
|
||
|
else if ( move_vector[1] < -MOVING_THRESHHOLD ) sub_state |= SUB_STATE_RIGHT;
|
||
|
Set_State( LAND, sub_state );
|
||
|
|
||
|
// Whenever a jump ends, play a land surface effect
|
||
|
Matrix3D tm = HumanPhys->Get_Transform();
|
||
|
int ground_type = HumanPhys->Get_Contact_Surface_Type();
|
||
|
SurfaceEffectsManager::Apply_Effect( ground_type, SurfaceEffectsManager::HITTER_TYPE_FOOTSTEP_LAND, tm );
|
||
|
}
|
||
|
|