mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
1156 lines
26 KiB
C++
1156 lines
26 KiB
C++
|
|
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "prey_local.h"
|
|
|
|
|
|
const idEventDef EV_Hand_DoRemove( "DoHandRemove", NULL );
|
|
const idEventDef EV_Hand_DoAttach( "DoHandAttach", "e" );
|
|
const idEventDef EV_Hand_Remove( "RemoveHand", NULL );
|
|
|
|
const idEventDef EV_Hand_Ready( "<ready>" );
|
|
const idEventDef EV_Hand_Lowered( "<lowered>" );
|
|
const idEventDef EV_Hand_Raise( "<raise>" );
|
|
|
|
CLASS_DECLARATION( hhAnimatedEntity, hhHand )
|
|
EVENT ( EV_Hand_DoRemove, hhHand::Event_DoHandRemove )
|
|
EVENT ( EV_Hand_DoAttach, hhHand::Event_DoHandAttach )
|
|
EVENT ( EV_Hand_Remove, hhHand::Event_RemoveHand )
|
|
EVENT ( EV_Hand_Ready, hhHand::Event_Ready )
|
|
EVENT ( EV_Hand_Lowered, hhHand::Event_Lowered )
|
|
EVENT ( EV_Hand_Raise, hhHand::Event_Raise )
|
|
END_CLASS
|
|
|
|
/*
|
|
============
|
|
hhHand::~hhHand
|
|
============
|
|
*/
|
|
hhHand::~hhHand() {
|
|
bool shouldWarn = (gameLocal.GameState() != GAMESTATE_SHUTDOWN && !gameLocal.isClient);
|
|
//rww - don't warn about this on client, since snapshot entities are free to be removed
|
|
//at any time.
|
|
|
|
// Check if the hand deleted is still in the hands list
|
|
if ( gameLocal.hands.Find( this ) ) {
|
|
if ( shouldWarn ) {
|
|
gameLocal.Warning( "The hand (%p/%s) was deleted before being removed",
|
|
this, spawnArgs.GetString( "classname" ) );
|
|
}
|
|
gameLocal.hands.Remove( this );
|
|
}
|
|
|
|
if ( owner != NULL ) {
|
|
if ( shouldWarn ) {
|
|
gameLocal.Warning( "A hand (%p) was deleted while having an owner", this );
|
|
}
|
|
}
|
|
|
|
StopSound( SND_CHANNEL_ANY );
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::Spawn
|
|
============
|
|
*/
|
|
void hhHand::Spawn( void ) {
|
|
gameLocal.hands.Append( idEntityPtr<hhHand> (this) );
|
|
|
|
owner = NULL;
|
|
previousHand = NULL;
|
|
|
|
renderEntity.weaponDepthHack = true;
|
|
|
|
animEvent = NULL;
|
|
|
|
priority = spawnArgs.GetInt("priority");
|
|
|
|
status = HS_UNKNOWN;
|
|
idealState = HS_READY;
|
|
|
|
animBlendFrames = 4; // needs blending
|
|
animDoneTime = 0;
|
|
|
|
attached = false;
|
|
attachTime = -1;
|
|
|
|
spawnArgs.GetBool( "replace_previous", "0", replacePrevious );
|
|
|
|
spawnArgs.GetBool( "lower_weapon", "1", lowerWeapon );
|
|
spawnArgs.GetBool( "aside_weapon", "1", asideWeapon );
|
|
|
|
handedness = spawnArgs.GetInt( "handedness", "2" );
|
|
|
|
physicsObj.SetSelf( this );
|
|
physicsObj.SetClipModel( NULL, 1.0f );
|
|
physicsObj.SetOrigin( GetOrigin() );
|
|
physicsObj.SetAxis( GetAxis() );
|
|
SetPhysics( &physicsObj );
|
|
|
|
// Lower overrides aside
|
|
if ( lowerWeapon && asideWeapon ) {
|
|
asideWeapon = false;
|
|
}
|
|
|
|
Hide();
|
|
}
|
|
|
|
void hhHand::Save(idSaveGame *savefile) const {
|
|
//savefile->WriteObject( owner );
|
|
owner.Save(savefile);
|
|
savefile->WriteInt( priority );
|
|
savefile->WriteObject( previousHand );
|
|
savefile->WriteBool( lowerWeapon );
|
|
savefile->WriteBool( asideWeapon );
|
|
savefile->WriteBool( attached );
|
|
savefile->WriteBool( replacePrevious );
|
|
savefile->WriteInt( attachTime );
|
|
savefile->WriteInt( handedness );
|
|
savefile->WriteInt( animDoneTime );
|
|
savefile->WriteInt( animBlendFrames );
|
|
savefile->WriteInt( status );
|
|
savefile->WriteInt( idealState );
|
|
savefile->WriteEventDef(animEvent);
|
|
savefile->WriteStaticObject( physicsObj );
|
|
}
|
|
|
|
void hhHand::Restore( idRestoreGame *savefile ) {
|
|
//savefile->ReadObject( reinterpret_cast<idClass *&>(owner) );
|
|
owner.Restore(savefile);
|
|
savefile->ReadInt( priority );
|
|
savefile->ReadObject( reinterpret_cast<idClass *&>(previousHand) );
|
|
savefile->ReadBool( lowerWeapon );
|
|
savefile->ReadBool( asideWeapon );
|
|
savefile->ReadBool( attached );
|
|
savefile->ReadBool( replacePrevious );
|
|
savefile->ReadInt( attachTime );
|
|
savefile->ReadInt( handedness );
|
|
savefile->ReadInt( animDoneTime );
|
|
savefile->ReadInt( animBlendFrames );
|
|
savefile->ReadInt( status );
|
|
savefile->ReadInt( idealState );
|
|
savefile->ReadEventDef(animEvent);
|
|
savefile->ReadStaticObject( physicsObj );
|
|
RestorePhysics( &physicsObj );
|
|
}
|
|
|
|
//rww - network code
|
|
void hhHand::WriteToSnapshot( idBitMsgDelta &msg ) const {
|
|
//physicsObj.WriteToSnapshot(msg);
|
|
//rww - trying to keep this all local
|
|
|
|
WriteBindToSnapshot(msg);
|
|
|
|
msg.WriteBits(owner.GetSpawnId(), 32);
|
|
|
|
if (previousHand) {
|
|
msg.WriteBits(gameLocal.GetSpawnId(previousHand), 32);
|
|
}
|
|
else {
|
|
msg.WriteBits(0, 32);
|
|
}
|
|
|
|
msg.WriteBits(attached, 1);
|
|
msg.WriteBits(replacePrevious, 1);
|
|
//msg.WriteBits(attachTime, 32);
|
|
//msg.WriteBits(animDoneTime, 32);
|
|
//msg.WriteBits(animBlendFrames, 32);
|
|
|
|
assert(idealState < (1<<4));
|
|
msg.WriteBits(idealState, 4);
|
|
|
|
assert(status < (1<<4));
|
|
msg.WriteBits(status, 4);
|
|
|
|
msg.WriteBits(IsHidden(), 1);
|
|
|
|
assert(gameLocal.hands.Num() < (1<<4));
|
|
msg.WriteBits(gameLocal.hands.Num(), 4);
|
|
int i = 0;
|
|
while (i < gameLocal.hands.Num()) {
|
|
hhHand *hand = gameLocal.hands[i].GetEntity();
|
|
|
|
if (hand) {
|
|
msg.WriteBits(gameLocal.GetSpawnId(hand), 32);
|
|
}
|
|
else {
|
|
msg.WriteBits(0, 32);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
msg.WriteBits(renderEntity.allowSurfaceInViewID, GENTITYNUM_BITS);
|
|
|
|
idAnimatedEntity::WriteToSnapshot(msg);
|
|
}
|
|
|
|
void hhHand::ReadFromSnapshot( const idBitMsgDelta &msg ) {
|
|
//physicsObj.ReadFromSnapshot(msg);
|
|
//rww - trying to keep this all local
|
|
|
|
ReadBindFromSnapshot(msg);
|
|
|
|
if (owner.SetSpawnId(msg.ReadBits(32))) {
|
|
physicsObj.SetSelfOwner(owner.GetEntity());
|
|
if (owner.IsValid() && owner.GetEntity()) {
|
|
DoHandAttach(owner.GetEntity());
|
|
} else {
|
|
owner = NULL;
|
|
}
|
|
}
|
|
|
|
//Show();
|
|
|
|
idEntityPtr<hhHand> newPrevHand;
|
|
int prevHandSpawnId = msg.ReadBits(32);
|
|
if (newPrevHand.SetSpawnId(prevHandSpawnId)) {
|
|
previousHand = newPrevHand.GetEntity();
|
|
}
|
|
else {
|
|
previousHand = NULL;
|
|
}
|
|
|
|
attached = !!msg.ReadBits(1);
|
|
replacePrevious = !!msg.ReadBits(1);
|
|
//attachTime = msg.ReadBits(32);
|
|
//animDoneTime = msg.ReadBits(32);
|
|
//animBlendFrames = msg.ReadBits(32);
|
|
|
|
idealState = msg.ReadBits(4);
|
|
|
|
int nextStatus = msg.ReadBits(4);
|
|
if (status != nextStatus) {
|
|
if (nextStatus == HS_LOWERING || nextStatus == HS_LOWERED) {
|
|
PutAway();
|
|
}
|
|
else if (nextStatus == HS_RAISING) {
|
|
Raise();
|
|
}
|
|
else if (nextStatus == HS_READY) {
|
|
//PlayAnim( -1, "idle" );
|
|
Ready();
|
|
}
|
|
status = nextStatus;
|
|
}
|
|
|
|
bool hidden = !!msg.ReadBits(1);
|
|
if (hidden != IsHidden()) {
|
|
if (hidden) {
|
|
Hide();
|
|
} else {
|
|
Show();
|
|
}
|
|
}
|
|
|
|
int numHands = msg.ReadBits(4);
|
|
gameLocal.hands.SetNum(numHands);
|
|
int i = 0;
|
|
while (i < numHands) {
|
|
int handSpawnId = msg.ReadBits(32);
|
|
gameLocal.hands[i].SetSpawnId( handSpawnId );
|
|
|
|
i++;
|
|
}
|
|
|
|
renderEntity.allowSurfaceInViewID = msg.ReadBits(GENTITYNUM_BITS);
|
|
|
|
idAnimatedEntity::ReadFromSnapshot(msg);
|
|
|
|
/*
|
|
if (msg.HasChanged()) {
|
|
Present();
|
|
}
|
|
*/
|
|
}
|
|
|
|
void hhHand::ClientPredictionThink( void ) {
|
|
BecomeActive(TH_THINK|TH_ANIMATE);
|
|
UpdateVisuals();
|
|
idAnimatedEntity::ClientPredictionThink();
|
|
}
|
|
|
|
bool hhHand::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
|
|
switch (event) {
|
|
case EVENT_REMOVEHAND: {
|
|
RemoveHand();
|
|
return true;
|
|
}
|
|
default: {
|
|
return hhAnimatedEntity::ClientReceiveEvent(event, time, msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
hhHand::Event_Ready
|
|
============
|
|
*/
|
|
void hhHand::Event_Ready() {
|
|
Show();
|
|
Ready();
|
|
}
|
|
|
|
|
|
/*
|
|
===========
|
|
hhHand::Event_Lowered
|
|
===========
|
|
*/
|
|
void hhHand::Event_Lowered() {
|
|
status = HS_LOWERED;
|
|
Hide();
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::Event_Raise
|
|
============
|
|
*/
|
|
void hhHand::Event_Raise() {
|
|
Raise();
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::Ready
|
|
============
|
|
*/
|
|
void hhHand::Ready() {
|
|
|
|
switch ( idealState ) {
|
|
|
|
case HS_READY:
|
|
CycleAnim(-1, "idle", 500);
|
|
status = HS_READY;
|
|
break;
|
|
|
|
case HS_LOWERED:
|
|
PutAway();
|
|
break;
|
|
|
|
default:
|
|
gameLocal.Warning( "hhHand::Ready: Unsupported ideal state: %d", idealState );
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::Raise
|
|
============
|
|
*/
|
|
void hhHand::Raise() {
|
|
|
|
Show();
|
|
|
|
if ( IsRaising() ) { // If already raising, return
|
|
return;
|
|
}
|
|
|
|
status = HS_RAISING;
|
|
PlayAnim( -1, "raise", &EV_Hand_Ready );
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::PutAway
|
|
============
|
|
*/
|
|
void hhHand::PutAway() {
|
|
|
|
if ( IsLowering() ) {
|
|
// already being put away, so don't play more than one put away animations
|
|
return;
|
|
}
|
|
|
|
status = HS_LOWERING;
|
|
PlayAnim( -1, "putaway", &EV_Hand_Lowered );
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
hhHand::CycleAnim
|
|
===============
|
|
*/
|
|
void hhHand::CycleAnim( int channel, const char *animname, int blendTime ) {
|
|
if ( channel < 0 ) {
|
|
channel = GetChannelForAnim( animname );
|
|
}
|
|
|
|
int anim = GetAnimator()->GetAnim( animname );
|
|
if ( anim ) {
|
|
GetAnimator()->CycleAnim( channel, anim, gameLocal.time, blendTime );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
hhHand::PlayAnim
|
|
===============
|
|
*/
|
|
void hhHand::PlayAnim( int channel, const char *animname, const idEventDef *event ) {
|
|
int anim;
|
|
|
|
// HUMANHEAD nla
|
|
if ( animEvent ) {
|
|
CancelEvents( animEvent );
|
|
}
|
|
animEvent = event;
|
|
|
|
if ( channel < 0 ) {
|
|
channel = GetChannelForAnim( animname );
|
|
}
|
|
// HUMANHEAD END
|
|
|
|
anim = GetAnimator()->GetAnim( animname );
|
|
if ( anim ) {
|
|
GetAnimator()->PlayAnim( channel, anim, gameLocal.time, FRAME2MS( animBlendFrames ) );
|
|
animDoneTime = GetAnimator()->CurrentAnim( channel )->GetEndTime();
|
|
} else {
|
|
// This is a valid case, some hands (mounted gun) don't animate
|
|
GetAnimator()->Clear( channel, gameLocal.time, FRAME2MS( animBlendFrames ) );
|
|
animDoneTime = 0;
|
|
}
|
|
animBlendFrames = 4;
|
|
|
|
// HUMANHEAD nla
|
|
if ( animEvent ) {
|
|
PostEventMS( animEvent, animDoneTime - gameLocal.time );
|
|
}
|
|
// HUMANHEAD END
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::AttachHand
|
|
Returns false if the hand can not be attached
|
|
============
|
|
*/
|
|
bool hhHand::AttachHand( hhPlayer *player, bool attachNow ) {
|
|
assert(player);
|
|
|
|
if ( !CheckHandAttach( player ) ) {
|
|
return( false );
|
|
}
|
|
|
|
int loweringFinished = LowerHandOrWeapon( player );
|
|
SetOwner( player );
|
|
Bind( player, true );
|
|
|
|
if ( loweringFinished >= 0 ) {
|
|
player->handNext = this;
|
|
// If the attachment should wait, and we don't want to force it to happen now
|
|
if ( loweringFinished - gameLocal.time > 0 && !attachNow ) {
|
|
PostEventMS( &EV_Hand_DoAttach, loweringFinished - gameLocal.time, player );
|
|
}
|
|
else {
|
|
Event_DoHandAttach( player );
|
|
}
|
|
attachTime = loweringFinished;
|
|
}
|
|
|
|
return( true );
|
|
}
|
|
|
|
/*
|
|
============
|
|
hhHand::LowerHandOrWeapon
|
|
Used when the hand adds itself.
|
|
returns the time when the lowering will be done
|
|
will be -1 if the hand has already been attached.
|
|
============
|
|
*/
|
|
int hhHand::LowerHandOrWeapon( hhPlayer *player ) {
|
|
int animDone = gameLocal.time;
|
|
int animDone2;
|
|
|
|
// If there is a 'next' hand, we can just replace it, as it is already playing the down anim for the hand
|
|
if ( player->handNext.IsValid() ) {
|
|
animDone = player->handNext->GetAttachTime();
|
|
|
|
gameLocal.hands.Remove( player->handNext.GetEntity() );
|
|
|
|
// Clear the old hand of any pending events, and then remove it
|
|
player->handNext->SetOwner( NULL );
|
|
player->handNext->CancelEvents( NULL );
|
|
player->handNext->ProcessEvent( &EV_Remove );
|
|
|
|
player->handNext = NULL;
|
|
}
|
|
// Else, If there is just a hand, play the down anim on it or replace it
|
|
else if ( player->hand.IsValid() ) {
|
|
//! Work out this logic more fully
|
|
if ( replacePrevious ) {
|
|
ReplaceHand( player );
|
|
animDone = -1;
|
|
}
|
|
// If it isn't on it's way down, move it down
|
|
if ( !player->hand->IsLowered() ) {
|
|
player->hand->PutAway();
|
|
animDone = player->hand->GetAnimDoneTime();
|
|
}
|
|
}
|
|
|
|
animDone2 = HandleWeapon( player, this, animDone - gameLocal.time );
|
|
if ( ( animDone >= 0 ) && ( animDone2 > animDone ) ) {
|
|
animDone = animDone2;
|
|
}
|
|
// If there is a weapon play the down anim on it
|
|
/*
|
|
if ( player->hhweapon ) {
|
|
if ( lowerWeapon && !player->hhweapon->IsLowered() ) {
|
|
player->hhweapon->PutAway();
|
|
animDone2 = player->hhweapon->GetAnimDoneTime();
|
|
if ( animDone2 > animDone ) {
|
|
animDone = animDone2;
|
|
}
|
|
}
|
|
else if ( asideWeapon && !player->hhweapon->IsAside() ) {
|
|
player->hhweapon->PutAside();
|
|
// When aside, we want to have it play right away, so dont' change animDone
|
|
}
|
|
// gameLocal.Printf("Scheduled down for %.2f\n", animDone);
|
|
}
|
|
*/
|
|
|
|
return( animDone );
|
|
}
|
|
|
|
/*
|
|
==============
|
|
RaiseHandOrWeapon
|
|
|
|
Assumes the hand is all the way down
|
|
==============
|
|
*/
|
|
void hhHand::RaiseHandOrWeapon( hhPlayer *player ) {
|
|
hhHand *theHand = NULL;
|
|
int raiseDelay = 0;
|
|
|
|
// Get the next hand
|
|
theHand = this->GetPreviousHand( player );
|
|
|
|
raiseDelay = HandleWeapon( player, theHand );
|
|
|
|
if ( theHand && ( !theHand->IsRaising() || !theHand->IsReady() ) ) {
|
|
theHand->PostEventMS( &EV_Hand_Raise, raiseDelay - gameLocal.time );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
hhHand::Reraise
|
|
Raises the hand again.
|
|
================
|
|
*/
|
|
void hhHand::Reraise( ) {
|
|
hhPlayer *thePlayer = NULL;
|
|
int raiseDelay = 0;
|
|
|
|
CancelEvents( &EV_Remove );
|
|
CancelEvents( &EV_Hand_Raise );
|
|
|
|
if ( owner.IsValid() && owner.GetEntity() && owner->IsType( hhPlayer::Type ) ) {
|
|
thePlayer = ( hhPlayer * ) owner.GetEntity();
|
|
}
|
|
else {
|
|
gameLocal.Printf( "hhHand::Reraise: Warning tried to reraise when not on an hhPlayer (%p)\n", owner );
|
|
return;
|
|
}
|
|
|
|
raiseDelay = HandleWeapon( thePlayer, this );
|
|
|
|
if ( !IsRaising() || !IsReady() ) {
|
|
PostEventMS( &EV_Hand_Raise, raiseDelay - gameLocal.time );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===========
|
|
hhHand::GetPreviousHand
|
|
===========
|
|
*/
|
|
hhHand *hhHand::GetPreviousHand( hhPlayer *player ) {
|
|
hhHand *prevHand = NULL;
|
|
|
|
// If there is no player, just give them our previous hand
|
|
if ( player == NULL ) {
|
|
return( previousHand );
|
|
}
|
|
|
|
// If we are the next hand, up the current hand
|
|
if ( player->handNext == this ) {
|
|
prevHand = player->hand.GetEntity();
|
|
}
|
|
// Else If we are the current hand
|
|
else if ( player->hand == this ) {
|
|
// If we have a previous hand, raise it if it isn't already up or being raised
|
|
if ( previousHand ) {
|
|
prevHand = previousHand;
|
|
}
|
|
}
|
|
// Else we are neither, throw a warning. How are we here?
|
|
else {
|
|
gameLocal.Warning( "ERROR GetPreviousHand: ERROR: Tried to get a previous hand when we (%p) are not on the player (%p/%p)",
|
|
this, player->handNext, player->hand );
|
|
}
|
|
|
|
return( prevHand );
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::HandleWeapon
|
|
Set the weapon in the proper place for the hand
|
|
Assumes the hand in question will be raised.
|
|
Returns time (MS) to wait until the hand can be raised. Only in the
|
|
case of the weapon being lowered does it really matter/ > 0
|
|
============
|
|
*/
|
|
int hhHand::HandleWeapon( hhPlayer *player, hhHand *hand, int weaponDelay, bool doNow ) {
|
|
int raiseHandDelay = gameLocal.time;
|
|
bool weaponReady = ( hand == NULL ) && !player->ChangingWeapons();
|
|
|
|
// If we don't have a weapon, then just return
|
|
if ( !player->weapon.IsValid() || player->GetIdealWeapon() == 0 ) {
|
|
return( 0 );
|
|
}
|
|
|
|
// If we have a hand to compare to
|
|
if ( hand ) {
|
|
// If the hand wants the weapon lowered
|
|
if ( hand->lowerWeapon || ( hand->handedness & player->weapon->GetHandedness() ) ) {
|
|
player->weapon->PutAway();
|
|
if ( doNow ) {
|
|
player->weapon->SetState( "Down", 0 );
|
|
}
|
|
else {
|
|
// Foce the gun to go, so we can know when it'll be done playing the anim.
|
|
player->weapon->UpdateScript();
|
|
raiseHandDelay = player->weapon->GetAnimDoneTime();
|
|
}
|
|
/*
|
|
// If it isn't lowered, lower it
|
|
if ( !player->weapon->IsLowered() ) {
|
|
player->weapon->PutAway();
|
|
raiseHandDelay = player->weapon->GetAnimDoneTime();
|
|
}
|
|
*/
|
|
} //. lower the weapon
|
|
// If the hand wants the weapon to the side
|
|
else if ( hand->asideWeapon ) {
|
|
player->weapon->PutAside();
|
|
if ( doNow ) {
|
|
player->weapon->SetState( "Aside", 0 );
|
|
}
|
|
// We only want a delay if the weapon should pop up?
|
|
else if ( player->weapon->IsLowered() ) {
|
|
// Foce the gun to go, so we can know when it'll be done playing the anim.
|
|
player->weapon->UpdateScript();
|
|
raiseHandDelay = player->weapon->GetAnimDoneTime();
|
|
player->weapon->SetState( "PutAside", 4 );
|
|
}
|
|
/*
|
|
// If it is lowered,
|
|
if ( player->weapon->IsLowered() ) {
|
|
// First raise it, then set it aside
|
|
int done = weaponDelay;
|
|
idAnim *anim = player->weapon->GetAnimator()->GetAnim( "raise" ); // UGLY Hack, as hardcoded to the name
|
|
|
|
player->weapon->PostEventMS( &EV_Weapon_WeaponRising, weaponDelay );
|
|
if ( anim ) { done = anim->Length(); }
|
|
player->weapon->PostEventMS( &EV_Weapon_Aside, done );
|
|
}
|
|
// Else if it is ready/upright and not aside
|
|
else if ( !player->weapon->IsAside() ) {
|
|
// Just set it aside
|
|
player->weapon->PutAside();
|
|
}
|
|
*/
|
|
}
|
|
// Weapon should be in ready mode
|
|
else {
|
|
weaponReady = true;
|
|
}
|
|
} // Valid hand
|
|
|
|
// If we don't have a hand, so just make sure the weapon is raised
|
|
if ( weaponReady ) {
|
|
player->weapon->Raise();
|
|
if ( doNow ) {
|
|
player->weapon->SetState( "Idle", 0 );
|
|
}
|
|
|
|
/*
|
|
|
|
// Clear any Aside events that may be posted. Happens when it was lowered, and the previous hand wanted aside
|
|
player->weapon->CancelEvents( &EV_Weapon_Aside );
|
|
|
|
// If the weapon is aside, put it upright
|
|
if ( player->weapon->IsAside() ) {
|
|
player->weapon->PutUpright();
|
|
}
|
|
// Else if it is lowering, raise it
|
|
else if ( !player->weapon->IsRising() && player->weapon->IsLowered() ) {
|
|
player->weapon->Raise();
|
|
}
|
|
// Else if we aren't ready, how can we not be??!?
|
|
else if ( player->weapon->IsLowered() || player->weapon->IsLowered() ) {
|
|
gameLocal.Warning( "hhHand::HandleWeapon ERROR: Have a weapon that is lowered/lowering when shouldn't be!" );
|
|
}
|
|
*/
|
|
}
|
|
|
|
return( raiseHandDelay );
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::RemoveHand
|
|
Plays the animations and schedules pointer changes
|
|
============
|
|
*/
|
|
bool hhHand::RemoveHand( void ) {
|
|
hhPlayer *player;
|
|
int animDone = gameLocal.time;
|
|
|
|
if ( owner.IsValid() && owner.GetEntity() ) {
|
|
if ( owner->IsType( hhPlayer::Type ) ) {
|
|
player = static_cast<hhPlayer *>( owner.GetEntity() );
|
|
}
|
|
else {
|
|
gameLocal.Warning( "ERROR: RemoveHand: Tried to remove from a non player" );
|
|
return( false );
|
|
}
|
|
}
|
|
else {
|
|
gameLocal.Warning( "ERROR: RemoveHand: Tried to remove with no owner!!" );
|
|
return( false );
|
|
}
|
|
|
|
if ( !CheckHandRemove( player ) ) {
|
|
return( false );
|
|
}
|
|
|
|
// Unaside is asap if we asided it, and the prev hand isn't gonna want it asided
|
|
// NLA - If we want to upright the GUI
|
|
hhHand *prevHand = GetPreviousHand( player );
|
|
if ( ( !prevHand || !prevHand->asideWeapon ) &&
|
|
( asideWeapon && player->weapon.IsValid() && player->weapon->IsAside() ) ){
|
|
player->weapon->PutUpright();
|
|
}
|
|
|
|
CancelEvents( &EV_Hand_DoRemove );
|
|
|
|
// Play down anim
|
|
if( !IsLowering() ) {
|
|
PutAway();
|
|
animDone = GetAnimDoneTime();
|
|
PostEventMS( &EV_Hand_DoRemove, animDone - gameLocal.time );
|
|
}
|
|
else if ( IsLowered() ) { // If already down, just remove it now
|
|
Event_DoHandRemove();
|
|
}
|
|
|
|
return( true );
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::SetOwner
|
|
============
|
|
*/
|
|
void hhHand::SetOwner( idActor *owner ) {
|
|
|
|
this->owner = owner;
|
|
|
|
if (owner) {
|
|
if( GetPhysics() && GetPhysics()->IsType(hhPhysics_StaticWeapon::Type) ) {
|
|
static_cast<hhPhysics_StaticWeapon*>(GetPhysics())->SetSelfOwner( owner );
|
|
}
|
|
|
|
// only show the surface in player view
|
|
renderEntity.allowSurfaceInViewID = owner->entityNumber+1;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::ReplaceHand
|
|
============
|
|
*/
|
|
void hhHand::ReplaceHand( hhPlayer *player) {
|
|
//int animDone;
|
|
hhHand *hand = NULL;
|
|
|
|
//! What to do if hand is null?
|
|
if( !player || !player->hand.IsValid() ) {
|
|
return;
|
|
}
|
|
hand = player->hand.GetEntity();
|
|
|
|
// Copy over any key info needed
|
|
this->previousHand = hand->previousHand;
|
|
|
|
HandleWeapon( player, this );
|
|
|
|
player->hand = this;
|
|
hand->attached = false;
|
|
hand->owner = NULL;
|
|
hand->Hide();
|
|
hand->PostEventMS( &EV_Remove, 0 );
|
|
|
|
gameLocal.hands.Remove( hand );
|
|
|
|
attached = true;
|
|
Show();
|
|
Raise();
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::CheckHandAttach
|
|
============
|
|
*/
|
|
bool hhHand::CheckHandAttach( hhPlayer *owner ) {
|
|
bool debug = 0;
|
|
|
|
if ( attached ) {
|
|
gameLocal.Warning( "Tried to attach an already attached hand." );
|
|
return( false );
|
|
}
|
|
|
|
if( !owner ) {
|
|
if ( debug ) { gameLocal.Printf( "Out because of owner\n" ); }
|
|
return( false );
|
|
}
|
|
|
|
// More important hand there. Abort
|
|
if ( owner->hand.IsValid() && ( GetPriority() < owner->hand->GetPriority() ) ) {
|
|
if ( debug ) { gameLocal.Printf( "Out because of hand priority\n" ); }
|
|
return( false );
|
|
}
|
|
|
|
// More important hand about to be there. Abort
|
|
if ( owner->handNext.IsValid() && ( GetPriority() < owner->handNext->GetPriority() ) ) {
|
|
if ( debug ) { gameLocal.Printf( "Out because of next hand priority\n" ); }
|
|
return( false );
|
|
}
|
|
|
|
//? What do to if both equal priority?
|
|
if ( owner->hand.IsValid() && ( GetPriority() == owner->hand->GetPriority() ) ) {
|
|
// Same hand, abort!
|
|
if ( ( owner->hand->spawnArgs.GetString( "classname" ) == spawnArgs.GetString( "classname" ) ) && ( owner->hand != this ) ) {
|
|
if ( debug ) { gameLocal.Printf( "Out because of same hand\n" ); }
|
|
return( false );
|
|
}
|
|
}
|
|
|
|
//? What do to if both equal priority?
|
|
if ( owner->handNext.IsValid() && ( GetPriority() == owner->handNext->GetPriority() ) ) {
|
|
// Same hand, abort!
|
|
hhHand* currentHand = owner->handNext.GetEntity();
|
|
if ( ( owner->handNext->spawnArgs.GetString( "classname" ) == spawnArgs.GetString( "classname" ) ) && ( owner->handNext != this ) ) {
|
|
if ( debug ) { gameLocal.Printf( "Out because of same next hand\n" ); }
|
|
return( false );
|
|
}
|
|
}
|
|
|
|
return( true );
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::CheckHandRemove
|
|
============
|
|
*/
|
|
bool hhHand::CheckHandRemove( hhPlayer *player ) {
|
|
|
|
// Check have a valid player
|
|
if ( player == NULL ) {
|
|
gameLocal.Warning( "ERROR: DoHandRemove: We are not attached to a player!");
|
|
return( false );
|
|
}
|
|
|
|
// We aren't here!
|
|
if ( IsAttached() && ( player->hand != this ) ) {
|
|
gameLocal.Warning( "ERROR: DoHandRemove: Tried to detach from an player we are not assigned to %d %p %p",
|
|
(int) IsAttached(), player->hand, this );
|
|
return( false );
|
|
}
|
|
|
|
return( true );
|
|
}
|
|
|
|
/*
|
|
============
|
|
hhHand::SetModel
|
|
============
|
|
*/
|
|
void hhHand::SetModel( const char *modelname ) {
|
|
hhAnimatedEntity::SetModel( modelname );
|
|
}
|
|
|
|
/*
|
|
============
|
|
hhHand::Present
|
|
============
|
|
*/
|
|
void hhHand::Present() {
|
|
hhAnimatedEntity::Present();
|
|
}
|
|
|
|
/*
|
|
============
|
|
hhHand::Event_DoHandAttach
|
|
============
|
|
*/
|
|
void hhHand::Event_DoHandAttach( idEntity *owner ) {
|
|
DoHandAttach( owner );
|
|
}
|
|
|
|
/*
|
|
============
|
|
hhHand::DoHandAttach
|
|
============
|
|
*/
|
|
bool hhHand::DoHandAttach( idEntity *owner ) {
|
|
hhPlayer *player;
|
|
|
|
if ( owner && owner->IsType( hhPlayer::Type ) ) {
|
|
player = static_cast<hhPlayer *>( owner );
|
|
}
|
|
else {
|
|
gameLocal.Warning("ERROR: Tried to attach to a non-player");
|
|
return( false );
|
|
}
|
|
|
|
if ( !CheckHandAttach( player ) ) {
|
|
PostEventMS( &EV_Remove, 0 );
|
|
return( false );
|
|
}
|
|
|
|
// Sanity check, we should be the top dogh
|
|
if ( player->handNext != this && !gameLocal.isClient ) { //rww - don't care on client, because we cannot rely on handNext
|
|
gameLocal.Warning( "ERROR: We (%p) should be the next hand (%p) but aren't",
|
|
this, player->handNext );
|
|
}
|
|
|
|
// Make sure nothing has changed
|
|
HandleWeapon( player, this );
|
|
|
|
// We are top dog, replace! :)
|
|
if ( !replacePrevious ) {
|
|
previousHand = player->hand.GetEntity();
|
|
}
|
|
else {
|
|
previousHand = NULL;
|
|
}
|
|
player->hand = this;
|
|
player->handNext = NULL;
|
|
|
|
attached = true;
|
|
attachTime = -1;
|
|
|
|
Raise();
|
|
Show();
|
|
|
|
return( true );
|
|
}
|
|
|
|
/*
|
|
============
|
|
hhHand::Event_DoHandRemove
|
|
============
|
|
*/
|
|
void hhHand::Event_DoHandRemove( void ) {
|
|
DoHandRemove( );
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::ForceRemove
|
|
- Should only be called when you don't need other hands/weaspons adjusted
|
|
============
|
|
*/
|
|
void hhHand::ForceRemove( void ) {
|
|
|
|
gameLocal.hands.Remove( this );
|
|
|
|
owner = NULL;
|
|
|
|
Hide();
|
|
}
|
|
|
|
/*
|
|
============
|
|
hhHand::DoHandRemove
|
|
============
|
|
*/
|
|
bool hhHand::DoHandRemove( void ) {
|
|
hhPlayer *player;
|
|
|
|
gameLocal.hands.Remove( this );
|
|
|
|
if ( owner.IsValid() && owner.GetEntity() && owner->IsType( hhPlayer::Type ) ) {
|
|
player = static_cast<hhPlayer *>( owner.GetEntity() );
|
|
}
|
|
else {
|
|
gameLocal.Warning( "ERROR: DoHandRemove: Tried to remove from a non player" );
|
|
return( false );
|
|
}
|
|
|
|
// Play up anim
|
|
RaiseHandOrWeapon( player );
|
|
|
|
if ( !CheckHandRemove( player ) ) {
|
|
return( false );
|
|
}
|
|
|
|
// Do the actual removal logic
|
|
Hide();
|
|
PostEventMS( &EV_Remove, 0 );
|
|
|
|
if ( IsAttached() ) {
|
|
player->hand = previousHand;
|
|
previousHand = NULL;
|
|
|
|
attached = false;
|
|
}
|
|
|
|
// If we were the next hand, clear it
|
|
if ( player->handNext == this ) {
|
|
player->handNext = NULL;
|
|
}
|
|
|
|
owner = NULL;
|
|
|
|
return( true );
|
|
}
|
|
|
|
/*
|
|
============
|
|
hhHand::Event_RemoveHand
|
|
Plays the animations and schedules pointer changes
|
|
============
|
|
*/
|
|
void hhHand::Event_RemoveHand( void ) {
|
|
RemoveHand();
|
|
}
|
|
|
|
/*
|
|
===========
|
|
hhHand::AddHand
|
|
===========
|
|
*/
|
|
hhHand *hhHand::AddHand( hhPlayer *player, const char *handclass, bool attachNow ) {
|
|
idDict args;
|
|
hhHand *hand = NULL;
|
|
|
|
args.SetVector( "origin", player->GetEyePosition() );
|
|
args.SetMatrix( "rotation", player->viewAngles.ToMat3() );
|
|
|
|
hand = static_cast< hhHand * >( gameLocal.SpawnObject( handclass, &args) );
|
|
if ( hand ) {
|
|
hand->SetOwner( player );
|
|
// We have a prob if you can't attach. Should return NULL
|
|
if ( !hand->AttachHand( player, attachNow ) ) {
|
|
hand->SetOwner( NULL );
|
|
|
|
gameLocal.hands.Remove( hand );
|
|
|
|
hand->PostEventMS( &EV_Remove, 0 );
|
|
|
|
return( NULL );
|
|
}
|
|
}
|
|
|
|
return( hand );
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
hhHand::PrintHandInfo
|
|
============
|
|
*/
|
|
void hhHand::PrintHandInfo( idPlayer *player ) {
|
|
hhPlayer *hhplayer = NULL;
|
|
hhHand *hand = NULL;
|
|
int count = 0;
|
|
idList< idEntityPtr< hhHand > > orphaned;
|
|
|
|
if ( player->IsType( hhPlayer::Type ) ) {
|
|
hhplayer = (hhPlayer *) player;
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
|
|
orphaned = gameLocal.hands;
|
|
|
|
gameLocal.Printf( "Weapon: %p Class: %s State: %d\n", player->weapon,
|
|
(const char *) player->weapon->GetDict()->GetString("classname"),
|
|
(int) player->weapon->GetStatus() );
|
|
|
|
hand = hhplayer->hand.GetEntity();
|
|
while ( hand != NULL ) {
|
|
count++;
|
|
gameLocal.Printf( "Hand %d: %p Class: %s State: %d\n", count, hand,
|
|
hand->spawnArgs.GetString("classname"), (int) hand->GetStatus() );
|
|
orphaned.Remove( hand );
|
|
hand = hand->previousHand;
|
|
}
|
|
|
|
count = 0;
|
|
for ( int i = 0; i < orphaned.Num(); ++i ){
|
|
count++;
|
|
hand = orphaned[ i ].GetEntity();
|
|
gameLocal.Printf( "Orphaned Hand %d: %p Class: %s State: %d\n", count, hand,
|
|
hand->spawnArgs.GetString("classname"), (int) hand->GetStatus() );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
hhHand::GetMasterDefaultPosition
|
|
================
|
|
*/
|
|
void hhHand::GetMasterDefaultPosition( idVec3 &masterOrigin, idMat3 &masterAxis ) const {
|
|
idActor* actor = NULL;
|
|
idEntity* master = GetBindMaster();
|
|
|
|
if( master ) {
|
|
if( master->IsType(idActor::Type) ) {
|
|
actor = static_cast<idActor*>( master );
|
|
actor->DetermineOwnerPosition( masterOrigin, masterAxis );
|
|
|
|
masterOrigin = actor->ApplyLandDeflect( masterOrigin, 1.1f );
|
|
} else {
|
|
hhAnimatedEntity::GetMasterDefaultPosition( masterOrigin, masterAxis );
|
|
}
|
|
}
|
|
}
|