#include "pch.h"
#include "TrainingMission.h"
#include "GoalList.h"
#include "Predicate.h"
#include "TrueCondition.h"
#include "FalseCondition.h"
#include "AndCondition.h"
#include "OrCondition.h"
#include "NotCondition.h"
#include "PeriodicCondition.h"
#include "ElapsedTimeCondition.h"
#include "ObjectMovingTowardsCondition.h"
#include "ObjectWithinRadiusCondition.h"
#include "ObjectPointingAtCondition.h"
#include "ConditionalAction.h"
#include "ConditionList.h"
#include "ActionList.h"
#include "MessageAction.h"
#include "PlaySoundAction.h"
#include "SetCommandAction.h"
#include "NoAction.h"
#include "NTimesCondition.h"
#include "EndMissionAction.h"
#include "ResetAction.h"
#include "ResetShipAction.h"
#include "SoundFinishedCondition.h"
#include "SetDisplayModeAction.h"
#include "TurnShipAboutCondition.h"
#include "GetRadarLODCondition.h"
#include "SetRadarLODAction.h"
#include "GetControlActiveCondition.h"
#include "GetStateBitsCondition.h"
#include "GetShipIsStoppedCondition.h"
#include "SetControlConstraintsAction.h"
#include "GetAutopilotCondition.h"
#include "SetAutopilotAction.h"
#include "GetTargetCondition.h"
#include "SuspendedPlaySoundAction.h"
#include "SuspendedSoundFinishedCondition.h"
#include "CommandAcknowledgedCondition.h"
#include "GetKeyCondition.h"
#include "GetChatCondition.h"
namespace Training
{
TrainingMission::TrainingMission (void) :
m_pCondition (0),
m_pDeadCondition (0),
m_commanderID (NA),
m_pChatCondition (0),
m_bSkipPostSlideShow (false)
{
TrekWindow* pWindow = GetWindow ();
if ((m_bMusicWasOn = pWindow->GetMusicIsOn ()) == true)
pWindow->SetMusicOn (false);
if ((m_fHUDStyle = pWindow->GetHUDStyle ()) != 0.0f)
pWindow->SetHUDStyle (0.0f);
pWindow->GetInput ()->LoadMap (DEFAULTINPUTMAP_FILE);
}
TrainingMission::~TrainingMission (void)
{
assert (m_pCondition == 0);
delete m_pDeadCondition;
std::list<Condition*>::iterator pWaitConditionIterator = m_WaitConditionList.begin ();
std::list<Condition*>::iterator end = m_WaitConditionList.end ();
while (pWaitConditionIterator != end)
delete (*pWaitConditionIterator++);
TrekWindow* pWindow = GetWindow ();
if (m_bSkipPostSlideShow)
pWindow->screen (ScreenIDTrainScreen);
else
pWindow->screen (ScreenIDPostTrainSlideshow);
PlayerInfo* pPlayerInfo = trekClient.GetPlayerInfo ();
trekClient.RemovePlayerFromSide (pPlayerInfo, QSR_Quit);
trekClient.RemovePlayerFromMission (pPlayerInfo, QSR_Quit);
pWindow->SetMusicOn (m_bMusicWasOn);
pWindow->SetHUDStyle (m_fHUDStyle);
pWindow->GetInput ()->LoadMap (INPUTMAP_FILE);
if (Time::IsPaused ())
Time::Continue ();
}
void TrainingMission::SetupShipAndCamera (void)
{
IshipIGC* pShip = trekClient.GetShip ();
trekClient.ResetClusterScanners(trekClient.GetShip()->GetSide());
pShip->SetOrientation(Orientation (Vector (1.0f, 0.0f, 0.0f), Vector (0.0f, 0.0f, 1.0f)));
pShip->SetPosition(Vector(0.0f, 0.0f, 0.0f));
pShip->SetCluster(trekClient.GetCore()->GetCluster(GetStartSectorID ()));
TrekWindow* pWindow = GetWindow ();
pWindow->SetViewMode (TrekWindow::vmCombat);
pWindow->SetCameraMode (TrekWindow::cmExternalOrbit);
pWindow->SetRadarMode (RadarImage::c_rlAll);
pWindow->TurnOffOverlayFlags (ofSectorPane | ofInventory | ofGameState);
}
void TrainingMission::Start (void)
{
trekClient.ClearLoadout ();
trekClient.GetClientEventSource ()->OnClearChat ();
CreateUniverse ();
trekClient.OnEnterGame();
m_pCondition = CreateMission ();
ResetAction::Initialize ();
CommandAcknowledgedCondition::SetCommandAcknowledged (c_cidDoNothing);
m_pCondition->Start ();
trekClient.m_serverOffset = 0;
}
bool TrainingMission::Frame (void)
{
if (m_pCondition)
{
if (not Time::IsPaused ())
{
std::list<Condition*>::iterator pWaitConditionIterator = m_WaitConditionList.begin ();
std::list<Condition*>::iterator end = m_WaitConditionList.end ();
if (pWaitConditionIterator != end)
{
while (pWaitConditionIterator != end)
{
if ((*pWaitConditionIterator)->Evaluate () == true)
{
delete (*pWaitConditionIterator);
m_WaitConditionList.erase (pWaitConditionIterator++);
}
else
{
pWaitConditionIterator++;
}
}
}
else
{
if (m_pCondition->Evaluate ())
Terminate ();
}
}
return false;
}
else
{
return true;
}
}
void TrainingMission::Terminate (void)
{
if (not Time::IsPaused ())
Time::Pause ();
m_pDeadCondition = m_pCondition;
m_pCondition = 0;
}
void TrainingMission::AddWaitCondition (Condition* pWaitCondition)
{
m_WaitConditionList.push_front (pWaitCondition);
}
void TrainingMission::RecordChat (ChatTarget recipient)
{
if (m_pChatCondition)
static_cast<GetChatCondition*> (m_pChatCondition)->RecordChat (recipient);
}
void TrainingMission::SetChatCondition (Condition* pChatCondition)
{
if (m_pChatCondition)
delete m_pChatCondition;
m_pChatCondition = pChatCondition;
}
bool TrainingMission::RecordKeyPress (TrekKey key)
{
switch (key)
{
case TK_ViewCommand:
case TK_ConModeCommand:
case TK_ConModeInvest:
case TK_TargetSelf:
case TK_Suicide:
case TK_ConModeGameState:
case TK_ConModeTeleport:
case TK_ToggleAutoPilot:
return false;
case TK_PauseTM:
{
if (Time::IsPaused ())
Time::Continue ();
else
Time::Pause ();
}
break;
#ifdef _DEBUG_TRAINING
case TK_SkipTMGoal:
{
}
break;
case TK_IncreaseTMClockSpeed:
{
Time::SetShift (Time::GetShift () + 1);
}
break;
case TK_DecreaseTMClockSpeed:
{
Time::SetShift (Time::GetShift () - 1);
}
break;
case TK_ResetTMClockSpeed:
{
Time::SetShift (0);
}
break;
#endif
default:
{
std::list<Condition*>::iterator iterator = m_KeyConditionList.begin ();
while (iterator != m_KeyConditionList.end ())
(static_cast<GetKeyCondition*> (*iterator++))->KeyPressed (key);
}
break;
}
return true;
}
void TrainingMission::AddKeyCondition (Condition* pKeyCondition)
{
m_KeyConditionList.push_front (pKeyCondition);
}
bool TrainingMission::ShipLanded (void)
{
return true;
}
void TrainingMission::ShipDied (ImodelIGC* pLauncher)
{
IshipIGC* pShip = trekClient.GetShip ();
TrekWindow* pWindow = GetWindow ();
m_deadViewMode = pWindow->GetViewMode ();
m_deadCameraMode = pWindow->GetCameraMode ();
m_deadSectorID = static_cast<SectorID> (pShip->GetCluster ()->GetObjectID ());
if (pLauncher && pLauncher->GetMission ())
{
Vector shipPosition = pShip->GetPosition ();
Vector launcherPosition = pLauncher->GetPosition ();
Vector delta = shipPosition - launcherPosition;
float fDeltaLength = delta.Length ();
Vector deltaUnit = delta / fDeltaLength;
float fNewVelocity = (pShip->GetVelocity ().Length () * 0.5f);
Vector newVelocity = deltaUnit * fNewVelocity;
float fNewSeparation = 1.5f * (pShip->GetRadius () + pLauncher->GetRadius ());
if (fNewSeparation > fDeltaLength)
pShip->SetPosition (launcherPosition + (deltaUnit * fNewSeparation));
pShip->SetVelocity (newVelocity);
}
trekClient.EjectPlayer (pLauncher);
pShip->SetCluster (NULL);
}
bool TrainingMission::RestoreShip (void)
{
IshipIGC* pShip = trekClient.GetShip ();
TrekWindow* pWindow = GetWindow ();
ImissionIGC* pMission = trekClient.GetCore ();
pShip->SetFraction (1.0f);
trekClient.SetViewCluster (NULL);
pShip->SetCluster (pMission->GetCluster (m_deadSectorID));
pWindow->SetViewMode (m_deadViewMode);
pWindow->SetCameraMode (m_deadCameraMode);
const ClusterListIGC* pClusterList = pMission->GetClusters ();
ClusterLinkIGC* pClusterLink;
for (pClusterLink = pClusterList->first (); pClusterLink; pClusterLink = pClusterLink->next ())
{
IclusterIGC * pCluster = pClusterLink->data ();
pCluster->SetActive (true);
}
AddWaitCondition (new ElapsedTimeCondition (5.0f));
return true;
}
IshipIGC* TrainingMission::GetCommanderShip (void) const
{
return trekClient.GetCore ()->GetShip (m_commanderID);
}
void TrainingMission::AddPartToShip (IshipIGC* pShip, PartID part, Mount mount, short ammo)
{
PartData pd;
pd.partID = part;
pd.mountID = mount;
pd.amount = ammo;
pShip->CreateAndAddPart (&pd);
}
void TrainingMission::AddPartToShip (PartID part, Mount mount, short ammo)
{
AddPartToShip (trekClient.GetShip (), part, mount, ammo);
}
IshipIGC* TrainingMission::CreateDrone (const ZString& name, ShipID shipID, HullID hullID, SideID sideID, PilotType pilotType)
{
DataShipIGC dataShip;
ImissionIGC* pMission = trekClient.GetCore ();
if (shipID == NA)
shipID = pMission->GenerateNewShipID ();
dataShip.shipID = (shipID != NA) ? shipID : pMission->GenerateNewShipID ();
dataShip.hullID = hullID;
dataShip.sideID = sideID;
dataShip.pilotType = pilotType;
strcpy (dataShip.name, name);
dataShip.nKills = 0;
dataShip.nDeaths = 0;
dataShip.nParts = 0;
dataShip.baseObjectID = NA;
switch (pilotType)
{
case c_ptMiner: dataShip.abmOrders = c_aabmMineHe3; break;
case c_ptBuilder: dataShip.abmOrders = c_aabmBuildable; break;
default: dataShip.abmOrders = 0; break;
}
IshipIGC* pShip = static_cast<IshipIGC*> (pMission->CreateObject (pMission->GetLastUpdate(), OT_ship, &dataShip, sizeof(DataShipIGC)));
CreatePlayerInfo (pShip, sideID, shipID);
DefaultLoadout (pShip);
pShip->SetAutopilot(true);
pShip->Release();
return pShip;
}
void TrainingMission::SetSkipPostSlideshow (void)
{
m_bSkipPostSlideShow = true;
}
void TrainingMission::LoadUniverse (const ZString& name, HullID hullID, StationID homeStationID)
{
ImissionIGC* pCore = trekClient.ResetStaticData ();
Time now = pCore->GetLastUpdate();
char* szStaticCoreFilename = IGC_STATIC_CORE_FILENAME;
int iStaticCoreVersion = LoadIGCStaticCore (szStaticCoreFilename, pCore, false);
static const float fSideColors[c_cSidesMax][3] =
{
{200.0f/255.0f, 15.0f/255.0f, 200.0f/255.0f}, { 8.0f/255.0f, 184.0f/255.0f, 184.0f/255.0f}, { 0.0f/255.0f, 0.0f/255.0f, 233.0f/255.0f}, {184.0f/255.0f, 184.0f/255.0f, 50.0f/255.0f}, {184.0f/255.0f, 92.0f/255.0f, 0.0f/255.0f}, {123.0f/255.0f, 61.0f/255.0f, 61.0f/255.0f} };
static const char* szSideNames[c_cSidesMax] =
{
"Iron League",
"Bios",
"Gigacorp",
"Protectorate",
"Colossal Mining Corp",
"Midnight Runners"
};
static CivID civs[c_cSidesMax] = {25, 35, 18, 25, 35, 18};
assert (sizeofArray(szSideNames) == c_cSidesMax);
assert (sizeofArray(civs) == c_cSidesMax);
for (SideID sid = 0; sid < c_cSidesMax; sid++)
{
IcivilizationIGC* pCiv = pCore->GetCivilization (civs[sid]);
DataSideIGC ds;
ds.nFlags = 0;
ds.sideID = sid;
ds.gasAttributes.Initialize();
assert (civs[sid] != NA);
ds.civilizationID = civs[sid];
ds.color.SetRGBA(fSideColors[sid][0], fSideColors[sid][1], fSideColors[sid][2]);
strcpy(ds.name, szSideNames[sid]);
ds.ttbmDevelopmentTechs = pCiv->GetBaseTechs();
ds.ttbmInitialTechs = pCiv->GetBaseTechs();
ds.conquest = 100 / c_cSidesMax;
ds.nKills = ds.nDeaths = ds.nBaseKills = ds.nBaseCaptures = ds.nFlags = ds.nArtifacts = 0;
ds.squadID = NA;
IsideIGC* pSide = static_cast<IsideIGC*> (pCore->CreateObject(now, OT_side, &ds, sizeof(ds)));
if (sid == 0)
{
TechTreeBitMask allTechs;
allTechs.SetAll ();
pSide->SetDevelopmentTechs (allTechs);
pSide->SetBuildingTechs (allTechs);
}
pSide->Release ();
}
FMD_S_MISSIONDEF fmMissionDef;
fmMissionDef.szDescription[0] = 0;
strcpy (fmMissionDef.misparms.szIGCStaticFile, szStaticCoreFilename);
fmMissionDef.misparms.verIGCcore = iStaticCoreVersion;
fmMissionDef.dwCookie = static_cast<DWORD> (pCore->GetMissionID ());
fmMissionDef.iSideMissionOwner = 0;
fmMissionDef.fAutoAcceptLeaders = false;
fmMissionDef.fInProgress = true;
fmMissionDef.stage = STAGE_STARTED;
for (int q = 0; q < c_cSidesMax; q++)
{
strcpy (fmMissionDef.rgszName[q], szSideNames[q]);
fmMissionDef.rgStationID[q] = NA;
fmMissionDef.rgShipIDLeaders[q] = NA;
fmMissionDef.rgcPlayers[q] = 0;
fmMissionDef.rgfAutoAccept[q] = true;
fmMissionDef.rgfReady[q] = true;
fmMissionDef.rgfForceReady[q] = true;
fmMissionDef.rgfActive[q] = true;
}
MissionInfo* pMissionInfo = trekClient.MyMission();
ZAssert (pMissionInfo);
pMissionInfo->Update (&fmMissionDef);
trekClient.GetClientEventSource ()->OnAddMission (pMissionInfo);
IshipIGC* pShip = trekClient.GetShip ();
pShip->SetName ("Cadet");
CreatePlayerInfo (trekClient.GetShip (), 0, pCore->GenerateNewShipID());
LoadIGCFile (name, pCore);
IhullTypeIGC* pHullType = pCore->GetHullType (hullID);
pShip->SetBaseHullType (pHullType);
DefaultLoadout (pShip);
trekClient.SaveLoadout (pShip);
ThingSite* pThingSite = trekClient.GetShip ()->GetThingSite();
assert (pThingSite);
pThingSite->SetTrailColor (pCore->GetSide (0)->GetColor());
m_commanderID = pCore->GenerateNewShipID();
IshipIGC* commanderShip = CreateDrone ("Commander", m_commanderID, 412, 0, c_ptWingman);
const ClusterListIGC* pClusterList = pCore->GetClusters ();
ClusterLinkIGC* pClusterLink;
for (pClusterLink = pClusterList->first (); pClusterLink; pClusterLink = pClusterLink->next ())
{
IclusterIGC * pCluster = pClusterLink->data ();
pCluster->SetActive (true);
}
}
void TrainingMission::DefaultLoadout (IshipIGC* pShip)
{
const IhullTypeIGC* pHullType = pShip->GetHullType ();
for (PartTypeLinkIGC* pPartTypeLink = pHullType->GetPreferredPartTypes()->first (); pPartTypeLink != NULL; pPartTypeLink = pPartTypeLink->next ())
{
IpartTypeIGC* pPartType = pPartTypeLink->data ();
EquipmentType equipmentType = pPartType->GetEquipmentType();
Mount mountMax = (equipmentType == ET_Weapon) ? pHullType->GetMaxWeapons () : 1;
for (Mount i = 0; i < mountMax; i++)
if ((pShip->GetMountedPart (equipmentType, i) == NULL) && pHullType->CanMount (pPartType, i))
pShip->CreateAndAddPart (pPartType, i, 0x7fff);
}
AddPartToShip (pShip, 24, -1, 0x7fff); AddPartToShip (pShip, 24, -2, 0x7fff); AddPartToShip (pShip, 25, -3, 0x7fff); AddPartToShip (pShip, 150, -4, 0x7fff); AddPartToShip (pShip, 150, -5, 0x7fff); IshieldIGC* pShield = static_cast<IshieldIGC*> (pShip->GetMountedPart (ET_Shield, 0));
if (pShield)
pShield->SetFraction (1.0f);
pShip->SetAmmo (pShip->GetHullType ()->GetMaxAmmo ());
pShip->SetEnergy (pShip->GetHullType ()->GetMaxEnergy ());
pShip->SetFuel (pShip->GetHullType ()->GetMaxFuel ());
}
void TrainingMission::CreatePlayerInfo (IshipIGC* pShip, SideID side, ShipID shipID)
{
ImissionIGC* pMission = trekClient.GetCore ();
IsideIGC* pSide = pShip->GetSide ();
if (pSide)
{
assert (static_cast<SideID> (pSide->GetObjectID ()) == side);
pShip->SetSide (NULL);
}
FMD_S_PLAYERINFO fmPlayerInfo;
PlayerInfo* pPlayerInfo = trekClient.FindAndCreatePlayerLink (shipID);
memset(&fmPlayerInfo, 0, sizeof(fmPlayerInfo));
strcpy(fmPlayerInfo.CharacterName, pShip->GetName ());
fmPlayerInfo.iSide = NA;
fmPlayerInfo.dtidDrone = NA;
fmPlayerInfo.shipID = shipID;
fmPlayerInfo.cbrgPersistPlayerScores = 0;
pPlayerInfo->Set (&fmPlayerInfo);
pPlayerInfo->SetMission (pMission);
if (pShip == trekClient.GetShip ())
trekClient.SetPlayerInfo (pPlayerInfo);
pPlayerInfo->SetShip (pShip);
pShip->SetPrivateData (reinterpret_cast<DWORD> (pPlayerInfo));
trekClient.AddPlayerToMission (pPlayerInfo);
trekClient.AddPlayerToSide (pPlayerInfo, side);
}
Goal* TrainingMission::CreatePlaySoundGoal (SoundID sound)
{
PlaySoundAction* pPlaySoundAction = new PlaySoundAction (sound);
Goal* pGoal = new Goal (new SoundFinishedCondition (pPlaySoundAction));
pGoal->AddStartAction (pPlaySoundAction);
return pGoal;
}
Condition* TrainingMission::CreateTooCloseCondition (TRef<ImodelIGC> place)
{
TRef<ImodelIGC> ship = static_cast<ImodelIGC*> (trekClient.GetShip());
ObjectWithinRadiusCondition* pWithinRadiusCondition = new ObjectWithinRadiusCondition (ship, place, ship->GetRadius () * 10.0f);
Condition* pMovingTowardsCondition = new ObjectMovingTowardsCondition (ship, place);
Condition* pAndCondition = new AndCondition (pWithinRadiusCondition, pMovingTowardsCondition);
MessageAction* pTooCloseMessage = new MessageAction (ZString ("Don't get too close to ") + GetModelName (place) + "!");
float fDisplayRadius = pWithinRadiusCondition->GetRadarRadius ();
char cFloatStringBuffer[256];
fDisplayRadius = floorf (fDisplayRadius * 0.02f) * 50.0f;
sprintf (cFloatStringBuffer, "Stay at least %g meters from ", floorf (fDisplayRadius));
pTooCloseMessage->AddMessage (ZString (cFloatStringBuffer) + GetModelName (place) + "!");
pTooCloseMessage->AddMessage ("A little close, don't ya think?");
pTooCloseMessage->AddMessage ("Watch your range!");
pTooCloseMessage->AddMessage ("Whoa! where are the parachutes?");
pTooCloseMessage->AddMessage ("You scratch my ship, I scratch your hide!");
Condition* pPeriodicCondition = new PeriodicCondition (pAndCondition, 2.0f);
ConditionalAction* pTooCloseCondition = new ConditionalAction (pPeriodicCondition, pTooCloseMessage, ConditionalAction::DELAYED_EXECUTION);
return pTooCloseCondition;
}
Condition* TrainingMission::CreateTooLongCondition (float fDelay, SoundID sound)
{
Condition* pPeriodicCondition = new PeriodicCondition (new NTimesCondition (new TrueCondition, 2, true), fDelay);
ConditionalAction* pTooLongCondition = new ConditionalAction (pPeriodicCondition, new PlaySoundAction (sound));
return pTooLongCondition;
}
}