Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS

Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
This commit is contained in:
Cyd
2026-06-24 21:28:16 -05:00
commit 2b8ca921cb
66341 changed files with 7923174 additions and 0 deletions
@@ -0,0 +1,171 @@
/*
LONG g_JoystickXStart = INT_MAX;
LONG g_JoystickXEnd = INT_MIN;
LONG g_JoystickYStart = INT_MAX;
LONG g_JoystickYEnd = INT_MIN;
*/
//g_JoystickXStart = INT_MIN;
//g_JoystickXEnd = INT_MAX;
//g_JoystickYStart = INT_MAX;
//g_JoystickYEnd = INT_MIN;
void CRIOMAIN::UpdateJoystickX (DIJOYSTATE &js)
{
#define RANGE_JOYSTICK 1000L
#define DEADZONE_JOYSTICK 30L
LONG lJ;
LONG JoystickX_Center = 0L;
if ((g_JoystickX < -RANGE_JOYSTICK) || (g_JoystickX > RANGE_JOYSTICK))
{
// error
}
else
{
// Set StartPosition
if (g_JoystickXStart > g_JoystickX)
g_JoystickXStart = g_JoystickX;
// Set EndPosition
if (g_JoystickXEnd < g_JoystickX)
g_JoystickXEnd = g_JoystickX;
if ((g_JoystickXStart + g_JoystickXEnd) != 0) {
JoystickX_Center = (g_JoystickXStart + g_JoystickXEnd) / 2;
} else {
JoystickX_Center = 0L;
}
lJ = JoystickX_Center - g_JoystickX;
if (lJ > 0) {
lJ -= DEADZONE_JOYSTICK;
} else if (lJ < 0) {
lJ += DEADZONE_JOYSTICK;
}
if ((g_JoystickX < JoystickX_Center + DEADZONE_JOYSTICK) && (g_JoystickX > JoystickX_Center - DEADZONE_JOYSTICK)) {
g_JoystickXLast = 0;
} else {
g_JoystickXLast = lJ * 15.0L;
if (g_JoystickXLast < -1000L) {
g_JoystickXLast = -1000L;
} else if (g_JoystickXLast > 1000L) {
g_JoystickXLast = 1000L;
}
}
}
if (g_lpJoystickXMode)
{
*g_lpJoystickXMode = g_JoystickXLast;
}
#if defined(_DEBUG) && 0 // watcom
static char s_szStr[256];
sprintf (s_szStr, "@JOY_X@ RIO (%ld), CENTER (%ld),START (%ld), END (%ld), LAST (%ld) \n",
g_JoystickX, JoystickX_Center, g_JoystickXStart, g_JoystickXEnd, g_JoystickXLast);
::OutputDebugString(s_szStr);
#endif // watcom
}
void CRIOMAIN::UpdateJoystickY (DIJOYSTATE &js)
{
#define RANGE_JOYSTICK 1000L
#define DEADZONE_JOYSTICK 30L
LONG lJ;
LONG JoystickY_Center = 0L;
if ((g_JoystickY < -RANGE_JOYSTICK) || (g_JoystickY > RANGE_JOYSTICK))
{
// error
}
else
{
// Set StartPosition
if (g_JoystickYStart > g_JoystickY)
g_JoystickYStart = g_JoystickY;
// Set EndPosition
if (g_JoystickYEnd < g_JoystickY)
g_JoystickYEnd = g_JoystickY;
// Set CenterPosition
if ((g_JoystickYStart + g_JoystickYEnd) != 0) {
JoystickY_Center = (g_JoystickYStart + g_JoystickYEnd) / 2;
} else {
JoystickY_Center = 0L;
}
lJ = JoystickY_Center - g_JoystickY;
// 고감도
// Dead Zone 에서 벗어난 시점을 0으로 계산한다
if (lJ > 0) {
lJ -= DEADZONE_JOYSTICK;
} else if (lJ < 0) {
lJ += DEADZONE_JOYSTICK;
}
if ((g_JoystickY < JoystickY_Center + DEADZONE_JOYSTICK) && (g_JoystickY > JoystickY_Center - DEADZONE_JOYSTICK)) {
g_JoystickYLast = 0;
} else {
g_JoystickYLast = lJ * -15.0L;
if (g_JoystickYLast < -1000L) {
g_JoystickYLast = -1000L;
} else if (g_JoystickYLast > 1000L) {
g_JoystickYLast = 1000L;
}
}
}
js.lY = g_JoystickYLast;
#if defined(_DEBUG) && 0 // watcom
static char s_szStr[256];
sprintf (s_szStr, "@JOY_Y@ RIO (%ld), CENTER (%ld),START (%ld), END (%ld), LAST (%ld) \n",
g_JoystickY, JoystickY_Center, g_JoystickYStart, g_JoystickYEnd, g_JoystickYLast);
::OutputDebugString(s_szStr);
#endif // watcom
}
/*
void CRIOMAIN::UpdateJoystick (DIJOYSTATE &js)
{
#define DEADZONE_JOYSTICK 20L
//*
// == JOYSTICK ==
// LEFT (+) - RIGHT (-)
// UP (-) - DOWN (+)
//
if (g_lpJoystickXMode)
{
if (g_JoystickX > DEADZONE_JOYSTICK || g_JoystickX < -DEADZONE_JOYSTICK) {
*g_lpJoystickXMode = g_JoystickX * -10;
} else {
*g_lpJoystickXMode = 0;
}
}
if (g_JoystickY > DEADZONE_JOYSTICK || g_JoystickY < -DEADZONE_JOYSTICK) {
js.lY = g_JoystickY * 10;
} else {
js.lY = 0;
}
#if defined(_DEBUG) && 0 // watcom
static char s_szStr[256];
sprintf (s_szStr, "x:[%ld], y:[%ld], z:[%ld]\n",
g_JoystickX, g_JoystickY, js.lRz);
::OutputDebugString(s_szStr);
#endif // watcom
}
*/
+244
View File
@@ -0,0 +1,244 @@
#include "MW4Headers.hpp"
#include "ABLAudio.hpp"
#include <Adept\AudioChannel.hpp>
#include <Adept\AudioCommand.hpp>
#include <Adept\AudioRenderer.hpp>
#include "mwguimanager.hpp"
#include "hudcomm.hpp"
using namespace ABL;
using namespace Stuff;
AudioManager* AudioManager::m_Instance = 0;
int AudioManager::m_RefCount = 0;
AudioManager::AudioManager()
: m_AudioCommands(0)
, m_MusicCommands(0)
, m_OldTimeout(0)
, m_NewVolume(1)
, m_TransitionBegin(0)
, m_TransitionEnd(0)
{
}
AudioManager::~AudioManager()
{
m_WhoIsTalking.clear ();
}
void AudioManager::SetVOPlayed(int hash)
{
m_PlayedVoiceOvers.insert(hash);
}
void AudioManager::IncrementRefCount()
{
if (m_Instance == 0)
{
m_Instance = new AudioManager;
}
++m_RefCount;
}
void AudioManager::DecrementRefCount()
{
Verify(m_RefCount > 0);
Verify(m_Instance != 0);
--m_RefCount;
if (m_RefCount == 0)
{
delete m_Instance;
m_Instance = 0;
}
}
void AudioManager::Load(MemoryStream *stream)
{
Verify(1 == 0);
// BUGBUG: TODO: NOT YET IMPLEMENTED
}
void AudioManager::Save(MemoryStream *stream)
{
Verify(1 == 0);
// BUGBUG: TODO: NOT YET IMPLEMENTED
}
void AudioManager::AddCommand(AudioCommand* command,int talker_id)
{
m_AudioCommands.Add(command);
m_WhoIsTalking[command] = talker_id;
}
void AudioManager::DeleteAllCommands()
{
ChainIteratorOf<AudioCommand *> i(&m_AudioCommands);
AudioCommand *command;
while((command = i.ReadAndNext()) != NULL)
{
command->Stop();
}
m_WhoIsTalking.clear ();
}
void AudioManager::Update()
{
if (m_AudioCommands.GetSize () != 0)
{
MWGUIManager *gui;
gui = MWGUIManager::GetInstance ();
if (gui)
{
HUDComm *comm;
comm = Cast_Object (HUDComm *,gui->Component (MWGUIManager::HUD_COMM));
Verify (comm);
std::map<AudioCommand *,int>::iterator iter;
iter = m_WhoIsTalking.find (m_AudioCommands.GetNth(0));
int id;
if (iter == m_WhoIsTalking.end ())
id = -1;
else
id = iter->second;
comm->PlayVideo (id,m_AudioCommands.GetNth(0));
}
}
if ((m_MusicCommands.GetSize() == 0) ||
(m_TransitionEnd == 0))
{
return;
}
if ((m_MusicCommands.GetSize() > 1) &&
(gos_GetElapsedTime() > m_TransitionBegin + m_OldTimeout))
{
{
ChainIteratorOf<AudioCommand*> i(&m_MusicCommands);
AudioCommand* command = i.ReadAndNext();
command->Stop();
}
{
ChainIteratorOf<AudioCommand*> i(&m_MusicCommands);
AudioCommand* command = i.ReadAndNext();
command->Play();
}
}
ChainIteratorOf<AudioCommand*> i(&m_MusicCommands);
AudioCommand* command = i.ReadAndNext();
if (command->GetPlayMode() == gosAudio_Stop)
{
command->Play();
}
if ((AudioRenderer::Instance != 0) &&
(AudioRenderer::Instance->m_channelTypes.GetLength() > AudioRenderer::MusicType))
{
AudioRenderer::Instance->m_channelTypes[AudioRenderer::MusicType].SetVolume(GetFadeVolume());
}
if (gos_GetElapsedTime() > m_TransitionEnd)
{
m_TransitionBegin = 0;
m_TransitionEnd = 0;
}
}
void AudioManager::AddMusicCommand(AudioCommand* command, Scalar old_timeout, Scalar new_timein, Scalar new_volume)
{
m_MusicCommands.Add(command);
while (m_MusicCommands.GetSize() > 2)
{
ChainIteratorOf<AudioCommand*> i(&m_MusicCommands);
i.ReadAndNext();
i.Remove();
}
if (m_MusicCommands.GetSize() == 1)
{
old_timeout = 0;
command->Play();
}
m_OldVolume = m_NewVolume;
m_OldTimeout = old_timeout;
m_NewVolume = new_volume;
m_TransitionBegin = (Stuff::Scalar)gos_GetElapsedTime();
m_TransitionEnd = m_TransitionBegin + m_OldTimeout + new_timein;
}
Scalar AudioManager::GetFadeVolume() const
{
const Scalar elapsed_time((Scalar)gos_GetElapsedTime());
if (elapsed_time > m_TransitionEnd)
{
return (m_NewVolume);
}
if (elapsed_time < m_TransitionBegin)
{
return (m_OldVolume);
}
if (elapsed_time < m_TransitionBegin + m_OldTimeout)
{
Scalar normalized = ((Scalar)gos_GetElapsedTime() - m_TransitionBegin) / (m_OldTimeout);
return (m_OldVolume * (1 - normalized));
}
Scalar middle = m_TransitionBegin + m_OldTimeout;
Scalar normalized = (elapsed_time - middle) / (m_TransitionEnd - middle);
return (m_NewVolume * normalized);
}
void AudioManager::MapTalker(int talker, Adept::ObjectID object_id)
{
talker_mapping::iterator found = m_TalkerMappings.find(talker);
if (found != m_TalkerMappings.end())
{
(*found).second = object_id;
return;
}
talker_pair p(talker,object_id);
m_TalkerMappings.insert(p);
}
Adept::ObjectID AudioManager::TalkerObjectID(int talker)
{
talker_mapping::iterator found = m_TalkerMappings.find(talker);
if (found == m_TalkerMappings.end())
{
return (-2);
}
return ((*found).second);
}
bool AudioManager::IsVoiceOverPlaying()
{
return (m_AudioCommands.GetSize() != 0);
}
bool AudioManager::IsMusicPlaying()
{
return (m_MusicCommands.GetSize() != 0);
}
+88
View File
@@ -0,0 +1,88 @@
#ifndef ABLAUDIO_HPP
#define ABLAUDIO_HPP
#pragma warning(push)
#include <stlport\set>
#include <stlport\map>
#pragma warning(pop)
#include <Stuff\Chain.hpp>
#include <Stuff\Scalar.hpp>
#include <Adept\Entity.hpp>
namespace Adept
{
class AudioCommand;
};
namespace ABL
{
class AudioManager
{
public:
AudioManager();
~AudioManager();
bool GetVOPlayed(int hash)
{
return (m_PlayedVoiceOvers.find(hash) != m_PlayedVoiceOvers.end());
}
void SetVOPlayed(int hash);
typedef int vo_id;
static AudioManager* GetInstance()
{
return (m_Instance);
}
static void IncrementRefCount();
static void DecrementRefCount();
void Load(MemoryStream *stream);
void Save(MemoryStream *stream);
void AddCommand(AudioCommand* command,int talker_id);
void DeleteAllCommands();
void AddMusicCommand(AudioCommand* command, Scalar old_timeout, Scalar new_timein, Scalar new_volume);
void Update();
bool IsVoiceOverPlaying();
bool IsMusicPlaying();
void MapTalker(int talker, Adept::ObjectID object_id);
Adept::ObjectID TalkerObjectID(int talker);
private:
static AudioManager* m_Instance;
static int m_RefCount;
Stuff::Scalar GetFadeVolume() const;
std::set<vo_id> m_PlayedVoiceOvers;
typedef std::pair<const int, Adept::ObjectID> talker_pair;
typedef std::map<const int, Adept::ObjectID> talker_mapping;
std::map<AudioCommand *,int> m_WhoIsTalking;
talker_mapping m_TalkerMappings;
Stuff::ChainOf<AudioCommand*> m_AudioCommands;
Stuff::ChainOf<AudioCommand*> m_MusicCommands;
Stuff::Scalar m_OldVolume;
Stuff::Scalar m_OldTimeout;
Stuff::Scalar m_NewVolume;
Stuff::Scalar m_TransitionBegin;
Stuff::Scalar m_TransitionEnd;
};
};
#endif // ABLAUDIO_HPP
File diff suppressed because it is too large Load Diff
+85
View File
@@ -0,0 +1,85 @@
#pragma once
#ifndef AI_ACTION_HPP
#define AI_ACTION_HPP
#include <Stuff\Auto_Ptr.hpp>
#include "AI_Fuzzy.hpp"
#include "AI_TacticInterface.hpp"
#include "aiutils.hpp"
namespace MW4AI
{
namespace Actions
{
void Fire(TacticInterface& i,
FireStyles::FireStyleID style);
enum MoveType
{
MOVE_FORWARD,
MOVE_BACKWARD,
MOVE_TO_FACE_TARGET
};
void ApproachTarget(TacticInterface& i, MoveType move_type);
void ApproachTarget(TacticInterface& i, Stuff::Scalar when);
void FleeTarget(TacticInterface& i);
void Jump(TacticInterface& i);
void Crouch(TacticInterface& i);
void ThrottleOverride(TacticInterface& i);
void FleeNearest(TacticInterface& i, Stuff::Scalar nearest);
void Disengage(TacticInterface& i, Stuff::Scalar distance);
void FindBetterLineOfFire(TacticInterface& i);
void GoToDistanceFromTarget(TacticInterface& i, Stuff::Scalar distance, MoveType move_type);
void GoToDistanceFromNearestEnemy(TacticInterface& i, Stuff::Scalar distance, MoveType move_type);
void GoToOtherSideOfTarget(TacticInterface& i, Stuff::Scalar distance);
void StopIfMoving(TacticInterface& i);
void Dodge(TacticInterface& i, Stuff::Scalar distance, MoveType move_type);
void Circle(TacticInterface& i, MoveType move_type, Stuff::Scalar distance = 0);
void CircleRandomly(TacticInterface& i);
void CircleFloat(TacticInterface& i, Stuff::Scalar distance);
void CircleToBehindTarget(TacticInterface& i, Stuff::Scalar maximum);
void CircleToFrontOfTarget(TacticInterface& i, Stuff::Scalar maximum);
void MoveForward(TacticInterface& i, Stuff::Scalar distance);
void CircleTargetNearEnemies(TacticInterface& i, Stuff::Scalar distance);
void GoBehindTarget(TacticInterface& i, Stuff::Scalar min_distance);
void GoInFrontOfTarget(TacticInterface& i, Stuff::Scalar min_distance);
void ForceDestinationRecalc(TacticInterface& i);
void RamTarget(TacticInterface& i, Stuff::Scalar recalc_tolerance = 8.0f);
void PatrolWithinRadiusOfAttackOrderPosition(TacticInterface& i, Stuff::Scalar inner_radius, Stuff::Scalar outer_radius);
void JumpToHeight(TacticInterface& i, Stuff::Scalar height);
enum FastCircleMoveType
{
MOVE_CLOSER,
MOVE_FARTHER,
MOVE_RANDOM
};
void DoFastCircle(TacticInterface& i, FastCircleMoveType move_type);
enum TrackTarget
{
TO_TARGET,
TO_NEAREST_ENEMY,
TO_NEAREST_ENEMY_OR_TARGET
};
void Track(TacticInterface& i,
TrackTarget target,
bool fTrack = true,
bool fTurn = true,
bool fPitch = false);
bool ShouldMoveForwardToPoint(TacticInterface& i, const Stuff::Point3D& dest);
extern bool g_HelicoptersIgnoreMissionBounds;
};
};
#endif // AI_ACTION
File diff suppressed because it is too large Load Diff
+471
View File
@@ -0,0 +1,471 @@
#pragma once
#ifndef AI_BEHAVIOR_HPP
#define AI_BEHAVIOR_HPP
#include "AI_Fuzzy.hpp"
#include "AI_FireStyle.hpp"
namespace MW4AI
{
class TacticInterface;
namespace Behaviors
{
class Behavior
{
public:
virtual Fuzzy Execute(TacticInterface& i) = 0;
Behavior();
virtual ~Behavior();
bool IsHappy() const
{
return (m_Happy);
}
virtual bool ShouldStopImmediately() const;
protected:
void SetHappy(bool happy)
{
m_Happy = happy;
}
private:
bool m_Happy;
};
class TryToFire
: public Behavior
{
public:
Fuzzy Execute(TacticInterface& i);
TryToFire(FireStyles::FireStyleID style = FireStyles::FIRE_MAXIMUM, Stuff::Scalar multiplier = 1);
private:
const FireStyles::FireStyleID m_FireStyle;
const Stuff::Scalar m_Multiplier;
};
class EvasiveManeuvers
: public Behavior
{
public:
Fuzzy Execute(TacticInterface& i);
EvasiveManeuvers();
protected:
virtual bool OKtoCrouch(TacticInterface& i) const { return (false); }
private:
Stuff::Scalar m_LastForceDestinationRecalc;
};
class EvasiveBehavior
: public EvasiveManeuvers
{
public:
Fuzzy Execute(TacticInterface& i);
};
class JumpToAvoidCollision
: public Behavior
{
public:
Fuzzy Execute(TacticInterface& i);
JumpToAvoidCollision(Stuff::Scalar time = 1.5f, Stuff::Scalar radius = 10);
private:
const Stuff::Scalar m_Time;
const Stuff::Scalar m_Radius;
};
class AvoidTrafficJams
: public Behavior
{
public:
Fuzzy Execute(TacticInterface& i);
AvoidTrafficJams();
private:
Stuff::Scalar m_LastTrafficJam;
};
class DodgeIfLineOfFireBlocked
: public Behavior
{
public:
Fuzzy Execute(TacticInterface& i);
};
class DefensiveBehavior
: public EvasiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
private:
JumpToAvoidCollision m_JumpToAvoidCollision;
AvoidTrafficJams m_AvoidTrafficJams;
};
class AggressiveBehavior
: public DefensiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
private:
DodgeIfLineOfFireBlocked m_DodgeIfLineOfFireBlocked;
};
class StopAndFire
: public AggressiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
protected:
bool OKtoCrouch(TacticInterface& i) const;
private:
TryToFire m_Fire;
};
class Ram
: public Behavior
{
public:
Fuzzy Execute(TacticInterface& i);
private:
TryToFire m_Fire;
};
class Joust
: public DefensiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
Joust();
private:
TryToFire m_Fire;
enum Mode
{
HEADING_IN,
HEADING_OUT
};
Mode m_Mode;
};
class Rush
: public AggressiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
private:
TryToFire m_Fire;
};
class HitAndRun
: public AggressiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
HitAndRun();
private:
enum Mode
{
HEADING_IN,
HEADING_OUT
};
Mode m_Mode;
TryToFire m_Fire;
};
class Rear
: public AggressiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
private:
TryToFire m_Fire;
};
class Front
: public AggressiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
private:
TryToFire m_Fire;
};
class CircleOfDeath
: public DefensiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
private:
TryToFire m_Fire;
};
class Retreat
: public EvasiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
Retreat();
private:
JumpToAvoidCollision m_Jump;
AvoidTrafficJams m_AvoidTrafficJams;
};
class BackUpAndFire
: public DefensiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
private:
TryToFire m_Fire;
AvoidTrafficJams m_AvoidTrafficJams;
};
class CircleHover
: public Behavior
{
public:
Fuzzy Execute(TacticInterface& i);
private:
TryToFire m_Fire;
};
class Strafe
: public Behavior
{
public:
Fuzzy Execute(TacticInterface& i);
Strafe();
private:
enum Mode
{
HEADING_IN,
HEADING_OUT
};
Mode m_Mode;
};
class StandGround
: public DefensiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
protected:
bool OKtoCrouch(TacticInterface& i) const { return (true); }
private:
TryToFire m_Fire;
};
class JumpAndShoot
: public Behavior
{
public:
JumpAndShoot();
Fuzzy Execute(TacticInterface& i);
bool ShouldStopImmediately() const;
private:
bool m_SeenByTarget;
enum JumpMode
{
JUMPING,
WAITING
};
JumpMode m_JumpMode;
Stuff::Scalar m_HoverHeight;
};
class Snipe
: public DefensiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
Snipe();
private:
TryToFire m_Fire;
enum Mode
{
HEADING_IN,
HEADING_OUT
};
Mode m_Mode;
};
class Defend
: public EvasiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
private:
AvoidTrafficJams m_AvoidTrafficJams;
};
class ShootOnly
: public TryToFire
{
};
class LocalPatrol
: public DefensiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
protected:
bool OKtoCrouch(TacticInterface& i) const { return (true); }
private:
TryToFire m_Fire;
};
class Surrender
: public Behavior
{
public:
Fuzzy Execute(TacticInterface& i);
};
class Ambush
: public Behavior
{
public:
Ambush();
Fuzzy Execute(TacticInterface& i);
bool ShouldStopImmediately() const;
private:
enum Mode
{
RUSH_OUT,
RUSH_BACK
};
Mode m_Mode;
TryToFire m_Fire;
bool m_SeenByTarget;
};
class DeathFromAbove
: public Behavior
{
public:
DeathFromAbove();
Fuzzy Execute(TacticInterface& i);
bool ShouldStopImmediately() const;
private:
enum Mode
{
WAIT_FOR_FUEL,
RUSH_IN,
JUMP,
FALL
};
Mode m_Mode;
bool m_DoneItOnce;
};
class HeliPopup
: public Behavior
{
public:
HeliPopup();
Fuzzy Execute(TacticInterface& i);
bool ShouldStopImmediately() const;
private:
enum Mode
{
POP_UP,
POP_DOWN
};
Mode m_Mode;
bool m_SeenByTarget;
};
class DiveBomb
: public Behavior
{
public:
Fuzzy Execute(TacticInterface& i);
};
class FastCircle
: public EvasiveBehavior
{
public:
Fuzzy Execute(TacticInterface& i);
private:
TryToFire m_Fire;
JumpToAvoidCollision m_JumpToAvoidCollision;
};
class Stare
: public Behavior
{
public:
Fuzzy Execute(TacticInterface& i);
};
};
};
#endif // AI_BEHAVIOR_HPP
@@ -0,0 +1,579 @@
#include "MW4Headers.hpp"
#include "AI_CombatTacticInterface.hpp"
#include "AI_Weapons.hpp"
#include "Mech.hpp"
#include "MWMission.hpp"
#include "Airplane.hpp"
#include "AI_FireStyle.hpp"
#include "AI_Tactics.hpp"
#include "Mech.hpp"
#include "JumpJet.hpp"
#include "AI_Groups.hpp"
#include "AI_Damage.hpp"
#include "ShooterAI.hpp"
using namespace MW4AI;
extern __int64 tCombatAITime_ShotWithin;
bool CombatTacticInterface::g_DisableMovement = false;
bool CombatTacticInterface::g_DisableFiring = false;
const Stuff::Scalar min_move_reissuance_distance = 8.0f;
CombatTacticInterface::CombatTacticInterface(MechWarrior4::CombatAI& combat_ai)
: m_CombatAI(combat_ai)
, m_LastMoveDestScore(0)
{
}
void CombatTacticInterface::MoveTo(const Point3D& point, bool move_forward, bool throttle_override, MWObject* ram_target)
{
#ifdef LAB_ONLY
if (ram_target == 0)
{
Verify(PointIsValid(point,true));
}
if (g_DisableMovement == true)
{
Stop();
return;
}
#endif
// TODO: move this somewhere else; also take move_forward and throttle_override into account
if ((m_CombatAI.m_TimeNotMoving == 0) &&
(GetLengthSquared(m_CombatAI.m_LastMoveDest,point) < (min_move_reissuance_distance * min_move_reissuance_distance)))
{
return;
}
m_CombatAI.MoveToPoint(point,move_forward,throttle_override,ram_target);
m_LastMoveDestScore = 0;
}
Stuff::Point3D CombatTacticInterface::GetAimPoint() const
{
return (m_CombatAI.m_LastAimPoint);
}
void CombatTacticInterface::TrackTo(const Stuff::Point3D& point)
{
m_CombatAI.TrackToPoint(point);
}
void CombatTacticInterface::TurnTo(const Stuff::Point3D& point, bool must_be_torso_twisted)
{
m_CombatAI.TurnToPoint(point,must_be_torso_twisted);
}
void CombatTacticInterface::PitchTo(const Stuff::Point3D& point)
{
m_CombatAI.PitchToPoint(point);
}
void CombatTacticInterface::Stop()
{
m_CombatAI.StopMoving();
m_LastMoveDestScore = 0;
}
void CombatTacticInterface::Fire(FireStyles::FireStyleID style_id)
{
#ifdef LAB_ONLY
if (g_DisableFiring == true)
{
return;
}
#endif
m_CombatAI.TryToFire(style_id);
}
bool CombatTacticInterface::HasPath() const
{
if (m_CombatAI.m_CurPath != 0)
{
return (true);
}
return (false);
}
bool CombatTacticInterface::Moving() const
{
return (m_CombatAI.m_TimeNotMoving == 0);
}
Stuff::Scalar CombatTacticInterface::WeaponRange(WR_WHO who, WR_QUALIFIER qualifier) const
{
MWObject* x = 0;
if (who == TacticInterface::SELF)
{
x = &(m_CombatAI.GetSelf());
}
else
{
x = &(m_CombatAI.GetTarget());
}
if (qualifier == TacticInterface::MIN)
{
return (GetMinWeaponDistance(*x));
}
return (GetMaxWeaponDistance(*x));
}
bool CombatTacticInterface::PointIsValid(const Point3D& point, bool ignore_mission_bounds, bool ignore_squads) const
{
return (m_CombatAI.PointIsValid(point,ignore_mission_bounds,ignore_squads));
}
MechWarrior4::MWObject& CombatTacticInterface::GetSelf() const
{
return (m_CombatAI.GetSelf());
}
MechWarrior4::Vehicle* CombatTacticInterface::GetSelf_AsVehicle() const
{
return (m_CombatAI.GetSelf_AsVehicle());
}
MechWarrior4::MWObject& CombatTacticInterface::GetTarget() const
{
return (m_CombatAI.GetTarget());
}
MechWarrior4::Vehicle* CombatTacticInterface::GetTarget_AsVehicle() const
{
return (m_CombatAI.GetTarget_AsVehicle());
}
FireData::HIT_RESULT CombatTacticInterface::GetLastHitResult() const
{
return (m_CombatAI.m_HitResult);
}
Stuff::Scalar CombatTacticInterface::GetDistanceFromTargetSquared() const
{
return (m_CombatAI.m_DistanceFromTargetSquared);
}
Moods::ID CombatTacticInterface::GetMood() const
{
int current_mood = (int)m_CombatAI.CurrentMood();
return ((Moods::ID)current_mood);
}
Stuff::Scalar CombatTacticInterface::GetDistanceFromDestinationSquared() const
{
if ((m_CombatAI.m_CurMove == 0) ||
(m_CombatAI.m_CurMove->Done() == true))
{
return (0);
}
if (m_CombatAI.m_LastMoveDest.GetLengthSquared() == 0)
{
return (0);
}
Stuff::Vector3D delta;
delta.Subtract((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(),
m_CombatAI.m_LastMoveDest);
return (delta.GetLengthSquared());
}
bool CombatTacticInterface::GetLastMoveDest(Stuff::Point3D& dest, bool ignore_movement) const
{
if (ignore_movement == false)
{
if ((m_CombatAI.m_CurMove == 0) ||
(m_CombatAI.m_CurMove->Done() == true))
{
return (false);
}
}
dest = m_CombatAI.m_LastMoveDest;
return (true);
}
void CombatTacticInterface::ClearMoveOrder()
{
m_CombatAI.ClearMoveOrder();
m_LastMoveDestScore = 0;
}
bool CombatTacticInterface::ProjectileApproaching(Stuff::Scalar interval)
{
const Stuff::Scalar min_reaction_delay = 0.2f;
Verify(interval > min_reaction_delay);
if ((m_CombatAI.m_LastTimeProjectileShotAtMe == 0) ||
(gos_GetElapsedTime() < m_CombatAI.m_LastTimeProjectileShotAtMe + min_reaction_delay))
{
return (false);
}
return (gos_GetElapsedTime() < m_CombatAI.m_LastTimeProjectileShotAtMe + interval);
}
const Stuff::Point3D& CombatTacticInterface::GetProjectileOrigin()
{
return (m_CombatAI.m_LastProjectileOrigin);
}
void CombatTacticInterface::Stand()
{
if (m_CombatAI.GetSelf_AsVehicle() == 0)
{
return;
}
if (m_CombatAI.GetSelf_AsVehicle()->IsDerivedFrom(Mech::DefaultData) == true)
{
Mech* mech = Cast_Object(Mech*,m_CombatAI.GetSelf_AsVehicle());
mech->GetUpRequestRequest();
}
}
void CombatTacticInterface::Crouch()
{
m_CombatAI.Crouch();
}
bool CombatTacticInterface::Crouching() const
{
return (m_CombatAI.Crouching());
}
void CombatTacticInterface::ThrottleOverride(Stuff::Scalar duration, bool force)
{
m_CombatAI.ThrottleOverride(duration,force);
}
bool CombatTacticInterface::ShotWithin(Stuff::Scalar lastvalid) const
{
TIME_FUNCTION(tCombatAITime_ShotWithin);
if (m_CombatAI.ShotBy(gos_GetElapsedTime() - lastvalid) != 0)
{
return (true);
}
return (false);
}
bool CombatTacticInterface::FiredWithin(Stuff::Scalar lastvalid) const
{
if (gos_GetElapsedTime() < m_CombatAI.GetLastFiredTime() + lastvalid)
{
return (true);
}
return (false);
}
void CombatTacticInterface::Jump()
{
if (CanJump() == false)
{
return;
}
m_CombatAI.OrderJump();
}
void CombatTacticInterface::Jump(Stuff::Scalar duration)
{
if (CanJump() == false)
{
return;
}
m_CombatAI.OrderJump(duration);
}
void CombatTacticInterface::StopJumping()
{
m_CombatAI.OrderStopJumping();
}
bool CombatTacticInterface::GetUnableToFireDuration(Stuff::Scalar duration) const
{
return (m_CombatAI.GetUnableToFireDuration(duration));
}
bool CombatTacticInterface::ShouldForceDestinationRecalc() const
{
return (m_CombatAI.ShouldForceDestinationRecalc());
}
MechWarrior4::MWObject* CombatTacticInterface::GetNearest(bool fMustBeEnemy)
{
return (m_CombatAI.GetNearest(fMustBeEnemy));
}
int CombatTacticInterface::GetEliteLevel() const
{
return (m_CombatAI.EliteSkill());
}
Stuff::Scalar CombatTacticInterface::GetTimeTargetedByEnemy() const
{
return (m_CombatAI.GetTimeTargetedByEnemy());
}
Stuff::Scalar CombatTacticInterface::GetAttackThrottle() const
{
return (m_CombatAI.GetAttackThrottle());
}
void CombatTacticInterface::ForceDestinationRecalc()
{
m_CombatAI.ForceDestinationRecalc();
}
Stuff::Point3D CombatTacticInterface::GetMoveDest() const
{
return (m_CombatAI.GetMoveDest());
}
Stuff::Scalar CombatTacticInterface::GetLastTimeRammedTarget() const
{
return (m_CombatAI.GetLastTimeRammedTarget());
}
Stuff::Scalar CombatTacticInterface::GetLastTimeJumped() const
{
return (m_CombatAI.GetLastTimeJumped());
}
Stuff::LinearMatrix4D CombatTacticInterface::GetAttackOrderPosition() const
{
if (m_CombatAI.m_LastAttackOrderPosition.GetPointer() == 0)
{
return (m_CombatAI.GetSelf().GetLocalToWorld());
}
return (*(m_CombatAI.m_LastAttackOrderPosition));
}
bool CombatTacticInterface::GetEscapeRegionFocusIfAvailable(Stuff::Point3D& focus) const
{
return (m_CombatAI.GetEscapeRegionFocusIfAvailable(focus));
}
void CombatTacticInterface::SurrenderPose()
{
m_CombatAI.SurrenderPose();
}
void CombatTacticInterface::SetSpeed(Stuff::Scalar speed)
{
m_CombatAI.SetSpeed(speed);
}
bool CombatTacticInterface::SuicideIsOK() const
{
return (m_CombatAI.SuicideIsOK());
}
unsigned int CombatTacticInterface::NumLegsDestroyed() const
{
return (m_CombatAI.m_NumLegsBlownOff);
}
Stuff::Scalar CombatTacticInterface::GetMovementScore() const
{
return (m_LastMoveDestScore);
}
void CombatTacticInterface::SetMovementScore(Stuff::Scalar score)
{
m_LastMoveDestScore = score;
}
bool CombatTacticInterface::PointIsInBadNeighborhood(const Stuff::Point3D& point) const
{
return (m_CombatAI.PointIsInBadNeighborhood(point));
}
bool CombatTacticInterface::ShouldRun() const
{
if (m_CombatAI.m_PerWeaponRayCasting == true)
{
return (true);
}
return (m_CombatAI.ShouldRun(true));
}
Stuff::Scalar CombatTacticInterface::GetCombatRadiusForRange(Stuff::Scalar percentile_range)
{
return (m_CombatAI.GetCombatRadiusForRange(percentile_range));
}
Stuff::LinearMatrix4D CombatTacticInterface::GetLastMoveOrderPosition() const
{
if (m_CombatAI.m_LastMoveOrderPosition.GetPointer() == 0)
{
return (m_CombatAI.GetSelf().GetLocalToWorld());
}
return (*(m_CombatAI.m_LastMoveOrderPosition));
}
Stuff::Scalar CombatTacticInterface::GetNormalizedJumpJetFuel()
{
if (GetSelf().IsDerivedFrom(Mech::DefaultData) == false)
{
return (0);
}
Mech* mech = Cast_Object(Mech*,&(GetSelf()));
Check_Object(mech);
if ((mech->GetJumpJet() == 0) ||
(mech->GetJumpJet()->GetGameModel() == 0) ||
(mech->GetJumpJet()->GetGameModel()->m_burnTime <= 0))
{
return (0);
}
return (mech->GetJumpJet()->CurrentCharge() / mech->GetJumpJet()->GetGameModel()->m_burnTime);
}
bool CombatTacticInterface::CanRetreat() const
{
std::vector<MWObject*> lancemates;
Groups::GetLancemates(lancemates);
if (std::find(lancemates.begin(),lancemates.end(),&(GetSelf())) != lancemates.end())
{
return (false);
}
return (true);
}
Stuff::Scalar CombatTacticInterface::GetCurrentVulnerableComponent()
{
return (m_CombatAI.GetCurrentVulnerableComponent());
}
bool CombatTacticInterface::CanJump() const
{
if (GetSelf().IsDerivedFrom(Mech::DefaultData) == false)
{
return (false);
}
Mech* mech = Cast_Object(Mech*,&GetSelf());
if ((mech->GetJumpJet() == 0) ||
(mech->GetJumpJet()->IsDestroyed() == true))
{
return (false);
}
return (true);
}
bool CombatTacticInterface::CanCrouch() const
{
return (GetSelf().IsDerivedFrom(Mech::DefaultData));
}
void CombatTacticInterface::FloatToPoint(const Stuff::Point3D& point)
{
m_CombatAI.FloatToPoint(point);
}
bool CombatTacticInterface::IsShootOnlyAI() const
{
return (m_CombatAI.IsDerivedFrom(ShooterAI::DefaultData));
}
void CombatTacticInterface::SetFallDampingEnabled(bool enabled)
{
m_CombatAI.SetFallDampingEnabled(enabled);
}
Adept::ObjectID CombatTacticInterface::GetObjectID() const
{
return (m_CombatAI.GetSelf().objectID);
}
Stuff::Scalar CombatTacticInterface::GetMaxFireCheatAngle() const
{
return (m_CombatAI.GetMaxFireCheatAngle());
}
bool CombatTacticInterface::LineMightHitFriendlyUnits(const Stuff::Line3D& line) const
{
return (m_CombatAI.LineMightHitFriendlyUnits(line));
}
bool CombatTacticInterface::MovedWithin(Stuff::Scalar duration) const
{
return (m_CombatAI.MovedWithin(duration));
}
void CombatTacticInterface::ContinuousFlyBy(const Stuff::Point3D& loc)
{
m_CombatAI.ContinuousFlyBy(loc);
}
bool CombatTacticInterface::RecentPathsFailed() const
{
return (m_CombatAI.RecentPathsFailed());
}
bool CombatTacticInterface::CanMove() const
{
return (m_CombatAI.CanMove());
}
bool CombatTacticInterface::MoveRequestPending() const
{
return (m_CombatAI.MoveRequestPending());
}
bool CombatTacticInterface::CanTrack() const
{
return (m_CombatAI.CanTrack());
}
bool CombatTacticInterface::CanTurn() const
{
return (m_CombatAI.CanTurn());
}
Stuff::Scalar CombatTacticInterface::DamageTakenSinceAttackOrder() const
{
Stuff::Scalar damage = MW4AI::Damage::GetDamageRating(m_CombatAI.GetSelf());
return (Stuff::Fabs(damage - m_CombatAI.m_LastAttackOrderDamageRating));
}
Stuff::Point3D CombatTacticInterface::GetLeashCenter() const
{
return (m_CombatAI.m_CombatLeash);
}
Stuff::Scalar CombatTacticInterface::GetLeashRadius() const
{
return (m_CombatAI.m_CombatLeashRadius);
}
@@ -0,0 +1,35 @@
#pragma once
#ifndef AI_COMBATTACTICINTERFACE_HPP
#define AI_COMBATTACTICINTERFACE_HPP
#include "AI_TacticInterface.hpp"
namespace MechWarrior4
{
class CombatAI;
};
namespace MW4AI
{
class CombatTacticInterface
: public TacticInterface
{
DERIVED_TacticInterface;
public:
CombatTacticInterface(MechWarrior4::CombatAI& combat_ai);
static bool g_DisableMovement;
static bool g_DisableFiring;
private:
MechWarrior4::CombatAI& m_CombatAI;
Stuff::Scalar m_LastMoveDestScore;
};
};
#endif // AI_COMBATTACTICINTERFACE_HPP
+552
View File
@@ -0,0 +1,552 @@
#include "MW4Headers.hpp"
#include "AI_Condition.hpp"
#include "AI_Weapons.hpp"
#include "MWPlayer.hpp"
#include "VehicleInterface.hpp"
#include "Torso.hpp"
#include "MWMission.hpp"
#include "JumpJet.hpp"
using namespace MW4AI;
using namespace MW4AI::Conditions;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::HittingSomethingElse(TacticInterface& i)
{
AILOGFUNC("Conditions::HittingSomethingElse");
if (i.GetUnableToFireDuration(4.0f) == true)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AnyWeaponReady
//
Fuzzy Conditions::AnyWeaponReady(TacticInterface& i)
{
AILOGFUNC("Conditions::AnyWeaponReady");
if (MW4AI::AnyWeaponReady(i.GetSelf()) == true)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::ProjectileApproaching(TacticInterface& i, Stuff::Scalar min_distance)
{
AILOGFUNC("Conditions::ProjectileApproaching");
AILOG1(min_distance);
if (i.ProjectileApproaching() == true)
{
Stuff::Point3D delta;
delta.Subtract(i.GetProjectileOrigin(),(Stuff::Point3D)i.GetSelf().GetLocalToWorld());
if (delta.GetLengthSquared() < min_distance * min_distance)
{
LOG_AND_RETURN(0);
}
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::Fired(TacticInterface& i, Stuff::Scalar within_when)
{
AILOGFUNC("Conditions::Fired");
AILOG1(within_when);
if (i.FiredWithin(within_when) == true)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::TargetedByEnemy(TacticInterface& i, Stuff::Scalar duration)
{
AILOGFUNC("Conditions::TargetedByEnemy");
AILOG1(duration);
if (i.GetTimeTargetedByEnemy() >= duration)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::Rammed(TacticInterface& i, Stuff::Scalar duration)
{
AILOGFUNC("Conditions::Rammed");
AILOG1(duration);
if (i.GetLastTimeRammedTarget() + duration > gos_GetElapsedTime())
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::InsideRadiusOfTarget(TacticInterface& i, Stuff::Scalar radius)
{
AILOGFUNC("Conditions::InsideRadiusOfTarget");
AILOG1(radius);
if (i.GetDistanceFromTargetSquared() <= radius * radius)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::InsideRadiusOfTarget(TacticInterface&i, Stuff::Scalar radius, Stuff::Scalar when)
{
AILOGFUNC("Conditions::InsideRadiusOfTarget");
AILOG2(radius,when);
Stuff::Point3D my_pos(i.GetSelf().GetLocalToWorld());
Stuff::Point3D target_pos;
i.GetTarget().EstimateFuturePosition(&target_pos,(Scalar)when,true);
my_pos.y = 0;
target_pos.y = 0;
if (GetLengthSquared(my_pos,target_pos) <= radius * radius)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::InsideRadiusOfRamTarget(TacticInterface& i, Stuff::Scalar radius)
{
AILOGFUNC("Conditions::InsideRadiusOfRamTarget");
AILOG(radius);
Verify(i.GetSelf_AsVehicle() != 0);
Stuff::Scalar time_to_reach = GetApproximateLength((Stuff::Point3D)i.GetSelf().GetLocalToWorld(),
(Stuff::Point3D)i.GetTarget().GetLocalToWorld()) / i.GetSelf_AsVehicle()->GetGameModel()->maxSpeed;
Stuff::Point3D target_pos;
i.GetTarget().EstimateFuturePosition(&target_pos,time_to_reach,false);
Stuff::Point3D my_pos((Stuff::Point3D)i.GetSelf().GetLocalToWorld());
my_pos.y = 0;
target_pos.y = 0;
if (GetLengthSquared(my_pos,target_pos) <= radius * radius)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy MW4AI::Conditions::InsideWeaponsRadiusOfTarget(TacticInterface& i,
TacticInterface::WR_WHO who,
TacticInterface::WR_QUALIFIER type,
Stuff::Scalar multiplier)
{
AILOGFUNC("Conditions::InsideWeaponsRadiusOfTarget");
AILOG3(who,type,multiplier);
Stuff::Scalar radius = i.WeaponRange(who,type) * multiplier;
if (i.GetDistanceFromTargetSquared() <= radius * radius)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy MW4AI::Conditions::InsidePercentileRangeOf(TacticInterface& i, Stuff::Scalar percentile_range, bool nearest_enemy)
{
AILOGFUNC("Conditions::InsidePercentileRangeOfTarget");
AILOG2(percentile_range,nearest_enemy);
Stuff::Scalar radius = i.GetCombatRadiusForRange(percentile_range);
if (nearest_enemy == true)
{
Adept::Entity* nearest = i.GetNearest(true);
if (nearest == 0)
{
nearest = &i.GetTarget();
}
if (GetLengthSquared((Stuff::Point3D)i.GetSelf().GetLocalToWorld(),
(Stuff::Point3D)nearest->GetLocalToWorld()) <= radius * radius)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
if (i.GetDistanceFromTargetSquared() <= radius * radius)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::VehicleMoving(TacticInterface& i)
{
AILOGFUNC("Conditions::VehicleMoving");
if (i.Moving() == true)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// VehicleCrouching
//
Fuzzy Conditions::VehicleCrouching(TacticInterface& i)
{
AILOGFUNC("Conditions::VehicleCrouching");
if (i.Crouching() == true)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::FacingTarget(TacticInterface& i)
{
AILOGFUNC("Conditions::FacingTarget");
const Stuff::LinearMatrix4D& my_matrix = i.GetSelf().GetLocalToWorld();
Stuff::Point3D target_pos(i.GetTarget().GetLocalToWorld());
Stuff::UnitVector3D my_forward;
my_matrix.GetLocalForwardInWorld(&my_forward);
Stuff::Point3D forward(my_forward);
forward += (Stuff::Point3D)my_matrix;
Stuff::UnitVector3D my_backward;
my_matrix.GetLocalBackwardInWorld(&my_backward);
Stuff::Point3D backward(my_backward);
backward += (Stuff::Point3D)my_matrix;
if (GetLengthSquared(forward,target_pos) < GetLengthSquared(backward,target_pos))
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::InFrontOfTarget(TacticInterface& i, bool fUseTorso)
{
AILOGFUNC("Conditions::InFrontOfTarget");
AILOG1(fUseTorso);
LinearMatrix4D relative_to;
if ((fUseTorso == true) &&
(i.GetTarget().GetTorso() != 0) &&
(i.GetTarget().GetTorso()->twistJoint != 0))
{
Check_Object(i.GetTarget().GetTorso());
relative_to = i.GetTarget().GetTorso()->twistJoint->GetLocalToWorld();
}
else
{
relative_to = i.GetTarget().GetLocalToWorld();
}
Stuff::Point3D delta;
delta.Subtract((Stuff::Point3D)i.GetSelf().GetLocalToWorld(),(Stuff::Point3D)relative_to);
Stuff::UnitVector3D delta_normalized(delta);
Stuff::UnitVector3D local_forward;
relative_to.GetLocalForwardInWorld(&local_forward);
Stuff::Scalar bearing = delta_normalized * local_forward;
bearing += 1;
bearing *= 0.5f;
if (bearing >= 0.5f)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0); // TODO: bearing is already a fuzzy; should return it as a Fuzzy!
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::JumpedWithin(TacticInterface& i, Stuff::Scalar duration)
{
AILOGFUNC("Conditions::JumpedWithin");
AILOG1(duration);
if (i.GetLastTimeJumped() + duration >= gos_GetElapsedTime())
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool Conditions::Jumping(TacticInterface& i)
{
AILOGFUNC("Conditions::Jumping");
if (i.GetSelf().IsDerivedFrom(Mech::DefaultData) == true)
{
Mech* mech = Cast_Object(Mech*,&(i.GetSelf()));
if ((mech->GetJumpJet() != 0) &&
(mech->GetJumpJet()->executionState->GetState() == JumpJet::ExecutionStateEngine::JumpingState))
{
LOG_AND_RETURN(true);
}
}
LOG_AND_RETURN(false);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::CanBeSeenByTarget(TacticInterface& i, Stuff::Scalar within_distance)
{
AILOGFUNC("Conditions::CanBeSeenByTarget");
const Stuff::Scalar distance = GetApproximateLength((Stuff::Point3D)i.GetSelf().GetLocalToWorld(),
(Stuff::Point3D)i.GetTarget().GetLocalToWorld());
if (distance > within_distance)
{
LOG_AND_RETURN(0);
}
if ((MWMission::GetInstance() != 0) &&
(MWMission::GetInstance()->GetGameModel() != 0))
{
const Adept::Mission::GameModel* game_model = MWMission::GetInstance()->GetGameModel();
if (distance > game_model->m_generalFogEnd)
{
LOG_AND_RETURN(0);
}
}
FireData fire_data(i.GetSelf(),
i.GetSelf().GetLineOfSight(),
i.GetTarget().GetLineOfSight());
fire_data.Project();
if (fire_data.GetHitResult(&i.GetTarget()) == FireData::HIT_TARGET)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::IsHighOffGround(TacticInterface& i)
{
AILOGFUNC("Conditions::IsHighOffGround");
const Stuff::Point3D my_pos(i.GetSelf().GetLocalToWorld());
BYTE tempmaterial;
if (my_pos.y - 10 > GetMapY(my_pos.x,my_pos.z,&i.GetSelf(),tempmaterial))
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::PlayerWillHitMe(TacticInterface& i,
Stuff::Scalar seconds,
Stuff::Scalar threshold)
{
AILOGFUNC("Conditions::PlayerWillHitMe");
AILOG2(seconds,threshold);
if ((Adept::Player::GetInstance() == 0) ||
(i.GetSelf_AsVehicle() == 0))
{
LOG_AND_RETURN(0);
}
MechWarrior4::MWPlayer* player = Cast_Object(MechWarrior4::MWPlayer*,Adept::Player::GetInstance());
Check_Object(player);
if (player->GetInterface() == 0)
{
LOG_AND_RETURN(0);
}
Adept::Entity* player_entity = player->GetInterface()->vehicle;
if ((player_entity == 0) ||
(player_entity->GetAlignment() == i.GetSelf().GetAlignment()) ||
(player_entity->IsDerivedFrom(MechWarrior4::Vehicle::DefaultData) == false))
{
LOG_AND_RETURN(0);
}
threshold *= threshold;
MechWarrior4::Vehicle* player_vehicle = Cast_Object(MechWarrior4::Vehicle*,player_entity);
if (GetLengthSquared((Stuff::Point3D)player_vehicle->GetLocalToWorld(),
(Stuff::Point3D)i.GetSelf().GetLocalToWorld()) < threshold)
{
LOG_AND_RETURN(1);
}
Stuff::Point3D next_player_pos;
player_vehicle->EstimateFuturePosition(&next_player_pos, (Scalar)seconds);
Stuff::Point3D next_self_pos;
i.GetSelf_AsVehicle()->EstimateFuturePosition(&next_self_pos, (Scalar)seconds);
if (GetLengthSquared(next_self_pos,
next_player_pos) < threshold)
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::ClusterFuckingSomeone(TacticInterface& i,
Stuff::Scalar radius)
{
AILOGFUNC("Conditions::ClusterFuckingSomeone");
AILOG1(radius);
if (i.GetLastTimeRammedTarget() + 1.0f > gos_GetElapsedTime())
{
LOG_AND_RETURN(1);
}
Adept::Entity* entity = i.GetNearest();
if (entity != 0)
{
if (i.GetSelf().IsDerivedFrom(Mech::DefaultData) == false)
{
radius *= 0.8f; // this is to ensure that vehicles smaller than mechs have smaller dodge radii
}
if (GetLengthSquared((Stuff::Point3D)i.GetSelf().GetLocalToWorld(),
(Stuff::Point3D)entity->GetLocalToWorld()) < radius * radius)
{
LOG_AND_RETURN(1);
}
}
LOG_AND_RETURN(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::EliteLevelBetween(TacticInterface& i, UserConstants::ID min, UserConstants::ID max)
{
AILOGFUNC("Conditions::EliteLevelBetween");
AILOG2(min,max);
int int_min = (int)UserConstants::Instance()->Get(min);
int int_max = (int)UserConstants::Instance()->Get(max);
Verify(int_min <= int_max);
Verify(int_min >= 0);
Verify(int_max <= 100);
LOG_AND_RETURN((i.GetEliteLevel() >= int_min) && (i.GetEliteLevel() <= int_max));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Fuzzy Conditions::AttackThrottleBetween(TacticInterface& i, Stuff::Scalar min, Stuff::Scalar max)
{
AILOGFUNC("Conditions::AttackThrottleBetween");
AILOG2(min,max);
Verify(min >= 0);
Verify(max <= 100);
if ((i.GetAttackThrottle() >= min) &&
(i.GetAttackThrottle() <= max))
{
LOG_AND_RETURN(1);
}
LOG_AND_RETURN(0);
}
@@ -0,0 +1,59 @@
#pragma once
#ifndef AI_CONDITION_HPP
#define AI_CONDITION_HPP
#include "AI_Fuzzy.hpp"
#include "AI_TacticInterface.hpp"
#include "aiutils.hpp"
namespace MW4AI
{
namespace Conditions
{
Fuzzy ProjectileApproaching(TacticInterface& i, Stuff::Scalar min_distance = 0);
Fuzzy HittingSomethingElse(TacticInterface& i);
Fuzzy AnyWeaponReady(TacticInterface& i);
Fuzzy Fired(TacticInterface& i, Stuff::Scalar within_when = 5.0f);
Fuzzy TargetedByEnemy(TacticInterface& i, Stuff::Scalar duration = 0.8f);
Fuzzy Rammed(TacticInterface& i, Stuff::Scalar duration = 5.0f);
Fuzzy InsideRadiusOfTarget(TacticInterface& i,
Stuff::Scalar radius);
Fuzzy InsideRadiusOfTarget(TacticInterface&i,
Stuff::Scalar radius,
Stuff::Scalar when);
Fuzzy InsideRadiusOfRamTarget(TacticInterface& i,
Stuff::Scalar radius);
Fuzzy InsideWeaponsRadiusOfTarget(TacticInterface& i,
TacticInterface::WR_WHO who,
TacticInterface::WR_QUALIFIER type,
Stuff::Scalar multiplier = 1.0f);
Fuzzy InsidePercentileRangeOf(TacticInterface& i,
Stuff::Scalar percentile_range,
bool nearest_enemy = false);
Fuzzy PlayerWillHitMe(TacticInterface& i,
Stuff::Scalar seconds,
Stuff::Scalar threshold);
Fuzzy VehicleCrouching(TacticInterface& i);
Fuzzy VehicleMoving(TacticInterface& i);
Fuzzy ClusterFuckingSomeone(TacticInterface& i,
Stuff::Scalar radius = 10.0f);
Fuzzy FacingTarget(TacticInterface& i);
Fuzzy InFrontOfTarget(TacticInterface& i, bool fUseTorso = false);
Fuzzy JumpedWithin(TacticInterface& i, Stuff::Scalar duration);
bool Jumping(TacticInterface& i);
Fuzzy CanBeSeenByTarget(TacticInterface& i, Stuff::Scalar within_distance = 600.0f);
Fuzzy IsHighOffGround(TacticInterface& i);
Fuzzy EliteLevelBetween(TacticInterface& i, UserConstants::ID min, UserConstants::ID max);
Fuzzy AttackThrottleBetween(TacticInterface& i, Stuff::Scalar min, Stuff::Scalar max);
};
};
#endif // AI_CONDITION_HPP
+106
View File
@@ -0,0 +1,106 @@
#include "MW4Headers.hpp"
#include "AI_Damage.hpp"
#include "MWDamageObject.hpp"
using namespace MW4AI;
using namespace MW4AI::Damage;
int Damage::GetArmorDamage(MWObject& mwobject, int armor_zone)
{
Stuff::SortedChainIteratorOf<Adept::DamageObject*,int> i(&(mwobject.damageObjects));
Adept::DamageObject* o;
while ((o = i.ReadAndNext()) != 0)
{
if (o->armorZone == armor_zone)
{
return (o->GetCurrentDamageLevel());
}
}
return (Adept::DamageObject::Destroyed);
}
Stuff::Scalar Damage::GetHighResArmorLevel(MechWarrior4::MWObject& mwobject, int armor_zone)
{
Stuff::SortedChainIteratorOf<Adept::DamageObject*,int> i(&(mwobject.damageObjects));
Adept::DamageObject* o;
while ((o = i.ReadAndNext()) != 0)
{
if (o->armorZone == armor_zone)
{
return (o->GetHighResDamageLevel());
}
}
return (0);
}
int Damage::GetInternalDamage(MWObject& mwobject, int internal_zone)
{
Stuff::SortedChainIteratorOf<MechWarrior4::MWInternalDamageObject*,int> i(&(mwobject.internalDamageObjects));
MechWarrior4::MWInternalDamageObject* o;
while ((o = i.ReadAndNext()) != 0)
{
if (o->damageZone == internal_zone)
{
return (o->GetCurrentDamageLevel());
}
}
return (Adept::InternalDamageObject::Destroyed);
}
bool Damage::CanRepair(MechWarrior4::MWObject& mwobject)
{
{
Stuff::SortedChainIteratorOf<MWInternalDamageObject*,int> i(&(mwobject.internalDamageObjects));
MWInternalDamageObject* internal_damageobject = 0;
while ((internal_damageobject = i.ReadAndNext()) != 0)
{
if (internal_damageobject->CanRepair() == true)
{
return (true);
}
}
}
{
Stuff::SortedChainIteratorOf<Adept::DamageObject*,int> i(&(mwobject.damageObjects));
Adept::DamageObject* damageobject = 0;
while ((damageobject = i.ReadAndNext()) != 0)
{
if (damageobject->CanRepair() == true)
{
return (true);
}
}
}
return (false);
}
Stuff::Scalar Damage::GetDamageRating(MechWarrior4::MWObject& mwobject)
{
Stuff::Scalar score = 0;
Stuff::SortedChainIteratorOf<Adept::DamageObject*,int> i(&(mwobject.damageObjects));
Adept::DamageObject* damageobject = 0;
while ((damageobject = i.ReadAndNext()) != 0)
{
score += damageobject->currentArmorValue;
}
return (score);
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#ifndef AI_DAMAGE_HPP
#define AI_DAMAGE_HPP
#include <Stuff\Scalar.hpp>
namespace MechWarrior4
{
class MWObject;
};
namespace MW4AI
{
namespace Damage
{
int GetArmorDamage(MechWarrior4::MWObject& mwobject, int armor_zone);
Stuff::Scalar GetHighResArmorLevel(MechWarrior4::MWObject& mwobject, int armor_zone);
int GetInternalDamage(MechWarrior4::MWObject& mwobject, int internal_zone);
Stuff::Scalar GetDamageRating(MechWarrior4::MWObject& mwobject);
bool CanRepair(MechWarrior4::MWObject& mwobject);
};
};
#endif // AI_DAMAGE_HPP
@@ -0,0 +1,917 @@
#include "MW4Headers.hpp"
#include "AI_DebugRenderer.hpp"
#include <Adept\EntityManager.hpp>
#include <Adept\CameraComponent.hpp>
#include <Adept\VideoRenderer.hpp>
#include "CombatAI.hpp"
#include "MWDamageObject.hpp"
#include <MW4\MWMission.hpp>
#include <ElementRenderer\StateChange.hpp>
#include "AIUtils.hpp"
#include "MWPlayer.hpp"
#include "VehicleInterface.hpp"
#include <stdlib.h>
#include "rail_move.hpp"
#include "Flag.hpp"
#include <GameOS\ToolOS.hpp>
using namespace MW4AI;
using namespace MechWarrior4;
extern MW4AI::CPathManager *g_PathManager;
const Stuff::Scalar max_distance_from_camera_to_draw = 500.0f;
const Stuff::Scalar max_distance_from_camera_to_draw_squared = max_distance_from_camera_to_draw * max_distance_from_camera_to_draw;
const int max_line_cloud_points = 500;
const int wheel_move_pixels = 32;
const int max_wheel_move_pixels = 1000;
const unsigned int max_spew_files = 2000;
DebugRenderer* DebugRenderer::m_Instance = 0;
MechWarrior4::CombatAI* GetCombatAI(MechWarrior4::MWObject& v)
{
Verify(&v != 0);
if ((v.GetAI() == 0) ||
(v.GetAI()->IsDerivedFrom(CombatAI::DefaultData) == false))
{
return (0);
}
CombatAI* combat_ai = Cast_Object(CombatAI*,v.GetAI());
Check_Object(combat_ai);
return (combat_ai);
}
MechWarrior4::CombatAI* GetCombatAI()
{
if (Adept::Player::GetInstance() == 0)
{
return (0);
}
MechWarrior4::MWPlayer* p = Cast_Object(MechWarrior4::MWPlayer*,Adept::Player::GetInstance());
if (p == 0)
{
return (0);
}
Check_Object(p);
if ((p->GetInterface() == 0) ||
(p->GetInterface()->vehicle == 0))
{
return (0);
}
return (GetCombatAI(*(p->GetInterface()->vehicle)));
}
DebugRenderer::DebugRenderer()
: m_AIStatsRendering(STATS_NONE)
, m_DrawingMovementLines(false)
, m_DrawingMovementPaths(false)
, m_DamageInfoRendering(false)
, m_PointCount(0)
, m_DeadReckoningRenderTime(0)
, m_ShowNumPathRequests(false)
, m_WheelDelta(0)
, m_LastDiagnosticSpewFileIndex(0)
{
Verify(m_Instance == 0);
m_Instance = this;
gos_PushCurrentHeap(ElementRenderer::g_Heap);
m_LineCloud = new ElementRenderer::LineCloudElement(max_line_cloud_points);
gos_PopCurrentHeap();
m_LineCloud->SetDataPointers(&m_PointCount, m_PointData, m_ColorData);
m_LineCloud->m_localOBB.localToParent = LinearMatrix4D::Identity;
m_LineCloud->m_localOBB.sphereRadius = -1;
Mission::GetInstance()->GetElement()->AttachChild(m_LineCloud);
}
DebugRenderer::~DebugRenderer()
{
Verify(m_Instance != 0);
m_Instance = 0;
}
void DebugRenderer::Execute()
{
#ifdef _ARMOR
try
{
#endif
ResetLinesToDraw();
if ((GetAIStatsRendering() != STATS_NONE) ||
(GetDamageInfoRendering() == true))
{
DrawAIStatsAndDamageInfo();
}
if ((GetMovementLineRendering() == true) ||
(GetDeadReckoningRendering() == true))
{
DrawLines();
}
if (GetMovementPathRendering() == true)
{
DrawMovementPaths();
}
if (GetShowNumPathRequests() == true)
{
DrawNumPathRequests();
}
if (GetDiagnosticsRendering() == true)
{
DrawDiagnostics();
}
#ifdef _ARMOR
}
catch (...)
{
}
#endif
}
void DebugRenderer::DrawAIStatsAndDamageInfo()
{
Verify((GetAIStatsRendering() != STATS_NONE) || (GetDamageInfoRendering() == true));
#ifdef LAB_ONLY
if ((Adept::EntityManager::GetInstance() == 0) ||
(Adept::VideoRenderer::Instance == 0))
{
return;
}
Check_Object(Adept::EntityManager::GetInstance());
Check_Object(Adept::VideoRenderer::Instance);
CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera();
if ((camera == 0) ||
(camera->GetElement() == 0))
{
return;
}
Check_Object(camera);
Point3D camera_pos = (Point3D)camera->GetElement()->GetLocalToWorld();
HGOSFONT3D font = gos_LoadFont("Assets\\Graphics\\arial8.tga", 0);
gos_TextSetAttributes(font,0x8FFF0000,1.0f,false,true,false,false);
std::vector<Adept::Entity*> entities_to_consider;
NameTable *table = NameTable::GetInstance();
int size(table->nameTableArray[NameTable::VehicleArray].GetLength());
{for (int i = 0;
i < size;
++i)
{
NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i];
Adept::Entity* ent = data->dataPointer->GetCurrent ();
if ((ent != 0) &&
(ent->IsDerivedFrom(MWObject::DefaultData) == true))
{
entities_to_consider.push_back(Cast_Object(MWObject*,ent));
}
}}
if (Adept::NameTable::GetInstance() != 0)
{
{
int last = Adept::NameTable::GetInstance()->GetLength(Adept::NameTable::BuildingArray);
{for (int i = 0;
i < last;
++i)
{
NameTableEntry* entry = Adept::NameTable::GetInstance()->FindEntry(Adept::NameTable::BuildingArray,i);
if ((entry != 0) &&
(entry->dataPointer->GetCurrent() != 0))
{
Adept::Entity* entity = entry->dataPointer->GetCurrent();
if (entity->IsDerivedFrom(MWObject::DefaultData) == true)
{
MWObject* mwobject = Cast_Object(MWObject*,entity);
if (mwobject->GetAI() != 0)
{
entities_to_consider.push_back(mwobject);
}
}
}
}}
}
{
int last = Adept::NameTable::GetInstance()->GetLength(Adept::NameTable::TurretArray);
{for (int i = 0;
i < last;
++i)
{
NameTableEntry* entry = Adept::NameTable::GetInstance()->FindEntry(Adept::NameTable::TurretArray,i);
if ((entry != 0) &&
(entry->dataPointer->GetCurrent() != 0))
{
Adept::Entity* entity = entry->dataPointer->GetCurrent();
if (entity->IsDerivedFrom(MWObject::DefaultData) == true)
{
entities_to_consider.push_back(entity);
}
}
}}
}
}
{
int size(Adept::NameTable::GetInstance()->nameTableArray[NameTable::FlagArray].GetLength());
{for (int i = 0;
i < size;
++i)
{
NameTableEntry *data = &Adept::NameTable::GetInstance()->nameTableArray [NameTable::FlagArray][i];
Adept::Entity* ent = data->dataPointer->GetCurrent();
if ((ent != 0) &&
(ent->IsDerivedFrom(Flag::DefaultData) == true))
{
entities_to_consider.push_back(ent);
}
}}
}
{for (std::vector<Adept::Entity*>::const_iterator i = entities_to_consider.begin();
i != entities_to_consider.end();
++i)
{
Point3D pos = (Point3D)(*i)->GetLocalToWorld();
Vector3D delta_from_camera;
delta_from_camera.Subtract(pos,camera_pos);
delta_from_camera.y = 0;
if (delta_from_camera.GetLengthSquared() > max_distance_from_camera_to_draw_squared)
{
continue;
}
Stuff::Vector2DOf<Stuff::Scalar> screen_pos;
if (WorldToScreenCoords(pos,screen_pos) == false)
{
continue;
}
screen_pos.x *= Environment.screenWidth;
screen_pos.y *= Environment.screenHeight;
if ((screen_pos.x >= Environment.screenWidth) ||
(screen_pos.y >= Environment.screenHeight))
{
continue;
}
if (PositionIsInFrontOfCamera(pos) == false)
{
continue;
}
int alpha = 0xFF000000 - ((int)((DistanceFromCamera(pos) * 200.0f) / max_distance_from_camera_to_draw) << 24);
int color = 0;
switch ((*i)->objectID & 0x00000007)
{
case 1: color = 0x008F8F8F; break;
case 2: color = 0x0000008F; break;
case 3: color = 0x00008F00; break;
case 4: color = 0x008F0000; break;
case 5: color = 0x008F008F; break;
case 6: color = 0x00008F8F; break;
case 7: color = 0x008F8F00; break;
}
gos_TextSetAttributes(font,alpha + color,1.0f,false,true,false,false);
gos_TextSetRegion((int)screen_pos.x,(int)screen_pos.y,Environment.screenWidth,Environment.screenHeight);
gos_TextSetPosition((int)screen_pos.x,(int)screen_pos.y);
std::string s;
if ((*i)->IsDerivedFrom(MWObject::DefaultData) == true)
{
MWObject* mwobject = Cast_Object(MWObject*,*i);
if ((GetAIStatsRendering() == STATS_ALL) ||
((GetAIStatsRendering() == STATS_CURRENT_VEHICLE) && (mwobject->GetAI() == GetCombatAI())))
{
mwobject->AddStatsToString(s);
if (mwobject->GetAI() != 0)
{
mwobject->GetAI()->AddStatsToString(s);
}
}
if (GetDamageInfoRendering() == true)
{
mwobject->AddDamageInfoToString(s);
}
}
else
{
if ((*i)->IsDerivedFrom(Flag::DefaultData) == true)
{
Flag* flag = Cast_Object(Flag*,*i);
flag->AddStatsToString(s);
}
}
gos_TextDraw(s.c_str());
gos_TextSetAttributes(font,0xFFFF0000,1.0f,false,true,false,false);
}}
gos_DeleteFont(font);
#endif
}
void DebugRenderer::DrawNumPathRequests()
{
#ifdef LAB_ONLY
Verify(GetShowNumPathRequests() == true);
HGOSFONT3D font = gos_LoadFont("Assets\\Graphics\\arial8.tga", 0);
gos_TextSetAttributes(font,0xFFFFFFFF,1.0f,false,true,false,false);
gos_TextSetRegion(0,0,Environment.screenWidth,Environment.screenHeight);
gos_TextSetPosition(10,2);
std::string s = "Path Requests: ";
s += IntToString(MW4AI::g_PathManager->GetNumPathRequests());
gos_TextDraw(s.c_str());
gos_DeleteFont(font);
#endif
}
bool DebugRenderer::PositionIsInFrontOfCamera(const Stuff::Point3D& pos) const
{
if (Adept::VideoRenderer::Instance == 0)
{
return (false);
}
CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera();
if ((camera == 0) ||
(camera->GetElement() == 0))
{
return (false);
}
Check_Object(camera);
Stuff::LinearMatrix4D matrix = camera->GetElement()->GetLocalToWorld();
if (pos == (Stuff::Point3D)matrix)
{
return (true);
}
return (GetSquaredDistToMatrixForward(pos,matrix) < GetSquaredDistToMatrixBackward(pos,matrix));
}
Stuff::Scalar DebugRenderer::DistanceFromCamera(const Stuff::Point3D& pos) const
{
if (Adept::VideoRenderer::Instance == 0)
{
return (false);
}
CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera();
if ((camera == 0) ||
(camera->GetElement() == 0))
{
return (false);
}
Check_Object(camera);
Stuff::Vector3D delta;
delta.Subtract((Stuff::Point3D)camera->GetElement()->GetLocalToWorld(),pos);
return (delta.GetApproximateLength());
}
void DebugRenderer::DrawLines()
{
Verify(GetMovementLineRendering() == true);
#ifdef LAB_ONLY
NameTable *table = NameTable::GetInstance();
int size(table->nameTableArray[NameTable::VehicleArray].GetLength());
{for (int i = 0;
i < size;
++i)
{
NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i];
Adept::Entity* ent = data->dataPointer->GetCurrent ();
if ((ent != 0) &&
(ent->IsDestroyed() == false) &&
(ent->IsDerivedFrom(MWObject::DefaultData) == true))
{
MWObject* v = Cast_Object(MWObject*,ent);
Verify(v != 0);
Check_Object(v);
if ((GetMovementLineRendering() == true) &&
(GetCombatAI(*v) != 0))
{
std::vector<Stuff::Point3D> points;
GetCombatAI(*v)->GetDirectPath(points);
if (points.size() > 0)
{
// points[0].y += 8.0f;
// points[1].y += 8.0f;
AddPointsToLinesToDraw(points,Stuff::RGBAColor(0xFF,0,0,0));
}
}
if (GetDeadReckoningRendering() == true)
{
std::vector<Stuff::Point3D> points;
points.push_back((Stuff::Point3D)v->GetLocalToWorld());
Stuff::Point3D temp;
points.push_back(v->EstimateFuturePosition(&temp, (Scalar)m_DeadReckoningRenderTime));
points[0].y += 6.0f;
points[1].y += 6.0f;
AddPointsToLinesToDraw(points,Stuff::RGBAColor(0,0,0xFF,0));
}
}
}}
DrawLineCloud();
#endif
}
void DebugRenderer::DrawLineCloud()
{
#ifdef LAB_ONLY
gos_PushCurrentHeap(ElementRenderer::g_Heap);
if (m_PointCount > 0)
{
{for (int i = 0;
i < m_PointCount;
++i)
{
Scalar length = m_PointData[i].GetLengthSquared();
if (length > m_LineCloud->m_localOBB.sphereRadius)
{
m_LineCloud->m_localOBB.sphereRadius = length;
}
}}
m_LineCloud->NeedNewBounds();
m_LineCloud->NeedMatrixSync();
ElementRenderer::StateChange *state = new ElementRenderer::StateChange();
Check_Object(state);
state->DisableZBufferCompare();
m_LineCloud->AdoptStateChange(state);
m_LineCloud->Sync();
}
gos_PopCurrentHeap();
#endif
}
void DebugRenderer::DrawMovementPaths()
{
Verify(GetMovementPathRendering() == true);
#ifdef LAB_ONLY
NameTable *table = NameTable::GetInstance();
int size(table->nameTableArray[NameTable::VehicleArray].GetLength());
{for (int i = 0;
i < size;
++i)
{
NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i];
Adept::Entity* ent = data->dataPointer->GetCurrent ();
if ((ent != 0) &&
(ent->IsDerivedFrom(Vehicle::DefaultData) == true))
{
Check_Object(ent);
Vehicle* v = Cast_Object(Vehicle*,ent);
Verify(v != 0);
Check_Object(v);
if (GetCombatAI(*v) != 0)
{
MW4AI::CRailPath* cur_path = GetCombatAI(*v)->getCurPath();
if (cur_path != 0)
{
Stuff::Point3D my_pos(v->GetLocalToWorld());
std::vector<Stuff::Point3D> path;
cur_path->PointList(path);
if (path.size () == 0)
continue;
path.insert(path.begin(),my_pos);
{for (int i = 1;
i < path.size();
++i)
{
std::vector<Stuff::Point3D> path2;
path2.push_back(path[i-1]);
path2.push_back(path[i]);
path2[0].y = my_pos.y + 7.0f;
path2[1].y = my_pos.y + 7.0f;
AddPointsToLinesToDraw(path2,Stuff::RGBAColor(0,0xFF,0,0));
}}
}
}
}
}}
DrawLineCloud();
#endif
}
DebugRenderer::STATS_RENDERING DebugRenderer::GetAIStatsRendering() const
{
return (m_AIStatsRendering);
}
void DebugRenderer::SetAIStatsRendering(DebugRenderer::STATS_RENDERING fDrawStats)
{
m_AIStatsRendering = fDrawStats;
}
bool DebugRenderer::GetDamageInfoRendering() const
{
return (m_DamageInfoRendering);
}
void DebugRenderer::SetDamageInfoRendering(bool fDrawDamageInfo)
{
m_DamageInfoRendering = fDrawDamageInfo;
}
bool DebugRenderer::GetMovementLineRendering() const
{
return (m_DrawingMovementLines);
}
void DebugRenderer::SetMovementLineRendering(bool fDrawMovementLines)
{
m_DrawingMovementLines = fDrawMovementLines;
}
bool DebugRenderer::GetMovementPathRendering() const
{
return (m_DrawingMovementPaths);
}
void DebugRenderer::SetMovementPathRendering(bool fDrawMovementPaths)
{
m_DrawingMovementPaths = fDrawMovementPaths;
}
DebugRenderer* DebugRenderer::GetInstance()
{
return (m_Instance);
}
bool DebugRenderer::WorldToScreenCoords(const Stuff::Point3D& world_coords,
Stuff::Vector2DOf<Stuff::Scalar>& screen_coords) const
{
if (Adept::VideoRenderer::Instance == 0)
{
return (false);
}
CameraComponent* camera = Adept::VideoRenderer::Instance->GetSceneCamera();
if ((camera == 0) ||
(camera->GetElement() == 0))
{
return (false);
}
Check_Object(camera);
camera->ComputeCursor(&screen_coords,world_coords);
return (true);
}
void DebugRenderer::ResetLinesToDraw()
{
m_PointCount = 0;
}
void DebugRenderer::AddPointsToLinesToDraw(const std::vector<Stuff::Point3D>& points, const Stuff::RGBAColor& color)
{
if (m_PointCount >= max_line_cloud_points)
{
return;
}
{for (std::vector<Stuff::Point3D>::const_iterator i = points.begin();
i != points.end();
++i)
{
m_PointData[m_PointCount] = *i;
// m_PointData[m_PointCount].y += 8.0f;
m_ColorData[m_PointCount] = color;
++m_PointCount;
if (m_PointCount >= max_line_cloud_points)
{
return;
}
}}
}
void DebugRenderer::SetDeadReckoningRenderTime(Stuff::Time time)
{
m_DeadReckoningRenderTime = time;
}
Stuff::Time DebugRenderer::GetDeadReckoningRenderTime() const
{
return (m_DeadReckoningRenderTime);
}
bool DebugRenderer::GetDeadReckoningRendering() const
{
return (m_DeadReckoningRenderTime > 0);
}
bool DebugRenderer::GetShowNumPathRequests() const
{
return (m_ShowNumPathRequests);
}
void DebugRenderer::SetShowNumPathRequests(bool fShow)
{
m_ShowNumPathRequests = fShow;
}
bool DebugRenderer::GetDiagnosticsRendering() const
{
if ((MWMission::GetInstance() == 0) ||
(MWMission::GetInstance()->IsDerivedFrom(MWMission::DefaultData) == false))
{
return (false);
}
Check_Object(MWMission::GetInstance());
MWMission *mission = Cast_Object(MWMission*,MWMission::GetInstance());
return (mission->GetDiagnosticsInterface().GetEnabled());
}
bool EraseSpewFile(unsigned int index)
{
std::string s = "AISpew\\spew.";
std::string suffix = IntToString(index);
while (suffix.size() < 4)
{
suffix = "0" + suffix;
}
s += suffix;
if (gos_DoesFileExist(s.c_str()) == true)
{
gos_DeleteFile(s.c_str());
return (true);
}
return (false);
}
void EraseExistingSpewFiles()
{
bool erased0 = EraseSpewFile(0);
bool erasedmax = EraseSpewFile(max_spew_files);
if ((erased0 == false) &&
(erasedmax == false))
{
return;
}
unsigned int i = 1;
bool previous = false;
while (i < max_spew_files)
{
previous = EraseSpewFile(i);
++i;
}
if (erasedmax == true)
{
++i;
}
if (previous == true)
{
while (EraseSpewFile(i) == true)
{
++i;
}
}
}
void SpewEntityInfo(Adept::Entity& entity, std::string& string, bool include_geometry_info = false)
{
string += "ObjectID: ";
string += IntToString(entity.objectID);
string += "; Name: ";
string += entity.instanceName;
if (include_geometry_info == true)
{
string += "\n Position: (";
Stuff::Point3D pos(entity.GetLocalToWorld());
string += ScalarToString(pos.x);
string += ",";
string += ScalarToString(pos.y);
string += ",";
string += ScalarToString(pos.z);
string += ")";
if (entity.IsDerivedFrom(MechWarrior4::Vehicle::DefaultData) == true)
{
MechWarrior4::Vehicle* v = Cast_Object(MechWarrior4::Vehicle*,&entity);
Check_Object(v);
string += "; Velocity: ";
string += ScalarToString(v->currentSpeedMPS);
string += " mps";
}
else
{
string += "; [not a vehicle]";
}
}
}
void SpewToDiagnosticFile(const std::string& spew_output, unsigned int index)
{
std::string text_to_spew = "Last Compile Date/Time: ";
text_to_spew += __DATE__;
text_to_spew += ", ";
text_to_spew += __TIME__;
text_to_spew += "\nSpewed at gos_GetElapsedTime() = ";
text_to_spew += ScalarToString((Stuff::Scalar)gos_GetElapsedTime());
text_to_spew += "\n";
CombatAI* combat_ai = GetCombatAI();
if (combat_ai != 0)
{
text_to_spew += "Vehicle AI ";
SpewEntityInfo(*combat_ai,text_to_spew);
text_to_spew += "\n\nVehicle ";
SpewEntityInfo(combat_ai->GetSelf(),text_to_spew,true);
text_to_spew += "\n\n";
combat_ai->AddStatsToString(text_to_spew);
if (combat_ai->Target() != 0)
{
text_to_spew += "\n\nTarget ";
SpewEntityInfo(*(combat_ai->Target()),text_to_spew,true);
}
else
{
text_to_spew += "\nNo target.";
}
}
text_to_spew += "\n\n";
text_to_spew += spew_output;
std::string s = "AISpew\\spew.";
std::string suffix = IntToString(index);
while (suffix.size() < 4)
{
suffix = "0" + suffix;
}
s += suffix;
HGOSFILE hGOSfile;
gos_OpenFile(&hGOSfile,s.c_str(),READWRITE);
gos_WriteFile(hGOSfile,text_to_spew.c_str(),text_to_spew.size());
gos_CloseFile(hGOSfile);
}
void DebugRenderer::DrawDiagnostics()
{
#ifdef LAB_ONLY
if ((MWMission::GetInstance() == 0) ||
(MWMission::GetInstance()->IsDerivedFrom(MWMission::DefaultData) == false))
{
return;
}
int wheelDelta = 0;
gos_GetMouseInfo(0,0,0,0,&wheelDelta,0);
if (wheelDelta != 0)
{
if (wheelDelta < 0)
{
m_WheelDelta += wheel_move_pixels;
if (m_WheelDelta > max_wheel_move_pixels)
{
m_WheelDelta = max_wheel_move_pixels;
}
}
else
{
m_WheelDelta -= wheel_move_pixels;
if (m_WheelDelta < 0)
{
m_WheelDelta = 0;
}
}
}
Check_Object(MWMission::GetInstance());
MWMission *mission = Cast_Object(MWMission*,MWMission::GetInstance());
std::string s;
mission->GetDiagnosticsInterface().GetSpew(s);
if (s.size() == 0)
{
return;
}
if (DiagnosticsInterface::GetInstance().GetFileSpewing() == true)
{
if (m_LastDiagnosticSpewFileIndex == 0)
{
EraseExistingSpewFiles();
gos_CreateDirectory("AISpew");
}
if (m_LastDiagnosticSpewFileIndex >= max_spew_files)
{
EraseSpewFile(m_LastDiagnosticSpewFileIndex - max_spew_files);
}
if (s != m_LastDiagnosticSpew)
{
SpewToDiagnosticFile(s,m_LastDiagnosticSpewFileIndex);
++m_LastDiagnosticSpewFileIndex;
}
}
HGOSFONT3D font = gos_LoadFont("Assets\\Graphics\\arial8.tga", 0);
gos_TextSetAttributes(font,0xFF000000,1.0f,false,true,false,false);
gos_TextSetRegion(10,10,Environment.screenWidth,Environment.screenHeight);
gos_TextSetPosition(10,10 - m_WheelDelta);
gos_TextDraw(s.c_str());
gos_DeleteFont(font);
m_LastDiagnosticSpew = s;
#endif
}
@@ -0,0 +1,126 @@
#pragma once
#ifndef AI_DEBUGRENDERER_HPP
#define AI_DEBUGRENDERER_HPP
#include <Stuff\Auto_Ptr.hpp>
#include <ElementRenderer\LineCloudElement.hpp>
#pragma warning (push)
#include <stlport\vector>
#include <stlport\string>
#pragma warning (pop)
namespace MW4AI
{
class DebugRenderer
{
public:
DebugRenderer();
~DebugRenderer();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Instance
//
static DebugRenderer* GetInstance();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Drawing
//
void Execute();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AI Statistics
//
enum STATS_RENDERING
{
STATS_NONE,
STATS_ALL,
STATS_CURRENT_VEHICLE
};
STATS_RENDERING GetAIStatsRendering() const;
void SetAIStatsRendering(STATS_RENDERING fDrawStats);
bool GetDamageInfoRendering() const;
void SetDamageInfoRendering(bool fDrawDamageInfo);
bool GetMovementLineRendering() const;
void SetMovementLineRendering(bool fDrawMovementLines);
bool GetMovementPathRendering() const;
void SetMovementPathRendering(bool fDrawMovementPaths);
bool GetDeadReckoningRendering() const;
void SetDeadReckoningRenderTime(Stuff::Time time = 0);
Stuff::Time GetDeadReckoningRenderTime() const;
bool GetShowNumPathRequests() const;
void SetShowNumPathRequests(bool fShow);
bool GetDiagnosticsRendering() const;
private:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Helper functions
//
bool WorldToScreenCoords(const Stuff::Point3D& world_coords,
Stuff::Vector2DOf<Stuff::Scalar>& screen_coords) const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Rendering functions
//
void DrawLines();
void DrawMovementPaths();
void DrawAIStatsAndDamageInfo();
void DrawNumPathRequests();
void DrawLineCloud();
void DrawDiagnostics();
bool PositionIsInFrontOfCamera(const Stuff::Point3D& pos) const;
Stuff::Scalar DistanceFromCamera(const Stuff::Point3D& pos) const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Line-drawing functions
//
void ResetLinesToDraw();
void AddPointsToLinesToDraw(const std::vector<Stuff::Point3D>& points,
const Stuff::RGBAColor& color);
private:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Data members
//
static DebugRenderer* m_Instance;
STATS_RENDERING m_AIStatsRendering;
bool m_DamageInfoRendering;
bool m_DrawingMovementLines;
bool m_DrawingMovementPaths;
enum { MAX_LINE_POINTS = 400 };
Stuff::Point3D m_PointData[MAX_LINE_POINTS];
Stuff::RGBAColor m_ColorData[MAX_LINE_POINTS];
unsigned m_PointCount;
ElementRenderer::LineCloudElement* m_LineCloud;
Stuff::Time m_DeadReckoningRenderTime;
bool m_ShowNumPathRequests;
unsigned int m_LastDiagnosticSpewFileIndex;
std::string m_LastDiagnosticSpew;
int m_WheelDelta;
};
};
#endif // AI_DEBUGRENDERER_HPP
@@ -0,0 +1,609 @@
#include "MW4Headers.hpp"
#include <Adept\DamageObject.hpp>
#include "AI_FindObject.hpp"
#include "Sensor.hpp"
#include "MWDamageObject.hpp"
#include "rail_move.hpp"
#include "CombatAI.hpp"
#include "MWPlayer.hpp"
#include "MWMission.hpp"
#include "VehicleInterface.hpp"
#include "MFB.hpp"
const Stuff::Scalar min_distance = 10.0f;
const Stuff::Scalar max_distance = 1000.0f;
const Stuff::Scalar min_tonnage = 40.0f;
const Stuff::Scalar max_tonnage = 105.0f;
const Stuff::Scalar find_object_shot_by_time = 2.0f;
const Stuff::Scalar building_data_refresh_rate = 4.0f;
const Stuff::Scalar find_object_cache_delay = 3.0f;
extern __int64 tCombatAITime_FindObject;
using namespace MW4AI;
using namespace MW4AI::FindObject;
using namespace MechWarrior4;
typedef SensorData sensor_data;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Scoring functions
//
inline Stuff::Scalar ScoreDistance(Adept::Entity& src, Adept::Entity& dest)
{
Vector3D delta;
delta.Subtract((Point3D)src.GetLocalToWorld(),(Point3D)dest.GetLocalToWorld());
delta.y = 0;
return (NormalizedValue(delta.GetLengthSquared(),
min_distance * min_distance,
max_distance * max_distance,
true));
}
inline Stuff::Scalar ScoreTonnage(Adept::Entity& entity)
{
if (entity.IsDerivedFrom(MWObject::DefaultData) == false)
{
return (0);
}
MWObject* object = Cast_Object(MWObject*,&entity);
return (NormalizedValue(object->GetTonage(),min_tonnage,max_tonnage));
}
inline Stuff::Scalar ScoreDamage(Adept::Entity& object)
{
if (object.IsDerivedFrom(MWObject::DefaultData) == false)
{
return (0);
}
MWObject* v = Cast_Object(MWObject*,&object);
Stuff::SortedChainIteratorOf<MWInternalDamageObject*,int> i(&(v->internalDamageObjects));
MWInternalDamageObject* o;
Stuff::Scalar total_damage = 0;
Stuff::Scalar max_damage = 0;
while ((o = i.ReadAndNext()) != 0)
{
total_damage += o->currentInternalDamage;
max_damage += o->baseInternalDamage;
}
if (Small_Enough(max_damage))
{
return (0);
}
return (NormalizedValue(total_damage,max_damage * 0.66f,max_damage,true)); // we crank up the minimum so 33% damage is considered 100% score
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ScoreByCriteria()
// Scores the given object (with a normalized score) using the given find criteria
Stuff::Scalar ScoreByCriteria(MWObject& src,
MWObject& target,
int criteria)
{
Verify((MW4AI::FindObject::Criteria)criteria >= MW4AI::FindObject::FC_FIRST);
Verify((MW4AI::FindObject::Criteria)criteria <= MW4AI::FindObject::FC_LAST);
switch ((MW4AI::FindObject::Criteria)criteria)
{
case MW4AI::FindObject::FC_BEST_TARGET:
{
return (0.45f * ScoreDistance(src,target) +
0.35f * ScoreDamage(target) +
0.2f * ScoreTonnage(target));
}
case MW4AI::FindObject::FC_GREATEST_THREAT:
{
return (0.6f * ScoreDistance(src,target) +
0.4f * ScoreTonnage(target));
}
case MW4AI::FindObject::FC_LEAST_THREAT:
{
return (1.0f - (0.6f * ScoreDistance(src,target) +
0.4f * ScoreTonnage(target)));
}
case MW4AI::FindObject::FC_MOST_DAMAGED:
{
return (ScoreDamage(target));
}
case MW4AI::FindObject::FC_NEAREST:
{
return (ScoreDistance(src,target));
}
}
Verify(!"Should never get here.");
return (ScoreDistance(src,target));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// QualifiesByAlignment
// Indicates whether a given sensor data object qualifies by testing its alignment
// against the given alignment-specification value.
bool QualifiesByAlignment(MWObject& src,
MWObject& target,
int fa_alignment)
{
Verify(fa_alignment != 0); // value of 0 makes no sense
Verify(fa_alignment <= MW4AI::FindObject::FA_ANY);
if (&src == &target)
{
return (false);
}
switch (src.GetRelativeAlignment(target.GetAlignment()))
{
case Adept::Entity::Enemy:
{
return ((fa_alignment & MW4AI::FindObject::FA_ENEMY) != 0);
}
case Adept::Entity::Player:
{
return ((fa_alignment & MW4AI::FindObject::FA_FRIENDLY) != 0);
}
case Adept::Entity::DefaultAlignment:
{
return ((fa_alignment & MW4AI::FindObject::FA_NEUTRAL) != 0);
}
}
return (false);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// QualifiesByType
// Indicates whether a given sensor data object qualifies by testing its
// object type against the given alignment-specification value.
bool QualifiesByType(MWObject& src,
MWObject& target,
int ft_type)
{
Verify(ft_type != 0); // 0 is invalid: you must specify a type
if (target.GetTargetDesirability() == MWObject::desirability_never)
{
return (false);
}
if (ft_type & FT_BUILDING)
{
if (target.IsDerivedFrom(Building::DefaultData) == true)
{
return (true);
}
}
if (ft_type & FT_MFB)
{
if (target.IsDerivedFrom(MFB::DefaultData) == true)
{
return (true);
}
}
if ((target.GetTargetDesirability() == MWObject::desirability_invalid) &&
(target.IsPlayerVehicle() == false))
{
if (target.GetAI() == 0)
{
return (false);
}
if ((target.weaponChain.IsEmpty() == true) &&
(target.IsDerivedFrom(Mech::DefaultData) == false) &&
(!(ft_type & FT_UNARMED)))
{
return (false);
}
}
if (ft_type & FT_MECH)
{
if (target.IsDerivedFrom(Mech::DefaultData) == true)
{
return (true);
}
}
if (ft_type & FT_AIRPLANE)
{
if (target.IsDerivedFrom(Airplane::DefaultData) == true)
{
return (true);
}
}
if (ft_type & FT_VEHICLE)
{
if ((target.IsDerivedFrom(Vehicle::DefaultData) == true) &&
(target.IsDerivedFrom(MFB::DefaultData) == false) &&
(target.IsDerivedFrom(Mech::DefaultData) == false) &&
(target.IsDerivedFrom(Airplane::DefaultData) == false))
{
return (true);
}
}
if (ft_type & FT_BOAT)
{
if (target.IsDerivedFrom(Boat::DefaultData) == true)
{
return (true);
}
}
if (ft_type & FT_TURRET)
{
if (target.IsDerivedFrom(Building::DefaultData) == true)
{
return (true);
}
}
return (false);
}
bool Qualifies(MWObject& src,
MWObject& target,
int fa_alignment,
int ft_type)
{
if (QualifiesByAlignment(src,target,fa_alignment) == false)
{
return (false);
}
return (QualifiesByType(src,target,ft_type));
}
void FillNameTableData(MWObject& src,
std::vector<MWObject*>& objects_to_search)
{
Adept::NameTable* table = Adept::NameTable::GetInstance();
{
int size(table->nameTableArray[NameTable::VehicleArray].GetLength());
{for (int i = 0;
i < size;
++i)
{
NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i];
Adept::Entity* ent = data->dataPointer->GetCurrent();
if ((ent != 0) &&
(ent->IsDestroyed() == false) &&
(ent != &src) &&
(ent->IsDerivedFrom(MWObject::DefaultData) == true))
{
objects_to_search.push_back(Cast_Object(MWObject*,ent));
}
}}
}
{
int size(table->nameTableArray[NameTable::PlayerArray].GetLength());
{for (int i = 0;
i < size;
++i)
{
NameTableEntry *data = &table->nameTableArray [NameTable::PlayerArray][i];
Adept::Entity* ent = data->dataPointer->GetCurrent ();
if ((ent != 0) &&
(ent->IsDerivedFrom(Adept::Player::DefaultData) == true))
{
Adept::Player* player = Cast_Object(Adept::Player*,ent);
if ((player->vehicle != 0) &&
(player->vehicle->IsDestroyed() == false) &&
(player->vehicle != &src) &&
(player->vehicle->IsDerivedFrom(MWObject::DefaultData) == true))
{
objects_to_search.push_back(Cast_Object(MWObject*,player->vehicle));
}
}
}}
}
}
void FillSensorData(MWObject& src,
const Sensor::sensorDataArray& sensed_data,
int number_of_contacts,
std::vector<MWObject*>& sensor_data_list)
{
if ((src.GetAI() != 0) &&
(src.GetAI()->GetExtendedSensorData(sensor_data_list) == true))
{
return;
}
if (number_of_contacts == 0)
{
return;
}
sensor_data_list.reserve(number_of_contacts);
{for (int i = 0;
i < number_of_contacts;
++i)
{
if ((sensed_data[i] != 0) &&
(sensed_data[i]->object.GetCurrent() != 0) &&
(sensed_data[i]->object.GetCurrent() != &src))
{
sensor_data_list.push_back(sensed_data[i]->object.GetCurrent());
}
}}
}
// FindObject(): finds an object given the given sensor (sensor) and qualifier (object_type)
long MW4AI::FindObject::Find(MWObject& src,
int fa_alignment,
int ft_type,
int fc_criteria,
int ff_flags,
Stuff::Scalar distance_limit,
const Adept::ObjectID* except_object)
{
AI_LOGIC("Find Object");
TIME_FUNCTION(tCombatAITime_FindObject);
Verify(ff_flags <= FF_WHO_SHOT + FF_SEEPLAYER + FF_LOOK_EVERYWHERE + FF_TARGETLOS);
if (distance_limit == 0)
{
distance_limit = MW4AI::FindObject::DISTANCE_LIMIT;
}
if (src.m_FindObjectList == 0)
{
src.m_FindObjectList = new MW4AI::FindObjectList;
}
std::vector<MWObject*>& objects_to_search = src.m_FindObjectList->objects;
objects_to_search.clear();
if ((ff_flags & MW4AI::FindObject::FF_SEEPLAYER) &&
(MWMission::GetInstance()->GetGameModel() != 0) &&
(Adept::Player::GetInstance() != 0))
{
MWPlayer* p = Cast_Object(MWPlayer*,Adept::Player::GetInstance());
if ((p != 0) &&
(p->GetInterface() != 0) &&
(p->GetInterface()->vehicle != 0))
{
Vehicle* vehicle = p->GetInterface()->vehicle;
if ((QualifiesByAlignment(src,*vehicle,fa_alignment) == true) &&
(vehicle->IsDestroyed() == false) &&
(vehicle->objectID != src.objectID))
{
const Adept::Mission::GameModel* game_model = MWMission::GetInstance()->GetGameModel();
Stuff::Scalar fog_distance = game_model->m_generalFogEnd;
if (fog_distance > 1200)
{
fog_distance = 1200;
}
if (fog_distance > distance_limit)
{
fog_distance = distance_limit;
}
Stuff::Point3D player_vehicle_pos(vehicle->GetLineOfSight());
Stuff::Point3D my_pos(src.GetLineOfSight());
Stuff::LinearMatrix4D src_los;
src.GetLineOfSight(src_los);
if ((GetLengthSquared(player_vehicle_pos,my_pos) < fog_distance * fog_distance) &&
(MatrixFacesPoint(src_los,player_vehicle_pos,Stuff::Pi_Over_4) == true))
{
if ((src.m_FindObjectCache != 0) &&
(src.m_FindObjectCache->m_RayCastTime + find_object_cache_delay < gos_GetElapsedTime()))
{
delete src.m_FindObjectCache;
src.m_FindObjectCache = 0;
}
MW4AI::FireData::HIT_RESULT hit_result;
if (src.m_FindObjectCache != 0)
{
hit_result = src.m_FindObjectCache->m_HitResult;
}
else
{
FireData fire_data(src,my_pos,player_vehicle_pos);
fire_data.Project();
hit_result = fire_data.GetHitResult(vehicle);
src.m_FindObjectCache = new MW4AI::FindObjectCache((Stuff::Scalar)gos_GetElapsedTime(),hit_result);
}
if (hit_result == FireData::HIT_TARGET)
{
if (src.GetSensor() == 0)
{
return (vehicle->objectID);
}
else
{
objects_to_search.push_back(vehicle);
}
}
}
}
}
}
if ((src.GetSensor() == 0) &&
(objects_to_search.size() == 0))
{
return (-2);
}
if ((ff_flags & MW4AI::FindObject::FF_WHO_SHOT) &&
(src.GetAI() != 0))
{
Adept::Entity* e = src.GetAI()->ShotBy(gos_GetElapsedTime() - find_object_shot_by_time);
if ((e != 0) &&
(e != &src) &&
(e->IsDerivedFrom(MWObject::DefaultData) == true) &&
(e->IsDestroyed() == false))
{
MWObject* v = Cast_Object(MWObject*,e);
Check_Object(v);
if (QualifiesByAlignment(src,*v,fa_alignment) == true)
{
return (v->objectID);
}
}
}
if (ff_flags & MW4AI::FindObject::FF_LOOK_EVERYWHERE)
{
FillNameTableData(src,objects_to_search);
}
else
{
FillSensorData(src,
src.GetSensor()->RefreshAndGetSensorData(),
src.GetSensor()->numberOfContacts,
objects_to_search);
if (ft_type & FT_BUILDING)
{
if (src.GetSensor()->GetLastTimeUpdatedBuildingData() < gos_GetElapsedTime() + building_data_refresh_rate + Stuff::Random::GetFraction())
{
src.GetSensor()->UpdateBuildingData();
}
FillSensorData(src,
src.GetSensor()->GetBuildingData(),
src.GetSensor()->numberOfBuildingContacts,
objects_to_search);
}
}
if (objects_to_search.size() == 0)
{
return (-2);
}
const Stuff::Scalar distance_limit_squared = distance_limit * distance_limit;
Stuff::Scalar best_score = 0;
std::vector<MWObject*>::const_iterator best_found = objects_to_search.end();
Stuff::Point3D my_pos(src.GetLocalToWorld());
{for (std::vector<MWObject*>::const_iterator i = objects_to_search.begin();
i != objects_to_search.end();
++i)
{
if ((except_object != 0) &&
((*i)->objectID == *except_object))
{
continue;
}
if (ff_flags & MW4AI::FindObject::FF_TARGETLOS)
{
// Test line of sight
Stuff::Point3D target_pos((*i)->GetLineOfSight());
Stuff::Point3D my_pos(src.GetLineOfSight());
FireData fire_data(src,my_pos,target_pos);
fire_data.Project();
if (fire_data.GetHitResult((*i)) != FireData::HIT_TARGET)
{
continue;
}
}
if (Qualifies(src,**i,fa_alignment,ft_type) == true)
{
Point3D pos((*i)->GetLocalToWorld());
Scalar distance(0);
if (src.GetAI() != 0)
{
distance = src.GetAI()->GetLeastSquaredSensorDistance(pos);
}
if (distance == 0)
{
Vector3D delta;
delta.Subtract(my_pos,pos);
delta.y = 0;
distance = delta.GetLengthSquared();
}
if (distance < distance_limit_squared)
{
Stuff::Scalar s;
if ((*i)->GetTargetDesirability() == MWObject::desirability_invalid)
{
s = ScoreByCriteria(src,**i,fc_criteria);
}
else
{
Verify((*i)->GetTargetDesirability() != MWObject::desirability_never);
s = (*i)->GetTargetDesirability();
}
Verify(s >= 0);
Verify(s <= 1);
if (s >= best_score)
{
if (s == 1)
{
return ((*i)->objectID);
}
best_score = s;
best_found = i;
}
}
}
}}
if (best_found == objects_to_search.end())
{
return (-2); // -2 = ABL constant for nothing found
}
return ((*best_found)->objectID);
}
@@ -0,0 +1,75 @@
#pragma once
#ifndef AI_FINDOBJECT_HPP
#define AI_FINDOBJECT_HPP
namespace MechWarrior4 { class Sensor; class MWObject; }
namespace MW4AI
{
namespace FindObject
{
enum Type // These must match the constants in MWCONST.ABI
{
FT_VEHICLE = 1, // if specified, include vehicles
FT_MECH = 2, // if specified, include 'Mechs
FT_AIRPLANE = 4, // if specified, include airplanes + helicopters
FT_BOAT = 8, // if specified, include boats
FT_MFB = 16, // if specified, include MFBs
FT_TURRET = 32, // if specified, include turrets
// the default:
FT_DEFAULT = 63, // include any units: = FT_VEHICLE + FT_MECH + FT_AIRPLANE + FT_BOAT + FT_MFB + FT_HOVER + FT_HELI + FT_BUILDING
// extras not included in the default
FT_BUILDING = 64, // if specified, take buildings into account
FT_UNARMED = 128 // if specified, include unarmed units (such as APCs)
};
enum Alignment // These must match the constants in MWCONST.ABI
{
FA_FRIENDLY = 1,
FA_ENEMY = 2,
FA_NEUTRAL = 4,
FA_ANY = FA_FRIENDLY + FA_ENEMY + FA_NEUTRAL
};
enum Criteria // These must match the constants in MWCONST.ABI
{
FC_BEST_TARGET = 1001, // change FC_FIRST if you change this
FC_GREATEST_THREAT = 1002,
FC_LEAST_THREAT = 1003,
FC_MOST_DAMAGED = 1004,
FC_NEAREST = 1005 // change FC_LAST if you change this
};
enum
{
FC_FIRST = FC_BEST_TARGET,
FC_LAST = FC_NEAREST
};
enum Flags // These must match the constants in MWCONST.ABI
{
FF_WHO_SHOT = 1,
FF_SEEPLAYER = 2,
FF_LOOK_EVERYWHERE = 4,
FF_TARGETLOS =8
};
enum
{
DISTANCE_LIMIT = 2000
};
long Find(MechWarrior4::MWObject& src,
int fa_alignment,
int ft_type,
int fc_criteria,
int ff_flags,
Stuff::Scalar distance_limit = (Stuff::Scalar)DISTANCE_LIMIT,
const Adept::ObjectID* except_object = 0);
};
};
#endif AI_FINDOBJECT_HPP
@@ -0,0 +1,37 @@
#ifndef AI_FINDOBJECTCACHE_HPP
#define AI_FINDOBJECTCACHE_HPP
#include "AI_FireData.hpp"
namespace MechWarrior4
{
class MWObject;
};
namespace MW4AI
{
class FindObjectCache
{
public:
FindObjectCache(Stuff::Scalar time, FireData::HIT_RESULT hit_result)
: m_RayCastTime(time)
, m_HitResult(hit_result)
{
}
const Stuff::Scalar m_RayCastTime;
const FireData::HIT_RESULT m_HitResult;
};
class FindObjectList
{
public:
std::vector<MechWarrior4::MWObject*> objects;
};
};
#endif // AI_FINDOBJECTCACHE_HPP
+209
View File
@@ -0,0 +1,209 @@
#include "MW4Headers.hpp"
#include "AI_FireData.hpp"
#include <Adept\CollisionGrid.hpp>
#include <Adept\Map.hpp>
#include "MWMover.hpp"
#include "aiutils.hpp"
#include "Weapon.hpp"
#include "ProjectileWeapon.hpp"
#include "Vehicle.hpp"
#include "MWDamageObject.hpp"
#include <Adept\Entity.hpp>
#include <Adept\Site.hpp>
using namespace MW4AI;
using namespace Stuff;
extern __int64 tCombatAITime_RayCasting;
extern __int64 tRayCasting;
Stuff::Scalar ground_hit_fudge_distance = 20.0f;
// TODO: how to ensure that our lifetime is longer than the source? refcounting? will it be an issue?
FireData::FireData(Adept::Entity& source,
const Stuff::Point3D& src,
const Stuff::Point3D& dest)
: m_Query(&m_Line,&m_Normal,Adept::Entity::CanBeShotFlag,&source)
, m_Normal(1,0,0)
, m_Source(source)
{
Check_Object(&source);
CreateLine(src,dest);
}
FireData::FireData(Adept::Entity& source,
MechWarrior4::Weapon& weapon,
const Stuff::Point3D& dest)
: m_Query(&m_Line,&m_Normal,Adept::Entity::CanBeShotFlag,&source)
, m_Normal(1,0,0)
, m_Source(source)
{
Check_Object(&source);
Stuff::Point3D src;
if (weapon.sitePointer == 0)
{
src = weapon.GetParentVehicle()->GetLocalToWorld();
}
else
{
src = weapon.sitePointer->GetLocalToWorld();
}
CreateLine(src,dest);
}
void FireData::CreateLine(const Stuff::Point3D& src,
const Stuff::Point3D& dest)
{
Vector3D target_direction;
target_direction.Subtract(dest,src);
m_Line.SetOrigin(src);
if (Small_Enough(target_direction))
{
m_Line.SetDirection(UnitVector3D(1,0,0));
m_Line.m_length = 0;
}
else
{
UnitVector3D origin_direction;
if (target_direction.GetLengthSquared() == 0)
{
target_direction = Stuff::Point3D(1,0,0);
}
origin_direction.Normalize(target_direction);
m_Line.SetDirection(origin_direction);
m_Line.m_length = target_direction.GetLength();
}
}
FireData::FireData(const FireData& copy_from)
: m_Query(copy_from.m_Query)
, m_Normal(copy_from.m_Normal)
, m_Line(copy_from.m_Line)
, m_Source(copy_from.m_Source)
{
m_Query.m_line = &m_Line;
m_Query.m_normal = &m_Normal;
}
Adept::Entity* FireData::Project()
{
if ((Small_Enough(m_Line.m_length)) ||
(Small_Enough(m_Line.m_direction)))
{
return (0);
}
Adept::Entity *entity_hit;
Check_Object(CollisionGrid::Instance);
{
TIME_FUNCTION(tCombatAITime_RayCasting);
TIME_FUNCTION(tRayCasting);
entity_hit = CollisionGrid::Instance->ProjectLine(&m_Query);
}
m_Query.m_raySource = entity_hit;
return (entity_hit);
}
FireData::HIT_RESULT FireData::GetHitResult(Adept::Entity* desired_target, bool ignore_dead_components) const
{
Verify(Adept::Map::GetInstance() != 0);
if (desired_target == 0)
{
if ((m_Query.m_raySource == 0) ||
(m_Query.m_raySource == Adept::Map::GetInstance()))
{
return (HIT_TARGET);
}
return (HIT_SOMETHING_ELSE);
}
Check_Object(desired_target);
if (m_Query.m_raySource == 0)
{
return (HIT_NOTHING);
}
if ((m_Query.m_raySource == Adept::Map::GetInstance()) &&
(m_Query.m_line != 0))
{
if (m_Query.m_line->m_length + ground_hit_fudge_distance > GetApproximateLength(GetOrigin(),(Stuff::Point3D)desired_target->GetLocalToWorld()))
{
return (HIT_NOTHING);
}
return (HIT_SOMETHING_ELSE);
}
if (m_Query.m_raySource->IsDerivedFrom(MWMover::DefaultData) == false)
{
if (m_Query.m_raySource == desired_target)
{
return (HIT_TARGET);
}
return (HIT_SOMETHING_ELSE);
}
MechWarrior4::MWMover* mover = Cast_Object(MechWarrior4::MWMover*,m_Query.m_raySource);
Check_Object(mover);
if (mover == desired_target)
{
return (HIT_TARGET);
}
if (ignore_dead_components == false)
{
if ((mover->damageObject != 0) &&
(mover->damageObject->internalDamageObject != 0) &&
(mover->damageObject->internalDamageObject->GetCurrentDamageLevel() == Adept::InternalDamageObject::Destroyed))
{
return (HIT_NOTHING);
}
}
if (mover->GetParentVehicle() == 0)
{
return (HIT_NOTHING);
}
if ((mover->GetParentVehicle() == desired_target) ||
(mover->GetParentVehicle()->GetAlignment() != m_Source.GetAlignment()))
{
return (HIT_TARGET);
}
return (HIT_SOMETHING_ELSE);
}
bool FireData::HitsGround() const
{
if ((m_Query.m_raySource != 0) &&
(m_Query.m_raySource == Adept::Map::GetInstance()) &&
(m_Query.m_line != 0))
{
return (true);
}
return (false);
}
+111
View File
@@ -0,0 +1,111 @@
#pragma once
#ifndef AI_FIREDATA_HPP
#define AI_FIREDATA_HPP
#include <Adept\Entity.hpp>
#include <Stuff\Line.hpp>
#include <Stuff\Normal.hpp>
#include <Stuff\Point3D.hpp>
namespace MechWarrior4
{
class Weapon;
};
namespace MW4AI
{
class FireData
{
public:
FireData(Adept::Entity& source,
const Stuff::Point3D& src,
const Stuff::Point3D& dest);
FireData(Adept::Entity& source,
MechWarrior4::Weapon& weapon,
const Stuff::Point3D& dest);
FireData(const FireData& copy_from);
Adept::Entity* Project();
inline Adept::Entity& GetSource() const;
inline const Stuff::Point3D& GetOrigin() const;
inline Stuff::Point3D GetDest();
inline const Stuff::Line3D& GetLine() const;
inline Stuff::Line3D& GetLine();
inline Adept::Entity__CollisionQuery& GetQuery();
inline Adept::Entity* GetRaySource() const;
inline void SetLineLength(Stuff::Scalar length);
enum HIT_RESULT
{
HIT_TARGET,
HIT_SOMETHING_ELSE,
HIT_NOTHING
};
HIT_RESULT GetHitResult(Adept::Entity* desired_target = 0, bool ignore_dead_components = false) const;
bool HitsGround() const;
private:
void CreateLine(const Stuff::Point3D& src,
const Stuff::Point3D& dest);
private:
Adept::Entity__CollisionQuery m_Query;
Stuff::Line3D m_Line;
Stuff::Normal3D m_Normal;
Adept::Entity& m_Source;
};
inline const Stuff::Line3D& FireData::GetLine() const
{
return (m_Line);
}
inline Stuff::Line3D& FireData::GetLine()
{
return (m_Line);
}
inline Adept::Entity__CollisionQuery& FireData::GetQuery()
{
return (m_Query);
}
inline Adept::Entity* FireData::GetRaySource() const
{
return (m_Query.m_raySource);
}
inline Adept::Entity& FireData::GetSource() const
{
return (m_Source);
}
inline const Stuff::Point3D& FireData::GetOrigin() const
{
return (m_Line.m_origin);
}
inline Stuff::Point3D FireData::GetDest()
{
Stuff::Point3D rv;
m_Line.FindEnd(&rv);
return (rv);
}
inline void FireData::SetLineLength(Stuff::Scalar length)
{
Verify(length > 0);
m_Line.m_length = length;
}
};
#endif // AI_FIREDATA_HPP
@@ -0,0 +1,43 @@
#include "MW4Headers.hpp"
#include "AI_FireParamPackage.hpp"
using namespace MW4AI;
FireParamPackage::FireParamPackage(FireData& _fire_data,
MechWarrior4::MWObject* _intended_target,
Stuff::Time _min_delay,
Stuff::Time _max_delay,
Adept::Entity* _who_to_hit,
MechWarrior4::Vehicle* _vehicle_shooting_at,
Adept::Entity* _component,
Stuff::Time _frame_delay,
Stuff::Scalar _current_heat,
Stuff::Scalar _max_heat,
bool _can_spend_ammo,
bool _can_commit_suicide,
FireSource _where_to_fire_from,
bool _can_fire_narc,
bool _can_generate_heat,
bool _per_weapon_raycasting)
: fire_data(_fire_data)
, intended_target(_intended_target)
, min_delay(_min_delay)
, max_delay(_max_delay)
, who_to_hit(_who_to_hit)
, vehicle_shooting_at(_vehicle_shooting_at)
, component(_component)
, frame_delay(_frame_delay)
, current_heat(_current_heat)
, max_heat(_max_heat)
, can_spend_ammo(_can_spend_ammo)
, can_commit_suicide(_can_commit_suicide)
, where_to_fire_from(_where_to_fire_from)
, can_fire_narc(_can_fire_narc)
, can_generate_heat(_can_generate_heat)
, per_weapon_raycasting(_per_weapon_raycasting)
{
}
@@ -0,0 +1,74 @@
#pragma once
#ifndef AI_FIREPARAMPACKAGE_HPP
#define AI_FIREPARAMPACHAGE_HPP
#include <Stuff\Scalar.hpp>
namespace Adept
{
class Entity;
};
namespace MechWarrior4
{
class Weapon;
class Vehicle;
};
namespace MW4AI
{
class FireData;
enum FireSource
{
FIRE_FROM_ANYWHERE,
FIRE_FROM_LEFT_ARM,
FIRE_FROM_RIGHT_ARM
};
class FireParamPackage
{
public:
FireParamPackage(FireData& _fire_data,
MechWarrior4::MWObject* _intended_target,
Stuff::Time _min_delay,
Stuff::Time _max_delay,
Adept::Entity* _who_to_hit,
MechWarrior4::Vehicle* _vehicle_shooting_at,
Adept::Entity* _component,
Stuff::Time _frame_delay,
Stuff::Scalar _current_heat,
Stuff::Scalar _max_heat,
bool _can_spend_ammo,
bool _can_commit_suicide,
FireSource _where_to_fire_from,
bool _can_fire_narc,
bool _can_generate_heat,
bool _per_weapon_raycasting);
public:
FireData& fire_data;
MechWarrior4::MWObject* intended_target;
const Stuff::Time min_delay;
const Stuff::Time max_delay;
const Adept::Entity* who_to_hit;
const MechWarrior4::Vehicle* vehicle_shooting_at;
Adept::Entity* component;
const Stuff::Time frame_delay;
const Stuff::Scalar current_heat;
const Stuff::Scalar max_heat;
const bool can_spend_ammo;
const bool can_commit_suicide;
const FireSource where_to_fire_from;
const bool can_fire_narc;
const bool can_generate_heat;
const bool per_weapon_raycasting;
};
};
#endif // AI_FIREPARAMPACHAGE_HPP
+489
View File
@@ -0,0 +1,489 @@
#include "MW4Headers.hpp"
#include "AI_FireStyle.hpp"
#include "Weapon.hpp"
#include "AI_Weapons.hpp"
#include "aiutils.hpp"
#include "MWObject.hpp"
#include "AI_FireData.hpp"
#include "ProjectileWeapon.hpp"
#include "HighExplosiveWeapon.hpp"
#include "LongTomWeapon.hpp"
#include "ArtilleryWeapon.hpp"
#include "NetWeapon.hpp"
// MSL 5.03 RTX
//#include "rtxweaponsub.hpp"
#include <Adept\Map.hpp>
#include <Adept\Site.hpp>
#include "NarcWeaponSubsystem.hpp"
#include "SubsystemClassData.hpp"
#include "MWDamageObject.hpp"
#include "ai.hpp"
#pragma warning(push)
#include <stlport\algorithm>
#pragma warning(pop)
const double linked_fire_shot_delay = 0.3f;
const Stuff::Scalar min_high_explosive_distance = 80.0f;
extern __int64 tCombatAITime_WeaponFiring;
extern __int64 tWeaponFiring;
using namespace MW4AI;
bool FireStyles::FireStyle::gHeatManagementEnabled = false; // TODO: remove this eventually ...
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// General fire styles functions
//
Auto_Ptr<FireStyles::FireStyle> FireStyles::CreateFireStyle(FireStyleID id)
{
switch (id)
{
case FireStyles::FIRE_MAXIMUM: { return (new FireStyles::MaximumFire()); }
case FireStyles::FIRE_OPPORTUNITY: { return (new FireStyles::OpportunityFire()); }
}
Verify(!"Should never get here.");
return (new FireStyles::MaximumFire());
}
void FireStyles::VerifyFireStyle(FireStyleID id)
{
Verify(id >= FireStyles::FIRE_FIRST);
Verify(id <= FireStyles::FIRE_LAST);
}
std::string FireStyles::FireStyleToString(FireStyleID id)
{
VerifyFireStyle(id);
switch (id)
{
case FireStyles::FIRE_MAXIMUM: { return ("Maximum"); }
case FireStyles::FIRE_OPPORTUNITY: { return ("Opportunity"); }
default:
{
Verify("Should not get here" == 0);
}
}
return ("");
}
MechWarrior4::MWObject* SelfOrParentVehicle(Adept::Entity* entity)
{
if ((entity == 0) ||
(entity->IsDerivedFrom(MechWarrior4::MWObject::DefaultData) == false))
{
return (0);
}
MechWarrior4::MWObject* mwobject = Cast_Object(MechWarrior4::MWObject*,entity);
Check_Object(mwobject);
if (mwobject->GetParentVehicle() == 0)
{
return (mwobject);
}
return (mwobject->GetParentVehicle());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Functors: these plug in to TrueForAllWeapons(), TrueForAnyWeapon(), etc. to perform the appropriate task or query
//
#define FUNCTOR_HEADER(classname) \
public: \
classname(const FireParamPackage& params) \
: m_Params(params) \
{ \
} \
private: \
const FireParamPackage& m_Params;
#define REMOVE true
#define NO_REMOVE false
class Fire_Functor
{
public:
virtual bool Execute(MechWarrior4::Weapon& weapon, MechWarrior4::WeaponUpdate& weapon_update) = 0;
};
class Functor_CanFire
: public Fire_Functor
{
FUNCTOR_HEADER(Functor_CanFire);
public:
bool Execute(MechWarrior4::Weapon& weapon, MechWarrior4::WeaponUpdate& weapon_update)
{
Check_Object(&weapon);
if ((m_Params.can_spend_ammo == false) &&
(weapon.GetAmmoCount() != -1))
{
return (REMOVE);
}
if (WeaponCanFire(weapon,m_Params.fire_data.GetLine().m_length,m_Params.min_delay,m_Params.max_delay) == false)
{
return (REMOVE);
}
return (NO_REMOVE);
}
};
class Functor_CorrectFireSource
: public Fire_Functor
{
FUNCTOR_HEADER(Functor_CorrectFireSource);
public:
bool Execute(MechWarrior4::Weapon& weapon, MechWarrior4::WeaponUpdate& weapon_update)
{
Check_Object(&weapon);
switch (m_Params.where_to_fire_from)
{
case FIRE_FROM_LEFT_ARM:
{
if (WeaponIsArmWeapon(weapon,true) == false)
{
return (REMOVE);
}
break;
}
case FIRE_FROM_RIGHT_ARM:
{
if (WeaponIsArmWeapon(weapon,false) == false)
{
return (REMOVE);
}
break;
}
}
return (NO_REMOVE);
}
};
class Functor_DoesDamage
: public Fire_Functor
{
FUNCTOR_HEADER(Functor_DoesDamage);
public:
bool Execute(MechWarrior4::Weapon& weapon, MechWarrior4::WeaponUpdate& weapon_update)
{
Check_Object(&weapon);
if (weapon.IsDerivedFrom(MechWarrior4::ProjectileWeapon::DefaultData) == true)
{
MechWarrior4::ProjectileWeapon* projectile_weapon = Cast_Object(MechWarrior4::ProjectileWeapon*,&weapon);
const ProjectileWeapon__GameModel* game_model = projectile_weapon->GetGameModel();
if (game_model->damageAmount <= 0)
{
return (REMOVE);
}
if (weapon.IsDerivedFrom(MechWarrior4::HighExplosiveWeapon::DefaultData) == true)
{
if (m_Params.can_commit_suicide == false)
{
return (REMOVE);
}
if (m_Params.fire_data.GetLine().m_length > min_high_explosive_distance)
{
return (REMOVE);
}
return (NO_REMOVE);
}
if (weapon.IsDerivedFrom(MechWarrior4::ArtilleryWeapon::DefaultData) == true)
{
return (REMOVE);
}
if ((m_Params.can_fire_narc == false) &&
(weapon.IsDerivedFrom(MechWarrior4::NarcWeapon::DefaultData) == true))
{
return (REMOVE);
}
}
return (NO_REMOVE);
}
};
class Functor_Fire
: public Fire_Functor
{
FUNCTOR_HEADER(Functor_Fire);
public:
bool Execute(MechWarrior4::Weapon& weapon, MechWarrior4::WeaponUpdate& weapon_update)
{
Check_Object(&weapon);
Verify(WeaponCanFire(weapon,0,m_Params.min_delay,m_Params.max_delay) == true);
std::pair<FireData,Stuff::Time> result = CalculateFireData(m_Params,weapon);
if ((m_Params.per_weapon_raycasting == true) &&
(weapon.IsDerivedFrom(MechWarrior4::MissileWeapon::DefaultData) == false))
{
FireData ray_cast_data(m_Params.fire_data.GetSource(),
weapon,
result.first.GetDest());
ray_cast_data.Project();
Adept::Entity* non_const_who_to_hit = const_cast<Adept::Entity*>(m_Params.who_to_hit);
switch (ray_cast_data.GetHitResult(non_const_who_to_hit))
{
case FireData::HIT_NOTHING:
case FireData::HIT_SOMETHING_ELSE:
{
return (REMOVE);
}
}
}
{
COMBAT_LOGIC("Update Attacking::Firing::With Current Query::Weapon");
TIME_FUNCTION(tWeaponFiring);
TIME_FUNCTION(tCombatAITime_WeaponFiring);
result.first.GetQuery().m_raySource = m_Params.component;
weapon.FireWeapon(&(result.first.GetQuery()),result.second, Stuff::Point3D::Identity);
}
// begin: fill in all the weapon_update members
weapon_update.targetOffset = Point3D::Identity;
if ((weapon_update.target.GetCurrent() != 0) &&
(weapon_update.target.GetCurrent() != Adept::Map::GetInstance()))
{
weapon_update.targetOffset.MultiplyByInverse(m_Params.fire_data.GetDest(),weapon_update.target.GetCurrent()->GetLocalToWorld());
}
else
{
weapon_update.targetOffset = m_Params.fire_data.GetDest();
}
weapon_update.lockTime = (Stuff::Scalar)result.second;
weapon_update.weaponFired |= (0x1 << weapon.GetWeaponID());
if (weapon.IsDerivedFrom(MechWarrior4::MissileWeapon::DefaultData) == true)
{
MechWarrior4::MissileWeapon* missile_weapon = Cast_Object(MechWarrior4::MissileWeapon*,&weapon);
weapon_update.AntiWeaponCount[weapon.GetWeaponID()] = missile_weapon->GetAMSNumber();
}
// end
return (NO_REMOVE);
}
};
class Functor_HeatLevelOK
: public Fire_Functor
{
public:
Functor_HeatLevelOK(const FireParamPackage& params)
: m_Params(params)
, m_HeatGeneratedSoFar(0)
{
}
private:
const FireParamPackage& m_Params;
Stuff::Scalar m_HeatGeneratedSoFar;
public:
bool Execute(MechWarrior4::Weapon& weapon, MechWarrior4::WeaponUpdate& weapon_update)
{
Check_Object(&weapon);
Stuff::Scalar heat = weapon.GetTotalHeatGenerated();
if ((m_Params.can_generate_heat == false) &&
(heat > 0))
{
return (REMOVE);
}
if (FireStyles::FireStyle::gHeatManagementEnabled == false)
{
return (NO_REMOVE);
}
if (weapon.IsDerivedFrom(MechWarrior4::HighExplosiveWeapon::DefaultData) == true)
{
return (NO_REMOVE);
}
if (m_Params.current_heat + m_HeatGeneratedSoFar + heat >= (m_Params.max_heat * 0.9f))
{
return (REMOVE);
}
m_HeatGeneratedSoFar += heat;
return (NO_REMOVE);
}
};
class Functor_HitsEntity
: public Fire_Functor
{
public:
Functor_HitsEntity(const FireParamPackage& params, Adept::Entity* entity)
: m_Params(params)
, m_Entity(entity)
{
}
private:
const FireParamPackage& m_Params;
Adept::Entity* m_Entity;
public:
bool Execute(MechWarrior4::Weapon& weapon, MechWarrior4::WeaponUpdate& weapon_update)
{
Verify(WeaponCanFire(weapon,0,m_Params.min_delay,m_Params.max_delay) == true);
if (weapon.IsDerivedFrom(MechWarrior4::HighExplosiveWeapon::DefaultData) == true)
{
return (NO_REMOVE);
}
if ((weapon.GetGameModel() != 0) &&
(weapon.GetGameModel()->splashRadius > m_Params.fire_data.GetLine().m_length))
{
return (REMOVE);
}
return (NO_REMOVE);
}
};
class Functor_WontFriendlyFire
: public Fire_Functor
{
public:
Functor_WontFriendlyFire(const FireParamPackage& params)
: m_Params(params)
{
}
private:
const FireParamPackage& m_Params;
public:
bool Execute(MechWarrior4::Weapon& weapon, MechWarrior4::WeaponUpdate& weapon_update)
{
if (m_Params.fire_data.GetSource().IsDerivedFrom(MWObject::DefaultData) == true)
{
MWObject* mwobject = Cast_Object(MWObject*,&m_Params.fire_data.GetSource());
if (MightHitFriendlies(m_Params.fire_data.GetLine(),GetMaxWeaponDistance(weapon),*mwobject,m_Params.intended_target) == true)
{
return (REMOVE);
}
}
return (NO_REMOVE);
}
};
#undef FUNCTOR_EXECUTE_FUNCTION
typedef std::vector<MechWarrior4::Weapon*> weapon_list;
typedef std::vector<Fire_Functor*> functor_list;
void GetQualifiedWeapons(Stuff::ChainOf<MechWarrior4::Weapon*>& weapons,
functor_list& qualifiers,
weapon_list& weapons_out,
MechWarrior4::WeaponUpdate& weapon_update)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&weapons);
MechWarrior4::Weapon* weapon = 0;
while ((weapon = i.ReadAndNext()) != 0)
{
Check_Object(weapon);
if (weapon->IsDestroyed() == false)
{
bool qualified = true;
{for (functor_list::iterator i = qualifiers.begin();
i != qualifiers.end();
++i)
{
if ((*i)->Execute(*weapon,weapon_update) == REMOVE)
{
qualified = false;
break;
}
}}
if (qualified == true)
{
weapons_out.push_back(weapon);
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Maximum fire : fire as much as you can, as often as you can
//
void FireStyles::MaximumFire::Execute(const FireParamPackage& params,
Stuff::ChainOf<MechWarrior4::Weapon *>& weapons,
Adept::Entity* target,
MechWarrior4::WeaponUpdate& weapon_update)
{
Functor_CanFire can_fire(params); // which weapons can hit the target point?
Functor_CorrectFireSource correct_fire_source(params); // which weapons fire from the correct source (left arm only/right arm only/any & all)?
Functor_DoesDamage does_damage(params); // which weapons actually do some kind of damage?
Functor_HeatLevelOK heat_level_ok(params); // which weapons can fire without overheating?
Functor_HitsEntity hits_entity(params,target); // which weapons hit the intended entity?
Functor_WontFriendlyFire no_friendly_fire(params); // which weapons have no chance of causing friendly fire
Functor_Fire fire(params); // OK, fire!
functor_list qualifiers;
qualifiers.push_back(&can_fire);
qualifiers.push_back(&correct_fire_source);
qualifiers.push_back(&does_damage);
qualifiers.push_back(&heat_level_ok);
qualifiers.push_back(&hits_entity);
qualifiers.push_back(&no_friendly_fire);
qualifiers.push_back(&fire);
weapon_list w;
GetQualifiedWeapons(weapons,qualifiers,w,weapon_update);
}
@@ -0,0 +1,87 @@
#pragma once
#ifndef AI_FIRESTYLE_HPP
#define AI_FIRESTYLE_HPP
#include <Stuff\auto_ptr.hpp>
#pragma warning(push)
#include <stlport\string>
#pragma warning(pop)
#include "AI_FireParamPackage.hpp"
#define INTERFACE_FireStyle(post) \
public: \
virtual void Execute(const FireParamPackage& params, \
Stuff::ChainOf<MechWarrior4::Weapon *>& weapons, \
Adept::Entity* target, \
MechWarrior4::WeaponUpdate& weapon_update) ##post
#define PURE_FireStyle INTERFACE_FireStyle(=0;)
#define DERIVED_FireStyle INTERFACE_FireStyle(;)
namespace MechWarrior4 { class Weapon; class Vehicle; class WeaponUpdate; }
namespace Adept { class Entity__CollisionQuery; }
namespace MW4AI
{
class FireParamPackage;
namespace FireStyles
{
enum FireStyleID
{
FIRE_OPPORTUNITY, // change FIRE_FIRST if you change this,
FIRE_MAXIMUM // change FIRE_LAST if you change this
};
enum
{
FIRE_FIRST = FIRE_OPPORTUNITY,
FIRE_LAST = FIRE_MAXIMUM
};
void VerifyFireStyle(FireStyleID id);
std::string FireStyleToString(FireStyleID id);
class FireStyle
{
PURE_FireStyle;
public:
virtual bool CanAlwaysFireAtSecondaryTargets() const { return (false); }
virtual bool ShouldFireAtPrimaryTarget() const { return (true); }
virtual FireStyleID GetID() const = 0;
virtual ~FireStyle() {};
static bool gHeatManagementEnabled;
};
Auto_Ptr<FireStyle> CreateFireStyle(FireStyleID id);
class MaximumFire
: public FireStyle
{
DERIVED_FireStyle;
public:
FireStyleID GetID() const { return (FIRE_MAXIMUM); }
};
class OpportunityFire
: public MaximumFire
{
public:
bool CanAlwaysFireAtSecondaryTargets() const { return (true); }
bool ShouldFireAtPrimaryTarget() const { return (false); }
FireStyleID GetID() const { return (FIRE_OPPORTUNITY); }
};
};
};
#endif // AI_FIRESTYLE_HPP
@@ -0,0 +1,291 @@
#include "MW4Headers.hpp"
#include "AI_FocusFireSquad.hpp"
#include "AI_Groups.hpp"
#include "AI_UserConstants.hpp"
#include "ai_squadorders.hpp"
#include "CombatAI.hpp"
#include <Adept\NameTable.hpp>
#include "Sensor.hpp"
#pragma warning(disable : 4284)
#pragma warning (push)
#include <stlport\set>
#pragma warning (pop)
using namespace MW4AI;
using namespace MW4AI::Squad;
using namespace MechWarrior4;
const Stuff::Scalar min_target_update_time = 2.0f;
//________________________________________________________________________________________________________________
namespace MW4AI
{
namespace Squad
{
class FocusFireSquad;
};
};
class FocusFireSquadOrders
: public SquadOrders
{
public:
FocusFireSquadOrders(FocusFireSquad& squad, MechWarrior4::Group& group, int alignment);
virtual void Update();
virtual bool PointIsValid(const Stuff::Point3D& point) const;
virtual void IssueCommand(Stuff::Auto_Ptr<LancemateCommands::LancemateCommand>& command);
virtual void NotifyShotFired();
virtual MWObject* GetAutoTarget() const;
virtual bool GetExtendedSensorData(std::vector<MWObject*>& sensor_data_list) const;
virtual Stuff::Scalar GetLeastSquaredSensorDistance(const Stuff::Point3D& point) const;
private:
FocusFireSquad& m_Squad;
MechWarrior4::Group& m_Group;
int m_Alignment;
};
FocusFireSquadOrders::FocusFireSquadOrders(FocusFireSquad& squad, MechWarrior4::Group& group, int alignment)
: m_Squad(squad)
, m_Group(group)
, m_Alignment(alignment)
{
}
void FocusFireSquadOrders::Update()
{
}
bool FocusFireSquadOrders::PointIsValid(const Stuff::Point3D& point) const
{
return (true);
}
void FocusFireSquadOrders::IssueCommand(Stuff::Auto_Ptr<LancemateCommands::LancemateCommand>& command)
{
}
void FocusFireSquadOrders::NotifyShotFired()
{
}
MWObject* FocusFireSquadOrders::GetAutoTarget() const
{
return (m_Squad.GetAutoTarget());
}
bool FocusFireSquadOrders::GetExtendedSensorData(std::vector<MWObject*>& sensor_data_list) const
{
std::vector<MWObject*> members;
m_Group.GetMembers(members);
{for (std::vector<MWObject*>::const_iterator i_members = members.begin();
i_members != members.end();
++i_members)
{
if ((*i_members)->GetSensor() != 0)
{
{for (int i_sensor = 0;
i_sensor < (*i_members)->GetSensor()->RefreshAndGetSensorData().GetLength();
++i_sensor)
{
MechWarrior4::SensorData* d = (*i_members)->GetSensor()->RefreshAndGetSensorData()[i_sensor];
if (d != 0)
{
Adept::Entity* current = d->object.GetCurrent();
if ((current != 0) &&
(current->IsDestroyed() == false) &&
(current->IsDerivedFrom(MWObject::DefaultData) == true))
{
MWObject* target = Cast_Object(MWObject*,current);
if ((target->GetAlignment() != m_Alignment) &&
(std::find(members.begin(),members.end(),target) == members.end()) &&
(std::find(sensor_data_list.begin(),sensor_data_list.end(),target) == sensor_data_list.end()))
{
sensor_data_list.push_back(target);
}
}
}
}}
}
}}
return (true);
}
Stuff::Scalar FocusFireSquadOrders::GetLeastSquaredSensorDistance(const Stuff::Point3D& point) const
{
std::vector<MWObject*> members;
m_Group.GetMembers(members);
Stuff::Scalar least_distance = 0;
{for (std::vector<MWObject*>::const_iterator i_members = members.begin();
i_members != members.end();
++i_members)
{
Stuff::Scalar distance(GetLengthSquared((Stuff::Point3D)((*i_members)->GetLocalToWorld()),point));
if ((least_distance == 0) ||
(distance < least_distance))
{
least_distance = distance;
}
}}
return (least_distance);
}
//________________________________________________________________________________________________________________
FocusFireSquad::FocusFireSquad()
: m_AutoTarget(-2)
, m_LastTargetUpdateTime(0)
{
}
ID FocusFireSquad::GetID() const
{
return (GROUPAI_FOCUSFIRESQUAD);
}
template <class X>
X GetMostFrequentElement(const std::multiset<X>& m)
{
std::set<X> s(m.begin(),m.end());
std::multiset<X>::size_type best_count = 0;
X best_element = 0;
{for (std::set<X>::const_iterator i = s.begin();
i != s.end();
++i)
{
std::multiset<X>::size_type count = m.count(*i);
if (count > best_count)
{
best_element = *i;
best_count = count;
}
}}
return (best_element);
}
void FocusFireSquad::Update(MechWarrior4::Group& group, MechWarrior4::CombatAI& combat_ai)
{
inherited::Update(group,combat_ai);
if (m_LastTargetUpdateTime + min_target_update_time > (Stuff::Scalar)gos_GetElapsedTime())
{
return;
}
m_LastTargetUpdateTime = (Stuff::Scalar)gos_GetElapsedTime();
m_AutoTarget = -2;
std::multiset<Adept::ObjectID> potential_targets;
std::vector<MWObject*> members;
group.GetMembers(members);
{for (std::vector<MWObject*>::iterator i = members.begin();
i != members.end();
++i)
{
if (((*i)->GetAI() != 0) &&
((*i)->GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true))
{
CombatAI* combat_ai = Cast_Object(CombatAI*,(*i)->GetAI());
MWObject* target = combat_ai->FindBestAutoTarget();
if (target != 0)
{
potential_targets.insert(target->objectID);
}
}
}}
if (potential_targets.size() == 0)
{
return;
}
m_AutoTarget = GetMostFrequentElement<Adept::ObjectID>(potential_targets);
}
void FocusFireSquad::NotifyShot(MechWarrior4::Group& group, Adept::ObjectID id)
{
inherited::NotifyShot(group,id);
}
void FocusFireSquad::NotifyShotFired(MechWarrior4::Group& group, const Stuff::Line3D& line, MechWarrior4::MWObject& at_who, MechWarrior4::MWObject& shooter)
{
inherited::NotifyShotFired(group,line,at_who,shooter);
}
void FocusFireSquad::NotifyMemberAdded(MechWarrior4::Group& group, MechWarrior4::MWObject& who)
{
inherited::NotifyMemberAdded(group,who);
if ((who.GetAI() != 0) &&
(who.GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true))
{
CombatAI* combat_ai = Cast_Object(CombatAI*,who.GetAI());
#pragma warning(disable:4239)
FocusFireSquadOrders* new_squad_orders = new FocusFireSquadOrders(*this,group,who.GetAlignment());
combat_ai->SetSquadOrders(Stuff::Auto_Ptr<SquadOrders>(new_squad_orders));
#pragma warning(default:4239)
}
}
void FocusFireSquad::NotifyMemberRemoved(MechWarrior4::Group& group, MechWarrior4::MWObject& who)
{
inherited::NotifyMemberRemoved(group,who);
if ((who.GetAI() != 0) &&
(who.GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true))
{
CombatAI* combat_ai = Cast_Object(CombatAI*,who.GetAI());
#pragma warning(disable:4239)
combat_ai->SetSquadOrders(Stuff::Auto_Ptr<SquadOrders>(0));
#pragma warning(default:4239)
}
}
void FocusFireSquad::SetEntityToIgnore(Adept::ObjectID objectid)
{
}
MWObject* FocusFireSquad::GetAutoTarget()
{
if (m_AutoTarget < 0)
{
return (0);
}
Entity* entity = Adept::NameTable::GetInstance()->FindData(m_AutoTarget);
if ((entity == 0) ||
(entity->IsDestroyed() == true) ||
(entity->IsDerivedFrom(MWObject::DefaultData) == false))
{
m_AutoTarget = -2;
return (0);
}
return (Cast_Object(MWObject*,entity));
}
@@ -0,0 +1,37 @@
#pragma once
#ifndef AI_FOCUSFIRESQUAD_HPP
#define AI_FOCUSFIRESQUAD_HPP
#include "AI_RadioSquad.hpp"
#include <Stuff\Scalar.hpp>
namespace MW4AI
{
namespace Squad
{
class FocusFireSquad
: public RadioSquad
{
DERIVED_SquadAI;
typedef RadioSquad inherited;
public:
FocusFireSquad();
ID GetID() const;
MWObject* GetAutoTarget();
private:
Adept::ObjectID m_AutoTarget;
Stuff::Scalar m_LastTargetUpdateTime;
};
};
};
#endif // AI_FOCUSFIRESQUAD_HPP
+82
View File
@@ -0,0 +1,82 @@
#pragma once
#ifndef AI_FUZZY_HPP
#define AI_FUZZY_HPP
#include "AI_Log.hpp"
namespace MW4AI
{
typedef Stuff::Scalar Fuzzy;
inline Fuzzy And(Fuzzy one, Fuzzy two)
{
if (one < two)
{
return (one);
}
return (two);
}
inline Fuzzy And(Fuzzy one, Fuzzy two, Fuzzy three)
{
if (one < two)
{
return (And(one,three));
}
return (And(two,three));
}
inline Fuzzy And(Fuzzy one, Fuzzy two, Fuzzy three, Fuzzy four)
{
if (one < two)
{
return (And(one,three,four));
}
return (And(two,three,four));
}
inline Fuzzy Or(Fuzzy one, Fuzzy two)
{
if (one > two)
{
return (one);
}
return (two);
}
inline Fuzzy Or(Fuzzy one, Fuzzy two, Fuzzy three)
{
if (one > two)
{
return (Or(one,three));
}
return (Or(two,three));
}
inline Fuzzy Or(Fuzzy one, Fuzzy two, Fuzzy three, Fuzzy four)
{
if (one > two)
{
return (Or(one,three,four));
}
return (Or(two,three,four));
}
inline Fuzzy Not(Fuzzy arg)
{
Verify(arg >= 0);
Verify(arg <= 1);
return (1 - arg);
}
};
#endif // AI_FUZZY_HPP
@@ -0,0 +1,51 @@
#include "MW4Headers.hpp"
#include "AI_Graveyard.hpp"
using namespace MW4AI;
Graveyard::Graveyard()
{
}
Graveyard::~Graveyard()
{
}
void Graveyard::NotifyCreated(Adept::ObjectID id)
{
{for (grave_list::iterator i = m_Graves.begin();
i != m_Graves.end();
++i)
{
if ((*i).id == id)
{
m_Graves.erase(i);
return;
}
}}
}
void Graveyard::NotifyDeceased(Adept::ObjectID id, Adept::ObjectID destroyer, Stuff::Scalar time_of_death)
{
#ifdef LAB_ONLY
{for (grave_list::iterator i = m_Graves.begin();
i != m_Graves.end();
++i)
{
Verify((*i).id != id);
}}
#endif
Grave grave(id,destroyer,time_of_death);
m_Graves.push_back(grave);
}
const grave_list& Graveyard::GetGraves() const
{
return (m_Graves);
}
@@ -0,0 +1,60 @@
#ifndef AI_GRAVEYARD_HPP
#define AI_GRAVEYARD_HPP
#include <Adept\Entity.hpp>
#pragma warning(push)
#include <stlport\vector>
#pragma warning(pop)
namespace MW4AI
{
class Graveyard;
class Grave
{
public:
Grave(Adept::ObjectID _id,
Adept::ObjectID _destroyer,
Stuff::Scalar _time_of_death)
: id(_id)
, destroyer(_destroyer)
, time_of_death(_time_of_death)
{
}
friend class Graveyard;
Adept::ObjectID id;
Adept::ObjectID destroyer;
Stuff::Scalar time_of_death;
};
typedef std::vector<Grave> grave_list;
class Graveyard
{
public:
Graveyard();
~Graveyard();
void NotifyCreated(Adept::ObjectID id);
void NotifyDeceased(Adept::ObjectID id,
Adept::ObjectID destroyer,
Stuff::Scalar time_of_death);
const grave_list& GetGraves() const;
private:
grave_list m_Graves;
private: // prevent copying
Graveyard(const Graveyard&);
Graveyard& operator=(const Graveyard&);
};
};
#endif // MWOBITUARY
+361
View File
@@ -0,0 +1,361 @@
#include "MW4Headers.hpp"
#include "AI_Groups.hpp"
#include <Adept\NameTable.hpp>
#include <Adept\Application.hpp>
#include "MWPlayer.hpp"
#include "MWMission.hpp"
#include "GroupContainer.hpp"
#include "VehicleInterface.hpp"
#include <Adept\Map.hpp>
using namespace MW4AI;
inline MWObject* GetMWObject(Adept::ObjectID object_id)
{
gosREPORT((NameTable::GetInstance() != 0),"The NameTable object does not exist");
Adept::Entity* entity = NameTable::GetInstance()->FindData(object_id);
if ((entity == 0) ||
(entity->IsDerivedFrom(MechWarrior4::MWObject::DefaultData) == false))
{
return (0);
}
return (Cast_Object(MechWarrior4::MWObject*,entity));
}
inline MechWarrior4::MWMission& GetMission()
{
gosREPORT((Adept::Mission::GetInstance() != 0),"The mission object does not exist");
gosREPORT((Adept::Mission::GetInstance()->IsDerivedFrom(MechWarrior4::MWMission::DefaultData) == true),"The mission object is not the correct type");
MechWarrior4::MWMission* mission = Cast_Object(MechWarrior4::MWMission*,Adept::Mission::GetInstance());
Check_Object(mission);
return (*mission);
}
bool Groups::AllDead(Group::identifier group)
{
if (Size(group) == 0)
{
return (false);
}
return (Size(group) == NumDead(group));
}
void Groups::AddObject(Adept::ObjectID object, Group::identifier group)
{
MWObject* mwobject = GetMWObject(object);
if (mwobject != 0)
{
GetMission().GetGroupContainer().AddObjectToGroup(*mwobject,group);
}
}
void Groups::RemoveObject(Adept::ObjectID object, Group::identifier group)
{
MWObject* mwobject = GetMWObject(object);
if (mwobject != 0)
{
GetMission().GetGroupContainer().RemoveObjectFromGroup(*mwobject,group);
}
}
int Groups::NumDead(Group::identifier group)
{
gosREPORT((Adept::Application::GetInstance() != 0),"The application object does not exist");
gosREPORT((NameTable::GetInstance() != 0),"The NameTable object does not exist");
// gosREPORT((Adept::Application::GetInstance()->networkingFlag == false),"Cannot use group NumDead(), AllDead() functions in multiplayer");
if (GetMission().GetGroupContainer().GroupExists(group) == false)
{
return (0);
}
const Group& g = GetMission().GetGroupContainer().GetGroup(group);
int num_dead = 0;
{for (Group::element_list::const_iterator i = g.GetElements().begin();
i != g.GetElements().end();
++i)
{
Adept::Entity* entity = Adept::NameTable::GetInstance()->FindData(*i);
if ((entity == 0) ||
(entity->IsDestroyed() == true))
{
++num_dead;
}
}}
return (num_dead);
}
int Groups::Size(Group::identifier group)
{
if (GetMission().GetGroupContainer().GroupExists(group) == false)
{
return (0);
}
const Group& g = GetMission().GetGroupContainer().GetGroup(group);
return (g.GetElements().size());
}
bool Groups::ContainsObject(Adept::ObjectID object, Group::identifier group)
{
MWObject* mwobject = GetMWObject(object);
if (mwobject != 0)
{
return (std::find(mwobject->GetGroups().begin(),mwobject->GetGroups().end(),group) != mwobject->GetGroups().end());
}
return (false);
}
bool Groups::GetFirstGroup(Adept::ObjectID object, Group::identifier& group_id)
{
MWObject* v = GetMWObject(object);
if (v == 0)
{
return (false);
}
if (v->GetGroups().size() == 0)
{
return (false);
}
group_id = v->GetGroups()[0];
return (true);
}
bool Groups::GetFirstObject(Group::identifier group, Adept::ObjectID& object)
{
if (GetMission().GetGroupContainer().GroupExists(group) == false)
{
return (false);
}
const Group& g = GetMission().GetGroupContainer().GetGroup(group);
if (g.GetElements().size() == 0)
{
return (false);
}
{for (Group::element_list::const_iterator i = g.GetElements().begin();
i != g.GetElements().end();
++i)
{
MWObject* o = GetMWObject(*i);
if ((o != 0) &&
(o->IsDestroyed() == false))
{
object = *i;
return (true);
}
}}
return (false);
}
MechWarrior4::Group& Groups::GetGroup(MechWarrior4::Group::identifier group_id)
{
Verify(Adept::Mission::GetInstance() != 0);
Verify(Adept::Mission::GetInstance()->IsDerivedFrom(MechWarrior4::MWMission::DefaultData) == true);
MechWarrior4::MWMission* mission = Cast_Object(MechWarrior4::MWMission*,Adept::Mission::GetInstance());
Check_Object(mission);
Verify(mission->GetGroupContainer().GroupExists(group_id));
return (mission->GetGroupContainer().GetGroup(group_id));
}
bool IsLancemateGroup(Group::identifier group)
{
if (GetMission().GetGroupContainer().GroupExists(group) == false)
{
return (false);
}
const Group& g = GetMission().GetGroupContainer().GetGroup(group);
if (g.GetElements().size() == 0)
{
return (false);
}
if (g.HasAI() == false)
{
return (false);
}
const MW4AI::Squad::AI* group_ai = g.GetAI();
if (group_ai->GetID() != MW4AI::Squad::GROUPAI_LANCEMATE)
{
return (false);
}
Adept::Entity* entity = NameTable::GetInstance()->FindData(g.GetElements()[0]);
if ((entity != 0) &&
(entity->IsPlayerVehicle() == true))
{
return (true);
}
return (false);
}
bool Groups::GetLancemateGroup(const std::vector<Group::identifier>& groups, Group::identifier& group_id)
{
{for (std::vector<Group::identifier>::const_iterator i = groups.begin();
i != groups.end();
++i)
{
if ((Size(*i) > 0) &&
(IsLancemateGroup(*i) == true))
{
group_id = *i;
return (true);
}
}}
return (false);
}
bool Groups::GetMember(Group::identifier group, unsigned int index, Adept::ObjectID& object)
{
if (GetMission().GetGroupContainer().GroupExists(group) == false)
{
return (false);
}
const Group& g = GetMission().GetGroupContainer().GetGroup(group);
if (index >= g.GetElements().size())
{
return (false);
}
object = g.GetElements()[index];
return (true);
}
void Groups::GetLancemates(std::vector<MWObject*>& lancemates, bool include_player)
{
if (Adept::Player::GetInstance() == 0)
{
return;
}
MechWarrior4::MWPlayer* p = Cast_Object(MechWarrior4::MWPlayer*,Adept::Player::GetInstance());
if (p == 0)
{
return;
}
Check_Object(p);
if ((p->GetInterface() == 0) ||
(p->GetInterface()->vehicle == 0))
{
return;
}
if (include_player == true)
{
lancemates.push_back(p->GetInterface()->vehicle);
}
{for (std::vector<Group::identifier>::const_iterator i = p->GetInterface()->vehicle->GetGroups().begin();
i != p->GetInterface()->vehicle->GetGroups().end();
++i)
{
if ((Size(*i) > 0) &&
(IsLancemateGroup(*i) == true))
{
const Group& g = GetMission().GetGroupContainer().GetGroup(*i);
{for (int index = 1;
index < g.GetElements().size();
++index)
{
Adept::Entity* entity = Adept::NameTable::GetInstance()->FindData(g.GetElements()[index]);
if ((entity != 0) &&
(entity->IsDerivedFrom(MWObject::DefaultData) == true))
{
MWObject* mwobject = Cast_Object(MWObject*,entity);
lancemates.push_back(mwobject);
}
}}
return;
}
}}
}
void Groups::GetGroupmates(const Adept::ObjectID& of_who, std::vector<MWObject*>& groupmates)
{
Adept::Entity* entity = Adept::NameTable::GetInstance()->FindData(of_who);
if ((entity == 0) ||
(entity->IsDerivedFrom(MWObject::DefaultData) == false))
{
return;
}
const GroupContainer& gc = GetMission().GetGroupContainer();
MWObject* mwobject = Cast_Object(MWObject*,entity);
{for (MWObject::GroupList::const_iterator i = mwobject->GetGroups().begin();
i != mwobject->GetGroups().end();
++i)
{
std::vector<MWObject*> group_members;
gc.GetGroup(*i).GetMembers(group_members);
{for (std::vector<MWObject*>::const_iterator i_members = group_members.begin();
i_members != group_members.end();
++i_members)
{
if (((*i_members)->objectID != of_who) &&
(std::find(groupmates.begin(),groupmates.end(),*i_members) == groupmates.end()))
{
groupmates.push_back(*i_members);
}
}}
}}
}
void Groups::NotifyPlayerFocusedOnEntity(MechWarrior4::MWObject& player_vehicle, Adept::Entity& entity)
{
if ((entity.IsDestroyed() == true) ||
(player_vehicle.IsDestroyed() == true) ||
(entity.GetAlignment() == player_vehicle.GetAlignment()) ||
(&entity == Adept::Map::GetInstance()))
{
return;
}
GroupContainer& gc = GetMission().GetGroupContainer();
{for (MWObject::GroupList::const_iterator i = player_vehicle.GetGroups().begin();
i != player_vehicle.GetGroups().end();
++i)
{
MW4AI::Squad::AI* squad_ai = gc.GetGroup(*i).GetAI();
if (squad_ai != 0)
{
squad_ai->SetEntityToIgnore(entity.objectID);
}
}}
}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#ifndef AI_GROUPS_HPP
#define AI_GROUPS_HPP
#include "Group.hpp"
namespace MW4AI
{
namespace Groups
{
bool AllDead(Group::identifier group);
void AddObject(Adept::ObjectID object, Group::identifier group);
void RemoveObject(Adept::ObjectID object, Group::identifier group);
int NumDead(Group::identifier group);
int Size(Group::identifier group);
bool ContainsObject(Adept::ObjectID object, Group::identifier group);
bool GetFirstGroup(Adept::ObjectID object, Group::identifier& group_id);
bool GetFirstObject(Group::identifier group, Adept::ObjectID& object);
MechWarrior4::Group& GetGroup(MechWarrior4::Group::identifier group_id);
bool GetMember(Group::identifier group, unsigned int index, Adept::ObjectID& object);
bool GetLancemateGroup(const std::vector<Group::identifier>& groups, Group::identifier& group_id);
void GetLancemates(std::vector<MWObject*>& lancemates, bool include_player = false);
void GetGroupmates(const Adept::ObjectID& of_who, std::vector<MWObject*>& groupmates);
void NotifyPlayerFocusedOnEntity(MechWarrior4::MWObject& player_vehicle, Adept::Entity& entity);
};
};
#endif // AI_GROUPS_HPP
@@ -0,0 +1,97 @@
#include "MW4Headers.hpp"
#include "AI_HitTesting.hpp"
#include <Adept\Map.hpp>
#include <Adept\CollisionGrid.hpp>
#include "MWMover.hpp"
#include "aiutils.hpp"
#include "Weapon.hpp"
#include "ProjectileWeapon.hpp"
#include "Vehicle.hpp"
#include "MWDamageObject.hpp"
#include "AI_FireData.hpp"
#include "SubsystemClassData.hpp"
using namespace Stuff;
using namespace MW4AI;
using namespace MechWarrior4;
const Stuff::Scalar line_exaggeration = 20.0f;
std::pair<MW4AI::FireData,Stuff::Time> MW4AI::CalculateFireData(const FireParamPackage& fire_params,
MechWarrior4::Weapon& weapon)
{
Verify(&fire_params != 0);
Check_Object(&weapon);
Stuff::Time missile_lock_time(0);
Stuff::Vector3D velocity(0,0,0);
if (weapon.IsDerivedFrom(ProjectileWeapon::DefaultData) == true)
{
ProjectileWeapon* projectile_weapon = Cast_Object(ProjectileWeapon*,&weapon);
Check_Object(projectile_weapon);
const ProjectileWeapon__GameModel* game_model = projectile_weapon->GetGameModel();
if (game_model != 0)
{
if (fire_params.who_to_hit != 0)
{
missile_lock_time = game_model->targetLockTime * 2;
}
velocity = game_model->initialLinearVelocity;
}
}
if (fire_params.vehicle_shooting_at == 0)
{
FireData new_fire_data(fire_params.fire_data);
std::pair<FireData,Stuff::Time> rv(new_fire_data,missile_lock_time);
rv.first.GetQuery().m_raySource = const_cast<Adept::Entity*>(fire_params.who_to_hit);
return (rv);
}
Check_Object(fire_params.vehicle_shooting_at);
Vehicle* v = (Vehicle*)fire_params.vehicle_shooting_at; // must cast away constness since GetLocalToWorld() is not const
Stuff::Point3D current_position(v->GetLocalToWorld());
Stuff::Point3D new_position;
Stuff::Time time;
if (Small_Enough(velocity))
{
time = fire_params.frame_delay;
}
else
{
v->EstimateFuturePosition(&new_position,(Scalar)fire_params.frame_delay,false);
time = fire_params.frame_delay +
(GetApproximateLength(new_position,current_position) / velocity.GetApproximateLength());
}
v->EstimateFuturePosition(&new_position,(Scalar)time);
Stuff::Point3D delta;
delta.Subtract(new_position,current_position);
Stuff::Point3D target_point(fire_params.fire_data.GetDest());
target_point += delta;
FireData new_fire_data(fire_params.fire_data.GetSource(),
fire_params.fire_data.GetOrigin(),
target_point);
new_fire_data.SetLineLength(new_fire_data.GetLine().m_length + line_exaggeration);
std::pair<FireData,Stuff::Time> rv(new_fire_data,missile_lock_time);
rv.first.GetQuery().m_raySource = const_cast<Adept::Entity*>(fire_params.who_to_hit);
return (rv);
}
@@ -0,0 +1,26 @@
#pragma once
#ifndef AI_HITTESTING_HPP
#define AI_HITTESTING_HPP
#include "AI_FireParamPackage.hpp"
#pragma warning(push)
#include <stlport\map>
#pragma warning(pop)
namespace MechWarrior4
{
class Weapon;
};
namespace MW4AI
{
std::pair<FireData,Stuff::Time> CalculateFireData(const FireParamPackage& fire_params,
MechWarrior4::Weapon& weapon);
};
#endif // AI_HITTESTING_HPP
+907
View File
@@ -0,0 +1,907 @@
#include "MW4Headers.hpp"
#include "AI_Lancemate.hpp"
#include "Group.hpp"
#include "CombatAI.hpp"
#include <Adept\NameTable.hpp>
#include "AIUtils.hpp"
#include "AI_CombatTacticInterface.hpp"
#include "AI_LancemateCommands.hpp"
#include "AI_FindObject.hpp"
#include "Mech.hpp"
#include "lancemate.hpp"
#include "AI_Groups.hpp"
#include "MWMission.hpp"
#include "MWApplication.hpp"
#pragma warning(push)
#include <stlport\algorithm>
#pragma warning(pop)
using namespace MW4AI;
using namespace MW4AI::Squad;
using namespace MechWarrior4;
using namespace MW4AI::LancemateAudio;
const Stuff::Scalar max_get_out_of_way_distance = 70.0f;
const Stuff::Scalar max_too_close_to_leaders_fire_distance = 40.0f;
const Stuff::Scalar max_dodge_leaders_fire_time = 8.0f;
const Stuff::Scalar max_unable_to_fire_give_up_time = 12.0f;
const Stuff::Scalar max_squared_disengage_distance = 900.0f * 900.0f;
const Stuff::Scalar target_to_avoid_refresh_time = 10.0f;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Group::element_list::size_type GetObjectIndex(MWObject& object,
const Group& group)
{
Group::element_list::const_iterator found = std::find(group.GetElements().begin(),group.GetElements().end(),object.objectID);
if (found == group.GetElements().end())
{
return (group.GetElements().size());
}
return (std::distance(group.GetElements().begin(),found));
}
inline Stuff::Scalar GetDistanceSquared(Adept::Entity& object1, Adept::Entity& object2)
{
return (GetLengthSquared((Stuff::Point3D)object1.GetLocalToWorld(),(Stuff::Point3D)object2.GetLocalToWorld()));
}
inline CombatAI* GetLeaderCombatAI(Adept::Entity* leader)
{
if (leader->IsDerivedFrom(MWObject::DefaultData) == false)
{
return (0);
}
MWObject* leader_mwobject = Cast_Object(MWObject*,leader);
Check_Object(leader_mwobject);
if ((leader_mwobject->GetAI() == 0) ||
(leader_mwobject->GetAI()->IsDerivedFrom(CombatAI::DefaultData) == false))
{
return (0);
}
CombatAI* combat_ai = Cast_Object(CombatAI*,leader_mwobject->GetAI());
Check_Object(combat_ai);
return (combat_ai);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
namespace MW4AI
{
class LancemateSquadOrders :
public SquadOrders
{
public:
LancemateSquadOrders(CombatAI& combat_ai,
Squad::Lancemate& lancemate_ai,
Group& group,
LancemateAudio::AudioManager& audio_manager);
~LancemateSquadOrders();
void Update();
bool PointIsValid(const Stuff::Point3D& point) const;
void IssueCommand(Stuff::Auto_Ptr<LancemateCommands::LancemateCommand>& command);
void NotifyShotFired();
void NotifyFriendlyFire(Adept::Entity& who);
bool CanExecuteCommands() const;
Stuff::Auto_Ptr<LancemateCommands::LancemateCommand> CreateCommand(LancemateCommands::ID command_id,Adept::Entity* pTarget2 = NULL);
bool ShouldRunScript() const;
bool GetLeaderAlignment(int& alignment);
void NotifyNoPath();
private:
int GetMyIndex() const;
MWObject* GetLeader() const;
bool UnitIsMovingToLeadersPath(MWObject& leader) const;
Stuff::Point3D GetPosition() const;
bool PointIsInLeadersPath(const Stuff::Point3D& point, MWObject& leader) const;
void UpdateLeaderAvoidance();
void UpdateShootNearbyEnemies();
void UpdateFriendlyFireFrustration();
MWObject* FindEntityToAttack(const Adept::ObjectID* except_who);
private:
CombatAI& m_CombatAI;
Squad::Lancemate& m_LancemateAI;
Group& m_Group;
LancemateAudio::AudioManager& m_AudioManager;
Stuff::Auto_Ptr<LancemateCommands::LancemateCommand> m_Command;
int m_FriendlyFireFrustration;
Stuff::Scalar m_LastTimeNoticedFriendlyFire;
Stuff::Scalar m_LastTimeFrustrationChanged;
bool m_TurnedAgainstPlayer;
};
};
Stuff::Auto_Ptr<LancemateCommands::LancemateCommand> LancemateSquadOrders::CreateCommand(LancemateCommands::ID command_id,Adept::Entity* pTarget2/* = NULL*/)
{
if ((m_Command.GetPointer() != 0) &&
(m_Command->CanInterrupt() == false))
{
if (!pTarget2)
m_AudioManager.PlayAudio(AUDIO_NO,m_CombatAI.GetTalkerSuffix());
return (0);
}
if (GetLeader() != 0)
{
return (LancemateCommands::CreateLancemateCommand(command_id,m_CombatAI,*GetLeader(),m_AudioManager,pTarget2));
}
return (0);
}
void LancemateSquadOrders::NotifyNoPath()
{
if (m_Command.GetPointer() != 0)
{
m_Command->NotifyNoPath();
}
}
LancemateSquadOrders::LancemateSquadOrders(CombatAI& combat_ai,
Squad::Lancemate& lancemate_ai,
Group& group,
LancemateAudio::AudioManager& audio_manager)
: m_CombatAI(combat_ai)
, m_LancemateAI(lancemate_ai)
, m_Group(group)
, m_AudioManager(audio_manager)
, m_FriendlyFireFrustration(0)
, m_LastTimeNoticedFriendlyFire((Stuff::Scalar)gos_GetElapsedTime())
, m_LastTimeFrustrationChanged((Stuff::Scalar)gos_GetElapsedTime())
, m_TurnedAgainstPlayer(false)
{
}
LancemateSquadOrders::~LancemateSquadOrders()
{
}
void LancemateSquadOrders::IssueCommand(Stuff::Auto_Ptr<LancemateCommands::LancemateCommand>& command)
{
if (m_TurnedAgainstPlayer == true)
{
return;
}
m_Command = command;
}
void LancemateSquadOrders::Update()
{
if ((m_TurnedAgainstPlayer == true) ||
(ShouldRunScript() == true))
{
return;
}
if (GetLeader() == &m_CombatAI.GetSelf())
{
return;
}
m_CombatAI.SetIgnoringFriendlyFire(true);
if (m_Command != 0)
{
if (m_Command->Finished() == true)
{
m_Command.Delete();
if (GetLeader() != 0)
{
#pragma warning(disable:4239)
IssueCommand(LancemateCommands::CreateLancemateCommand(LancemateCommands::LANCEMATE_DEFAULT,m_CombatAI,*(GetLeader()),m_AudioManager));
#pragma warning(default:4239)
}
}
else
{
m_Command->Update();
}
if (m_Command->CanDistract() == true)
{
if (m_CombatAI.GetAttackState() == CombatAI::ATTACKING)
{
if ((m_CombatAI.Target() == 0) ||
(m_CombatAI.GetUnableToFireDuration(max_unable_to_fire_give_up_time) == true) ||
(GetLengthSquared((Stuff::Point3D)m_CombatAI.GetSelf().GetLocalToWorld(),
(Stuff::Point3D)m_CombatAI.Target()->GetLocalToWorld()) > max_squared_disengage_distance))
{
m_CombatAI.Reset(false);
}
else
{
UpdateShootNearbyEnemies();
}
}
else
{
UpdateShootNearbyEnemies();
}
}
}
UpdateLeaderAvoidance();
UpdateFriendlyFireFrustration();
}
int LancemateSquadOrders::GetMyIndex() const
{
Verify(m_Group.GetElements().size() > 0);
return (index_of(m_Group.GetElements().begin(),m_Group.GetElements().end(),m_CombatAI.GetSelf().objectID));
}
MWObject* LancemateSquadOrders::GetLeader() const
{
if (m_Group.GetElements().size() == 0)
{
return (0);
}
Adept::Entity* entity = m_Group.IDToEntity(*(m_Group.GetElements().begin()));
if (entity == 0)
{
return (0);
}
Check_Object(entity);
if ((entity->IsDestroyed() == true) ||
(entity->IsDerivedFrom(MWObject::DefaultData) == false))
{
return (0);
}
return (Cast_Object(MWObject*,entity));
}
Stuff::Point3D LancemateSquadOrders::GetPosition() const
{
return (m_CombatAI.GetSelf().GetLocalToWorld());
}
bool LancemateSquadOrders::UnitIsMovingToLeadersPath(MWObject& leader) const
{
if (m_CombatAI.GetAttackState() != CombatAI::ATTACKING)
{
return (false);
}
CombatTacticInterface iface(m_CombatAI);
Stuff::Point3D dest(GetPosition());
iface.GetLastMoveDest(dest);
return (!PointIsValid(dest));
}
void LancemateSquadOrders::UpdateLeaderAvoidance()
{
if (m_Command.GetPointer() == 0)
{
return;
}
if (m_Command->CanDistract() == false)
{
return;
}
int index(GetMyIndex());
Verify(index < m_Group.GetElements().size()); // if this fails, the combat_ai does not belong to the group
if (index == 0)
{
return;
}
MWObject* leader = GetLeader();
if (leader == 0)
{
return; // the leader cannot be part of the formation; he dictates it
}
Check_Object(leader);
int attempt_index = 0;
CombatTacticInterface iface(m_CombatAI);
while (UnitIsMovingToLeadersPath(*leader) == true)
{
Stuff::Scalar distance = 0;
Stuff::Scalar radians = 0;
Stuff::Point3D my_pos(GetPosition());
Stuff::UnitVector3D forward_vector;
m_CombatAI.GetSelf().GetLocalToWorld().GetLocalForwardInWorld(&forward_vector);
Stuff::Point3D forward(forward_vector);
forward += my_pos;
switch (attempt_index % 4)
{
case 0: { radians = 0.0f;break; }
case 1: { radians = Stuff::Pi_Over_2; break; }
case 2: { radians = -Stuff::Pi_Over_2; break; }
case 3: { radians = Stuff::Pi; break; }
}
switch (attempt_index / 4)
{
case 0: { distance = 10.0f;break; }
case 1: { distance = 20.0f; break; }
case 2: { distance = 50.0f; break; }
case 3: { distance = 100.0f; break; }
}
Stuff::Point3D dest(RotateVector(forward,my_pos,radians,distance));
if (m_CombatAI.PointIsValid(dest) == true)
{
m_CombatAI.MoveToPoint(dest);
}
++attempt_index;
if (attempt_index >= 16)
{
return;
}
}
}
void LancemateSquadOrders::UpdateShootNearbyEnemies()
{
Verify(m_Group.GetElements().size() > 0);
Verify(m_Command.GetPointer() != 0);
if (m_CombatAI.Attacking() == true)
{
if (m_CombatAI.Target()->IsDerivedFrom(MWObject::DefaultData) == true)
{
MWObject* target = Cast_Object(MWObject*,m_CombatAI.Target());
if (target->GetTargetDesirability() > 0)
{
return;
}
if ((target->weaponChain.IsEmpty() == false) ||
(target->GetAI() != 0))
{
return;
}
}
}
if (UserConstants::Instance() == 0)
{
return;
}
Stuff::Scalar lancemate_min_radius = m_CombatAI.GetSquadTargetingRadius();
Verify(lancemate_min_radius > 0);
Adept::ObjectID id(m_LancemateAI.GetTargetToAvoid());
Adept::ObjectID* id_ptr = 0;
if (id >= 0)
{
id_ptr = &id;
}
MWObject* mwobject = m_Command->FindSomeoneToAttack(id_ptr,FindObject::FC_BEST_TARGET,lancemate_min_radius);
if ((mwobject != 0) &&
(mwobject != m_CombatAI.Target()))
{
Check_Object(mwobject);
m_CombatAI.Reset(m_Command->CanDeviateFromPath());
m_CombatAI.Target(mwobject);
m_CombatAI.OrderAttack(m_Command->CanDeviateFromPath());
}
}
bool LancemateSquadOrders::PointIsInLeadersPath(const Stuff::Point3D& point, MWObject& leader) const
{
const Stuff::LinearMatrix4D& leader_matrix = leader.GetLocalToWorld();
if (GetLengthSquared((Stuff::Point3D)leader_matrix,
point) < (max_get_out_of_way_distance * max_get_out_of_way_distance))
{
if ((GetSquaredDistToMatrixForward(point,leader_matrix) < GetSquaredDistToMatrixLeft(point,leader_matrix)) &&
(GetSquaredDistToMatrixForward(point,leader_matrix) < GetSquaredDistToMatrixRight(point,leader_matrix)))
{
return (true);
}
}
return (false);
}
bool LancemateSquadOrders::PointIsValid(const Stuff::Point3D& point) const
{
Verify(UserConstants::Instance() != 0);
int index(GetMyIndex());
Verify(index < m_Group.GetElements().size()); // if this fails, the combat_ai does not belong to the group
if (index == 0)
{
return (true);
}
MWObject* leader = GetLeader();
if (leader == 0)
{
return (true);
}
Check_Object(leader);
if ((m_Command.GetPointer() != 0) &&
(m_Command->OnLeash() == true) &&
(GetLengthSquared(point,m_Command->GetLeashPoint()) > m_Command->GetLeashRadius() * m_Command->GetLeashRadius()))
{
return (false);
}
if ((m_LancemateAI.GetLastLeaderFireTime() != 0) &&
(m_LancemateAI.GetLastLeaderFireTime() + max_dodge_leaders_fire_time > gos_GetElapsedTime()))
{
Verify(m_LancemateAI.GetLeaderFireLine() != 0);
if (LinePenetrates(*m_LancemateAI.GetLeaderFireLine(),point,max_too_close_to_leaders_fire_distance) == true)
{
return (false);
}
}
Vehicle* leader_vehicle = Cast_Object(Vehicle*,leader);
Check_Object(leader_vehicle);
if (leader_vehicle->speedDemandMPS < Stuff::SMALL)
{
return (true);
}
return (!PointIsInLeadersPath(point,*leader));
}
void LancemateSquadOrders::NotifyShotFired()
{
if ((m_CombatAI.GetSelf().GetSensor() == 0) ||
(m_TurnedAgainstPlayer == true))
{
return;
}
if ((m_Command.GetPointer() != 0) &&
(m_Command->CanDistract() == false))
{
return;
}
if ((m_CombatAI.Attacking() == false) ||
((m_LancemateAI.GetTargetToAvoid() > 0) && (m_CombatAI.Target()->objectID == m_LancemateAI.GetTargetToAvoid())))
{
Adept::ObjectID avoid_id = m_LancemateAI.GetTargetToAvoid();
Verify(m_Command.GetPointer() != 0);
MWObject* mwobject = 0;
if (avoid_id >= 0)
{
m_Command->FindSomeoneToAttack(&avoid_id);
}
else
{
m_Command->FindSomeoneToAttack(0);
}
if ((mwobject != 0) &&
(m_CombatAI.Target() != mwobject))
{
Check_Object(mwobject);
m_CombatAI.Reset(m_Command->CanDeviateFromPath());
m_CombatAI.Target(mwobject);
m_CombatAI.OrderAttack(m_Command->CanDeviateFromPath());
}
}
}
void LancemateSquadOrders::NotifyFriendlyFire(Adept::Entity& who)
{
if (m_TurnedAgainstPlayer == true)
{
MechWarrior4::MWMission *mission = Cast_Object (MechWarrior4::MWMission*,MechWarrior4::MWMission::GetInstance());
Check_Object (mission);
mission->EndMissionState (false);
return;
}
if ((m_CombatAI.GetSelf().IsPlayerVehicle() == true) ||
(who.IsPlayerVehicle() == false))
{
return;
}
// MSL 5.04 Friendly Fire Betty Changes
return;
// if ((m_LastTimeFrustrationChanged + 3.0f < gos_GetElapsedTime()) && (m_FriendlyFireFrustration < 4))
if (m_LastTimeFrustrationChanged + 3.0f < gos_GetElapsedTime())// && (m_FriendlyFireFrustration < 4))
{
++m_FriendlyFireFrustration;
m_LastTimeFrustrationChanged = (Stuff::Scalar)gos_GetElapsedTime();
// MSL 5.04 Friendly Fire Betty Changes
MWApplication* app = Cast_Object(MWApplication*,MWApplication::GetInstance());
switch (m_FriendlyFireFrustration)
{
case 1:
{
app->SendSound(who.GetReplicatorID(), VehicleInterface::FRIENDLYFIREPENALTY);
// m_AudioManager.PlayAudio(AUDIO_FF1,m_CombatAI.GetTalkerSuffix());
break;
}
case 2:
{
app->SendSound(who.GetReplicatorID(), VehicleInterface::FRIENDLYFIREPENALTY);
// m_AudioManager.PlayAudio(AUDIO_FF2,m_CombatAI.GetTalkerSuffix());
break;
}
case 3:
{
app->SendSound(who.GetReplicatorID(), VehicleInterface::FRIENDLYFIREPENALTY);
// m_AudioManager.PlayAudio(AUDIO_FF3,m_CombatAI.GetTalkerSuffix());
// m_AudioManager.SetPissedOff(true);
break;
}
// MSL 5.04 Friendly Fire Betty Changes
// case 4:
// {
// m_TurnedAgainstPlayer = true;
// m_AudioManager.PlayAudio(AUDIO_FF4,m_CombatAI.GetTalkerSuffix());
// m_CombatAI.Reset(true);
// m_CombatAI.Target(&who);
// m_CombatAI.OrderAttack(true);
// MSL 5.00
// MechWarrior4::MWMission *mission = Cast_Object (MechWarrior4::MWMission*,MechWarrior4::MWMission::GetInstance());
// Check_Object (mission);
// mission->SetEndMissionTime (30.0f);
// mission->EndMissionState (false);
// break;
// }
default:
{
app->SendSound(who.GetReplicatorID(), VehicleInterface::FRIENDLYFIREPENALTY);
break;
}
}
}
m_LastTimeNoticedFriendlyFire = (Stuff::Scalar)gos_GetElapsedTime();
}
void LancemateSquadOrders::UpdateFriendlyFireFrustration()
{
if (m_FriendlyFireFrustration > 0)
{
if (m_LastTimeNoticedFriendlyFire + 18.0f < gos_GetElapsedTime())
{
--m_FriendlyFireFrustration;
m_LastTimeNoticedFriendlyFire = (Stuff::Scalar)gos_GetElapsedTime();
}
}
}
bool LancemateSquadOrders::CanExecuteCommands() const
{
if (m_TurnedAgainstPlayer == true)
{
return (false);
}
return (true);
}
bool LancemateSquadOrders::ShouldRunScript() const
{
if ((GetLeader() != 0) &&
(GetLeader()->IsPlayerVehicle() == true))
{
return (false);
}
return (true);
}
bool LancemateSquadOrders::GetLeaderAlignment(int& alignment)
{
MWObject* leader = GetLeader();
if ((leader != 0) &&
(leader != &(m_CombatAI.GetSelf())))
{
alignment = leader->GetAlignment();
return (true);
}
return (false);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Lancemate::Lancemate()
: m_LastLeaderFireTime(0)
, m_LastPickTargetTime(0)
, m_TargetToAvoid(-2)
, m_TargetToAvoidTime(0)
{
}
Lancemate::~Lancemate()
{
{for (std::vector<CombatAI*>::iterator i = m_CombatAIsWithSquadOrders.begin();
i != m_CombatAIsWithSquadOrders.end();
++i)
{
if ((*i)->GetSquadOrders() != 0)
{
#pragma warning(disable:4239)
(*i)->SetSquadOrders(Stuff::Auto_Ptr<SquadOrders>(0));
#pragma warning(default:4239)
}
}}
}
ID Lancemate::GetID() const
{
return (GROUPAI_LANCEMATE);
}
void Lancemate::Update(Group& group, CombatAI& combat_ai)
{
if ((combat_ai.GetSquadOrders() != 0) &&
(combat_ai.GetSquadOrders()->ShouldRunScript() == true))
{
return;
}
inherited::Update(group,combat_ai);
if ((combat_ai.IsDestroyed() == true) &&
(combat_ai.GetSquadOrders() != 0))
{
NotifyMemberRemoved(group,combat_ai.GetSelf());
}
Adept::Entity* leader = GetLeader(group);
if ((leader != 0) &&
(leader->IsDerivedFrom(Mech::DefaultData) == true))
{
Mech* mech = Cast_Object(Mech*,leader);
m_AudioManager.Update(group,*mech);
}
}
void Lancemate::NotifyShot(Group& group, Adept::ObjectID id)
{
inherited::NotifyShot(group,id);
}
void Lancemate::NotifyShotFired(Group& group,
const Stuff::Line3D& line,
MWObject& at_who,
MWObject& shooter)
{
inherited::NotifyShotFired(group,line,at_who,shooter);
Verify(&at_who != &shooter);
Verify(std::find(shooter.GetGroups().begin(),shooter.GetGroups().end(),group.GetID()) != shooter.GetGroups().end());
if (GetObjectIndex(shooter,group) != 0)
{
return;
}
Verify(std::find(at_who.GetGroups().begin(),at_who.GetGroups().end(),group.GetID()) != at_who.GetGroups().end());
if ((m_LastLeaderFireTime < gos_GetElapsedTime()) &&
(LinePenetrates(line,(Stuff::Point3D)(at_who.GetLocalToWorld()),max_too_close_to_leaders_fire_distance) == true))
{
m_LastLeaderFireTime = gos_GetElapsedTime();
Stuff::Line3D* new_line = new Stuff::Line3D;
*new_line = line;
m_LeaderFireLine.Assimilate(new_line);
}
if (m_LastPickTargetTime < gos_GetElapsedTime())
{
m_LastPickTargetTime = gos_GetElapsedTime();
Propagate_NotifyShotFired(group);
}
}
void Lancemate::Propagate_NotifyShotFired(Group& group)
{
Verify(group.GetElements().size() > 0);
// CombatAI* leader_combatai = GetLeaderCombatAI(GetLeader(group));
// TODO: get leader's target -- this will be a challenge since the "leader" can be the player
typedef std::vector<MWObject*> member_list;
member_list members;
group.GetMembers(members);
{for (member_list::iterator i = members.begin();
i != members.end();
++i)
{
if (((*i)->GetAI() != 0) &&
((*i)->GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true))
{
CombatAI* combat_ai = Cast_Object(CombatAI*,(*i)->GetAI());
Check_Object(combat_ai);
if (combat_ai->GetSquadOrders() != 0)
{
combat_ai->GetSquadOrders()->NotifyShotFired();
}
}
}}
}
Stuff::Time Lancemate::GetLastLeaderFireTime() const
{
return (m_LastLeaderFireTime);
}
Stuff::Line3D* Lancemate::GetLeaderFireLine() const
{
return (m_LeaderFireLine.GetPointer());
}
void Lancemate::NotifyMemberAdded(Group& group, MWObject& who)
{
if ((who.GetAI() != 0) &&
(who.IsPlayerVehicle() == false) &&
(who.IsDestroyed() == false) &&
(who.GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true))
{
CombatAI* combat_ai = Cast_Object(CombatAI*,who.GetAI());
#pragma warning(disable:4239)
LancemateSquadOrders* new_squad_orders = new LancemateSquadOrders(*combat_ai,*this,group,m_AudioManager);
combat_ai->SetSquadOrders(Stuff::Auto_Ptr<SquadOrders>(new_squad_orders));
if (std::find(m_CombatAIsWithSquadOrders.begin(),m_CombatAIsWithSquadOrders.end(),combat_ai) == m_CombatAIsWithSquadOrders.end())
{
m_CombatAIsWithSquadOrders.push_back(combat_ai);
}
Adept::Entity* leader = GetLeader(group);
if ((leader != 0) &&
(leader->IsDerivedFrom(MWObject::DefaultData) == true))
{
new_squad_orders->IssueCommand(LancemateCommands::CreateLancemateCommand(LancemateCommands::LANCEMATE_DEFAULT,*combat_ai,*(Cast_Object(MWObject*,leader)),m_AudioManager));
}
#pragma warning(default:4239)
}
}
void Lancemate::NotifyMemberRemoved(Group& group, MWObject& who)
{
Verify(who.GetAI() != 0);
Verify(who.GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true);
if ((who.GetAI() != 0) &&
(who.GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true))
{
CombatAI* combat_ai = Cast_Object(CombatAI*,who.GetAI());
#pragma warning(disable:4239)
combat_ai->SetSquadOrders(Stuff::Auto_Ptr<SquadOrders>(0));
#pragma warning(default:4239)
std::vector<CombatAI*>::iterator found = std::find(m_CombatAIsWithSquadOrders.begin(),m_CombatAIsWithSquadOrders.end(),combat_ai);
if (found != m_CombatAIsWithSquadOrders.end())
{
m_CombatAIsWithSquadOrders.erase(found);
}
}
}
void Lancemate::SetEntityToIgnore(Adept::ObjectID objectid)
{
SetTargetToAvoid(objectid);
}
Adept::ObjectID Lancemate::GetTargetToAvoid() const
{
if (m_TargetToAvoidTime + target_to_avoid_refresh_time > gos_GetElapsedTime())
{
return (m_TargetToAvoid);
}
return (-2);
}
void Lancemate::SetTargetToAvoid(Adept::ObjectID id)
{
m_TargetToAvoid = id;
m_TargetToAvoidTime = gos_GetElapsedTime();
}
void Lancemate::NotifyMechDestroyed(MechWarrior4::Group& group,
const Adept::ReplicatorID& inflicting_id,
const Adept::ReplicatorID& victim_id)
{
Connection *connection = Network::GetInstance()->GetConnection(victim_id.connectionID);
if (connection == 0)
{
return;
}
Replicator* rep = connection->FindReplicator(victim_id);
if (rep == 0)
{
return;
}
Entity *ent = Cast_Object(Entity*,rep);
if (ent->IsDerivedFrom(Mech::DefaultData) == false)
{
return;
}
Mech* mech = Cast_Object(Mech*,ent);
if ((mech->GetAI() == 0) ||
(mech->IsPlayerVehicle() == true))
{
return;
}
std::vector<MWObject*> lancemates;
MW4AI::Groups::GetLancemates(lancemates,false);
if (std::find(lancemates.begin(),lancemates.end(),mech) != lancemates.end())
{
m_AudioManager.PlayAudio(LancemateAudio::AUDIO_EJECT,mech->GetAI()->GetTalkerSuffix());
}
}
@@ -0,0 +1,71 @@
#pragma once
#ifndef AI_LANCEMATE_HPP
#define AI_LANCEMATE_HPP
#include "AI_RadioSquad.hpp"
#include "AI_LancemateAudio.hpp"
#include <Stuff\Line.hpp>
#include <Stuff\Auto_Ptr.hpp>
namespace Adept
{
class Entity;
};
namespace MechWarrior4
{
class AI;
class CombatAI;
};
namespace MW4AI
{
namespace Squad
{
class Lancemate
: public RadioSquad
{
DERIVED_SquadAI;
public:
Lancemate();
virtual ~Lancemate();
typedef RadioSquad inherited;
ID GetID() const;
bool IgnoresFriendlyFire() const { return (true); }
Stuff::Time GetLastLeaderFireTime() const;
Stuff::Line3D* GetLeaderFireLine() const;
Adept::ObjectID GetTargetToAvoid() const;
void SetTargetToAvoid(Adept::ObjectID id);
virtual void NotifyMechDestroyed(MechWarrior4::Group& group,
const Adept::ReplicatorID& inflicting_id,
const Adept::ReplicatorID& victim_id);
private:
void Propagate_NotifyShotFired(MechWarrior4::Group& group);
private:
Stuff::Auto_Ptr<Stuff::Line3D> m_LeaderFireLine;
Stuff::Time m_LastLeaderFireTime;
Stuff::Time m_LastPickTargetTime;
Adept::ObjectID m_TargetToAvoid;
Stuff::Time m_TargetToAvoidTime;
LancemateAudio::AudioManager m_AudioManager;
std::vector<CombatAI*> m_CombatAIsWithSquadOrders;
};
};
};
#endif // AI_LANCEMATE_HPP
@@ -0,0 +1,276 @@
#include "MW4Headers.hpp"
#include "AI_LancemateAudio.hpp"
#include <Adept\AudioRenderer.hpp>
#include "LancemateDefines.hpp"
#include "Mech.hpp"
#include "CombatAI.hpp"
#include <Adept\AudioCommand.hpp>
#include <Adept\Application.hpp>
using namespace MW4AI;
using namespace MW4AI::LancemateAudio;
const Stuff::Scalar audio_update_frequency = 1.0f;
const Stuff::Scalar min_audio_replay_time = 60.0f;
const Stuff::Scalar min_mandatory_audio_replay_time = 1.0f;
const Stuff::Time min_idle_time = 65.0f;
AudioManager::AudioManager()
: m_LastTimeAnyAudioPlayed(0)
, m_LastAudioUpdate(0)
, m_PissedOff(false)
{
m_LastTimeNotInactive = 0;
}
AudioManager::~AudioManager()
{
}
void AudioManager::Update(MechWarrior4::Group& group, MechWarrior4::Mech& leader)
{
if ((m_LastAudioUpdate != 0) &&
(m_LastAudioUpdate + audio_update_frequency > gos_GetElapsedTime()))
{
return;
}
if (group.GetElements().size() > 1)
{
std::vector<MWObject*> members;
group.GetMembers(members);
if (members.size() > 1)
{
members.erase(members.begin());
{for (std::vector<MWObject*>::iterator i = members.begin();
i != members.end();
++i)
{
if (((*i)->GetAI() != 0) &&
((*i)->GetAI()->CanAct() == true) &&
((*i)->GetAI()->IsDerivedFrom(CombatAI::DefaultData) == true))
{
CombatAI* combat_ai = Cast_Object(CombatAI*,(*i)->GetAI());
if ((combat_ai->MoveDone() == false) ||
(combat_ai->GetAttackState() == CombatAI::ATTACKING))
{
m_LastTimeNotInactive = gos_GetElapsedTime();
break;
}
}
}}
}
else
{
m_LastTimeNotInactive = gos_GetElapsedTime();
}
}
if ((m_LastTimeNotInactive != 0) &&
(m_LastTimeNotInactive + min_idle_time < gos_GetElapsedTime()) &&
(Adept::Application::GetInstance()->networkingFlag == false))
{
PlayAudio(AUDIO_IDLE,"");
m_LastTimeNotInactive = gos_GetElapsedTime();
}
m_LastAudioUpdate = gos_GetElapsedTime();
}
void AudioManager::PlayAudio(Category category, const Stuff::MString& talker_suffix)
{
MString sound_name("VO\\Generic\\");
bool apply_talker_suffix = true;
// MSL 5.03 Modified wav file called for check fire messages
switch (category)
{
case AUDIO_FF1:
{
// sound_name += "CheckFire1";
// break;
sound_name += "FriendlyTarget_Bet.wav{handle}";
apply_talker_suffix = false;
break;
}
case AUDIO_FF2:
{
// sound_name += "CheckFire2";
// break;
sound_name += "FriendlyTarget_Bet.wav{handle}";
apply_talker_suffix = false;
break;
}
case AUDIO_FF3:
{
// sound_name += "CheckFire1";
// break;
sound_name += "FriendlyTarget_Bet.wav{handle}";
apply_talker_suffix = false;
break;
}
case AUDIO_FF4:
{
sound_name += "KillIan1_RAT.wav{handle}";
apply_talker_suffix = false;
break;
}
case AUDIO_OK:
{
if (m_PissedOff == true)
{
sound_name += "RogerBummed";
}
else
{
switch (gos_rand() & 0x03)
{
case 0:
{
sound_name += "Roger1";
break;
}
case 1:
{
sound_name += "Roger2";
break;
}
case 2:
{
sound_name += "RogerHarried";
break;
}
case 3:
{
sound_name += "Copy";
break;
}
}
}
break;
}
case AUDIO_OKX:
{
sound_name += "RogerBummed";
break;
}
case AUDIO_NO:
{
switch (gos_rand() & 0x01)
{
case 0:
{
sound_name += "NoComply1";
break;
}
case 1:
{
sound_name += "NoComply2";
break;
}
}
break;
}
case AUDIO_TARGETDESTROYED:
{
switch (gos_rand() & 0x01)
{
case 0:
{
sound_name += "TargetDestroyed1";
break;
}
case 1:
{
sound_name += "TargetDestroyed2";
break;
}
}
break;
}
case AUDIO_ATNAV:
{
sound_name += "AtNav";
break;
}
case AUDIO_EJECT:
{
sound_name += "Ejecting";
switch (gos_rand() % 3)
{
case 0: { sound_name += "1"; break; }
case 1: { sound_name += "2"; break; }
default: break;
}
break;
}
case AUDIO_IDLE:
{
sound_name += "Figit";
switch (gos_rand() % 3)
{
case 0: { sound_name += "1"; break; }
case 1: { sound_name += "2"; break; }
case 2: { sound_name += "3"; break; }
}
sound_name += "_RAT.wav{handle}";
apply_talker_suffix = false;
break;
}
}
if (apply_talker_suffix == true)
{
sound_name += talker_suffix;
sound_name += ".wav{handle}";
}
AudioCommand *command = AudioCommand::Create(AudioRenderer::VOType, sound_name, 1.0f, 1.0f);
if (command)
{
Check_Object(command);
command->Play();
}
// PlayAudio(*randomly_chosen);
m_LastTimeAnyAudioPlayed = gos_GetElapsedTime();
m_LastTimeAudioPlayed[category] = gos_GetElapsedTime();
}
void AudioManager::PlayAudio(Category category, const MechWarrior4::AI& ai)
{
if (&ai) {
PlayAudio(category, ai.GetTalkerSuffix());
}
}
void AudioManager::AddAudioCue(Category category, int sound_id)
{
Verify(category >= 0);
Verify(category < MAX_AUDIO_CATEGORIES);
// todo
}
void AudioManager::SetPissedOff(bool pissed_off)
{
m_PissedOff = pissed_off;
}
@@ -0,0 +1,76 @@
#ifndef AI_LANCEMATEAUDIO_HPP
#define AI_LANCEMATEAUDIO_HPP
#include "ai_squad.hpp"
#pragma warning(push)
#include <stlport\list>
#include <stlport\vector>
#pragma warning(pop)
namespace MechWarrior4
{
class Mech;
};
namespace MW4AI
{
namespace LancemateAudio
{
enum Category
{
AUDIO_FF1,
AUDIO_FF2,
AUDIO_FF3,
AUDIO_FF4,
AUDIO_OK,
AUDIO_OKX,
AUDIO_NO,
AUDIO_TARGETDESTROYED,
AUDIO_ATNAV,
AUDIO_EJECT,
AUDIO_IDLE,
MAX_AUDIO_CATEGORIES
};
enum Priority
{
PRIORITY_OPTIONAL,
PRIORITY_MANDATORY
};
class AudioManager
{
public:
AudioManager();
~AudioManager();
void PlayAudio(Category category, const Stuff::MString& talker_suffix);
void PlayAudio(Category category, const MechWarrior4::AI& ai);
void Update(MechWarrior4::Group& group, MechWarrior4::Mech& leader);
void SetPissedOff(bool pissed_off);
private:
void AddAudioCue(Category category, int sound_id);
void UpdateAudio(MechWarrior4::Group& group);
private:
Stuff::Time m_LastTimeAudioPlayed[MAX_AUDIO_CATEGORIES];
Stuff::Time m_LastTimeAnyAudioPlayed;
Stuff::Time m_LastAudioUpdate;
Stuff::Time m_LastTimeNotInactive;
bool m_PissedOff;
};
};
};
#endif // AI_LANCEMATEAUDIO_HPP
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,113 @@
#pragma once
#ifndef AI_LANCEMATECOMMANDS_HPP
#define AI_LANCEMATECOMMANDS_HPP
#include "AI_LancemateAudio.hpp"
#include <Adept\Entity.hpp>
#include <Stuff\Auto_Ptr.hpp>
#pragma warning(push)
#include <stlport\vector>
#pragma warning(pop)
#include "AI_FindObject.hpp"
namespace MW4AI
{
namespace LancemateCommands
{
enum ID
{
LANCEMATE_FIRST = 4999, // NOTE: change the constants in MWCONST.ABI if you change these
LANCEMATE_DEFAULT = 5000,
LANCEMATE_ATTACKPLAYERSTARGET = 5001,
LANCEMATE_DEFENDPLAYERSTARGET = 5002,
LANCEMATE_FORMONME = 5003,
LANCEMATE_HOLDFIRE = 5004,
LANCEMATE_GOTOMYNAVPOINT = 5005,
LANCEMATE_STOP = 5006,
LANCEMATE_SHUTDOWN = 5007,
LANCEMATE_ATTACKNEARESTTHREAT = 5008,
LANCEMATE_REPAIRATNEARESTREPAIRBAY = 5009,
//LANCEMATE_CAPTUREPLAYERSFLAG?
LANCEMATE_LAST = 5011
};
typedef std::vector<Adept::ObjectID> lancemate_list;
void Execute(ID command, const lancemate_list& lancemates);
void ExecuteForAllLancemates2(Mech* paMechs[], int nMechs, LancemateCommands::ID command_id, MWObject* pLeader, MWObject* pTarget);
#define INTERFACE_LancemateCommand(post) \
public: \
virtual void Init() ##post \
virtual bool Finished() const ##post \
virtual void Update() ##post
#define PURE_LancemateCommand INTERFACE_LancemateCommand(=0;)
#define DERIVED_LancemateCommand(classname) \
INTERFACE_LancemateCommand(;) \
classname(MechWarrior4::CombatAI& combat_ai, MechWarrior4::MWObject& leader, LancemateAudio::AudioManager& audio_manager, Adept::Entity* pTarget2 = NULL) \
: LancemateCommand(combat_ai,leader,audio_manager,pTarget2) { Init(); }
class LancemateCommand
{
public:
PURE_LancemateCommand;
LancemateCommand(MechWarrior4::CombatAI& combat_ai,
MechWarrior4::MWObject& leader,
LancemateAudio::AudioManager& audio_manager,
Adept::Entity* pTarget2 = NULL); // jcem
virtual ~LancemateCommand();
virtual bool OnLeash() const;
virtual Stuff::Point3D GetLeashPoint() const;
virtual Stuff::Scalar GetLeashRadius() const;
virtual bool CanDistract() const;
virtual bool CanDeviateFromPath() const;
virtual void NotifyNoPath();
virtual bool CanInterrupt() const { return (true); }
MechWarrior4::MWObject* FindSomeoneToAttack(const Adept::ObjectID* except_who,
FindObject::Criteria = FindObject::FC_BEST_TARGET,
Stuff::Scalar radius = MW4AI::FindObject::DISTANCE_LIMIT) const;
protected:
MechWarrior4::CombatAI& m_CombatAI;
SlotOf<MechWarrior4::MWObject*> m_Leader;
LancemateAudio::AudioManager& m_AudioManager;
SlotOf<Adept::Entity*> m_pTarget2;
};
Stuff::Auto_Ptr<LancemateCommand> CreateLancemateCommand(ID command,
MechWarrior4::CombatAI& combat_ai,
MechWarrior4::MWObject& leader,
LancemateAudio::AudioManager& audio_manager,
Adept::Entity* pTarget2 = NULL);
class Default
: public LancemateCommand
{
DERIVED_LancemateCommand(Default);
virtual bool CanDistract() const;
virtual bool CanDeviateFromPath() const;
virtual void NotifyNoPath();
private:
void GoIntoFormation();
private:
SlotOf<Adept::Entity*> m_LastTarget;
Stuff::Scalar m_LastTimeNotWaiting;
};
};
};
#endif // AI_LANCEMATECOMMANDS_HPP
+591
View File
@@ -0,0 +1,591 @@
#include "MW4Headers.hpp"
#include "AI_Log.hpp"
#include "aiutils.hpp"
#include "MWPlayer.hpp"
#include "VehicleInterface.hpp"
int g_objects_in_existence = 0;
using namespace MW4AI;
LogNode::LogNode(Type type, const std::string& text, const std::string& label)
: m_Text(text)
, m_Type(type)
, m_Label(label)
, m_Line(0)
{
Verify(type >= TYPE_FIRST);
Verify(type <= TYPE_LAST);
++g_objects_in_existence;
}
LogNode::LogNode(Type type, const std::string& text, const std::string& label, const std::string& filename, int line_number)
: m_Text(text)
, m_Type(type)
, m_Label(label)
, m_File(filename)
, m_Line(line_number)
{
Verify(type >= TYPE_FIRST);
Verify(type <= TYPE_LAST);
++g_objects_in_existence;
}
LogNode::~LogNode()
{
--g_objects_in_existence;
while (m_Children.size() > 0)
{
delete (*(m_Children.begin()));
m_Children.erase(m_Children.begin());
}
}
LogNode* LogNode::AddChild(Type type, const std::string& text, const std::string& label)
{
LogNode* new_node = new LogNode(type,text,label);
m_Children.push_back(new_node);
return (new_node);
}
LogNode* LogNode::AddChild(Type type, const std::string& text, const std::string& label, const std::string& filename, int line_number)
{
LogNode* new_node = new LogNode(type,text,label,filename,line_number);
m_Children.push_back(new_node);
return (new_node);
}
LogNode* LogNode::Find(const std::string& text)
{
{for (std::vector<LogNode*>::iterator i = m_Children.begin();
i != m_Children.end();
++i)
{
LogNode* found = (*i)->Find(text);
if (found != 0)
{
return (found);
}
}}
if (m_Text == text)
{
return (this);
}
return (0);
}
std::string LogNode::GetText() const
{
return (m_Text);
}
LogNode::Type LogNode::GetType() const
{
return (m_Type);
}
std::string LogNode::GetLabel() const
{
return (m_Label);
}
std::string LogNode::GetFile() const
{
return (m_File);
}
int LogNode::GetLine() const
{
return (m_Line);
}
void LogNode::SpewToString(std::string& output, unsigned int level, bool first_in_row) const
{
std::string prefix;
if (m_Text.size() > 0)
{
{for (unsigned int i = 0;
i < level;
++i)
{
prefix += " | ";
}}
if (GetType() == LogNode::TYPE_FUNCTION)
{
output += prefix;
}
output += m_Text;
if (m_Label.size() != 0)
{
output += " (";
output += m_Label;
output += ")";
}
if (m_File.size() != 0)
{
std::string f = m_File;
while (f.find('\\') != std::string::npos)
{
f.erase(0,1);
}
output += " [";
output += f;
output += ", line ";
output += IntToString(m_Line);
output += "]";
}
if (GetType() == LogNode::TYPE_FUNCTION)
{
output += "\n";
}
}
bool fDrawn = false;
{for (std::vector<LogNode*>::const_iterator i = m_Children.begin();
i != m_Children.end();
++i)
{
if ((*i)->GetType() == LogNode::TYPE_PARAMETER)
{
if (fDrawn == false)
{
output += prefix;
}
else
{
output += ", ";
}
(*i)->SpewToString(output,level+1);
fDrawn = true;
}
}}
{for (std::vector<LogNode*>::const_iterator i = m_Children.begin();
i != m_Children.end();
++i)
{
if ((*i)->GetType() == LogNode::TYPE_RETURN_VALUE)
{
if (fDrawn == false)
{
output += prefix;
}
else
{
output += ", ";
}
(*i)->SpewToString(output,level+1);
fDrawn = true;
}
}}
if (fDrawn == true)
{
output += "\n";
}
{for (std::vector<LogNode*>::const_iterator i = m_Children.begin();
i != m_Children.end();
++i)
{
if ((*i)->GetType() == LogNode::TYPE_FUNCTION)
{
(*i)->SpewToString(output,level+1);
}
}}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DiagnosticsInterface* DiagnosticsInterface::m_Instance = 0;
DiagnosticsInterface::DiagnosticsInterface()
: m_Enabled(false)
, m_ExecutingObject(0)
, m_FileAndLineEnabled(false)
, m_ParameterNamesEnabled(false)
, m_FileSpewing(false)
{
Verify(m_Instance == 0);
m_Instance = this;
m_Root.Assimilate(new LogNode(LogNode::TYPE_FUNCTION,""));
}
DiagnosticsInterface::~DiagnosticsInterface()
{
Verify(m_Instance == this);
m_Instance = 0;
}
void DiagnosticsInterface::Reset()
{
if (m_Root.GetPointer() != 0)
{
m_Root.Delete();
m_Root.Assimilate(new LogNode(LogNode::TYPE_FUNCTION,""));
}
}
DiagnosticsInterface& DiagnosticsInterface::GetInstance()
{
Verify(m_Instance != 0);
return (*m_Instance);
}
void DiagnosticsInterface::Log(LogNode::Type type, const std::string& value, const std::string& label)
{
if (CanLog() == false)
{
return;
}
std::string l;
if ((GetParameterNamesEnabled() == true) ||
(type != LogNode::TYPE_PARAMETER))
{
l = label;
}
Verify(m_Stack.size() > 0);
m_Stack.back()->AddChild(type,value,l);
}
void DiagnosticsInterface::Log(LogNode::Type type, const Stuff::Scalar& value, const std::string& label)
{
if (CanLog() == false)
{
return;
}
Log(type,ScalarToString(value),label);
}
void DiagnosticsInterface::Log(LogNode::Type type, const Stuff::Point3D& value, const std::string& label)
{
if (CanLog() == false)
{
return;
}
std::string s("(");
s += ScalarToString(value.x);
s += ",";
s += ScalarToString(value.y);
s += ",";
s += ScalarToString(value.z);
s += ")";
Log(type,s,label);
}
void DiagnosticsInterface::Log(LogNode::Type type, const int& value, const std::string& label)
{
if (CanLog() == false)
{
return;
}
Log(type,IntToString(value),label);
}
void DiagnosticsInterface::Log(LogNode::Type type, const bool& value, const std::string& label)
{
if (CanLog() == false)
{
return;
}
Log(type,BoolToString(value),label);
}
void DiagnosticsInterface::Log(LogNode::Type type, const TacticInterface::WR_WHO& value, const std::string& label)
{
if (CanLog() == false)
{
return;
}
switch (value)
{
case TacticInterface::SELF:
{
Log(type,(std::string)"Self",label);
return;
}
case TacticInterface::TARGET:
{
Log(type,(std::string)"Target",label);
return;
}
}
Log(type,(std::string)"***INVALID***",label);
}
void DiagnosticsInterface::Log(LogNode::Type type, const TacticInterface::WR_QUALIFIER& value, const std::string& label)
{
if (CanLog() == false)
{
return;
}
switch (value)
{
case TacticInterface::MIN:
{
Log(type,(std::string)"Min",label);
return;
}
case TacticInterface::MAX:
{
Log(type,(std::string)"Max",label);
return;
}
}
Log(type,(std::string)"***INVALID***",label);
}
void DiagnosticsInterface::Log(LogNode::Type type, const Stuff::Time& value, const std::string& label)
{
if (CanLog() == false)
{
return;
}
Log(type,ScalarToString((Stuff::Scalar)value),label);
}
void DiagnosticsInterface::Log(LogNode::Type type, const UserConstants::ID& value, const std::string& label)
{
if (CanLog() == false)
{
return;
}
Log(type,IntToString((int)value),label);
}
void DiagnosticsInterface::Log(LogNode::Type type, const FireStyles::FireStyleID& value, const std::string& label)
{
if (CanLog() == false)
{
return;
}
Log(type,FireStyles::FireStyleToString(value),label);
}
void DiagnosticsInterface::Log(LogNode::Type type, const FireData::HIT_RESULT& value, const std::string& label)
{
if (CanLog() == false)
{
return;
}
switch (value)
{
case FireData::HIT_TARGET:
{
Log(type,(std::string)"HIT_TARGET",label);
return;
}
case FireData::HIT_SOMETHING_ELSE:
{
Log(type,(std::string)"HIT_SOMETHING_ELSE",label);
return;
}
case FireData::HIT_NOTHING:
{
Log(type,(std::string)"HIT_NOTHING",label);
return;
}
}
Log(type,(std::string)"***INVALID***",label);
}
void DiagnosticsInterface::PushFunction(const std::string& funcname, const std::string& file, int line)
{
if (CanLog() == false)
{
return;
}
LogNode* new_node = 0;
if (m_Stack.size() == 0)
{
if (GetFileAndLineEnabled() == true)
{
new_node = m_Root->AddChild(LogNode::TYPE_FUNCTION,funcname,"",file,line);
}
else
{
new_node = m_Root->AddChild(LogNode::TYPE_FUNCTION,funcname);
}
}
else
{
if (GetFileAndLineEnabled() == true)
{
new_node = m_Stack.back()->AddChild(LogNode::TYPE_FUNCTION,funcname,"",file,line);
}
else
{
new_node = m_Stack.back()->AddChild(LogNode::TYPE_FUNCTION,funcname);
}
}
m_Stack.push_back(new_node);
}
void DiagnosticsInterface::PopFunction(const std::string& funcname)
{
if (CanLog() == false)
{
return;
}
Verify(m_Stack.size() > 0);
Verify(m_Stack.back()->GetText() == funcname);
m_Stack.pop_back();
if (m_Stack.size() == 0)
{
if (m_Root.GetPointer() != 0)
{
m_BufferedSpew = "";
m_Root->SpewToString(m_BufferedSpew);
}
}
}
void DiagnosticsInterface::SetEnabled(bool enabled)
{
#ifdef LAB_ONLY
m_Enabled = enabled;
#endif
}
bool DiagnosticsInterface::GetEnabled() const
{
return (m_Enabled);
}
void DiagnosticsInterface::SetFileAndLineEnabled(bool enabled)
{
m_FileAndLineEnabled = enabled;
}
bool DiagnosticsInterface::GetFileAndLineEnabled() const
{
return (m_FileAndLineEnabled);
}
void DiagnosticsInterface::SetParameterNamesEnabled(bool enabled)
{
m_ParameterNamesEnabled = enabled;
}
bool DiagnosticsInterface::GetParameterNamesEnabled() const
{
return (m_ParameterNamesEnabled);
}
void DiagnosticsInterface::SetFileSpewing(bool enabled)
{
m_FileSpewing = enabled;
}
bool DiagnosticsInterface::GetFileSpewing() const
{
return (m_FileSpewing);
}
void DiagnosticsInterface::GetSpew(std::string& output) const
{
output = m_BufferedSpew;
}
Adept::Entity* GetPlayerVehicle()
{
if (Adept::Player::GetInstance() == 0)
{
return (0);
}
MechWarrior4::MWPlayer* p = Cast_Object(MechWarrior4::MWPlayer*,Adept::Player::GetInstance());
if (p == 0)
{
return (0);
}
Check_Object(p);
if (p->GetInterface() == 0)
{
return (0);
}
return (p->GetInterface()->vehicle);
}
void DiagnosticsInterface::SetExecutingObject(MechWarrior4::MWObject* object)
{
m_ExecutingObject = object;
if ((m_ExecutingObject != 0) &&
(GetPlayerVehicle() != 0) &&
(m_ExecutingObject == GetPlayerVehicle()))
{
Reset();
}
}
bool DiagnosticsInterface::CanLog() const
{
if ((GetEnabled() == false) ||
(m_ExecutingObject == 0) ||
(GetPlayerVehicle() == 0))
{
return (false);
}
return (m_ExecutingObject == GetPlayerVehicle());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
LogFunction::LogFunction(const std::string& name, const std::string& file, int line)
: m_Name(name)
{
DiagnosticsInterface::GetInstance().PushFunction(m_Name,file,line);
}
LogFunction::~LogFunction()
{
DiagnosticsInterface::GetInstance().PopFunction(m_Name);
}
+158
View File
@@ -0,0 +1,158 @@
#pragma once
#ifndef AI_LOG_HPP
#define AI_LOG_HPP
#pragma warning(push)
#include <stlport\string>
#include <stlport\vector>
#pragma warning(pop)
#include "AI_UserConstants.hpp"
#include "AI_TacticInterface.hpp"
#include "AI_FireData.hpp"
#include <Stuff\Auto_Ptr.hpp>
namespace MechWarrior4
{
class MWObject;
};
namespace MW4AI
{
class LogNode
{
public:
enum Type
{
TYPE_PARAMETER, // change TYPE_FIRST if you change this
TYPE_RETURN_VALUE,
TYPE_FUNCTION // change TYPE_LAST if you change this
};
LogNode(Type type, const std::string& text, const std::string& label = "");
LogNode(Type type, const std::string& text, const std::string& label, const std::string& filename, int line_number);
~LogNode();
LogNode* AddChild(Type type, const std::string& text, const std::string& label = "");
LogNode* AddChild(Type type, const std::string& text, const std::string& label, const std::string& filename, int line_number);
LogNode* Find(const std::string& text);
std::string GetText() const;
std::string GetLabel() const;
Type GetType() const;
std::string GetFile() const;
int GetLine() const;
void SpewToString(std::string& output, unsigned int level = 0, bool first_in_row = false) const;
private:
const std::string m_Text;
const std::string m_Label;
std::vector<LogNode*> m_Children;
const Type m_Type;
const std::string m_File;
const int m_Line;
enum
{
TYPE_FIRST = TYPE_PARAMETER,
TYPE_LAST = TYPE_FUNCTION
};
};
class DiagnosticsInterface
{
public:
DiagnosticsInterface();
~DiagnosticsInterface();
static DiagnosticsInterface& GetInstance();
void Log(LogNode::Type type, const std::string& value, const std::string& label = "");
void Log(LogNode::Type type, const Stuff::Scalar& value, const std::string& label = "");
void Log(LogNode::Type type, const Stuff::Point3D& value, const std::string& label = "");
void Log(LogNode::Type type, const int& value, const std::string& label = "");
void Log(LogNode::Type type, const bool& value, const std::string& label = "");
void Log(LogNode::Type type, const TacticInterface::WR_WHO& value, const std::string& label = "");
void Log(LogNode::Type type, const TacticInterface::WR_QUALIFIER& value, const std::string& label = "");
void Log(LogNode::Type type, const Stuff::Time& value, const std::string& label = "");
void Log(LogNode::Type type, const UserConstants::ID& value, const std::string& label = "");
void Log(LogNode::Type type, const FireStyles::FireStyleID& value, const std::string& label = "");
void Log(LogNode::Type type, const FireData::HIT_RESULT& value, const std::string& label = "");
void PushFunction(const std::string& funcname, const std::string& file, int line);
void PopFunction(const std::string& funcname);
void SetEnabled(bool enabled);
bool GetEnabled() const;
void SetFileAndLineEnabled(bool enabled);
bool GetFileAndLineEnabled() const;
void SetParameterNamesEnabled(bool enabled);
bool GetParameterNamesEnabled() const;
void SetFileSpewing(bool enabled);
bool GetFileSpewing() const;
void Reset();
void GetSpew(std::string& output) const;
void SetExecutingObject(MechWarrior4::MWObject* object);
private:
static DiagnosticsInterface* m_Instance;
Stuff::Auto_Ptr<LogNode> m_Root;
std::vector<LogNode*> m_Stack;
bool m_Enabled;
bool m_FileAndLineEnabled;
bool m_ParameterNamesEnabled;
bool m_FileSpewing;
MWObject* m_ExecutingObject;
std::string m_BufferedSpew;
private:
bool CanLog() const;
};
class LogFunction
{
public:
LogFunction(const std::string& name, const std::string& file, int line);
~LogFunction();
private:
const std::string m_Name;
};
/*
// disabled: AI logging is not currently used for anything, so no point wasting time on it, even in Debug
#ifdef _ARMOR
#define AILOGFUNC(funcname) MW4AI::LogFunction func(funcname,__FILE__,__LINE__);
#define AILOGTEXT(value) MW4AI::DiagnosticsInterface::GetInstance().Log(LogNode::TYPE_PARAMETER,(std::string)value);
#define AILOG(value) MW4AI::DiagnosticsInterface::GetInstance().Log(LogNode::TYPE_PARAMETER,value,#value);
#define AILOG1(value1) AILOG(value1);
#define AILOG2(value1,value2) AILOG(value1); AILOG(value2);
#define AILOG3(value1,value2,value3) AILOG(value1); AILOG(value2); AILOG(value3);
#define AILOG4(value1,value2,value3,value4) AILOG(value1); AILOG(value2); AILOG(value3); AILOG(value4);
#define LOG_AND_RETURN(value) MW4AI::DiagnosticsInterface::GetInstance().Log(LogNode::TYPE_RETURN_VALUE,value,"RETURNED"); return (value);
#else
*/
#define AILOGFUNC(funcname) ;
#define AILOGTEXT(value) ;
#define AILOG(value) ;
#define AILOG1(value1) ;
#define AILOG2(value1,value2) ;
#define AILOG3(value1,value2,value3) ;
#define AILOG4(value1,value2,value3,value4) ;
#define LOG_AND_RETURN(value) return (value);
// #endif
};
#endif // AI_LOG_HPP
+106
View File
@@ -0,0 +1,106 @@
#include "MW4Headers.hpp"
#include "AI_MoodSquad.hpp"
#include "ai.hpp"
#include "AI_Groups.hpp"
#include "AI_UserConstants.hpp"
using namespace MW4AI;
using namespace MW4AI::Squad;
using namespace MechWarrior4;
MoodSquad::MoodSquad()
: m_LastMoodUpdateTime(0)
, m_NumDeadUnits(0)
{
}
ID MoodSquad::GetID() const
{
return (GROUPAI_MOODSQUAD);
}
void MoodSquad::Update(MechWarrior4::Group& group, MechWarrior4::CombatAI& combat_ai)
{
inherited::Update(group,combat_ai);
if (m_LastMoodUpdateTime >= gos_GetElapsedTime())
{
return;
}
const int num_dead_units = Groups::NumDead(group.GetID());
if ((m_LastMoodUpdateTime != 0) &&
(num_dead_units > m_NumDeadUnits))
{
std::vector<MWObject*> groupmates;
group.GetMembers(groupmates);
if (groupmates.size() > 0)
{
const int dead_unit_delta = m_NumDeadUnits - num_dead_units;
const Stuff::Scalar mood_delta = ((Stuff::Scalar)dead_unit_delta / groupmates.size()) * UserConstants::Instance()->Get(UserConstants::mood_squad_dead_unit_multiplier);
LowerEveryonesMood(mood_delta,groupmates);
}
}
m_NumDeadUnits = num_dead_units;
m_LastMoodUpdateTime = gos_GetElapsedTime();
}
void MoodSquad::LowerEveryonesMood(Stuff::Scalar mood_delta, std::vector<MWObject*>& groupmates)
{
{for (std::vector<MWObject*>::const_iterator i = groupmates.begin();
i != groupmates.end();
++i)
{
if ((*i)->GetAI() != 0)
{
Stuff::Scalar mood = (*i)->GetAI()->CurrentMood();
mood += mood_delta;
if (mood < MW4AI::MOODMIN)
{
mood = MW4AI::MOODMIN;
}
if (mood > MW4AI::MOODMAX)
{
mood = MW4AI::MOODMAX;
}
(*i)->GetAI()->CurrentMood(mood);
}
}}
}
void MoodSquad::NotifyShot(MechWarrior4::Group& group, Adept::ObjectID id)
{
inherited::NotifyShot(group,id);
}
void MoodSquad::NotifyShotFired(MechWarrior4::Group& group, const Stuff::Line3D& line, MechWarrior4::MWObject& at_who, MechWarrior4::MWObject& shooter)
{
inherited::NotifyShotFired(group,line,at_who,shooter);
}
void MoodSquad::NotifyMemberAdded(MechWarrior4::Group& group, MechWarrior4::MWObject& who)
{
inherited::NotifyMemberAdded(group,who);
}
void MoodSquad::NotifyMemberRemoved(MechWarrior4::Group& group, MechWarrior4::MWObject& who)
{
inherited::NotifyMemberRemoved(group,who);
}
void MoodSquad::SetEntityToIgnore(Adept::ObjectID objectid)
{
}
@@ -0,0 +1,38 @@
#pragma once
#ifndef AI_MOODSQUAD_HPP
#define AI_MOODSQUAD_HPP
#include "AI_RadioSquad.hpp"
#include <Stuff\Scalar.hpp>
namespace MW4AI
{
namespace Squad
{
class MoodSquad
: public RadioSquad
{
DERIVED_SquadAI;
typedef RadioSquad inherited;
public:
MoodSquad();
ID GetID() const;
private:
void LowerEveryonesMood(Stuff::Scalar mood_delta, std::vector<MWObject*>& groupmates);
private:
Stuff::Time m_LastMoodUpdateTime;
int m_NumDeadUnits;
};
};
};
#endif // AI_MOODSQUAD_HPP
+131
View File
@@ -0,0 +1,131 @@
#include "MW4Headers.hpp"
#include "AI_Moods.hpp"
#include <Stuff\Auto_Ptr.hpp>
using namespace MW4AI::Moods;
/*
template <class enum_type, class container_type>
Stuff::Auto_Ptr<container_type> CreateEnumContainer(enum_type first, enum_type last)
{
container_type* container = new container_type;
Verify(sizeof(enum_type) == sizeof(int));
{for (int i = (int)first;
i != ((int)last) + 1;
++i)
{
container->push_back((enum_type)i);
}}
return (container);
}
*/
Stuff::Auto_Ptr<MW4AI::Moods::Mood> MW4AI::Moods::CreateMood(MW4AI::Moods::ID mood)
{
Verify(MW4AI::MOODMIN == DESPERATE_START);
Verify(MW4AI::MOODMAX == BRUTAL_END);
if ((mood >= DESPERATE_START) &&
(mood <= DESPERATE_END))
{
return (new Desperate);
}
if ((mood >= DEFENSIVE_START) &&
(mood <= DEFENSIVE_END))
{
return (new Defensive);
}
if ((mood >= NEUTRAL_START) &&
(mood <= NEUTRAL_END))
{
return (new Neutral);
}
if ((mood >= AGRESSIVE_START) &&
(mood <= AGRESSIVE_END))
{
return (new Aggressive);
}
if ((mood >= BRUTAL_START) &&
(mood <= BRUTAL_END))
{
return (new Brutal);
}
Verify(!"Mood not found.");
return (new (Neutral));
}
void VerifyMood(MW4AI::Moods::ID mood)
{
Verify(MW4AI::MOODMIN == DESPERATE_START);
Verify(MW4AI::MOODMAX == BRUTAL_END);
Verify(mood >= MW4AI::MOODMIN);
Verify(mood <= MW4AI::MOODMAX);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Desperate mood
//
/*
void MW4AI::Moods::Desperate::GetTactics(std::vector<Tactics::TacticID>& tactics) const
{
tactics.push_back(TACTIC_RETREAT);
}*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Defensive mood
//
/*
void MW4AI::Moods::Defensive::GetTactics(std::vector<Tactics::TacticID>& tactics) const
{
// tactics.push_back(TACTIC_REAR);
// tactics.push_back(TACTIC_BACK_UP_AND_FIRE);
tactics.push_back(TACTIC_RUSH);
}*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Neutral mood
//
/*
void MW4AI::Moods::Neutral::GetTactics(std::vector<Tactics::TacticID>& tactics) const
{
// tactics.push_back(TACTIC_STAND_GROUND);
// tactics.push_back(TACTIC_HIT_AND_RUN);
tactics.push_back(TACTIC_RUSH);
}*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Aggressive mood
//
/*
void MW4AI::Moods::Aggressive::GetTactics(std::vector<Tactics::TacticID>& tactics) const
{
// tactics.push_back(TACTIC_CIRCLE_OF_DEATH);
// tactics.push_back(TACTIC_JOUST);
// tactics.push_back(TACTIC_RUSH);
tactics.push_back(TACTIC_RUSH);
}*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Brutal mood
//
/*
void MW4AI::Moods::Brutal::GetTactics(std::vector<Tactics::TacticID>& tactics) const
{
// tactics.push_back(TACTIC_STOP_AND_FIRE);
// tactics.push_back(TACTIC_RAM);
tactics.push_back(TACTIC_RUSH);
}*/
+75
View File
@@ -0,0 +1,75 @@
#pragma once
#ifndef AI_MOODS_HPP
#define AI_MOODS_HPP
#include "AI.hpp"
#pragma warning (push)
#include <stlport\vector>
#include <stlport\string>
#pragma warning (pop)
namespace MW4AI
{
namespace Moods
{
enum ID // NOTE: the keywords and constants here must exactly match those in MWCONST.ABI
{
DESPERATE_START = 1, // change MOODMIN in Adept\AI.hpp if you change this
DESPERATE_END = 2,
DEFENSIVE_START = 3,
DEFENSIVE_END = 4,
NEUTRAL_START = 5,
NEUTRAL_END = 6,
AGRESSIVE_START = 7,
AGRESSIVE_END = 8,
BRUTAL_START = 9,
BRUTAL_END = 10 // change MOODMAX in Adept\AI.hpp if you change this
};
class Mood
{
public:
virtual std::string GetName() const = 0;
virtual ~Mood() {};
};
Stuff::Auto_Ptr<Mood> CreateMood(ID mood);
void VerifyMood(ID mood);
#define BEGINDEF_MOOD(classname,stringname) \
class classname \
: public Mood \
{ \
public: \
std::string GetName() const { return (stringname); } \
#define ENDDEF_MOOD };
BEGINDEF_MOOD(Desperate,"DESPERATE")
ENDDEF_MOOD
BEGINDEF_MOOD(Defensive,"DEFENSIVE")
ENDDEF_MOOD
BEGINDEF_MOOD(Neutral,"NEUTRAL")
ENDDEF_MOOD
BEGINDEF_MOOD(Aggressive,"AGGRESSIVE")
ENDDEF_MOOD
BEGINDEF_MOOD(Brutal,"BRUTAL")
ENDDEF_MOOD
#undef BEGINDEF_MOOD
#undef ENDDEF_MOOD
};
};
#endif // AI_MOODS_HPP
@@ -0,0 +1,99 @@
#include "MW4Headers.hpp"
#include "AI_RadioSquad.hpp"
#include "ai.hpp"
using namespace MW4AI;
using namespace MW4AI::Squad;
using namespace MechWarrior4;
const Stuff::Scalar isshot_propagation_delay = 2.0f;
RadioSquad::RadioSquad()
{
}
RadioSquad::~RadioSquad()
{
}
ID RadioSquad::GetID() const
{
return (GROUPAI_RADIOSQUAD);
}
void RadioSquad::Update(MechWarrior4::Group& group, MechWarrior4::CombatAI& combat_ai)
{
UpdateIsShotCommunications(group);
}
void RadioSquad::NotifyShot(MechWarrior4::Group& group, Adept::ObjectID id)
{
is_shot_notifier n(id,gos_GetElapsedTime() + isshot_propagation_delay);
is_shot_notifier_list::iterator found = m_IsShotNotifiers.find(n.first);
if ((found == m_IsShotNotifiers.end()) ||
((*found).second > n.second))
{
if (found != m_IsShotNotifiers.end())
{
m_IsShotNotifiers.erase(found);
}
m_IsShotNotifiers.insert(n);
}
}
void RadioSquad::NotifyShotFired(MechWarrior4::Group& group, const Stuff::Line3D& line, MechWarrior4::MWObject& at_who, MechWarrior4::MWObject& shooter)
{
}
void RadioSquad::UpdateIsShotCommunications(const Group& group)
{
{for (is_shot_notifier_list::iterator i = m_IsShotNotifiers.begin();
i != m_IsShotNotifiers.end();
++i)
{
if ((*i).second < gos_GetElapsedTime())
{
{for (Group::element_list::const_iterator i_group = group.GetElements().begin();
i_group != group.GetElements().end();
++i_group)
{
Adept::Entity* entity = group.IDToEntity(*i_group);
if ((entity != 0) &&
(entity->IsDerivedFrom(MWObject::DefaultData) == true))
{
MWObject* mwobject = Cast_Object(MWObject*,entity);
if (mwobject->GetAI() != 0)
{
mwobject->GetAI()->NotifyShot((*i).first,false);
}
}
}}
m_IsShotNotifiers.erase(i);
UpdateIsShotCommunications(group);
return;
}
}}
}
void RadioSquad::NotifyMemberAdded(MechWarrior4::Group& group, MechWarrior4::MWObject& who)
{
}
void RadioSquad::NotifyMemberRemoved(MechWarrior4::Group& group, MechWarrior4::MWObject& who)
{
}
void RadioSquad::SetEntityToIgnore(Adept::ObjectID objectid)
{
}
@@ -0,0 +1,40 @@
#pragma once
#ifndef AI_RADIOSQUAD_HPP
#define AI_RADIOSQUAD_HPP
#include "AI_Squad.hpp"
#pragma warning(push)
#include <stlport\map>
#pragma warning(pop)
namespace MW4AI
{
namespace Squad
{
class RadioSquad
: public AI
{
DERIVED_SquadAI;
public:
RadioSquad();
virtual ~RadioSquad();
ID GetID() const;
private:
void UpdateIsShotCommunications(const MechWarrior4::Group& group);
private:
typedef std::pair<const Adept::ObjectID, Stuff::Time> is_shot_notifier;
typedef std::map<const Adept::ObjectID, Stuff::Time> is_shot_notifier_list;
is_shot_notifier_list m_IsShotNotifiers;
};
};
};
#endif // AI_RADIOSQUAD_HPP
@@ -0,0 +1,60 @@
#include "MW4Headers.hpp"
#include "AI_SearchLight.hpp"
#include <Adept\Mission.hpp>
#include "CombatAI.hpp"
using namespace MW4AI;
SearchLightController::SearchLightController(CombatAI& combat_ai)
: m_CombatAI(combat_ai)
, m_State(UNSPECIFIED)
{
}
void SearchLightController::Update()
{
bool on = false;
if (m_State == ON)
{
on = true;
}
else
{
if (m_State == UNSPECIFIED)
{
Adept::Mission* mission = Adept::Mission::GetInstance();
if (mission != 0)
{
on = mission->m_isNightMission;
}
}
}
if (on == m_CombatAI.GetSelf().IsSearchLightOn())
{
return;
}
if (on == true)
{
m_CombatAI.GetSelf().TurnOnSearchLight();
}
else
{
m_CombatAI.GetSelf().TurnOffSearchLight();
}
}
void SearchLightController::SetState(State state)
{
Verify(state >= STATE_FIRST);
Verify(state <= STATE_LAST);
m_State = state;
}
@@ -0,0 +1,49 @@
#pragma once
#ifndef AI_SEARCHLIGHT_HPP
#define AI_SEARCHLIGHT_HPP
namespace MechWarrior4
{
class CombatAI;
};
namespace MW4AI
{
class SearchLightController
{
public:
enum State
{
ON,
OFF,
UNSPECIFIED
};
enum
{
STATE_FIRST = ON,
STATE_LAST = UNSPECIFIED
};
SearchLightController(CombatAI& combat_ai);
void Update();
void SetState(State state);
State GetState() const
{
return (m_State);
}
private:
CombatAI& m_CombatAI;
State m_State;
};
};
#endif // AI_SEARCHLIGHT_HPP
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,241 @@
#ifndef AI_SITUATIONAL_ANALYSIS_HPP
#define AI_SITUATIONAL_ANALYSIS_HPP
#include <Stuff\Point3D.hpp>
#pragma warning(push)
#include <stlport\vector>
#include <stlport\map>
#pragma warning(pop)
#include "AI_Fuzzy.hpp"
#include "AI_TacticInterface.hpp"
#define INTERFACE_PointEvaluator(post) \
public: \
virtual Fuzzy Evaluate(TacticInterface& i, \
const enemies_list& enemies, \
const Stuff::Point3D& point) const ##post
#define PURE_PointEvaluator INTERFACE_PointEvaluator(=0;)
#define DERIVED_PointEvaluator INTERFACE_PointEvaluator(;)
#define INTERFACE_RegionGenerator(post) \
public: \
virtual void Generate(TacticInterface& i, \
point_list& points, \
int iteration = 0) const ##post \
virtual unsigned int Iterations() const ##post \
virtual bool IgnoreMissionBounds(TacticInterface& i) const ##post
#define PURE_RegionGenerator INTERFACE_RegionGenerator(=0;)
#define DERIVED_RegionGenerator INTERFACE_RegionGenerator(;)
namespace MechWarrior4
{
class MWObject;
};
namespace MW4AI
{
class TacticInterface;
namespace SituationalAnalysis
{
typedef std::vector<Stuff::Point3D> point_list;
typedef std::vector<MWObject*> enemies_list;
typedef std::multimap<const Fuzzy,Stuff::Point3D> ranked_point_list;
typedef std::pair<const Fuzzy,Stuff::Point3D> ranked_point;
class PointEvaluator
{
PURE_PointEvaluator;
virtual ~PointEvaluator() {};
public:
static void SetEvaluationState(bool post_evaluation);
protected:
bool GetEvaluationState() const { return (m_PostEvaluationState); }
private:
static bool m_PostEvaluationState;
};
class RegionGenerator { PURE_RegionGenerator; virtual ~RegionGenerator() {}; };
enum DistanceQualifier
{
NEAREST,
FARTHEST
};
enum FromWho
{
FROM_SELF,
FROM_TARGET,
FROM_NEAREST_ENEMY,
FROM_ALL_ENEMIES,
INVALID
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Evaluate(): the pluggable evaluation function
//
Stuff::Point3D Evaluate(TacticInterface& iface,
const RegionGenerator& search_region_generator,
const PointEvaluator& evaluator,
Stuff::Scalar minimum_distance = 0);
Fuzzy EvaluatePoint(TacticInterface& iface,
const Stuff::Point3D& point,
const PointEvaluator& evaluator,
const enemies_list* enemies = 0);
Fuzzy GetWaterValue(const Stuff::Point3D& point);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Evaluators
//
class Evaluator_DistanceFrom
: public PointEvaluator
{
DERIVED_PointEvaluator;
public:
Evaluator_DistanceFrom(FromWho who,
Stuff::Scalar min,
Stuff::Scalar max,
DistanceQualifier want_nearest);
protected:
const Stuff::Scalar m_Min;
const Stuff::Scalar m_Max;
const DistanceQualifier m_WantNearest;
const FromWho m_Who;
};
class Evaluator_Random
: public PointEvaluator
{
DERIVED_PointEvaluator;
};
class Evaluator_WeightedAverage
: public PointEvaluator
{
DERIVED_PointEvaluator;
public:
Evaluator_WeightedAverage(Stuff::Scalar weight1, PointEvaluator& evaluator1,
Stuff::Scalar weight2, PointEvaluator& evaluator2);
Evaluator_WeightedAverage(Stuff::Scalar weight1, PointEvaluator& evaluator1,
Stuff::Scalar weight2, PointEvaluator& evaluator2,
Stuff::Scalar weight3, PointEvaluator& evaluator3);
protected:
std::vector<Stuff::Scalar> m_Weights;
std::vector<PointEvaluator*> m_Evaluators;
};
class Evaluator_InFrontOf
: public PointEvaluator
{
DERIVED_PointEvaluator;
public:
Evaluator_InFrontOf(FromWho who,
bool in_front,
bool use_torso = false);
private:
const FromWho m_Who;
const bool m_InFront;
const bool m_UseTorso;
};
class Evaluator_45DegreesInFront
: public PointEvaluator
{
DERIVED_PointEvaluator;
public:
Evaluator_45DegreesInFront(bool random);
private:
const bool m_Random;
};
class Evaluator_ToSideOf
: public PointEvaluator
{
DERIVED_PointEvaluator;
public:
Evaluator_ToSideOf(FromWho who,
bool to_side);
private:
const FromWho m_Who;
const bool m_ToSide;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Generators
//
class Generator_EscapeRegion
: public RegionGenerator
{
DERIVED_RegionGenerator;
};
class Generator_Circle
: public RegionGenerator
{
DERIVED_RegionGenerator;
public:
Generator_Circle(FromWho who,
Stuff::Scalar magnitude,
Stuff::Scalar points_on_circumference = 12.0f,
Stuff::Scalar shrink_rate = 0.8f);
Generator_Circle(const Stuff::Point3D& origin,
Stuff::Scalar magnitude,
Stuff::Scalar points_on_circumference = 12.0f,
Stuff::Scalar shrink_Rate = 0.8f);
private:
const FromWho m_Who;
const Stuff::Point3D m_Origin;
const Stuff::Scalar m_Magnitude;
const Stuff::Scalar m_Points;
const Stuff::Scalar m_ShrinkRate;
};
class Generator_InFrontOf
: public RegionGenerator
{
DERIVED_RegionGenerator;
public:
Generator_InFrontOf(FromWho who,
Stuff::Scalar length,
Stuff::Scalar random_skew = 0);
private:
const FromWho m_Who;
const Stuff::Scalar m_Length;
const Stuff::Scalar m_RandomSkew;
};
};
};
#undef INTERFACE_PointEvaluator
#undef PURE_PointEvaluator
#undef DERIVED_PointEvaluator
#undef INTERFACE_RegionGenerator
#undef PURE_RegionGenerator
#undef DERIVED_RegionGenerator
#endif // AI_SITUATIONAL_ANALYSIS_HPP
+354
View File
@@ -0,0 +1,354 @@
#include "MW4Headers.hpp"
#include "AI_Specials.hpp"
#include "aiutils.hpp"
#include <Adept\Resource.hpp>
#include "MWPlayer.hpp"
#include "VehicleInterface.hpp"
#include <gosfx\gosfx.hpp>
#include <Adept\Effect.hpp>
#include <Adept\Map.hpp>
using namespace MW4AI;
const Stuff::Scalar max_delay_between_fireworks = 2.5f;
const Stuff::Scalar max_fireworks_origin_skew = 40.0f;
Specials* Specials::m_Instance = 0;
Specials::Specials()
: m_RefCount(0)
, m_Resource("ai\\ai.specials")
, m_FireworksStopTime(0)
, m_NextFireworkStartTime(0)
, m_LaunchConfetti(false)
, m_ConfettiLaunched(false)
{
/*
Verify(m_Resource.DoesResourceExist());
m_Resource.Rewind();
m_NotationFile.Assimilate(new Stuff::NotationFile(&m_Resource));
m_FlareResource.Assimilate(new Adept::Resource(GetResourceName("Signal Flare","signal_flare").c_str()));
m_ConfettiResource.Assimilate(new Adept::Resource(GetResourceName("confetti","confetti").c_str()));
{
std::vector<std::string> resource_names;
GetResourceName_Multiple("Fireworks","firework",resource_names);
{for (std::vector<std::string>::const_iterator i = resource_names.begin();
i != resource_names.end();
++i)
{
Stuff::Auto_Ptr<Adept::Resource> temp(new Adept::Resource((*i).c_str()));
m_FireworksResource.push_back(temp);
}}
}
{
std::vector<std::string> resource_names;
GetResourceName_Multiple("Fighter Smoke","smoke",resource_names);
{for (std::vector<std::string>::const_iterator i = resource_names.begin();
i != resource_names.end();
++i)
{
Stuff::Auto_Ptr<Adept::Resource> temp(new Adept::Resource((*i).c_str()));
m_FighterSmoke.push_back(temp);
}}
}
*/
}
Specials::~Specials()
{
}
void Specials::IncrementRefCount()
{
if (m_Instance == 0)
{
m_Instance = new MW4AI::Specials();
}
++m_Instance->m_RefCount;
}
void Specials::DecrementRefCount()
{
Verify(m_Instance != 0);
Verify(m_Instance->m_RefCount > 0);
--(m_Instance->m_RefCount);
if (m_Instance->m_RefCount == 0)
{
delete m_Instance;
m_Instance = 0;
}
}
Specials* Specials::Instance()
{
return (m_Instance);
}
std::string Specials::GetResourceName(const std::string& block_name, const std::string& item_name)
{
Verify(m_NotationFile.GetPointer() != 0);
Stuff::Page* page = m_NotationFile->FindPage(block_name.c_str());
if (page == 0)
{
Verify(!"Item not found. Make sure you have the latest CONTENT\\AI\\AI.SPECIALS file.");
return ("");
}
Stuff::Note* note = page->FindNote(item_name.c_str());
if (note == 0)
{
Verify(!"Item not found.");
return ("");
}
const char* rv;
note->GetEntry(&rv);
return (rv);
}
void Specials::GetResourceName_Multiple(const std::string& block_name, const std::string& item_name, std::vector<std::string>& resource_names)
{
Verify(m_NotationFile.GetPointer() != 0);
Stuff::Page* page = m_NotationFile->FindPage(block_name.c_str());
if (page == 0)
{
Verify(!"Item not found. Make sure you have the latest CONTENT\\AI\\AI.SPECIALS file.");
return;
}
Stuff::Note* note_total = page->FindNote("total");
if (note_total == 0)
{
return;
}
int total;
note_total->GetEntry(&total);
Verify(total >= 0);
{for (int i = 0;
i < total;
++i)
{
std::string modified_item_name(item_name);
modified_item_name += IntToString(i);
Stuff::Note* note = page->FindNote(modified_item_name.c_str());
if (note == 0)
{
Verify(!"Item not found.");
}
else
{
const char* resource_name;
note->GetEntry(&resource_name);
resource_names.push_back(resource_name);
}
}}
}
MWObject* Specials::GetPlayerVehicle()
{
if (Adept::Player::GetInstance() == 0)
{
return (0);
}
MechWarrior4::MWPlayer* p = Cast_Object(MechWarrior4::MWPlayer*,Adept::Player::GetInstance());
if ((p == 0) ||
(p->GetInterface() == 0))
{
return (0);
}
return (p->GetInterface()->vehicle);
}
int Specials::GetNumFireworkTypes() const
{
return (m_FireworksResource.size());
}
void Specials::LaunchSignalFlare(const Stuff::Point3D& pos)
{
// m_QueuedSignalFlares.push_back(pos);
}
void Specials::LaunchFirework(unsigned int type, const Stuff::Point3D& pos)
{
/*
if (type > m_FireworksResource.size())
{
return;
}
Adept::Resource* resource = m_FireworksResource[type];
if ((GetPlayerVehicle() == 0) ||
(resource == 0) ||
(resource->GetResourceID() == ResourceID::Null))
{
return;
}
GetPlayerVehicle()->CreateEffect(resource->GetResourceID(),pos);
*/
}
void Specials::LaunchFireworks(const Stuff::Point3D& pos, int duration)
{
/*
m_FireworksStopTime = (Stuff::Time)gos_GetElapsedTime() + (Stuff::Time)duration;
m_NextFireworkStartTime = (Stuff::Time)gos_GetElapsedTime() + GetTimeToNextFirework();
m_FireworksOrigin = pos;
*/
}
void Specials::LaunchConfetti()
{
if (m_ConfettiLaunched == false)
{
m_LaunchConfetti = true;
}
}
void Specials::Update()
{
/*
if (GetPlayerVehicle() != 0)
{
if ((m_FlareResource.GetPointer() != 0) &&
(m_FlareResource->GetResourceID() != ResourceID::Null))
{
while (m_QueuedSignalFlares.size() > 0)
{
GetPlayerVehicle()->CreateEffect(m_FlareResource->GetResourceID(),*(m_QueuedSignalFlares.begin()));
m_QueuedSignalFlares.erase(m_QueuedSignalFlares.begin());
}
}
if (m_LaunchConfetti == true)
{
if ((m_ConfettiResource.GetPointer() != 0) &&
(m_ConfettiResource->GetResourceID() != ResourceID::Null))
{
MechWarrior4::MWPlayer* p = Cast_Object(MechWarrior4::MWPlayer*,Adept::Player::GetInstance());
if ((p != 0) &&
(p->GetInterface() != 0))
{
p->GetInterface()->CreateWeatherEffect(m_ConfettiResource->GetResourceID());
}
}
m_LaunchConfetti = false;
m_ConfettiLaunched = true;
}
}
if (gos_GetElapsedTime() < m_FireworksStopTime)
{
int iters = 0;
while (m_NextFireworkStartTime < gos_GetElapsedTime())
{
LaunchRandomFirework();
m_NextFireworkStartTime += GetTimeToNextFirework();
++iters;
if (iters > 4)
{
return;
}
}
}
*/
}
Stuff::Time Specials::GetTimeToNextFirework() const
{
return (Stuff::Random::GetFraction() * max_delay_between_fireworks);
}
void Specials::LaunchRandomFirework()
{
/*
Stuff::Point3D pos(m_FireworksOrigin);
OffsetTargetPoint(pos,max_fireworks_origin_skew);
LaunchFirework(gos_rand() % m_FireworksResource.size(),pos);
*/
}
void Specials::LaunchFighterSmoke(MechWarrior4::MWObject& mwobject, int smoke_index)
{
/*
Check_Pointer(this);
AttachSmoke(mwobject,smoke_index,Stuff::Point3D(-11,0,0));
AttachSmoke(mwobject,smoke_index,Stuff::Point3D(11,0,0));
*/
}
void Specials::AttachSmoke(MechWarrior4::MWObject& mwobject, int smoke_index, const Stuff::Point3D& offset)
{
if ((smoke_index > m_FighterSmoke.size()) ||
(m_FighterSmoke[smoke_index]->DoesResourceExist() == false))
{
return;
}
MechWarrior4::MWObject::ClassID class_ID;
class_ID = Adept::Entity::GetClassIDFromDataListID(m_FighterSmoke[smoke_index]->GetResourceID());
Verify(class_ID != NullClassID);
LinearMatrix4D initial_position = LinearMatrix4D::Identity;
initial_position.Multiply(gosFX::Effect_Against_Motion, mwobject.GetElement()->GetNewLocalToParent());
Adept::Effect::CreateMessage effect_create_message(
sizeof(Effect::CreateMessage),
DefaultEventPriority,
MechWarrior4::MWObject::CreateMessage::DefaultFlags,
class_ID,
Effect::DefaultFlags|Effect::LoopFlag,
m_FighterSmoke[smoke_index]->GetResourceID(),
initial_position,
0.0f,
MechWarrior4::MWObject::ExecutionStateEngine::AlwaysExecuteState,
NameTable::NullObjectID,
Entity::DefaultAlignment
);
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
Entity *entity;
ReplicatorID trail_id = Connection::Hermit->GetNextReplicatorID();
entity = mwobject.CreateEntity(&stream, &trail_id, false);
Check_Object(entity);
Check_Object(Adept::Map::GetInstance());
Adept::Map::GetInstance()->AddChild(entity);
Effect* effect = Cast_Object(Effect*,entity);
effect->SetFollowEntity(&mwobject);
effect->effectOffset.BuildTranslation(offset);
effect->executionState->RequestState(Effect::ExecutionStateEngine::RunningState);
effect->SyncMatrices(true);
}
@@ -0,0 +1,86 @@
#pragma once
#ifndef AI_SPECIALS_HPP
#define AI_SPECIALS_HPP
#include <Stuff\Auto_Container.hpp>
#pragma warning(push)
#include <stlport\string>
#include <stlport\vector>
#pragma warning(pop)
#include <Adept\Resource.hpp>
#include <Stuff\NotationFile.hpp>
#include <Stuff\Point3D.hpp>
namespace Stuff
{
class Point3D;
};
namespace MechWarrior4
{
class MWObject;
};
namespace MW4AI
{
class Specials
{
public:
Specials();
~Specials();
static void IncrementRefCount();
static void DecrementRefCount();
static Specials* Instance();
void LaunchSignalFlare(const Stuff::Point3D& pos);
void LaunchFireworks(const Stuff::Point3D& pos, int duration);
void LaunchConfetti();
void LaunchFighterSmoke(MechWarrior4::MWObject& mwobject, int smoke_index);
int GetNumFireworkTypes() const;
void Update();
private:
std::string GetResourceName(const std::string& block_name, const std::string& item_name);
void GetResourceName_Multiple(const std::string& block_name, const std::string& item_name, std::vector<std::string>& resource_names);
MWObject* GetPlayerVehicle();
void LaunchFirework(unsigned int type, const Stuff::Point3D& pos);
Stuff::Time GetTimeToNextFirework() const;
void LaunchRandomFirework();
void AttachSmoke(MechWarrior4::MWObject& mwobject, int smoke_index, const Stuff::Point3D& offset);
private:
int m_RefCount;
static Specials* m_Instance;
Adept::Resource m_Resource;
Stuff::Auto_Ptr<Stuff::NotationFile> m_NotationFile;
Stuff::Auto_Ptr<Adept::Resource> m_FlareResource;
Stuff::Auto_Container<Adept::Resource, std::vector<Adept::Resource*> > m_FireworksResource;
Stuff::Auto_Ptr<Adept::Resource> m_ConfettiResource;
Stuff::Auto_Container<Adept::Resource, std::vector<Adept::Resource*> > m_FighterSmoke;
Stuff::Time m_FireworksStopTime;
Stuff::Time m_NextFireworkStartTime;
Stuff::Point3D m_FireworksOrigin;
bool m_LaunchConfetti;
bool m_ConfettiLaunched;
std::vector<Stuff::Point3D> m_QueuedSignalFlares;
};
};
#endif // AI_SPECIALS_HPP
+73
View File
@@ -0,0 +1,73 @@
#include "MW4Headers.hpp"
#include "AI_Squad.hpp"
#include "AI_Lancemate.hpp"
#include "AI_MoodSquad.hpp"
#include "AI_FocusFireSquad.hpp"
#include "Group.hpp"
#include "aiutils.hpp"
#include "CombatAI.hpp"
Stuff::Auto_Ptr<MW4AI::Squad::AI> MW4AI::Squad::CreateAI(MW4AI::Squad::ID id)
{
Verify(id > GROUPAI_FIRST);
Verify(id < GROUPAI_LAST);
MW4AI::Squad::AI* ai = 0;
switch (id)
{
case GROUPAI_NONE:
{
break;
}
case GROUPAI_LANCEMATE:
{
ai = new Lancemate;
break;
}
case GROUPAI_RADIOSQUAD:
{
ai = new RadioSquad;
break;
}
case GROUPAI_MOODSQUAD:
{
ai = new MoodSquad;
break;
}
case GROUPAI_FOCUSFIRESQUAD:
{
ai = new FocusFireSquad;
break;
}
default:
{
Verify(!"GroupAI ID not found.");
break;
}
}
Stuff::Auto_Ptr<MW4AI::Squad::AI> rv(ai);
return (rv);
}
Adept::Entity* MW4AI::Squad::AI::GetLeader(const MechWarrior4::Group& group) const
{
return (group.IDToEntity(*(group.GetElements().begin())));
}
int MW4AI::Squad::AI::GetIndex(const MechWarrior4::CombatAI& combat_ai, const MechWarrior4::Group& group) const
{
Verify(group.GetElements().size() > 0);
return (index_of(group.GetElements().begin(),group.GetElements().end(),combat_ai.GetSelf().objectID));
}
+82
View File
@@ -0,0 +1,82 @@
#pragma once
#ifndef AI_SQUAD_HPP
#define AI_SQUAD_HPP
#include <Stuff\Auto_Ptr.hpp>
#include <Adept\Entity.hpp>
#include <Adept\NameTable.hpp>
namespace MechWarrior4
{
class CombatAI;
class MWObject;
class Group;
};
#define INTERFACE_SquadAI(post) \
public: \
virtual void Update(MechWarrior4::Group& group, \
MechWarrior4::CombatAI& combat_ai) ##post \
virtual void NotifyShot(MechWarrior4::Group& group, \
Adept::ObjectID id) ##post \
virtual void NotifyShotFired(MechWarrior4::Group& group, \
const Stuff::Line3D& line, \
MechWarrior4::MWObject& at_who, \
MechWarrior4::MWObject& shooter) ##post \
virtual void NotifyMemberAdded(MechWarrior4::Group& group, \
MechWarrior4::MWObject& who) ##post \
virtual void SetEntityToIgnore(Adept::ObjectID objectid) ##post \
virtual void NotifyMemberRemoved(MechWarrior4::Group& group, \
MechWarrior4::MWObject& who) ##post
#define PURE_SquadAI INTERFACE_SquadAI(=0;)
#define DERIVED_SquadAI INTERFACE_SquadAI(;)
namespace MW4AI
{
namespace Squad
{
enum ID // NOTE: these constants must exactly match those in MWCONST.ABI
{
GROUPAI_FIRST = 3999,
GROUPAI_NONE = 4000,
GROUPAI_LANCEMATE = 4001,
GROUPAI_RADIOSQUAD = 4002,
GROUPAI_MOODSQUAD = 4003,
GROUPAI_FOCUSFIRESQUAD = 4004,
GROUPAI_LAST = 4005
};
class AI
{
PURE_SquadAI;
public:
virtual ~AI() {};
virtual bool IgnoresFriendlyFire() const { return (false); }
virtual ID GetID() const = 0;
virtual void NotifyMechDestroyed(MechWarrior4::Group& group,
const Adept::ReplicatorID& inflicting_id,
const Adept::ReplicatorID& victim_id)
{ };
protected:
Adept::Entity* GetLeader(const MechWarrior4::Group& group) const;
int GetIndex(const MechWarrior4::CombatAI& combat_ai, const MechWarrior4::Group& group) const;
};
Stuff::Auto_Ptr<AI> CreateAI(ID id);
};
};
#endif // AI_SQUAD_HPP
@@ -0,0 +1,15 @@
#include "MW4Headers.hpp"
#include "AI_SquadOrders.hpp"
using namespace MW4AI;
SquadOrders::~SquadOrders()
{
}
@@ -0,0 +1,42 @@
#pragma once
#ifndef AI_SQUADORDERS_HPP
#define AI_SQUADORDERS_HPP
#include <Stuff\Point3D.hpp>
#include <Stuff\Auto_Ptr.hpp>
#include "AI_LancemateCommands.hpp"
namespace MechWarrior4
{
class MWObject;
};
namespace MW4AI
{
class SquadOrders
{
public:
virtual ~SquadOrders();
virtual void Update() = 0;
virtual bool PointIsValid(const Stuff::Point3D& point) const = 0;
virtual void IssueCommand(Stuff::Auto_Ptr<LancemateCommands::LancemateCommand>& command) = 0;
virtual void NotifyShotFired() = 0;
virtual void NotifyFriendlyFire(Adept::Entity& who) {};
virtual bool CanExecuteCommands() const { return (true); }
virtual MWObject* GetAutoTarget() const { return (0); }
virtual bool GetExtendedSensorData(std::vector<MWObject*>& sensor_data_list) const { return (false); }
virtual Stuff::Scalar GetLeastSquaredSensorDistance(const Stuff::Point3D& point) const { return (0); }
virtual Stuff::Auto_Ptr<LancemateCommands::LancemateCommand> CreateCommand(LancemateCommands::ID command_id,Adept::Entity* pTarget2 = NULL) { return (0); }
virtual bool ShouldRunScript() const { return (true); }
virtual bool GetLeaderAlignment(int& alignment) { return (false); }
virtual void NotifyNoPath() { };
};
};
#endif // AI_SQUADORDERS_HPP
@@ -0,0 +1,199 @@
#include "MW4Headers.hpp"
#include "AI_Statistics.hpp"
#include <windows.h>
#include <buildnum\curver.h>
#include <gameos\registry.hpp>
#include <Adept\NameTable.hpp>
#include "data_client.hpp"
#include "aiutils.hpp"
#include "gameinfo.hpp"
#include <Adept\Application.hpp>
#include <Adept\DamageObject.hpp>
// NOTE: this has all been (permanently?) commented out since no
// one is using it. -- PAULTOZ
using namespace MW4AI;
using namespace MW4AI::Statistics;
namespace MW4AI
{
namespace Statistics
{
bool g_StatisticsEnabled = false;
};
};
void Statistics::Init()
{
#ifdef LAB_ONLY
gos_PushCurrentHeap(Heap);
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
SYSTEMTIME st;
FileTimeToSystemTime(&ft,&st);
std::string s;
s += IntToString(st.wMonth);
s += "/";
s += IntToString(st.wDay);
s += "/";
s += IntToString(st.wYear);
s += " ";
s += IntToString(st.wHour);
s += ":";
s += IntToString(st.wMinute);
char computer_name[200];
DWORD name_size = 200;
GetComputerName(computer_name,&name_size);
char user_name[200];
DWORD username_size = 200;
GetUserName((char*)&user_name,&username_size);
#if 0
if (!strcmp (user_name,"dabzug"))
g_AbzugFlag = true;
else
g_AbzugFlag = false;
if (s_NoAbzug)
g_AbzugFlag = false;
#endif
DataClient::Add_StartMission((float)gos_GetElapsedTime());
DataClient::Add_BuildVersion(CURRENT_BUILD_FULL_STRING);
DataClient::Add_CompileDate(__DATE__);
DataClient::Add_CompileTime(__TIME__);
DataClient::Add_UserName(user_name);
DataClient::Add_MachineName(computer_name);
DataClient::Add_DateTime(s.c_str());
DataClient::Add_MissionName(MWGameInfo::g_MissionName);
DataClient::Add_PlayerMech(MWGameInfo::g_PlayerMech);
DataClient::Add_NetworkingFlag(Application::GetInstance()->networkingFlag);
gos_PopCurrentHeap();
#endif
}
void Statistics::Quit()
{
#ifdef LAB_ONLY
DataClient::Add_EndMission((float)gos_GetElapsedTime());
#endif
}
std::string LookupName(int id)
{
if (NameTable::GetInstance() == 0)
{
return ("");
}
NameTableEntry* entry = NameTable::GetInstance()->FindEntry(id);
if (entry == 0)
{
return ("");
}
return (entry->objectName);
}
void Statistics::NotifyDamageTaken(int receiver_id, int sender_id, float damage, int damage_type)
{
#ifdef LAB_ONLY
std::string receiver_name(LookupName(receiver_id));
std::string sender_name(LookupName(sender_id));
std::string damage_type_name;
switch (damage_type)
{
case Adept::BeamDamageType:
{
damage_type_name = "Beam Damage";
break;
}
case Adept::MissileDamageType:
{
damage_type_name = "Missile Damage";
break;
}
case Adept::ProjectileDamageType:
{
damage_type_name = "Projectile Damage";
break;
}
case Adept::SplashDamageType:
{
damage_type_name = "Splash Damage";
break;
}
case Adept::HeatDamageType:
{
damage_type_name = "Heat Damage";
break;
}
// MSL 5.03 Lava
case Adept::LavaDamageType:
{
damage_type_name = "Lava Damage";
break;
}
case Adept::AmmoFireDamageType:
{
damage_type_name = "Ammo Fire Damage";
break;
}
}
DataClient::Add_Damage(receiver_id,receiver_name.c_str(),sender_id,sender_name.c_str(),damage,damage_type_name.c_str(),(float)gos_GetElapsedTime());
#endif
}
void Statistics::NotifyDestroyed(int destroyed_id)
{
#ifdef LAB_ONLY
std::string destroyed_name(LookupName(destroyed_id));
DataClient::Add_Destroyed(destroyed_id,destroyed_name.c_str(),(float)gos_GetElapsedTime());
#endif
}
void Statistics::NotifyObjective(char* objective_name, bool succeeded)
{
#ifdef LAB_ONLY
DataClient::Add_Objective(objective_name,succeeded,(float)gos_GetElapsedTime());
#endif
}
void Statistics::NotifyToHitRoll(int shooter_id, float base_to_hit, float modified_to_hit, float rolled)
{
#ifdef LAB_ONLY
std::string shooter_name(LookupName(shooter_id));
DataClient::Add_ToHitRoll(shooter_name.c_str(),shooter_id,base_to_hit,modified_to_hit,rolled,(float)gos_GetElapsedTime());
#endif
}
bool Statistics::Enabled()
{
//#ifdef LAB_ONLY
return (g_StatisticsEnabled);
//#endif
}
void Statistics::SetEnabled(bool enabled)
{
#ifdef LAB_ONLY
g_StatisticsEnabled = enabled;
#endif
}
@@ -0,0 +1,29 @@
#pragma once
#ifndef AI_STATISTICS_HPP
#define AI_STATISTICS_HPP
#include <Stuff\Scalar.hpp>
namespace MW4AI
{
namespace Statistics
{
void Init();
void Quit();
bool Enabled();
void SetEnabled(bool enabled);
void NotifyDamageTaken(int receiver_id, int sender_id, float damage, int damage_type);
void NotifyDestroyed(int destroyed_id);
void NotifyObjective(char* objective_name, bool succeeded);
void NotifyToHitRoll(int shooter_id, float base_to_hit, float modified_to_hit, float rolled);
};
};
#endif // AI_STATISTICS_HPP
@@ -0,0 +1,132 @@
#pragma once
#ifndef AI_TACTICINTERFACE_HPP
#define AI_TACTICINTERFACE_HPP
#include <Stuff\Scalar.hpp>
#include <Stuff\Point3D.hpp>
#include "AI_FireStyle.hpp"
#include "AI_Moods.hpp"
#include "AI_FireData.hpp"
namespace MechWarrior4
{
class MWObject;
};
#define INTERFACE_TacticInterface(post) \
public: \
virtual void MoveTo(const Point3D& point, bool move_forward = true, bool throttle_override = false, MWObject* ram_target = 0) ##post \
virtual bool PointIsValid(const Point3D& point, bool ignore_mission_bounds = false, bool ignore_squads = false) const ##post \
virtual bool HasPath() const ##post \
virtual bool Moving() const ##post \
virtual void Stop() ##post \
virtual void ClearMoveOrder() ##post \
virtual Stuff::Point3D GetAimPoint() const ##post \
virtual void TrackTo(const Stuff::Point3D& point) ##post \
virtual void TurnTo(const Stuff::Point3D& point, bool must_be_torso_twisted = true) ##post \
virtual void PitchTo(const Stuff::Point3D& point) ##post \
virtual Stuff::Scalar WeaponRange(WR_WHO who, WR_QUALIFIER qualifier) const ##post \
virtual void Fire(FireStyles::FireStyleID style = FireStyles::FIRE_MAXIMUM) ##post \
virtual MechWarrior4::MWObject& GetSelf() const ##post \
virtual MechWarrior4::Vehicle* GetSelf_AsVehicle() const ##post \
virtual MechWarrior4::MWObject& GetTarget() const ##post \
virtual MechWarrior4::Vehicle* GetTarget_AsVehicle() const ##post \
virtual MechWarrior4::MWObject* GetNearest(bool fMustBeEnemy = false) ##post \
virtual Stuff::Scalar GetDistanceFromTargetSquared() const ##post \
virtual Stuff::Scalar GetDistanceFromDestinationSquared() const ##post \
virtual Moods::ID GetMood() const ##post \
virtual bool ProjectileApproaching(Stuff::Scalar interval = 4.0f) ##post \
virtual const Stuff::Point3D& GetProjectileOrigin() ##post \
virtual void Stand() ##post \
virtual void Crouch() ##post \
virtual bool Crouching() const ##post \
virtual FireData::HIT_RESULT GetLastHitResult() const ##post \
virtual void ThrottleOverride(Stuff::Scalar duration, bool force = false) ##post \
virtual bool GetLastMoveDest(Stuff::Point3D& dest, bool ignore_movement = false) const ##post \
virtual bool ShotWithin(Stuff::Scalar lastvalid) const ##post \
virtual bool FiredWithin(Stuff::Scalar lastvalid) const ##post \
virtual void Jump(Stuff::Scalar duration) ##post \
virtual void Jump() ##post \
virtual void StopJumping() ##post \
virtual bool GetUnableToFireDuration(Stuff::Scalar duration) const ##post \
virtual bool ShouldForceDestinationRecalc() const ##post \
virtual int GetEliteLevel() const ##post \
virtual Stuff::Scalar GetTimeTargetedByEnemy() const ##post \
virtual Stuff::Scalar GetAttackThrottle() const ##post \
virtual void ForceDestinationRecalc() ##post \
virtual Stuff::Point3D GetMoveDest() const ##post \
virtual Stuff::Scalar GetLastTimeRammedTarget() const ##post \
virtual Stuff::Scalar GetLastTimeJumped() const ##post \
virtual Stuff::LinearMatrix4D GetAttackOrderPosition() const ##post \
virtual Stuff::LinearMatrix4D GetLastMoveOrderPosition() const ##post \
virtual bool GetEscapeRegionFocusIfAvailable(Stuff::Point3D& focus) const ##post \
virtual void SurrenderPose() ##post \
virtual void SetSpeed(Stuff::Scalar speed) ##post \
virtual bool SuicideIsOK() const ##post \
virtual unsigned int NumLegsDestroyed() const ##post \
virtual Stuff::Scalar GetMovementScore() const ##post \
virtual void SetMovementScore(Stuff::Scalar score) ##post \
virtual bool PointIsInBadNeighborhood(const Stuff::Point3D& point) const ##post \
virtual bool ShouldRun() const ##post \
virtual Stuff::Scalar GetCombatRadiusForRange(Stuff::Scalar percentile_range) ##post \
virtual Stuff::Scalar GetNormalizedJumpJetFuel() ##post \
virtual bool CanRetreat() const ##post \
virtual Stuff::Scalar GetCurrentVulnerableComponent() ##post \
virtual bool CanJump() const ##post \
virtual bool CanCrouch() const ##post \
virtual void FloatToPoint(const Stuff::Point3D& point) ##post \
virtual bool IsShootOnlyAI() const ##post \
virtual void SetFallDampingEnabled(bool enabled) ##post \
virtual Adept::ObjectID GetObjectID() const ##post \
virtual Stuff::Scalar GetMaxFireCheatAngle() const ##post \
virtual bool LineMightHitFriendlyUnits(const Stuff::Line3D& line) const ##post \
virtual bool MovedWithin(Stuff::Scalar duration) const ##post \
virtual void ContinuousFlyBy(const Stuff::Point3D& loc) ##post \
virtual bool RecentPathsFailed() const ##post \
virtual bool CanMove() const ##post \
virtual bool MoveRequestPending() const ##post \
virtual bool CanTrack() const ##post \
virtual bool CanTurn() const ##post \
virtual Stuff::Scalar DamageTakenSinceAttackOrder() const ##post \
virtual Stuff::Point3D GetLeashCenter() const ##post \
virtual Stuff::Scalar GetLeashRadius() const ##post
#define PURE_TacticInterface INTERFACE_TacticInterface(=0;)
#define DERIVED_TacticInterface INTERFACE_TacticInterface(;)
namespace MechWarrior4
{
class Vehicle;
};
namespace MW4AI
{
class TacticInterface
{
protected:
TacticInterface() {};
virtual ~TacticInterface() {};
public:
enum WR_WHO
{
SELF,
TARGET
};
enum WR_QUALIFIER
{
MIN,
MAX
};
PURE_TacticInterface;
};
};
#endif // AI_TACTICINTERFACE_HPP
+689
View File
@@ -0,0 +1,689 @@
#include "MW4Headers.hpp"
#include "AI_Tactics.hpp"
#include "Helicopter.hpp"
#include "Mech.hpp"
#include "AI_TacticInterface.hpp"
#include "LRMWeaponSubsystem.hpp"
#include "MRMWeaponSubsystem.hpp"
#include "AI_Condition.hpp"
#include "Building.hpp"
#include "SubsystemClassData.hpp"
using namespace Stuff;
using namespace MW4AI;
using namespace MW4AI::Tactics;
using namespace MechWarrior4;
#pragma warning(disable:4239)
const Stuff::Time satisfaction_delta_per_second = 0.08f;
const Stuff::Scalar min_satisfaction_threshold = 0.1f;
const Stuff::Time duration_to_ignore_tactic_satisfaction = 8.0f; // we initially ignore whether or not the tactic is working for this many seconds
const Stuff::Scalar min_tactic_duration = 30.0f; // minimum duration of any tactic, in seconds
const Stuff::Scalar max_tactic_duration = 120.0f; // maximum duration of any tactic, in seconds
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Tactics::Registrar* Registrar::instance = 0;
void Tactics::Registrar::IncrementRefCount(TacticInterface& i)
{
if (instance == 0)
{
gos_PushCurrentHeap(MechWarrior4::Heap);
instance = new Registrar(i);
gos_PopCurrentHeap();
}
else
{
Verify(instance->m_RefCount > 0);
}
++(instance->m_RefCount);
}
void Tactics::Registrar::DecrementRefCount()
{
Verify(instance != 0);
Verify(instance->m_RefCount > 0);
--(instance->m_RefCount);
if (instance->m_RefCount == 0)
{
delete instance;
instance = 0;
}
}
Tactics::Registrar& Registrar::GetInstance()
{
Verify(instance != 0);
Verify(instance->m_RefCount > 0);
return (*instance);
}
Registrar::Registrar(TacticInterface& iface)
: m_RefCount(0)
{
#define ADD(tactic) \
{ Auto_Ptr<Tactic> t(new tactic); \
m_Tactics.push_back(t); }
ADD(Circle);
ADD(Strafe);
ADD(CircleHover);
ADD(StandGround);
ADD(StopAndFire);
ADD(Ram);
ADD(Joust);
ADD(Rush);
ADD(HitAndRun);
ADD(Front);
ADD(Rear);
ADD(Retreat);
ADD(BackUpAndFire);
ADD(JumpAndShoot);
ADD(Snipe);
ADD(ShootOnly);
ADD(Defend);
ADD(LocalPatrol);
ADD(Surrender);
ADD(Ambush);
ADD(DeathFromAbove);
ADD(HeliPopup);
ADD(DiveBomb);
ADD(FastCircle);
ADD(Stare);
#undef ADD
}
Tactics::TacticID Registrar::SelectTactic(TacticInterface& iface, const std::vector<TacticID>& most_recent_tactics) const
{
// MSL 5.05
if (iface.GetSelf().IsDerivedFrom(Building::DefaultData) == true)
{
return (TACTIC_SHOOT_ONLY);
}
if ((iface.GetSelf().IsDerivedFrom(Vehicle::DefaultData) == false) ||
(iface.IsShootOnlyAI() == true))
{
return (TACTIC_SHOOT_ONLY);
}
if (iface.GetSelf().IsDerivedFrom(Helicopter::DefaultData) == true)
{
return (TACTIC_CIRCLE_HOVER);
}
if (iface.GetSelf().IsDerivedFrom(Airplane::DefaultData) == true)
{
MechWarrior4::Airplane* plane = Cast_Object(MechWarrior4::Airplane*,&(iface.GetSelf()));
const MechWarrior4::Airplane::GameModel* game_model = plane->GetGameModel();
switch (game_model->m_attackType)
{
default:
{
Verify(!"Error: no airplane attack type specified.");
return (TACTIC_DIVE_BOMB);
}
case MechWarrior4::Vehicle::NightShadeAttackType:
{
return (TACTIC_DIVE_BOMB);
}
case MechWarrior4::Vehicle::ShiloneAttackType:
{
return (TACTIC_STRAFE);
}
}
}
if (iface.GetSelf().IsDerivedFrom(Mech::DefaultData) == false)
{
if (iface.GetMood() <= 2)
{
return (TACTIC_RETREAT);
}
return (TACTIC_SNIPE);
}
std::vector<Tactic*> tactics;
{for (tactic_container::const_iterator i = m_Tactics.begin();
i != m_Tactics.end();
++i)
{
if (((*i)->CanBeSelectedAutomatically(iface) == true) &&
(std::find(most_recent_tactics.begin(),most_recent_tactics.end(),(*i)->GetID()) == most_recent_tactics.end()))
{
tactics.push_back(*i);
}
}}
if (tactics.size() == 0)
{
{for (tactic_container::const_iterator i = m_Tactics.begin();
i != m_Tactics.end();
++i)
{
if ((*i)->CanBeSelectedAutomatically(iface) == true)
{
if (((*i)->GetID() != TACTIC_RETREAT) ||
(iface.CanRetreat() == true))
{
tactics.push_back(*i);
}
}
}}
if (tactics.size() == 0)
{
return (TACTIC_CIRCLE_OF_DEATH);
}
}
if (tactics.size() == 1)
{
return ((*(tactics.begin()))->GetID());
}
while (tactics.size() > 2)
{
std::vector<Tactic*>::iterator worst = tactics.end();
Stuff::Scalar worst_score = 100;
{for (std::vector<Tactic*>::iterator i = tactics.begin();
i != tactics.end();
++i)
{
const Stuff::Scalar score((*i)->Evaluate(iface));
if (score <= worst_score)
{
worst_score = score;
worst = i;
}
}}
tactics.erase(worst);
}
return (tactics[Stuff::Random::GetInt() & 0x01]->GetID());
}
Tactic& Registrar::GetTactic(TacticID id) const
{
{for (tactic_container::const_iterator i = m_Tactics.begin();
i != m_Tactics.end();
++i)
{
if ((*i)->GetID() == id)
{
return (**i);
}
}}
Verify(!"Should never get here!");
return (**(m_Tactics.begin()));
}
Auto_Ptr<MW4AI::Tactics::Tactic> MW4AI::Tactics::CreateTactic(TacticInterface& i, TacticID id)
{
Tactic* t = 0;
switch (id)
{
case TACTIC_STOP_AND_FIRE: { t = new StopAndFire(); break; }
case TACTIC_RAM: { t = new Ram(); break; }
case TACTIC_JOUST: { t = new Joust(); break; }
case TACTIC_RUSH: { t = new Rush(); break; }
case TACTIC_HIT_AND_RUN: { t = new HitAndRun(); break; }
case TACTIC_FRONT: { t = new Front(); break; }
case TACTIC_REAR: { t = new Rear(); break; }
case TACTIC_CIRCLE_OF_DEATH: { t = new Circle(); break; }
case TACTIC_RETREAT: { t = new Retreat(); break; }
case TACTIC_BACK_UP_AND_FIRE: { t = new BackUpAndFire(); break; }
case TACTIC_CIRCLE_HOVER: { t = new CircleHover(); break; }
case TACTIC_STRAFE: { t = new Strafe(); break; }
case TACTIC_STAND_GROUND: { t = new StandGround(); break; }
case TACTIC_JUMP_AND_SHOOT: { t = new JumpAndShoot(); break; }
case TACTIC_SNIPE: { t = new Snipe(); break; }
case TACTIC_SHOOT_ONLY: { t = new ShootOnly(); break; }
case TACTIC_DEFEND: { t = new Defend(); break; }
case TACTIC_LOCAL_PATROL: { t = new LocalPatrol(); break; }
case TACTIC_SURRENDER: { t = new Surrender(); break; }
case TACTIC_AMBUSH: { t = new Ambush(); break; }
case TACTIC_DEATH_FROM_ABOVE: { t = new DeathFromAbove(); break; }
case TACTIC_HELI_POPUP: { t = new HeliPopup(); break; }
case TACTIC_DIVE_BOMB: { t = new DiveBomb(); break; }
case TACTIC_FAST_CIRCLE: { t = new FastCircle(); break; }
case TACTIC_STARE: { t = new Stare(); break; }
default:
{
Verify("Tactic not found!" == 0);
}
}
if (t == 0)
{
return (0);
}
return (t);
}
Registrar::~Registrar()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// General tactics functions
//
void VerifyTactic(TacticID id)
{
Verify(id >= TACTIC_FIRST);
Verify(id <= TACTIC_LAST);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Tactic
//
void Tactic::SetExplicit(bool is_explicit)
{
m_Explicit = is_explicit;
}
bool Tactic::GetExplicit() const
{
return (m_Explicit);
}
bool Tactic::CanBeSelectedAutomatically(TacticInterface& iface) const
{
return (false);
}
Tactic::Tactic()
: m_CreationTime((Stuff::Scalar)gos_GetElapsedTime())
, m_CreationMood(-1)
, m_Satisfaction(1.0f)
, m_LastSatisfactionUpdate(0)
, m_TacticToIgnore((TacticID)0)
{
m_AutoEndTime = m_CreationTime + min_tactic_duration + ((max_tactic_duration - min_tactic_duration) * Stuff::Random::GetFraction());
m_CreationTime += Stuff::Random::GetFraction();
}
void Tactic::SetIgnoreExplicitTactic(TacticID tactic)
{
m_TacticToIgnore = tactic;
}
TacticID Tactic::GetIgnoreExplicitTactic() const
{
return (m_TacticToIgnore);
}
Tactic::~Tactic()
{
}
Stuff::Scalar Tactic::GetDuration() const
{
return ((Stuff::Scalar)gos_GetElapsedTime() - m_CreationTime);
}
void Tactic::Update(TacticInterface& i)
{
if (m_CreationMood == -1)
{
m_CreationMood = (Stuff::Scalar)i.GetMood();
}
}
bool Tactic::ShouldAbandon(TacticInterface& i) const
{
if (ShouldAbandonImmediately() == true)
{
m_Explicit = false;
return (true);
}
if ((m_Explicit == true) ||
(GetDuration() < UserConstants::Instance()->Get(UserConstants::min_tactic_time)) ||
(m_CreationMood == -1))
{
return (false);
}
if ((i.GetSelf().IsDerivedFrom(Building::DefaultData) == true) &&
(i.GetSelf().IsDerivedFrom(Airplane::DefaultData) == true))
{
return (false);
}
Stuff::Scalar mood_delta = Stuff::Fabs(m_CreationMood - i.GetMood());
if (mood_delta > 1)
{
return (true);
}
if (gos_GetElapsedTime() > m_AutoEndTime)
{
return (true);
}
return (IsIneffective());
}
bool Tactic::IsIneffective() const
{
if (m_Satisfaction <= min_satisfaction_threshold)
{
return (true);
}
return (false);
}
Stuff::Scalar Tactic::Evaluate(TacticInterface& iface) const
{
return (0);
}
void Tactic::UpdateSatisfaction()
{
if ((m_LastSatisfactionUpdate != 0) &&
(m_CreationTime + duration_to_ignore_tactic_satisfaction < gos_GetElapsedTime()))
{
const Stuff::Time time_delta = gos_GetElapsedTime() - m_LastSatisfactionUpdate;
if (IsHappy() == true)
{
m_Satisfaction += (Stuff::Scalar)(satisfaction_delta_per_second * time_delta);
if (m_Satisfaction > 1.0f)
{
m_Satisfaction = 1.0f;
}
}
else
{
m_Satisfaction -= (Stuff::Scalar)(satisfaction_delta_per_second * time_delta);
if (m_Satisfaction < 0.0f)
{
m_Satisfaction = 0.0f;
}
}
}
m_LastSatisfactionUpdate = gos_GetElapsedTime();
}
bool Tactic::Finished() const
{
if (ShouldAbandonImmediately() == true)
{
return (true);
}
if ((m_TacticToIgnore != (TacticID)0) &&
(GetID() != m_TacticToIgnore))
{
return (true);
}
return (false);
}
bool Tactic::ShouldIgnoreLOS() const
{
return (false);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Tactic
//
inline bool Qualifies(TacticInterface& iface,
UserConstants::ID min_elite, UserConstants::ID max_elite,
UserConstants::ID min_mood, UserConstants::ID max_mood)
{
if ((iface.GetEliteLevel() < UserConstants::Instance()->Get(min_elite)) ||
(iface.GetEliteLevel() > UserConstants::Instance()->Get(max_elite)))
{
return (false);
}
if ((iface.GetMood() < UserConstants::Instance()->Get(min_mood)) ||
(iface.GetMood() > UserConstants::Instance()->Get(max_mood)))
{
return (false);
}
return (true);
}
Stuff::Scalar Score_FasterThanTarget(TacticInterface& iface)
{
Vehicle* v1 = iface.GetSelf_AsVehicle();
Vehicle* v2 = iface.GetTarget_AsVehicle();
Stuff::Scalar my_speed(0);
if (v1 != 0)
{
my_speed = v1->GetGameModel()->maxSpeed;
}
Stuff::Scalar target_speed(0);
if (v2 != 0)
{
target_speed = v2->GetGameModel()->maxSpeed;
}
if (my_speed > target_speed)
{
return (1);
}
return (0);
}
Stuff::Scalar Score_HaveMissiles(TacticInterface& iface)
{
Stuff::ChainIteratorOf<MechWarrior4::Weapon*> i(&(iface.GetSelf().weaponChain));
MechWarrior4::Weapon* weapon = 0;
while ((weapon = i.ReadAndNext()) != 0)
{
if (weapon->GetAmmoCount() > 0) // TODO: comment this back in when ammo # works correctly ...
{
if ((weapon->IsDerivedFrom(LRMWeaponSubsystem::DefaultData) == true) ||
(weapon->IsDerivedFrom(MRMWeaponSubsystem::DefaultData) == true))
{
return (1);
}
}
}
return (0);
}
Stuff::Scalar Score_TargetFacingAway(TacticInterface& iface)
{
if (Conditions::InFrontOfTarget(iface,true) < 0.5f)
{
return (1);
}
return (0);
}
Stuff::Scalar Score_FarFromTarget(TacticInterface& iface)
{
if (GetApproximateLength((Stuff::Point3D)iface.GetSelf().GetLocalToWorld(),
(Stuff::Point3D)iface.GetTarget().GetLocalToWorld()) > 250)
{
return (1);
}
return (0);
}
Stuff::Scalar Score_Gimped(TacticInterface& iface)
{
if (iface.NumLegsDestroyed() == 1)
{
return (1);
}
return (0);
}
Stuff::Scalar Score_WantsToUseVCH(TacticInterface& iface)
{
if (iface.GetCurrentVulnerableComponent() != 0)
{
return (1);
}
return (0);
}
bool Joust::CanBeSelectedAutomatically(TacticInterface& iface) const
{
return (Qualifies(iface,
UserConstants::min_elite_joust,
UserConstants::max_elite_joust,
UserConstants::min_mood_joust,
UserConstants::max_mood_joust));
}
Stuff::Scalar Joust::Evaluate(TacticInterface& iface) const
{
return ( ( 0.5f * Score_FasterThanTarget(iface))
+ (-1.0f * Score_FarFromTarget(iface))
+ (-1.0f * Score_Gimped(iface))
+ (-1.0f * Score_WantsToUseVCH(iface)));
}
bool Rush::CanBeSelectedAutomatically(TacticInterface& iface) const
{
return (Qualifies(iface,
UserConstants::min_elite_rush,
UserConstants::max_elite_rush,
UserConstants::min_mood_rush,
UserConstants::max_mood_rush));
}
Stuff::Scalar Rush::Evaluate(TacticInterface& iface) const
{
return ( (-0.5f * Score_FasterThanTarget(iface))
+ (-1.0f * Score_HaveMissiles(iface))
+ ( 1.0f * Score_TargetFacingAway(iface))
+ (-0.5f * Score_FarFromTarget(iface))
+ ( 1.0f * Score_Gimped(iface))
+ (-0.5f * Score_WantsToUseVCH(iface)));
}
bool HitAndRun::CanBeSelectedAutomatically(TacticInterface& iface) const
{
return (Qualifies(iface,
UserConstants::min_elite_hitandrun,
UserConstants::max_elite_hitandrun,
UserConstants::min_mood_hitandrun,
UserConstants::max_mood_hitandrun));
}
Stuff::Scalar HitAndRun::Evaluate(TacticInterface& iface) const
{
return ( ( 1.0f * Score_FasterThanTarget(iface))
+ (-1.0f * Score_Gimped(iface))
+ (-1.0f * Score_WantsToUseVCH(iface)));
}
bool Rear::CanBeSelectedAutomatically(TacticInterface& iface) const
{
return (Qualifies(iface,
UserConstants::min_elite_rear,
UserConstants::max_elite_rear,
UserConstants::min_mood_rear,
UserConstants::max_mood_rear));
}
Stuff::Scalar Rear::Evaluate(TacticInterface& iface) const
{
return ( ( 1.0f * Score_TargetFacingAway(iface))
+ ( 1.0f * Score_Gimped(iface))
+ ( 0.5f * Score_WantsToUseVCH(iface)));
}
bool Circle::CanBeSelectedAutomatically(TacticInterface& iface) const
{
return (Qualifies(iface,
UserConstants::min_elite_circle,
UserConstants::max_elite_circle,
UserConstants::min_mood_circle,
UserConstants::max_mood_circle));
}
Stuff::Scalar Circle::Evaluate(TacticInterface& iface) const
{
return ( ( 0.5f * Score_FasterThanTarget(iface))
+ ( 1.0f * Score_HaveMissiles(iface))
+ ( 0.5f * Score_FarFromTarget(iface))
+ (-0.5f * Score_Gimped(iface))
+ ( 1.0f * Score_WantsToUseVCH(iface)));
}
bool Retreat::CanBeSelectedAutomatically(TacticInterface& iface) const
{
return (Qualifies(iface,
UserConstants::min_elite_retreat,
UserConstants::max_elite_retreat,
UserConstants::min_mood_retreat,
UserConstants::max_mood_retreat));
}
Stuff::Scalar Retreat::Evaluate(TacticInterface& iface) const
{
return ( ( 1.0f * Score_FasterThanTarget(iface))
+ (-1.0f * Score_TargetFacingAway(iface))
+ (-1.0f * Score_FarFromTarget(iface))
+ (-1.0f * Score_Gimped(iface))
+ (-0.5f * Score_WantsToUseVCH(iface)));
}
bool DeathFromAbove::CanBeSelectedAutomatically(TacticInterface& iface) const
{
if ((iface.CanJump() == false) ||
(iface.GetTarget().IsDerivedFrom(Mech::DefaultData) == false))
{
return (false);
}
return (Qualifies(iface,
UserConstants::min_elite_dfa,
UserConstants::max_elite_dfa,
UserConstants::min_mood_dfa,
UserConstants::max_mood_dfa));
}
Stuff::Scalar DeathFromAbove::Evaluate(TacticInterface& iface) const
{
return ( ( 1.0f * Score_FasterThanTarget(iface))
+ (-1.0f * Score_FarFromTarget(iface))
+ (-2.0f * Score_Gimped(iface))
+ (-0.5f * Score_WantsToUseVCH(iface)));
}
+255
View File
@@ -0,0 +1,255 @@
#pragma once
#ifndef AI_TACTICS_HPP
#define AI_TACTICS_HPP
#include <stuff\auto_container.hpp>
#pragma warning (push)
#include <stlport\string>
#include <stlport\vector>
#pragma warning (pop)
#include "AI_Behavior.hpp"
#include <Stuff\Scalar.hpp>
namespace Stuff { class Point3D; }
namespace MechWarrior4 { class Vehicle; }
namespace MW4AI
{
namespace Tactics
{
enum TacticID
{
// NOTE: The keywords and constants here must exactly match those in MWCONST.ABI
TACTIC_PICK_BEST = 2000, // update TACTIC_FIRST if you change this
TACTIC_STOP_AND_FIRE = 2001,
TACTIC_RAM = 2002,
TACTIC_JOUST = 2003,
TACTIC_RUSH = 2004,
TACTIC_HIT_AND_RUN = 2005,
TACTIC_FRONT = 2006,
TACTIC_REAR = 2007,
TACTIC_CIRCLE_OF_DEATH = 2008,
TACTIC_BACK_UP_AND_FIRE = 2009,
TACTIC_RETREAT = 2010,
TACTIC_CIRCLE_HOVER = 2011,
TACTIC_STRAFE = 2012,
TACTIC_STAND_GROUND = 2013,
TACTIC_JUMP_AND_SHOOT = 2014,
TACTIC_SNIPE = 2015,
TACTIC_SHOOT_ONLY = 2016,
TACTIC_DEFEND = 2017,
TACTIC_LOCAL_PATROL = 2018,
TACTIC_SURRENDER = 2019,
TACTIC_AMBUSH = 2020,
TACTIC_DEATH_FROM_ABOVE = 2021,
TACTIC_HELI_POPUP = 2022,
TACTIC_DIVE_BOMB = 2023,
TACTIC_FAST_CIRCLE = 2024,
TACTIC_STARE = 2025 // update TACTIC_LAST if you change this
};
class Tactic
{
public:
virtual void Update(TacticInterface& i);
virtual TacticID GetID() const = 0;
virtual std::string GetName() const = 0;
Tactic();
virtual ~Tactic();
virtual bool CanBeSelectedAutomatically(TacticInterface& iface) const;
virtual bool ShouldIgnoreLOS() const;
void SetExplicit(bool is_explicit);
bool GetExplicit() const;
bool ShouldAbandon(TacticInterface& i) const;
virtual bool ShouldAbandonImmediately() const = 0;
virtual Stuff::Scalar Evaluate(TacticInterface& iface) const;
void SetIgnoreExplicitTactic(TacticID tactic);
TacticID GetIgnoreExplicitTactic() const;
bool Finished() const;
void UpdateSatisfaction();
private:
Stuff::Scalar GetDuration() const;
bool IsIneffective() const;
Stuff::Scalar m_CreationTime;
Stuff::Scalar m_CreationMood;
mutable bool m_Explicit;
Stuff::Scalar m_Satisfaction;
Stuff::Time m_LastSatisfactionUpdate;
Stuff::Scalar m_AutoEndTime;
TacticID m_TacticToIgnore;
protected:
virtual bool IsHappy() const = 0;
};
enum
{
TACTIC_FIRST = TACTIC_PICK_BEST,
TACTIC_LAST = TACTIC_STARE
};
void VerifyTactic(TacticID id);
Stuff::Auto_Ptr<Tactic> CreateTactic(TacticInterface& i, TacticID id);
class Registrar
{
public:
static void IncrementRefCount(TacticInterface& i);
static void DecrementRefCount();
static Registrar& GetInstance();
Registrar(TacticInterface& i);
~Registrar();
TacticID SelectTactic(TacticInterface& i, const std::vector<TacticID>& most_recent_tactics) const;
Tactic& GetTactic(TacticID id) const;
private:
int m_RefCount;
static Registrar* instance;
typedef Stuff::Auto_Container<Tactic,std::vector<Tactic*> > tactic_container;
tactic_container m_Tactics;
};
#define BEGINDEF_TACTIC(classname,id,string_name,behavior_type) \
class classname: \
public Tactic \
{ \
protected: \
TacticID GetID() const { return (id); } \
std::string GetName() const { return (string_name); } \
bool ShouldAbandonImmediately() const { return (m_Implementation.ShouldStopImmediately()); } \
void Update(TacticInterface& i) \
{ \
Tactic::Update(i); \
m_Implementation.Execute(i); \
} \
bool IsHappy() const { return (m_Implementation.IsHappy()); } \
private: \
behavior_type m_Implementation;
#define ENDDEF_TACTIC };
BEGINDEF_TACTIC(StopAndFire,TACTIC_STOP_AND_FIRE,"Stop and Fire",MW4AI::Behaviors::StopAndFire)
ENDDEF_TACTIC
BEGINDEF_TACTIC(Ram,TACTIC_RAM,"Ram",MW4AI::Behaviors::Ram)
ENDDEF_TACTIC
BEGINDEF_TACTIC(Joust,TACTIC_JOUST,"Joust",MW4AI::Behaviors::Joust);
public:
bool CanBeSelectedAutomatically(TacticInterface& iface) const;
Stuff::Scalar Evaluate(TacticInterface& iface) const;
ENDDEF_TACTIC
BEGINDEF_TACTIC(Rush,TACTIC_RUSH,"Rush",MW4AI::Behaviors::Rush)
public:
bool CanBeSelectedAutomatically(TacticInterface& iface) const;
Stuff::Scalar Evaluate(TacticInterface& iface) const;
ENDDEF_TACTIC
BEGINDEF_TACTIC(HitAndRun,TACTIC_HIT_AND_RUN,"Hit and Run",MW4AI::Behaviors::HitAndRun)
public:
bool CanBeSelectedAutomatically(TacticInterface& iface) const;
Stuff::Scalar Evaluate(TacticInterface& iface) const;
ENDDEF_TACTIC
BEGINDEF_TACTIC(Front,TACTIC_FRONT,"Front",MW4AI::Behaviors::Front)
ENDDEF_TACTIC
BEGINDEF_TACTIC(Rear,TACTIC_REAR,"Rear",MW4AI::Behaviors::Rear)
public:
bool CanBeSelectedAutomatically(TacticInterface& iface) const;
Stuff::Scalar Evaluate(TacticInterface& iface) const;
ENDDEF_TACTIC
BEGINDEF_TACTIC(Circle,TACTIC_CIRCLE_OF_DEATH,"Circle",MW4AI::Behaviors::CircleOfDeath)
public:
bool CanBeSelectedAutomatically(TacticInterface& iface) const;
Stuff::Scalar Evaluate(TacticInterface& iface) const;
ENDDEF_TACTIC
BEGINDEF_TACTIC(Retreat,TACTIC_RETREAT,"Retreat",MW4AI::Behaviors::Retreat)
public:
bool CanBeSelectedAutomatically(TacticInterface& iface) const;
Stuff::Scalar Evaluate(TacticInterface& iface) const;
ENDDEF_TACTIC
BEGINDEF_TACTIC(BackUpAndFire,TACTIC_BACK_UP_AND_FIRE,"Back Up and Fire",MW4AI::Behaviors::BackUpAndFire)
ENDDEF_TACTIC
BEGINDEF_TACTIC(CircleHover,TACTIC_CIRCLE_HOVER,"Circle Hover",MW4AI::Behaviors::CircleHover)
ENDDEF_TACTIC
BEGINDEF_TACTIC(Strafe,TACTIC_STRAFE,"Strafe",MW4AI::Behaviors::Strafe)
virtual bool ShouldIgnoreLOS() const
{
return (true);
}
ENDDEF_TACTIC
BEGINDEF_TACTIC(StandGround,TACTIC_STAND_GROUND,"Stand Ground",MW4AI::Behaviors::StandGround)
ENDDEF_TACTIC
BEGINDEF_TACTIC(JumpAndShoot,TACTIC_JUMP_AND_SHOOT,"Jump and Shoot",MW4AI::Behaviors::JumpAndShoot)
ENDDEF_TACTIC
BEGINDEF_TACTIC(Snipe,TACTIC_SNIPE,"Snipe",MW4AI::Behaviors::Snipe)
ENDDEF_TACTIC
BEGINDEF_TACTIC(ShootOnly,TACTIC_SHOOT_ONLY,"ShootOnly",MW4AI::Behaviors::ShootOnly)
ENDDEF_TACTIC
BEGINDEF_TACTIC(Defend,TACTIC_DEFEND,"Defend",MW4AI::Behaviors::Defend)
ENDDEF_TACTIC
BEGINDEF_TACTIC(LocalPatrol,TACTIC_LOCAL_PATROL,"Local Patrol",MW4AI::Behaviors::LocalPatrol)
ENDDEF_TACTIC
BEGINDEF_TACTIC(Surrender,TACTIC_SURRENDER,"Surrender",MW4AI::Behaviors::Surrender)
ENDDEF_TACTIC
BEGINDEF_TACTIC(Ambush,TACTIC_AMBUSH,"Ambush",MW4AI::Behaviors::Ambush)
ENDDEF_TACTIC
BEGINDEF_TACTIC(DeathFromAbove,TACTIC_DEATH_FROM_ABOVE,"Death From Above",MW4AI::Behaviors::DeathFromAbove)
public:
bool CanBeSelectedAutomatically(TacticInterface& iface) const;
Stuff::Scalar Evaluate(TacticInterface& iface) const;
ENDDEF_TACTIC
BEGINDEF_TACTIC(HeliPopup,TACTIC_HELI_POPUP,"Heli Popup",MW4AI::Behaviors::HeliPopup)
ENDDEF_TACTIC
BEGINDEF_TACTIC(DiveBomb,TACTIC_DIVE_BOMB,"Dive Bomb",MW4AI::Behaviors::DiveBomb)
ENDDEF_TACTIC
BEGINDEF_TACTIC(FastCircle,TACTIC_FAST_CIRCLE,"Fast Circle",MW4AI::Behaviors::FastCircle)
ENDDEF_TACTIC
BEGINDEF_TACTIC(Stare,TACTIC_STARE,"Stare",MW4AI::Behaviors::Stare)
ENDDEF_TACTIC
#undef BEGINDEF_TACTIC
#undef ENDDEF_TACTIC
};
};
#endif AI_TACTICS_HPP
+156
View File
@@ -0,0 +1,156 @@
#include "MW4Headers.hpp"
#include "AI_Types.hpp"
using namespace MW4AI;
Types* Types::m_Instance = 0;
Types::Types()
: m_RefCount(0)
, m_Resource("ai\\ai.types")
{
Verify(m_Resource.DoesResourceExist());
m_Resource.LoadData();
m_NotationFile.Assimilate(new Stuff::NotationFile(&m_Resource));
Verify(m_NotationFile.GetPointer() != 0);
Stuff::NotationFile::PageIterator* page_iter = m_NotationFile->MakePageIterator();
Stuff::Page* page;
while((page = page_iter->ReadAndNext()) != NULL)
{
Check_Object(page);
ReadPage(*page);
}
delete page_iter;
}
Types::~Types()
{
while (m_Types.size() > 0)
{
delete (*(m_Types.begin()));
m_Types.erase(m_Types.begin());
}
}
void GetNoteEntry(Stuff::Note& note, std::string& value)
{
const char* char_ptr;
note.GetEntry(&char_ptr);
value = char_ptr;
}
void GetNoteEntry(Stuff::Note& note, Stuff::Scalar& value)
{
note.GetEntry(&value);
}
void GetNoteEntry(Stuff::Note& note, int value)
{
note.GetEntry(&value);
}
void Types::ReadPage(Stuff::Page& page)
{
Stuff::Note* type = page.FindNote("type");
if (type == 0)
{
return;
}
std::string type_name;
GetNoteEntry(*type,type_name);
Type* new_type = 0;
if (type_name == "integer")
new_type = new Type_Integer(page);
else if (type_name == "string")
new_type = new Type_String(page);
else if (type_name == "real")
new_type = new Type_Real(page);
else
return;
m_Types.push_back(new_type);
}
void Types::IncrementRefCount()
{
if (m_Instance == 0)
{
m_Instance = new Types();
}
++m_Instance->m_RefCount;
}
void Types::DecrementRefCount()
{
Verify(m_Instance != 0);
Verify(m_Instance->m_RefCount > 0);
--(m_Instance->m_RefCount);
if (m_Instance->m_RefCount == 0)
{
delete m_Instance;
m_Instance = 0;
}
}
Types* Types::Instance()
{
return (m_Instance);
}
#define GET_IF_FOUND(string_name,data_member) \
Stuff::Note* note_##data_member = page.FindNote(string_name); \
if (note_##data_member != 0) { GetNoteEntry(*note_##data_member,data_member); }
Type::Type(Stuff::Page& page)
{
m_Name = page.GetName();
GET_IF_FOUND("default_text",m_DefaultText);
GET_IF_FOUND("display",m_Display);
GET_IF_FOUND("values",m_Values);
}
Type_Integer::Type_Integer(Stuff::Page& page)
: Type(page)
, m_Min(0)
, m_Max(100)
, m_Default(50)
{
GET_IF_FOUND("min",m_Min);
GET_IF_FOUND("max",m_Max);
GET_IF_FOUND("default",m_Default);
}
Type_Real::Type_Real(Stuff::Page& page)
: Type(page)
, m_Min(0)
, m_Max(1)
, m_Default(0.5f)
{
GET_IF_FOUND("min",m_Min);
GET_IF_FOUND("max",m_Max);
GET_IF_FOUND("default",m_Default);
}
Type_String::Type_String(Stuff::Page& page)
: Type(page)
{
}
+88
View File
@@ -0,0 +1,88 @@
#pragma once
#ifndef AI_TYPES_HPP
#define AI_TYPES_HPP
#include <Stuff\Scalar.hpp>
#include <Stuff\Auto_Ptr.hpp>
#pragma warning(push)
#include <stlport\string>
#include <stlport\vector>
#pragma warning(pop)
#include <Adept\Resource.hpp>
#include <Stuff\NotationFile.hpp>
namespace MW4AI
{
class Type
{
public:
Type(Stuff::Page& page);
protected:
std::string m_Name;
std::string m_DefaultText;
std::string m_Display;
std::string m_Values;
};
class Types
{
public:
Types();
~Types();
static void IncrementRefCount();
static void DecrementRefCount();
static Types* Instance();
private:
void ReadPage(Stuff::Page& page);
private:
Adept::Resource m_Resource;
Stuff::Auto_Ptr<Stuff::NotationFile> m_NotationFile;
int m_RefCount;
static Types* m_Instance;
std::vector<Type*> m_Types;
};
class Type_Integer
: public Type
{
public:
Type_Integer(Stuff::Page& page);
private:
int m_Min;
int m_Max;
int m_Default;
};
class Type_Real
: public Type
{
public:
Type_Real(Stuff::Page& page);
private:
Stuff::Scalar m_Min;
Stuff::Scalar m_Max;
Stuff::Scalar m_Default;
};
class Type_String
: public Type
{
public:
Type_String(Stuff::Page& page);
};
};
#endif // AI_TYPES_HPP
@@ -0,0 +1,611 @@
#include "MW4Headers.hpp"
#include "AI_UserConstants.hpp"
using namespace MW4AI;
UserConstants* UserConstants::m_Instance = 0;
UserConstants::UserConstants()
: m_RefCount(0)
, m_Resource("ai\\ai.constants")
, m_LastPage(0)
{
Verify(m_Resource.DoesResourceExist());
m_Resource.LoadData();
m_NotationFile.Assimilate(new Stuff::NotationFile(&m_Resource));
const std::string friendly_fire_building_cheat("Friendly Fire Building Cheat");
const std::string mood_entropy("Mood Entropy");
const std::string mood_multipliers("Mood Modifiers");
const std::string missed_shot_modifiers("Missed Shot Modifiers");
const std::string speed_definitions("Speed Definitions");
const std::string tonnage_definitions("Tonnage Definitions");
const std::string distance_definitions("Distance Definitions");
const std::string to_hit_modifiers("To-Hit Modifiers");
const std::string elite_levels("Elite Levels");
const std::string evasion_characteristics("Evasion Characteristics");
const std::string lancemates("Lancemates");
const std::string firing("Firing");
const std::string tactics("Tactics");
const std::string tactic_selection("Tactic Selection");
const std::string ai_slope ("AI Slope");
const std::string ai_movecost ("AI Movement Costs");
const std::string objective ("Objective");
const std::string skills ("Skills");
const std::string piloting ("Piloting");
const std::string ejecting("Ejecting");
const std::string difficulty ("Difficulty");
const std::string collision ("Collision");
const std::string joystick ("Joystick");
const std::string salvage ("Salvage");
const std::string mouse ("Mouse");
{for (int i = ID_FIRST;
i <= ID_LAST;
++i)
{
switch ((ID)i)
{
#define ENTRY(itemname,blockname) case itemname: { LookUpValue(blockname,#itemname,(int)itemname); break; }
ENTRY(entropy_regeneration_at_0, mood_entropy);
ENTRY(entropy_regeneration_at_100, mood_entropy);
ENTRY(building_ff_multiplier, friendly_fire_building_cheat);
ENTRY(shutdown, mood_multipliers);
ENTRY(internal_armor_breached, mood_multipliers);
ENTRY(fall_down, mood_multipliers);
ENTRY(first_arm_hit, mood_multipliers);
ENTRY(second_arm_hit, mood_multipliers);
ENTRY(first_leg_hit, mood_multipliers);
ENTRY(mood_squad_dead_unit_multiplier, mood_multipliers);
ENTRY(interval_multiplier_desperate, mood_multipliers);
ENTRY(interval_multiplier_defensive, mood_multipliers);
ENTRY(interval_multiplier_neutral, mood_multipliers);
ENTRY(interval_multiplier_aggressive, mood_multipliers);
ENTRY(interval_multiplier_brutal, mood_multipliers);
ENTRY(skew_at_0, missed_shot_modifiers);
ENTRY(skew_at_100, missed_shot_modifiers);
ENTRY(skew_inc_at_0, missed_shot_modifiers);
ENTRY(skew_inc_at_100, missed_shot_modifiers);
ENTRY(speed_stopped, speed_definitions);
ENTRY(speed_slow, speed_definitions);
ENTRY(speed_medium, speed_definitions);
ENTRY(speed_fast, speed_definitions);
ENTRY(speed_maximum, speed_definitions);
ENTRY(mech_tiny, tonnage_definitions);
ENTRY(mech_small, tonnage_definitions);
ENTRY(mech_medium, tonnage_definitions);
ENTRY(mech_large, tonnage_definitions);
ENTRY(mech_huge, tonnage_definitions);
ENTRY(distance_adjacent, distance_definitions);
ENTRY(distance_near, distance_definitions);
ENTRY(distance_medium, distance_definitions);
ENTRY(distance_far, distance_definitions);
ENTRY(distance_very_far, distance_definitions);
ENTRY(if_crouched, to_hit_modifiers);
ENTRY(if_tiny, to_hit_modifiers);
ENTRY(if_small, to_hit_modifiers);
ENTRY(if_medium_size, to_hit_modifiers);
ENTRY(if_large, to_hit_modifiers);
ENTRY(if_huge, to_hit_modifiers);
ENTRY(if_stopped, to_hit_modifiers);
ENTRY(if_slow, to_hit_modifiers);
ENTRY(if_medium_speed, to_hit_modifiers);
ENTRY(if_fast, to_hit_modifiers);
ENTRY(if_maximum, to_hit_modifiers);
ENTRY(if_shooter_stopped, to_hit_modifiers);
ENTRY(if_shooter_slow, to_hit_modifiers);
ENTRY(if_shooter_medium, to_hit_modifiers);
ENTRY(if_shooter_fast, to_hit_modifiers);
ENTRY(if_shooter_maximum, to_hit_modifiers);
ENTRY(if_adjacent, to_hit_modifiers);
ENTRY(if_near, to_hit_modifiers);
ENTRY(if_medium_range, to_hit_modifiers);
ENTRY(if_far, to_hit_modifiers);
ENTRY(if_very_far, to_hit_modifiers);
ENTRY(if_firing_with_one_arm, to_hit_modifiers);
ENTRY(if_turning, to_hit_modifiers);
ENTRY(if_bearing_90, to_hit_modifiers);
ENTRY(min_evade_when_missiles_shot_at_me, elite_levels);
ENTRY(max_evade_when_missiles_shot_at_me, elite_levels);
ENTRY(min_evade_when_targeted, elite_levels);
ENTRY(max_evade_when_targeted, elite_levels);
ENTRY(min_evade_by_jumping, elite_levels);
ENTRY(max_evade_by_jumping, elite_levels);
ENTRY(min_evade_by_throttle_override, elite_levels);
ENTRY(max_evade_by_throttle_override, elite_levels);
ENTRY(min_evade_by_crouching, elite_levels);
ENTRY(max_evade_by_crouching, elite_levels);
ENTRY(min_jump_if_rushed, elite_levels);
ENTRY(max_jump_if_rushed, elite_levels);
ENTRY(min_opportunity_fire, elite_levels);
ENTRY(max_opportunity_fire, elite_levels);
ENTRY(min_look_left_or_right, elite_levels);
ENTRY(max_look_left_or_right, elite_levels);
ENTRY(min_look_time_at_0, elite_levels);
ENTRY(min_look_time_at_100, elite_levels);
ENTRY(min_dont_use_limited_ammo_vs_non_mechs, elite_levels);
ENTRY(max_dont_use_limited_ammo_vs_non_mechs, elite_levels);
ENTRY(min_vulnerable_leg_hiding, elite_levels);
ENTRY(max_vulnerable_leg_hiding, elite_levels);
ENTRY(min_mood_vulnerable_leg_hiding, elite_levels);
ENTRY(max_mood_vulnerable_leg_hiding, elite_levels);
ENTRY(switch_to_random_component_picking, elite_levels);
ENTRY(switch_to_most_damaged_component_picking, elite_levels);
ENTRY(min_prefer_water, elite_levels);
ENTRY(max_prefer_water, elite_levels);
ENTRY(min_throttle_override, elite_levels);
ENTRY(torso_twist_multiplier_at_0, elite_levels);
ENTRY(torso_twist_use_full_multiplier, elite_levels);
ENTRY(jump_wait_time_at_0, evasion_characteristics);
ENTRY(jump_wait_time_at_100, evasion_characteristics);
ENTRY(evade_focus_time_at_0, evasion_characteristics);
ENTRY(evade_focus_time_at_100, evasion_characteristics);
ENTRY(lancemate_can_attack_radius, lancemates);
ENTRY(max_lancemate_distance_from_leader, lancemates);
ENTRY(max_defend_distance_from_target, tactics);
ENTRY(jump_and_shoot_hover_height_min, tactics);
ENTRY(jump_and_shoot_hover_height_max, tactics);
ENTRY(max_fire_cheat_angle, firing);
ENTRY(max_airplane_fire_cheat_angle, firing);
ENTRY(max_turret_fire_cheat_angle, firing);
ENTRY(min_tactic_time, tactic_selection);
ENTRY(min_elite_joust, tactic_selection);
ENTRY(max_elite_joust, tactic_selection);
ENTRY(min_mood_joust, tactic_selection);
ENTRY(max_mood_joust, tactic_selection);
ENTRY(min_elite_rush, tactic_selection);
ENTRY(max_elite_rush, tactic_selection);
ENTRY(min_mood_rush, tactic_selection);
ENTRY(max_mood_rush, tactic_selection);
ENTRY(min_elite_hitandrun, tactic_selection);
ENTRY(max_elite_hitandrun, tactic_selection);
ENTRY(min_mood_hitandrun, tactic_selection);
ENTRY(max_mood_hitandrun, tactic_selection);
ENTRY(min_elite_rear, tactic_selection);
ENTRY(max_elite_rear, tactic_selection);
ENTRY(min_mood_rear, tactic_selection);
ENTRY(max_mood_rear, tactic_selection);
ENTRY(min_elite_circle, tactic_selection);
ENTRY(max_elite_circle, tactic_selection);
ENTRY(min_mood_circle, tactic_selection);
ENTRY(max_mood_circle, tactic_selection);
ENTRY(min_elite_retreat, tactic_selection);
ENTRY(max_elite_retreat, tactic_selection);
ENTRY(min_mood_retreat, tactic_selection);
ENTRY(max_mood_retreat, tactic_selection);
ENTRY(min_elite_dfa, tactic_selection);
ENTRY(max_elite_dfa, tactic_selection);
ENTRY(min_mood_dfa, tactic_selection);
ENTRY(max_mood_dfa, tactic_selection);
ENTRY(leg_up_slope, ai_slope);
ENTRY(leg_down_slope, ai_slope);
ENTRY(track_up_slope, ai_slope);
ENTRY(track_down_slope, ai_slope);
ENTRY(wheel_up_slope, ai_slope);
ENTRY(wheel_down_slope, ai_slope);
ENTRY(hover_up_slope, ai_slope);
ENTRY(hover_down_slope, ai_slope);
ENTRY(leg_dirt_cost, ai_movecost);
ENTRY(leg_rock_cost, ai_movecost);
ENTRY(leg_steel_cost, ai_movecost);
ENTRY(leg_blacktop_cost, ai_movecost);
ENTRY(leg_glass_cost, ai_movecost);
ENTRY(leg_brick_cost, ai_movecost);
ENTRY(leg_grass_cost, ai_movecost);
ENTRY(leg_wood_cost, ai_movecost);
ENTRY(leg_tree_cost, ai_movecost);
ENTRY(leg_swamp_cost, ai_movecost);
ENTRY(leg_concrete_cost, ai_movecost);
ENTRY(leg_rough_cost, ai_movecost);
ENTRY(leg_snow_cost, ai_movecost);
ENTRY(leg_underbrush_cost, ai_movecost);
ENTRY(leg_shallowwater_cost, ai_movecost);
ENTRY(leg_midwater_cost, ai_movecost);
ENTRY(leg_oceanicwater_cost, ai_movecost);
ENTRY(leg_desert_cost, ai_movecost);
ENTRY(leg_flatswamp_cost, ai_movecost);
ENTRY(leg_thickswamp_cost, ai_movecost);
// MSL 5.03 Lava
ENTRY(leg_crackedlava_cost, ai_movecost);
ENTRY(leg_openlava_cost, ai_movecost);
ENTRY(track_dirt_cost, ai_movecost);
ENTRY(track_rock_cost, ai_movecost);
ENTRY(track_steel_cost, ai_movecost);
ENTRY(track_blacktop_cost, ai_movecost);
ENTRY(track_glass_cost, ai_movecost);
ENTRY(track_brick_cost, ai_movecost);
ENTRY(track_grass_cost, ai_movecost);
ENTRY(track_wood_cost, ai_movecost);
ENTRY(track_tree_cost, ai_movecost);
ENTRY(track_swamp_cost, ai_movecost);
ENTRY(track_concrete_cost, ai_movecost);
ENTRY(track_rough_cost, ai_movecost);
ENTRY(track_snow_cost, ai_movecost);
ENTRY(track_underbrush_cost, ai_movecost);
ENTRY(track_shallowwater_cost,ai_movecost);
ENTRY(track_midwater_cost, ai_movecost);
ENTRY(track_oceanicwater_cost,ai_movecost);
ENTRY(track_desert_cost, ai_movecost);
ENTRY(track_flatswamp_cost, ai_movecost);
ENTRY(track_thickswamp_cost, ai_movecost);
// MSL 5.03 Lava
ENTRY(track_crackedlava_cost, ai_movecost);
ENTRY(track_openlava_cost, ai_movecost);
ENTRY(wheel_dirt_cost, ai_movecost);
ENTRY(wheel_rock_cost, ai_movecost);
ENTRY(wheel_steel_cost, ai_movecost);
ENTRY(wheel_blacktop_cost, ai_movecost);
ENTRY(wheel_glass_cost, ai_movecost);
ENTRY(wheel_brick_cost, ai_movecost);
ENTRY(wheel_grass_cost, ai_movecost);
ENTRY(wheel_wood_cost, ai_movecost);
ENTRY(wheel_tree_cost, ai_movecost);
ENTRY(wheel_swamp_cost, ai_movecost);
ENTRY(wheel_concrete_cost, ai_movecost);
ENTRY(wheel_rough_cost, ai_movecost);
ENTRY(wheel_snow_cost, ai_movecost);
ENTRY(wheel_underbrush_cost, ai_movecost);
ENTRY(wheel_shallowwater_cost,ai_movecost);
ENTRY(wheel_midwater_cost, ai_movecost);
ENTRY(wheel_oceanicwater_cost,ai_movecost);
ENTRY(wheel_desert_cost, ai_movecost);
ENTRY(wheel_flatswamp_cost, ai_movecost);
ENTRY(wheel_thickswamp_cost, ai_movecost);
// MSL 5.03 Lava
ENTRY(wheel_crackedlava_cost, ai_movecost);
ENTRY(wheel_openlava_cost, ai_movecost);
ENTRY(hover_dirt_cost, ai_movecost);
ENTRY(hover_rock_cost, ai_movecost);
ENTRY(hover_steel_cost, ai_movecost);
ENTRY(hover_blacktop_cost, ai_movecost);
ENTRY(hover_glass_cost, ai_movecost);
ENTRY(hover_brick_cost, ai_movecost);
ENTRY(hover_grass_cost, ai_movecost);
ENTRY(hover_wood_cost, ai_movecost);
ENTRY(hover_tree_cost, ai_movecost);
ENTRY(hover_swamp_cost, ai_movecost);
ENTRY(hover_concrete_cost, ai_movecost);
ENTRY(hover_rough_cost, ai_movecost);
ENTRY(hover_snow_cost, ai_movecost);
ENTRY(hover_underbrush_cost, ai_movecost);
ENTRY(hover_shallowwater_cost,ai_movecost);
ENTRY(hover_midwater_cost, ai_movecost);
ENTRY(hover_oceanicwater_cost,ai_movecost);
ENTRY(hover_desert_cost, ai_movecost);
ENTRY(hover_flatswamp_cost, ai_movecost);
ENTRY(hover_thickswamp_cost, ai_movecost);
// MSL 5.03 Lava
ENTRY(hover_crackedlava_cost, ai_movecost);
ENTRY(hover_openlava_cost, ai_movecost);
ENTRY(objective_display_time, objective);
ENTRY(default_pilot, skills);
ENTRY(default_gunnery, skills);
ENTRY(default_elite, skills);
ENTRY(default_minheat, skills);
ENTRY(default_maxheat, skills);
ENTRY(default_sensor, skills);
ENTRY(default_blind, skills);
ENTRY(default_longrange, skills);
ENTRY(default_shortrange, skills);
ENTRY(default_addpilot, skills);
ENTRY(default_addgunnery, skills);
ENTRY(default_addelite, skills);
ENTRY(max_skill_add, skills);
ENTRY(max_fog_dist_to_use_blind_skill, skills);
ENTRY(damage_amount, piloting);
ENTRY(fall_damage_minus, piloting);
ENTRY(fall_splash_multiplier, piloting);
ENTRY(min_fall_timer, piloting);
ENTRY(damage_mod, piloting);
ENTRY(low_water_mod, piloting);
ENTRY(mid_water_mod, piloting);
ENTRY(concrete_mod, piloting);
ENTRY(gimped_mod, piloting);
ENTRY(double_damage_mod, piloting);
ENTRY(moving_fast_mod, piloting);
ENTRY(jump_recover_mod, piloting);
ENTRY(max_water_jump, piloting);
ENTRY(flying_turn_rate, piloting);
ENTRY(eject_chance_for_non_lancemate, ejecting);
ENTRY(eject_chance_for_lancemate, ejecting);
ENTRY(eject_chance_ok_when_ejected, ejecting);
ENTRY(eject_chance_injured_when_ejected, ejecting);
ENTRY(friend_easy_gunnery_mod, difficulty);
ENTRY(friend_medium_gunnery_mod, difficulty);
ENTRY(friend_hard_gunnery_mod, difficulty);
ENTRY(friend_impossible_gunnery_mod, difficulty);
ENTRY(enemy_easy_gunnery_mod, difficulty);
ENTRY(enemy_medium_gunnery_mod, difficulty);
ENTRY(enemy_hard_gunnery_mod, difficulty);
ENTRY(enemy_impossible_gunnery_mod, difficulty);
ENTRY(neutral_easy_gunnery_mod, difficulty);
ENTRY(neutral_medium_gunnery_mod, difficulty);
ENTRY(neutral_hard_gunnery_mod, difficulty);
ENTRY(neutral_impossible_gunnery_mod, difficulty);
ENTRY(collision_mech_light_damage, collision);
ENTRY(collision_mech_light_slowdown, collision);
ENTRY(collision_mech_light_mech_speed, collision);
ENTRY(collision_mech_light_building_speed, collision);
ENTRY(collision_mech_medium_tonage, collision);
ENTRY(collision_mech_medium_damage, collision);
ENTRY(collision_mech_medium_slowdown, collision);
ENTRY(collision_mech_medium_mech_speed, collision);
ENTRY(collision_mech_medium_building_speed, collision);
ENTRY(collision_mech_heavy_tonage, collision);
ENTRY(collision_mech_heavy_damage, collision);
ENTRY(collision_mech_heavy_slowdown, collision);
ENTRY(collision_mech_heavy_mech_speed, collision);
ENTRY(collision_mech_heavy_building_speed, collision);
ENTRY(collision_dfa_speed, collision);
ENTRY(collision_dfa_damage_given, collision);
ENTRY(collision_dfa_damage_taken, collision);
ENTRY(collision_tank_slowdown, collision);
ENTRY(throttle_center, joystick);
ENTRY(throttle_dead_low, joystick);
ENTRY(throttle_dead_high, joystick);
ENTRY(chance_salvage, salvage);
ENTRY(mouse_min_change, mouse);
ENTRY(mouse_interia_mult, mouse);
ENTRY(mouse_max_mouse, mouse);
default: { Verify(!"Should never get here."); }
#undef ENTRY
}
}}
for (int i = ID_MOVE_COST_START;i <= ID_MOVE_COST_LAST;++i)
{
if (m_Value[i] <= -100)
m_Value[i] = FLT_MAX;
}
}
UserConstants::~UserConstants()
{
}
Stuff::Scalar UserConstants::Get(ID id) const
{
Verify(id >= ID_FIRST);
Verify(id <= ID_LAST);
return (m_Value[(int)id]);
}
void UserConstants::LookUpValue(const std::string& header_name, const std::string& item_name, int value_index)
{
Verify(m_NotationFile.GetPointer() != 0);
Stuff::Page* page = 0;
if ((m_LastPage != 0) &&
(stricmp(header_name.c_str(),m_LastPage->GetName()) == 0))
{
page = m_LastPage;
}
else
{
page = m_NotationFile->FindPage(header_name.c_str());
if (page == 0)
{
Verify(!"Item not found. Make sure you have the latest CONTENT\\AI\\AI.CONSTANTS file.");
m_Value[value_index] = 0;
return;
}
m_LastPage = page;
}
Stuff::Note* note = page->FindNote(item_name.c_str());
m_Value[value_index] = 0;
if (note == 0)
{
Verify(!"Item not found.");
}
else
{
note->GetEntry(&(m_Value[value_index]));
}
}
void UserConstants::IncrementRefCount()
{
if (m_Instance == 0)
{
m_Instance = new UserConstants();
}
++m_Instance->m_RefCount;
}
void UserConstants::DecrementRefCount()
{
Verify(m_Instance != 0);
Verify(m_Instance->m_RefCount > 0);
--(m_Instance->m_RefCount);
if (m_Instance->m_RefCount == 0)
{
delete m_Instance;
m_Instance = 0;
}
}
UserConstants* UserConstants::Instance()
{
return (m_Instance);
}
Stuff::Scalar UserConstants::GetMultiplier_Tonnage(Stuff::Scalar tonnage) const
{
return (FindCategorizedValue(tonnage,mech_tiny,mech_huge,if_tiny));
}
Stuff::Scalar UserConstants::GetMultiplier_CrouchState(bool fCrouched) const
{
if (fCrouched == true)
{
return (Get(if_crouched));
}
return (1.0f);
}
Stuff::Scalar UserConstants::GetMultiplier_Speed(Stuff::Scalar kph) const
{
return (FindCategorizedValue(kph,speed_stopped,speed_maximum,if_stopped));
}
Stuff::Scalar UserConstants::GetMultiplier_ShooterSpeed(Stuff::Scalar kph) const
{
return (FindCategorizedValue(kph,speed_stopped,speed_maximum,if_shooter_stopped));
}
Stuff::Scalar UserConstants::GetMultiplier_Distance(Stuff::Scalar distance) const
{
return (FindCategorizedValue(distance,distance_adjacent,distance_very_far,if_adjacent));
}
UserConstants::ID UserConstants::FindCategory(Stuff::Scalar user_value, UserConstants::ID first, UserConstants::ID last) const
{
Verify(last > first);
Verify(first >= ID_FIRST);
Verify(last <= ID_LAST);
UserConstants::ID category = first;
{for (int i = first;
i < last;
++i)
{
if (user_value > Get((UserConstants::ID)i))
{
category = (UserConstants::ID)((int)category + 1);
}
else
{
break;
}
}}
Verify(category >= first);
Verify(category <= last);
return (category);
}
Stuff::Scalar UserConstants::FindCategorizedValue(Stuff::Scalar user_value, UserConstants::ID first, UserConstants::ID last, UserConstants::ID first_lookup) const
{
Verify((first_lookup > last) || (first_lookup < first));
Verify(first_lookup >= ID_FIRST);
Verify(first_lookup <= ID_LAST);
UserConstants::ID category = FindCategory(user_value,first,last);
int difference = category - first;
UserConstants::ID lookup = (UserConstants::ID)(first_lookup + difference);
return (Get(lookup));
}
Stuff::Scalar UserConstants::GetMultiplier_Bearing(const Stuff::Point3D& self, const Stuff::LinearMatrix4D& shooting_at, Stuff::Scalar target_speed) const
{
Stuff::Point3D delta;
delta.Subtract(self,(Stuff::Point3D)shooting_at);
if (delta.GetLengthSquared() == 0)
{
return (1);
}
Stuff::UnitVector3D delta_normalized(delta);
Stuff::UnitVector3D local_forward;
shooting_at.GetLocalForwardInWorld(&local_forward);
Stuff::Scalar bearing = delta_normalized * local_forward;
if (bearing < 0)
{
bearing = -bearing;
}
if (bearing > 1)
{
bearing = 1;
}
Stuff::Scalar multiplier = bearing + ((1 - bearing) * Get(if_bearing_90));
switch (FindCategory(target_speed,speed_stopped,speed_maximum))
{
case speed_stopped:
case speed_slow:
{
break;
}
case speed_medium:
case speed_fast:
{
multiplier *= multiplier;
break;
}
case speed_maximum:
{
multiplier *= multiplier;
multiplier *= multiplier;
break;
}
default:
{
Verify(!"Should never get here.");
break;
}
}
return (multiplier);
}
Stuff::Scalar UserConstants::GetMultiplier_TurnRate(Stuff::Scalar yaw_demand) const
{
Verify(yaw_demand >= 0);
Verify(yaw_demand <= 1);
return ((1 - yaw_demand) + (yaw_demand * Get(if_turning)));
}
@@ -0,0 +1,386 @@
#pragma once
#ifndef AI_USERCONSTANTS_HPP
#define AI_USERCONSTANTS_HPP
#include <Stuff\Scalar.hpp>
#include <Stuff\Auto_Ptr.hpp>
#pragma warning(push)
#include <stlport\string>
#pragma warning(pop)
#include <Adept\Resource.hpp>
#include <Stuff\NotationFile.hpp>
#include <Stuff\Matrix.hpp>
namespace Stuff
{
class Page;
};
namespace MW4AI
{
class UserConstants
{
public:
enum ID
{
entropy_regeneration_at_0 = 0, // change ID_FIRST if you change this
entropy_regeneration_at_100,
building_ff_multiplier,
shutdown,
internal_armor_breached,
fall_down,
first_arm_hit,
second_arm_hit,
first_leg_hit,
mood_squad_dead_unit_multiplier,
interval_multiplier_desperate,
interval_multiplier_defensive,
interval_multiplier_neutral,
interval_multiplier_aggressive,
interval_multiplier_brutal,
skew_at_0,
skew_at_100,
skew_inc_at_0,
skew_inc_at_100,
speed_stopped,
speed_slow,
speed_medium,
speed_fast,
speed_maximum,
mech_tiny,
mech_small,
mech_medium,
mech_large,
mech_huge,
distance_adjacent,
distance_near,
distance_medium,
distance_far,
distance_very_far,
if_crouched,
if_tiny,
if_small,
if_medium_size,
if_large,
if_huge,
if_stopped,
if_slow,
if_medium_speed,
if_fast,
if_maximum,
if_shooter_stopped,
if_shooter_slow,
if_shooter_medium,
if_shooter_fast,
if_shooter_maximum,
if_adjacent,
if_near,
if_medium_range,
if_far,
if_very_far,
if_firing_with_one_arm,
if_turning,
if_bearing_90,
min_evade_when_missiles_shot_at_me,
max_evade_when_missiles_shot_at_me,
min_evade_when_targeted,
max_evade_when_targeted,
min_evade_by_jumping,
max_evade_by_jumping,
min_evade_by_throttle_override,
max_evade_by_throttle_override,
min_evade_by_crouching,
max_evade_by_crouching,
min_jump_if_rushed,
max_jump_if_rushed,
min_opportunity_fire,
max_opportunity_fire,
min_look_left_or_right,
max_look_left_or_right,
min_look_time_at_0,
min_look_time_at_100,
min_dont_use_limited_ammo_vs_non_mechs,
max_dont_use_limited_ammo_vs_non_mechs,
min_vulnerable_leg_hiding,
max_vulnerable_leg_hiding,
min_mood_vulnerable_leg_hiding,
max_mood_vulnerable_leg_hiding,
min_throttle_override,
torso_twist_multiplier_at_0,
torso_twist_use_full_multiplier,
switch_to_random_component_picking,
switch_to_most_damaged_component_picking,
min_prefer_water,
max_prefer_water,
jump_wait_time_at_0,
jump_wait_time_at_100,
evade_focus_time_at_0,
evade_focus_time_at_100,
lancemate_can_attack_radius,
max_lancemate_distance_from_leader,
max_defend_distance_from_target,
jump_and_shoot_hover_height_min,
jump_and_shoot_hover_height_max,
max_fire_cheat_angle,
max_airplane_fire_cheat_angle,
max_turret_fire_cheat_angle,
min_tactic_time,
min_elite_joust,
max_elite_joust,
min_mood_joust,
max_mood_joust,
min_elite_rush,
max_elite_rush,
min_mood_rush,
max_mood_rush,
min_elite_hitandrun,
max_elite_hitandrun,
min_mood_hitandrun,
max_mood_hitandrun,
min_elite_rear,
max_elite_rear,
min_mood_rear,
max_mood_rear,
min_elite_circle,
max_elite_circle,
min_mood_circle,
max_mood_circle,
min_elite_retreat,
max_elite_retreat,
min_mood_retreat,
max_mood_retreat,
min_elite_dfa,
max_elite_dfa,
min_mood_dfa,
max_mood_dfa,
leg_up_slope,
leg_down_slope,
track_up_slope,
track_down_slope,
wheel_up_slope,
wheel_down_slope,
hover_up_slope,
hover_down_slope,
leg_dirt_cost,
leg_rock_cost,
leg_steel_cost,
leg_blacktop_cost,
leg_glass_cost,
leg_brick_cost,
leg_grass_cost,
leg_wood_cost,
leg_tree_cost,
leg_swamp_cost,
leg_concrete_cost,
leg_rough_cost,
leg_snow_cost,
leg_underbrush_cost,
leg_shallowwater_cost,
leg_midwater_cost,
leg_oceanicwater_cost,
leg_desert_cost,
leg_flatswamp_cost,
leg_thickswamp_cost,
// MSL 5.03 Lava
leg_crackedlava_cost,
leg_openlava_cost,
track_dirt_cost,
track_rock_cost,
track_steel_cost,
track_blacktop_cost,
track_glass_cost,
track_brick_cost,
track_grass_cost,
track_wood_cost,
track_tree_cost,
track_swamp_cost,
track_concrete_cost,
track_rough_cost,
track_snow_cost,
track_underbrush_cost,
track_shallowwater_cost,
track_midwater_cost,
track_oceanicwater_cost,
track_desert_cost,
track_flatswamp_cost,
track_thickswamp_cost,
// MSL 5.03 Lava
track_crackedlava_cost,
track_openlava_cost,
wheel_dirt_cost,
wheel_rock_cost,
wheel_steel_cost,
wheel_blacktop_cost,
wheel_glass_cost,
wheel_brick_cost,
wheel_grass_cost,
wheel_wood_cost,
wheel_tree_cost,
wheel_swamp_cost,
wheel_concrete_cost,
wheel_rough_cost,
wheel_snow_cost,
wheel_underbrush_cost,
wheel_shallowwater_cost,
wheel_midwater_cost,
wheel_oceanicwater_cost,
wheel_desert_cost,
wheel_flatswamp_cost,
wheel_thickswamp_cost,
// MSL 5.03 Lava
wheel_crackedlava_cost,
wheel_openlava_cost,
hover_dirt_cost,
hover_rock_cost,
hover_steel_cost,
hover_blacktop_cost,
hover_glass_cost,
hover_brick_cost,
hover_grass_cost,
hover_wood_cost,
hover_tree_cost,
hover_swamp_cost,
hover_concrete_cost,
hover_rough_cost,
hover_snow_cost,
hover_underbrush_cost,
hover_shallowwater_cost,
hover_midwater_cost,
hover_oceanicwater_cost,
hover_desert_cost,
hover_flatswamp_cost,
hover_thickswamp_cost,
// MSL 5.03 Lava
hover_crackedlava_cost,
hover_openlava_cost,
objective_display_time,
default_pilot,
default_gunnery,
default_elite,
default_minheat,
default_maxheat,
default_sensor,
default_blind,
default_longrange,
default_shortrange,
default_addpilot,
default_addgunnery,
default_addelite,
max_skill_add,
max_fog_dist_to_use_blind_skill,
damage_amount,
damage_mod,
fall_damage_minus,
fall_splash_multiplier,
min_fall_timer,
low_water_mod,
mid_water_mod,
concrete_mod,
gimped_mod,
double_damage_mod,
moving_fast_mod,
jump_recover_mod,
max_water_jump,
eject_chance_for_non_lancemate,
eject_chance_for_lancemate,
eject_chance_ok_when_ejected,
eject_chance_injured_when_ejected,
friend_easy_gunnery_mod,
friend_medium_gunnery_mod,
friend_hard_gunnery_mod,
friend_impossible_gunnery_mod,
enemy_easy_gunnery_mod,
enemy_medium_gunnery_mod,
enemy_hard_gunnery_mod,
enemy_impossible_gunnery_mod,
neutral_easy_gunnery_mod,
neutral_medium_gunnery_mod,
neutral_hard_gunnery_mod,
neutral_impossible_gunnery_mod,
collision_mech_light_damage,
collision_mech_light_slowdown,
collision_mech_light_building_speed,
collision_mech_light_mech_speed,
collision_mech_medium_tonage,
collision_mech_medium_damage,
collision_mech_medium_slowdown,
collision_mech_medium_building_speed,
collision_mech_medium_mech_speed,
collision_mech_heavy_tonage,
collision_mech_heavy_damage,
collision_mech_heavy_slowdown,
collision_mech_heavy_building_speed,
collision_mech_heavy_mech_speed,
collision_dfa_speed,
collision_dfa_damage_given,
collision_dfa_damage_taken,
collision_tank_slowdown,
throttle_center,
throttle_dead_low,
throttle_dead_high,
chance_salvage,
mouse_min_change,
mouse_interia_mult,
mouse_max_mouse,
flying_turn_rate,
dont_use_this_id // Insert all user constants BEFORE this one
};
enum
{
ID_FIRST = entropy_regeneration_at_0,
ID_LAST = dont_use_this_id-1,
ID_MOVE_COST_START = leg_dirt_cost,
// MSL 5.03 Lava
// ID_MOVE_COST_LAST = hover_thickswamp_cost
ID_MOVE_COST_LAST = hover_openlava_cost
};
UserConstants();
~UserConstants();
Stuff::Scalar Get(ID id) const;
static void IncrementRefCount();
static void DecrementRefCount();
static UserConstants* Instance();
Stuff::Scalar GetMultiplier_Tonnage(Stuff::Scalar tonnage) const;
Stuff::Scalar GetMultiplier_CrouchState(bool fCrouched) const;
Stuff::Scalar GetMultiplier_Speed(Stuff::Scalar kph) const;
Stuff::Scalar GetMultiplier_ShooterSpeed(Stuff::Scalar kph) const;
Stuff::Scalar GetMultiplier_Distance(Stuff::Scalar distance) const;
Stuff::Scalar GetMultiplier_Bearing(const Stuff::Point3D& self, const Stuff::LinearMatrix4D& shooting_at, Stuff::Scalar target_speed) const;
Stuff::Scalar GetMultiplier_TurnRate(Stuff::Scalar yaw_demand) const;
UserConstants::ID FindCategory(Stuff::Scalar user_value, MW4AI::UserConstants::ID first, MW4AI::UserConstants::ID last) const;
private:
Stuff::Scalar m_Value[ID_LAST - ID_FIRST + 1];
int m_RefCount;
void LookUpValue(const std::string& header_name, const std::string& item_name, int value_index);
static UserConstants* m_Instance;
Stuff::Scalar FindCategorizedValue(Stuff::Scalar user_value, ID first, ID last, ID first_lookup) const;
private:
Adept::Resource m_Resource;
Stuff::Auto_Ptr<Stuff::NotationFile> m_NotationFile;
Stuff::Page* m_LastPage;
};
};
#endif // AI_USERCONSTANTS_HPP
File diff suppressed because it is too large Load Diff
+99
View File
@@ -0,0 +1,99 @@
#pragma once
#ifndef AI_WEAPONS_HPP
#define AI_WEAPONS_HPP
#include <Stuff\Scalar.hpp>
#pragma warning (push)
#include <stlport\vector>
#pragma warning (pop)
#include "AI_HitTesting.hpp"
namespace Adept
{
class Entity__CollisionQuery;
};
namespace MechWarrior4
{
class MWObject;
class Weapon;
};
namespace Adept
{
class DamageObject;
};
namespace MW4AI
{
Stuff::Scalar GetMaxWeaponDistance(MechWarrior4::Weapon& weapon);
// Stuff::Scalar GetMinWeaponDistance(MechWarrior4::Weapon& weapon);
Stuff::Scalar GetMaxWeaponDistance(MechWarrior4::MWObject& vehicle);
Stuff::Scalar GetMinWeaponDistance(MechWarrior4::MWObject& vehicle);
void SetWeaponsToMaxWaitValue(MechWarrior4::MWObject& object);
bool HasAnyUnlimitedAmmoWeapons(MechWarrior4::MWObject& object);
bool HasAnyProjectileWeapons(MechWarrior4::MWObject& object);
bool WeaponCanFire(MechWarrior4::Weapon& weapon,
Stuff::Scalar line_length = 0,
Stuff::Time min_delay = 0,
Stuff::Time max_delay = 0);
bool GetWeaponsThatCanFire(std::vector<Weapon *>& weapons,
bool can_spend_ammo,
Stuff::Time min_delay,
Stuff::Time max_delay);
bool GetWeaponsThatCanFireAt(std::vector<Weapon *>& weapons,
const Stuff::Point3D& aim);
bool GetWeaponsThatCanFireFrom(std::vector<Weapon *>& weapons,
FireSource fire_source);
bool MightHitFriendlies(const Stuff::Line3D& line,
Stuff::Scalar line_length,
MechWarrior4::MWObject& shooter,
MechWarrior4::MWObject* ignore = 0);
bool AnyWeaponReady(MechWarrior4::MWObject& vehicle,
Stuff::Time min_delay = 0,
Stuff::Time max_delay = 0);
bool AnyWeaponNotReady(MechWarrior4::MWObject& vehicle,
Stuff::Time min_delay = 0,
Stuff::Time max_delay = 0);
unsigned int NumWeapons(MechWarrior4::MWObject& vehicle);
unsigned int NumWeaponsReady(MechWarrior4::MWObject& vehicle,
Stuff::Time min_delay = 0,
Stuff::Time max_delay = 0);
bool WeaponIsArmWeapon(const MechWarrior4::Weapon& weapon, bool left);
Stuff::LinearMatrix4D WeaponSiteLocalToWorld(const MechWarrior4::Weapon& weapon);
typedef std::vector<Adept::DamageObject*> component_vector;
void DamageObjectChainToVector(Stuff::SortedChainOf<Adept::DamageObject*,int>& chain, component_vector& v);
Adept::DamageObject* GetComponent_MostDamaged(MechWarrior4::MWObject& who, const component_vector& v);
Adept::DamageObject* GetComponent_LeastDamaged(const component_vector& v);
Adept::DamageObject* GetComponent_Random(const component_vector& v);
Adept::DamageObject* GetComponent_TorsoThenTopDown(const component_vector& v);
void GetLeftmostAndRightmostWeapons(MechWarrior4::MWObject& object,
std::vector<MechWarrior4::Weapon*>& weapons);
Stuff::Point3D GetWeaponCenter(MechWarrior4::MWObject& object);
void SetRaySourceToBestComponent(Adept::Entity__CollisionQuery& query);
};
#endif AI_WEAPONS_HPP
+192
View File
@@ -0,0 +1,192 @@
#include "MW4Headers.hpp"
#include "AMS.hpp"
#include "SubsystemClassData.hpp"
#include "vehicleinterface.hpp"
#include "mechlabheaders.h"
//#############################################################################
//############################### AMS ###################################
//#############################################################################
AMS::ClassData*
AMS::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AMS::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
AMSClassID,
"MechWarrior4::AMS",
BaseClass::DefaultData,
0, NULL,
(Entity::Factory)Make,
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
ExecutionStateEngine::DefaultData,
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
NULL,
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
(Entity::GameModel::ModelSave)GameModel::SaveGameModel,
(Subsystem::StreamCreate) CreateStream
);
Register_Object(DefaultData);
DIRECT_GAME_MODEL_ATTRIBUTE(
AMS__GameModel,
AMSEffectResource,
amsEffectResource,
ResourceID
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AMS::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AMS*
AMS::Make(
CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(message);
gos_PushCurrentHeap(Heap);
AMS *new_entity =
new AMS(DefaultData, message, base_id, NULL);
gos_PopCurrentHeap();
Check_Object(new_entity);
return new_entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AMS::AMS(
ClassData *class_data,
CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::Element *element
):
Subsystem(class_data, message, base_id, element)
{
Check_Object(message);
ammoCount = message->ammoCount;
maxAmmoCount = ammoCount;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Replicator::CreateMessage*
AMS::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
{
Check_Object(this);
Check_Object(stream);
stream->AllocateBytes(sizeof(CreateMessage));
Subsystem::SaveMakeMessage(stream, res_file);
CreateMessage *message =
Cast_Pointer(CreateMessage*, stream->GetPointer());
message->messageLength = sizeof(*message);
message->ammoCount = ammoCount;
return message;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AMS::~AMS()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AMS::DestroySubsystem()
{
Check_Object(this);
#if 0
MWObject *mw_object = GetParentVehicle();
Check_Object(mw_object);
Verify(mw_object->IsDerivedFrom(Vehicle::DefaultData));
Vehicle *vehicle = Cast_Object(Vehicle *, mw_object);
vehicle->DestroyAMS();
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AMS::SubtractAmmo(int count)
{
Check_Object(this);
if (!Network::GetInstance()->AmIServer())
return;
if(ammoCount == -1)
return;
if(GetParentVehicle()->vehicleInterface)
{
const GameModel *model = GetGameModel();
switch (model->itemID)
{
case Sub_AMS:
GetParentVehicle()->vehicleInterface->ReactToEvent (VehicleInterface::AMS_ENGAGED);
break;
case Sub_LAMS:
GetParentVehicle()->vehicleInterface->ReactToEvent (VehicleInterface::LAMS_ENGAGED);
break;
#if defined(LAB_ONLY)
default:
PAUSE (("unknown type of ams"));
break;
#endif
}
}
ammoCount -= count;
Min_Clamp(ammoCount, 0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AMS::CreateStream(ResourceID data_list, MemoryStream *stream)
{
Check_Pointer(stream);
stream->AllocateBytes(sizeof(AMS__CreateMessage));
Subsystem::CreateStream(data_list, stream);
AMS__CreateMessage *create_message = Cast_Pointer(
AMS__CreateMessage *, stream->GetPointer());
create_message->ammoCount = -1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AMS::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
+214
View File
@@ -0,0 +1,214 @@
#pragma once
#include "MW4.hpp"
#include "Subsystem.hpp"
namespace MechWarrior4
{
class Vehicle;
//##########################################################################
//################## AMS::CreateMessage ##############################
//##########################################################################
class AMS__CreateMessage:
public Subsystem__CreateMessage
{
public:
typedef Subsystem__CreateMessage BaseClass;
int
ammoCount;
AMS__CreateMessage(
size_t length,
int priority,
int message_flags,
Stuff::RegisteredClass::ClassID class_id,
int replicator_flags,
const ResourceID& instance_id,
const Stuff::LinearMatrix4D &creation_matrix,
Stuff::Scalar age,
int execution_state,
int name_id,
int entity_alignment,
int subsystem_index,
BYTE location_id,
int critical_hits,
int ammo_count
):
Subsystem__CreateMessage(
length,
priority,
message_flags,
class_id,
replicator_flags,
instance_id,
creation_matrix,
age,
execution_state,
name_id,
entity_alignment,
subsystem_index,
location_id,
critical_hits
),
ammoCount(ammo_count)
{}
static void
ConstructCreateMessage(Script *script);
};
//##########################################################################
//########################### AMS GameModel ###########################
//##########################################################################
class AMS__GameModel:
public Subsystem::GameModel
{
public:
typedef Subsystem::GameModel BaseClass;
Adept::ResourceID
amsEffectResource;
enum {
AMSEffectResourceAttributeID = Subsystem__GameModel::NextAttributeID,
NextAttributeID
};
static bool
ReadAndVerify(
AMS__GameModel *model,
ModelAttributeEntry *attribute_entry,
const char *data,
char **error,
int error_buffer = 128
);
static void
ConstructGameModel(Script *script);
};
typedef Subsystem__ClassData AMS__ClassData;
typedef Subsystem__Message AMS__Message;
typedef Subsystem__ExecutionStateEngine AMS__ExecutionStateEngine;
//##########################################################################
//########################### AMS #####################################
//##########################################################################
class AMS:
public Subsystem
{
public:
static void
InitializeClass();
static void
TerminateClass();
typedef Subsystem BaseClass;
//##########################################################################
// Inheritance support
//
public:
typedef AMS__ClassData ClassData;
typedef AMS__GameModel GameModel;
typedef AMS__Message Message;
typedef AMS__ExecutionStateEngine ExecutionStateEngine;
typedef AMS__CreateMessage CreateMessage;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Run-time Construction and Destruction Support
//
public:
static AMS*
Make(
CreateMessage *message,
ReplicatorID *base_id
);
Adept::Replicator::CreateMessage*
SaveMakeMessage(MemoryStream *stream, Adept::ResourceFile *res_file);
void
SaveInstanceText(Stuff::Page *page);
static void
CreateStream(
Adept::ResourceID data_list,
Stuff::MemoryStream *stream
);
protected:
AMS(
ClassData *class_data,
CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::Element *element
);
~AMS();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class Data & Game Model Support
//
public:
const GameModel*
GetGameModel()
{return Cast_Pointer(const GameModel*, gameModelResource.GetPointer());}
public:
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Simulation Support
//
public:
void
DestroySubsystem();
bool
DoesHaveAmmo()
{
Check_Object(this);
if (ammoCount == -1)
return true;
return ammoCount != 0;
}
int GetAmmo()
{Check_Object(this); return ammoCount;}
void
SetAmmo(int ammo_number)
{Check_Object(this); ammoCount = ammo_number;};
int GetMaxAmmoCount()
{Check_Object(this); return ammoCount;};
void
SubtractAmmo(int count);
int
ammoCount;
int
maxAmmoCount;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Test Support
//
public:
void
TestInstance() const;
};
}
+138
View File
@@ -0,0 +1,138 @@
//===========================================================================//
// File: Weapon_Tool.cpp
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 09/09/98 JSE Inital base class based off of Shadowrun/Adept
// 09/24/98 BDB Inital Weapon subsystem class based off of Subsystem_Tool.cpp
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include "MW4Headers.hpp"
#include "AMS.hpp"
#include "MWTool.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AMS__CreateMessage::ConstructCreateMessage(Script *script)
{
Check_Object(script);
//
//--------------
// Set up stream
//--------------
//
MemoryStream *message_stream = script->messageStream;
Check_Object(message_stream);
message_stream->AllocateBytes(sizeof(AMS__CreateMessage));
BaseClass::ConstructCreateMessage(script);
AMS__CreateMessage *message =
Cast_Pointer(
AMS__CreateMessage*,
message_stream->GetPointer()
);
message->messageLength = sizeof(*message);
//
//---------------------------
// Point at the notation file
//---------------------------
//
Page *page = script->instancePage;
Check_Object(page);
Check_Object(Tool::Instance);
int ammo_count;
if(page->GetEntry("AmmoCount", &ammo_count))
{
message->ammoCount = ammo_count;
}
else
{
message->ammoCount = -1;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AMS::SaveInstanceText(Page *instance_page)
{
Check_Object(this);
BaseClass::SaveInstanceText(instance_page);
instance_page->SetEntry("AmmoCount", ammoCount);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AMS__GameModel::ConstructGameModel(Script *script)
{
Check_Object(script);
//
//--------------
// Set up stream
//--------------
//
MemoryStream *model_stream = script->modelStream;
Check_Object(model_stream);
model_stream->AllocateBytes(sizeof(AMS__GameModel));
BaseClass::ConstructGameModel(script);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
AMS__GameModel::ReadAndVerify(
AMS__GameModel *model,
ModelAttributeEntry *attribute_entry,
const char *data,
char **error,
int error_buffer
)
{
Check_Object(attribute_entry);
bool result = false;
bool valid_data = (*data != '\0');
//
//----------------------------------------
//Read in the values from the data entered
//----------------------------------------
//
result =
BaseClass::ReadAndVerify(
model,
attribute_entry,
data,
error,
error_buffer
);
//
//---------------------------
//Verify all the model values
//---------------------------
//
switch(attribute_entry->attributeID)
{
case AMSEffectResourceAttributeID:
{
if(!valid_data)
{
ResourceID value = ResourceID::Null;
attribute_entry->SetValue(model, (void *)&value);
result = true;
}
break;
}
}
return result;
}
+199
View File
@@ -0,0 +1,199 @@
//***************************************************************************
//
// ABL.H
//
//***************************************************************************
#ifndef ABL_H
#define ABL_H
#include<Stuff\Stuff.hpp>
#pragma warning (disable:4284)
#pragma warning (push)
#include <stlport\string>
#pragma warning (pop)
extern bool gShowScriptErrors;
#define ablREPORT(exp,Message) {if (gShowScriptErrors && !(exp)) {PAUSE((Message));}}
namespace ABL
{
char *ablERROR(char *str);
const int MAX_ABL_ERROR_STR = 255;
const int ABL_DETAIL_ERROR_STRING_SIZE = 2048;
class ABLError
{
protected:
char m_ErrorString[MAX_ABL_ERROR_STR];
char m_ErrorFile[MAX_ABL_ERROR_STR];
static char m_DetailErrorString[ABL_DETAIL_ERROR_STRING_SIZE];
int m_Line;
int m_Code;
public:
ABLError (char *str,char *file,int line,int code)
{
Str_Copy (m_ErrorString,str,MAX_ABL_ERROR_STR);
Str_Copy (m_ErrorFile,file,MAX_ABL_ERROR_STR);
m_Line = line;
m_Code = code;
}
ABLError ()
{
m_ErrorString[0] = 0;
m_ErrorFile[0] = 0;
m_Line = 0;
m_Code = 0;
}
~ABLError ()
{
}
const char *String (void) const
{
return m_ErrorString;
}
const char *File (void) const
{
return m_ErrorFile;
}
int Line (void) const
{
return m_Line;
}
int Code (void) const
{
return m_Code;
}
char *Details (void)
{
char line[25];
Str_Copy (m_DetailErrorString," ",ABL_DETAIL_ERROR_STRING_SIZE);
Str_Copy (m_DetailErrorString,m_ErrorFile,ABL_DETAIL_ERROR_STRING_SIZE);
Str_Cat (m_DetailErrorString,"(",ABL_DETAIL_ERROR_STRING_SIZE);
itoa (m_Line,line,10);
Str_Cat (m_DetailErrorString,line,ABL_DETAIL_ERROR_STRING_SIZE);
Str_Cat (m_DetailErrorString,")",ABL_DETAIL_ERROR_STRING_SIZE);
Str_Cat (m_DetailErrorString,": ",ABL_DETAIL_ERROR_STRING_SIZE);
Str_Cat (m_DetailErrorString,m_ErrorString,ABL_DETAIL_ERROR_STRING_SIZE);
return m_DetailErrorString;
}
void String (const char *str)
{
Str_Copy (m_ErrorString,str,MAX_ABL_ERROR_STR);
}
void File (const char *file)
{
Str_Copy (m_ErrorFile,file,MAX_ABL_ERROR_STR);
}
void Line (const int line)
{
m_Line = line;
}
void Code (const int code)
{
m_Code = code;
}
};
}
#include "ablgen.h"
#include "ablexec.h"
#include "ablsymt.h"
#include "ablenv.h"
#ifndef ABLDBUG_H
#include "abldbug.h"
#endif
#ifndef GAMEOS_HPP
#include <gameos\gameos.hpp>
#endif
#ifndef STUFF_HPP
#include <stuff\stuff.hpp>
#endif
#include "mw4headers.hpp"
#include "ai.hpp"
#include "mwobject.hpp"
namespace ABL
{
//***************************************************************************
extern MechWarrior4::AI *CurWarrior;
//#define DEBUGGING
void ABLi_init (unsigned long symTableHeapSize = 102400,
unsigned long stackHeapSize = 40960,
unsigned long codeHeapSize = 102400,
unsigned long runtimeStackSize = 20480,
unsigned long maxCodeBufferSize = 10240,
unsigned long maxRegisteredModules = 200,
unsigned long maxStaticVariables = 100,
void (*callback)(char* s) = NULL,
bool debugInfo = false,
bool debug = false,
bool profile = false);
inline void SetABLExecFunction (ABLExecFunctionType func)
{
Check_Pointer (func);
routineExecFunction = func;
}
ABLParamPtr ABLi_createParamList (long numParameters);
void ABLi_setIntegerParam (ABLParamPtr paramList, long index, long value);
void ABLi_setRealParam (ABLParamPtr paramList, long index, float value);
void ABLi_deleteParamList (ABLParamPtr paramList);
long ABLi_preProcess (char* sourceFileName,
ABLError *error,
long* numErrors = NULL,
long* numLinesProcessed = NULL,
long* numFilesProcessed = NULL,
bool printLines = false);
// long ABLi_preProcessFromParams(const std::string& params, const std::string& script_suffix);
long ABLi_loadLibrary (char* sourceFileName,
ABLError *error,
long* numErrors = NULL,
long* numLinesProcessed = NULL,
long* numFilesProcessed = NULL,
bool printLines = false);
long ABLi_execute (SymTableNodePtr moduleIdPtr,
SymTableNodePtr functionIdPtr = NULL,
ABLParamPtr paramList = NULL,
StackItemPtr returnVal = NULL);
long ABLi_deleteModule (SymTableNodePtr moduleIdPtr);
ABLModulePtr ABLi_getModule (long id);
DebuggerPtr ABLi_getDebugger (void);
void ABLi_saveEnvironment (FilePtr ablFile);
void ABLi_loadEnvironment (FilePtr ablFile, bool malloc);
void ABLi_close (void);
bool ABLi_enabled (void);
//***************************************************************************
}
#endif
+132
View File
@@ -0,0 +1,132 @@
#include "MW4Headers.hpp"
#include "AblProfiler.hpp"
using namespace ABL;
namespace ABL
{
void ABL_AddToProfileLog (char* profileString);
};
Profiler* Profiler::m_Instance = 0;
Profiler* Profiler::Instance()
{
return (m_Instance);
}
Profiler::Profiler()
: m_Active(false)
{
Verify(m_Instance == 0);
m_Instance = this;
}
Profiler::~Profiler()
{
Verify(m_Instance == this);
SpewIt();
m_Instance = 0;
}
void Profiler::SetActive(bool active)
{
if (m_Active == active)
{
return;
}
m_Active = active;
if (m_Active == true)
{
m_PerFunctionTiming.clear();
m_PerModuleTiming.clear();
}
}
bool Profiler::GetActive() const
{
return (m_Active);
}
Profiler::CallInfo::CallInfo()
: total_time(0)
, total_calls(0)
{
}
void Profiler::NotifyFunctionCalled(double time,
const char* function_name,
const char* module_name)
{
AddTimeToCallInfoMap(time,function_name,m_PerFunctionTiming);
AddTimeToCallInfoMap(time,module_name,m_PerModuleTiming);
}
void Profiler::AddTimeToCallInfoMap(double time, const char* name, call_info_map& m)
{
m[name].total_time += time;
++(m[name].total_calls);
call_info_map::iterator i(m.find(name));
}
inline std::string DoubleToString(double d)
{
char buf[80];
sprintf(buf,"%.4f",d);
return (buf);
}
inline std::string IntToString(int i)
{
char buf[100];
sprintf(buf,"%d",i);
return (buf);
}
void Profiler::SpewIt() const
{
#if defined(LAB_ONLY)
SPEWALWAYS((0,"\n"));
{for (call_info_map::const_iterator i = m_PerFunctionTiming.begin();
i != m_PerFunctionTiming.end();
++i)
{
std::string s("Function: ");
s += (*i).first;
s += " Total Time: ";
s += DoubleToString((*i).second.total_time);
s += " Total Function Calls: ";
s += IntToString((*i).second.total_calls);
SPEWALWAYS((0,"%s",s.c_str()));
}}
SPEWALWAYS((0,"\n"));
{for (call_info_map::const_iterator i = m_PerModuleTiming.begin();
i != m_PerModuleTiming.end();
++i)
{
std::string s("Script: ");
s += (*i).first;
s += " Total Time: ";
s += DoubleToString((*i).second.total_time);
s += " Total Function Calls: ";
s += IntToString((*i).second.total_calls);
SPEWALWAYS((0,"%s",s.c_str()));
}}
SPEWALWAYS((0,"\n"));
#endif
}
@@ -0,0 +1,54 @@
#pragma once
#ifndef ABLPROFILER_HPP
#define ABLPROFILER_HPP
#pragma warning (push)
#include <stlport\map>
#include <stlport\string>
#pragma warning (pop)
namespace ABL
{
class Profiler
{
public:
Profiler();
~Profiler();
void SetActive(bool active);
bool GetActive() const;
void NotifyFunctionCalled(double time,
const char* function_name,
const char* module_name);
static Profiler* Instance();
private:
struct CallInfo
{
CallInfo();
double total_time;
int total_calls;
};
bool m_Active;
typedef std::map<std::string,CallInfo> call_info_map;
call_info_map m_PerFunctionTiming;
call_info_map m_PerModuleTiming;
void AddTimeToCallInfoMap(double time, const char* name, call_info_map& m);
void UpdateCallInfoMap(call_info_map& m);
void SpewIt() const;
static Profiler* m_Instance;
};
};
#endif // ABLPROFILER_HPP
File diff suppressed because it is too large Load Diff
+298
View File
@@ -0,0 +1,298 @@
//***************************************************************************
//
// ABLDBUG.H
//
//***************************************************************************
#ifndef ABLDBUG_H
#define ABLDBUG_H
#ifdef USE_IFACE
#ifndef AWINDOW_H
#include <awindow.h>
#endif
#endif
#ifndef DABLDBUG_H
#include "dabldbug.h"
#endif
#ifndef ABLENV_H
#include "ablenv.h"
#endif
namespace ABL
{
//***************************************************************************
typedef enum {
DEBUG_COMMAND_SET_MODULE,
DEBUG_COMMAND_TRACE,
DEBUG_COMMAND_STEP,
DEBUG_COMMAND_BREAKPOINT_SET,
DEBUG_COMMAND_BREAKPOINT_REMOVE,
DEBUG_COMMAND_WATCH_SET,
DEBUG_COMMAND_WATCH_REMOVE_ALL,
DEBUG_COMMAND_PRINT,
DEBUG_COMMAND_CONTINUE,
DEBUG_COMMAND_HELP,
DEBUG_COMMAND_INFO,
NUM_DEBUG_COMMANDS
} DebugCommandCode;
//***************************************************************************
typedef struct _Watch {
SymTableNodePtr idPtr;
bool store;
bool breakOnStore;
bool fetch;
bool breakOnFetch;
} Watch;
typedef Watch* WatchPtr;
class WatchManager {
protected:
long maxWatches;
long numWatches;
WatchPtr watches;
public:
void* operator new (size_t mySize);
void operator delete (void* us);
void init (void) {
maxWatches = 0;
maxWatches = 0;
watches = NULL;
}
long init (long max);
void destroy (void);
WatchManager (void) {
init();
}
~WatchManager (void) {
destroy();
}
WatchPtr add (SymTableNodePtr idPtr);
long remove (SymTableNodePtr idPtr);
long removeAll (void);
long setStore (SymTableNodePtr idPtr, bool state, bool breakToDebug = false);
long setFetch (SymTableNodePtr idPtr, bool state, bool breakToDebug = false);
bool getStore (SymTableNodePtr idPtr);
bool getFetch (SymTableNodePtr idPtr);
void print (void);
};
//---------------------------------------------------------------------------
class BreakPointManager {
protected:
long maxBreakPoints;
long numBreakPoints;
long* breakPoints;
public:
void* operator new (size_t mySize);
void operator delete (void* us);
void init (void) {
maxBreakPoints = 0;
numBreakPoints = 0;
breakPoints = NULL;
}
long init (long max);
void destroy (void);
BreakPointManager (void) {
init();
}
~BreakPointManager (void) {
destroy();
}
long add (long lineNumber);
long remove (long lineNumber);
long removeAll (void);
bool isBreakPoint (long lineNumber);
void print (void);
};
//---------------------------------------------------------------------------
#define WATCH_STORE_OFF 1
#define WATCH_STORE_ON 2
#define WATCH_FETCH_OFF 4
#define WATCH_FETCH_ON 8
#define WATCH_BREAK 16
class Debugger {
protected:
ABLModulePtr module; // Current executing module
WatchManagerPtr watchManager; // Current executing watch manager
BreakPointManagerPtr breakPointManager; // Current executing breakpt manager
ABLModulePtr debugModule; // Current module being debugged
bool enabled;
bool debugCommand;
bool halt;
bool trace;
bool step;
bool traceEntry;
bool traceExit;
bool atbreakpoint;
static char message[512];
void (*printCallback)(char* s);
public:
void* operator new (size_t mySize);
void operator delete (void* us);
void init (void);
long init (void (*callback)(char* s), ABLModulePtr _module);
void destroy (void);
void setCallback (void (*callback)(char* s))
{
printCallback = callback;
}
Debugger (void) {
init();
}
~Debugger (void) {
destroy();
}
void enable (void) {
enabled = true;
}
void disable (void) {
enabled = false;
}
bool isEnabled (void) {
return(enabled);
}
long print (char* s);
void setModule (ABLModulePtr _module);
long setWatch (long states);
long addBreakPoint (void);
long removeBreakPoint (void);
void sprintStatement (char* dest);
void sprintLineNumber (char* dest);
void sprintDataValue (char* dest, StackItemPtr data, TypePtr dataType);
long sprintSimpleValue (char* dest, SymTableNodePtr symbol);
long sprintArrayValue (char* dest, SymTableNodePtr symbol, char* subscriptString);
long sprintValue (char* dest, char* exprString);
long traceStatementExecution (void);
long traceRoutineEntry (SymTableNodePtr idPtr);
long traceRoutineExit (SymTableNodePtr idPtr);
long traceDataStore (SymTableNodePtr id, TypePtr idType, StackItemPtr target, TypePtr targetType);
long traceDataFetch (SymTableNodePtr id, TypePtr idType, StackItemPtr data);
void showValue (void);
void assignVariable (void);
void displayModuleInstanceRegistry (void);
void processCommand (long commandId, char* strParam1, long numParam1, ABLModulePtr moduleParam1);
void debugMode (void);
void AddActualParam (SymTableNodePtr formalIdPtr,StackItemPtr tos);
void EndActualParams (void);
void StartActualParams (SymTableNodePtr idPtr);
ABLModulePtr getDebugModule (void) {
return(debugModule);
}
};
//---------------------------------------------------------------------------
#ifdef USE_IFACE
class DebuggerWindow : public aTitleWindow {
public:
/*virtual*/ long init(long xPos, long yPos,long w, long h, char* t);
/*virtual*/ void destroy(void);
/*virtual*/ void resize(long w, long h);
};
//---------------------------------------------------------------------------
class ScrollingTextWindow : public aObject {
public:
long cWidth;
long cHeight;
public:
virtual void init (void);
virtual long init(long xPos, long yPos,long w, long h, char* t);
ScrollingTextWindow (void) {
init();
}
~ScrollingTextWindow (void) {
destroy();
}
virtual void handleEvent (aEvent* event);
virtual void draw (void);
virtual void resize (long w, long h);
virtual void print (char* s);
};
#endif
//***************************************************************************
}
#endif
+923
View File
@@ -0,0 +1,923 @@
//***************************************************************************
//
// ABLDECL.CPP
//
//***************************************************************************
#include "MW4Headers.hpp"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef ABLHEAP_H
#include "ablheap.h"
#endif
#ifndef ABLGEN_H
#include "ablgen.h"
#endif
#ifndef ABLERR_H
#include "ablerr.h"
#endif
#ifndef ABLSCAN_H
#include "ablscan.h"
#endif
#ifndef ABLSYMT_H
#include "ablsymt.h"
#endif
#ifndef ABLPARSE_H
#include "ablparse.h"
#endif
#ifndef ABLEXEC_H
#include "ablexec.h"
#endif
#ifdef USE_IFACE
#ifndef IFACE_H
#include <iface.h>
#endif
#endif
namespace ABL
{
//***************************************************************************
extern TokenCodeType curToken;
extern char wordString[];
extern Literal curLiteral;
extern SymTableNodePtr SymTableDisplay[];
extern long level;
extern TypePtr IntegerTypePtr;
extern TypePtr CharTypePtr;
extern TypePtr RealTypePtr;
extern TypePtr BooleanTypePtr;
extern TokenCodeType declarationStartList[];
extern TokenCodeType statementStartList[];
extern UserHeapPtr AblSymTableHeap;
extern UserHeapPtr AblStackHeap;
extern long eternalOffset;
extern long NumStaticVariables;
extern long MaxStaticVariables;
extern long* StaticVariablesSizes;
extern long* EternalVariablesSizes;
extern ABLModulePtr CurLibrary;
//***************************************************************************
TokenCodeType followRoutineList[] = {
TKN_SEMICOLON,
TKN_EOF,
TKN_NONE
};
TokenCodeType followDeclarationList[] = {
TKN_SEMICOLON,
TKN_IDENTIFIER,
TKN_EOF,
TKN_NONE
};
TokenCodeType followVariablesList[] = {
TKN_SEMICOLON,
TKN_IDENTIFIER,
TKN_EOF,
TKN_NONE
};
//-------------------------------------
// If we support record/struct types...
#if 0
TokenCodeType followFieldsList[] = {
TKN_SEMICOLON,
TKN_END,
TKN_IDENTIFIER,
TKN_EOF,
TKN_NONE
};
#endif
TokenCodeType followVarBlockList[] = {
TKN_FUNCTION,
TKN_CODE,
TKN_EOF,
TKN_NONE
};
TokenCodeType followDimensionList[] = {
TKN_COMMA,
TKN_RBRACKET,
//TKN_OF,
//TKN_SEMICOLON,
TKN_EOF,
TKN_NONE
};
TokenCodeType indexTypeStartList[] = {
TKN_IDENTIFIER,
TKN_NUMBER,
//TKN_STAR,
//TKN_STRING,
//TKN_LPAREN,
//TKN_MINUS,
//TKN_PLUS,
TKN_NONE
};
TokenCodeType followIndexesList[] = {
TKN_OF,
TKN_IDENTIFIER,
TKN_LPAREN,
//TKN_RECORD,
TKN_PLUS,
TKN_MINUS,
TKN_NUMBER,
//TKN_STRING,
TKN_SEMICOLON,
TKN_EOF,
TKN_NONE
};
//***************************************************************************
// MISC. routines
//***************************************************************************
/*inline*/
void ifTokenGet(TokenCodeType tokenCode)
{
if (curToken == tokenCode)
getToken();
}
//***************************************************************************
/*inline*/ void ifTokenGetElseError (TokenCodeType tokenCode, SyntaxErrorType errorCode)
{
if (curToken == tokenCode)
getToken();
else
syntaxError(errorCode);
}
//***************************************************************************
// DECLARATIONS routines
//***************************************************************************
void declarations (SymTableNodePtr routineIdPtr, long allowFunctions, long allowStates)
{
if (curToken == TKN_CONST)
{
getToken();
constDefinitions();
}
if (curToken == TKN_TYPE)
{
getToken();
typeDefinitions();
}
if (curToken == TKN_VAR)
{
getToken();
varDeclarations(routineIdPtr);
}
//---------------------------------------------------
// Loop to process all of the function definitions...
if (allowFunctions)
while (curToken == TKN_FUNCTION)
{
routine();
//---------------------
// Error synchronize...
synchronize(followRoutineList, declarationStartList, statementStartList);
if (curToken == TKN_SEMICOLON)
getToken();
else if (tokenIn(declarationStartList) || tokenIn(statementStartList))
syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
}
else if (curToken == TKN_FUNCTION)
syntaxError(ABL_ERR_SYNTAX_NO_FUNCTION_NESTING);
//---------------------------------------------------
// Loop to process all of the state definitions...
if (allowStates)
while (curToken == TKN_STATE)
{
state();
//---------------------
// Error synchronize...
synchronize(followRoutineList, declarationStartList, statementStartList);
if (curToken == TKN_SEMICOLON)
getToken();
else if (tokenIn(declarationStartList) || tokenIn(statementStartList))
syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
}
else if (curToken == TKN_STATE)
syntaxError(ABL_ERR_SYNTAX_NO_STATE_NESTING);
}
//***************************************************************************
// CONST routines
//***************************************************************************
void constDefinitions (void)
{
//-------------------------------------------------------
// Loop to process definitions separated by semicolons...
while (curToken == TKN_IDENTIFIER)
{
SymTableNodePtr constantIdPtr;
searchAndEnterLocalSymTable(constantIdPtr);
constantIdPtr->defn.key = DFN_CONST;
constantIdPtr->library = CurLibrary;
getToken();
ifTokenGetElseError(TKN_EQUAL, ABL_ERR_SYNTAX_MISSING_EQUAL);
doConst(constantIdPtr);
analyzeConstDefn(constantIdPtr);
//---------------------------------
// Error synchronize: should be a ;
synchronize(followDeclarationList, declarationStartList, statementStartList);
if (curToken == TKN_SEMICOLON)
getToken();
else if (tokenIn(declarationStartList) || tokenIn(statementStartList))
syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
}
}
//***************************************************************************
TypePtr makeStringType (long length)
{
TypePtr stringTypePtr = createType();
if (!stringTypePtr)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc stringType ");
stringTypePtr->form = FRM_ARRAY;
stringTypePtr->size = length;
stringTypePtr->typeIdPtr = NULL;
stringTypePtr->info.array.indexTypePtr = IntegerTypePtr;
stringTypePtr->info.array.elementTypePtr = CharTypePtr;
stringTypePtr->info.array.elementCount = length + 1;
return(stringTypePtr);
}
//***************************************************************************
void doConst (SymTableNodePtr constantIdPtr)
{
TokenCodeType sign = TKN_PLUS;
bool sawSign = false;
if ((curToken == TKN_PLUS) || (curToken == TKN_MINUS))
{
sign = curToken;
sawSign = true;
getToken();
}
//----------------------------------
// Numeric constant: real or integer
if (curToken == TKN_NUMBER)
{
if (curLiteral.type == LIT_INTEGER)
{
if (sign == TKN_PLUS)
constantIdPtr->defn.info.constant.value.integer = curLiteral.value.integer;
else
constantIdPtr->defn.info.constant.value.integer = -(curLiteral.value.integer);
constantIdPtr->typePtr = setType(IntegerTypePtr);
}
else
{
if (sign == TKN_PLUS)
constantIdPtr->defn.info.constant.value.real = curLiteral.value.real;
else
constantIdPtr->defn.info.constant.value.real = -(curLiteral.value.real);
constantIdPtr->typePtr = setType(RealTypePtr);
}
}
else if (curToken == TKN_IDENTIFIER)
{
SymTableNodePtr idPtr = NULL;
searchAllSymTables(idPtr);
if (!idPtr)
syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER);
else if (idPtr->defn.key != DFN_CONST)
syntaxError(ABL_ERR_SYNTAX_NOT_A_CONSTANT_IDENTIFIER);
else if (idPtr->typePtr == IntegerTypePtr)
{
if (sign == TKN_PLUS)
constantIdPtr->defn.info.constant.value.integer = idPtr->defn.info.constant.value.integer;
else
constantIdPtr->defn.info.constant.value.integer = -(idPtr->defn.info.constant.value.integer);
constantIdPtr->typePtr = setType(IntegerTypePtr);
}
else if (idPtr->typePtr == CharTypePtr)
{
if (sawSign)
syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
//if (sign == TKN_PLUS)
constantIdPtr->defn.info.constant.value.character = idPtr->defn.info.constant.value.character;
//else
// constantIdPtr->defn.info.constant.value.character = -(idPtr->defn.info.constant.value.character);
constantIdPtr->typePtr = setType(CharTypePtr);
}
else if (idPtr->typePtr == RealTypePtr)
{
if (sign == TKN_PLUS)
constantIdPtr->defn.info.constant.value.real = idPtr->defn.info.constant.value.real;
else
constantIdPtr->defn.info.constant.value.real = -(idPtr->defn.info.constant.value.real);
constantIdPtr->typePtr = setType(RealTypePtr);
}
else if (((Type*)(idPtr->typePtr))->form == FRM_ENUM)
{
if (sawSign)
syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
constantIdPtr->defn.info.constant.value.integer = idPtr->defn.info.constant.value.integer;
constantIdPtr->typePtr = setType(idPtr->typePtr);
}
else if (((TypePtr)(idPtr->typePtr))->form == FRM_ARRAY)
{
if (sawSign)
syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
constantIdPtr->defn.info.constant.value.stringPtr = idPtr->defn.info.constant.value.stringPtr;
constantIdPtr->typePtr = setType(idPtr->typePtr);
}
}
else if (curToken == TKN_STRING)
{
if (sawSign)
syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
if (strlen(curLiteral.value.string) == 1)
{
constantIdPtr->defn.info.constant.value.character = curLiteral.value.string[0];
constantIdPtr->typePtr = setType(CharTypePtr);
}
else
{
long length = strlen(curLiteral.value.string);
constantIdPtr->defn.info.constant.value.stringPtr = (char*)AblSymTableHeap->Malloc(length + 1);
if (!constantIdPtr->defn.info.constant.value.stringPtr)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc array string constant ");
strcpy(constantIdPtr->defn.info.constant.value.stringPtr, curLiteral.value.string);
constantIdPtr->typePtr = makeStringType(length);
}
}
else
{
constantIdPtr->typePtr = NULL;
syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
}
getToken();
}
//***************************************************************************
// TYPE routines
//***************************************************************************
//---------------------------------------------------------------------------
// Need to implement type routines if we allow user-defined types, and/or the
// PASCAL style array types (otherwise, arrays should be implemented in the
// var routines...
void typeDefinitions (void)
{
while (curToken == TKN_IDENTIFIER)
{
SymTableNodePtr typeIdPtr;
searchAndEnterLocalSymTable(typeIdPtr);
typeIdPtr->defn.key = DFN_TYPE;
typeIdPtr->library = CurLibrary;
getToken();
ifTokenGetElseError(TKN_EQUAL, ABL_ERR_SYNTAX_MISSING_EQUAL);
//----------------------------------
// Process the type specification...
typeIdPtr->typePtr = doType();
if (typeIdPtr->typePtr->typeIdPtr == NULL)
typeIdPtr->typePtr->typeIdPtr = typeIdPtr;
analyzeTypeDefn(typeIdPtr);
//---------------
// Error synch...
synchronize(followDeclarationList, declarationStartList, statementStartList);
if (curToken == TKN_SEMICOLON)
getToken();
else if (tokenIn(declarationStartList) || tokenIn(statementStartList))
syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
}
}
//***************************************************************************
TypePtr doType (void)
{
switch (curToken)
{
case TKN_IDENTIFIER: {
SymTableNodePtr idPtr;
searchAllSymTables(idPtr);
if (!idPtr)
{
syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER);
return(NULL);
}
else if (idPtr->defn.key == DFN_TYPE)
{
//----------------------------------------------------------
// NOTE: Array types should be parsed in this case if a left
// bracket follows the type identifier.
TypePtr elementType = setType(identifierType(idPtr));
if (curToken == TKN_LBRACKET)
{
//--------------
// Array type...
TypePtr typePtr = createType();
if (!typePtr)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc array type ");
TypePtr elementTypePtr = typePtr;
//bool openArray = false;
do
{
getToken();
if (tokenIn(indexTypeStartList))
{
elementTypePtr->form = FRM_ARRAY;
elementTypePtr->size = 0;
elementTypePtr->typeIdPtr = NULL;
//----------------------------------------------
// All array indices must be integer, for now...
elementTypePtr->info.array.indexTypePtr = setType(IntegerTypePtr);
//------------------------
// Read the index count...
switch (curToken)
{
case TKN_NUMBER:
if (curLiteral.type == LIT_INTEGER)
elementTypePtr->info.array.elementCount = curLiteral.value.integer;
else
{
elementTypePtr->form = FRM_NONE;
elementTypePtr->size = 0;
elementTypePtr->typeIdPtr = NULL;
elementTypePtr->info.array.indexTypePtr = NULL;
syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE);
}
getToken();
break;
case TKN_IDENTIFIER: {
SymTableNodePtr idPtr;
searchAllSymTables(idPtr);
if (idPtr == NULL)
syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER);
else if (idPtr->defn.key == DFN_CONST)
{
if (idPtr->typePtr == IntegerTypePtr)
elementTypePtr->info.array.elementCount = idPtr->defn.info.constant.value.integer;
else
{
elementTypePtr->form = FRM_NONE;
elementTypePtr->size = 0;
elementTypePtr->typeIdPtr = NULL;
elementTypePtr->info.array.indexTypePtr = NULL;
syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE);
}
}
else
{
elementTypePtr->form = FRM_NONE;
elementTypePtr->size = 0;
elementTypePtr->typeIdPtr = NULL;
elementTypePtr->info.array.indexTypePtr = NULL;
syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE);
}
getToken();
}
break;
#if 0
case TKN_STAR: {
openArray = true;
elementTypePtr->info.array.elementCount = -1;
getToken();
if (curToken != TKN_RBRACKET)
{
elementTypePtr->form = FRM_NONE;
elementTypePtr->size = 0;
elementTypePtr->typeIdPtr = NULL;
elementTypePtr->info.array.indexTypePtr = NULL;
syntaxError(ABL_ERR_SYNTAX_MISSING_RBRACKET);
}
}
break;
#endif
default:
elementTypePtr->form = FRM_NONE;
elementTypePtr->size = 0;
elementTypePtr->typeIdPtr = NULL;
elementTypePtr->info.array.indexTypePtr = NULL;
syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE);
getToken();
}
}
else
{
elementTypePtr->form = FRM_NONE;
elementTypePtr->size = 0;
elementTypePtr->typeIdPtr = NULL;
elementTypePtr->info.array.indexTypePtr = NULL;
syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE);
getToken();
}
synchronize(followDimensionList, NULL, NULL);
//--------------------------------
// Create an array element type...
if (curToken == TKN_COMMA)
{
elementTypePtr = elementTypePtr->info.array.elementTypePtr = createType();
if (!elementTypePtr)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc array element Type ");
}
} while (curToken == TKN_COMMA);
ifTokenGetElseError(TKN_RBRACKET, ABL_ERR_SYNTAX_MISSING_RBRACKET);
elementTypePtr->info.array.elementTypePtr = elementType;
typePtr->size = arraySize(typePtr);
elementType = typePtr;
}
return(elementType);
}
//---------------------
// NO SUBRANGES, YET...
//else if (idPtr->defn.key == DFN_CONST)
// return(subrangeType(idPtr));
else
{
syntaxError(ABL_ERR_SYNTAX_NOT_A_TYPE_IDENTIFIER);
return(NULL);
}
}
break;
case TKN_LPAREN:
return(enumerationType());
//case TKN_RECORD:
// STOP(("666???"));
//return(recordType());
case TKN_PLUS:
case TKN_MINUS:
case TKN_NUMBER:
case TKN_STRING:
STOP(("666???"));
//return(subrangeType(NULL));
default:
syntaxError(ABL_ERR_SYNTAX_INVALID_TYPE);
return(NULL);
}
}
//***************************************************************************
TypePtr identifierType (SymTableNodePtr idPtr)
{
TypePtr typePtr = (TypePtr)idPtr->typePtr;
getToken();
return(typePtr);
}
//***************************************************************************
TypePtr enumerationType (void)
{
SymTableNodePtr constantIdPtr = NULL;
SymTableNodePtr lastIdPtr = NULL;
TypePtr typePtr = createType();
if (!typePtr)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc enumeration type ");
long constantValue = -1;
typePtr->form = FRM_ENUM;
typePtr->size = sizeof(long);
typePtr->typeIdPtr = NULL;
getToken();
//------------------------------------------------------------
// Process list of identifiers in this new enumeration type...
while (curToken == TKN_IDENTIFIER)
{
searchAndEnterLocalSymTable(constantIdPtr);
constantIdPtr->defn.key = DFN_CONST;
constantIdPtr->defn.info.constant.value.integer = ++constantValue;
constantIdPtr->typePtr = typePtr;
constantIdPtr->library = CurLibrary;
if (lastIdPtr == NULL)
typePtr->info.enumeration.constIdPtr = lastIdPtr = constantIdPtr;
else
{
lastIdPtr->next = constantIdPtr;
lastIdPtr = constantIdPtr;
}
getToken();
ifTokenGet(TKN_COMMA);
}
ifTokenGetElseError(TKN_RPAREN, ABL_ERR_SYNTAX_MISSING_RPAREN);
typePtr->info.enumeration.max = constantValue;
return(typePtr);
}
//***************************************************************************
TypePtr subrangeType (void)
{
// NOT IMPLEMENTED...
return(NULL);
}
//***************************************************************************
long arraySize (TypePtr typePtr)
{
if (typePtr->info.array.elementTypePtr->size == 0)
typePtr->info.array.elementTypePtr->size = arraySize(typePtr->info.array.elementTypePtr);
if (typePtr->info.array.elementCount == -1)
{
//--------------------------------------------------------------
// Open array, so just return the size of its element. Remember,
// open arrays must be open at the end...
typePtr->size = typePtr->info.array.elementTypePtr->size;
}
else
typePtr->size = typePtr->info.array.elementCount * typePtr->info.array.elementTypePtr->size;
return(typePtr->size);
}
//***************************************************************************
// VAR routines
//***************************************************************************
void varDeclarations (SymTableNodePtr routineIdPtr)
{
varOrFieldDeclarations(routineIdPtr,
STACK_FRAME_HEADER_SIZE + routineIdPtr->defn.info.routine.paramCount);
}
//***************************************************************************
void varOrFieldDeclarations (SymTableNodePtr routineIdPtr, long offset)
{
bool varFlag = (routineIdPtr != NULL);
SymTableNodePtr idPtr = NULL;
SymTableNodePtr firstIdPtr = NULL;
SymTableNodePtr lastIdPtr = NULL;
SymTableNodePtr prevLastIdPtr = NULL;
long totalSize = 0;
while ((curToken == TKN_IDENTIFIER) || (curToken == TKN_ETERNAL) || (curToken == TKN_STATIC))
{
VariableType varType = VAR_TYPE_NORMAL;
if ((curToken == TKN_ETERNAL) || (curToken == TKN_STATIC))
{
if (curToken == TKN_ETERNAL)
varType = VAR_TYPE_ETERNAL;
else
varType = VAR_TYPE_STATIC;
getToken();
if (curToken != TKN_IDENTIFIER)
syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER);
}
firstIdPtr = NULL;
//------------------------------
// Process the variable type...
TypePtr typePtr = doType();
//------------------------------------------------------------------
// Since we haven't really assigned it here, decrement its
// numInstances. Every variable in this list will set it properly...
typePtr->numInstances--;
long size = typePtr->size;
//-------------------------------------------------------
// Now that we've read the type, read in the variable (or
// possibly list of variables) declared of this type.
// Loop to process every variable (and field, if records
// are being implemented:) in sublist...
while (curToken == TKN_IDENTIFIER)
{
if (varFlag)
{
//---------------------------------------------
// We're working with a variable declaration...
if (varType == VAR_TYPE_ETERNAL)
{
long curLevel = level;
level = 0;
searchAndEnterThisTable (idPtr, SymTableDisplay[0]);
level = curLevel;
}
else
searchAndEnterLocalSymTable(idPtr);
idPtr->library = CurLibrary;
idPtr->defn.key = DFN_VAR;
}
else
{
syntaxError(ABL_ERR_SYNTAX_NO_RECORD_TYPES);
#if 0
//-------------------------------------------------
// We're dealing with a record field declaration...
searchAndEnterThisSymTable(idPtr, recordType->info.record.fieldSymTable);
idPtr->defn.key = DFN_FIELD;
#endif
}
idPtr->labelIndex = 0;
//------------------------------------------
// Now, link Id's together into a sublist...
if (!firstIdPtr)
{
firstIdPtr = lastIdPtr = idPtr;
if (varFlag && (varType != VAR_TYPE_ETERNAL) && (routineIdPtr->defn.info.routine.locals == NULL))
routineIdPtr->defn.info.routine.locals = idPtr;
}
else
{
lastIdPtr->next = idPtr;
lastIdPtr = idPtr;
}
getToken();
ifTokenGet(TKN_COMMA);
}
//--------------------------------------------------------------------------
// Assign the offset and the type to all variable or field Ids in sublist...
for (idPtr = firstIdPtr; idPtr != NULL; idPtr = idPtr->next)
{
idPtr->typePtr = setType(typePtr);
if (varFlag)
{
idPtr->defn.info.data.varType = varType;
switch (varType)
{
case VAR_TYPE_NORMAL:
totalSize += size;
idPtr->defn.info.data.offset = offset++;
break;
case VAR_TYPE_ETERNAL: {
idPtr->defn.info.data.offset = eternalOffset;
//-----------------------------------
// Initialize the variable to zero...
StackItemPtr dataPtr = (StackItemPtr)stack + eternalOffset;
if (typePtr->form == FRM_ARRAY)
{
dataPtr->address = (Address)AblStackHeap->Malloc((size_t)size);
if (!dataPtr->address)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc eternal array ");
memset(dataPtr->address, 0, size);
//NEW
EternalVariablesSizes[eternalOffset] = size;
}
else
{
dataPtr->integer = 0;
//NEW
EternalVariablesSizes[eternalOffset] = 0;
}
eternalOffset++;
}
break;
case VAR_TYPE_STATIC: {
if (NumStaticVariables == MaxStaticVariables)
syntaxError(ABL_ERR_SYNTAX_TOO_MANY_STATIC_VARS);
idPtr->defn.info.data.offset = NumStaticVariables;
// StackItemPtr dataPtr = (StackItemPtr)staticData + NumStaticVariables;
if (typePtr->form == FRM_ARRAY)
{
// dataPtr = (char*)AblStackHeap->malloc((size_t)size);
// memset(dataPtr, 0, size);
StaticVariablesSizes[NumStaticVariables] = size;
}
else
{
// *dataPtr = 0;
StaticVariablesSizes[NumStaticVariables] = 0;
}
NumStaticVariables++;
}
break;
}
analyzeVarDecl(idPtr);
}
else
{
//----------------
// record field...
idPtr->defn.info.data.varType = VAR_TYPE_NORMAL;
idPtr->defn.info.data.offset = offset;
offset += size;
}
}
//--------------------------------------------------
// Now, link this sublist to the previous sublist...
if (varType != VAR_TYPE_ETERNAL)
{
if (prevLastIdPtr != NULL)
prevLastIdPtr->next = firstIdPtr;
prevLastIdPtr = lastIdPtr;
}
//---------------------
// Error synchronize...
if (varFlag)
synchronize(followVariablesList, declarationStartList, statementStartList);
//------------------------------------------------------------------
// NOTE: When records are implemented, the following should be in...
//else
// synchronize(followFieldsList, declarationStartList, statementStartList);
if (curToken == TKN_SEMICOLON)
getToken();
else if (varFlag && (tokenIn(declarationStartList) || tokenIn(statementStartList)))
syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
}
synchronize(followVarBlockList, NULL, NULL);
if (varFlag)
{
//----------------------------------------------------------------
// If the following error occurs too frequently, simply make the
// totalLocalSize field an unsigned long instead, and dramatically
// increase the totalSize limit here...
if (totalSize > 32000)
syntaxError(ABL_ERR_SYNTAX_TOO_MANY_LOCAL_VARIABLES);
routineIdPtr->defn.info.routine.totalLocalSize = (unsigned short) totalSize;
}
// NOT CURRENTLY SUPPORTING RECORDS...
//else
// recordType->size = offset;
}
//***************************************************************************
}
File diff suppressed because it is too large Load Diff
+341
View File
@@ -0,0 +1,341 @@
//***************************************************************************
//
// ENVIRON.H
//
//***************************************************************************
#ifndef ABLENV_H
#define ABLENV_H
#include <stdio.h>
#ifndef DABLENV_H
#include "dablenv.h"
#endif
#include "ablgen.h"
#ifndef ABLSYMT_H
#include "ablsymt.h"
#endif
#ifndef ABLEXEC_H
#include "ablexec.h"
#endif
#ifndef DABLDBUG_H
#include "dabldbug.h"
#endif
#ifndef DFILE_H
#include "dfile.h"
#endif
namespace ABL
{
//***************************************************************************
typedef struct _SourceFile
{
char fileName[MAXLEN_FILENAME];
unsigned char fileNumber;
FilePtr filePtr;
long lineNumber;
} SourceFile;
//---------------------------------------------------------------------------
#define MAX_USER_FILES 6
#define MAX_USER_FILE_LINES 50
#define MAX_USER_FILE_LINELEN 200
#if 0
class UserFile
{
public:
long handle;
bool inUse;
char fileName[MAXLEN_FILENAME];
Stuff::MemoryStream *stream;
long numLines;
long totalLines;
char lines[MAX_USER_FILE_LINES][MAX_USER_FILE_LINELEN];
static UserFile *files[MAX_USER_FILES];
public:
/*
void* operator new (size_t mySize);
void operator delete (void* us);
*/
void init (void)
{
handle = -1;
inUse = false;
fileName[0] = NULL;
stream = NULL;
numLines = 0;
totalLines = 0;
for (long i = 0; i < MAX_USER_FILE_LINES; i++)
lines[i][0] = NULL;
}
UserFile (void)
{
init();
}
void destroy (void);
~UserFile (void)
{
destroy();
}
void dump (void);
void close (void);
long open (Stuff::MemoryStream *stream);
void write (char* s);
static void setup (void);
static void cleanup (void);
static UserFile *getNewFile (void);
};
#endif
//---------------------------------------------------------------------------
#define MAX_ABLMODULE_NAME 25
#define MAX_SOURCE_FILES 256 // per module
#define MAX_LIBRARIES_USED 25 // per module
typedef struct
{
char name[128];
long size;
} VariableInfo;
typedef struct
{
char name[128];
long codeSegmentSize;
} RoutineInfo;
typedef struct
{
char name[128];
char fileName[128];
long numStaticVars;
long totalSizeStaticVars;
VariableInfo largestStaticVar;
long totalCodeSegmentSize;
long numRoutines;
RoutineInfo routineInfo[128];
} ModuleInfo;
typedef struct
{
char* fileName;
SymTableNodePtr moduleIdPtr;
long numSourceFiles;
char** sourceFiles;
long numLibrariesUsed;
ABLModulePtr* librariesUsed;
long numStaticVars;
long* sizeStaticVars;
long totalSizeStaticVars;
long numInstances;
} ModuleEntry;
typedef ModuleEntry* ModuleEntryPtr;
class ABLModule
{
private:
long id;
char name[MAX_ABLMODULE_NAME];
long handle;
StackItemPtr staticData;
StackItem returnVal;
bool initCalled;
WatchManagerPtr watchManager;
BreakPointManagerPtr breakPointManager;
SymTableNodePtr curState;
bool trace;
bool step;
bool traceEntry;
bool traceExit;
//static long numModules;
public:
// void* operator new (size_t mySize);
// void operator delete (void* us);
void init (void)
{
id = -1;
name[0] = NULL;
handle = -1;
staticData = NULL;
initCalled = false;
watchManager = NULL;
breakPointManager = NULL;
curState = NULL;
trace = false;
step = false;
traceEntry = false;
traceExit = false;
}
SymTableNodePtr GetCurState() const
{
return(curState);
}
ABLModule (void)
{
init();
}
reset (void);
long init (long moduleHandle);
void write (MemoryStream *stream);
void read (MemoryStream *stream);
long getId (void)
{
return(id);
}
void SwitchStates (const char *name);
long getHandle (void)
{
return(handle);
}
StackItemPtr getStaticData (void)
{
return(staticData);
}
void setInitCalled (bool called)
{
initCalled = called;
}
bool getInitCalled (void)
{
return(initCalled);
}
char* getName (void)
{
return(name);
}
void setName (char* _name);
WatchManagerPtr getWatchManager (void)
{
return(watchManager);
}
BreakPointManagerPtr getBreakPointManager (void)
{
return(breakPointManager);
}
void setTrace (bool _trace)
{
trace = _trace;
traceEntry = _trace;
traceExit = _trace;
}
bool getTrace (void)
{
return(trace);
}
void setStep (bool _step)
{
step = _step;
}
bool getStep (void)
{
return(step);
}
long execute (ABLParamPtr paramList = NULL);
long execute (ABLParamPtr moduleParamList, SymTableNodePtr functionIdPtr);
SymTableNodePtr findSymbol (char* symbolName, SymTableNodePtr curFunction = NULL, bool searchLibraries = false);
SymTableNodePtr findFunction (char* functionName, bool searchLibraries = false);
char* getSourceFile (long fileNumber);
char* getSourceDirectory (long fileNumber, char* directory);
void getInfo (ModuleInfo* moduleInfo);
float getReal (void)
{
return(returnVal.real);
}
long getInteger (void)
{
return(returnVal.integer);
}
long setStaticInteger (char* name, long value);
long getStaticInteger (char* name);
long setStaticReal (char* name, float value);
float getStaticReal (char* name);
long setStaticIntegerArray (char* name, long size, long* values);
long getStaticIntegerArray (char* name, long size, long* values);
long setStaticRealArray (char* name, long size, float* values);
long getStaticRealArray (char* name, long size, float* values);
void destroy (void);
~ABLModule (void)
{
destroy();
}
};
//*************************************************************************
void initModuleRegistry (long maxModules);
void destroyModuleRegistry (void);
void initLibraryRegistry (long maxLibraries);
void destroyLibraryRegistry (void);
//***************************************************************************
}
#endif
+255
View File
@@ -0,0 +1,255 @@
//***************************************************************************
//
// ABLERR.CPP
//
//***************************************************************************
#include "MW4Headers.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#ifndef ABLGEN_H
#include "ablgen.h"
#endif
#ifndef ABLERR_H
#include "ablerr.h"
#endif
#ifndef ABL_H
#include "abl.h"
#endif
#ifndef GAMEOS_HPP
#include <gameos\gameos.hpp>
#endif
bool gShowScriptErrors;
//***************************************************************************
namespace ABL
{
//----------
// EXTERNALS
extern char* tokenp;
extern long execLineNumber;
extern long lineNumber;
extern long FileNumber;
extern char SourceFiles[MAX_SOURCE_FILES][MAXLEN_FILENAME];
extern ABLModulePtr CurModule;
char ABLError::m_DetailErrorString[ABL_DETAIL_ERROR_STRING_SIZE];
//extern BOOL debuggerCommandFlag;
//---------------------------------------------------------------------------
//----------------------
// SYNTAX ERROR messages
char* syntaxErrorMessages[] = {
"No syntax error", // 0
"Syntax error",
"Too many errors",
"Cannot open source file",
"Unexpected end-of-file",
"Invalid number",
"Invalid fraction",
"Invalid exponent",
"Too many digits",
"Real out of range",
"Integer out of range", // 10
"MIssing right parenthesis",
"Invalid expression",
"Undefined identifier",
"Redefined identifier",
"Unexpected token",
"Incompatible types",
"Nesting too deep",
"Code segment overflow",
"Missing equal",
"Missing semi-colon", // 20
"Invalid constant",
"Not a constant identifier",
"No record types",
"Missing colon (ouch)",
"Not a type identifier",
"Invalid type",
"Missing end",
"Invalid identifier usage",
"Too many subscripts",
"Missing right bracket", // 30
"Incompatible assignment",
"Missing until",
"Missing then",
"Invalid for control",
"Missing identifier",
"Missing to",
"Missing period",
"Missing module or fsm",
"Missing library",
"Already forwarded", // 40
"Invalid reference parameter",
"Wrong number of parameters",
"Missing begin",
"Missing endvar",
"No function nesting",
"Missing code",
"Missing endif",
"Missing endwhile",
"Missing endfor",
"Missing endfunction", // 50
"Missing endmodule",
"Missing endlibrary",
"Missing do",
"Invalid index type",
"Missing comma",
"Too many static variables",
"Missing endcase",
"Missing endswitch",
"Missing constant",
"Bad language directive parameter", // 60
"Unknown language directive",
"Too Many Formal Parameters",
"Too Many Local Variables",
"Code was found outside of a state block in an fsm",
"Cannot nest states within functions or other states",
"Cannot forward declare states",
"Missing endstate",
"Cannot trans to a non state",
"Cannot us the trans keyword in a non fsm",
"A state was forwarded but not actually instantiated"
};
//---------------------------------------------------------------------------
//-----------------------
// RUNTIME ERROR messages
char* runtimeErrorMessages[] = {
"Runtime stack overflow",
"Infinite Loop",
"Nested function call",
"Unimplemented feature",
"Value out of range",
"Division by zero",
"Invalid function argument",
"Invalid case value",
"Abort"
};
//---------------------------------------------------------------------------
//--------
// GLOBALS
long errorCount = 0;
ABLError *ablError;
jmp_buf abl_jmp_buf;
extern DebuggerPtr debugger;
//***************************************************************************
void ABL_Fatal (long errCode, char* s)
{
STOP((s));
}
//---------------------------------------------------------------------------
void ABL_Assert (bool test, long errCode, char* s)
{
#ifdef _DEBUG
if (!test)
STOP((s));
#endif
}
//***************************************************************************
void syntaxError (long errCode)
{
char errMessage[MAXLEN_ERROR_MESSAGE];
sprintf(errMessage, "SYNTAX ERROR %s [line %d] - (type %d) %s\n", SourceFiles[FileNumber], lineNumber, errCode, syntaxErrorMessages[errCode]);
if (ablError)
{
ablError->String (syntaxErrorMessages[errCode]);
ablError->File (SourceFiles[FileNumber]);
ablError->Line (lineNumber);
ablError->Code (errCode);
longjmp (abl_jmp_buf,1);
}
else
ABL_Fatal(0, errMessage);
*tokenp = NULL;
errorCount++;
if (errorCount > MAX_SYNTAX_ERRORS)
{
sprintf(errMessage, "Way too many syntax errors. ABL aborted.\n");
ABL_Fatal(0, errMessage);
}
}
//---------------------------------------------------------------------------
void runtimeError (long errCode)
{
char message[512];
if (debugger)
{
sprintf(message, "RUNTIME ERROR: [%d] %s", errCode, runtimeErrorMessages[errCode]);
debugger->print(message);
sprintf(message, "MODULE %s", CurModule->getName());
debugger->print(message);
if (FileNumber > -1)
sprintf(message, "FILE %s", CurModule->getSourceFile(FileNumber));
else
sprintf(message, "FILE %s: unavailable");
debugger->print(message);
sprintf(message, "LINE %d", execLineNumber);
debugger->print(message);
debugger->debugMode();
}
sprintf(message, "ABL RUNTIME ERROR %s [line %d] - (type %d) %s\n", (FileNumber > -1) ? CurModule->getSourceFile(FileNumber) : "unavailable", execLineNumber, errCode, runtimeErrorMessages[errCode]);
ABL_Fatal(-ABL_ERR_RUNTIME_ABORT, message);
}
//***************************************************************************
char *ABL_runtimeErrorString (char *str,int stringlen)
{
char line[25];
*str = 0;
if (ABL::FileNumber > -1)
{
// Str_Cat (str," FILE: ",stringlen);
Str_Cat (str,CurModule->getSourceFile(FileNumber),stringlen);
}
// Str_Cat (str," LINE: ",stringlen);
Str_Cat (str,"(",stringlen);
itoa (execLineNumber,line,10);
Str_Cat (str,line,stringlen);
Str_Cat (str,")",stringlen);
Str_Cat (str," MODULE: ",stringlen);
Str_Cat (str,CurModule->getName (),stringlen);
return str;
}
}
+117
View File
@@ -0,0 +1,117 @@
//***************************************************************************
//
// ERROR.H
//
//***************************************************************************
#ifndef ABLERR_H
#define ABLERR_H
//***************************************************************************
namespace ABL
{
#define MAX_SYNTAX_ERRORS 1 //20
#define MAXLEN_ERROR_MESSAGE 256
typedef enum {
ABL_ERR_SYNTAX_NONE, // 0
ABL_ERR_SYNTAX_ERROR,
ABL_ERR_SYNTAX_TOO_MANY_ERRORS,
ABL_ERR_SYNTAX_SOURCE_FILE_OPEN,
ABL_ERR_SYNTAX_UNEXPECTED_EOF,
ABL_ERR_SYNTAX_INVALID_NUMBER,
ABL_ERR_SYNTAX_INVALID_FRACTION,
ABL_ERR_SYNTAX_INVALID_EXPONENT,
ABL_ERR_SYNTAX_TOO_MANY_DIGITS,
ABL_ERR_SYNTAX_REAL_OUT_OF_RANGE,
ABL_ERR_SYNTAX_INTEGER_OUT_OF_RANGE, // 10
ABL_ERR_SYNTAX_MISSING_RPAREN,
ABL_ERR_SYNTAX_INVALID_EXPRESSION,
ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER,
ABL_ERR_SYNTAX_REDEFINED_IDENTIFIER,
ABL_ERR_SYNTAX_UNEXPECTED_TOKEN,
ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES,
ABL_ERR_SYNTAX_NESTING_TOO_DEEP,
ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW,
ABL_ERR_SYNTAX_MISSING_EQUAL,
ABL_ERR_SYNTAX_MISSING_SEMICOLON, // 20
ABL_ERR_SYNTAX_INVALID_CONSTANT,
ABL_ERR_SYNTAX_NOT_A_CONSTANT_IDENTIFIER,
ABL_ERR_SYNTAX_NO_RECORD_TYPES,
ABL_ERR_SYNTAX_MISSING_COLON,
ABL_ERR_SYNTAX_NOT_A_TYPE_IDENTIFIER,
ABL_ERR_SYNTAX_INVALID_TYPE,
ABL_ERR_SYNTAX_MISSING_END,
ABL_ERR_SYNTAX_INVALID_IDENTIFIER_USAGE,
ABL_ERR_SYNTAX_TOO_MANY_SUBSCRIPTS,
ABL_ERR_SYNTAX_MISSING_RBRACKET, // 30
ABL_ERR_SYNTAX_INCOMPATIBLE_ASSIGNMENT,
ABL_ERR_SYNTAX_MISSING_UNTIL,
ABL_ERR_SYNTAX_MISSING_THEN,
ABL_ERR_SYNTAX_INVALID_FOR_CONTROL,
ABL_ERR_SYNTAX_MISSING_IDENTIFIER,
ABL_ERR_SYNTAX_MISSING_TO,
ABL_ERR_SYNTAX_MISSING_PERIOD,
ABL_ERR_SYNTAX_MISSING_MODULE,
ABL_ERR_SYNTAX_MISSING_LIBRARY,
ABL_ERR_SYNTAX_ALREADY_FORWARDED, // 40
ABL_ERR_SYNTAX_INVALID_REF_PARAM,
ABL_ERR_SYNTAX_WRONG_NUMBER_OF_PARAMS,
ABL_ERR_SYNTAX_MISSING_BEGIN,
ABL_ERR_SYNTAX_MISSING_END_VAR,
ABL_ERR_SYNTAX_NO_FUNCTION_NESTING,
ABL_ERR_SYNTAX_MISSING_CODE,
ABL_ERR_SYNTAX_MISSING_END_IF,
ABL_ERR_SYNTAX_MISSING_END_WHILE,
ABL_ERR_SYNTAX_MISSING_END_FOR,
ABL_ERR_SYNTAX_MISSING_END_FUNCTION, // 50
ABL_ERR_SYNTAX_MISSING_END_MODULE,
ABL_ERR_SYNTAX_MISSING_END_LIBRARY,
ABL_ERR_SYNTAX_MISSING_DO,
ABL_ERR_SYNTAX_INVALID_INDEX_TYPE,
ABL_ERR_SYNTAX_MISSING_COMMA,
ABL_ERR_SYNTAX_TOO_MANY_STATIC_VARS,
ABL_ERR_SYNTAX_MISSING_END_CASE,
ABL_ERR_SYNTAX_MISSING_END_SWITCH,
ABL_ERR_SYNTAX_MISSING_CONSTANT,
ABL_ERR_SYNTAX_BAD_LANGUAGE_DIRECTIVE_USAGE, // 60
ABL_ERR_SYNTAX_UNKNOWN_LANGUAGE_DIRECTIVE,
ABL_ERR_SYNTAX_TOO_MANY_FORMAL_PARAMETERS,
ABL_ERR_SYNTAX_TOO_MANY_LOCAL_VARIABLES,
ABL_ERR_SYNTAX_CODE_OUTSIDE_STATE_BLOCK,
ABL_ERR_SYNTAX_NO_STATE_NESTING,
ABL_ERR_SYNTAX_STATE_FORWARD,
ABL_ERR_SYNTAX_MISSING_END_STATE,
ABL_ERR_SYNTAX_TRANS_TO_NON_STATE,
ABL_ERR_SYNTAX_TRANS_IN_NONFSM,
ABL_ERR_SYNTAX_FORWARDED_STATE_NOT_DECLARED,
NUM_ABL_SYNTAX_ERRORS
} SyntaxErrorType;
typedef enum {
ABL_ERR_RUNTIME_STACK_OVERFLOW,
ABL_ERR_RUNTIME_INFINITE_LOOP,
ABL_ERR_RUNTIME_NESTED_FUNCTION_CALL,
ABL_ERR_RUNTIME_UNIMPLEMENTED_FEATURE,
ABL_ERR_RUNTIME_VALUE_OUT_OF_RANGE,
ABL_ERR_RUNTIME_DIVISION_BY_ZERO,
ABL_ERR_RUNTIME_INVALID_FUNCTION_ARGUMENT,
ABL_ERR_RUNTIME_INVALID_CASE_VALUE,
ABL_ERR_RUNTIME_ABORT,
NUM_ABL_RUNTIME_ERRORS
} RuntimeErrorType;
//***************************************************************************
void syntaxError (long errCode);
void runtimeError (long errCode);
void ABL_Fatal (long errCode, char* s);
void ABL_Assert (bool test, long errCode, char* s);
char *ABL_runtimeErrorString (char *str,int strlen);
//***************************************************************************
}
#endif
+597
View File
@@ -0,0 +1,597 @@
//***************************************************************************
//
// ABLEXEC.CPP
//
//***************************************************************************
#include "MW4Headers.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef ABLGEN_H
#include "ablgen.h"
#endif
#ifndef ABLERR_H
#include "ablerr.h"
#endif
#ifndef ABLSCAN_H
#include "ablscan.h"
#endif
#ifndef ABLEXEC_H
#include "ablexec.h"
#endif
#ifndef ABLDBUG_H
#include "abldbug.h"
#endif
#ifndef ABLHEAP_H
#include "ablheap.h"
#endif
//***************************************************************************
namespace ABL
{
//--------
// GLOBALS
ABLExecFunctionType routineExecFunction = NULL;
char* codeBuffer = NULL;
char* codeBufferPtr = NULL;
char* codeSegmentPtr = NULL;
char* codeSegmentLimit = NULL;
char* statementStartPtr = NULL;
TokenCodeType codeToken;
long execLineNumber;
long execStatementCount = 0;
StackItem* stack = NULL;
StackItemPtr tos = NULL;
StackItemPtr stackFrameBasePtr = NULL;
StackItemPtr StaticDataPtr = NULL;
long* StaticVariablesSizes = NULL;
long* EternalVariablesSizes = NULL;
long eternalOffset = 0;
long MaxStaticVariables = 0;
long MaxEternalVariables = 0;
long NumStaticVariables = 0;
long CurModuleHandle = 0;
long MaxCodeBufferSize = 0;
bool CallModuleInit = false;
bool InOrdersBlock = false;
long MaxLoopIterations = 100001;
bool AssertEnabled = false;
bool PrintEnabled = true;
bool StringFunctionsEnabled = true;
bool DebugCodeEnabled = false;
bool IncludeDebugInfo = true;
bool ProfileABL = false;
bool Crunch = true;
//----------
// EXTERNALS
extern SymTableNodePtr CurRoutineIdPtr;
extern ModuleEntryPtr ModuleRegistry;
extern ABLModulePtr* ModuleInstanceRegistry;
extern ABLModulePtr CurModule;
extern ABLModulePtr CurLibrary;
extern TokenCodeType curToken;
extern long lineNumber;
extern long FileNumber;
extern long level;
extern TypePtr IntegerTypePtr;
extern TypePtr CharTypePtr;
extern TypePtr RealTypePtr;
extern TypePtr BooleanTypePtr;
extern UserHeapPtr AblCodeHeap;
extern UserHeapPtr AblStackHeap;
extern StackItem returnValue;
extern bool ExitWithReturn;
extern bool ExitFromTacOrder;
extern DebuggerPtr debugger;
//***************************************************************************
// CRUNCH/DECRUNCH routines
//***************************************************************************
void crunchToken (void)
{
if (!Crunch)
return;
if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
{
STOP(("ABL SyntaxError #%d", ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW));
}
else
{
*codeBufferPtr = (char) curToken;
codeBufferPtr++;
}
}
//***************************************************************************
void uncrunchToken (void)
{
codeBufferPtr--;
}
//***************************************************************************
void crunchSymTableNodePtr (SymTableNodePtr nodePtr)
{
if (!Crunch)
return;
if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
{
STOP(("ABL SyntaxError #%d", ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW));
}
else
{
SymTableNodePtr* nodePtrPtr = (SymTableNodePtr*)codeBufferPtr;
*nodePtrPtr = nodePtr;
codeBufferPtr += sizeof(SymTableNodePtr);
}
}
//***************************************************************************
void uncrunchSymTableNodePtr (void)
{
//-------------------------------------
// Pull sym table node ptr off the buffer
codeBufferPtr -= sizeof(SymTableNodePtr);
}
//***************************************************************************
void crunchStatementMarker (void)
{
if (!Crunch)
return;
if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
{
STOP(("ABL SyntaxError #%d", ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW));
}
else
{
char saveCode = *(--codeBufferPtr);
*codeBufferPtr = (char)TKN_STATEMENT_MARKER;
codeBufferPtr++;
if (IncludeDebugInfo)
{
*((unsigned char*)codeBufferPtr) = (unsigned char)FileNumber;
codeBufferPtr += sizeof(unsigned char);
*((long*)codeBufferPtr) = lineNumber;
codeBufferPtr += sizeof(long);
}
*codeBufferPtr = saveCode;
codeBufferPtr++;
}
}
//***************************************************************************
void uncrunchStatementMarker (void)
{
//-------------------------
// Pull code off the buffer
codeBufferPtr--;
//-------------------------------
// Pull debug info off the buffer
if (IncludeDebugInfo)
codeBufferPtr -= (sizeof(unsigned char) + sizeof(long));
//-------------------------------------
// Pull statement marker off the buffer
codeBufferPtr--;
}
//***************************************************************************
char* crunchAddressMarker (Address address)
{
if (!Crunch)
return(NULL);
char* saveCodeBufferPtr = NULL;
if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
{
STOP(("ABL SyntaxError #%d", ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW));
}
else
{
char saveCode = *(--codeBufferPtr);
*codeBufferPtr = (char)TKN_ADDRESS_MARKER;
codeBufferPtr++;
saveCodeBufferPtr = codeBufferPtr;
*((Address*)codeBufferPtr) = address;
codeBufferPtr += sizeof(Address);
*codeBufferPtr = saveCode;
codeBufferPtr++;
}
return(saveCodeBufferPtr);
}
//***************************************************************************
char* fixupAddressMarker (Address address)
{
if (!Crunch)
return(NULL);
char* oldAddress = *((Address*)address);
*((long*)address) = codeBufferPtr - address;
return(oldAddress);
}
//***************************************************************************
void crunchInteger (long value)
{
if (!Crunch)
return;
if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
{
STOP(("ABL SyntaxError #%d", ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW));
}
else
{
*((long*)codeBufferPtr) = value;
codeBufferPtr += sizeof(long);
}
}
//***************************************************************************
void crunchOffset (Address address)
{
if (!Crunch)
return;
if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
{
STOP(("ABL SyntaxError #%d", ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW));
}
else
{
*((long*)codeBufferPtr) = address - codeBufferPtr;
codeBufferPtr += sizeof(long);
}
}
//***************************************************************************
char* createCodeSegment (long& codeSegmentSize)
{
codeSegmentSize = codeBufferPtr - codeBuffer + 1;
char* codeSegment = (char*)AblCodeHeap->Malloc(codeSegmentSize);
if (!codeSegment)
ABL_Fatal(0, " ABL: Unable to AblCodeHeap->malloc code segment ");
for (long i = 0; i < codeSegmentSize; i++)
codeSegment[i] = codeBuffer[i];
codeBufferPtr = codeBuffer;
return(codeSegment);
}
//***************************************************************************
void pushStackFrameHeader (long oldLevel, long newLevel)
{
//-----------------------------------
// Make space for the return value...
pushInteger(0);
StackFrameHeaderPtr headerPtr = (StackFrameHeaderPtr)stackFrameBasePtr;
//----------------------------------------------------------------------
// STATIC LINK
// Currently, let's not allow functions defined within functions. Assume
// the old scope level equals the new scope level, for now.
if (newLevel == -1)
{
//--------------------------------------------------------------------
// Calling a library function, so push a NULL static link since
// it's scope is in a different module than the calling function.
// Note that global variables in libraries should be STATIC, otherwise
// they're never in scope! Weird "feature" which we may want
// to fix later...
pushAddress(NULL);
}
else if (newLevel == oldLevel + 1)
{
//----------------------------------------------------------------
// Calling a routine nested within the caller, so push the pointer
// to the caller's stack frame. In ABL, as currently defined
// (2/22/96), this should only be when a module's code section is
// calling a function...
pushAddress((Address)headerPtr);
}
else if (newLevel == oldLevel)
{
//---------------------------------------------------------------
// Calling a function at the same scope level. We like that! Push
// pointer to stack frame of their common parent...
pushAddress(headerPtr->staticLink.address);
}
else
{
//-------------------------------------------------------
// Oops. We don't want nested functions, for now, in ABL.
STOP(("ABL SyntaxError #%d", ABL_ERR_RUNTIME_NESTED_FUNCTION_CALL));
}
pushAddress((Address)stackFrameBasePtr);
//---------------------------
// Push the return address...
pushAddress(0);
}
//***************************************************************************
void allocLocal (TypePtr typePtr)
{
if (typePtr == IntegerTypePtr)
pushInteger(0);
else if (typePtr == RealTypePtr)
pushReal((float)0.0);
else if (typePtr == BooleanTypePtr)
pushByte(0);
else if (typePtr == CharTypePtr)
pushByte(0);
else
switch (typePtr->form)
{
case FRM_ENUM:
pushInteger(0);
break;
// NOTE: We currently are not supporting sub ranges, until
// we really want 'em...
// case FRM_SUBRANGE:
// allocLocal(typePtr->info.subrange.rangeTypePtr);
// break;
case FRM_ARRAY:
char* ptr = (char*)AblStackHeap->Malloc(typePtr->size);
if (!ptr)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc local array ");
pushAddress((Address)ptr);
break;
}
}
//***************************************************************************
void freeLocal (SymTableNodePtr idPtr)
{
//---------------------------------------
// Frees data allocated on local stack...
TypePtr typePtr = (TypePtr)(idPtr->typePtr);
StackItemPtr itemPtr = NULL;
if (((typePtr->form == FRM_ARRAY) /* || (typePtr->form == FRM_RECORD)*/) &&
(idPtr->defn.key != DFN_REFPARAM))
{
switch (idPtr->defn.info.data.varType)
{
case VAR_TYPE_NORMAL:
itemPtr = stackFrameBasePtr + idPtr->defn.info.data.offset;
break;
// case VAR_TYPE_ETERNAL:
// itemPtr = stack + idPtr->defn.info.data.offset;
// break;
// case VAR_TYPE_STATIC:
// itemPtr = StaticDataPtr + idPtr->defn.info.data.offset;
// break;
}
if (!itemPtr)
runtimeError(0);
else
AblStackHeap->Free(itemPtr->address);
}
}
//***************************************************************************
// FUNCTION ENTRY/EXIT routines
//***************************************************************************
void routineEntry (SymTableNodePtr routineIdPtr)
{
if (debugger)
debugger->traceRoutineEntry(routineIdPtr);
memset(&returnValue, 0, sizeof(StackItem));
//------------------------------
// Switch to new code segment...
codeSegmentPtr = routineIdPtr->defn.info.routine.codeSegment;
//----------------------------------------------
// Allocate local variables onto system stack...
for (SymTableNodePtr varIdPtr = (SymTableNodePtr)(routineIdPtr->defn.info.routine.locals);
varIdPtr != NULL;
varIdPtr = varIdPtr->next)
if (varIdPtr->defn.info.data.varType == VAR_TYPE_NORMAL)
allocLocal((TypePtr)(varIdPtr->typePtr));
}
//***************************************************************************
void routineExit (SymTableNodePtr routineIdPtr)
{
if (debugger)
debugger->traceRoutineExit(routineIdPtr);
//-----------------------------------------
// De-alloc parameters & local variables...
for (SymTableNodePtr idPtr = (SymTableNodePtr)(routineIdPtr->defn.info.routine.params);
idPtr != NULL;
idPtr = idPtr->next)
freeLocal(idPtr);
for (idPtr = (SymTableNodePtr)(routineIdPtr->defn.info.routine.locals);
idPtr != NULL;
idPtr = idPtr->next)
if (idPtr->defn.info.data.varType == VAR_TYPE_NORMAL)
freeLocal(idPtr);
StackFrameHeaderPtr headerPtr = (StackFrameHeaderPtr)stackFrameBasePtr;
codeSegmentPtr = headerPtr->returnAddress.address;
if (routineIdPtr->typePtr == NULL)
tos = stackFrameBasePtr - 1;
else
tos = stackFrameBasePtr;
stackFrameBasePtr = (StackItemPtr)headerPtr->dynamicLink.address;
}
//***************************************************************************
void execute (SymTableNodePtr routineIdPtr)
{
SymTableNodePtr thisRoutineIdPtr = CurRoutineIdPtr;
CurRoutineIdPtr = routineIdPtr;
routineEntry(routineIdPtr);
//----------------------------------------------------
// Now, search this module for the function we want...
if (CallModuleInit)
{
CallModuleInit = false;
SymTableNodePtr initFunctionIdPtr = searchSymTable("init", ModuleRegistry[CurModule->getHandle()].moduleIdPtr->defn.info.routine.localSymTable);
if (initFunctionIdPtr)
{
execRoutineCall(initFunctionIdPtr);
//-------------------------------------------------------------------------
// Since we're calling the function directly, we need to compensate for the
// codeSegmentPtr being incremented by 1 in the normal execRoutineCall...
codeSegmentPtr--;
}
}
if (routineIdPtr->defn.key == DFN_FSM)
{
execRoutineCall (routineIdPtr->defn.info.routine.state);
codeSegmentPtr--;
routineExit(routineIdPtr);
}
else
{
getCodeToken();
execStatement();
//---------------------------------------------
// In case we exited with a return statement...
ExitWithReturn = false;
ExitFromTacOrder = false;
routineExit(routineIdPtr);
}
CurRoutineIdPtr = thisRoutineIdPtr;
}
//***************************************************************************
void executeChild (SymTableNodePtr routineIdPtr, SymTableNodePtr childRoutineIdPtr)
{
// THIS DOES NOT SUPPORT CALLING FUNCTIONS WITH PARAMETERS YET!
SymTableNodePtr thisRoutineIdPtr = CurRoutineIdPtr;
CurRoutineIdPtr = routineIdPtr;
routineEntry(routineIdPtr);
//----------------------------------------------------
// Now, search this module for the function we want...
SymTableNodePtr initFunctionIdPtr = NULL;
if (CallModuleInit)
{
CallModuleInit = false;
initFunctionIdPtr = searchSymTable("init", routineIdPtr->defn.info.routine.localSymTable);
if (initFunctionIdPtr)
{
execRoutineCall(initFunctionIdPtr);
//-------------------------------------------------------------------------
// Since we're calling the function directly, we need to compensate for the
// codeSegmentPtr being incremented by 1 in the normal execRoutineCall...
codeSegmentPtr--;
}
}
if (initFunctionIdPtr != childRoutineIdPtr)
{
//-----------------------------------------------------------------------
// If we're calling the module's init function, and we just did above,
// don't call it again! That's why we make the check on the above line...
execRoutineCall(childRoutineIdPtr);
//-------------------------------------------------------------------------
// Since we're calling the function directly, we need to compensate for the
// codeSegmentPtr being incremented by 1 in the normal execRoutineCall...
codeSegmentPtr--;
}
//---------------------------------------------
// In case we exited with a return statement...
ExitWithReturn = false;
ExitFromTacOrder = false;
routineExit(routineIdPtr);
CurRoutineIdPtr = thisRoutineIdPtr;
}
//***************************************************************************
// MISC routines
//***************************************************************************
}
+193
View File
@@ -0,0 +1,193 @@
//***************************************************************************
//
// EXECUTOR.H
//
//***************************************************************************
#ifndef ABLEXEC_H
#define ABLEXEC_H
#include "ablgen.h"
#include "ablsymt.h"
#include "ablparse.h"
namespace ABL
{
//***************************************************************************
#define STATEMENT_MARKER 0x70
#define ADDRESS_MARKER 0x71
//***************************************************************************
//--------------
// ABL Parameter
#define ABL_PARAM_VOID 0
#define ABL_PARAM_INTEGER 1
#define ABL_PARAM_REAL 2
typedef struct {
char type;
long integer;
float real;
} ABLParam;
typedef ABLParam* ABLParamPtr;
//---------------
// RUN-TIME STACK
typedef union {
long integer;
float real;
unsigned char byte;
Address address;
} StackItem;
typedef StackItem* StackItemPtr;
typedef struct {
StackItem functionValue;
StackItem staticLink;
StackItem dynamicLink;
StackItem returnAddress;
} StackFrameHeader;
typedef StackFrameHeader* StackFrameHeaderPtr;
//***************************************************************************
#if 0
//class ABLmodule {
// public:
// SymTableNodePtr moduleIdPtr;
// public:
//};
#endif
//***************************************************************************
extern char* codeBuffer;
extern char* codeBufferPtr;
extern char* codeSegmentPtr;
extern char* codeSegmentLimit;
extern char* statementStartPtr;
extern TokenCodeType codeToken;
extern long execLineNumber;
extern long execStatementCount;
extern StackItem* stack;
extern StackItemPtr tos;
extern StackItemPtr stackFrameBasePtr;
//***************************************************************************
//----------
// FUNCTIONS
SymTableNodePtr getSymTableCodePtr (void);
TypePtr execRoutineCall (void);
TypePtr execExpression (void);
TypePtr execVariable (void);
//*************************
// CRUNCH/DECRUNCH routines
//*************************
void crunchToken (void);
void uncrunchToken (void);
void crunchSymTableNodePtr (SymTableNodePtr nodePtr);
void uncrunchSymTableNodePtr (void);
void crunchStatementMarker (void);
void uncrunchStatementMarker (void);
char* crunchAddressMarker (Address address);
char* fixupAddressMarker (Address address);
void crunchInteger (long value);
void crunchOffset (Address address);
char* createCodeSegment (long& codeSegmentSize);
SymTableNodePtr getCodeSymTableNodePtr (void);
long getCodeStatementMarker (void);
char* getCodeAddressMarker (void);
long getCodeInteger (void);
char* getCodeAddress (void);
//***************
// STACK routines
//***************
void pop (void);
void getCodeToken (void);
void pushInteger (long value);
void pushReal (float value);
void pushByte (char value);
void pushAddress (Address address);
void pushBoolean (bool value);
void pushStackFrameHeader (long oldLevel, long newLevel);
void allocLocal (TypePtr typePtr);
void freeData (SymTableNodePtr idPtr);
//*****************************
// FUNCTION ENTRY/EXIT routines
//*****************************
void routineEntry (SymTableNodePtr routineIdPtr);
void routineExit (SymTableNodePtr routineIdPtr);
void execute (SymTableNodePtr routineIdPtr);
void executeChild (SymTableNodePtr routineIdPtr, SymTableNodePtr childRoutineIdPtr);
//******************
// EXECSTMT routines
//******************
void execStatement (void);
void execAssignmentStatement (SymTableNodePtr idPtr);
TypePtr execRoutineCall (SymTableNodePtr routineIdPtr);
TypePtr execDeclaredRoutineCall (SymTableNodePtr routineIdPtr);
TypePtr execExternRoutineCall (SymTableNodePtr routineIdPtr);
void execActualParams (SymTableNodePtr routineIdPtr);
void execExternParams (SymTableNodePtr routineIdPtr);
void execCompoundStatement (void);
void execCaseStatement (void);
void execForStatement (void);
void execIfStatement (void);
void execRepeatStatement (void);
void execWhileStatement (void);
void execSwitchStatement (void);
//******************
// EXECEXPR routines
//******************
TypePtr execField (void);
TypePtr execSubscripts (TypePtr typePtr);
TypePtr execConstant (SymTableNodePtr idPtr);
TypePtr execVariable (SymTableNodePtr idPtr, UseType use);
TypePtr execFactor (void);
TypePtr execTerm (void);
TypePtr execSimpleExpression (void);
TypePtr execExpression (void);
//*****************
// EXECSTD routines
//*****************
//TypePtr execStandardRoutineCall (SymTableNodePtr routineIdPtr);
typedef TypePtr (* ABLExecFunctionType) (SymTableNodePtr);
extern ABLExecFunctionType routineExecFunction;
//***************************************************************************
}
#include "ablexec.inl"
#endif
+516
View File
@@ -0,0 +1,516 @@
//***************************************************************************
//
// ABLEXPR.CPP
//
//***************************************************************************
#include "MW4Headers.hpp"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef ABLGEN_H
#include "ablgen.h"
#endif
#ifndef ABLERR_H
#include "ablerr.h"
#endif
#ifndef ABLSCAN_H
#include "ablscan.h"
#endif
#ifndef ABLSYMT_H
#include "ablsymt.h"
#endif
#ifndef ABLPARSE_H
#include "ablparse.h"
#endif
#ifndef ABLEXEC_H
#include "ablexec.h"
#endif
#ifndef ABLHEAP_H
#include "ablheap.h"
#endif
namespace ABL
{
//***************************************************************************
extern TokenCodeType curToken;
extern char tokenString[];
extern char wordString[];
extern Literal curLiteral;
extern SymTableNodePtr SymTableDisplay[];
extern long level;
extern TypePtr IntegerTypePtr, CharTypePtr, RealTypePtr, BooleanTypePtr;
extern Type DummyType;
extern TokenCodeType statementEndList[];
extern UserHeapPtr AblSymTableHeap;
//***************************************************************************
TokenCodeType relationalOperatorList[] = {
TKN_LT,
TKN_LE,
TKN_EQUALEQUAL,
TKN_NE,
TKN_GE,
TKN_GT,
TKN_NONE
};
TokenCodeType addOperatorList[] = {
TKN_PLUS,
TKN_MINUS,
TKN_OR,
TKN_NONE
};
TokenCodeType multiplyOperatorList[] = {
TKN_STAR,
TKN_FSLASH,
TKN_DIV, // we'll probably want to make this covered with FSLASH
TKN_MOD,
TKN_AND,
TKN_NONE
};
//***************************************************************************
// MISC
//***************************************************************************
/*
inline void ifTokenGet (TokenCodeType tokenCode) {
if (curToken == tokenCode)
getToken();
}
//***************************************************************************
inline void ifTokenGetElseError (TokenCodeType tokenCode, SyntaxErrorType errCode) {
if (curToken == tokenCode)
getToken();
else
syntaxError(errCode);
}
//***************************************************************************
*/
/*inline*/ TypePtr baseType (TypePtr thisType) {
//---------------------------------------------------------------------
// Since we don't have a sub-range type, block this out for now.
// However, if we decide to put a subrange type into ABL, the following
// three lines should be included...
//if (thisType->form == FRM_SUBRANGE)
// return(thisType->info.subrange.rangeTypePtr;
//else
return(thisType);
}
//***************************************************************************
inline bool integerOperands (TypePtr type1, TypePtr type2) {
return((type1 == IntegerTypePtr) && (type2 == IntegerTypePtr));
}
//***************************************************************************
inline bool realOperands (TypePtr type1, TypePtr type2) {
if (type1 == RealTypePtr)
return((type2 == RealTypePtr) || (type2 == IntegerTypePtr));
else if (type2 == RealTypePtr)
return(type1 == IntegerTypePtr);
else
return(false);
}
//***************************************************************************
inline bool booleanOperands (TypePtr type1, TypePtr type2) {
return((type1 == BooleanTypePtr) && (type2 == BooleanTypePtr));
}
//***************************************************************************
void checkRelationalOpTypes (TypePtr type1, TypePtr type2) {
if ((type1 == NULL) || (type2 == NULL))
{
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
return;
}
if ((type1 == type2) && ((type1->form == FRM_SCALAR) || (type1->form == FRM_ENUM)))
return;
if (((type1 == IntegerTypePtr) && (type2 == RealTypePtr)) ||
((type2 == IntegerTypePtr) && (type1 == RealTypePtr)))
return;
if ((type1->form == FRM_ARRAY) && (type2->form == FRM_ARRAY) &&
(type1->info.array.elementTypePtr == CharTypePtr) && (type2->info.array.elementTypePtr == CharTypePtr) &&
(type1->info.array.elementCount == type2->info.array.elementCount))
return;
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
}
//***************************************************************************
long isAssignTypeCompatible (TypePtr type1, TypePtr type2) {
type1 = baseType(type1);
type2 = baseType(type2);
if (type1 == type2)
return(1);
if ((type1 == RealTypePtr) && (type2 == IntegerTypePtr))
return(1);
if ((type1->form == FRM_ARRAY) && (type2->form == FRM_ARRAY) &&
(type1->info.array.elementTypePtr == CharTypePtr) && (type2->info.array.elementTypePtr == CharTypePtr) &&
(type1->info.array.elementCount >= type2->info.array.elementCount))
return(1);
return(0);
}
//***************************************************************************
// EXPRESSION routines
//***************************************************************************
TypePtr variable (SymTableNodePtr variableIdPtr) {
TypePtr typePtr = (TypePtr)(variableIdPtr->typePtr);
DefinitionType defnKey = variableIdPtr->defn.key;
crunchSymTableNodePtr(variableIdPtr);
switch (defnKey) {
case DFN_VAR:
case DFN_VALPARAM:
case DFN_REFPARAM:
case DFN_FUNCTION:
//case DFN_MODULE:
case DFN_UNDEFINED:
break;
default:
typePtr = &DummyType;
syntaxError(ABL_ERR_SYNTAX_INVALID_IDENTIFIER_USAGE);
}
getToken();
//---------------------------------------------------------------------
// There should not be a parameter list. However, if there is, parse it
// for error recovery...
if (curToken == TKN_LPAREN) {
syntaxError(ABL_ERR_SYNTAX_UNEXPECTED_TOKEN);
actualParamList(variableIdPtr, 0);
return(typePtr);
}
//--------------------------------------------------------------------
// Subscripts or field designators (when/if we support record types :)
while ((curToken == TKN_LBRACKET) || (curToken == TKN_PERIOD)) {
if (curToken == TKN_LBRACKET)
typePtr = arraySubscriptList(typePtr);
else
STOP(("666???"));
//typePtr = recordField(typePtr);
}
return(typePtr);
}
//***************************************************************************
TypePtr arraySubscriptList (TypePtr typePtr) {
TypePtr indexTypePtr = NULL;
TypePtr elementTypePtr = NULL;
TypePtr subscriptTypePtr = NULL;
do {
if (typePtr->form == FRM_ARRAY) {
indexTypePtr = typePtr->info.array.indexTypePtr;
elementTypePtr = typePtr->info.array.elementTypePtr;
getToken();
subscriptTypePtr = expression();
//-------------------------------------------------------------
// If the subscript expression isn't assignment type compatible
// with its corresponding subscript type, we're screwed...
if (!isAssignTypeCompatible(indexTypePtr, subscriptTypePtr))
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
typePtr = elementTypePtr;
}
else {
syntaxError(ABL_ERR_SYNTAX_TOO_MANY_SUBSCRIPTS);
while ((curToken != TKN_RBRACKET) && !tokenIn(statementEndList))
getToken();
}
} while (curToken == TKN_COMMA);
ifTokenGetElseError(TKN_RBRACKET, ABL_ERR_SYNTAX_MISSING_RBRACKET);
return(typePtr);
}
//***************************************************************************
TypePtr factor (void) {
TypePtr thisType = NULL;
switch (curToken) {
case TKN_IDENTIFIER: {
SymTableNodePtr IdPtr = NULL;
searchAndFindAllSymTables(IdPtr);
switch (IdPtr->defn.key) {
case DFN_FUNCTION:
crunchSymTableNodePtr(IdPtr);
getToken();
thisType = routineCall(IdPtr, 1);
break;
case DFN_CONST:
crunchSymTableNodePtr(IdPtr);
getToken();
thisType = (TypePtr)(IdPtr->typePtr);
break;
default:
thisType = (TypePtr)variable(IdPtr);
break;
}
}
break;
case TKN_NUMBER: {
SymTableNodePtr thisNode = searchSymTable(tokenString, SymTableDisplay[1]);
if (!thisNode)
//--------------------------------------------------------------------------
// NOTE: The following commented-out line is from MAK. However, I believe we
// want the ampersand, as inserted in the following line...
// thisNode = enterSymTable(tokenString, SymTableDisplay[1]);
thisNode = enterSymTable(tokenString, &SymTableDisplay[1]);
if (curLiteral.type == LIT_INTEGER) {
thisNode->typePtr = IntegerTypePtr;
thisType = (TypePtr)(thisNode->typePtr);
thisNode->defn.info.constant.value.integer = curLiteral.value.integer;
}
else {
thisNode->typePtr = RealTypePtr;
thisType = (TypePtr)(thisNode->typePtr);
thisNode->defn.info.constant.value.real = curLiteral.value.real;
}
crunchSymTableNodePtr(thisNode);
getToken();
}
break;
case TKN_STRING: {
long length = strlen(curLiteral.value.string);
SymTableNodePtr thisNode = searchSymTable(tokenString, SymTableDisplay[1]);
if (!thisNode)
//--------------------------------------------------------------------------
// NOTE: The following commented-out line is from MAK. However, I believe we
// want the ampersand, as inserted in the following line...
// thisNode = enterSymTable(tokenString, SymTableDisplay[1]);
thisNode = enterSymTable(tokenString, &SymTableDisplay[1]);
if (length == 1) {
thisNode->defn.info.constant.value.character = curLiteral.value.string[0];
thisType = CharTypePtr;
}
else {
thisNode->typePtr = thisType = makeStringType(length);
thisNode->info = (char*)AblSymTableHeap->Malloc(length + 1);
if (!thisNode->info)
ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc string literal ");
strcpy(thisNode->info, curLiteral.value.string);
}
crunchSymTableNodePtr(thisNode);
getToken();
}
break;
case TKN_NOT:
getToken();
thisType = factor();
break;
case TKN_LPAREN:
getToken();
thisType = expression();
ifTokenGetElseError(TKN_RPAREN, ABL_ERR_SYNTAX_MISSING_RPAREN);
break;
default:
syntaxError(ABL_ERR_SYNTAX_INVALID_EXPRESSION);
thisType = &DummyType;
break;
}
return(thisType);
}
//***************************************************************************
TypePtr term (void) {
//-------------------------
// Grab the first factor...
TypePtr resultType = factor();
//------------------------------------------------------------------
// Now, continue grabbing factors separated by multiply operators...
while (tokenIn(multiplyOperatorList)) {
TokenCodeType op = curToken;
resultType = baseType(resultType);
getToken();
TypePtr secondType = baseType(factor());
switch (op) {
case TKN_STAR:
if (integerOperands(resultType, secondType)) {
//---------------------------------------------------
// Both operands are integer, so result is integer...
resultType = IntegerTypePtr;
}
else if (realOperands(resultType, secondType)) {
//----------------------------------------------------
// Both real operands, or mixed (real and integer)...
resultType = RealTypePtr;
}
else {
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
resultType = &DummyType;
}
break;
case TKN_FSLASH:
if (integerOperands(resultType, secondType)) {
//---------------------------------------------------
// Both operands are integer, so result is integer...
resultType = IntegerTypePtr;
}
else if (realOperands(resultType, secondType)) {
//----------------------------------------------------
// Both real operands, or mixed (real and integer)...
resultType = RealTypePtr;
}
else {
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
resultType = &DummyType;
}
break;
case TKN_DIV:
case TKN_MOD:
//----------------------------------------------------------
// Both operands should be integer, and result is integer...
if (!integerOperands(resultType, secondType))
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
resultType = IntegerTypePtr;
break;
case TKN_AND:
if (!booleanOperands(resultType, secondType))
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
resultType = BooleanTypePtr;
break;
}
}
return(resultType);
}
//***************************************************************************
TypePtr simpleExpression (void) {
bool usedUnaryOp = false;
TokenCodeType unaryOp = TKN_PLUS;
if ((curToken == TKN_PLUS) || (curToken == TKN_MINUS)) {
unaryOp = curToken;
usedUnaryOp = true;
getToken();
}
//------------------------------------------------
// Grab the first term in the simple expression...
TypePtr resultType = term();
if (usedUnaryOp && (baseType(resultType) != IntegerTypePtr) && (resultType != RealTypePtr))
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
//---------------------------------------------------
// Continue to process all terms in the expression...
while (tokenIn(addOperatorList)) {
TokenCodeType op = curToken;
resultType = baseType(resultType);
getToken();
TypePtr secondType = baseType(term());
switch (op) {
case TKN_PLUS:
case TKN_MINUS:
if (integerOperands(resultType, secondType)) {
//---------------------------------------------------
// Both operands are integer, so result is integer...
resultType = IntegerTypePtr;
}
else if (realOperands(resultType, secondType)) {
//----------------------------------------------------
// Both real operands, or mixed (real and integer)...
resultType = RealTypePtr;
}
else {
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
resultType = &DummyType;
}
break;
case TKN_OR:
if (!booleanOperands(resultType, secondType))
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
resultType = BooleanTypePtr;
break;
}
}
return(resultType);
}
//***************************************************************************
TypePtr expression (void) {
//------------------------------------
// Grab the first simple expression...
TypePtr resultType = simpleExpression();
if (tokenIn(relationalOperatorList)) {
resultType = baseType(resultType);
//---------------------------------------
// Snatch the second simple expression...
getToken();
TypePtr secondType = baseType(simpleExpression());
checkRelationalOpTypes(resultType, secondType);
resultType = BooleanTypePtr;
}
return(resultType);
}
//***************************************************************************
}
+56
View File
@@ -0,0 +1,56 @@
//***************************************************************************
//
// GENERAL.H
//
//***************************************************************************
#ifndef ABLGEN_H
#define ABLGEN_H
//***************************************************************************
namespace ABL
{
//---------------------------------------------------------------------
// Set this, once we have the actual executor modules up and running...
#define USE_COMPOUND_STATEMENTS 0
#define ANALYZE_ON 0
#define CHAR_FORMFEED '\f'
#define CHAR_EOF '\x7f'
#define MAX_INCLUDE_DEPTH 6
#define MAXLEN_FILENAME 256
#define MAXLEN_SOURCELINE 2048
#define MAXLEN_PRINTLINE 80
#define MAXLEN_TOKENSTRING MAXLEN_SOURCELINE
#define MAX_LINES_PER_PAGE 50
#define MAXLEN_STRING_CONSTANT 1024
#define MAX_NESTING_LEVEL 3
#define LEN_DATESTRING 26
#define MAXSIZE_CODE_BUFFER 20480
#define MAXSIZE_STACK 10240
#define STACK_FRAME_HEADER_SIZE 4
#define SYSTEM_HEAP_SIZE 1024 * 1024 // General system memory...
// Masher Commands available...
#define COMMAND_HELP_SHORT 0
#define COMMAND_WAIT_LONG 1
#define COMMAND_WAIT_SHORT 2
#define COMMAND_RANDOM_LONG 3
#define COMMAND_RANDOM_SHORT 4
#define COMMAND_NUM_RUNS_LONG 5
#define COMMAND_NUM_RUNS_SHORT 6
//***************************************************************************
typedef char* Address;
}
//***************************************************************************
#endif
+108
View File
@@ -0,0 +1,108 @@
//***************************************************************************
//
// PARSER.H
//
//***************************************************************************
#ifndef ABLPARSE_H
#define ABLPARSE_H
#include "ablgen.h"
#include "ablsymt.h"
#include "ablerr.h"
//***************************************************************************
namespace ABL
{
typedef enum {
USE_EXPR,
USE_TARGET,
USE_REFPARAM
} UseType;
typedef enum {
BLOCK_MODULE,
BLOCK_ROUTINE
} BlockType;
//***************************************************************************
//----------
// FUNCTIONS
TypePtr baseType (TypePtr thisType);
TypePtr expression (void);
TypePtr variable (SymTableNodePtr variableIdPtr);
TypePtr arraySubscriptList (TypePtr typePtr);
//TypePtr routineCall (SymTableNodePtr routineIdPtr, BOOL parmCheckFlag);
TypePtr baseType (void);
void checkRelationalOpTypes (TypePtr type1, TypePtr type2);
long isAssignTypeCompatible (TypePtr type1, TypePtr type2);
void ifTokenGet (TokenCodeType tokenCode);
void ifTokenGetElseError (TokenCodeType tokenCode, SyntaxErrorType errCode);
// DECL routines
void declarations (SymTableNodePtr routineIdPtr, long allowFunctions, long allowStates);
void constDefinitions (void);
void doConst (SymTableNodePtr constantIdPtr);
void varDeclarations (SymTableNodePtr routineIdPtr);
void varOrFieldDeclarations (SymTableNodePtr routineIdPtr, long offset);
void typeDefinitions (void);
TypePtr doType (void);
TypePtr identifierType (SymTableNodePtr idPtr);
TypePtr enumerationType (void);
TypePtr subrangeType (void);
TypePtr arrayType (void);
long arraySize (TypePtr typePtr);
TypePtr makeStringType (long length);
// ROUTINE functions
void module (void);
SymTableNodePtr moduleHeader (void);
void routine (void);
SymTableNodePtr functionHeader (void);
SymTableNodePtr formalParamList (long* count, long* totalSize);
TypePtr routineCall (SymTableNodePtr routineIdPtr, long paramCheckFlag);
TypePtr declaredRoutineCall (SymTableNodePtr routineIdPtr, long paramCheckFlag);
void actualParamList (SymTableNodePtr routineIdPtr, long paramCheckFlag);
void block (SymTableNodePtr routineIdPtr);
void state (void);
SymTableNodePtr stateHeader (void);
// STATEMNT routines
void compoundStatement (void);
void assignmentStatement (SymTableNodePtr varIdPtr);
void repeatStatement (void);
void whileStatement (void);
void ifStatement (void);
void forStatement (void);
void switchStatement (void);
void statement (void);
// STANDARD routines
TypePtr stdPrint (void);
TypePtr stdAbs (void);
TypePtr stdRound (void);
TypePtr stdTrunc (void);
TypePtr stdSqrt (void);
TypePtr stdRandom (void);
TypePtr standardRoutineCall (SymTableNodePtr routineIdPtr);
// FILE routines
long openSourceFile (char* sourceFileName);
long closeSourceFile (void);
#if !ANALYZE_ON
#define analyzeConstDefn(idPtr)
#define analyzeVarDecl(idPtr)
#define analyzeTypeDefn(idPtr)
#define analyzeRoutineHeader(idPtr)
#define analyzeBlock(idPtr)
#endif
}
//***************************************************************************
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+188
View File
@@ -0,0 +1,188 @@
//***************************************************************************
//
// SCANNER.H
//
//***************************************************************************
#ifndef ABLSCAN_H
#define ABLSCAN_H
#include "ablgen.h"
#include "ablerr.h"
namespace ABL
{
//***************************************************************************
#define TAB_SIZE 4
//#define MIN_INTEGER -2147483648
#define MAX_INTEGER 2147483647
#define MAX_DIGIT_COUNT 20
#define MAX_EXPONENT 20
//***************************************************************************
//------------
// TOKEN CODES
typedef enum {
TKN_NONE,
TKN_IDENTIFIER,
TKN_NUMBER,
TKN_TYPE,
TKN_STRING,
TKN_STAR,
TKN_LPAREN,
TKN_RPAREN,
TKN_MINUS,
TKN_PLUS,
TKN_EQUAL,
TKN_LBRACKET,
TKN_RBRACKET,
TKN_COLON,
TKN_SEMICOLON,
TKN_LT,
TKN_GT,
TKN_COMMA,
TKN_PERIOD,
TKN_FSLASH,
TKN_EQUALEQUAL,
TKN_LE,
TKN_GE,
TKN_NE,
TKN_EOF,
TKN_ERROR,
TKN_CODE,
TKN_ORDERS,
TKN_AND,
TKN_SWITCH,
TKN_CASE,
TKN_CONST,
TKN_DIV,
TKN_DO,
TKN_OF,
TKN_ELSE,
TKN_END_IF,
TKN_END_WHILE,
TKN_END_FOR,
TKN_END_FUNCTION,
TKN_END_MODULE,
TKN_END_LIBRARY,
TKN_END_VAR,
TKN_END_CODE,
TKN_END_CASE,
TKN_END_SWITCH,
TKN_FOR,
TKN_FUNCTION,
TKN_IF,
TKN_MOD,
TKN_NOT,
TKN_OR,
TKN_REPEAT,
TKN_THEN,
TKN_TO,
TKN_UNTIL,
TKN_VAR,
TKN_REF,
TKN_WHILE,
TKN_ELSIF,
TKN_RETURN,
TKN_MODULE,
TKN_LIBRARY,
TKN_ETERNAL,
TKN_STATIC,
TKN_FSM,
TKN_END_FSM,
TKN_STATE,
TKN_END_STATE,
TKN_TRANS,
TKN_POUND,
TKN_UNEXPECTED_TOKEN,
TKN_STATEMENT_MARKER,
TKN_ADDRESS_MARKER,
NUM_TOKENS
} TokenCodeType;
typedef enum {
CHR_LETTER,
CHR_DIGIT,
CHR_DQUOTE,
CHR_SPECIAL,
CHR_EOF
} CharCodeType;
typedef struct {
char* string;
TokenCodeType tokenCode;
} ReservedWord;
//***************************************************************************
//------------------
// LITERAL structure
typedef enum {
LIT_INTEGER,
LIT_REAL,
LIT_STRING
} LiteralType;
typedef struct {
LiteralType type;
struct {
long integer;
float real;
char string[MAXLEN_TOKENSTRING];
} value;
} Literal;
//---------------------------------------------------------------------------
typedef struct CaseItem {
int labelValue;
char* branchLocation;
struct CaseItem* next;
} CaseItem;
typedef CaseItem* CaseItemPtr;
//***************************************************************************
//----------
// FUNCTIONS
inline CharCodeType calcCharCode (long ch);
long isReservedWord (void);
void initScanner (char* fileName);
void quitScanner (void);
void skipComment (void);
void skipBlanks (void);
void getChar(void);
void crunchToken (void);
void downShiftWord (void);
void getToken(void);
void getWord (void);
void accumulateValue (float* valuePtr, SyntaxErrorType errCode);
void getNumber (void);
void getString (void);
void getSpecial (void);
bool tokenIn (TokenCodeType* tokenList);
void synchronize (TokenCodeType* tokenList1,
TokenCodeType* tokenList2,
TokenCodeType* tokenList3);
bool getSourceLine (void);
void printLine (char* line);
void initPageHeader (char* fileName);
void printPageHeader (void);
//----------
// VARIABLES
extern char wordString[MAXLEN_TOKENSTRING];
//***************************************************************************
}
#endif
File diff suppressed because it is too large Load Diff
+578
View File
@@ -0,0 +1,578 @@
//***************************************************************************
//
// ABLSTMT.CPP
//
//***************************************************************************
#include "MW4Headers.hpp"
#ifndef ABLGEN_H
#include "ablgen.h"
#endif
#ifndef ABLERR_H
#include "ablerr.h"
#endif
#ifndef ABLSCAN_H
#include "ablscan.h"
#endif
#ifndef ABLSYMT_H
#include "ablsymt.h"
#endif
#ifndef ABLPARSE_H
#include "ablparse.h"
#endif
#ifndef ABLEXEC_H
#include "ablexec.h"
#endif
#ifndef ABLHEAP_H
#include "ablheap.h"
#endif
#include "ablfuncs.hpp"
namespace ABL
{
//***************************************************************************
extern TokenCodeType curToken;
extern char tokenString[];
extern char wordString[];
extern Literal curLiteral;
extern TokenCodeType statementStartList[];
extern TokenCodeType statementEndList[];
extern SymTableNodePtr symTableDisplay[];
extern long level;
extern long FSMLevel;
extern char* codeBuffer;
extern TypePtr IntegerTypePtr;
extern TypePtr RealTypePtr;
extern TypePtr BooleanTypePtr;
extern TypePtr CharTypePtr;
extern Type DummyType;
extern SymTableNodePtr CurRoutineIdPtr;
extern UserHeapPtr AblStackHeap;
extern SymTableNodePtr SymTableDisplay[MAX_NESTING_LEVEL];
extern bool AssertEnabled;
extern bool PrintEnabled;
extern bool StringFunctionsEnabled;
extern bool Crunch;
extern bool parsingFSM;
extern ABLModulePtr CurLibrary;
//--------
// GLOBALS
TokenCodeType FollowSwitchExpressionList[] = {
TKN_CASE,
TKN_SEMICOLON,
TKN_NONE
};
TokenCodeType FollowCaseLabelList[] = {
TKN_COLON,
TKN_SEMICOLON,
TKN_NONE
};
TokenCodeType CaseLabelStartList[] = {
TKN_IDENTIFIER,
TKN_NUMBER,
TKN_PLUS,
TKN_MINUS,
TKN_STRING,
TKN_NONE
};
//***************************************************************************
void assignmentStatement (SymTableNodePtr varIdPtr) {
//-----------------------------------
// Grab the variable we're setting...
TypePtr varType = variable(varIdPtr);
ifTokenGetElseError(TKN_EQUAL, ABL_ERR_SYNTAX_MISSING_EQUAL);
//---------------------------------------------------------
// Now, get the expression we're setting the variable to...
TypePtr exprType = expression();
//----------------------------------------
// They better be assignment compatible...
if (!isAssignTypeCompatible(varType, exprType))
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_ASSIGNMENT);
}
//***************************************************************************
void repeatStatement (void) {
getToken();
if (curToken != TKN_UNTIL) {
do {
statement();
while (curToken == TKN_SEMICOLON)
getToken();
if (curToken == TKN_UNTIL)
break;
} while (tokenIn(statementStartList));
}
ifTokenGetElseError(TKN_UNTIL, ABL_ERR_SYNTAX_MISSING_UNTIL);
TypePtr exprType = expression();
if (exprType != BooleanTypePtr)
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
}
//***************************************************************************
void whileStatement (void) {
// NEW STYLE, using endwhile keyword...
getToken();
char* loopEndLocation = crunchAddressMarker(NULL);
TypePtr exprType = expression();
if (exprType != BooleanTypePtr)
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
//---------------------------------------
// Let's not use a DO keyword, for now...
ifTokenGetElseError(TKN_DO, ABL_ERR_SYNTAX_MISSING_DO);
if (curToken != TKN_END_WHILE)
do {
statement();
while (curToken == TKN_SEMICOLON)
getToken();
if (curToken == TKN_END_WHILE)
break;
} while (tokenIn(statementStartList));
ifTokenGetElseError(TKN_END_WHILE, ABL_ERR_SYNTAX_MISSING_END_WHILE);
fixupAddressMarker(loopEndLocation);
}
//***************************************************************************
void ifStatement (void) {
getToken();
char* falseLocation = crunchAddressMarker(NULL);
TypePtr exprType = expression();
if (exprType != BooleanTypePtr)
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
ifTokenGetElseError(TKN_THEN, ABL_ERR_SYNTAX_MISSING_THEN);
if ((curToken != TKN_END_IF) && (curToken != TKN_ELSE))
do {
statement();
while (curToken == TKN_SEMICOLON)
getToken();
if ((curToken == TKN_END_IF) || (curToken == TKN_ELSE))
break;
} while (tokenIn(statementStartList));
fixupAddressMarker(falseLocation);
//-----------------------------
// ELSE branch, if necessary...
if (curToken == TKN_ELSE) {
getToken();
char* ifEndLocation = crunchAddressMarker(NULL);
if (curToken != TKN_END_IF)
do {
statement();
while (curToken == TKN_SEMICOLON)
getToken();
if (curToken == TKN_END_IF)
break;
} while (tokenIn(statementStartList));
fixupAddressMarker(ifEndLocation);
}
ifTokenGetElseError(TKN_END_IF, ABL_ERR_SYNTAX_MISSING_END_IF);
}
//***************************************************************************
void forStatement (void) {
getToken();
char* loopEndLocation = crunchAddressMarker(NULL);
TypePtr forType = NULL;
if (curToken == TKN_IDENTIFIER) {
SymTableNodePtr forIdPtr = NULL;
searchAndFindAllSymTables(forIdPtr);
crunchSymTableNodePtr(forIdPtr);
if (/*(forIdPtr->level != level) ||*/ (forIdPtr->defn.key != DFN_VAR))
syntaxError(ABL_ERR_SYNTAX_INVALID_FOR_CONTROL);
forType = baseType((TypePtr)(forIdPtr->typePtr));
getToken();
//------------------------------------------------------------------
// If we end up adding a CHAR type, this line needs to be changed...
if ((forType != IntegerTypePtr) && /*(forType != CharTypePtr) &&*/ (forType->form != FRM_ENUM))
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
}
else {
syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER);
forType = &DummyType;
}
ifTokenGetElseError(TKN_EQUAL, ABL_ERR_SYNTAX_MISSING_EQUAL);
TypePtr exprType = expression();
if (!isAssignTypeCompatible(forType, exprType))
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
if (curToken == TKN_TO)
getToken();
else
syntaxError(ABL_ERR_SYNTAX_MISSING_TO);
exprType = expression();
if (!isAssignTypeCompatible(forType, exprType))
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
//-----------------------------------------
// For now, let's use the DO keyword...
ifTokenGetElseError(TKN_DO, ABL_ERR_SYNTAX_MISSING_DO);
if (curToken != TKN_END_FOR)
do {
statement();
while (curToken == TKN_SEMICOLON)
getToken();
if (curToken == TKN_END_FOR)
break;
} while (tokenIn(statementStartList));
ifTokenGetElseError(TKN_END_FOR, ABL_ERR_SYNTAX_MISSING_END_FOR);
fixupAddressMarker(loopEndLocation);
}
//***************************************************************************
TypePtr caseLabel (CaseItemPtr& caseItemHead, CaseItemPtr& caseItemTail, long& caseLabelCount) {
CaseItemPtr newCaseItem = (CaseItemPtr)AblStackHeap->Malloc(sizeof(CaseItem));
if (!newCaseItem)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc case item ");
if (caseItemHead) {
caseItemTail->next = newCaseItem;
caseItemTail = newCaseItem;
}
else
caseItemHead = caseItemTail = newCaseItem;
newCaseItem->next = NULL;
caseLabelCount++;
TokenCodeType sign = TKN_PLUS;
bool sawSign = false;
if ((curToken == TKN_PLUS) || (curToken == TKN_MINUS)) {
sign = curToken;
sawSign = true;
getToken();
}
if (curToken == TKN_NUMBER) {
SymTableNodePtr thisNode = searchSymTable(tokenString, SymTableDisplay[1]);
if (!thisNode)
thisNode = enterSymTable(tokenString, &SymTableDisplay[1]);
crunchSymTableNodePtr(thisNode);
if (curLiteral.type == LIT_INTEGER)
newCaseItem->labelValue = (sign == TKN_PLUS) ? curLiteral.value.integer : -curLiteral.value.integer;
else
syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
return(IntegerTypePtr);
}
else if (curToken == TKN_IDENTIFIER) {
SymTableNodePtr idPtr;
searchAllSymTables(idPtr);
crunchSymTableNodePtr(idPtr);
if (!idPtr) {
syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER);
return(&DummyType);
}
else if (idPtr->defn.key != DFN_CONST) {
syntaxError(ABL_ERR_SYNTAX_NOT_A_CONSTANT_IDENTIFIER);
return(&DummyType);
}
else if (idPtr->typePtr == IntegerTypePtr) {
newCaseItem->labelValue = (sign == TKN_PLUS ? idPtr->defn.info.constant.value.integer : -idPtr->defn.info.constant.value.integer);
return(IntegerTypePtr);
}
else if (idPtr->typePtr == CharTypePtr) {
if (sawSign)
syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
newCaseItem->labelValue = idPtr->defn.info.constant.value.character;
return(CharTypePtr);
}
else if (idPtr->typePtr->form == FRM_ENUM) {
if (sawSign)
syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
newCaseItem->labelValue = idPtr->defn.info.constant.value.integer;
return(idPtr->typePtr);
}
else
return(&DummyType);
}
else if (curToken == TKN_STRING) {
// STRING/CHAR TYPE...
}
else {
syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
return(&DummyType);
}
return(&DummyType);
}
//---------------------------------------------------------------------------
void caseBranch (CaseItemPtr& caseItemHead, CaseItemPtr& caseItemTail, long& caseLabelCount, TypePtr expressionType) {
//static CaseItemPtr oldCaseItemTail = NULL;
CaseItemPtr oldCaseItemTail = caseItemTail;
bool anotherLabel;
do {
TypePtr labelType = caseLabel(caseItemHead, caseItemTail, caseLabelCount);
if (expressionType != labelType)
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
getToken();
if (curToken == TKN_COMMA) {
getToken();
if (tokenIn(CaseLabelStartList))
anotherLabel = true;
else {
syntaxError(ABL_ERR_SYNTAX_MISSING_CONSTANT);
anotherLabel = false;
}
}
else
anotherLabel = false;
} while (anotherLabel);
//--------------
// Error sync...
synchronize(FollowCaseLabelList, statementStartList, NULL);
ifTokenGetElseError(TKN_COLON, ABL_ERR_SYNTAX_MISSING_COLON);
//-----------------------------------------------------------------
// Fill in the branch location for each CaseItem for this branch...
CaseItemPtr caseItem = (!oldCaseItemTail ? caseItemHead : oldCaseItemTail->next);
//oldCaseItemTail = CaseItemTail;
while (caseItem) {
caseItem->branchLocation = codeBufferPtr;
caseItem = caseItem->next;
}
if (curToken != TKN_END_CASE)
do {
statement();
while (curToken == TKN_SEMICOLON)
getToken();
if (curToken == TKN_END_CASE)
break;
} while (tokenIn(statementStartList));
ifTokenGetElseError(TKN_END_CASE, ABL_ERR_SYNTAX_MISSING_END_CASE);
ifTokenGetElseError(TKN_SEMICOLON, ABL_ERR_SYNTAX_MISSING_SEMICOLON);
}
//---------------------------------------------------------------------------
void switchStatement (void) {
//-------------------------
// Init the branch table...
getToken();
char* branchTableLocation = crunchAddressMarker(NULL);
CaseItemPtr caseItemHead = NULL;
CaseItemPtr caseItemTail = NULL;
long caseLabelCount = 0;
//CaseItemHead = CaseItemTail = NULL;
//CaseLabelCount = 0;
TypePtr expressionType = expression();
//-----------------------------------------------------------------------------
// NOTE: If we have subranges in ABL, we'll have to check in the following line
// for a subrange, as well...
if (((expressionType->form != FRM_SCALAR) && (expressionType->form != FRM_ENUM)) || (expressionType == RealTypePtr))
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
synchronize(FollowSwitchExpressionList, NULL, NULL);
//----------------------------
// Process each CASE branch...
bool moreBranches = (curToken == TKN_CASE);
char* caseEndChain = NULL;
while (moreBranches) {
getToken();
if (tokenIn(CaseLabelStartList))
caseBranch(caseItemHead, caseItemTail, caseLabelCount, expressionType);
//---------------------------------------------------
// Link another address marker at the end of the CASE
// branch to point to the end of the CASE block...
caseEndChain = crunchAddressMarker(caseEndChain);
moreBranches = (curToken == TKN_CASE);
}
//if (curToken == TKN_DEFAULT) {
//}
//-------------------------
// Emit the branch table...
fixupAddressMarker(branchTableLocation);
crunchInteger(caseLabelCount);
CaseItemPtr caseItem = caseItemHead;
while (caseItem) {
crunchInteger(caseItem->labelValue);
crunchOffset(caseItem->branchLocation);
CaseItemPtr nextCaseItem = caseItem->next;
AblStackHeap->Free(caseItem);
caseItem = nextCaseItem;
}
ifTokenGetElseError(TKN_END_SWITCH, ABL_ERR_SYNTAX_MISSING_END_SWITCH);
//--------------------------------------------
// Patch up the case branch address markers...
while (caseEndChain)
caseEndChain = fixupAddressMarker(caseEndChain);
}
//***************************************************************************
void statement (void) {
//-------------------------------------------------------------------
// NOTE: Since we currently don't support generic BEGIN/END (compound
// statement) blocks...
if ((curToken != TKN_CODE) /*&& (curToken != TKN_BEGIN)*/)
crunchStatementMarker();
switch (curToken) {
case TKN_IDENTIFIER: {
SymTableNodePtr IdPtr = NULL;
//--------------------------------------------------------------
// First, do we have an assignment statement or a function call?
searchAndFindAllSymTables(IdPtr);
if ((IdPtr->defn.key == DFN_FUNCTION)/* || (IdPtr->defn.key == DFN_MODULE)*/) {
RoutineKey key = IdPtr->defn.info.routine.key;
if ((key == RTN_ASSERT) || (key == RTN_PRINT) || (key == RTN_CONCAT)) {
bool uncrunch = ((key == RTN_ASSERT) && !AssertEnabled) ||
((key == RTN_PRINT) && !PrintEnabled) ||
((key == RTN_CONCAT) && !StringFunctionsEnabled);
if (uncrunch) {
uncrunchStatementMarker();
Crunch = false;
}
}
crunchSymTableNodePtr(IdPtr);
getToken();
SymTableNodePtr thisRoutineIdPtr = CurRoutineIdPtr;
routineCall(IdPtr, 1);
CurRoutineIdPtr = thisRoutineIdPtr;
Crunch = true;
}
else
assignmentStatement(IdPtr);
}
break;
case TKN_REPEAT:
repeatStatement();
break;
case TKN_WHILE:
whileStatement();
break;
case TKN_IF:
ifStatement();
break;
case TKN_FOR:
forStatement();
break;
case TKN_SWITCH:
switchStatement();
break;
case TKN_TRANS:
if (!parsingFSM)
{
syntaxError (ABL_ERR_SYNTAX_TRANS_IN_NONFSM);
break;
}
SymTableNodePtr IdPtr = NULL;
Crunch = false;
getToken ();
Crunch = true;
Verify (FSMLevel != 0);
IdPtr = searchSymTable(wordString, SymTableDisplay[FSMLevel]);
// searchLocalSymTable(IdPtr);
if (IdPtr == NULL)
{
Verify (FSMLevel != 0);
IdPtr = enterSymTable(wordString, &SymTableDisplay[FSMLevel]);
// enterLocalSymTable(IdPtr);
IdPtr->defn.key = DFN_STATE;
IdPtr->defn.info.routine.key = RTN_FORWARD;
IdPtr->defn.info.routine.paramCount = 0;
IdPtr->defn.info.routine.totalParamSize = 0;
IdPtr->defn.info.routine.totalLocalSize = 0;
IdPtr->defn.info.routine.params = NULL;
IdPtr->defn.info.routine.locals = NULL;
IdPtr->defn.info.routine.localSymTable = NULL;
IdPtr->defn.info.routine.codeSegment = NULL;
IdPtr->library = CurLibrary;
IdPtr->typePtr = &DummyType;
IdPtr->labelIndex = 0;
IdPtr->level = (unsigned char) FSMLevel;
}
if (IdPtr->defn.key == DFN_STATE)
{
crunchSymTableNodePtr(IdPtr);
getToken ();
}
else
{
syntaxError (ABL_ERR_SYNTAX_TRANS_TO_NON_STATE);
}
break;
}
//---------------------------------------------------------------------
// Now, make sure the statement is closed off with the proper block end
// statement, if necessary (which is usually the case :).
synchronize(statementEndList, NULL, NULL);
if (tokenIn(statementStartList))
syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
}
//***************************************************************************
}
+968
View File
@@ -0,0 +1,968 @@
//***************************************************************************
//
// ABLSYMT.CPP
//
//***************************************************************************
#include "MW4Headers.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef ABLGEN_H
#include "ablgen.h"
#endif
#ifndef ABLERR_H
#include "ablerr.h"
#endif
#ifndef ABLSYMT_H
#include "ablsymt.h"
#endif
#ifndef ABLSCAN_H
#include "ablscan.h"
#endif
#ifndef ABLENV_H
#include "ablenv.h"
#endif
#ifndef ABLHEAP_H
#include "ablheap.h"
#endif
#include "ablfuncs.hpp"
namespace ABL
{
//***************************************************************************
//----------
// EXTERNALS
extern long level; // current nesting/scope level
extern UserHeapPtr AblSymTableHeap;
//--------
// GLOBALS
SymTableNodePtr SymTableDisplay[MAX_NESTING_LEVEL];
ABLModulePtr LibrariesUsed[MAX_LIBRARIES_USED];
long NumLibrariesUsed = 0;
//------------------
// Pre-defined types
TypePtr IntegerTypePtr;
TypePtr CharTypePtr;
TypePtr RealTypePtr;
TypePtr BooleanTypePtr;
Type DummyType = { // for erroneous type definitions
0,
FRM_NONE,
0,
NULL
};
//***************************************************************************
// MISC. (initially were macros)
//***************************************************************************
/*inline*/ void searchLocalSymTable (SymTableNodePtr& IdPtr) {
IdPtr = searchSymTable(wordString, SymTableDisplay[level]);
}
//***************************************************************************
inline void searchThisSymTable (SymTableNodePtr& IdPtr, SymTableNodePtr thisTable) {
IdPtr = searchSymTable(wordString, thisTable);
}
//***************************************************************************
/*inline*/ void searchAllSymTables (SymTableNodePtr& IdPtr) {
IdPtr = searchSymTableDisplay(wordString);
}
//***************************************************************************
/*inline*/ void enterLocalSymTable (SymTableNodePtr& IdPtr) {
IdPtr = enterSymTable(wordString, &SymTableDisplay[level]);
}
//***************************************************************************
inline void enterNameLocalSymTable (SymTableNodePtr& IdPtr, const char* name) {
IdPtr = enterSymTable(name, &SymTableDisplay[level]);
}
//***************************************************************************
/*inline*/ void searchAndFindAllSymTables (SymTableNodePtr& IdPtr) {
if ((IdPtr = searchSymTableDisplay(wordString)) == NULL)
{
syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER);
IdPtr = enterSymTable(wordString, &SymTableDisplay[level]);
IdPtr->defn.key = DFN_UNDEFINED;
IdPtr->typePtr = &DummyType;
}
}
//***************************************************************************
/*inline*/ void searchAndEnterLocalSymTable (SymTableNodePtr& IdPtr) {
if ((IdPtr = searchSymTable(wordString, SymTableDisplay[level])) == NULL)
IdPtr = enterSymTable(wordString, &SymTableDisplay[level]);
else
syntaxError(ABL_ERR_SYNTAX_REDEFINED_IDENTIFIER);
}
//***************************************************************************
/*inline*/ void searchAndEnterThisTable (SymTableNodePtr& IdPtr, SymTableNodePtr thisTable) {
if ((IdPtr = searchSymTable(wordString, thisTable)) == NULL)
IdPtr = enterSymTable(wordString, &thisTable);
else
syntaxError(ABL_ERR_SYNTAX_REDEFINED_IDENTIFIER);
}
//***************************************************************************
inline SymTableNodePtr symTableSuccessor (SymTableNodePtr nodeX) {
if (nodeX->right) {
// return the treeMin...
while (nodeX->left)
nodeX = nodeX->left;
return(nodeX);
}
SymTableNodePtr nodeY = nodeX->parent;
while (nodeY && (nodeX == nodeY->right)) {
nodeX = nodeY;
nodeY = nodeY->parent;
}
return(nodeY);
}
//***************************************************************************
// TYPE management routines
//***************************************************************************
TypePtr createType (void) {
TypePtr newType = (TypePtr)AblSymTableHeap->Malloc(sizeof(Type));
if (!newType)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc newType ");
newType->numInstances = 1;
newType->form = FRM_NONE;
newType->size = 0;
newType->typeIdPtr = NULL;
return(newType);
}
//---------------------------------------------------------------------------
TypePtr setType (TypePtr type) {
if (type)
type->numInstances++;
return(type);
}
//---------------------------------------------------------------------------
void clearType (TypePtr& type) {
if (type) {
type->numInstances--;
if (type->numInstances == 0) {
AblSymTableHeap->Free(type);
type = NULL;
}
}
}
//***************************************************************************
// SYMBOL TABLE routines
//***************************************************************************
void recordLibraryUsed (SymTableNodePtr memberNodePtr) {
//------------------------------------------------------------------
// If the library already on our list, then don't bother. Otherwise,
// add it to our list...
ABLModulePtr library = memberNodePtr->library;
for (long i = 0; i < NumLibrariesUsed; i++)
if (LibrariesUsed[i] == library)
return;
//---------------------------------------------------
// New library, so record it if we still have room...
if (NumLibrariesUsed > MAX_LIBRARIES_USED)
ABL_Fatal(0, " ABL: Too many libraries referenced from module ");
LibrariesUsed[NumLibrariesUsed++] = library;
}
//***************************************************************************
SymTableNodePtr searchSymTable (const char* name, SymTableNodePtr nodePtr) {
while (nodePtr) {
long compareResult = strcmp(name, nodePtr->name);
if (compareResult == 0)
return(nodePtr);
if (compareResult < 0)
nodePtr = nodePtr->left;
else
nodePtr = nodePtr->right;
}
return(NULL);
}
//***************************************************************************
SymTableNodePtr searchLibrarySymTable (const char* name, SymTableNodePtr nodePtr) {
//-------------------------------------------------------------
// Since all libraries are at the symbol display 0-level, we'll
// check the local symbol table of all libraries. WARNING: This
// will find the FIRST instance of a symbol with that name,
// so don't load two libraries with a similarly named function
// or variable, otherwise you may not get the one you want
// unless you explicitly reference the library you want
// (e.g. testLib.fudge, rather than just fudge). This is WAY
// inefficient compared to simply knowing the library we want,
// so any ABL programmer that causes this function to be called
// should be shot --gd 9/29/97
if (nodePtr) {
long compareResult = strcmp(name, nodePtr->name);
if (compareResult == 0)
return(nodePtr);
else {
if (nodePtr->library && (nodePtr->defn.key == DFN_MODULE)) {
SymTableNodePtr memberNodePtr = searchSymTable(name, nodePtr->defn.info.routine.localSymTable);
if (memberNodePtr)
return(memberNodePtr);
}
SymTableNodePtr nodeFoundPtr = searchLibrarySymTable(name, nodePtr->left);
if (nodeFoundPtr)
return(nodeFoundPtr);
nodeFoundPtr = searchLibrarySymTable(name, nodePtr->right);
if (nodeFoundPtr)
return(nodeFoundPtr);
}
}
return(NULL);
}
//***************************************************************************
SymTableNodePtr searchLibrarySymTableDisplay (const char* name) {
SymTableNodePtr nodePtr = searchLibrarySymTable(name, SymTableDisplay[0]);
return(nodePtr);
}
//***************************************************************************
SymTableNodePtr searchSymTableDisplay (const char* name) {
//---------------------------------------------------------------------
// First check if this is an explicit library reference. If so, we need
// to determine which library and which identifier in that library...
char* separator = strchr(name, '.');
SymTableNodePtr nodePtr = NULL;
if (separator) {
*separator = NULL;
SymTableNodePtr libraryNodePtr = searchSymTable(name, SymTableDisplay[0]);
if (!libraryNodePtr)
return(NULL);
//-------------------------------------
// Now, search for the member symbol...
char* memberName = separator + 1;
SymTableNodePtr memberNodePtr = searchSymTable(memberName, libraryNodePtr->defn.info.routine.localSymTable);
if (memberNodePtr)
recordLibraryUsed(memberNodePtr);
return(memberNodePtr);
}
else {
for (long i = level; i >= 0; i--) {
SymTableNodePtr nodePtr = searchSymTable(name, SymTableDisplay[i]);
if (nodePtr)
return(nodePtr);
}
//------------------------------------------------------------
// We haven't found it, so maybe it's from a library but just
// is not explicitly called with the library name. Since all
// libraries are at the symbol table's 0-level, we'll check
// the local symbol table of all libraries. WARNING: This
// will find the FIRST instance of a symbol with that name,
// so don't load two libraries with a similarly named function
// or variable, otherwise you may not get the one you want
// unless you explicitly reference the library you want
// (e.g. testLib.fudge, rather than just fudge)...
nodePtr = searchLibrarySymTableDisplay(name);
if (nodePtr)
recordLibraryUsed(nodePtr);
}
return(nodePtr);
}
//***************************************************************************
SymTableNodePtr enterSymTable (const char* name, SymTableNodePtr* ptrToNodePtr) {
//-------------------------------------
// First, create the new symbol node...
SymTableNodePtr newNode = (SymTableNodePtr)AblSymTableHeap->Malloc(sizeof(SymTableNode));
if (!newNode)
ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc symbol ");
newNode->name = (char*)AblSymTableHeap->Malloc(strlen(name) + 1);
if (!newNode->name)
ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc symbol name ");
strcpy(newNode->name, name);
newNode->left = NULL;
newNode->parent = NULL;
newNode->right = NULL;
newNode->next = NULL;
newNode->info = NULL;
newNode->defn.key = DFN_UNDEFINED;
newNode->defn.info.data.varType = VAR_TYPE_NORMAL;
newNode->defn.info.data.offset = 0;
newNode->typePtr = NULL;
newNode->level = (unsigned char) level;
newNode->labelIndex = 0;
//-------------------------------------
// Find where to put this new symbol...
SymTableNodePtr curNode = *ptrToNodePtr;
SymTableNodePtr parentNode = NULL;
while (curNode) {
if (strcmp(name, curNode->name) < 0)
ptrToNodePtr = &(curNode->left);
else
ptrToNodePtr = &(curNode->right);
parentNode = curNode;
curNode = *ptrToNodePtr;
}
newNode->parent = parentNode;
*ptrToNodePtr = newNode;
return(newNode);
}
//***************************************************************************
#if 0
SymTableNodePtr enterModuleInSymTable (char* name, SymTableNodePtr* ptrToNodePtr) {
//-------------------------------------
// First, create the new symbol node...
SymTableNodePtr newNode = (SymTableNodePtr)AblSymTableHeap->malloc(sizeof(SymTableNode));
newNode->name = (char*)AblSymTableHeap->malloc(strlen(name) + 1);
strcpy(newNode->name, name);
newNode->left = NULL;
newNode->right = NULL;
newNode->next = NULL;
newNode->info = NULL;
newNode->defn.key = DFN_UNDEFINED;
newNode->typePtr = NULL;
newNode->level = level;
newNode->labelIndex = 0;
//-------------------------------------
// Find where to put this new symbol...
SymTableNodePtr curNode = *ptrToNodePtr;
while (curNode) {
if (strcmp(name, curNode->name) < 0)
ptrToNodePtr = &(curNode->left);
else
ptrToNodePtr = &(curNode->right);
curNode = *ptrToNodePtr;
}
*ptrToNodePtr = newNode;
return(newNode);
}
#endif
//***************************************************************************
SymTableNodePtr insertSymTable (SymTableNodePtr* tableRoot, SymTableNodePtr newNode) {
newNode->left = NULL;
newNode->parent = NULL;
newNode->right = NULL;
//------------------------------------
// Find where to insert this symbol...
SymTableNodePtr curNode = *tableRoot;
SymTableNodePtr parentNode = NULL;
while (curNode) {
if (strcmp(newNode->name, curNode->name) < 0)
tableRoot = &(curNode->left);
else
tableRoot = &(curNode->right);
parentNode = curNode;
curNode = *tableRoot;
}
newNode->parent = parentNode;
*tableRoot = newNode;
return(newNode);
}
//***************************************************************************
SymTableNodePtr extractSymTable (SymTableNodePtr* tableRoot, SymTableNodePtr nodeKill) {
//------------------------------------------------------------------------
// NOTE: While this routine extracts a node from the symbol table,
// it does not account for other nodes in the table that may be pointing
// to the now-extracted node. Currently, this is not a problem as this
// routine is really just used to extract the module's Identifier at level
// 0 in the SymTable Display. Do we want to eliminate the use of the
// parent pointer, and just hardcode something that may be more efficient
// for this level-0 special case?
SymTableNodePtr nodeX = NULL;
SymTableNodePtr nodeY = NULL;
if ((nodeKill->left == NULL) || (nodeKill->right == NULL))
nodeY = nodeKill;
else
nodeY = symTableSuccessor(nodeKill);
if (nodeY->left)
nodeX = nodeY->left;
else
nodeX = nodeY->right;
if (nodeX)
nodeX->parent = nodeY->parent;
if (nodeY->parent == NULL)
*tableRoot = nodeX;
else if (nodeY == nodeY->parent->left)
nodeY->parent->left = nodeX;
else
nodeY->parent->right = nodeX;
if (nodeY != nodeKill) {
//--------------------------------------
// Copy y data to nodeKill's position...
nodeKill->next = nodeY->next;
nodeKill->name = nodeY->name;
nodeKill->info = nodeY->info;
memcpy(&nodeKill->defn, &nodeY->defn, sizeof(Definition));
nodeKill->typePtr = nodeY->typePtr;
nodeKill->level = nodeY->level;
nodeKill->labelIndex = nodeY->labelIndex;
}
return(nodeY);
}
//***************************************************************************
void enterStandardRoutine (const char* name, RoutineKey routineKey, DefinitionType definitionKey, bool isOrder) {
SymTableNodePtr routineIdPtr;
enterNameLocalSymTable(routineIdPtr, name);
routineIdPtr->defn.key = definitionKey;
routineIdPtr->defn.info.routine.key = routineKey;
routineIdPtr->defn.info.routine.isOrder = isOrder;
routineIdPtr->defn.info.routine.params = NULL;
routineIdPtr->defn.info.routine.localSymTable = NULL;
routineIdPtr->library = NULL;
routineIdPtr->typePtr = NULL;
}
//***************************************************************************
void enterScope (SymTableNodePtr symTableRoot) {
if (++level >= MAX_NESTING_LEVEL) {
STOP(("ABL syntax error #%d", ABL_ERR_SYNTAX_NESTING_TOO_DEEP));
}
SymTableDisplay[level] = symTableRoot;
}
//***************************************************************************
SymTableNodePtr exitScope (void) {
return(SymTableDisplay[level--]);
}
//***************************************************************************
void initSymTable (void) {
//---------------------------------
// Init the level-0 symbol table...
SymTableDisplay[0] = NULL;
//----------------------------------------------------------------------
// Set up the basic variable types as identifiers in the symbol table...
SymTableNodePtr integerIdPtr;
enterNameLocalSymTable(integerIdPtr, "integer");
SymTableNodePtr charIdPtr;
enterNameLocalSymTable(charIdPtr, "char");
SymTableNodePtr realIdPtr;
enterNameLocalSymTable(realIdPtr, "real");
SymTableNodePtr booleanIdPtr;
enterNameLocalSymTable(booleanIdPtr, "boolean");
SymTableNodePtr falseIdPtr;
enterNameLocalSymTable(falseIdPtr, "false");
SymTableNodePtr trueIdPtr;
enterNameLocalSymTable(trueIdPtr, "true");
//------------------------------------------------------------------
// Now, create the basic variable TYPEs, and point their identifiers
// to their proper type definition...
IntegerTypePtr = createType();
if (!IntegerTypePtr)
ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc Integer Type ");
CharTypePtr = createType();
if (!CharTypePtr)
ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc Char Type ");
RealTypePtr = createType();
if (!RealTypePtr)
ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc Real Type ");
BooleanTypePtr = createType();
if (!BooleanTypePtr)
ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc Boolean Type ");
integerIdPtr->defn.key = DFN_TYPE;
integerIdPtr->typePtr = IntegerTypePtr;
IntegerTypePtr->form = FRM_SCALAR;
IntegerTypePtr->size = sizeof(long);
IntegerTypePtr->typeIdPtr = integerIdPtr;
charIdPtr->defn.key = DFN_TYPE;
charIdPtr->typePtr = CharTypePtr;
CharTypePtr->form = FRM_SCALAR;
CharTypePtr->size = sizeof(char);
CharTypePtr->typeIdPtr = charIdPtr;
realIdPtr->defn.key = DFN_TYPE;
realIdPtr->typePtr = RealTypePtr;
RealTypePtr->form = FRM_SCALAR;
RealTypePtr->size = sizeof(float);
RealTypePtr->typeIdPtr = realIdPtr;
booleanIdPtr->defn.key = DFN_TYPE;
booleanIdPtr->typePtr = BooleanTypePtr;
BooleanTypePtr->form = FRM_ENUM;
BooleanTypePtr->size = sizeof(long);
BooleanTypePtr->typeIdPtr = booleanIdPtr;
//----------------------------------------------------
// Set up the FALSE identifier for the boolean type...
BooleanTypePtr->info.enumeration.max = 1;
((TypePtr)(booleanIdPtr->typePtr))->info.enumeration.constIdPtr = falseIdPtr;
falseIdPtr->defn.key = DFN_CONST;
falseIdPtr->defn.info.constant.value.integer = 0;
falseIdPtr->typePtr = BooleanTypePtr;
//----------------------------------------------------
// Set up the TRUE identifier for the boolean type...
falseIdPtr->next = trueIdPtr;
trueIdPtr->defn.key = DFN_CONST;
trueIdPtr->defn.info.constant.value.integer = 1;
trueIdPtr->typePtr = BooleanTypePtr;
//-------------------------------------------
// Set up the standard, built-in functions...
AddSpecificABLFunction("return", RTN_RETURN,stdReturn,execStdReturn);
AddSpecificABLFunction("print", RTN_PRINT,stdPrint,execStdPrint);
AddSpecificABLFunction("concat", RTN_CONCAT,stdConcat,execStdConcat);
AddSpecificABLFunction("abs", RTN_ABS, stdAbs,execStdAbs);
AddSpecificABLFunction("random", RTN_RANDOM, stdRandom,execStdRandom);
AddSpecificABLFunction("round", RTN_ROUND, stdRound,execStdRound);
AddSpecificABLFunction("sqrt", RTN_SQRT, stdSqrt,execStdSqrt);
AddSpecificABLFunction("trunc", RTN_TRUNC, stdTrunc,execStdTrunc);
AddSpecificABLFunction("getmodulehandle", RTN_GETMODHANDLE, stdGetModHandle,execStdGetModHandle);
AddSpecificABLFunction("getmodulename", RTN_GETMODNAME, stdGetModName,execStdGetModName);
AddSpecificABLFunction("setmodulename", RTN_SETMODNAME, stdSetModName,execStdSetModName);
AddSpecificABLFunction("setmaxloops", RTN_SETMAXLOOPS, stdSetMaxLoops,execStdSetMaxLoops);
AddSpecificABLFunction("fatal", RTN_FATAL, stdFatal,execStdFatal);
AddSpecificABLFunction("assert", RTN_ASSERT, stdAssert,execStdAssert);
//-----------------------------------
// MW4 specific extensions
//-----------------------------------
AddABLFunction("getplayer",ParseNoParamInteger,execgetPlayer);
AddABLFunction("getself",ParseNoParamInteger ,execgetSelf);
AddABLFunction("getplayervehicle",ParseOneIntegerInteger ,execgetPlayerVehicle);
AddABLFunction("setentropymood",ParseTwoInteger ,execsetEntropyMood);
AddABLFunction("settarget",ParseTwoInteger,execsetTarget);
AddABLFunction("gettarget",ParseOneIntegerInteger,execgetTarget);
AddABLFunction("whoshot",ParseOneIntegerInteger ,execwhoShot);
AddABLFunction("whodestroyed",ParseOneIntegerInteger ,execwhoDestroyed);
AddABLFunction("getnearestenemy",ParseOneIntegerInteger,execgetNearestEnemy);
AddABLFunction("findobject",hbFindObject,execFindObject);
AddABLFunction("findobjectexcept",hbFindObjectExcept,execFindObjectExcept);
AddABLFunction("setcurmood",ParseTwoInteger ,execsetCurMood);
AddABLFunction("gethp",ParseOneIntegerInteger ,execgetHP);
AddABLFunction("getlocation",hbgetLocation,execgetLocation);
AddABLFunction("getnearestpathpoint",hbgetNearestPathPoint ,execgetNearestPathPoint);
AddABLFunction("getgreatestthreat",ParseTwoIntegerInteger ,execgetGreatestThreat);
AddABLFunction("getleastthreat",ParseTwoIntegerInteger ,execgetLeastThreat);
AddABLFunction("getmechtype",ParseOneIntegerInteger,execgetMechType);
AddABLFunction("getalignment",ParseOneIntegerInteger ,execgetAlignment);
AddABLFunction("setalignment",ParseTwoInteger ,execsetAlignment);
AddABLFunction("getgunneryskill",ParseOneIntegerInteger,execgetGunnerySkill);
AddABLFunction("getpilotskill",ParseOneIntegerInteger,execgetPilotSkill);
AddABLFunction("setskilllevel",hbsetSkillLevel ,execsetSkillLevel);
AddABLFunction("setattackthrottle",ParseTwoInteger,execSetAttackThrottle);
AddABLFunction("getattackthrottle",ParseOneIntegerInteger,execGetAttackThrottle);
AddABLFunction("setignorefriendlyfire",ParseIntegerBoolean,execSetIgnoreFriendlyFire);
AddABLFunction("setfiringdelay",hbSetFiringDelay,execSetFiringDelay);
AddABLFunction("setcombatleash",hbSetCombatLeash,execSetCombatLeash);
AddABLFunction("setguitarget",ParseTwoInteger,execSetGUITarget);
AddABLFunction("getguitarget",ParseOneIntegerInteger,execGetGUITarget);
AddABLFunction("getzoomstate",ParseOneIntegerBoolean,execGetZoomState);
AddABLFunction("setcrouchstate",ParseIntegerBoolean,execSetCrouchState);
AddABLFunction("getteamnumber",ParseOneIntegerInteger,execGetTeamNumber);
AddABLFunction("teamexists",ParseOneIntegerBoolean,execTeamExists);
AddABLFunction("getgameparam",ParseOneIntegerInteger,execGetGameParam);
AddABLFunction("setteamtracking",ParseTwoInteger,execSetTeamTracking);
AddABLFunction("gettimer",ParseOneIntegerInteger ,execgetTimer);
AddABLFunction("settimer",ParseTwoInteger,execsetTimer);
AddABLFunction("playerorder",ParseOneIntegerInteger,execplayerOrder);
AddABLFunction("getelitelevel",ParseOneIntegerInteger,execgetEliteLevel);
AddABLFunction("geteliteskill",ParseOneIntegerInteger,execgetEliteLevel);
AddABLFunction("setelitelevel",hbsetEliteLevel,execsetEliteLevel);
AddABLFunction("clearmoveorder",ParseOneInteger,execclearMoveOrder);
AddABLFunction("isshutdown",ParseOneIntegerBoolean,execIsShutdown);
AddABLFunction("isshot",ParseOneIntegerBoolean,execisShot);
AddABLFunction("iswithin",hbisWithin,execisWithin);
AddABLFunction("isdead",ParseOneIntegerBoolean,execisDead);
AddABLFunction("isequal",hbisEqual,execisEqual);
AddABLFunction("islesser",hbisLesser,execisLesser);
AddABLFunction("isgreater",hbisGreater ,execisGreater);
AddABLFunction("equalid",ParseTwoIntegerBoolean ,execequalID);
AddABLFunction("isrammed",ParseOneIntegerBoolean,execisRammed);
AddABLFunction("whorammed",ParseOneIntegerInteger,execwhoRammed);
AddABLFunction("cansee",ParseTwoIntegerBoolean,execcanSee);
AddABLFunction("cantarget",ParseTwoIntegerBoolean,execcanTarget);
AddABLFunction("battlevaluelesser",ParseOneIntegerBoolean,execbattleValueLesser);
AddABLFunction("battleValuelesserid",ParseTwoIntegerBoolean,execbattleValueLesserID);
AddABLFunction("timelesser",hbtimeLesser,exectimeLesser);
AddABLFunction("timegreater",hbtimeGreater,exectimeGreater);
AddABLFunction("rand",ParseTwoIntegerInteger ,execrand);
AddABLFunction("playsound",ParseOneInteger ,execplaySound);
AddABLFunction("playmusic",ParseTwoInteger ,execplayMusic);
AddABLFunction("killmusic",ParseOneInteger ,execkillMusic);
AddABLFunction("fadeinmusic",ParseThreeInteger ,execfadeInMusic);
AddABLFunction("fadeoutmusic",ParseThreeInteger ,execfadeOutMusic);
AddABLFunction("playsoundonce",ParseOneInteger ,execplaySoundOnce);
AddABLFunction("killsound",ParseOneInteger,execkillSound);
AddABLFunction("setaudiofxenabled",ParseOneBoolean,execSetAudioFXEnabled);
AddABLFunction("playeffect",ParseOneInteger,execplayEffect);
AddABLFunction("killeffect",ParseOneInteger,execkillEffect);
AddABLFunction("playlancematesound",ParsePlayLancemateSound,execPlayLancemateSound);
AddABLFunction("playvoiceover",ParsePlayLancemateSound,execPlayVoiceOver);
AddABLFunction("playvoiceoveronce",ParsePlayLancemateSound,execPlayVoiceOverOnce);
AddABLFunction("killvoiceovers",ParseNoParam,execKillVoiceOvers);
AddABLFunction("isvoiceoverplaying",ParseNoParamBoolean,execIsVoiceOverPlaying);
AddABLFunction("ismusicplaying",ParseNoParamBoolean,execIsMusicPlaying);
AddABLFunction("startmusic",ParseStartMusic,execStartMusic);
AddABLFunction("playbettysound",ParseOneInteger,execPlayBettySound);
AddABLFunction("playteambettysound",ParseTwoInteger,execPlayTeamBettySound);
AddABLFunction("startmusicall",ParseOneInteger,execStartMusicAll);
AddABLFunction("teamsetnav",ParseTwoInteger,execTeamSetNav);
AddABLFunction("specifytalker",ParseTwoInteger,execSpecifyTalker);
AddABLFunction("navpointreached",ParseOneInteger,execNavPointReached);
AddABLFunction("setchancelancemateseject",ParseOneInteger,execSetChanceLancematesEject);
AddABLFunction("setchancelancematesokwhenejecting",ParseOneInteger,execSetChanceLancematesOKWhenEjecting);
AddABLFunction("setchancelancematesinjuredwhenejecting",ParseOneInteger,execSetChanceLancematesInjuredWhenEjecting);
AddABLFunction("reveallancemate",ParseString,execRevealLancemate);
AddABLFunction("hidelancemate",ParseString,execHideLancemate);
AddABLFunction("revealobjective",ParseOneInteger,execrevealObjective);
AddABLFunction("hideobjective",ParseOneInteger,exechideObjective);
AddABLFunction("failobjective",ParseOneInteger,execfailObjective);
AddABLFunction("successobjective",ParseOneInteger,execsuccessObjective);
AddABLFunction("failobjectiveall",ParseOneInteger,execfailObjectiveAll);
AddABLFunction("successobjectiveall",ParseOneInteger,execsuccessObjectiveAll);
AddABLFunction("checkobjectivecompletion",ParseOneIntegerInteger,execcheckObjectiveCompletion);
AddABLFunction("isvisible",ParseOneIntegerBoolean,execisVisible);
AddABLFunction("showallrevealedobjectives",ParseNoParam,execshowAllRevealedObjectives);
AddABLFunction("endmission",ParseEndMission,execEndMission);
AddABLFunction("ismissioncomplete",ParseStringBoolean,execIsMissionComplete);
AddABLFunction("savegame",ParseNoParam,execsaveGame);
AddABLFunction("revealnavpoint",ParseOneIntegerForRevealNavPoint,execrevealNavPoint);
AddABLFunction("setnavpoint",ParseOneInteger,execsetNavPoint);
AddABLFunction("isnavrevealed",ParseOneIntegerBoolean,execIsNavRevealed);
AddABLFunction("hidenav",ParseOneInteger,execHideNav);
AddABLFunction("setradarnav",ParseTwoInteger,execSetRadarNav);
AddABLFunction("CreateHeatSphere",ParseFourInteger,execcreateHeatSphere);
AddABLFunction("CreateInstantHeatSphere",ParseThreeInteger,execcreateInstantHeatSphere);
AddABLFunction("CreateFogSphere",ParseThreeInteger,execcreateFogSphere);
AddABLFunction("CreateRadarSphere",ParseFourInteger,execcreateRadarSphere);
AddABLFunction("teleport",hbteleport,execteleport);
AddABLFunction("teleportandlook",hbteleportAndLook,execteleportAndLook); // jcem
AddABLFunction("teleporttohell",ParseOneInteger,execteleportToHell);
AddABLFunction("damnthe",ParseOneInteger,execteleportToHell);
AddABLFunction("playchatter",ParseOneInteger,execplayChatter);
AddABLFunction("playchatterPriority",ParseTwoInteger,execplayChatterPriority);
AddABLFunction("killchatter",ParseNoParam,execkillChatter);
AddABLFunction("starttimer",ParseOneInteger,execstartTimer);
AddABLFunction("killtimer",ParseOneInteger,execkillTimer);
AddABLFunction("resettimer",ParseOneInteger,execresetTimer);
AddABLFunction("pausetimer",hbpauseTimer,execpauseTimer);
AddABLFunction("orderdie",ParseNoParam,execorderDie);
AddABLFunction("ordermovelookout",ParseNoParam,execorderMoveLookOut);
AddABLFunction("ordermoveto",hborderMoveTo,execorderMoveTo);
AddABLFunction("ordermovetofree",hborderMoveTo,execorderMoveToFree);
AddABLFunction("orderformationmove",hborderFormationMove,execorderFormationMove);
AddABLFunction("orderformonspot",hborderFormOnSpot,execorderFormOnSpot);
AddABLFunction("ordermovetorigid",hborderMoveTo,execorderMoveToRigid);
AddABLFunction("ordermoveflee",ParseTwoIntegerInteger,execorderMoveFlee);
AddABLFunction("ordermoveresumepatrol",hborderMoveResumePatrol,execorderMoveResumePatrol);
AddABLFunction("ordermoveresumepatrolfree",hborderMoveResumePatrol,execorderMoveResumePatrolFree);
AddABLFunction("ordermoveresumepatrolrigid",hborderMoveResumePatrol,execorderMoveResumePatrolRigid);
AddABLFunction("ordermovefollow",hborderMoveFollow,execorderMoveFollow);
AddABLFunction("ordermovesit",hborderMoveSit,execorderMoveSit);
AddABLFunction("ordermovetolocpoint",hborderMoveToLocPoint,execorderMoveToLocPoint);
AddABLFunction("ordermovetoobject",hborderMoveToObject,execorderMoveToObject);
AddABLFunction("orderattack",hborderAttack,execorderAttack);
AddABLFunction("orderattacktactic",hborderAttackTactic,execorderAttackTactic);
AddABLFunction("orderattackbomb",ParseNoParam,execorderAttackBomb);
AddABLFunction("orderstopattacking",ParseNoParam,execorderStopAttacking);
AddABLFunction("ordershootpoint",hborderShootPoint,execorderShootPoint);
AddABLFunction("lancematecommand",ParseTwoInteger,execlancemateCommand);
AddABLFunction("enableaistats",ParseNoParam,execEnableAIStats);
AddABLFunction("disableaistats",ParseNoParam,execDisableAIStats);
AddABLFunction("enablemovelines",ParseNoParam,execEnableMoveLines);
AddABLFunction("disablemovelines",ParseNoParam,execDisableMoveLines);
AddABLFunction("enableglobalinvulnerable",ParseNoParam,execEnableGlobalInvulnerable);
AddABLFunction("disableglobalinvulnerable",ParseNoParam,execDisableGlobalInvulnerable);
AddABLFunction("enableinvulnerable",ParseOneInteger,execEnableInvulnerable);
AddABLFunction("disableinvulnerable",ParseOneInteger,execDisableInvulnerable);
AddABLFunction("destroy",ParseOneInteger,execDestroy);
AddABLFunction("gosmenuitemexec",ParseString,execGOSMenuItemExec);
AddABLFunction("gosmenuitemchecked",ParseStringBoolean,execGOSMenuItemChecked);
AddABLFunction("settargetdesirability",ParseTwoInteger,execSetTargetDesirability);
AddABLFunction("setisshotradius",ParseTwoInteger,execSetIsShotRadius);
AddABLFunction("setsquadtargetingradius",ParseTwoInteger,execSetSquadTargetingRadius);
AddABLFunction("setsearchlight",ParseIntegerBoolean,execSetSearchLight);
AddABLFunction("setgroupai",ParseTwoInteger,execSetGroupAI);
AddABLFunction("getlancemate",ParseOneIntegerInteger,execGetLancemate);
AddABLFunction("notifygroupenemyspotted",ParseTwoInteger,execNotifyGroupEnemySpotted);
AddABLFunction("tacticisfinished",ParseOneIntegerBoolean,execTacticIsFinished);
AddABLFunction("groupalldead",ParseOneIntegerBoolean,execGroupAllDead);
AddABLFunction("groupaddobject",ParseTwoInteger,execGroupAddObject);
AddABLFunction("groupremoveobject",ParseTwoInteger,execGroupRemoveObject);
AddABLFunction("groupnumdead",ParseOneIntegerInteger,execGroupNumDead);
AddABLFunction("groupsize",ParseOneIntegerInteger,execGroupSize);
AddABLFunction("groupcontainsobject",ParseTwoIntegerBoolean,execGroupContainsObject);
AddABLFunction("groupgetfirstgroup",ParseOneIntegerInteger,execGroupGetFirstGroup);
AddABLFunction("groupgetfirstobject",ParseOneIntegerInteger,execGroupGetFirstObject);
AddABLFunction("groupgetobject",ParseTwoIntegerInteger,execGroupGetObject);
AddABLFunction("groupobjectid",ParseOneIntegerInteger,execGroupObjectID);
AddABLFunction("groupallwithin",hbGroupAllWithin,execGroupAllWithin);
AddABLFunction("teamobjectid",ParseOneIntegerInteger,execTeamObjectID);
AddABLFunction("disableaijumping",ParseNoParam,execDisableAIJumping);
AddABLFunction("play2danim",hbplay2DAnim,execplay2DAnim);
AddABLFunction("cinemastart",ParseNoParam,execcinemaStart);
AddABLFunction("cinemaend",ParseNoParam,execcinemaEnd);
AddABLFunction("cinemaskip",ParseNoParamBoolean,execcinemaskip);
AddABLFunction("setcamerafootshake",ParseTwoInteger,execSetCameraFootShake);
AddABLFunction("setinternalcamera", hbsetinternalcamera, execsetinternalcamera);
AddABLFunction("setactivecamera", hbsetactivecamera, execsetactivecamera);
AddABLFunction("setcameraFOV", hbsetcameraFOV, execsetcameraFOV);
AddABLFunction("fadetoblack", hbfadetoblack, execfadetoblack);
AddABLFunction("fadefromblack", hbfadefromblack, execfadefromblack);
AddABLFunction("fadetowhite", hbfadetowhite, execfadetowhite);
AddABLFunction("fadefromwhite", hbfadefromwhite, execfadefromwhite);
AddABLFunction("camerafollowobject", hbcamerafollowobject, execcamerafollowobject);
AddABLFunction("camerafollowpath", hbcamerafollowpath, execcamerafollowpath);
AddABLFunction("cameraposition", hbcameraposition, execcameraposition);
AddABLFunction("cameradetach", ParseNoParam, execcameradetach);
AddABLFunction("cameraoffset", hbcameraoffset, execcameraoffset);
AddABLFunction("overridecamerapitch", hboverridecamerapitch, execoverridecamerapitch);
AddABLFunction("overridecamerayaw", hboverridecamerayaw, execoverridecamerayaw);
AddABLFunction("overridecameraroll", hboverridecameraroll, execoverridecameraroll);
AddABLFunction("resetcameraoverrides", ParseNoParam, execresetcameraoverrides);
AddABLFunction("targetfollowobject", hbtargetfollowobject, exectargetfollowobject);
AddABLFunction("targetfollowpath", hbtargetfollowpath, exectargetfollowpath);
AddABLFunction("targetposition", hbtargetposition, exectargetposition);
AddABLFunction("targetdetach", ParseNoParam, exectargetdetach);
AddABLFunction("targetoffset", hbtargetoffset, exectargetoffset);
AddABLFunction("setdebugstring",hbSetDebugString,execSetDebugString);
AddABLFunction("startup",ParseOneInteger,execstartup);
AddABLFunction("shutdown",ParseOneInteger,execshutDown);
AddABLFunction("getmemoryinteger",ParseTwoIntegerInteger,execGetMemoryInteger);
AddABLFunction("setmemoryinteger",hbSetMemoryInteger,execSetMemoryInteger);
AddABLFunction("getmemoryreal",hbGetMemoryReal,execGetMemoryReal);
AddABLFunction("setmemoryreal",hbSetMemoryReal,execSetMemoryReal);
AddABLFunction("setglobaltrigger",ParseIntegerBoolean,execSetGlobalTrigger);
AddABLFunction("getglobaltrigger",ParseOneIntegerBoolean,execGetGlobalTrigger);
AddABLFunction("setsensorvisibility",ParseIntegerBoolean,execSetSensorVisibility);
AddABLFunction("setautotargeting",ParseIntegerBoolean,execSetAutoTargeting);
AddABLFunction("enableperweaponraycasting",ParseIntegerBoolean,execEnablePerWeaponRayCasting);
AddABLFunction("ordertakeoff",ParseOneIntegerBoolean,execorderTakeOff);
AddABLFunction("orderland",ParseNoParamBoolean,execorderLand);
AddABLFunction("iswithinlocpoint",hbisWithinLoc,execisWithinLoc);
AddABLFunction("playershooting",ParseTwoIntegerBoolean,execPlayerShooting);
AddABLFunction("playerai",ParsePlayerAI,execPlayerAI);
AddABLFunction("distance",hbDistance,execDistance);
AddABLFunction("stopexecute",ParseOneInteger,execStopExecute);
AddABLFunction("startexecute",ParseOneInteger,execStartExecute);
AddABLFunction("setactivationdistance",ParseOneInteger,execSetActivationDistance);
AddABLFunction("selfdestruct",ParseOneInteger,execSelfDestruct);
AddABLFunction("flyby",ParseOneIntegerBoolean,execFlyBy);
AddABLFunction("save",ParseOneInteger,execSave);
AddABLFunction("helpmessage",ParseTwoInteger,execHelpMessage);
AddABLFunction("getdifficulty",ParseNoParamInteger,execGetDifficulty);
AddABLFunction("eject",ParseOneInteger,execEject);
AddABLFunction("addmechinstancesalvage", ParseString, execAddMechInstanceSalvage);
AddABLFunction("addcomponentsalvage", ParseStringInteger, execAddComponentSalvage);
AddABLFunction("addweaponsalvage", ParseStringInteger, execAddWeaponSalvage);
AddABLFunction ("markBuildingAsScorable", ParseOneInteger, execMarkBuildingAsScorable);
AddABLFunction("jump",ParseTwoInteger,execJump);
AddABLFunction("crouch",ParseOneInteger,execCrouch);
AddABLFunction("fall",ParseTwoInteger,execFall);
AddABLFunction("torsopitch",ParseIntegerReal,execTorsoPitch);
AddABLFunction("torsoyaw",ParseIntegerReal,execTorsoYaw);
AddABLFunction("setgimped",ParseIntegerBoolean,execSetGimped);
AddABLFunction("setrotation",ParseTwoInteger,execSetRotation);
AddABLFunction("sethelicoptersignoremissionbounds",ParseOneBoolean,execSetHelicoptersIgnoreMissionBounds);
AddABLFunction("settorsocenteringenabled",ParseIntegerBoolean,execSetTorsoCenteringEnabled);
AddABLFunction("setalwaysignoreobstacles",ParseOneBoolean,execSetAlwaysIgnoreObstacles);
AddABLFunction("setignorefog",ParseIntegerBoolean,execSetIgnoreFog);
AddABLFunction("setcompositingenabled",ParseOneBoolean,execSetCompositingEnabled);
AddABLFunction("setsensormode",ParseTwoInteger,execSetSensorMode);
AddABLFunction("getsensormode",ParseOneIntegerInteger,execGetSensorMode);
AddABLFunction("setminspeed",ParseTwoInteger,execSetMinSpeed);
AddABLFunction("addbucket",ParseAddBucket,execAddBucket);
AddABLFunction("killbucket",ParseKillBucket,execKillBucket);
AddABLFunction("showbucket",ParseShowBucket,execShowBucket);
AddABLFunction("hidebucket",ParseHideBucket,execHideBucket);
AddABLFunction("getbucketvalue",ParseGetBucketValue,execGetBucketValue);
AddABLFunction("findbucketvalue",ParseFindBucketValue,execFindBucketValue);
AddABLFunction("setbucketvalue",ParseSetBucketValue,execSetBucketValue);
AddABLFunction("trackbucket",ParseTrackBucket,execTrackBucket);
AddABLFunction("trackobjectbucket",ParseTrackObjectBucket,execTrackObjectBucket);
AddABLFunction("findbucket",ParseFindBucket,execFindBucket);
AddABLFunction("addcustombucketparameter",ParseTwoInteger,execAddCustomBucketParameter);
AddABLFunction("setcustombucketname",ParseString,execSetCustomBucketName);
AddABLFunction("setcustombucketnameindex",ParseOneInteger,execSetCustomBucketNameIndex);
AddABLFunction("addpoints",ParseTwoInteger,execAddPoints);
AddABLFunction("chatmessage",ParseString,execChatMessage);
AddABLFunction("attachflag",ParseTwoInteger,execAttachFlag);
AddABLFunction("dropflag",ParseOneInteger,execDropFlag);
// MSL 5.05 Return Flag Script Command
AddABLFunction("returnflag",ParseOneInteger,execReturnFlag);
AddABLFunction("deactiveflag",ParseTwoInteger,execDeactiveFlag);
AddABLFunction("setmaxflagscarried",ParseTwoInteger,execSetMaxFlagsCarried);
AddABLFunction("setflagdropreturntime",ParseOneInteger,execSetFlagDropReturnTime);
AddABLFunction("setflagcapturereturntime",ParseOneInteger,execSetFlagCaptureReturnTime);
AddABLFunction("setflagsenabled",ParseOneInteger,execSetFlagsEnabled);
AddABLFunction("setflagcaptureenabled",ParseOneBoolean,execSetFlagCaptureEnabled);
AddABLFunction("showflagsasnavpoints",ParseOneBoolean,execShowFlagsAsNavPoints);
AddABLFunction("setviewmode",ParseOneInteger,execSetViewMode);
AddABLFunction("getviewmode",ParseOneIntegerInteger,execGetViewMode);
AddABLFunction("setinputtypeenabled",ParseIntegerBoolean,execSetInputTypeEnabled);
AddABLFunction("sethudcomponentenabled",ParseIntegerBoolean,execSetHUDComponentEnabled);
AddABLFunction("resetammo",ParseOneInteger,execResetAmmo);
AddABLFunction("overrideheatoption",ParseOneBoolean,execOverrideHeatOption);
AddABLFunction("setmissionbounds",ParseTwoInteger,execSetMissionBounds);
AddABLFunction("respawn",ParseOneInteger,execRespawn);
AddABLFunction("resetmission",ParseNoParam,execResetMission);
AddABLFunction("getdamagerating",ParseOneIntegerInteger,execGetDamageRating);
AddABLFunction("istargeted",ParseOneIntegerBoolean,execIsTargeted);
AddABLFunction("lookingtoward",ParseOneIntegerBoolean,execLookingToward);
AddABLFunction("firedweapongroup",ParseOneIntegerBoolean,execFiredWeaponGroup);
AddABLFunction("issettonavpoint",ParseOneIntegerBoolean,execIsSetToNavPoint);
AddABLFunction("orderdooropen",ParseNoParamBoolean,execorderDoorOpen);
AddABLFunction("orderdoorclose",ParseNoParamBoolean,execorderDoorClose);
AddABLFunction("boarddropship",ParseTwoIntegerBoolean,execboardDropShip);
AddABLFunction("drop",ParseOneIntegerBoolean,execDrop);
AddABLFunction("showtimer",ParseShowTimer,execShowTimer);
AddABLFunction("showhelparrow",ParseShowHelpArrow,execShowHelpArrow);
AddABLFunction("makecolor",ParseMakeColor,execMakeColor);
AddABLFunction("sethelparrow",ParseSetHelpArrow,execSetHelpArrow);
AddABLFunction("respawnmission",ParseNoParam,execRespawnMission);
AddABLFunction("setdmgmodifier",ParseThreeInteger,execSetDmgModifier); // jcem
AddABLFunction("restoreoriginalbounds",ParseNoParam,execRestoreOriginalBounds); // jcem
AddABLFunction("setboundsfrompaths",ParseTwoInteger,execSetBoundsFromPaths); // jcem
AddABLFunction("randselect",ParseThreeInteger,execRandSelect); // jcem
AddABLFunction("respawnposition",ParseTwoInteger,execRespawnPosition); // jcem
AddABLFunction("getcoop",ParseOneIntegerInteger,execGetCOOP); // jcem
AddABLFunction("setcoop",ParseTwoIntegerInteger,execSetCOOP); // jcem
AddABLFunction("gettime",ParseNoParamReal,execGetTime); // jcem
AddABLFunction("gettimex",ParseNoParamReal,execGetTimeX); // jcem
AddABLFunction("igettime",ParseNoParamInteger,execIGetTime); // jcem
AddABLFunction("igettimex",ParseNoParamInteger,execIGetTimeX); // jcem
AddABLFunction("playsoundstr",ParseString,execPlaySoundStr); // jcem
AddABLFunction("logmaprespawn",ParseNoParamBoolean,execLogMapRespawn);
AddABLFunction("logdefendingteam",ParseOneIntegerBoolean,execLogDefendingTeam);
AddABLFunction("loghqdestroyed",ParseTwoIntegerBoolean,execLogHQDestroyed);
AddABLFunction("logdefendtimeaward",ParseTwoIntegerBoolean,execLogDefendTimeAward);
}
//***************************************************************************
//***************************************************************************
}
+200
View File
@@ -0,0 +1,200 @@
//***************************************************************************
//
// SYMTABLE.H
//
//***************************************************************************
#ifndef ABLSYMT_H
#define ABLSYMT_H
#include "ablgen.h"
#include "ablscan.h"
#include "dablenv.h"
//***************************************************************************
namespace ABL
{
//---------------------
// DEFINITION structure
typedef int RoutineKey;
typedef union
{
long integer;
char character;
float real;
char* stringPtr;
} Value;
typedef enum
{
VAR_TYPE_NORMAL,
VAR_TYPE_STATIC,
VAR_TYPE_ETERNAL
} VariableType;
typedef enum
{
DFN_UNDEFINED,
DFN_CONST,
DFN_TYPE,
DFN_VAR,
//DFN_FIELD, // Currently not implementing record structures...
DFN_VALPARAM,
DFN_REFPARAM,
DFN_MODULE,
DFN_PROCEDURE,
DFN_FUNCTION,
DFN_STATE,
DFN_FSM
} DefinitionType;
typedef struct _SymTableNode* SymTableNodePtr;
typedef struct _Type* TypePtr;
typedef struct
{
Value value;
} Constant;
typedef struct _Routine
{
RoutineKey key;
bool isOrder;
unsigned char paramCount;
unsigned char totalParamSize;
unsigned short totalLocalSize;
union
{
SymTableNodePtr params; // for modules
SymTableNodePtr state; // for fsm's
};
SymTableNodePtr locals;
SymTableNodePtr localSymTable;
char* codeSegment;
long codeSegmentSize;
} Routine;
typedef struct
{
VariableType varType;
long offset;
SymTableNodePtr recordIdPtr; // Currently not implementing record structures...
} Data;
typedef union
{
Constant constant;
Routine routine;
Data data;
} DefinitionInfo;
typedef struct
{
DefinitionType key;
DefinitionInfo info;
} Definition;
//***************************************************************************
//------------------
// SYMBOL TABLE node
typedef struct _SymTableNode
{
SymTableNodePtr left;
SymTableNodePtr parent;
SymTableNodePtr right;
SymTableNodePtr next;
char* name;
char* info;
Definition defn;
TypePtr typePtr;
ABLModulePtr library;
unsigned char level;
long labelIndex; // really for compiling only...
} SymTableNode;
//***************************************************************************
//---------------
// TYPE structure
typedef enum
{
FRM_NONE,
FRM_SCALAR,
FRM_ENUM,
FRM_ARRAY
//FRM_RECORD
} FormType;
//---------------------------------------------------------------------
// Currently, we are only supporting the basic types: arrays and simple
// variables.
typedef struct _Type
{
long numInstances;
FormType form;
long size;
SymTableNodePtr typeIdPtr;
union
{
struct
{
SymTableNodePtr constIdPtr;
long max;
} enumeration;
struct
{
TypePtr indexTypePtr; // should be Integer
TypePtr elementTypePtr; // should be Real, Integer, Char or array
long elementCount;
} array;
// Not currently implementing record structures...
//struct {
// SymTableNodePtr fieldSymTable;
//} record;
} info;
} Type;
//***************************************************************************
void searchLocalSymTable (SymTableNodePtr& IdPtr);
void searchThisSymTable (SymTableNodePtr& IdPtr, SymTableNodePtr thisTable);
void searchAllSymTables (SymTableNodePtr& IdPtr);
void enterLocalSymTable (SymTableNodePtr& IdPtr);
void enterNameLocalSymTable (SymTableNodePtr& IdPtr, const char* name);
void searchAndFindAllSymTables (SymTableNodePtr& IdPtr);
void searchAndEnterLocalSymTable (SymTableNodePtr& IdPtr);
/*inline*/void searchAndEnterThisTable (SymTableNodePtr& IdPtr, SymTableNodePtr thisTable);
inline SymTableNodePtr symTableSuccessor (SymTableNodePtr nodeX);
SymTableNodePtr searchSymTable (const char* name, SymTableNodePtr nodePtr);
SymTableNodePtr searchSymTableDisplay (const char* name);
SymTableNodePtr enterSymTable (const char* name, SymTableNodePtr* ptrToNodePtr);
SymTableNodePtr insertSymTable (SymTableNodePtr* tableRoot, SymTableNodePtr newNode);
SymTableNodePtr extractSymTable (SymTableNodePtr* tableRoot, SymTableNodePtr nodeKill);
void enterStandardRoutine (const char* name, RoutineKey routineKey, DefinitionType definitionKey, bool isOrder = false);
void enterScope (SymTableNodePtr symTableRoot);
SymTableNodePtr exitScope (void);
void initSymTable (void);
TypePtr createType (void);
TypePtr setType (TypePtr type);
void clearType (TypePtr& type);
extern SymTableNodePtr SymTableDisplay[MAX_NESTING_LEVEL];
//***************************************************************************
}
#endif
+663
View File
@@ -0,0 +1,663 @@
//***************************************************************************
//
// ABLXEXPR.CPP
//
//***************************************************************************
#include "MW4Headers.hpp"
#include <string.h>
#ifndef ABLGEN_H
#include "ablgen.h"
#endif
#ifndef ABLERR_H
#include "ablerr.h"
#endif
#ifndef ABLSCAN_H
#include "ablscan.h"
#endif
#ifndef ABLSYMT_H
#include "ablsymt.h"
#endif
#ifndef ABLPARSE_H
#include "ablparse.h"
#endif
#ifndef ABLEXEC_H
#include "ablexec.h"
#endif
#ifndef ABLDBUG_H
#include "abldbug.h"
#endif
#ifndef ABLHEAP_H
#include "ablheap.h"
#endif
namespace ABL
{
//***************************************************************************
//----------
// EXTERNALS
extern long level;
extern char* codeSegmentPtr;
extern TokenCodeType codeToken;
extern StackItem* stack;
extern StackItemPtr tos;
extern StackItemPtr stackFrameBasePtr;
extern StackItemPtr StaticDataPtr;
extern SymTableNodePtr CurRoutineIdPtr;
extern ABLModulePtr CurModule;
extern TypePtr IntegerTypePtr;
extern TypePtr CharTypePtr;
extern TypePtr RealTypePtr;
extern TypePtr BooleanTypePtr;
extern UserHeapPtr AblStackHeap;
extern DebuggerPtr debugger;
//***************************************************************************
inline void promoteOperandsToReal (StackItemPtr operand1Ptr, TypePtr type1Ptr,
StackItemPtr operand2Ptr, TypePtr type2Ptr)
{
if (type1Ptr == IntegerTypePtr)
operand1Ptr->real = (float)(operand1Ptr->integer);
if (type2Ptr == IntegerTypePtr)
operand2Ptr->real = (float)(operand2Ptr->integer);
}
//***************************************************************************
TypePtr execField (void)
{
//------------------------------------------------------------------
// NOTE: this routine has been included should we use records/fields
// in ABL...
getCodeToken();
SymTableNodePtr fieldIdPtr = getCodeSymTableNodePtr();
tos->address += fieldIdPtr->defn.info.data.offset;
getCodeToken();
return((TypePtr)(fieldIdPtr->typePtr));
}
//***************************************************************************
TypePtr execSubscripts (TypePtr typePtr)
{
//----------------------------------------
// Loop to execute bracketed subscripts...
while (codeToken == TKN_LBRACKET)
{
do
{
getCodeToken();
execExpression();
long subscriptValue = tos->integer;
pop();
//-------------------------
// Range check the index...
if ((subscriptValue < 0) || (subscriptValue >= typePtr->info.array.elementCount))
runtimeError(ABL_ERR_RUNTIME_VALUE_OUT_OF_RANGE);
tos->address += (subscriptValue * typePtr->info.array.elementTypePtr->size);
if (codeToken == TKN_COMMA)
typePtr = typePtr->info.array.elementTypePtr;
} while (codeToken == TKN_COMMA);
getCodeToken();
if (codeToken == TKN_LBRACKET)
typePtr = typePtr->info.array.elementTypePtr;
}
return(typePtr->info.array.elementTypePtr);
}
//***************************************************************************
TypePtr execConstant (SymTableNodePtr idPtr)
{
TypePtr typePtr = (TypePtr)(idPtr->typePtr);
if ((baseType(typePtr) == IntegerTypePtr) || (typePtr->form == FRM_ENUM))
pushInteger(idPtr->defn.info.constant.value.integer);
else if (typePtr == RealTypePtr)
pushReal(idPtr->defn.info.constant.value.real);
else if (typePtr == CharTypePtr)
pushInteger(idPtr->defn.info.constant.value.character);
else if (typePtr->form == FRM_ARRAY)
pushAddress(idPtr->defn.info.constant.value.stringPtr);
if (debugger)
debugger->traceDataFetch(idPtr, typePtr, tos);
getCodeToken();
return(typePtr);
}
//***************************************************************************
TypePtr execVariable (SymTableNodePtr idPtr, UseType use)
{
TypePtr typePtr = (TypePtr)(idPtr->typePtr);
// First, point to the variable's stack item. If the variable's scope
// level is less than the current scope level, follow the static links
// to the proper stack frame base...
StackItemPtr dataPtr = NULL;
switch (idPtr->defn.info.data.varType)
{
case VAR_TYPE_NORMAL: {
StackFrameHeaderPtr headerPtr = (StackFrameHeaderPtr)stackFrameBasePtr;
long delta = level - idPtr->level;
while (delta-- > 0)
headerPtr = (StackFrameHeaderPtr)headerPtr->staticLink.address;
dataPtr = (StackItemPtr)headerPtr + idPtr->defn.info.data.offset;
}
break;
case VAR_TYPE_ETERNAL:
dataPtr = (StackItemPtr)stack + idPtr->defn.info.data.offset;
break;
case VAR_TYPE_STATIC:
//---------------------------------------------------------
// If we're referencing a library's static variable, we may
// need to shift to its static data space temporarily...
if (idPtr->library && (idPtr->library != CurModule))
StaticDataPtr = idPtr->library->getStaticData();
dataPtr = (StackItemPtr)StaticDataPtr + idPtr->defn.info.data.offset;
if (idPtr->library && (idPtr->library != CurModule))
StaticDataPtr = CurModule->getStaticData();
break;
}
//---------------------------------------------------------------
// If it's a scalar or enumeration reference parameter, that item
// points to the actual item...
if ((idPtr->defn.key == DFN_REFPARAM) && (typePtr->form != FRM_ARRAY)/* && (typePtr->form != FRM_RECORD)*/)
dataPtr = (StackItemPtr)dataPtr->address;
ABL_Assert(dataPtr != NULL, 0, " ABL.execVariable(): dataPtr is NULL ");
//-----------------------------------------------------
// Now, push the address of the variable's data area...
if ((typePtr->form == FRM_ARRAY) /*|| (typePtr->form == FRM_RECORD)*/)
{
//pushInteger(typePtr->size);
pushAddress((Address)dataPtr->address);
}
else
pushAddress((Address)dataPtr);
//-----------------------------------------------------------------------------------
// If there is a subscript (or field identifier, if records are being used in ABL)
// then modify the address to point to the proper element of the array (or record)...
getCodeToken();
while ((codeToken == TKN_LBRACKET) /*|| (codeTOken == TKN_PERIOD)*/)
{
if (codeToken == TKN_LBRACKET)
typePtr = execSubscripts(typePtr);
//else if (codeToken == TKN_PERIOD)
// typePtr = execField(typePtr);
}
TypePtr baseTypePtr = baseType(typePtr);
//------------------------------------------------------------
// Leave the modified address on the top of the stack if:
// a) it's an assignment target;
// b) it reresents a parameter passed by reference;
// c) it's the address of an array or record;
// Otherwise, replace the address with the value it points to.
if ((use != USE_TARGET) && (use != USE_REFPARAM) && (typePtr->form != FRM_ARRAY) /*&& (typePtr->form != FRM_RECORD)*/)
{
if ((baseTypePtr == IntegerTypePtr) || (typePtr->form == FRM_ENUM))
{
tos->integer = *((long*)tos->address);
}
else if (baseTypePtr == CharTypePtr)
tos->byte = *((char*)tos->address);
else
tos->real = *((float*)tos->address);
}
if (debugger)
{
if ((use != USE_TARGET) && (use != USE_REFPARAM))
{
if ((typePtr->form == FRM_ARRAY) /*|| (typePtr->form == FRM_RECORD)*/)
debugger->traceDataFetch(idPtr, typePtr, (StackItemPtr)tos->address);
else
debugger->traceDataFetch(idPtr, typePtr, tos);
}
}
return(typePtr);
}
//***************************************************************************
TypePtr execFactor (void)
{
TypePtr resultTypePtr = NULL;
switch (codeToken)
{
case TKN_IDENTIFIER: {
SymTableNodePtr idPtr = getCodeSymTableNodePtr();
if (idPtr->defn.key == DFN_FUNCTION)
{
SymTableNodePtr thisRoutineIdPtr = CurRoutineIdPtr;
resultTypePtr = execRoutineCall(idPtr);
CurRoutineIdPtr = thisRoutineIdPtr;
}
else if (idPtr->defn.key == DFN_CONST)
resultTypePtr = execConstant(idPtr);
else
resultTypePtr = execVariable(idPtr, USE_EXPR);
}
break;
case TKN_NUMBER: {
SymTableNodePtr numberPtr = getCodeSymTableNodePtr();
if (numberPtr->typePtr == IntegerTypePtr)
{
pushInteger(numberPtr->defn.info.constant.value.integer);
resultTypePtr = IntegerTypePtr;
}
else
{
pushReal(numberPtr->defn.info.constant.value.real);
resultTypePtr = RealTypePtr;
}
getCodeToken();
}
break;
case TKN_STRING: {
SymTableNodePtr nodePtr = getCodeSymTableNodePtr();
long length = strlen(nodePtr->name);
if (length > 1)
{
//-----------------------------------------------------------------------
// Remember, the double quotes are on the back and front of the string...
pushAddress(nodePtr->info);
resultTypePtr = nodePtr->typePtr;
}
else
{
//----------------------------------------------
// Just push the one character in this string...
pushByte(nodePtr->name[0]);
resultTypePtr = CharTypePtr;
}
getCodeToken();
}
break;
case TKN_NOT:
getCodeToken();
resultTypePtr = execFactor();
//--------------------------------------
// Following flips 1 to 0, and 0 to 1...
tos->integer = 1 - tos->integer;
break;
case TKN_LPAREN:
getCodeToken();
resultTypePtr = execExpression();
getCodeToken();
break;
}
return(resultTypePtr);
}
//***************************************************************************
TypePtr execTerm (void)
{
StackItemPtr operand1Ptr;
StackItemPtr operand2Ptr;
TypePtr type2Ptr;
TokenCodeType op;
TypePtr resultTypePtr = execFactor();
//----------------------------------------------
// Process the factors separated by operators...
while ((codeToken == TKN_STAR) || (codeToken == TKN_FSLASH) ||
(codeToken == TKN_DIV) || (codeToken == TKN_MOD) ||
(codeToken == TKN_AND))
{
op = codeToken;
resultTypePtr = baseType(resultTypePtr);
getCodeToken();
type2Ptr = baseType(execFactor());
operand1Ptr = tos - 1;
operand2Ptr = tos;
if (op == TKN_AND)
{
operand1Ptr->integer = operand1Ptr->integer && operand2Ptr->integer;
resultTypePtr = BooleanTypePtr;
}
else
switch (op)
{
case TKN_STAR:
if ((resultTypePtr == IntegerTypePtr) && (type2Ptr == IntegerTypePtr))
{
//-----------------------------
// Both operands are integer...
operand1Ptr->integer = operand1Ptr->integer * operand2Ptr->integer;
resultTypePtr = IntegerTypePtr;
}
else
{
//----------------------------------------------------------------
// Both operands are real, or one is real and the other integer...
promoteOperandsToReal(operand1Ptr, resultTypePtr, operand2Ptr, type2Ptr);
operand1Ptr->real = operand1Ptr->real * operand2Ptr->real;
resultTypePtr = RealTypePtr;
}
break;
case TKN_FSLASH:
//--------------------------------------------------------------------
// Both operands are real, or one is real and the other an integer. We
// probably want this same token to be used for integers, as opposed
// to using the DIV token...
if ((resultTypePtr == IntegerTypePtr) && (type2Ptr == IntegerTypePtr))
{
//-----------------------------
// Both operands are integer...
if (operand2Ptr->integer == 0)
{
#ifdef _DEBUG
runtimeError(ABL_ERR_RUNTIME_DIVISION_BY_ZERO);
#else
//HACK!!!!!!!!!!!!
operand1Ptr->integer = 0;
#endif
}
else
operand1Ptr->integer = operand1Ptr->integer / operand2Ptr->integer;
resultTypePtr = IntegerTypePtr;
}
else
{
//----------------------------------------------------------------
// Both operands are real, or one is real and the other integer...
promoteOperandsToReal(operand1Ptr, resultTypePtr, operand2Ptr, type2Ptr);
if (operand2Ptr->real == 0.0)
#ifdef _DEBUG
runtimeError(ABL_ERR_RUNTIME_DIVISION_BY_ZERO);
#else
//HACK!!!!!!!!!!!!
operand1Ptr->real = 0.0;
#endif
else
operand1Ptr->real = operand1Ptr->real / operand2Ptr->real;
resultTypePtr = RealTypePtr;
}
break;
case TKN_DIV:
case TKN_MOD:
//-----------------------------
// Both operands are integer...
if (operand2Ptr->integer == 0)
#ifdef _DEBUG
runtimeError(ABL_ERR_RUNTIME_DIVISION_BY_ZERO);
#else
//HACK!!!!!!!!!!!!
operand1Ptr->integer = 0;
#endif
else
{
if (op == TKN_DIV)
operand1Ptr->integer = operand1Ptr->integer / operand2Ptr->integer;
else
operand1Ptr->integer = operand1Ptr->integer % operand2Ptr->integer;
}
resultTypePtr = IntegerTypePtr;
break;
}
//------------------------------
// Pop off the second operand...
pop();
}
return(resultTypePtr);
}
//***************************************************************************
TypePtr execSimpleExpression (void)
{
TokenCodeType unaryOp = TKN_PLUS;
//------------------------------------------------------
// If there's a + or - before the expression, save it...
if ((codeToken == TKN_PLUS) || (codeToken == TKN_MINUS))
{
unaryOp = codeToken;
getCodeToken();
}
TypePtr resultTypePtr = execTerm();
//-------------------------------------------------------
// If there was a unary -, negate the top of the stack...
if (unaryOp == TKN_MINUS)
{
if (resultTypePtr == IntegerTypePtr)
tos->integer = -(tos->integer);
else
tos->real = -(tos->real);
}
while ((codeToken == TKN_PLUS) || (codeToken == TKN_MINUS) || (codeToken == TKN_OR))
{
TokenCodeType op = codeToken;
resultTypePtr = baseType(resultTypePtr);
getCodeToken();
TypePtr type2Ptr = baseType(execTerm());
StackItemPtr operand1Ptr = tos - 1;
StackItemPtr operand2Ptr = tos;
if (op == TKN_OR)
{
operand1Ptr->integer = operand1Ptr->integer || operand2Ptr->integer;
resultTypePtr = BooleanTypePtr;
}
else if ((resultTypePtr == IntegerTypePtr) && (type2Ptr == IntegerTypePtr))
{
if (op == TKN_PLUS)
operand1Ptr->integer = operand1Ptr->integer + operand2Ptr->integer;
else
operand1Ptr->integer = operand1Ptr->integer - operand2Ptr->integer;
resultTypePtr = IntegerTypePtr;
}
else
{
//-------------------------------------------------------------------
// Both operands are real, or one is real and the other is integer...
promoteOperandsToReal(operand1Ptr, resultTypePtr, operand2Ptr, type2Ptr);
if (op == TKN_PLUS)
operand1Ptr->real = operand1Ptr->real + operand2Ptr->real;
else
operand1Ptr->real = operand1Ptr->real - operand2Ptr->real;
resultTypePtr = RealTypePtr;
}
//--------------------------
// Pop the second operand...
pop();
}
return(resultTypePtr);
}
//***************************************************************************
TypePtr execExpression (void)
{
StackItemPtr operand1Ptr;
StackItemPtr operand2Ptr;
TokenCodeType op;
bool result = false;
//-----------------------------------
// Get the first simple expression...
TypePtr resultTypePtr = execSimpleExpression();
TypePtr type2Ptr = NULL;
//-----------------------------------------------------------
// If there is a relational operator, save it and process the
// second simple expression...
if ((codeToken == TKN_EQUALEQUAL) || (codeToken == TKN_LT) ||
(codeToken == TKN_GT) || (codeToken == TKN_NE) ||
(codeToken == TKN_LE) || (codeToken == TKN_GE))
{
op = codeToken;
resultTypePtr = baseType(resultTypePtr);
getCodeToken();
//---------------------------------
// Get the 2nd simple expression...
type2Ptr = baseType(execSimpleExpression());
operand1Ptr = tos - 1;
operand2Ptr = tos;
//-----------------------------------------------------
// Both operands are integer, boolean or enumeration...
if (((resultTypePtr == IntegerTypePtr) && (type2Ptr == IntegerTypePtr)) ||
(resultTypePtr->form == FRM_ENUM))
{
switch (op)
{
case TKN_EQUALEQUAL:
result = operand1Ptr->integer == operand2Ptr->integer;
break;
case TKN_LT:
result = operand1Ptr->integer < operand2Ptr->integer;
break;
case TKN_GT:
result = operand1Ptr->integer > operand2Ptr->integer;
break;
case TKN_NE:
result = operand1Ptr->integer != operand2Ptr->integer;
break;
case TKN_LE:
result = operand1Ptr->integer <= operand2Ptr->integer;
break;
case TKN_GE:
result = operand1Ptr->integer >= operand2Ptr->integer;
break;
}
}
else if (resultTypePtr == CharTypePtr)
{
switch (op)
{
case TKN_EQUALEQUAL:
result = operand1Ptr->byte == operand2Ptr->byte;
break;
case TKN_LT:
result = operand1Ptr->byte < operand2Ptr->byte;
break;
case TKN_GT:
result = operand1Ptr->byte > operand2Ptr->byte;
break;
case TKN_NE:
result = operand1Ptr->byte != operand2Ptr->byte;
break;
case TKN_LE:
result = operand1Ptr->byte <= operand2Ptr->byte;
break;
case TKN_GE:
result = operand1Ptr->byte >= operand2Ptr->byte;
break;
}
}
else if ((resultTypePtr->form == FRM_ARRAY) && (resultTypePtr->info.array.elementTypePtr == CharTypePtr))
{
//----------------------------------------
// Strings. For now, always return true...
result = true;
}
else if ((resultTypePtr == RealTypePtr) || (type2Ptr == RealTypePtr))
{
promoteOperandsToReal(operand1Ptr, resultTypePtr, operand2Ptr, type2Ptr);
switch (op)
{
case TKN_EQUALEQUAL:
result = operand1Ptr->real == operand2Ptr->real;
break;
case TKN_LT:
result = operand1Ptr->real < operand2Ptr->real;
break;
case TKN_GT:
result = operand1Ptr->real > operand2Ptr->real;
break;
case TKN_NE:
result = operand1Ptr->real != operand2Ptr->real;
break;
case TKN_LE:
result = operand1Ptr->real <= operand2Ptr->real;
break;
case TKN_GE:
result = operand1Ptr->real >= operand2Ptr->real;
break;
}
}
//---------------------------------------------------------
// Replace the two operands with the result on the stack...
if (result)
operand1Ptr->integer = 1;
else
operand1Ptr->integer = 0;
pop();
resultTypePtr = BooleanTypePtr;
}
return(resultTypePtr);
}
//***************************************************************************
}
File diff suppressed because it is too large Load Diff
+159
View File
@@ -0,0 +1,159 @@
#include "MW4Headers.hpp"
// Created 5/16/2002 by ASH - Advanced Gyro
#include "AdvancedGyro.hpp"
#include "SubsystemClassData.hpp"
#include "Mech.hpp"
//#############################################################################
//############################ AdvancedGyro ###########################
//#############################################################################
AdvancedGyro::ClassData*
AdvancedGyro::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AdvancedGyro::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
AdvancedGyroClassID,
"MechWarrior4::AdvancedGyro",
Subsystem::DefaultData,
0, NULL,
(Entity::Factory)Make,
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
ExecutionStateEngine::DefaultData,
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
NULL,
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
(Entity::GameModel::ModelSave)GameModel::SaveGameModel,
(Subsystem::StreamCreate)CreateStream
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AdvancedGyro::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AdvancedGyro*
AdvancedGyro::Make(
CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(message);
gos_PushCurrentHeap(Heap);
AdvancedGyro *new_entity =
new AdvancedGyro(DefaultData, message, base_id, NULL);
gos_PopCurrentHeap();
Check_Object(new_entity);
return new_entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AdvancedGyro::AdvancedGyro(
ClassData *class_data,
CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::Element *element
):
Subsystem(class_data, message, base_id, element)
{
Check_Object(message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AdvancedGyro::~AdvancedGyro()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
AdvancedGyro::ConnectSubsystem()
{
Check_Object(this);
Verify(GetParentVehicle()->IsDerivedFrom(Mech::DefaultData));
m_parentMech = Cast_Pointer(Mech*, GetParentVehicle());
const Mech::GameModel *mech_model = m_parentMech->GetGameModel();
Check_Object(mech_model);
bool return_value = false;
if(m_parentMech->DoesHaveAvailableTonage(mech_model->m_advancedGyroTonnage))
return_value = BaseClass::ConnectSubsystem();
if(return_value)
m_parentMech->AddTonage(mech_model->m_advancedGyroTonnage);
return return_value;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//
bool
AdvancedGyro::DisconnectSubsystem()
{
Check_Object(this);
Verify(GetParentVehicle()->IsDerivedFrom(Mech::DefaultData));
m_parentMech = Cast_Pointer(Mech*, GetParentVehicle());
const Mech::GameModel *mech_model = m_parentMech->GetGameModel();
Check_Object(mech_model);
bool return_value = false;
return_value = BaseClass::DisconnectSubsystem();
if(return_value)
m_parentMech->SubtractTonage(mech_model->m_advancedGyroTonnage);
return return_value;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AdvancedGyro::DestroySubsystem()
{
Check_Object(this);
MWObject *mw_object = GetParentVehicle();
Check_Object(mw_object);
Verify(mw_object->IsDerivedFrom(Mech::DefaultData));
Mech *mech = Cast_Object(Mech *, mw_object);
mech->DestroyAdvancedGyro();
m_parentMech = Cast_Pointer(Mech*, GetParentVehicle());
const Mech::GameModel *mech_model = m_parentMech->GetGameModel();
Check_Object(mech_model);
m_parentMech->SubtractTonage(mech_model->m_advancedGyroTonnage);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AdvancedGyro::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
@@ -0,0 +1,91 @@
// Created 6/16/2002 by ASH - Advanced Gyro
#pragma once
#include "MW4.hpp"
#include "Subsystem.hpp"
namespace MechWarrior4
{
class Mech;
typedef Subsystem__ClassData AdvancedGyro__ClassData;
typedef Subsystem__GameModel AdvancedGyro__GameModel;
typedef Subsystem__Message AdvancedGyro__Message;
typedef Subsystem__ExecutionStateEngine AdvancedGyro__ExecutionStateEngine;
typedef Subsystem__CreateMessage AdvancedGyro__CreateMessage;
//##########################################################################
//######################## AdvancedGyro #############################
//##########################################################################
class AdvancedGyro:
public Subsystem
{
public:
static void
InitializeClass();
static void
TerminateClass();
typedef Subsystem BaseClass;
//##########################################################################
// Inheritance support
//
public:
typedef AdvancedGyro__ClassData ClassData;
typedef AdvancedGyro__GameModel GameModel;
typedef AdvancedGyro__Message Message;
typedef AdvancedGyro__ExecutionStateEngine ExecutionStateEngine;
typedef AdvancedGyro__CreateMessage CreateMessage;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Run-time Construction and Destruction Support
//
public:
static AdvancedGyro*
Make(
CreateMessage *message,
ReplicatorID *base_id
);
protected:
AdvancedGyro(
ClassData *class_data,
CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::Element *element
);
~AdvancedGyro();
Mech *m_parentMech;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data support
//
public:
static ClassData
*DefaultData;
void
DestroySubsystem();
bool
ConnectSubsystem();
bool
DisconnectSubsystem();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Test Support
//
public:
void
TestInstance() const;
};
}
File diff suppressed because it is too large Load Diff
+506
View File
@@ -0,0 +1,506 @@
//===========================================================================//
// File: Mech.hpp
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 09/09/98 JSE Inital base class based off of Shadowrun/Adept //
// 09/22/98 BDD Inital base Mech class based off Vehicle //
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#pragma once
#include "MW4.hpp"
#include "Vehicle.hpp"
#pragma warning (push)
#include <vector>
#pragma warning (pop)
namespace Adept
{
class Effect;
}
namespace MechWarrior4
{
class Airplane;
class Subsystem;
extern DWORD Executed_Airplane_Count;
//##########################################################################
//############### Airplane::ExecutionStateEngine #####################
//##########################################################################
class Airplane__ExecutionStateEngine:
public Vehicle__ExecutionStateEngine
{
public:
static void
InitializeClass();
static void
TerminateClass();
typedef Vehicle__ExecutionStateEngine BaseClass;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Run-time Construction and Destruction Support
//
public:
typedef Airplane__ExecutionStateEngine*
(*Factory)(
Airplane *entity,
FactoryRequest *request
);
static Airplane__ExecutionStateEngine*
Make(
Airplane *mover,
FactoryRequest *request
);
protected:
Airplane__ExecutionStateEngine(
ClassData *class_data,
Airplane *mover,
FactoryRequest *request
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class Data support
//
public:
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// State stuff
//
public:
enum {
TakingOffMotionState = Vehicle::ExecutionStateEngine::StateCount,
LandingMotionState,
CrashingDeathState,
TaxiState,
PopupState,
PopdownState,
FloatState,
StateCount
};
int
RequestState(
int new_state,
void* data = NULL
);
protected:
static const StateEntry
StateEntries[];
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Test Support
//
public:
void
TestInstance() const;
};
//##########################################################################
//##################### Airplane::ModelResource #######################
//##########################################################################
class Airplane__GameModel:
public Vehicle__GameModel
{
public:
Stuff::Scalar
flyingAltitude;
Stuff::Radian
tiltSpeed;
Stuff::Radian
tiltDegree;
Stuff::Scalar
percentageOfTurnToStartTilt;
Stuff::Scalar
percentageOfSpeedToStartTilt;
Stuff::Radian
pitchSpeed;
Stuff::Radian
pitchDegree;
Stuff::Scalar
percentageOfSpeedToStartPitch;
Stuff::Scalar maxClimb,maxDescent;
Stuff::Scalar
maxTurnAngle,
thrusterAcceleration,
takeOffSpeed;
Adept::ResourceID
takeOffResource,
takeOffGroundResource,
landingResource,
landingGroundResource;
static bool
ReadAndVerify(
Airplane__GameModel *model,
ModelAttributeEntry *attribute_entry,
const char *data,
char **error,
int error_buffer = 128
);
static void
ConstructGameModel(Script *script);
enum {
FlyingAltitudeAttributeID = Vehicle__GameModel::NextAttributeID,
TiltSpeedAttributeID,
TiltDegreeAttributeID,
PercentageOfTurnToStartTiltAttributeID,
PercentageOfSpeedToStartTiltAttributeID,
MaxTurnAngleAttributeID,
ThrusterAccelerationAttributeID,
PitchSpeedAttributeID,
PitchDegreeAttributeID,
PercentageOfSpeedToStartPitchAttributeID,
TakeOffSpeedAttributeID,
MaxClimbAttributeID,
MaxDescentAttributeID,
TakeOffResourceAttributeID,
TakeOffGroundResourceAttributeID,
LandingResourceAttributeID,
LandingGroundResourceAttributeID,
NextAttributeID
};
};
//##########################################################################
//################## Mech::CreateMessage #############################
//##########################################################################
class Airplane__CreateMessage:
public Vehicle__CreateMessage
{
public:
Stuff::Scalar
altitude;
Airplane__CreateMessage(
size_t length,
int priority,
int message_flags,
Stuff::RegisteredClass::ClassID class_id,
int replicator_flags,
const ResourceID& instance_id,
const Stuff::LinearMatrix4D &creation_matrix,
Stuff::Scalar age,
int execution_state,
int name_id,
int entity_alignment,
const Stuff::Motion3D &initial_velocity,
const Stuff::Motion3D &initial_acceleration,
const char *entity_name,
const ResourceID& armature_id,
const Adept::ResourceID& site_id,
const ResourceID& subsystem_id,
const ResourceID& damage_id,
char skin_prefix,
int team_prefix,
int pilot_prefix,
int name_index,
bool has_instance_name,
Stuff::Scalar plane_altitude
):
Vehicle__CreateMessage(
length,
priority,
message_flags,
class_id,
replicator_flags,
instance_id,
creation_matrix,
age,
execution_state,
name_id,
entity_alignment,
initial_velocity,
initial_acceleration,
entity_name,
armature_id,
site_id,
subsystem_id,
damage_id,
skin_prefix,
team_prefix,
pilot_prefix,
name_index,
has_instance_name
),
altitude(plane_altitude)
{};
static void
ConstructCreateMessage(Script *script);
};
//##########################################################################
//############################ Airplane ###############################
//##########################################################################
//-------------------------------------------------------------------------
// The following helper classes must always be typedef'd or overriden by an
// inheritor
//
typedef Vehicle__ClassData Airplane__ClassData;
typedef Vehicle__Message Airplane__Message;
//----------------------- End of inheritance stuff ------------------------
class Airplane:
public Vehicle
{
friend class MovementClass;
public:
static void
InitializeClass();
static void
TerminateClass();
typedef Vehicle BaseClass;
//##########################################################################
// Inheritance support
//
public:
typedef Airplane__ClassData ClassData;
typedef Airplane__GameModel GameModel;
typedef Airplane__Message Message;
typedef Airplane__ExecutionStateEngine ExecutionStateEngine;
typedef Airplane__CreateMessage CreateMessage;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Run-time Construction and Destruction Support
//
public:
static Airplane*
Make(
CreateMessage *message,
ReplicatorID *base_id
);
Adept::Replicator::CreateMessage*
SaveMakeMessage(MemoryStream *stream, Adept::ResourceFile *res_file);
void
SaveInstanceText(Stuff::Page *instance_page);
void
Respawn(Adept::Entity::CreateMessage *message);
void
CommonCreation(CreateMessage *message);
void
LoadAnimationScripts();
protected:
Airplane(
ClassData *class_data,
CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::Element *element
);
~Airplane();
void
Reuse(
const CreateMessage *message,
ReplicatorID *base_id
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class Data support
//
public:
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Game Model Support
//
public:
const GameModel*
GetGameModel()
{
Check_Object(this);
return Cast_Pointer(const GameModel*,gameModelResource.GetPointer());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execution Support
//
protected:
static stlport::vector<Scalar> *m_Heights;
bool m_OnGround;
public:
void AdjustAltitude (void);
bool OnGround (void)
{ return m_OnGround; }
void
PreCollisionExecute(Stuff::Time till);
void
PostCollisionExecute(Stuff::Time till);
virtual void
TakeOff(Stuff::Scalar runway_distance);
void
Land(void);
void
Popup(Stuff::Scalar to_height);
void
Popdown(Stuff::Scalar to_height);
void
Float(const Stuff::Point3D& dest);
Stuff::Point3D
takeOffTargetPosition;
Stuff::Point3D
takeOffIntermidiatePosition;
Stuff::Point3D
takeOffFinalOffset;
bool
shouldBeDone;
bool
shouldDie;
bool
shouldLeaveReckage;
Stuff::Scalar flyingAltitude;
Stuff::Scalar m_AttackAltitude;
bool m_Attacking;
Stuff::Point3D&
EstimateFuturePosition(
Stuff::Point3D *new_position,
Stuff::Scalar seconds,
bool consider_terrain = true
);
Stuff::SlotOf<Adept::Effect *>
m_crashingEffect;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Attribute Support
//
public:
enum {
TakingOffSFXAttributeID = Vehicle::NextAttributeID,
InAirSFXAttributeID,
IdleSFXAttributeID,
NextAttributeID
};
public:
int
takingOffSFX,
inAirSFX,
idleSFX,
dyingSFX;
bool
hasTakeOffAnimationLoaded;
void SetTakingOff()
{Check_Pointer(this); takingOffSFX = 1; inAirSFX = 0; idleSFX = 0; dyingSFX = 0;}
void SetInAir()
{Check_Pointer(this); takingOffSFX = 0; inAirSFX = 1; idleSFX = 0; dyingSFX = 0;}
void SetIdle()
{Check_Pointer(this); takingOffSFX = 0; inAirSFX = 0; idleSFX = 1; dyingSFX = 0;}
void SetDying()
{Check_Pointer(this); takingOffSFX = 0; inAirSFX = 0; idleSFX = 0; dyingSFX = 1;}
void SetDead()
{Check_Pointer(this); takingOffSFX = 0; inAirSFX = 0; idleSFX = 0; dyingSFX = 0;}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Tilt Stuff
//
Stuff::Scalar tiltAngle;
Stuff::Scalar tiltRequest;
Stuff::Scalar pitchAngle;
Stuff::Scalar pitchRequest;
void TiltPlane(Stuff::Scalar time_slice);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
public:
void TurnOn();
void TurnOff();
virtual void LandingMovementSimulation(Stuff::Time till);
void FlyingMovementSimulation(Stuff::Time till);
void TakeOffMovementSimulation(Stuff::Time till);
void PopUpOrDownSimulation(Stuff::Scalar time_slice, Stuff::Scalar height);
void FloatSimulation(Stuff::Scalar time_slice);
void ComputeForwardSpeed(Stuff::Scalar time_slice);
virtual void
TakeOffThrusterSimulation(Stuff::Time till, const Stuff::Vector3D& new_velocity, const Stuff::Vector3D& instantanious_angular_velocity,bool canswitch);
void
CrashingDeathMovementSimulation(Stuff::Time till);
void
ReactToDestruction(int damage_mode, int damage_type);
bool
CollisionHandler(
Stuff::LinearMatrix4D *new_position,
Stuff::DynamicArrayOf<CollisionData> *collisions
);
void
GetNetworkPosition(Stuff::Point3D &current_position, Stuff::YawPitchRoll &current_rotation);
private:
Stuff::Scalar m_PopupHeight;
Stuff::Scalar m_PopdownHeight;
Stuff::Scalar m_PopupClimbSpeed;
Stuff::Point3D m_FloatTargetPosition;
Stuff::Scalar m_FloatSpeed;
Stuff::YawPitchRoll m_YPR;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Test Support
//
public:
void
TestInstance() const;
};
inline Airplane__ExecutionStateEngine::Airplane__ExecutionStateEngine(
ClassData *class_data,
Airplane *mover,
FactoryRequest *request
):
BaseClass(class_data, mover, request)
{}
}
@@ -0,0 +1,134 @@
//===========================================================================//
// File: AnimationState.cpp
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 02/23/999 JSE Inital coding
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Microsoft Corp. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include "MW4Headers.hpp"
#include "Airplane.hpp"
#include "AirplaneAnimationStateEngine.hpp"
//#############################################################################
//########################## AirplaneAnimationState #####################
//#############################################################################
AirplaneAnimationStateEngine::ClassData*
AirplaneAnimationStateEngine::DefaultData = NULL;
const StateEngine::StateEntry
AirplaneAnimationStateEngine::StateEntries[]=
{
STATE_ENTRY(AirplaneAnimationStateEngine, Idle),
STATE_ENTRY(AirplaneAnimationStateEngine, TakeOff),
STATE_ENTRY(AirplaneAnimationStateEngine, EndTakeOff)
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AirplaneAnimationStateEngine::InitializeClass()
{
Check_Object(AnimationStateEngine::DefaultData);
Verify(!DefaultData);
DefaultData =
new ClassData(
AirplaneAnimationStateEngineClassID,
"AirplaneAnimationStateEngine",
AnimationStateEngine::DefaultData,
ELEMENTS(StateEntries),
StateEntries,
NULL,
NULL
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AirplaneAnimationStateEngine::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AirplaneAnimationStateEngine*
AirplaneAnimationStateEngine::Make(Vehicle *vehicle, const FactoryRequest *request)
{
Check_Object(request);
Check_Object(vehicle);
gos_PushCurrentHeap(Heap);
AirplaneAnimationStateEngine* engine = new AirplaneAnimationStateEngine(vehicle, DefaultData, request);
gos_PopCurrentHeap();
return engine;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AirplaneAnimationStateEngine::Save(FactoryRequest *request)
{
Check_Object(this);
Check_Object(request);
AnimationStateEngine::Save(request);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AirplaneAnimationStateEngine::Reuse(const FactoryRequest *request)
{
Check_Object(this);
Check_Object(request);
AnimationStateEngine::Reuse(request);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AirplaneAnimationStateEngine::AirplaneAnimationStateEngine(
Vehicle *vehicle,
ClassData *class_data,
const FactoryRequest *request
):
AnimationStateEngine(vehicle, class_data, request)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AirplaneAnimationStateEngine::~AirplaneAnimationStateEngine()
{
}
//#############################################################################
//########################## AnimationStateEngine #######################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
AirplaneAnimationStateEngine::TestClass()
{
Verify(IsDerivedFrom(DefaultData));
}

Some files were not shown because too many files have changed in this diff Show More