/* =========================================================================== Copyright (C) 2015 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code 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 2 of the License, or (at your option) any later version. OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // simpleactor.h: Base class for character AI. #pragma once #include "weapon.h" #include "sentient.h" #include "container.h" #include "stack.h" #include "navigate.h" #include "scriptmaster.h" #include "characterstate.h" #include "actorpath.h" enum eEmotionMode { EMOTION_NONE, EMOTION_NEUTRAL, EMOTION_WORRY, EMOTION_PANIC, EMOTION_FEAR, EMOTION_DISGUST, EMOTION_ANGER, EMOTION_AIMING, EMOTION_DETERMINED, EMOTION_DEAD, EMOTION_CURIOUS }; enum eAnimMode { ANIM_MODE_NONE, ANIM_MODE_NORMAL, ANIM_MODE_PATH, ANIM_MODE_PATH_GOAL, ANIM_MODE_DEST, ANIM_MODE_SCRIPTED, ANIM_MODE_NOCLIP, ANIM_MODE_FALLING_PATH, ANIM_MODE_FROZEN, ANIM_MODE_ATTACHED, }; enum eAnimWeightType { ANIM_WEIGHT_NONE, ANIM_WEIGHT_MOTION, ANIM_WEIGHT_ACTION, ANIM_WEIGHT_CROSSBLEND_1, ANIM_WEIGHT_CROSSBLEND_2, ANIM_WEIGHT_CROSSBLEND_DIALOG, ANIM_WEIGHT_SAY, ANIM_WEIGHT_AIM, ANIM_WEIGHT_LASTFRAME, }; class SimpleActor; typedef SafePtr SimpleActorPtr; class SimpleActor : public Sentient { public: int m_eAnimMode; ScriptThreadLabel m_Anim; SafePtr m_pAnimThread; int m_eNextAnimMode; const_str m_csNextAnimString; ScriptThreadLabel m_NextAnimLabel; bool m_bNextForceStart; float m_fCrouchWeight; bool m_YawAchieved; float m_DesiredYaw; bool m_bHasDesiredLookDest; bool m_bHasDesiredLookAngles; Vector m_vDesiredLookDest; Vector m_DesiredLookAngles; Vector m_DesiredGunDir; ActorPath m_Path; float m_Dest[3]; float m_NoClipDest[3]; float path_failed_time; float m_fPathGoalTime; bool m_bStartPathGoalEndAnim; const_str m_csPathGoalEndAnimScript; qboolean m_walking; qboolean m_groundPlane; vec3_t m_groundPlaneNormal; Vector watch_offset; bool m_bThink; int m_PainTime; eEmotionMode m_eEmotionMode; float m_fAimLimit_up; float m_fAimLimit_down; int m_ChangeMotionAnimIndex; int m_ChangeActionAnimIndex; int m_ChangeSayAnimIndex; protected: unsigned int m_weightType[MAX_FRAMEINFOS]; float m_weightBase[MAX_FRAMEINFOS]; float m_weightCrossBlend[MAX_FRAMEINFOS]; bool m_AnimMotionHigh; bool m_AnimActionHigh; bool m_AnimDialogHigh; public: int hit_obstacle_time; float obstacle_vel[2]; const_str m_csAnimName; const_str m_csSayAnim; const_str m_csUpperAnim; const_str m_csCurrentPosition; int m_bPathErrorTime; class PathNode *m_NearestNode; Vector m_vNearestNodePos; short m_bUpdateAnimDoneFlags; float m_maxspeed; const_str m_csMood; const_str m_csIdleMood; int m_iMotionSlot; int m_iActionSlot; int m_iSaySlot; bool m_bLevelMotionAnim; bool m_bLevelActionAnim; byte m_bLevelSayAnim; byte m_bNextLevelSayAnim; bool m_bMotionAnimSet; bool m_bActionAnimSet; bool m_bSayAnimSet; bool m_bAimAnimSet; int m_iVoiceTime; bool m_bDoAI; ScriptThreadLabel m_PainHandler; ScriptThreadLabel m_DeathHandler; ScriptThreadLabel m_AttackHandler; ScriptThreadLabel m_SniperHandler; float m_fCrossblendTime; public: CLASS_PROTOTYPE(SimpleActor); SimpleActor(); ~SimpleActor(); void Archive(Archiver &arc) override; virtual void SetMoveInfo(mmove_t *mm); virtual void GetMoveInfo(mmove_t *mm); bool CanSeeFrom(vec3_t pos, Entity *ent); virtual bool CanTarget(void); virtual bool IsImmortal(void); bool DoesTheoreticPathExist(Vector vDestPos, float fMaxPath); void SetPath(Vector vDestPos, const char *description, int iMaxDirtyTime, float *vLeashHome, float fLeashDistSquared); void SetPath(SimpleEntity *pDestNode, const char *description, int iMaxDirtyTime); void SetPathWithinDistance(Vector vDestPos, char *description, float fMaxPath, int iMaxDirtyTime); void FindPathAway(vec3_t vAwayFrom, vec2_t vDirPreferred, float fMinSafeDist); void ClearPath(void); bool PathComplete(void) const; bool PathExists(void) const; bool PathIsValid(void) const; bool PathAvoidsSquadMates(void) const; void ShortenPathToAvoidSquadMates(void); PathInfo *CurrentPathNode(void) const; PathInfo *LastPathNode(void) const; float PathDist(void) const; bool PathHasCompleteLookahead(void) const; Vector PathGoal(void) const; const float *PathDelta(void) const; bool PathGoalSlowdownStarted(void) const; void SetDest(vec3_t dest); void StopTurning(void); void SetDesiredYaw(float yaw); void SetDesiredYawDir(const vec2_t vec); void SetDesiredYawDest(const vec3_t vec); void UpdateEmotion(void); int GetEmotionAnim(void); int GetMotionSlot(int slot); int GetActionSlot(int slot); int GetSaySlot(void); void StartCrossBlendAnimSlot(int slot); void StartMotionAnimSlot(int slot, int anim, float weight); void StartAimMotionAnimSlot(int slot, int anim); void StartActionAnimSlot(int anim); void StartSayAnimSlot(int anim); void StartAimAnimSlot(int slot, int anim); void SetBlendedWeight(int slot); void EventSetAnimLength(Event *ev); void UpdateNormalAnimSlot(int slot); void UpdateCrossBlendAnimSlot(int slot); void UpdateCrossBlendDialogAnimSlot(int slot); void UpdateSayAnimSlot(int slot); void UpdateLastFrameSlot(int slot); void UpdateAnimSlot(int slot); void StopAllAnimating(void); void ChangeMotionAnim(void); void ChangeActionAnim(void); void ChangeSayAnim(void); void StopAnimating(int slot); void AnimFinished(int slot) override; void UpdateAim(void); void UpdateAimMotion(void); void EventAIOn(Event *ev); void EventAIOff(Event *ev); void EventGetWeaponGroup(Event *ev); void EventGetWeaponType(Event *ev); void EventGetPainHandler(Event *ev); void EventSetPainHandler(Event *ev); void EventGetDeathHandler(Event *ev); void EventSetDeathHandler(Event *ev); void EventGetAttackHandler(Event *ev); void EventSetAttackHandler(Event *ev); void EventGetSniperHandler(Event *ev); void EventSetSniperHandler(Event *ev); void EventSetCrossblendTime(Event *ev); void EventGetCrossblendTime(Event *ev); void EventSetEmotion(Event *ev); void EventGetPosition(Event *ev); void EventSetPosition(Event *ev); void EventGetAnimMode(Event *ev); void EventSetAnimMode(Event *ev); void EventSetAnimFinal(Event *ev); void EventNoAnimLerp(Event *ev); // Added in 2.0 const_str GetRunAnim(void); const_str GetWalkAnim(void); void DesiredAnimation(int eAnimMode, const_str csAnimString); void StartAnimation(int eAnimMode, const_str csAnimString); void DesiredAnimation(int eAnimMode, ScriptThreadLabel AnimLabel); void StartAnimation(int eAnimMode, ScriptThreadLabel AnimLabel); void ContinueAnimationAllowNoPath(void); void ContinueAnimation(void); void SetPathGoalEndAnim(const_str csEndAnim); bool UpdateSelectedAnimation(void); void Anim_Attack(void); void Anim_Suppress(void); // Added in 2.0 void Anim_Sniper(void); void Anim_Aim(void); void Anim_Shoot(void); void Anim_Idle(void); void Anim_Crouch(void); void Anim_Prone(void); void Anim_Stand(void); void Anim_Cower(void); void Anim_Killed(void); void Anim_StartPain(void); void Anim_Pain(void); void Anim_CrouchRunTo(int eAnimMode); void Anim_CrouchWalkTo(int eAnimMode); void Anim_StandRunTo(int eAnimMode); void Anim_StandWalkTo(int eAnimMode); void Anim_RunTo(int eAnimMode); void Anim_WalkTo(int eAnimMode); void Anim_RunAwayFiring(int eAnimMode); void Anim_RunToShooting(int eAnimMode); void Anim_RunToAlarm(int eAnimMode); void Anim_RunToCasual(int eAnimMode); void Anim_RunToCover(int eAnimMode); void Anim_RunToDanger(int eAnimMode); void Anim_RunToDive(int eAnimMode); void Anim_RunToFlee(int eAnimMode); void Anim_RunToInOpen(int eAnimMode); void Anim_Emotion(eEmotionMode eEmotMode); void Anim_Say(const_str csSayAnimScript, int iMinTimeSinceLastSay, bool bCanInterrupt); void Anim_FullBody(const_str csFullBodyAnim, int eAnimMode); virtual const char *DumpCallTrace(const char *pszFmt, ...) const; }; inline void SimpleActor::StartAnimation(int eAnimMode, const_str csAnimString) { m_eNextAnimMode = eAnimMode; m_csNextAnimString = csAnimString; m_bNextForceStart = true; } inline void SimpleActor::DesiredAnimation(int eAnimMode, const_str csAnimString) { m_eNextAnimMode = eAnimMode; m_csNextAnimString = csAnimString; m_bNextForceStart = false; } inline void SimpleActor::StartAnimation(int eAnimMode, ScriptThreadLabel AnimLabel) { m_eNextAnimMode = eAnimMode; m_csNextAnimString = STRING_NULL; m_NextAnimLabel = AnimLabel; m_bNextForceStart = true; } inline void SimpleActor::DesiredAnimation(int eAnimMode, ScriptThreadLabel AnimLabel) { m_eNextAnimMode = eAnimMode; m_csNextAnimString = STRING_NULL; m_NextAnimLabel = AnimLabel; m_bNextForceStart = false; } inline void SimpleActor::ContinueAnimationAllowNoPath(void) { if (m_eNextAnimMode < ANIM_MODE_NONE) { m_eNextAnimMode = m_eAnimMode; m_csNextAnimString = STRING_NULL; m_NextAnimLabel = m_Anim; m_bNextForceStart = false; } } inline void SimpleActor::ContinueAnimation(void) { ContinueAnimationAllowNoPath(); if ((m_eNextAnimMode == ANIM_MODE_PATH || m_eNextAnimMode == ANIM_MODE_PATH_GOAL) && !PathExists()) { assert(!"ContinueAnimation() called on a pathed animation, but no path exists"); Anim_Stand(); } } inline void SimpleActor::SetPathGoalEndAnim(const_str csEndAnim) { m_csPathGoalEndAnimScript = csEndAnim; } inline void SimpleActor::Archive(Archiver& arc) { int i; Sentient::Archive(arc); arc.ArchiveInteger(&m_eAnimMode); m_Anim.Archive(arc); arc.ArchiveBool(&m_bHasDesiredLookDest); arc.ArchiveBool(&m_bHasDesiredLookAngles); arc.ArchiveVector(&m_vDesiredLookDest); arc.ArchiveVec3(m_DesiredLookAngles); arc.ArchiveVec3(m_DesiredGunDir); m_Path.Archive(arc); arc.ArchiveVec3(m_Dest); arc.ArchiveVec3(m_NoClipDest); arc.ArchiveFloat(&path_failed_time); arc.ArchiveFloat(&m_fPathGoalTime); arc.ArchiveBool(&m_bStartPathGoalEndAnim); Director.ArchiveString(arc, m_csPathGoalEndAnimScript); arc.ArchiveInteger(&m_eNextAnimMode); Director.ArchiveString(arc, m_csNextAnimString); m_NextAnimLabel.Archive(arc); arc.ArchiveBool(&m_bNextForceStart); arc.ArchiveBoolean(&m_walking); arc.ArchiveBoolean(&m_groundPlane); arc.ArchiveVec3(m_groundPlaneNormal); arc.ArchiveVector(&watch_offset); arc.ArchiveBool(&m_bThink); arc.ArchiveInteger(&m_PainTime); arc.ArchiveBool(&m_bAimAnimSet); arc.ArchiveBool(&m_bActionAnimSet); Director.ArchiveString(arc, m_csMood); Director.ArchiveString(arc, m_csIdleMood); ArchiveEnum(m_eEmotionMode, eEmotionMode); arc.ArchiveFloat(&m_fAimLimit_up); arc.ArchiveFloat(&m_fAimLimit_down); for (i = 0; i < MAX_FRAMEINFOS; i++) { arc.ArchiveUnsigned(&m_weightType[i]); } for (i = 0; i < MAX_FRAMEINFOS; i++) { arc.ArchiveFloat(&m_weightBase[i]); } for (i = 0; i < MAX_FRAMEINFOS; i++) { arc.ArchiveFloat(&m_weightCrossBlend[i]); } arc.ArchiveBool(&m_AnimMotionHigh); arc.ArchiveBool(&m_AnimActionHigh); arc.ArchiveBool(&m_AnimDialogHigh); arc.ArchiveVec2(obstacle_vel); Director.ArchiveString(arc, m_csCurrentPosition); arc.ArchiveBool(&m_bMotionAnimSet); arc.ArchiveBool(&m_bDoAI); arc.ArchiveFloat(&m_fCrossblendTime); arc.ArchiveSafePointer(&m_pAnimThread); arc.ArchiveBool(&m_YawAchieved); arc.ArchiveFloat(&m_DesiredYaw); arc.ArchiveInteger(&m_iVoiceTime); arc.ArchiveBool(&m_bSayAnimSet); arc.ArchiveInteger(&hit_obstacle_time); Director.ArchiveString(arc, m_csAnimName); arc.ArchiveInteger(&m_bPathErrorTime); arc.ArchiveInteger(&m_iMotionSlot); arc.ArchiveInteger(&m_iActionSlot); arc.ArchiveInteger(&m_iSaySlot); arc.ArchiveBool(&m_bLevelMotionAnim); arc.ArchiveBool(&m_bLevelActionAnim); arc.ArchiveByte(&m_bLevelSayAnim); arc.ArchiveByte(&m_bNextLevelSayAnim); Director.ArchiveString(arc, m_csSayAnim); Director.ArchiveString(arc, m_csUpperAnim); m_PainHandler.Archive(arc); m_DeathHandler.Archive(arc); m_AttackHandler.Archive(arc); m_SniperHandler.Archive(arc); arc.ArchiveObjectPointer((Class **)&m_NearestNode); arc.ArchiveVector(&m_vNearestNodePos); arc.ArchiveFloat(&m_fCrouchWeight); arc.ArchiveFloat(&m_maxspeed); } inline void SimpleActor::StopTurning(void) { m_YawAchieved = true; } inline void SimpleActor::SetDesiredYaw(float yaw) { m_YawAchieved = false; m_DesiredYaw = yaw; } inline void SimpleActor::SetDesiredYawDir(const vec2_t vec) { SetDesiredYaw(vectoyaw(vec)); } inline void SimpleActor::SetDesiredYawDest(const vec3_t vec) { vec2_t facedir; VectorSub2D(vec, origin, facedir); if (!facedir[0] || !facedir[1]) { SetDesiredYawDir(facedir); } } inline void SimpleActor::SetDest(vec3_t dest) { VectorCopy(dest, m_Dest); }