533 lines
13 KiB
C++
533 lines
13 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* 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/>.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2006-2010 - Frictional Games
|
|
*
|
|
* This file is part of Penumbra Overture.
|
|
*/
|
|
|
|
#ifndef GAME_GAME_ENEMY_H
|
|
#define GAME_GAME_ENEMY_H
|
|
|
|
#include "hpl1/engine/engine.h"
|
|
#include "hpl1/penumbra-overture/GameEntity.h"
|
|
|
|
#include "hpl1/penumbra-overture/CharacterMove.h"
|
|
|
|
using namespace hpl;
|
|
|
|
class cGameTrigger;
|
|
class cCharacterMove;
|
|
class iGameEntity;
|
|
|
|
//-----------------------------------------
|
|
|
|
#define STATE_IDLE 0
|
|
#define STATE_HUNT 1
|
|
#define STATE_ATTACK 2
|
|
#define STATE_FLEE 3
|
|
#define STATE_KNOCKDOWN 4
|
|
#define STATE_DEAD 5
|
|
#define STATE_PATROL 6
|
|
#define STATE_INVESTIGATE 7
|
|
#define STATE_BREAKDOOR 8
|
|
#define STATE_CALLBACKUP 9
|
|
#define STATE_MOVETO 10
|
|
#define STATE_EAT 11
|
|
#define STATE_ATTENTION 12
|
|
#define STATE_NUM 13
|
|
|
|
//-----------------------------------------
|
|
|
|
enum eEnemyMoveState {
|
|
eEnemyMoveState_Backward,
|
|
eEnemyMoveState_Stopped,
|
|
eEnemyMoveState_Walking,
|
|
eEnemyMoveState_Running,
|
|
eEnemyMoveState_LastEnum
|
|
};
|
|
|
|
//-----------------------------------------
|
|
|
|
class cEnemyPatrolNode : public iSerializable {
|
|
kSerializableClassInit(cEnemyPatrolNode) public : cEnemyPatrolNode() {}
|
|
cEnemyPatrolNode(const tString &asNode, float afTime, const tString &asAnim) : msNodeName(asNode), mfWaitTime(afTime), msAnimation(asAnim) {}
|
|
|
|
tString msNodeName;
|
|
float mfWaitTime;
|
|
tString msAnimation;
|
|
};
|
|
|
|
//-----------------------------------------
|
|
|
|
class cLineOfSightRayCallback : public iPhysicsRayCallback {
|
|
public:
|
|
void Reset();
|
|
bool OnIntersect(iPhysicsBody *pBody, cPhysicsRayParams *apParams);
|
|
bool Intersected();
|
|
|
|
private:
|
|
bool mbIntersected;
|
|
iPhysicsBody *mpGrabBody;
|
|
};
|
|
|
|
//------------------------------------------
|
|
|
|
class cEnemyFindGround : public iPhysicsRayCallback {
|
|
public:
|
|
bool GetGround(const cVector3f &avStartPos, const cVector3f &avDir,
|
|
cVector3f *apDestPosition, cVector3f *apDestNormal,
|
|
float afMaxDistance = 10);
|
|
|
|
bool OnIntersect(iPhysicsBody *pBody, cPhysicsRayParams *apParams);
|
|
|
|
private:
|
|
bool mbIntersected;
|
|
float mfMinDist;
|
|
cVector3f mvPos;
|
|
cVector3f mvNormal;
|
|
float mfMaxDistance;
|
|
};
|
|
|
|
//------------------------------------------
|
|
|
|
class cEnemyCheckForDoor : public iPhysicsRayCallback {
|
|
public:
|
|
bool CheckDoor(const cVector3f &avStart, const cVector3f &avEnd);
|
|
|
|
bool BeforeIntersect(iPhysicsBody *pBody);
|
|
bool OnIntersect(iPhysicsBody *pBody, cPhysicsRayParams *apParams);
|
|
|
|
private:
|
|
bool mbIntersected;
|
|
};
|
|
|
|
//------------------------------------------
|
|
|
|
class iGameEnemy_SaveData : public iGameEntity_SaveData {
|
|
kSerializableClassInit(iGameEnemy_SaveData);
|
|
|
|
public:
|
|
bool mbHasBeenActivated;
|
|
|
|
cVector3f mvCharBodyPosition;
|
|
cVector3f mvCharBodyRotation;
|
|
int mlCurrentPatrolNode;
|
|
|
|
float mfDisappearTime;
|
|
bool mbDisappearActive;
|
|
bool mbHasDisappeared;
|
|
|
|
bool mbUsesTriggers;
|
|
|
|
cVector3f mvLastPlayerPos;
|
|
tString msOnDeathCallback;
|
|
tString msOnAttackCallback;
|
|
cContainerVec<cEnemyPatrolNode> mvPatrolNodes;
|
|
|
|
iGameEntity *CreateEntity();
|
|
};
|
|
|
|
//-----------------------------------------
|
|
|
|
class iGameEnemyState {
|
|
public:
|
|
iGameEnemyState(int alId, cInit *apInit, iGameEnemy *apEnemy);
|
|
virtual ~iGameEnemyState() = default;
|
|
|
|
virtual void OnEnterState(iGameEnemyState *apPrevState) = 0;
|
|
virtual void OnLeaveState(iGameEnemyState *apNextState) = 0;
|
|
|
|
virtual void OnUpdate(float afTimeStep) = 0;
|
|
|
|
virtual void OnDraw() = 0;
|
|
virtual void OnPostSceneDraw() = 0;
|
|
|
|
virtual void OnSeePlayer(const cVector3f &avPosition, float afChance) = 0;
|
|
virtual bool OnHearNoise(const cVector3f &avPosition, float afVolume) = 0;
|
|
virtual void OnTakeHit(float afDamage) = 0;
|
|
virtual void OnDeath(float afDamage) = 0;
|
|
virtual void OnAnimationOver(const tString &asAnimName) = 0;
|
|
virtual void OnFlashlight(const cVector3f &avPosition) = 0;
|
|
|
|
void SetPreviousState(int alX) { mlPreviousState = alX; }
|
|
int GetPreviousState() { return mlPreviousState; }
|
|
|
|
int GetId() { return mlId; }
|
|
|
|
protected:
|
|
int mlId;
|
|
cInit *mpInit;
|
|
cPlayer *mpPlayer;
|
|
iGameEnemy *mpEnemy;
|
|
cCharacterMove *mpMover;
|
|
|
|
int mlPreviousState;
|
|
};
|
|
|
|
//-----------------------------------------
|
|
|
|
class iGameEnemy : public iGameEntity {
|
|
typedef iGameEntity super;
|
|
friend class cEntityLoader_GameEnemy;
|
|
|
|
public:
|
|
iGameEnemy(cInit *apInit, const tString &asName, TiXmlElement *apGameElem);
|
|
virtual ~iGameEnemy(void);
|
|
|
|
// Special
|
|
void LoadBaseProperties(TiXmlElement *apGameElem);
|
|
|
|
// Actions
|
|
void OnPlayerInteract();
|
|
void OnPlayerPick();
|
|
|
|
void Setup(cWorld3D *apWorld);
|
|
|
|
void OnWorldLoad();
|
|
void OnPostLoadScripts();
|
|
void OnWorldExit();
|
|
void OnDraw();
|
|
void OnPostSceneDraw();
|
|
virtual void ExtraPostSceneDraw() {}
|
|
|
|
void Update(float afTimeStep);
|
|
|
|
bool IsLoading() { return mbLoading; }
|
|
|
|
void OnDamage(float afX);
|
|
void OnDeath(float afX);
|
|
|
|
void OnFlashlight(const cVector3f &avPos);
|
|
|
|
virtual void OnSetActive(bool abX);
|
|
|
|
virtual bool MoveToPos(const cVector3f &avFeetPos) = 0;
|
|
|
|
virtual void ShowPlayer(const cVector3f &avPlayerFeetPos) {}
|
|
|
|
virtual bool IsFighting() { return false; }
|
|
|
|
// Physics
|
|
void SetupBody();
|
|
|
|
// Properties
|
|
cVector3f GetPosition();
|
|
void SetFOV(float afAngle) { mfFOV = afAngle; }
|
|
|
|
const tString &GetHitPS() { return msHitPS; }
|
|
const tString &GetEnemyType() { return msEnemyType; }
|
|
|
|
const tString &GetCloseMusic() { return msCloseMusic; }
|
|
int GetCloseMusicPrio() { return mlCloseMusicPrio; }
|
|
float GetCloseMusicStartDist() { return mfCloseMusicStartDist; }
|
|
float GetCloseMusicStopDist() { return mfCloseMusicStopDist; }
|
|
|
|
const tString &GetAttackMusic() { return msAttackMusic; }
|
|
int GetAttackMusicPrio() { return mlAttackMusicPrio; }
|
|
|
|
// States
|
|
void AddState(iGameEnemyState *apState);
|
|
void ChangeState(int alId);
|
|
iGameEnemyState *GetState(int alId);
|
|
int GetCurrentStateId() { return mlCurrentState; }
|
|
|
|
// Triggers
|
|
bool HandleTrigger(cGameTrigger *apTrigger);
|
|
|
|
eGameTriggerType GetTriggerTypes() { return mTriggerTypes; }
|
|
|
|
float GetTriggerUpdateCount() { return mfTriggerUpdateCount; }
|
|
void SetTriggerUpdateCount(float afX) { mfTriggerUpdateCount = afX; }
|
|
float GetTriggerUpdateRate() { return mfTriggerUpdateRate; }
|
|
|
|
void SetSkipSoundTriggerCount(float afX) { mfSkipSoundTriggerCount = afX; }
|
|
|
|
// Content control
|
|
void PlayAnim(const tString &asName, bool abLoop, float afFadeTime,
|
|
bool abDependsOnSpeed = false, float afSpeedMul = 1.0f,
|
|
bool abSyncWithPrevFrame = false,
|
|
bool abOverideMoveState = true);
|
|
void UseMoveStateAnimations();
|
|
|
|
cAnimationState *GetCurrentAnimation() { return mpCurrentAnimation; }
|
|
|
|
void PlaySound(const tString &asName);
|
|
|
|
// Callabcks
|
|
void SetOnDeathCallback(const tString &asFunc) { msOnDeathCallback = asFunc; }
|
|
void SetOnAttackCallback(const tString &asFunc) { msOnAttackCallback = asFunc; }
|
|
tString GetOnAttackCallback() { return msOnAttackCallback; }
|
|
|
|
// AI
|
|
bool CanSeePlayer();
|
|
cCharacterMove *GetMover() { return mpMover; }
|
|
cVector3f GetLastPlayerPos() { return mvLastPlayerPos; }
|
|
void SetLastPlayerPos(const cVector3f &avPos) { mvLastPlayerPos = avPos; }
|
|
|
|
void SetTempPosition(const cVector3f &avPos) { mvTempPosition = avPos; }
|
|
cVector3f GetTempPosition() { return mvTempPosition; }
|
|
|
|
void SetTempFloat(float afX) { mfTempFloat = afX; }
|
|
float GetTempFloat() { return mfTempFloat; }
|
|
|
|
cEnemyFindGround *GetGroundFinder() { return &mFindGround; }
|
|
|
|
cEnemyCheckForDoor *GetDoorChecker() { return &mDoorCheck; }
|
|
bool CheckForDoor();
|
|
|
|
bool CheckForTeamMate(float afMaxDist, bool abCheckIfFighting);
|
|
|
|
bool IsAttracted() { return mbIsAttracted; }
|
|
void SetAttracted(bool abX) { mbIsAttracted = abX; }
|
|
|
|
bool GetUsesTriggers() { return mbUsesTriggers; }
|
|
void SetUsesTriggers(bool abX) { mbUsesTriggers = abX; }
|
|
|
|
// Patrolling
|
|
void AddPatrolNode(const tString &asNode, float afTime, const tString &asAnimation);
|
|
cEnemyPatrolNode *GetPatrolNode(int alIdx) { return &mvPatrolNodes[alIdx]; }
|
|
int GetPatrolNodeNum() { return (int)mvPatrolNodes.size(); }
|
|
cEnemyPatrolNode *CurrentPatrolNode() { return &mvPatrolNodes[mlCurrentPatrolNode]; }
|
|
|
|
void ClearPatrolNodes();
|
|
|
|
int GetCurrentPatrolNode() { return mlCurrentPatrolNode; }
|
|
float GetWaitTime() { return mfWaitTime; }
|
|
float GetWaitTimeCount() { return mfWaitTimeCount; }
|
|
|
|
void SetCurrentPatrolNode(int alX) { mlCurrentPatrolNode = alX; }
|
|
void IncCurrentPatrolNode() {
|
|
mlCurrentPatrolNode++;
|
|
if (mlCurrentPatrolNode >= (int)mvPatrolNodes.size())
|
|
mlCurrentPatrolNode = 0;
|
|
}
|
|
void SetWaitTime(float afX) { mfWaitTime = afX; }
|
|
void SetWaitTimeCount(float afX) { mfWaitTimeCount = afX; }
|
|
void AddWaitTimeCount(float afX) { mfWaitTimeCount += afX; }
|
|
|
|
float GetDoorBreakCount() { return mfDoorBreakCount; }
|
|
void SetDoorBreakCount(float afX) { mfDoorBreakCount = afX; }
|
|
void AddDoorBreakCount(float afX) { mfDoorBreakCount += afX; }
|
|
|
|
const cVector3f &GetModelOffsetAngles() { return mvModelOffsetAngles; }
|
|
|
|
// Virtual
|
|
virtual void OnUpdate(float afTimeStep) = 0;
|
|
virtual void OnLoad() = 0;
|
|
|
|
// SaveObject implementation
|
|
iGameEntity_SaveData *CreateSaveData();
|
|
void SaveToSaveData(iGameEntity_SaveData *apSaveData);
|
|
void LoadFromSaveData(iGameEntity_SaveData *apSaveData);
|
|
|
|
protected:
|
|
void UpdateEnemyPose(float afTimeStep);
|
|
|
|
void UpdateAnimations(float afTimeStep);
|
|
void UpdateCheckForPlayer(float afTimeStep);
|
|
|
|
bool HandleSoundTrigger(cGameTrigger *apTrigger);
|
|
|
|
bool LineOfSight(const cVector3f &avPos, const cVector3f &avSize);
|
|
|
|
bool mbSetFeetAtGroundOnStart;
|
|
bool mbAttachMeshToBody;
|
|
bool mbRemoveAttackerOnDisable;
|
|
|
|
tVector3fVec mvRayStartPoses;
|
|
tVector3fVec mvRayEndPoses;
|
|
|
|
cEnemyFindGround mFindGround;
|
|
|
|
eGameTriggerType mTriggerTypes;
|
|
|
|
cCharacterMove *mpMover;
|
|
|
|
tString msEnemyType;
|
|
|
|
float mfTriggerUpdateCount;
|
|
float mfTriggerUpdateRate;
|
|
|
|
float mfSkipSoundTriggerCount;
|
|
|
|
cAStarHandler *mpAStarAir;
|
|
cAStarHandler *mpAStarGround;
|
|
cAINodeContainer *mpNodeContainerAir;
|
|
cAINodeContainer *mpNodeContainerGround;
|
|
|
|
cLineOfSightRayCallback mRayCallback;
|
|
|
|
Common::Array<iGameEnemyState *> mvStates;
|
|
int mlCurrentState;
|
|
|
|
cEnemyCheckForDoor mDoorCheck;
|
|
|
|
cAnimationState *mpCurrentAnimation;
|
|
bool mbAnimationIsSpeedDependant;
|
|
float mfAnimationSpeedMul;
|
|
|
|
bool mbOverideMoveState;
|
|
eEnemyMoveState mMoveState;
|
|
|
|
cVector3f mvTempPosition;
|
|
float mfTempFloat;
|
|
|
|
tStringVec mvPreloadSounds;
|
|
|
|
bool mbLoading;
|
|
|
|
bool mbAlignToGroundNormal;
|
|
cMatrixf m_mtxStartPose;
|
|
cMatrixf m_mtxGoalPose;
|
|
float mfPoseCount;
|
|
|
|
bool mbHasBeenActivated;
|
|
|
|
bool mbUsesTriggers;
|
|
|
|
///////////////////////////////
|
|
// Variable Properties
|
|
cVector3f mvLastPlayerPos;
|
|
float mfCanSeePlayerCount;
|
|
float mfCheckForPlayerCount;
|
|
float mfCheckForPlayerRate;
|
|
bool mbCanSeePlayer;
|
|
int mlPlayerInLOSCount;
|
|
int mlMaxPlayerInLOSCount;
|
|
|
|
float mfCalcPlayerHiddenPosCount;
|
|
|
|
float mfDamageSoundTimer;
|
|
|
|
tString msOnDeathCallback;
|
|
tString msOnAttackCallback;
|
|
|
|
Common::Array<cEnemyPatrolNode> mvPatrolNodes;
|
|
|
|
int mlCurrentPatrolNode;
|
|
float mfWaitTime;
|
|
float mfWaitTimeCount;
|
|
|
|
float mfDoorBreakCount;
|
|
|
|
bool mbIsAttracted;
|
|
|
|
/////////////////////////////////
|
|
// Properties to be implemented
|
|
bool mbDisappear;
|
|
float mfDisappearMinTime;
|
|
float mfDisappearMaxTime;
|
|
float mfDisappearMinDistance;
|
|
tString msDisappearPS;
|
|
tString msDisappearSound;
|
|
bool mbDisappearFreezesRagdoll;
|
|
|
|
float mfDisappearTime;
|
|
bool mbDisappearActive;
|
|
bool mbHasDisappeared;
|
|
|
|
tString msCloseMusic;
|
|
int mlCloseMusicPrio;
|
|
float mfCloseMusicStartDist;
|
|
float mfCloseMusicStopDist;
|
|
|
|
tString msAttackMusic;
|
|
int mlAttackMusicPrio;
|
|
|
|
bool mbShowDebug;
|
|
|
|
tString msGroundNodeType;
|
|
|
|
cVector3f mvBodySize;
|
|
float mfBodyMass;
|
|
|
|
float mfMaxForwardSpeed;
|
|
float mfMaxBackwardSpeed;
|
|
|
|
float mfAcceleration;
|
|
float mfDeacceleration;
|
|
|
|
float mfMaxTurnSpeed;
|
|
float mfAngleDistTurnMul;
|
|
|
|
float mfMinBreakAngle;
|
|
float mfBreakAngleMul;
|
|
|
|
float mfSpeedMoveAnimMul;
|
|
float mfTurnSpeedMoveAnimMul;
|
|
|
|
cMatrixf m_mtxModelOffset;
|
|
cVector3f mvModelOffsetAngles;
|
|
|
|
float mfIdleToMoveLimit;
|
|
float mfMoveToLideLimit;
|
|
|
|
float mfMaxPushMass;
|
|
float mfPushForce;
|
|
|
|
float mfMaxSeeDist;
|
|
|
|
float mfMinAttackDist;
|
|
|
|
float mfFOV;
|
|
float mfFOVXMul;
|
|
|
|
float mfMaxHealth;
|
|
|
|
float mfStoppedToWalkSpeed;
|
|
float mfWalkToStoppedSpeed;
|
|
float mfWalkToRunSpeed;
|
|
float mfRunToWalkSpeed;
|
|
float mfMoveAnimSpeedMul;
|
|
tString msBackwardAnim;
|
|
tString msStoppedAnim;
|
|
tString msWalkAnim;
|
|
tString msRunAnim;
|
|
|
|
float mfMinStunSpeed;
|
|
float mfMinStunImpulse;
|
|
float mfObjectCollideStun;
|
|
float mfStunDamageMul;
|
|
|
|
tString msHitPS;
|
|
};
|
|
|
|
//--------------------------------------
|
|
|
|
class cEntityLoader_GameEnemy : public cEntityLoader_Object {
|
|
|
|
public:
|
|
cEntityLoader_GameEnemy(const tString &asName, cInit *apInit);
|
|
~cEntityLoader_GameEnemy();
|
|
|
|
private:
|
|
void BeforeLoad(TiXmlElement *apRootElem, const cMatrixf &a_mtxTransform, cWorld3D *apWorld);
|
|
void AfterLoad(TiXmlElement *apRootElem, const cMatrixf &a_mtxTransform, cWorld3D *apWorld);
|
|
|
|
cInit *mpInit;
|
|
};
|
|
|
|
//--------------------------------------
|
|
|
|
#endif // GAME_GAME_ENEMY_H
|