From d17521c8b9085a91d08fecfd0b51bbbf7b1dccac Mon Sep 17 00:00:00 2001 From: "milo24x7@gmail.com" Date: Sun, 7 Jul 2013 22:08:49 +0000 Subject: Updated open source license declaration and fixed some formatting issues. --- Stars45/Mission.cpp | 4346 ++++++++++++++++++++++++++------------------------- 1 file changed, 2185 insertions(+), 2161 deletions(-) (limited to 'Stars45/Mission.cpp') diff --git a/Stars45/Mission.cpp b/Stars45/Mission.cpp index 777f78c..ee9f9b6 100644 --- a/Stars45/Mission.cpp +++ b/Stars45/Mission.cpp @@ -1,2161 +1,2185 @@ -/* Project Starshatter 5.0 - Destroyer Studios LLC - Copyright (C) 1997-2007. All Rights Reserved. - - SUBSYSTEM: Stars.exe - FILE: Mission.cpp - AUTHOR: John DiCamillo - - - OVERVIEW - ======== - Mission classes -*/ - -#include "MemDebug.h" -#include "Mission.h" -#include "MissionEvent.h" -#include "StarSystem.h" -#include "Galaxy.h" -#include "Starshatter.h" -#include "Ship.h" -#include "ShipDesign.h" -#include "Element.h" -#include "Instruction.h" -#include "WeaponDesign.h" -#include "Sim.h" - -#include "Game.h" -#include "DataLoader.h" -#include "ParseUtil.h" -#include "FormatUtil.h" -#include "Random.h" -#include "Skin.h" - -// +--------------------------------------------------------------------+ - -Mission::Mission(int identity, const char* fname, const char* pname) -: id(identity), type(0), team(1), ok(false), active(false), complete(false), -star_system(0), start(33 * 3600), stardate(0), target(0), ward(0), -current(0), degrees(false) -{ - objective = Game::GetText("Mission.unspecified"); - sitrep = Game::GetText("Mission.unknown"); - - if (fname) - strcpy_s(filename, fname); - else - ZeroMemory(filename, sizeof(filename)); - - if (pname) - strcpy_s(path, pname); - else - strcpy_s(path, "Missions/"); -} - -Mission::~Mission() -{ - ::Print("Mission::~Mission() id = %d name = '%s'\n", id, name.data()); - elements.destroy(); - events.destroy(); -} - -// +--------------------------------------------------------------------+ - -const char* -Mission::Subtitles() const -{ - return subtitles; -} - -// +--------------------------------------------------------------------+ - -void -Mission::AddElement(MissionElement* elem) -{ - if (elem) - elements.append(elem); -} - -// +--------------------------------------------------------------------+ - -MissionElement* -Mission::FindElement(const char* name) -{ - ListIter iter = elements; - while (++iter) { - MissionElement* elem = iter.value(); - - if (elem->Name() == name) - return elem; - } - - return 0; -} - -// +--------------------------------------------------------------------+ - -void -Mission::IncreaseElemPriority(int elem_index) -{ - if (elem_index > 0 && elem_index < elements.size()) { - MissionElement* elem1 = elements.at(elem_index-1); - MissionElement* elem2 = elements.at(elem_index); - - elements.at(elem_index-1) = elem2; - elements.at(elem_index) = elem1; - } -} - -void -Mission::DecreaseElemPriority(int elem_index) -{ - if (elem_index >= 0 && elem_index < elements.size()-1) { - MissionElement* elem1 = elements.at(elem_index); - MissionElement* elem2 = elements.at(elem_index+1); - - elements.at(elem_index) = elem2; - elements.at(elem_index+1) = elem1; - } -} - -// +--------------------------------------------------------------------+ - -void -Mission::IncreaseEventPriority(int event_index) -{ - if (event_index > 0 && event_index < events.size()) { - MissionEvent* event1 = events.at(event_index-1); - MissionEvent* event2 = events.at(event_index); - - events.at(event_index-1) = event2; - events.at(event_index) = event1; - } -} - -void -Mission::DecreaseEventPriority(int event_index) -{ - if (event_index >= 0 && event_index < events.size()-1) { - MissionEvent* event1 = events.at(event_index); - MissionEvent* event2 = events.at(event_index+1); - - events.at(event_index) = event2; - events.at(event_index+1) = event1; - } -} - -// +--------------------------------------------------------------------+ - -void -Mission::SetStarSystem(StarSystem* s) -{ - if (star_system != s) { - star_system = s; - - if (!system_list.contains(s)) - system_list.append(s); - } -} - -void -Mission::ClearSystemList() -{ - star_system = 0; - system_list.clear(); -} - -// +--------------------------------------------------------------------+ - -void -Mission::SetPlayer(MissionElement* player_element) -{ - ListIter elem = elements; - while (++elem) { - MissionElement* element = elem.value(); - if (element == player_element) - element->player = 1; - else - element->player = 0; - } -} - -MissionElement* -Mission::GetPlayer() -{ - MissionElement* p = 0; - - ListIter elem = elements; - while (++elem) { - if (elem->player > 0) - p = elem.value(); - } - - return p; -} - -// +--------------------------------------------------------------------+ - -MissionEvent* -Mission::FindEvent(int event_type) const -{ - Mission* pThis = (Mission*) this; - ListIter iter = pThis->events; - while (++iter) { - MissionEvent* event = iter.value(); - - if (event->Event() == event_type) - return event; - } - - return 0; -} - -void -Mission::AddEvent(MissionEvent* event) -{ - if (event) - events.append(event); -} - -// +--------------------------------------------------------------------+ - -bool -Mission::Load(const char* fname, const char* pname) -{ - ok = false; - - if (fname) - strcpy_s(filename, fname); - - if (pname) - strcpy_s(path, pname); - - if (!filename[0]) { - Print("\nCan't Load Mission, script unspecified.\n"); - return ok; - } - - // wipe existing mission before attempting to load... - elements.destroy(); - events.destroy(); - - Print("\nLoad Mission: '%s'\n", filename); - - DataLoader* loader = DataLoader::GetLoader(); - bool old_fs = loader->IsFileSystemEnabled(); - BYTE* block = 0; - - loader->UseFileSystem(true); - loader->SetDataPath(path); - loader->LoadBuffer(filename, block, true); - loader->SetDataPath(0); - loader->UseFileSystem(old_fs); - - ok = ParseMission((const char*) block); - - loader->ReleaseBuffer(block); - Print("Mission Loaded.\n\n"); - - if (ok) - Validate(); - - return ok; -} - -// +--------------------------------------------------------------------+ - -bool -Mission::ParseMission(const char* block) -{ - Parser parser(new(__FILE__,__LINE__) BlockReader(block)); - Term* term = parser.ParseTerm(); - char err[256]; - - if (!term) { - sprintf_s(err, "ERROR: could not parse '%s'\n", filename); - AddError(err); - return ok; - } - else { - TermText* file_type = term->isText(); - if (!file_type || file_type->value() != "MISSION") { - sprintf_s(err, "ERROR: invalid mission file '%s'\n", filename); - AddError(err); - term->print(10); - return ok; - } - } - - ok = true; - - char target_name[256]; - char ward_name[256]; - - target_name[0] = 0; - ward_name[0] = 0; - - do { - delete term; term = 0; - term = parser.ParseTerm(); - - if (term) { - TermDef* def = term->isDef(); - if (def) { - Text defname = def->name()->value(); - defname.setSensitive(false); - - if (defname == "name") { - GetDefText(name, def, filename); - name = Game::GetText(name); - } - - else if (defname == "desc") { - GetDefText(desc, def, filename); - if (desc.length() > 0 && desc.length() < 32) - desc = Game::GetText(desc); - } - - else if (defname == "type") { - char typestr[64]; - GetDefText(typestr, def, filename); - type = TypeFromName(typestr); - } - - else if (defname == "system") { - char sysname[64]; - GetDefText(sysname, def, filename); - - Galaxy* galaxy = Galaxy::GetInstance(); - - if (galaxy) { - SetStarSystem(galaxy->GetSystem(sysname)); - } - } - - else if (defname == "degrees") - GetDefBool(degrees, def, filename); - - else if (defname == "region") - GetDefText(region, def, filename); - - else if (defname == "objective") { - GetDefText(objective, def, filename); - if (objective.length() > 0 && objective.length() < 32) - objective = Game::GetText(objective); - } - - else if (defname == "sitrep") { - GetDefText(sitrep, def, filename); - if (sitrep.length() > 0 && sitrep.length() < 32) - sitrep = Game::GetText(sitrep); - } - - else if (defname == "subtitles") { - Text subtitles_path; - DataLoader* loader = DataLoader::GetLoader(); - BYTE* block = 0; - - GetDefText(subtitles_path, def, filename); - loader->SetDataPath(0); - loader->LoadBuffer(subtitles_path, block, true); - - subtitles = Text("\n") + (const char*) block; - - loader->ReleaseBuffer(block); - } - - else if (defname == "start") - GetDefTime(start, def, filename); - - else if (defname == "stardate") - GetDefNumber(stardate, def, filename); - - else if (defname == "team") - GetDefNumber(team, def, filename); - - else if (defname == "target") - GetDefText(target_name, def, filename); - - else if (defname == "ward") - GetDefText(ward_name, def, filename); - - else if ((defname == "element") || - (defname == "ship") || - (defname == "station")) { - - if (!def->term() || !def->term()->isStruct()) { - sprintf_s(err, "ERROR: element struct missing in '%s'\n", filename); - AddError(err); - } - else { - TermStruct* val = def->term()->isStruct(); - MissionElement* elem = ParseElement(val); - AddElement(elem); - } - } - - else if (defname == "event") { - if (!def->term() || !def->term()->isStruct()) { - sprintf_s(err, "ERROR: event struct missing in '%s'\n", filename); - AddError(err); - } - else { - TermStruct* val = def->term()->isStruct(); - MissionEvent* event = ParseEvent(val); - AddEvent(event); - } - } - } // def - } // term - } - while (term); - - if (ok) { - if (target_name[0]) - target = FindElement(target_name); - - if (ward_name[0]) - ward = FindElement(ward_name); - } - - return ok; -} - -// +--------------------------------------------------------------------+ - -bool -Mission::Save() -{ - Validate(); - - if (!filename[0] || !path[0]) { - AddError(Game::GetText("Mission.error.no-file")); - return ok; - } - - Text content = Serialize(); - - if (content.length() < 8) { - AddError(Game::GetText("Mission.error.no-serial")); - return ok; - } - - if (!_stricmp(path, "mods/missions/")) { - CreateDirectory("Mods", 0); - CreateDirectory("Mods/Missions", 0); - } - - else if (!_stricmp(path, "multiplayer/")) { - CreateDirectory("Multiplayer", 0); - } - - char fname[256]; - sprintf_s(fname, "%s%s", path, filename); - FILE* f; - fopen_s(&f, fname, "w"); - if (f) { - fwrite(content.data(), content.length(), 1, f); - fclose(f); - } - - return ok; -} - -// +--------------------------------------------------------------------+ - -void -Mission::Validate() -{ - char err[256]; - - ok = true; - - if (elements.isEmpty()) { - sprintf_s(err, Game::GetText("Mission.error.no-elem").data(), filename); - AddError(err); - } - else { - bool found_player = false; - - for (int i = 0; i < elements.size(); i++) { - MissionElement* elem = elements.at(i); - - if (elem->Name().length() < 1) { - sprintf_s(err, Game::GetText("Mission.error.unnamed-elem").data(), filename); - AddError(err); - } - - if (elem->Player() > 0) { - if (!found_player) { - found_player = true; - - if (elem->Region() != GetRegion()) { - sprintf_s(err, Game::GetText("Mission.error.wrong-sector").data(), - elem->Name().data(), - GetRegion()); - AddError(err); - } - } - else { - sprintf_s(err, Game::GetText("Mission.error.extra-player").data(), - elem->Name().data(), - filename); - AddError(err); - } - } - } - - if (!found_player) { - sprintf_s(err, Game::GetText("Mission.error.no-player").data(), filename); - AddError(err); - } - } -} - -void -Mission::AddError(Text err) -{ - ::Print(err); - errmsg += err; - - ok = false; -} - -// +--------------------------------------------------------------------+ - -#define MSN_CHECK(x) if (!_stricmp(n, #x)) result = Mission::x; - -int -Mission::TypeFromName(const char* n) -{ - int result = -1; - - MSN_CHECK(PATROL) - else MSN_CHECK(SWEEP) - else MSN_CHECK(INTERCEPT) - else MSN_CHECK(AIR_PATROL) - else MSN_CHECK(AIR_SWEEP) - else MSN_CHECK(AIR_INTERCEPT) - else MSN_CHECK(STRIKE) - else MSN_CHECK(ASSAULT) - else MSN_CHECK(DEFEND) - else MSN_CHECK(ESCORT) - else MSN_CHECK(ESCORT_FREIGHT) - else MSN_CHECK(ESCORT_SHUTTLE) - else MSN_CHECK(ESCORT_STRIKE) - else MSN_CHECK(INTEL) - else MSN_CHECK(SCOUT) - else MSN_CHECK(RECON) - else MSN_CHECK(BLOCKADE) - else MSN_CHECK(FLEET) - else MSN_CHECK(BOMBARDMENT) - else MSN_CHECK(FLIGHT_OPS) - else MSN_CHECK(TRANSPORT) - else MSN_CHECK(CARGO) - else MSN_CHECK(TRAINING) - else MSN_CHECK(OTHER) - - if (result < PATROL) { - for (int i = PATROL; i <= OTHER && result < PATROL; i++) { - if (!_stricmp(n, RoleName(i))) { - result = i; - } - } - } - - return result; -} - -// +--------------------------------------------------------------------+ - -static int elem_id = 351; - -MissionElement* -Mission::ParseElement(TermStruct* val) -{ - Text design; - Text skin_name; - Text role_name; - int deck = 1; - char err[256]; - - MissionElement* element = new(__FILE__,__LINE__) MissionElement(); - element->rgn_name = region; - element->elem_id = elem_id++; - - current = element; - - for (int i = 0; i < val->elements()->size(); i++) { - TermDef* pdef = val->elements()->at(i)->isDef(); - if (pdef) { - Text defname = pdef->name()->value(); - defname.setSensitive(false); - - if (defname == "name") - GetDefText(element->name, pdef, filename); - - else if (defname == "carrier") - GetDefText(element->carrier, pdef, filename); - - else if (defname == "commander") - GetDefText(element->commander, pdef, filename); - - else if (defname == "squadron") - GetDefText(element->squadron, pdef, filename); - - else if (defname == "path") - GetDefText(element->path, pdef, filename); - - else if (defname == "design") { - GetDefText(design, pdef, filename); - element->design = ShipDesign::Get(design, element->path); - - if (!element->design) { - sprintf_s(err, Game::GetText("Mission.error.unknown-ship").data(), design.data(), filename); - AddError(err); - } - } - - else if (defname == "skin") { - if (!element->design) { - sprintf_s(err, Game::GetText("Mission.error.out-of-order").data(), filename); - AddError(err); - } - - else if (pdef->term()->isText()) { - GetDefText(skin_name, pdef, filename); - element->skin = element->design->FindSkin(skin_name); - } - - else if (pdef->term()->isStruct()) { - sprintf_s(err, Game::GetText("Mission.error.bad-skin").data(), filename); - AddError(err); - } - } - - else if (defname == "mission") { - GetDefText(role_name, pdef, filename); - element->mission_role = TypeFromName(role_name); - } - - else if (defname == "intel") { - GetDefText(role_name, pdef, filename); - element->intel = Intel::IntelFromName(role_name); - } - - else if (defname == "loc") { - Vec3 loc; - GetDefVec(loc, pdef, filename); - element->SetLocation(loc); - } - - else if (defname == "rloc") { - if (pdef->term()->isStruct()) { - RLoc* rloc = ParseRLoc(pdef->term()->isStruct()); - element->SetRLoc(*rloc); - delete rloc; - } - } - - else if (defname.indexOf("head") == 0) { - if (pdef->term()->isArray()) { - Vec3 head; - GetDefVec(head, pdef, filename); - if (degrees) head.z *= (float) DEGREES; - element->heading = head.z; - } - else if (pdef->term()->isNumber()) { - double heading = 0; - GetDefNumber(heading, pdef, filename); - if (degrees) heading *= DEGREES; - element->heading = heading; - } - } - - else if (defname == "region" || defname == "rgn") - GetDefText(element->rgn_name, pdef, filename); - - else if (defname == "iff") - GetDefNumber(element->IFF_code, pdef, filename); - - else if (defname == "count") - GetDefNumber(element->count, pdef, filename); - - else if (defname == "maint_count") - GetDefNumber(element->maint_count, pdef, filename); - - else if (defname == "dead_count") - GetDefNumber(element->dead_count, pdef, filename); - - else if (defname == "player") - GetDefNumber(element->player, pdef, filename); - - else if (defname == "alert") - GetDefBool(element->alert, pdef, filename); - - else if (defname == "playable") - GetDefBool(element->playable, pdef, filename); - - else if (defname == "rogue") - GetDefBool(element->rogue, pdef, filename); - - else if (defname == "invulnerable") - GetDefBool(element->invulnerable, pdef, filename); - - else if (defname == "command_ai") - GetDefNumber(element->command_ai, pdef, filename); - - else if (defname.indexOf("respawn") == 0) - GetDefNumber(element->respawns, pdef, filename); - - else if (defname.indexOf("hold") == 0) - GetDefNumber(element->hold_time, pdef, filename); - - else if (defname.indexOf("zone") == 0) { - if (pdef->term() && pdef->term()->isBool()) { - bool locked = false; - GetDefBool(locked, pdef, filename); - element->zone_lock = locked; - } - else { - GetDefNumber(element->zone_lock, pdef, filename); - } - } - - else if (defname == "objective") { - if (!pdef->term() || !pdef->term()->isStruct()) { - sprintf_s(err, Game::GetText("Mission.error.no-objective").data(), element->name.data(), filename); - AddError(err); - } - else { - TermStruct* val = pdef->term()->isStruct(); - Instruction* obj = ParseInstruction(val, element); - element->objectives.append(obj); - } - } - - else if (defname == "instr") { - Text* obj = new(__FILE__,__LINE__) Text; - if (GetDefText(*obj, pdef, filename)) - element->instructions.append(obj); - else - delete obj; - } - - else if (defname == "ship") { - if (!pdef->term() || !pdef->term()->isStruct()) { - sprintf_s(err, Game::GetText("Mission.error.no-ship").data(), element->name.data(), filename); - AddError(err); - } - else { - TermStruct* val = pdef->term()->isStruct(); - MissionShip* s = ParseShip(val, element); - element->ships.append(s); - - if (s->Integrity() < 0 && element->design) - s->SetIntegrity(element->design->integrity); - } - } - - else if (defname == "order" || defname == "navpt") { - if (!pdef->term() || !pdef->term()->isStruct()) { - sprintf_s(err, Game::GetText("Mission.error.no-navpt").data(), element->name.data(), filename); - AddError(err); - } - else { - TermStruct* val = pdef->term()->isStruct(); - Instruction* npt = ParseInstruction(val, element); - element->navlist.append(npt); - } - } - - else if (defname == "loadout") { - if (!pdef->term() || !pdef->term()->isStruct()) { - sprintf_s(err, Game::GetText("Mission.error.no-loadout").data(), element->name.data(), filename); - AddError(err); - } - else { - TermStruct* val = pdef->term()->isStruct(); - ParseLoadout(val, element); - } - } - } - } - - if (element->name.length() < 1) { - sprintf_s(err, Game::GetText("Mission.error.unnamed-elem").data(), filename); - AddError(err); - } - - else if (element->design == 0) { - sprintf_s(err, Game::GetText("Mission.error.unknown-ship").data(), element->name.data(), filename); - AddError(err); - } - - current = 0; - - return element; -} - -MissionEvent* -Mission::ParseEvent(TermStruct* val) -{ - MissionEvent* event = new(__FILE__,__LINE__) MissionEvent; - Text event_name; - Text trigger_name; - static int event_id = 1; - static double event_time = 0; - - for (int i = 0; i < val->elements()->size(); i++) { - TermDef* pdef = val->elements()->at(i)->isDef(); - if (pdef) { - Text defname = pdef->name()->value(); - defname.setSensitive(false); - - if (defname == "event") { - GetDefText(event_name, pdef, filename); - event->event = MissionEvent::EventForName(event_name); - } - - else if (defname == "trigger") { - GetDefText(trigger_name, pdef, filename); - event->trigger = MissionEvent::TriggerForName(trigger_name); - } - - else if (defname == "id") - GetDefNumber(event_id, pdef, filename); - - else if (defname == "time") - GetDefNumber(event_time, pdef, filename); - - else if (defname == "delay") - GetDefNumber(event->delay, pdef, filename); - - else if (defname == "event_param" || defname == "param" || defname == "color") { - ZeroMemory(event->event_param, sizeof(event->event_param)); - - if (pdef->term()->isNumber()) { - GetDefNumber(event->event_param[0], pdef, filename); - event->event_nparams = 1; - } - - else if (pdef->term()->isArray()) { - std::vector plist; - GetDefArray(plist, pdef, filename); - - for (int i = 0; i < 10 && i < (int)plist.size(); i++) { - float f = plist[i]; - event->event_param[i] = (int) f; - event->event_nparams = i + 1; - } - } - } - - else if (defname == "trigger_param") { - ZeroMemory(event->trigger_param, sizeof(event->trigger_param)); - - if (pdef->term()->isNumber()) { - GetDefNumber(event->trigger_param[0], pdef, filename); - event->trigger_nparams = 1; - } - - else if (pdef->term()->isArray()) { - std::vector plist; - GetDefArray(plist, pdef, filename); - - for (int i = 0; i < 10 && i < (int)plist.size(); i++) { - float f = plist[i]; - event->trigger_param[i] = (int) f; - event->trigger_nparams = i + 1; - } - } - } - - else if (defname == "event_ship" || defname == "ship") - GetDefText(event->event_ship, pdef, filename); - - else if (defname == "event_source" || defname == "source" || defname == "font") - GetDefText(event->event_source, pdef, filename); - - else if (defname == "event_target" || defname == "target" || defname == "image") - GetDefText(event->event_target, pdef, filename); - - else if (defname == "event_message" || defname == "message") { - Text raw_msg; - GetDefText(raw_msg, pdef, filename); - raw_msg = Game::GetText(raw_msg); - event->event_message = FormatTextEscape(raw_msg); - } - - else if (defname == "event_chance" || defname == "chance") - GetDefNumber(event->event_chance, pdef, filename); - - else if (defname == "event_sound" || defname == "sound") - GetDefText(event->event_sound, pdef, filename); - - else if (defname == "loc" || defname == "vec" || defname == "fade") - GetDefVec(event->event_point, pdef, filename); - - else if (defname == "rect") - GetDefRect(event->event_rect, pdef, filename); - - else if (defname == "trigger_ship") - GetDefText(event->trigger_ship, pdef, filename); - - else if (defname == "trigger_target") - GetDefText(event->trigger_target, pdef, filename); - } - } - - event->id = event_id++; - event->time = event_time; - return event; -} - -MissionShip* -Mission::ParseShip(TermStruct* val, MissionElement* element) -{ - MissionShip* msn_ship = new(__FILE__,__LINE__) MissionShip; - - Text name; - Text skin_name; - Text regnum; - Text region; - char err[256]; - Vec3 loc(-1.0e9f, -1.0e9f, -1.0e9f); - Vec3 vel(-1.0e9f, -1.0e9f, -1.0e9f); - int respawns = -1; - double heading = -1e9; - double integrity = -1; - int ammo[16]; - int fuel[4]; - int i; - - for (i = 0; i < 16; i++) - ammo[i] = -10; - - for (i = 0; i < 4; i++) - fuel[i] = -10; - - for (i = 0; i < val->elements()->size(); i++) { - TermDef* pdef = val->elements()->at(i)->isDef(); - if (pdef) { - Text defname = pdef->name()->value(); - defname.setSensitive(false); - - if (defname == "name") - GetDefText(name, pdef, filename); - - else if (defname == "skin") { - if (!element || !element->design) { - sprintf_s(err, Game::GetText("Mission.error.out-of-order").data(), filename); - AddError(err); - } - - else if (pdef->term()->isText()) { - GetDefText(skin_name, pdef, filename); - msn_ship->skin = element->design->FindSkin(skin_name); - } - - else if (pdef->term()->isStruct()) { - sprintf_s(err, Game::GetText("Mission.error.bad-skin").data(), filename); - AddError(err); - } - } - - else if (defname == "regnum") - GetDefText(regnum, pdef, filename); - - else if (defname == "region") - GetDefText(region, pdef, filename); - - else if (defname == "loc") - GetDefVec(loc, pdef, filename); - - else if (defname == "velocity") - GetDefVec(vel, pdef, filename); - - else if (defname == "respawns") - GetDefNumber(respawns, pdef, filename); - - else if (defname == "heading") { - if (pdef->term()->isArray()) { - Vec3 h; - GetDefVec(h, pdef, filename); - if (degrees) h.z *= (float) DEGREES; - heading = h.z; - } - else if (pdef->term()->isNumber()) { - double h = 0; - GetDefNumber(h, pdef, filename); - if (degrees) h *= DEGREES; - heading = h; - } - } - - else if (defname == "integrity") - GetDefNumber(integrity, pdef, filename); - - else if (defname == "ammo") - GetDefArray(ammo, 16, pdef, filename); - - else if (defname == "fuel") - GetDefArray(fuel, 4, pdef, filename); - } - } - - msn_ship->SetName(name); - msn_ship->SetRegNum(regnum); - msn_ship->SetRegion(region); - msn_ship->SetIntegrity(integrity); - - if (loc.x > -1e9) - msn_ship->SetLocation(loc); - - if (vel.x > -1e9) - msn_ship->SetVelocity(vel); - - if (respawns > -1) - msn_ship->SetRespawns(respawns); - - if (heading > -1e9) - msn_ship->SetHeading(heading); - - if (ammo[0] > -10) - msn_ship->SetAmmo(ammo); - - if (fuel[0] > -10) - msn_ship->SetFuel(fuel); - - return msn_ship; -} - -Instruction* -Mission::ParseInstruction(TermStruct* val, MissionElement* element) -{ - int order = Instruction::VECTOR; - int status = Instruction::PENDING; - int formation = 0; - int speed = 0; - int priority = 1; - int farcast = 0; - int hold = 0; - int emcon = 0; - Vec3 loc(0,0,0); - RLoc* rloc = 0; - Text order_name; - Text status_name; - Text order_rgn_name; - Text tgt_name; - Text tgt_desc; - - for (int i = 0; i < val->elements()->size(); i++) { - TermDef* pdef = val->elements()->at(i)->isDef(); - if (pdef) { - Text defname = pdef->name()->value(); - defname.setSensitive(false); - - if (defname == "cmd") { - GetDefText(order_name, pdef, filename); - - for (int cmd = 0; cmd < Instruction::NUM_ACTIONS; cmd++) - if (!_stricmp(order_name, Instruction::ActionName(cmd))) - order = cmd; - } - - else if (defname == "status") { - GetDefText(status_name, pdef, filename); - - for (int n = 0; n < Instruction::NUM_STATUS; n++) - if (!_stricmp(status_name, Instruction::StatusName(n))) - status = n; - } - - else if (defname == "loc") { - GetDefVec(loc, pdef, filename); - } - - else if (defname == "rloc") { - if (pdef->term()->isStruct()) - rloc = ParseRLoc(pdef->term()->isStruct()); - } - - else if (defname == "rgn") { - GetDefText(order_rgn_name, pdef, filename); - } - else if (defname == "speed") { - GetDefNumber(speed, pdef, filename); - } - else if (defname == "formation") { - GetDefNumber(formation, pdef, filename); - } - else if (defname == "emcon") { - GetDefNumber(emcon, pdef, filename); - } - else if (defname == "priority") { - GetDefNumber(priority, pdef, filename); - } - else if (defname == "farcast") { - if (pdef->term()->isBool()) { - bool f = false; - GetDefBool(f, pdef, filename); - farcast = f; - } - else { - GetDefNumber(farcast, pdef, filename); - } - } - else if (defname == "tgt") { - GetDefText(tgt_name, pdef, filename); - } - else if (defname == "tgt_desc") { - GetDefText(tgt_desc, pdef, filename); - } - else if (defname.indexOf("hold") == 0) { - GetDefNumber(hold, pdef, filename); - } - } - } - - Text rgn; - - if (order_rgn_name.length() > 0) - rgn = order_rgn_name; - - else if (element->navlist.size() > 0) - rgn = element->navlist[element->navlist.size()-1]->RegionName(); - - else - rgn = region; - - if (tgt_desc.length() && tgt_name.length()) - tgt_desc = tgt_desc + " " + tgt_name; - - Instruction* instr = new(__FILE__,__LINE__) Instruction(rgn, loc, order); - - instr->SetStatus(status); - instr->SetEMCON(emcon); - instr->SetFormation(formation); - instr->SetSpeed(speed); - instr->SetTarget(tgt_name); - instr->SetTargetDesc(tgt_desc); - instr->SetPriority(priority-1); - instr->SetFarcast(farcast); - instr->SetHoldTime(hold); - - if (rloc) { - instr->GetRLoc() = *rloc; - delete rloc; - } - - return instr; -} - -void -Mission::ParseLoadout(TermStruct* val, MissionElement* element) -{ - int ship = -1; - int stations[16]; - Text name; - - ZeroMemory(stations, sizeof(stations)); - - for (int i = 0; i < val->elements()->size(); i++) { - TermDef* pdef = val->elements()->at(i)->isDef(); - if (pdef) { - Text defname = pdef->name()->value(); - defname.setSensitive(false); - - if (defname == "ship") { - GetDefNumber(ship, pdef, filename); - } - else if (defname == "name") { - GetDefText(name, pdef, filename); - } - else if (defname == "stations") { - GetDefArray(stations, 16, pdef, filename); - } - } - } - - MissionLoad* load = new(__FILE__,__LINE__) MissionLoad(ship); - - if (name.length()) - load->SetName(name); - - for (int i = 0; i < 16; i++) - load->SetStation(i, stations[i]); - - element->loadouts.append(load); -} - -RLoc* -Mission::ParseRLoc(TermStruct* val) -{ - Vec3 base_loc; - RLoc* rloc = new(__FILE__,__LINE__) RLoc; - RLoc* ref = 0; - - double dex = 0; - double dex_var = 5e3; - double az = 0; - double az_var = PI; - double el = 0; - double el_var = 0.1; - - for (int i = 0; i < val->elements()->size(); i++) { - TermDef* pdef = val->elements()->at(i)->isDef(); - if (pdef) { - Text defname = pdef->name()->value(); - defname.setSensitive(false); - - if (defname == "dex") { - GetDefNumber(dex, pdef, filename); - rloc->SetDistance(dex); - } - else if (defname == "dex_var") { - GetDefNumber(dex_var, pdef, filename); - rloc->SetDistanceVar(dex_var); - } - else if (defname == "az") { - GetDefNumber(az, pdef, filename); - if (degrees) az *= DEGREES; - rloc->SetAzimuth(az); - } - else if (defname == "az_var") { - GetDefNumber(az_var, pdef, filename); - if (degrees) az_var *= DEGREES; - rloc->SetAzimuthVar(az_var); - } - else if (defname == "el") { - GetDefNumber(el, pdef, filename); - if (degrees) el *= DEGREES; - rloc->SetElevation(el); - } - else if (defname == "el_var") { - GetDefNumber(el_var, pdef, filename); - if (degrees) el_var *= DEGREES; - rloc->SetElevationVar(el_var); - } - else if (defname == "loc") { - GetDefVec(base_loc, pdef, filename); - rloc->SetBaseLocation(base_loc); - } - - else if (defname == "ref") { - Text refstr; - GetDefText(refstr, pdef, filename); - - int sep = refstr.indexOf(':'); - - if (sep >= 0) { - Text elem_name = refstr.substring(0, sep); - Text nav_name = refstr.substring(sep+1, refstr.length()); - MissionElement* elem = 0; - - if (elem_name == "this") - elem = current; - else - elem = FindElement(elem_name); - - if (elem && elem->NavList().size() > 0) { - int index = atoi(nav_name)-1; - if (index < 0) - index = 0; - else if (index >= elem->NavList().size()) - index = elem->NavList().size()-1; - - ref = &elem->NavList()[index]->GetRLoc(); - rloc->SetReferenceLoc(ref); - } - else { - ::Print("Warning: no ref found for rloc '%s' in elem '%s'\n", refstr.data(), current->Name().data()); - rloc->SetBaseLocation(RandomPoint()); - } - } - else { - MissionElement* elem = 0; - - if (refstr == "this") - elem = current; - else - elem = FindElement(refstr); - - if (elem) { - ref = &elem->GetRLoc(); - rloc->SetReferenceLoc(ref); - } - else { - ::Print("Warning: no ref found for rloc '%s' in elem '%s'\n", refstr.data(), current->Name().data()); - rloc->SetBaseLocation(RandomPoint()); - } - } - } - } - } - - return rloc; -} - -const char* -Mission::RoleName(int role) -{ - switch (role) { - case PATROL: return "Patrol"; - case SWEEP: return "Sweep"; - case INTERCEPT: return "Intercept"; - case AIR_PATROL: return "Airborne Patrol"; - case AIR_SWEEP: return "Airborne Sweep"; - case AIR_INTERCEPT: return "Airborne Intercept"; - case STRIKE: return "Strike"; - case ASSAULT: return "Assault"; - case DEFEND: return "Defend"; - case ESCORT: return "Escort"; - case ESCORT_FREIGHT: return "Freight Escort"; - case ESCORT_SHUTTLE: return "Shuttle Escort"; - case ESCORT_STRIKE: return "Strike Escort"; - case INTEL: return "Intel"; - case SCOUT: return "Scout"; - case RECON: return "Recon"; - case BLOCKADE: return "Blockade"; - case FLEET: return "Fleet"; - case BOMBARDMENT: return "Attack"; - case FLIGHT_OPS: return "Flight Ops"; - case TRANSPORT: return "Transport"; - case CARGO: return "Cargo"; - case TRAINING: return "Training"; - default: - case OTHER: return "Misc"; - } -} - -// +--------------------------------------------------------------------+ - -Text -Mission::Serialize(const char* player_elem, int player_index) -{ - Text s = "MISSION\n\nname: \""; - s += SafeString(Name()); - - if (desc.length()) { - s += "\"\ndesc: \""; - s += SafeString(desc); - } - - s += "\"\ntype: \""; - s += SafeString(TypeName()); - - ListIter sys_iter = system_list; - while (++sys_iter) { - StarSystem* sys = sys_iter.value(); - - if (sys != star_system) { - s += "\"\nsystem: \""; - s += sys->Name(); - } - } - - s += "\"\nsystem: \""; - if (GetStarSystem()) - s += SafeString(GetStarSystem()->Name()); - else - s += "null"; - - ListIter iter = GetElements(); - - Sim* sim = Sim::GetSim(); - if (sim && sim->GetElements().size() > 0) - iter = sim->GetMissionElements(); - - s += "\"\n"; - - bool region_set = false; - if (player_elem && *player_elem) { - // set the mission region to that of the active player - while (++iter) { - MissionElement* e = iter.value(); - if (e->Name() == player_elem) { - char buf[32]; - sprintf_s(buf, "team: %d\n", e->GetIFF()); - s += buf; - - s += "region: \""; - s += SafeString(e->Region()); - s += "\"\n\n"; - - region_set = true; - break; - } - } - - iter.reset(); - } - - if (!region_set) { - s += "region: \""; - s += SafeString(GetRegion()); - s += "\"\n\n"; - } - - if (Objective() && *Objective()) { - s += "objective: \""; - s += SafeString(Objective()); - s += "\"\n\n"; - } - - if (Situation() && *Situation()) { - s += "sitrep: \""; - s += SafeString(Situation()); - s += "\"\n\n"; - } - - char buffer[256]; - FormatTime(buffer, Start()); - - s += "start: \""; - s += buffer; - s += "\"\n\n"; - s += "degrees: true\n\n"; - - while (++iter) { - MissionElement* elem = iter.value(); - - s += "element: {\n"; - s += " name: \""; - s += SafeString(elem->Name()); - s += "\"\n"; - - if (elem->Path().length()) { - s += " path: \""; - s += SafeString(elem->Path()); - s += "\"\n"; - } - - if (elem->GetDesign()) { - s += " design: \""; - s += SafeString(elem->GetDesign()->name); - s += "\"\n"; - } - - if (elem->GetSkin()) { - s += " skin: \""; - s += SafeString(elem->GetSkin()->Name()); - s += "\"\n"; - } - - if (elem->Squadron().length()) { - s += " squadron: \""; - s += SafeString(elem->Squadron()); - s += "\"\n"; - } - - if (elem->Carrier().length()) { - s += " carrier: \""; - s += SafeString(elem->Carrier()); - s += "\"\n"; - } - - if (elem->Commander().length()) { - s += " commander: \""; - s += SafeString(elem->Commander()); - s += "\"\n"; - } - - s += " mission: \""; - s += elem->RoleName(); - s += "\"\n\n"; - - if (elem->IntelLevel()) { - s += " intel: \""; - s += Intel::NameFromIntel(elem->IntelLevel()); - s += "\"\n"; - } - - sprintf_s(buffer, " count: %d\n", elem->Count()); - s += buffer; - - if (elem->MaintCount()) { - sprintf_s(buffer, " maint_count: %d\n", elem->MaintCount()); - s += buffer; - } - - if (elem->DeadCount()) { - sprintf_s(buffer, " dead_count: %d\n", elem->DeadCount()); - s += buffer; - } - - if (elem->RespawnCount()) { - sprintf_s(buffer, " respawn_count: %d\n", elem->RespawnCount()); - s += buffer; - } - - if (elem->HoldTime()) { - sprintf_s(buffer, " hold_time: %d\n", elem->HoldTime()); - s += buffer; - } - - if (elem->ZoneLock()) { - sprintf_s(buffer, " zone_lock: %d\n", elem->ZoneLock()); - s += buffer; - } - - if (elem->IsAlert()) { - s += " alert: true\n"; - } - - if (!elem->IsSquadron()) { - sprintf_s(buffer, " command_ai:%d\n", elem->CommandAI()); - s += buffer; - } - - sprintf_s(buffer, " iff: %d\n", elem->GetIFF()); - s += buffer; - - if (player_elem) { - if (elem->Name() == player_elem) { - if (player_index < 1) - player_index = 1; - - sprintf_s(buffer, " player: %d\n", player_index); - s += buffer; - } - } - - else { - if (elem->Player()) { - sprintf_s(buffer, " player: %d\n", elem->Player()); - s += buffer; - } - } - - if (!elem->IsSquadron()) { - if (elem->IsPlayable()) - s += " playable: true\n"; - else - s += " playable: false\n"; - } - - - s += " region: \""; - s += elem->Region(); - s += "\"\n"; - - sprintf_s(buffer, " loc: (%.0f, %.0f, %.0f)\n", - elem->Location().x, - elem->Location().y, - elem->Location().z); - s += buffer; - - if (elem->Heading() != 0) { - sprintf_s(buffer, " head: %d\n", (int) (elem->Heading()/DEGREES)); - s += buffer; - } - - if (elem->Loadouts().size()) { - s += "\n"; - - ListIter load_iter = elem->Loadouts(); - while (++load_iter) { - MissionLoad* load = load_iter.value(); - - sprintf_s(buffer, " loadout: { ship: %d, ", load->GetShip()); - s += buffer; - - if (load->GetName().length()) { - s += "name: \""; - s += SafeString(load->GetName()); - s += "\" }\n"; - } - else { - s += "stations: ("; - - for (int i = 0; i < 16; i++) { - sprintf_s(buffer, "%d", load->GetStation(i)); - s += buffer; - - if (i < 15) - s += ", "; - } - - s += ") }\n"; - } - } - } - - if (elem->Objectives().size()) { - s += "\n"; - - ListIter obj_iter = elem->Objectives(); - while (++obj_iter) { - Instruction* inst = obj_iter.value(); - - s += " objective: { cmd: "; - s += Instruction::ActionName(inst->Action()); - s += ", tgt: \""; - s += SafeString(inst->TargetName()); - s += "\" }\n"; - } - } - - if (elem->NavList().size()) { - s += "\n"; - - ListIter nav_iter = elem->NavList(); - while (++nav_iter) { - Instruction* inst = nav_iter.value(); - - s += " navpt: { cmd: "; - s += Instruction::ActionName(inst->Action()); - s += ", status: "; - s += Instruction::StatusName(inst->Status()); - - if (inst->TargetName() && *inst->TargetName()) { - s += ", tgt: \""; - s += SafeString(inst->TargetName()); - s += "\""; - } - - sprintf_s(buffer, ", loc: (%.0f, %.0f, %.0f), speed: %d", - inst->Location().x, - inst->Location().y, - inst->Location().z, - inst->Speed()); - s += buffer; - - if (inst->RegionName() && *inst->RegionName()) { - s += ", rgn: \""; - s += inst->RegionName(); - s += "\""; - } - - if (inst->HoldTime()) { - sprintf_s(buffer, ", hold: %d", (int) inst->HoldTime()); - s += buffer; - } - - if (inst->Farcast()) { - s += ", farcast: true"; - } - - if (inst->Formation() > Instruction::DIAMOND) { - sprintf_s(buffer, ", formation: %d", (int) inst->Formation()); - s += buffer; - } - - if (inst->Priority() > Instruction::PRIMARY) { - sprintf_s(buffer, ", priority: %d", (int) inst->Priority()); - s += buffer; - } - - s += " }\n"; - } - } - - if (elem->Instructions().size()) { - s += "\n"; - - ListIter i_iter = elem->Instructions(); - while (++i_iter) { - s += " instr: \""; - s += SafeString(*i_iter.value()); - s += "\"\n"; - } - } - - if (elem->Ships().size()) { - ListIter s_iter = elem->Ships(); - while (++s_iter) { - MissionShip* ship = s_iter.value(); - - s += "\n ship: {\n"; - - if (ship->Name().length()) { - s += " name: \""; - s += SafeString(ship->Name()); - s += "\"\n"; - } - - if (ship->RegNum().length()) { - s += " regnum: \""; - s += SafeString(ship->RegNum()); - s += "\"\n"; - } - - if (ship->Region().length()) { - s += " region: \""; - s += SafeString(ship->Region()); - s += "\"\n"; - } - - if (fabs(ship->Location().x) < 1e9) { - sprintf_s(buffer, " loc: (%.0f, %.0f, %.0f),\n", - ship->Location().x, - ship->Location().y, - ship->Location().z); - s += buffer; - } - - if (fabs(ship->Velocity().x) < 1e9) { - sprintf_s(buffer, " velocity: (%.1f, %.1f, %.1f),\n", - ship->Velocity().x, - ship->Velocity().y, - ship->Velocity().z); - s += buffer; - } - - if (ship->Respawns() > -1) { - sprintf_s(buffer, " respawns: %d,\n", ship->Respawns()); - s += buffer; - } - - if (ship->Heading() > -1e9) { - sprintf_s(buffer, " heading: %d,\n", (int) (ship->Heading()/DEGREES)); - s += buffer; - } - - if (ship->Integrity() > -1) { - sprintf_s(buffer, " integrity: %d,\n", (int) ship->Integrity()); - s += buffer; - } - - if (ship->Decoys() > -1) { - sprintf_s(buffer, " decoys: %d,\n", ship->Decoys()); - s += buffer; - } - - if (ship->Probes() > -1) { - sprintf_s(buffer, " probes: %d,\n", ship->Probes()); - s += buffer; - } - - if (ship->Ammo()[0] > -10) { - s += "\n ammo: ("; - - for (int i = 0; i < 16; i++) { - sprintf_s(buffer, "%d", ship->Ammo()[i]); - s += buffer; - - if (i < 15) - s += ", "; - } - - s += ")\n"; - } - - if (ship->Fuel()[0] > -10) { - s += "\n fuel: ("; - - for (int i = 0; i < 4; i++) { - sprintf_s(buffer, "%d", ship->Fuel()[i]); - s += buffer; - - if (i < 3) - s += ", "; - } - - s += ")\n"; - } - - s += " }\n"; - } - } - - s += "}\n\n"; - } - - ListIter iter2 = GetEvents(); - while (++iter2) { - MissionEvent* event = iter2.value(); - - s += "event: {\n"; - - s += " id: "; - sprintf_s(buffer, "%d", event->EventID()); - s += buffer; - s += ",\n time: "; - sprintf_s(buffer, "%.1f", event->Time()); - s += buffer; - s += ",\n delay: "; - sprintf_s(buffer, "%.1f", event->Delay()); - s += buffer; - s += ",\n event: "; - s += event->EventName(); - s += "\n"; - - if (event->EventShip().length()) { - s += " event_ship: \""; - s += SafeString(event->EventShip()); - s += "\"\n"; - } - - if (event->EventSource().length()) { - s += " event_source: \""; - s += SafeString(event->EventSource()); - s += "\"\n"; - } - - if (event->EventTarget().length()) { - s += " event_target: \""; - s += SafeString(event->EventTarget()); - s += "\"\n"; - } - - if (event->EventSound().length()) { - s += " event_sound: \""; - s += SafeString(event->EventSound()); - s += "\"\n"; - } - - if (event->EventMessage().length()) { - s += " event_message: \""; - s += SafeString(event->EventMessage()); - s += "\"\n"; - } - - if (event->EventParam()) { - sprintf_s(buffer, "%d", event->EventParam()); - s += " event_param: "; - s += buffer; - s += "\n"; - } - - if (event->EventChance()) { - sprintf_s(buffer, "%d", event->EventChance()); - s += " event_chance: "; - s += buffer; - s += "\n"; - } - - s += " trigger: \""; - s += event->TriggerName(); - s += "\"\n"; - - if (event->TriggerShip().length()) { - s += " trigger_ship: \""; - s += SafeString(event->TriggerShip()); - s += "\"\n"; - } - - if (event->TriggerTarget().length()) { - s += " trigger_target: \""; - s += SafeString(event->TriggerTarget()); - s += "\"\n"; - } - - Text param_str = event->TriggerParamStr(); - - if (param_str.length()) { - s += " trigger_param: "; - s += param_str; - s += "\n"; - } - - s += "}\n\n"; - } - - s += "// EOF\n"; - - return s; -} - -// +====================================================================+ - -static int elem_idkey = 1; - -MissionElement::MissionElement() -: id (elem_idkey++), -elem_id(0), design(0), skin(0), count(1), maint_count(0), dead_count(0), -IFF_code(0), player(0), alert(false), playable(false), rogue(false), invulnerable(false), -respawns(0), hold_time(0), zone_lock(0), heading(0), mission_role(Mission::OTHER), -intel(Intel::SECRET), command_ai(1), combat_group(0), combat_unit(0) -{ -} - -MissionElement::~MissionElement() -{ - ships.destroy(); - objectives.destroy(); - instructions.destroy(); - navlist.destroy(); - loadouts.destroy(); -} - -Text -MissionElement::Abbreviation() const -{ - if (design) - return design->abrv; - - return "UNK"; -} - -Text -MissionElement::GetShipName(int index) const -{ - if (index < 0 || index >= ships.size()) { - if (count > 1) { - char sname[256]; - sprintf_s(sname, "%s %d", (const char*) name, index+1); - return sname; - } - else { - return name; - } - } - - return ships.at(index)->Name(); -} - -Text -MissionElement::GetRegistry(int index) const -{ - if (index < 0 || index >= ships.size()) { - return Text(); - } - - return ships.at(index)->RegNum(); -} - -Text -MissionElement::RoleName() const -{ - return Mission::RoleName(mission_role); -} - -Color -MissionElement::MarkerColor() const -{ - return Ship::IFFColor(IFF_code); -} - -bool -MissionElement::IsStatic() const -{ - int design_type = 0; - if (GetDesign()) - design_type = GetDesign()->type; - - return design_type >= Ship::STATION; -} - -bool -MissionElement::IsGroundUnit() const -{ - int design_type = 0; - if (GetDesign()) - design_type = GetDesign()->type; - - return (design_type & Ship::GROUND_UNITS) ? true : false; -} - -bool -MissionElement::IsStarship() const -{ - int design_type = 0; - if (GetDesign()) - design_type = GetDesign()->type; - - return (design_type & Ship::STARSHIPS) ? true : false; -} - -bool -MissionElement::IsDropship() const -{ - int design_type = 0; - if (GetDesign()) - design_type = GetDesign()->type; - - return (design_type & Ship::DROPSHIPS) ? true : false; -} - -bool -MissionElement::IsCarrier() const -{ - const ShipDesign* design = GetDesign(); - if (design && design->flight_decks.size() > 0) - return true; - - return false; -} - -bool -MissionElement::IsSquadron() const -{ - if (carrier.length() > 0) - return true; - - return false; -} - -// +--------------------------------------------------------------------+ - -Point -MissionElement::Location() const -{ - MissionElement* pThis = (MissionElement*) this; - return pThis->rloc.Location(); -} - -void -MissionElement::SetLocation(const Point& l) -{ - rloc.SetBaseLocation(l); - rloc.SetReferenceLoc(0); - rloc.SetDistance(0); -} - -void -MissionElement::SetRLoc(const RLoc& r) -{ - rloc = r; -} - -// +----------------------------------------------------------------------+ - -void -MissionElement::AddNavPoint(Instruction* pt, Instruction* afterPoint) -{ - if (pt && !navlist.contains(pt)) { - if (afterPoint) { - int index = navlist.index(afterPoint); - - if (index > -1) - navlist.insert(pt, index+1); - else - navlist.append(pt); - } - - else { - navlist.append(pt); - } - } -} - -void -MissionElement::DelNavPoint(Instruction* pt) -{ - if (pt) - delete navlist.remove(pt); -} - -void -MissionElement::ClearFlightPlan() -{ - navlist.destroy(); -} - -// +----------------------------------------------------------------------+ - -int -MissionElement::GetNavIndex(const Instruction* n) -{ - int index = 0; - - if (navlist.size() > 0) { - ListIter navpt = navlist; - while (++navpt) { - index++; - if (navpt.value() == n) - return index; - } - } - - return 0; -} - -// +====================================================================+ - -MissionLoad::MissionLoad(int s, const char* n) -: ship(s) -{ - for (int i = 0; i < 16; i++) - load[i] = -1; // default: no weapon mounted - - if (n) - name = n; -} - -MissionLoad::~MissionLoad() -{ -} - -// +--------------------------------------------------------------------+ - -int -MissionLoad::GetShip() const -{ - return ship; -} - -void -MissionLoad::SetShip(int s) -{ - ship = s; -} - -Text -MissionLoad::GetName() const -{ - return name; -} - -void -MissionLoad::SetName(Text n) -{ - name = n; -} - -int* -MissionLoad::GetStations() -{ - return load; -} - -int -MissionLoad::GetStation(int index) -{ - if (index >= 0 && index < 16) - return load[index]; - - return 0; -} - -void -MissionLoad::SetStation(int index, int selection) -{ - if (index >= 0 && index < 16) - load[index] = selection; -} - - -// +====================================================================+ - -MissionShip::MissionShip() -: loc(-1e9, -1e9, -1e9), respawns(0), heading(0), integrity(100), -decoys(-10), probes(-10), skin(0) -{ - for (int i = 0; i < 16; i++) - ammo[i] = -10; - - for (int i = 0; i < 4; i++) - fuel[i] = -10; -} - -void -MissionShip::SetAmmo(const int* a) -{ - if (a) { - for (int i = 0; i < 16; i++) - ammo[i] = a[i]; - } -} - -void -MissionShip::SetFuel(const int* f) -{ - if (f) { - for (int i = 0; i < 4; i++) - fuel[i] = f[i]; - } -} +/* Starshatter OpenSource Distribution + Copyright (c) 1997-2004, Destroyer Studios LLC. + All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name "Destroyer Studios" nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + SUBSYSTEM: Stars.exe + FILE: Mission.cpp + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Mission classes +*/ + +#include "MemDebug.h" +#include "Mission.h" +#include "MissionEvent.h" +#include "StarSystem.h" +#include "Galaxy.h" +#include "Starshatter.h" +#include "Ship.h" +#include "ShipDesign.h" +#include "Element.h" +#include "Instruction.h" +#include "WeaponDesign.h" +#include "Sim.h" + +#include "Game.h" +#include "DataLoader.h" +#include "ParseUtil.h" +#include "FormatUtil.h" +#include "Random.h" +#include "Skin.h" + +// +--------------------------------------------------------------------+ + +Mission::Mission(int identity, const char* fname, const char* pname) +: id(identity), type(0), team(1), ok(false), active(false), complete(false), +star_system(0), start(33 * 3600), stardate(0), target(0), ward(0), +current(0), degrees(false) +{ + objective = Game::GetText("Mission.unspecified"); + sitrep = Game::GetText("Mission.unknown"); + + if (fname) + strcpy_s(filename, fname); + else + ZeroMemory(filename, sizeof(filename)); + + if (pname) + strcpy_s(path, pname); + else + strcpy_s(path, "Missions/"); +} + +Mission::~Mission() +{ + ::Print("Mission::~Mission() id = %d name = '%s'\n", id, name.data()); + elements.destroy(); + events.destroy(); +} + +// +--------------------------------------------------------------------+ + +const char* +Mission::Subtitles() const +{ + return subtitles; +} + +// +--------------------------------------------------------------------+ + +void +Mission::AddElement(MissionElement* elem) +{ + if (elem) + elements.append(elem); +} + +// +--------------------------------------------------------------------+ + +MissionElement* +Mission::FindElement(const char* name) +{ + ListIter iter = elements; + while (++iter) { + MissionElement* elem = iter.value(); + + if (elem->Name() == name) + return elem; + } + + return 0; +} + +// +--------------------------------------------------------------------+ + +void +Mission::IncreaseElemPriority(int elem_index) +{ + if (elem_index > 0 && elem_index < elements.size()) { + MissionElement* elem1 = elements.at(elem_index-1); + MissionElement* elem2 = elements.at(elem_index); + + elements.at(elem_index-1) = elem2; + elements.at(elem_index) = elem1; + } +} + +void +Mission::DecreaseElemPriority(int elem_index) +{ + if (elem_index >= 0 && elem_index < elements.size()-1) { + MissionElement* elem1 = elements.at(elem_index); + MissionElement* elem2 = elements.at(elem_index+1); + + elements.at(elem_index) = elem2; + elements.at(elem_index+1) = elem1; + } +} + +// +--------------------------------------------------------------------+ + +void +Mission::IncreaseEventPriority(int event_index) +{ + if (event_index > 0 && event_index < events.size()) { + MissionEvent* event1 = events.at(event_index-1); + MissionEvent* event2 = events.at(event_index); + + events.at(event_index-1) = event2; + events.at(event_index) = event1; + } +} + +void +Mission::DecreaseEventPriority(int event_index) +{ + if (event_index >= 0 && event_index < events.size()-1) { + MissionEvent* event1 = events.at(event_index); + MissionEvent* event2 = events.at(event_index+1); + + events.at(event_index) = event2; + events.at(event_index+1) = event1; + } +} + +// +--------------------------------------------------------------------+ + +void +Mission::SetStarSystem(StarSystem* s) +{ + if (star_system != s) { + star_system = s; + + if (!system_list.contains(s)) + system_list.append(s); + } +} + +void +Mission::ClearSystemList() +{ + star_system = 0; + system_list.clear(); +} + +// +--------------------------------------------------------------------+ + +void +Mission::SetPlayer(MissionElement* player_element) +{ + ListIter elem = elements; + while (++elem) { + MissionElement* element = elem.value(); + if (element == player_element) + element->player = 1; + else + element->player = 0; + } +} + +MissionElement* +Mission::GetPlayer() +{ + MissionElement* p = 0; + + ListIter elem = elements; + while (++elem) { + if (elem->player > 0) + p = elem.value(); + } + + return p; +} + +// +--------------------------------------------------------------------+ + +MissionEvent* +Mission::FindEvent(int event_type) const +{ + Mission* pThis = (Mission*) this; + ListIter iter = pThis->events; + while (++iter) { + MissionEvent* event = iter.value(); + + if (event->Event() == event_type) + return event; + } + + return 0; +} + +void +Mission::AddEvent(MissionEvent* event) +{ + if (event) + events.append(event); +} + +// +--------------------------------------------------------------------+ + +bool +Mission::Load(const char* fname, const char* pname) +{ + ok = false; + + if (fname) + strcpy_s(filename, fname); + + if (pname) + strcpy_s(path, pname); + + if (!filename[0]) { + Print("\nCan't Load Mission, script unspecified.\n"); + return ok; + } + + // wipe existing mission before attempting to load... + elements.destroy(); + events.destroy(); + + Print("\nLoad Mission: '%s'\n", filename); + + DataLoader* loader = DataLoader::GetLoader(); + bool old_fs = loader->IsFileSystemEnabled(); + BYTE* block = 0; + + loader->UseFileSystem(true); + loader->SetDataPath(path); + loader->LoadBuffer(filename, block, true); + loader->SetDataPath(0); + loader->UseFileSystem(old_fs); + + ok = ParseMission((const char*) block); + + loader->ReleaseBuffer(block); + Print("Mission Loaded.\n\n"); + + if (ok) + Validate(); + + return ok; +} + +// +--------------------------------------------------------------------+ + +bool +Mission::ParseMission(const char* block) +{ + Parser parser(new(__FILE__,__LINE__) BlockReader(block)); + Term* term = parser.ParseTerm(); + char err[256]; + + if (!term) { + sprintf_s(err, "ERROR: could not parse '%s'\n", filename); + AddError(err); + return ok; + } + else { + TermText* file_type = term->isText(); + if (!file_type || file_type->value() != "MISSION") { + sprintf_s(err, "ERROR: invalid mission file '%s'\n", filename); + AddError(err); + term->print(10); + return ok; + } + } + + ok = true; + + char target_name[256]; + char ward_name[256]; + + target_name[0] = 0; + ward_name[0] = 0; + + do { + delete term; term = 0; + term = parser.ParseTerm(); + + if (term) { + TermDef* def = term->isDef(); + if (def) { + Text defname = def->name()->value(); + defname.setSensitive(false); + + if (defname == "name") { + GetDefText(name, def, filename); + name = Game::GetText(name); + } + + else if (defname == "desc") { + GetDefText(desc, def, filename); + if (desc.length() > 0 && desc.length() < 32) + desc = Game::GetText(desc); + } + + else if (defname == "type") { + char typestr[64]; + GetDefText(typestr, def, filename); + type = TypeFromName(typestr); + } + + else if (defname == "system") { + char sysname[64]; + GetDefText(sysname, def, filename); + + Galaxy* galaxy = Galaxy::GetInstance(); + + if (galaxy) { + SetStarSystem(galaxy->GetSystem(sysname)); + } + } + + else if (defname == "degrees") + GetDefBool(degrees, def, filename); + + else if (defname == "region") + GetDefText(region, def, filename); + + else if (defname == "objective") { + GetDefText(objective, def, filename); + if (objective.length() > 0 && objective.length() < 32) + objective = Game::GetText(objective); + } + + else if (defname == "sitrep") { + GetDefText(sitrep, def, filename); + if (sitrep.length() > 0 && sitrep.length() < 32) + sitrep = Game::GetText(sitrep); + } + + else if (defname == "subtitles") { + Text subtitles_path; + DataLoader* loader = DataLoader::GetLoader(); + BYTE* block = 0; + + GetDefText(subtitles_path, def, filename); + loader->SetDataPath(0); + loader->LoadBuffer(subtitles_path, block, true); + + subtitles = Text("\n") + (const char*) block; + + loader->ReleaseBuffer(block); + } + + else if (defname == "start") + GetDefTime(start, def, filename); + + else if (defname == "stardate") + GetDefNumber(stardate, def, filename); + + else if (defname == "team") + GetDefNumber(team, def, filename); + + else if (defname == "target") + GetDefText(target_name, def, filename); + + else if (defname == "ward") + GetDefText(ward_name, def, filename); + + else if ((defname == "element") || + (defname == "ship") || + (defname == "station")) { + + if (!def->term() || !def->term()->isStruct()) { + sprintf_s(err, "ERROR: element struct missing in '%s'\n", filename); + AddError(err); + } + else { + TermStruct* val = def->term()->isStruct(); + MissionElement* elem = ParseElement(val); + AddElement(elem); + } + } + + else if (defname == "event") { + if (!def->term() || !def->term()->isStruct()) { + sprintf_s(err, "ERROR: event struct missing in '%s'\n", filename); + AddError(err); + } + else { + TermStruct* val = def->term()->isStruct(); + MissionEvent* event = ParseEvent(val); + AddEvent(event); + } + } + } // def + } // term + } + while (term); + + if (ok) { + if (target_name[0]) + target = FindElement(target_name); + + if (ward_name[0]) + ward = FindElement(ward_name); + } + + return ok; +} + +// +--------------------------------------------------------------------+ + +bool +Mission::Save() +{ + Validate(); + + if (!filename[0] || !path[0]) { + AddError(Game::GetText("Mission.error.no-file")); + return ok; + } + + Text content = Serialize(); + + if (content.length() < 8) { + AddError(Game::GetText("Mission.error.no-serial")); + return ok; + } + + if (!_stricmp(path, "mods/missions/")) { + CreateDirectory("Mods", 0); + CreateDirectory("Mods/Missions", 0); + } + + else if (!_stricmp(path, "multiplayer/")) { + CreateDirectory("Multiplayer", 0); + } + + char fname[256]; + sprintf_s(fname, "%s%s", path, filename); + FILE* f; + fopen_s(&f, fname, "w"); + if (f) { + fwrite(content.data(), content.length(), 1, f); + fclose(f); + } + + return ok; +} + +// +--------------------------------------------------------------------+ + +void +Mission::Validate() +{ + char err[256]; + + ok = true; + + if (elements.isEmpty()) { + sprintf_s(err, Game::GetText("Mission.error.no-elem").data(), filename); + AddError(err); + } + else { + bool found_player = false; + + for (int i = 0; i < elements.size(); i++) { + MissionElement* elem = elements.at(i); + + if (elem->Name().length() < 1) { + sprintf_s(err, Game::GetText("Mission.error.unnamed-elem").data(), filename); + AddError(err); + } + + if (elem->Player() > 0) { + if (!found_player) { + found_player = true; + + if (elem->Region() != GetRegion()) { + sprintf_s(err, Game::GetText("Mission.error.wrong-sector").data(), + elem->Name().data(), + GetRegion()); + AddError(err); + } + } + else { + sprintf_s(err, Game::GetText("Mission.error.extra-player").data(), + elem->Name().data(), + filename); + AddError(err); + } + } + } + + if (!found_player) { + sprintf_s(err, Game::GetText("Mission.error.no-player").data(), filename); + AddError(err); + } + } +} + +void +Mission::AddError(Text err) +{ + ::Print(err); + errmsg += err; + + ok = false; +} + +// +--------------------------------------------------------------------+ + +#define MSN_CHECK(x) if (!_stricmp(n, #x)) result = Mission::x; + +int +Mission::TypeFromName(const char* n) +{ + int result = -1; + + MSN_CHECK(PATROL) + else MSN_CHECK(SWEEP) + else MSN_CHECK(INTERCEPT) + else MSN_CHECK(AIR_PATROL) + else MSN_CHECK(AIR_SWEEP) + else MSN_CHECK(AIR_INTERCEPT) + else MSN_CHECK(STRIKE) + else MSN_CHECK(ASSAULT) + else MSN_CHECK(DEFEND) + else MSN_CHECK(ESCORT) + else MSN_CHECK(ESCORT_FREIGHT) + else MSN_CHECK(ESCORT_SHUTTLE) + else MSN_CHECK(ESCORT_STRIKE) + else MSN_CHECK(INTEL) + else MSN_CHECK(SCOUT) + else MSN_CHECK(RECON) + else MSN_CHECK(BLOCKADE) + else MSN_CHECK(FLEET) + else MSN_CHECK(BOMBARDMENT) + else MSN_CHECK(FLIGHT_OPS) + else MSN_CHECK(TRANSPORT) + else MSN_CHECK(CARGO) + else MSN_CHECK(TRAINING) + else MSN_CHECK(OTHER) + + if (result < PATROL) { + for (int i = PATROL; i <= OTHER && result < PATROL; i++) { + if (!_stricmp(n, RoleName(i))) { + result = i; + } + } + } + + return result; +} + +// +--------------------------------------------------------------------+ + +static int elem_id = 351; + +MissionElement* +Mission::ParseElement(TermStruct* val) +{ + Text design; + Text skin_name; + Text role_name; + int deck = 1; + char err[256]; + + MissionElement* element = new(__FILE__,__LINE__) MissionElement(); + element->rgn_name = region; + element->elem_id = elem_id++; + + current = element; + + for (int i = 0; i < val->elements()->size(); i++) { + TermDef* pdef = val->elements()->at(i)->isDef(); + if (pdef) { + Text defname = pdef->name()->value(); + defname.setSensitive(false); + + if (defname == "name") + GetDefText(element->name, pdef, filename); + + else if (defname == "carrier") + GetDefText(element->carrier, pdef, filename); + + else if (defname == "commander") + GetDefText(element->commander, pdef, filename); + + else if (defname == "squadron") + GetDefText(element->squadron, pdef, filename); + + else if (defname == "path") + GetDefText(element->path, pdef, filename); + + else if (defname == "design") { + GetDefText(design, pdef, filename); + element->design = ShipDesign::Get(design, element->path); + + if (!element->design) { + sprintf_s(err, Game::GetText("Mission.error.unknown-ship").data(), design.data(), filename); + AddError(err); + } + } + + else if (defname == "skin") { + if (!element->design) { + sprintf_s(err, Game::GetText("Mission.error.out-of-order").data(), filename); + AddError(err); + } + + else if (pdef->term()->isText()) { + GetDefText(skin_name, pdef, filename); + element->skin = element->design->FindSkin(skin_name); + } + + else if (pdef->term()->isStruct()) { + sprintf_s(err, Game::GetText("Mission.error.bad-skin").data(), filename); + AddError(err); + } + } + + else if (defname == "mission") { + GetDefText(role_name, pdef, filename); + element->mission_role = TypeFromName(role_name); + } + + else if (defname == "intel") { + GetDefText(role_name, pdef, filename); + element->intel = Intel::IntelFromName(role_name); + } + + else if (defname == "loc") { + Vec3 loc; + GetDefVec(loc, pdef, filename); + element->SetLocation(loc); + } + + else if (defname == "rloc") { + if (pdef->term()->isStruct()) { + RLoc* rloc = ParseRLoc(pdef->term()->isStruct()); + element->SetRLoc(*rloc); + delete rloc; + } + } + + else if (defname.indexOf("head") == 0) { + if (pdef->term()->isArray()) { + Vec3 head; + GetDefVec(head, pdef, filename); + if (degrees) head.z *= (float) DEGREES; + element->heading = head.z; + } + else if (pdef->term()->isNumber()) { + double heading = 0; + GetDefNumber(heading, pdef, filename); + if (degrees) heading *= DEGREES; + element->heading = heading; + } + } + + else if (defname == "region" || defname == "rgn") + GetDefText(element->rgn_name, pdef, filename); + + else if (defname == "iff") + GetDefNumber(element->IFF_code, pdef, filename); + + else if (defname == "count") + GetDefNumber(element->count, pdef, filename); + + else if (defname == "maint_count") + GetDefNumber(element->maint_count, pdef, filename); + + else if (defname == "dead_count") + GetDefNumber(element->dead_count, pdef, filename); + + else if (defname == "player") + GetDefNumber(element->player, pdef, filename); + + else if (defname == "alert") + GetDefBool(element->alert, pdef, filename); + + else if (defname == "playable") + GetDefBool(element->playable, pdef, filename); + + else if (defname == "rogue") + GetDefBool(element->rogue, pdef, filename); + + else if (defname == "invulnerable") + GetDefBool(element->invulnerable, pdef, filename); + + else if (defname == "command_ai") + GetDefNumber(element->command_ai, pdef, filename); + + else if (defname.indexOf("respawn") == 0) + GetDefNumber(element->respawns, pdef, filename); + + else if (defname.indexOf("hold") == 0) + GetDefNumber(element->hold_time, pdef, filename); + + else if (defname.indexOf("zone") == 0) { + if (pdef->term() && pdef->term()->isBool()) { + bool locked = false; + GetDefBool(locked, pdef, filename); + element->zone_lock = locked; + } + else { + GetDefNumber(element->zone_lock, pdef, filename); + } + } + + else if (defname == "objective") { + if (!pdef->term() || !pdef->term()->isStruct()) { + sprintf_s(err, Game::GetText("Mission.error.no-objective").data(), element->name.data(), filename); + AddError(err); + } + else { + TermStruct* val = pdef->term()->isStruct(); + Instruction* obj = ParseInstruction(val, element); + element->objectives.append(obj); + } + } + + else if (defname == "instr") { + Text* obj = new(__FILE__,__LINE__) Text; + if (GetDefText(*obj, pdef, filename)) + element->instructions.append(obj); + else + delete obj; + } + + else if (defname == "ship") { + if (!pdef->term() || !pdef->term()->isStruct()) { + sprintf_s(err, Game::GetText("Mission.error.no-ship").data(), element->name.data(), filename); + AddError(err); + } + else { + TermStruct* val = pdef->term()->isStruct(); + MissionShip* s = ParseShip(val, element); + element->ships.append(s); + + if (s->Integrity() < 0 && element->design) + s->SetIntegrity(element->design->integrity); + } + } + + else if (defname == "order" || defname == "navpt") { + if (!pdef->term() || !pdef->term()->isStruct()) { + sprintf_s(err, Game::GetText("Mission.error.no-navpt").data(), element->name.data(), filename); + AddError(err); + } + else { + TermStruct* val = pdef->term()->isStruct(); + Instruction* npt = ParseInstruction(val, element); + element->navlist.append(npt); + } + } + + else if (defname == "loadout") { + if (!pdef->term() || !pdef->term()->isStruct()) { + sprintf_s(err, Game::GetText("Mission.error.no-loadout").data(), element->name.data(), filename); + AddError(err); + } + else { + TermStruct* val = pdef->term()->isStruct(); + ParseLoadout(val, element); + } + } + } + } + + if (element->name.length() < 1) { + sprintf_s(err, Game::GetText("Mission.error.unnamed-elem").data(), filename); + AddError(err); + } + + else if (element->design == 0) { + sprintf_s(err, Game::GetText("Mission.error.unknown-ship").data(), element->name.data(), filename); + AddError(err); + } + + current = 0; + + return element; +} + +MissionEvent* +Mission::ParseEvent(TermStruct* val) +{ + MissionEvent* event = new(__FILE__,__LINE__) MissionEvent; + Text event_name; + Text trigger_name; + static int event_id = 1; + static double event_time = 0; + + for (int i = 0; i < val->elements()->size(); i++) { + TermDef* pdef = val->elements()->at(i)->isDef(); + if (pdef) { + Text defname = pdef->name()->value(); + defname.setSensitive(false); + + if (defname == "event") { + GetDefText(event_name, pdef, filename); + event->event = MissionEvent::EventForName(event_name); + } + + else if (defname == "trigger") { + GetDefText(trigger_name, pdef, filename); + event->trigger = MissionEvent::TriggerForName(trigger_name); + } + + else if (defname == "id") + GetDefNumber(event_id, pdef, filename); + + else if (defname == "time") + GetDefNumber(event_time, pdef, filename); + + else if (defname == "delay") + GetDefNumber(event->delay, pdef, filename); + + else if (defname == "event_param" || defname == "param" || defname == "color") { + ZeroMemory(event->event_param, sizeof(event->event_param)); + + if (pdef->term()->isNumber()) { + GetDefNumber(event->event_param[0], pdef, filename); + event->event_nparams = 1; + } + + else if (pdef->term()->isArray()) { + std::vector plist; + GetDefArray(plist, pdef, filename); + + for (int i = 0; i < 10 && i < (int)plist.size(); i++) { + float f = plist[i]; + event->event_param[i] = (int) f; + event->event_nparams = i + 1; + } + } + } + + else if (defname == "trigger_param") { + ZeroMemory(event->trigger_param, sizeof(event->trigger_param)); + + if (pdef->term()->isNumber()) { + GetDefNumber(event->trigger_param[0], pdef, filename); + event->trigger_nparams = 1; + } + + else if (pdef->term()->isArray()) { + std::vector plist; + GetDefArray(plist, pdef, filename); + + for (int i = 0; i < 10 && i < (int)plist.size(); i++) { + float f = plist[i]; + event->trigger_param[i] = (int) f; + event->trigger_nparams = i + 1; + } + } + } + + else if (defname == "event_ship" || defname == "ship") + GetDefText(event->event_ship, pdef, filename); + + else if (defname == "event_source" || defname == "source" || defname == "font") + GetDefText(event->event_source, pdef, filename); + + else if (defname == "event_target" || defname == "target" || defname == "image") + GetDefText(event->event_target, pdef, filename); + + else if (defname == "event_message" || defname == "message") { + Text raw_msg; + GetDefText(raw_msg, pdef, filename); + raw_msg = Game::GetText(raw_msg); + event->event_message = FormatTextEscape(raw_msg); + } + + else if (defname == "event_chance" || defname == "chance") + GetDefNumber(event->event_chance, pdef, filename); + + else if (defname == "event_sound" || defname == "sound") + GetDefText(event->event_sound, pdef, filename); + + else if (defname == "loc" || defname == "vec" || defname == "fade") + GetDefVec(event->event_point, pdef, filename); + + else if (defname == "rect") + GetDefRect(event->event_rect, pdef, filename); + + else if (defname == "trigger_ship") + GetDefText(event->trigger_ship, pdef, filename); + + else if (defname == "trigger_target") + GetDefText(event->trigger_target, pdef, filename); + } + } + + event->id = event_id++; + event->time = event_time; + return event; +} + +MissionShip* +Mission::ParseShip(TermStruct* val, MissionElement* element) +{ + MissionShip* msn_ship = new(__FILE__,__LINE__) MissionShip; + + Text name; + Text skin_name; + Text regnum; + Text region; + char err[256]; + Vec3 loc(-1.0e9f, -1.0e9f, -1.0e9f); + Vec3 vel(-1.0e9f, -1.0e9f, -1.0e9f); + int respawns = -1; + double heading = -1e9; + double integrity = -1; + int ammo[16]; + int fuel[4]; + int i; + + for (i = 0; i < 16; i++) + ammo[i] = -10; + + for (i = 0; i < 4; i++) + fuel[i] = -10; + + for (i = 0; i < val->elements()->size(); i++) { + TermDef* pdef = val->elements()->at(i)->isDef(); + if (pdef) { + Text defname = pdef->name()->value(); + defname.setSensitive(false); + + if (defname == "name") + GetDefText(name, pdef, filename); + + else if (defname == "skin") { + if (!element || !element->design) { + sprintf_s(err, Game::GetText("Mission.error.out-of-order").data(), filename); + AddError(err); + } + + else if (pdef->term()->isText()) { + GetDefText(skin_name, pdef, filename); + msn_ship->skin = element->design->FindSkin(skin_name); + } + + else if (pdef->term()->isStruct()) { + sprintf_s(err, Game::GetText("Mission.error.bad-skin").data(), filename); + AddError(err); + } + } + + else if (defname == "regnum") + GetDefText(regnum, pdef, filename); + + else if (defname == "region") + GetDefText(region, pdef, filename); + + else if (defname == "loc") + GetDefVec(loc, pdef, filename); + + else if (defname == "velocity") + GetDefVec(vel, pdef, filename); + + else if (defname == "respawns") + GetDefNumber(respawns, pdef, filename); + + else if (defname == "heading") { + if (pdef->term()->isArray()) { + Vec3 h; + GetDefVec(h, pdef, filename); + if (degrees) h.z *= (float) DEGREES; + heading = h.z; + } + else if (pdef->term()->isNumber()) { + double h = 0; + GetDefNumber(h, pdef, filename); + if (degrees) h *= DEGREES; + heading = h; + } + } + + else if (defname == "integrity") + GetDefNumber(integrity, pdef, filename); + + else if (defname == "ammo") + GetDefArray(ammo, 16, pdef, filename); + + else if (defname == "fuel") + GetDefArray(fuel, 4, pdef, filename); + } + } + + msn_ship->SetName(name); + msn_ship->SetRegNum(regnum); + msn_ship->SetRegion(region); + msn_ship->SetIntegrity(integrity); + + if (loc.x > -1e9) + msn_ship->SetLocation(loc); + + if (vel.x > -1e9) + msn_ship->SetVelocity(vel); + + if (respawns > -1) + msn_ship->SetRespawns(respawns); + + if (heading > -1e9) + msn_ship->SetHeading(heading); + + if (ammo[0] > -10) + msn_ship->SetAmmo(ammo); + + if (fuel[0] > -10) + msn_ship->SetFuel(fuel); + + return msn_ship; +} + +Instruction* +Mission::ParseInstruction(TermStruct* val, MissionElement* element) +{ + int order = Instruction::VECTOR; + int status = Instruction::PENDING; + int formation = 0; + int speed = 0; + int priority = 1; + int farcast = 0; + int hold = 0; + int emcon = 0; + Vec3 loc(0,0,0); + RLoc* rloc = 0; + Text order_name; + Text status_name; + Text order_rgn_name; + Text tgt_name; + Text tgt_desc; + + for (int i = 0; i < val->elements()->size(); i++) { + TermDef* pdef = val->elements()->at(i)->isDef(); + if (pdef) { + Text defname = pdef->name()->value(); + defname.setSensitive(false); + + if (defname == "cmd") { + GetDefText(order_name, pdef, filename); + + for (int cmd = 0; cmd < Instruction::NUM_ACTIONS; cmd++) + if (!_stricmp(order_name, Instruction::ActionName(cmd))) + order = cmd; + } + + else if (defname == "status") { + GetDefText(status_name, pdef, filename); + + for (int n = 0; n < Instruction::NUM_STATUS; n++) + if (!_stricmp(status_name, Instruction::StatusName(n))) + status = n; + } + + else if (defname == "loc") { + GetDefVec(loc, pdef, filename); + } + + else if (defname == "rloc") { + if (pdef->term()->isStruct()) + rloc = ParseRLoc(pdef->term()->isStruct()); + } + + else if (defname == "rgn") { + GetDefText(order_rgn_name, pdef, filename); + } + else if (defname == "speed") { + GetDefNumber(speed, pdef, filename); + } + else if (defname == "formation") { + GetDefNumber(formation, pdef, filename); + } + else if (defname == "emcon") { + GetDefNumber(emcon, pdef, filename); + } + else if (defname == "priority") { + GetDefNumber(priority, pdef, filename); + } + else if (defname == "farcast") { + if (pdef->term()->isBool()) { + bool f = false; + GetDefBool(f, pdef, filename); + farcast = f; + } + else { + GetDefNumber(farcast, pdef, filename); + } + } + else if (defname == "tgt") { + GetDefText(tgt_name, pdef, filename); + } + else if (defname == "tgt_desc") { + GetDefText(tgt_desc, pdef, filename); + } + else if (defname.indexOf("hold") == 0) { + GetDefNumber(hold, pdef, filename); + } + } + } + + Text rgn; + + if (order_rgn_name.length() > 0) + rgn = order_rgn_name; + + else if (element->navlist.size() > 0) + rgn = element->navlist[element->navlist.size()-1]->RegionName(); + + else + rgn = region; + + if (tgt_desc.length() && tgt_name.length()) + tgt_desc = tgt_desc + " " + tgt_name; + + Instruction* instr = new(__FILE__,__LINE__) Instruction(rgn, loc, order); + + instr->SetStatus(status); + instr->SetEMCON(emcon); + instr->SetFormation(formation); + instr->SetSpeed(speed); + instr->SetTarget(tgt_name); + instr->SetTargetDesc(tgt_desc); + instr->SetPriority(priority-1); + instr->SetFarcast(farcast); + instr->SetHoldTime(hold); + + if (rloc) { + instr->GetRLoc() = *rloc; + delete rloc; + } + + return instr; +} + +void +Mission::ParseLoadout(TermStruct* val, MissionElement* element) +{ + int ship = -1; + int stations[16]; + Text name; + + ZeroMemory(stations, sizeof(stations)); + + for (int i = 0; i < val->elements()->size(); i++) { + TermDef* pdef = val->elements()->at(i)->isDef(); + if (pdef) { + Text defname = pdef->name()->value(); + defname.setSensitive(false); + + if (defname == "ship") { + GetDefNumber(ship, pdef, filename); + } + else if (defname == "name") { + GetDefText(name, pdef, filename); + } + else if (defname == "stations") { + GetDefArray(stations, 16, pdef, filename); + } + } + } + + MissionLoad* load = new(__FILE__,__LINE__) MissionLoad(ship); + + if (name.length()) + load->SetName(name); + + for (int i = 0; i < 16; i++) + load->SetStation(i, stations[i]); + + element->loadouts.append(load); +} + +RLoc* +Mission::ParseRLoc(TermStruct* val) +{ + Vec3 base_loc; + RLoc* rloc = new(__FILE__,__LINE__) RLoc; + RLoc* ref = 0; + + double dex = 0; + double dex_var = 5e3; + double az = 0; + double az_var = PI; + double el = 0; + double el_var = 0.1; + + for (int i = 0; i < val->elements()->size(); i++) { + TermDef* pdef = val->elements()->at(i)->isDef(); + if (pdef) { + Text defname = pdef->name()->value(); + defname.setSensitive(false); + + if (defname == "dex") { + GetDefNumber(dex, pdef, filename); + rloc->SetDistance(dex); + } + else if (defname == "dex_var") { + GetDefNumber(dex_var, pdef, filename); + rloc->SetDistanceVar(dex_var); + } + else if (defname == "az") { + GetDefNumber(az, pdef, filename); + if (degrees) az *= DEGREES; + rloc->SetAzimuth(az); + } + else if (defname == "az_var") { + GetDefNumber(az_var, pdef, filename); + if (degrees) az_var *= DEGREES; + rloc->SetAzimuthVar(az_var); + } + else if (defname == "el") { + GetDefNumber(el, pdef, filename); + if (degrees) el *= DEGREES; + rloc->SetElevation(el); + } + else if (defname == "el_var") { + GetDefNumber(el_var, pdef, filename); + if (degrees) el_var *= DEGREES; + rloc->SetElevationVar(el_var); + } + else if (defname == "loc") { + GetDefVec(base_loc, pdef, filename); + rloc->SetBaseLocation(base_loc); + } + + else if (defname == "ref") { + Text refstr; + GetDefText(refstr, pdef, filename); + + int sep = refstr.indexOf(':'); + + if (sep >= 0) { + Text elem_name = refstr.substring(0, sep); + Text nav_name = refstr.substring(sep+1, refstr.length()); + MissionElement* elem = 0; + + if (elem_name == "this") + elem = current; + else + elem = FindElement(elem_name); + + if (elem && elem->NavList().size() > 0) { + int index = atoi(nav_name)-1; + if (index < 0) + index = 0; + else if (index >= elem->NavList().size()) + index = elem->NavList().size()-1; + + ref = &elem->NavList()[index]->GetRLoc(); + rloc->SetReferenceLoc(ref); + } + else { + ::Print("Warning: no ref found for rloc '%s' in elem '%s'\n", refstr.data(), current->Name().data()); + rloc->SetBaseLocation(RandomPoint()); + } + } + else { + MissionElement* elem = 0; + + if (refstr == "this") + elem = current; + else + elem = FindElement(refstr); + + if (elem) { + ref = &elem->GetRLoc(); + rloc->SetReferenceLoc(ref); + } + else { + ::Print("Warning: no ref found for rloc '%s' in elem '%s'\n", refstr.data(), current->Name().data()); + rloc->SetBaseLocation(RandomPoint()); + } + } + } + } + } + + return rloc; +} + +const char* +Mission::RoleName(int role) +{ + switch (role) { + case PATROL: return "Patrol"; + case SWEEP: return "Sweep"; + case INTERCEPT: return "Intercept"; + case AIR_PATROL: return "Airborne Patrol"; + case AIR_SWEEP: return "Airborne Sweep"; + case AIR_INTERCEPT: return "Airborne Intercept"; + case STRIKE: return "Strike"; + case ASSAULT: return "Assault"; + case DEFEND: return "Defend"; + case ESCORT: return "Escort"; + case ESCORT_FREIGHT: return "Freight Escort"; + case ESCORT_SHUTTLE: return "Shuttle Escort"; + case ESCORT_STRIKE: return "Strike Escort"; + case INTEL: return "Intel"; + case SCOUT: return "Scout"; + case RECON: return "Recon"; + case BLOCKADE: return "Blockade"; + case FLEET: return "Fleet"; + case BOMBARDMENT: return "Attack"; + case FLIGHT_OPS: return "Flight Ops"; + case TRANSPORT: return "Transport"; + case CARGO: return "Cargo"; + case TRAINING: return "Training"; + default: + case OTHER: return "Misc"; + } +} + +// +--------------------------------------------------------------------+ + +Text +Mission::Serialize(const char* player_elem, int player_index) +{ + Text s = "MISSION\n\nname: \""; + s += SafeString(Name()); + + if (desc.length()) { + s += "\"\ndesc: \""; + s += SafeString(desc); + } + + s += "\"\ntype: \""; + s += SafeString(TypeName()); + + ListIter sys_iter = system_list; + while (++sys_iter) { + StarSystem* sys = sys_iter.value(); + + if (sys != star_system) { + s += "\"\nsystem: \""; + s += sys->Name(); + } + } + + s += "\"\nsystem: \""; + if (GetStarSystem()) + s += SafeString(GetStarSystem()->Name()); + else + s += "null"; + + ListIter iter = GetElements(); + + Sim* sim = Sim::GetSim(); + if (sim && sim->GetElements().size() > 0) + iter = sim->GetMissionElements(); + + s += "\"\n"; + + bool region_set = false; + if (player_elem && *player_elem) { + // set the mission region to that of the active player + while (++iter) { + MissionElement* e = iter.value(); + if (e->Name() == player_elem) { + char buf[32]; + sprintf_s(buf, "team: %d\n", e->GetIFF()); + s += buf; + + s += "region: \""; + s += SafeString(e->Region()); + s += "\"\n\n"; + + region_set = true; + break; + } + } + + iter.reset(); + } + + if (!region_set) { + s += "region: \""; + s += SafeString(GetRegion()); + s += "\"\n\n"; + } + + if (Objective() && *Objective()) { + s += "objective: \""; + s += SafeString(Objective()); + s += "\"\n\n"; + } + + if (Situation() && *Situation()) { + s += "sitrep: \""; + s += SafeString(Situation()); + s += "\"\n\n"; + } + + char buffer[256]; + FormatTime(buffer, Start()); + + s += "start: \""; + s += buffer; + s += "\"\n\n"; + s += "degrees: true\n\n"; + + while (++iter) { + MissionElement* elem = iter.value(); + + s += "element: {\n"; + s += " name: \""; + s += SafeString(elem->Name()); + s += "\"\n"; + + if (elem->Path().length()) { + s += " path: \""; + s += SafeString(elem->Path()); + s += "\"\n"; + } + + if (elem->GetDesign()) { + s += " design: \""; + s += SafeString(elem->GetDesign()->name); + s += "\"\n"; + } + + if (elem->GetSkin()) { + s += " skin: \""; + s += SafeString(elem->GetSkin()->Name()); + s += "\"\n"; + } + + if (elem->Squadron().length()) { + s += " squadron: \""; + s += SafeString(elem->Squadron()); + s += "\"\n"; + } + + if (elem->Carrier().length()) { + s += " carrier: \""; + s += SafeString(elem->Carrier()); + s += "\"\n"; + } + + if (elem->Commander().length()) { + s += " commander: \""; + s += SafeString(elem->Commander()); + s += "\"\n"; + } + + s += " mission: \""; + s += elem->RoleName(); + s += "\"\n\n"; + + if (elem->IntelLevel()) { + s += " intel: \""; + s += Intel::NameFromIntel(elem->IntelLevel()); + s += "\"\n"; + } + + sprintf_s(buffer, " count: %d\n", elem->Count()); + s += buffer; + + if (elem->MaintCount()) { + sprintf_s(buffer, " maint_count: %d\n", elem->MaintCount()); + s += buffer; + } + + if (elem->DeadCount()) { + sprintf_s(buffer, " dead_count: %d\n", elem->DeadCount()); + s += buffer; + } + + if (elem->RespawnCount()) { + sprintf_s(buffer, " respawn_count: %d\n", elem->RespawnCount()); + s += buffer; + } + + if (elem->HoldTime()) { + sprintf_s(buffer, " hold_time: %d\n", elem->HoldTime()); + s += buffer; + } + + if (elem->ZoneLock()) { + sprintf_s(buffer, " zone_lock: %d\n", elem->ZoneLock()); + s += buffer; + } + + if (elem->IsAlert()) { + s += " alert: true\n"; + } + + if (!elem->IsSquadron()) { + sprintf_s(buffer, " command_ai:%d\n", elem->CommandAI()); + s += buffer; + } + + sprintf_s(buffer, " iff: %d\n", elem->GetIFF()); + s += buffer; + + if (player_elem) { + if (elem->Name() == player_elem) { + if (player_index < 1) + player_index = 1; + + sprintf_s(buffer, " player: %d\n", player_index); + s += buffer; + } + } + + else { + if (elem->Player()) { + sprintf_s(buffer, " player: %d\n", elem->Player()); + s += buffer; + } + } + + if (!elem->IsSquadron()) { + if (elem->IsPlayable()) + s += " playable: true\n"; + else + s += " playable: false\n"; + } + + + s += " region: \""; + s += elem->Region(); + s += "\"\n"; + + sprintf_s(buffer, " loc: (%.0f, %.0f, %.0f)\n", + elem->Location().x, + elem->Location().y, + elem->Location().z); + s += buffer; + + if (elem->Heading() != 0) { + sprintf_s(buffer, " head: %d\n", (int) (elem->Heading()/DEGREES)); + s += buffer; + } + + if (elem->Loadouts().size()) { + s += "\n"; + + ListIter load_iter = elem->Loadouts(); + while (++load_iter) { + MissionLoad* load = load_iter.value(); + + sprintf_s(buffer, " loadout: { ship: %d, ", load->GetShip()); + s += buffer; + + if (load->GetName().length()) { + s += "name: \""; + s += SafeString(load->GetName()); + s += "\" }\n"; + } + else { + s += "stations: ("; + + for (int i = 0; i < 16; i++) { + sprintf_s(buffer, "%d", load->GetStation(i)); + s += buffer; + + if (i < 15) + s += ", "; + } + + s += ") }\n"; + } + } + } + + if (elem->Objectives().size()) { + s += "\n"; + + ListIter obj_iter = elem->Objectives(); + while (++obj_iter) { + Instruction* inst = obj_iter.value(); + + s += " objective: { cmd: "; + s += Instruction::ActionName(inst->Action()); + s += ", tgt: \""; + s += SafeString(inst->TargetName()); + s += "\" }\n"; + } + } + + if (elem->NavList().size()) { + s += "\n"; + + ListIter nav_iter = elem->NavList(); + while (++nav_iter) { + Instruction* inst = nav_iter.value(); + + s += " navpt: { cmd: "; + s += Instruction::ActionName(inst->Action()); + s += ", status: "; + s += Instruction::StatusName(inst->Status()); + + if (inst->TargetName() && *inst->TargetName()) { + s += ", tgt: \""; + s += SafeString(inst->TargetName()); + s += "\""; + } + + sprintf_s(buffer, ", loc: (%.0f, %.0f, %.0f), speed: %d", + inst->Location().x, + inst->Location().y, + inst->Location().z, + inst->Speed()); + s += buffer; + + if (inst->RegionName() && *inst->RegionName()) { + s += ", rgn: \""; + s += inst->RegionName(); + s += "\""; + } + + if (inst->HoldTime()) { + sprintf_s(buffer, ", hold: %d", (int) inst->HoldTime()); + s += buffer; + } + + if (inst->Farcast()) { + s += ", farcast: true"; + } + + if (inst->Formation() > Instruction::DIAMOND) { + sprintf_s(buffer, ", formation: %d", (int) inst->Formation()); + s += buffer; + } + + if (inst->Priority() > Instruction::PRIMARY) { + sprintf_s(buffer, ", priority: %d", (int) inst->Priority()); + s += buffer; + } + + s += " }\n"; + } + } + + if (elem->Instructions().size()) { + s += "\n"; + + ListIter i_iter = elem->Instructions(); + while (++i_iter) { + s += " instr: \""; + s += SafeString(*i_iter.value()); + s += "\"\n"; + } + } + + if (elem->Ships().size()) { + ListIter s_iter = elem->Ships(); + while (++s_iter) { + MissionShip* ship = s_iter.value(); + + s += "\n ship: {\n"; + + if (ship->Name().length()) { + s += " name: \""; + s += SafeString(ship->Name()); + s += "\"\n"; + } + + if (ship->RegNum().length()) { + s += " regnum: \""; + s += SafeString(ship->RegNum()); + s += "\"\n"; + } + + if (ship->Region().length()) { + s += " region: \""; + s += SafeString(ship->Region()); + s += "\"\n"; + } + + if (fabs(ship->Location().x) < 1e9) { + sprintf_s(buffer, " loc: (%.0f, %.0f, %.0f),\n", + ship->Location().x, + ship->Location().y, + ship->Location().z); + s += buffer; + } + + if (fabs(ship->Velocity().x) < 1e9) { + sprintf_s(buffer, " velocity: (%.1f, %.1f, %.1f),\n", + ship->Velocity().x, + ship->Velocity().y, + ship->Velocity().z); + s += buffer; + } + + if (ship->Respawns() > -1) { + sprintf_s(buffer, " respawns: %d,\n", ship->Respawns()); + s += buffer; + } + + if (ship->Heading() > -1e9) { + sprintf_s(buffer, " heading: %d,\n", (int) (ship->Heading()/DEGREES)); + s += buffer; + } + + if (ship->Integrity() > -1) { + sprintf_s(buffer, " integrity: %d,\n", (int) ship->Integrity()); + s += buffer; + } + + if (ship->Decoys() > -1) { + sprintf_s(buffer, " decoys: %d,\n", ship->Decoys()); + s += buffer; + } + + if (ship->Probes() > -1) { + sprintf_s(buffer, " probes: %d,\n", ship->Probes()); + s += buffer; + } + + if (ship->Ammo()[0] > -10) { + s += "\n ammo: ("; + + for (int i = 0; i < 16; i++) { + sprintf_s(buffer, "%d", ship->Ammo()[i]); + s += buffer; + + if (i < 15) + s += ", "; + } + + s += ")\n"; + } + + if (ship->Fuel()[0] > -10) { + s += "\n fuel: ("; + + for (int i = 0; i < 4; i++) { + sprintf_s(buffer, "%d", ship->Fuel()[i]); + s += buffer; + + if (i < 3) + s += ", "; + } + + s += ")\n"; + } + + s += " }\n"; + } + } + + s += "}\n\n"; + } + + ListIter iter2 = GetEvents(); + while (++iter2) { + MissionEvent* event = iter2.value(); + + s += "event: {\n"; + + s += " id: "; + sprintf_s(buffer, "%d", event->EventID()); + s += buffer; + s += ",\n time: "; + sprintf_s(buffer, "%.1f", event->Time()); + s += buffer; + s += ",\n delay: "; + sprintf_s(buffer, "%.1f", event->Delay()); + s += buffer; + s += ",\n event: "; + s += event->EventName(); + s += "\n"; + + if (event->EventShip().length()) { + s += " event_ship: \""; + s += SafeString(event->EventShip()); + s += "\"\n"; + } + + if (event->EventSource().length()) { + s += " event_source: \""; + s += SafeString(event->EventSource()); + s += "\"\n"; + } + + if (event->EventTarget().length()) { + s += " event_target: \""; + s += SafeString(event->EventTarget()); + s += "\"\n"; + } + + if (event->EventSound().length()) { + s += " event_sound: \""; + s += SafeString(event->EventSound()); + s += "\"\n"; + } + + if (event->EventMessage().length()) { + s += " event_message: \""; + s += SafeString(event->EventMessage()); + s += "\"\n"; + } + + if (event->EventParam()) { + sprintf_s(buffer, "%d", event->EventParam()); + s += " event_param: "; + s += buffer; + s += "\n"; + } + + if (event->EventChance()) { + sprintf_s(buffer, "%d", event->EventChance()); + s += " event_chance: "; + s += buffer; + s += "\n"; + } + + s += " trigger: \""; + s += event->TriggerName(); + s += "\"\n"; + + if (event->TriggerShip().length()) { + s += " trigger_ship: \""; + s += SafeString(event->TriggerShip()); + s += "\"\n"; + } + + if (event->TriggerTarget().length()) { + s += " trigger_target: \""; + s += SafeString(event->TriggerTarget()); + s += "\"\n"; + } + + Text param_str = event->TriggerParamStr(); + + if (param_str.length()) { + s += " trigger_param: "; + s += param_str; + s += "\n"; + } + + s += "}\n\n"; + } + + s += "// EOF\n"; + + return s; +} + +// +====================================================================+ + +static int elem_idkey = 1; + +MissionElement::MissionElement() +: id (elem_idkey++), +elem_id(0), design(0), skin(0), count(1), maint_count(0), dead_count(0), +IFF_code(0), player(0), alert(false), playable(false), rogue(false), invulnerable(false), +respawns(0), hold_time(0), zone_lock(0), heading(0), mission_role(Mission::OTHER), +intel(Intel::SECRET), command_ai(1), combat_group(0), combat_unit(0) +{ +} + +MissionElement::~MissionElement() +{ + ships.destroy(); + objectives.destroy(); + instructions.destroy(); + navlist.destroy(); + loadouts.destroy(); +} + +Text +MissionElement::Abbreviation() const +{ + if (design) + return design->abrv; + + return "UNK"; +} + +Text +MissionElement::GetShipName(int index) const +{ + if (index < 0 || index >= ships.size()) { + if (count > 1) { + char sname[256]; + sprintf_s(sname, "%s %d", (const char*) name, index+1); + return sname; + } + else { + return name; + } + } + + return ships.at(index)->Name(); +} + +Text +MissionElement::GetRegistry(int index) const +{ + if (index < 0 || index >= ships.size()) { + return Text(); + } + + return ships.at(index)->RegNum(); +} + +Text +MissionElement::RoleName() const +{ + return Mission::RoleName(mission_role); +} + +Color +MissionElement::MarkerColor() const +{ + return Ship::IFFColor(IFF_code); +} + +bool +MissionElement::IsStatic() const +{ + int design_type = 0; + if (GetDesign()) + design_type = GetDesign()->type; + + return design_type >= Ship::STATION; +} + +bool +MissionElement::IsGroundUnit() const +{ + int design_type = 0; + if (GetDesign()) + design_type = GetDesign()->type; + + return (design_type & Ship::GROUND_UNITS) ? true : false; +} + +bool +MissionElement::IsStarship() const +{ + int design_type = 0; + if (GetDesign()) + design_type = GetDesign()->type; + + return (design_type & Ship::STARSHIPS) ? true : false; +} + +bool +MissionElement::IsDropship() const +{ + int design_type = 0; + if (GetDesign()) + design_type = GetDesign()->type; + + return (design_type & Ship::DROPSHIPS) ? true : false; +} + +bool +MissionElement::IsCarrier() const +{ + const ShipDesign* design = GetDesign(); + if (design && design->flight_decks.size() > 0) + return true; + + return false; +} + +bool +MissionElement::IsSquadron() const +{ + if (carrier.length() > 0) + return true; + + return false; +} + +// +--------------------------------------------------------------------+ + +Point +MissionElement::Location() const +{ + MissionElement* pThis = (MissionElement*) this; + return pThis->rloc.Location(); +} + +void +MissionElement::SetLocation(const Point& l) +{ + rloc.SetBaseLocation(l); + rloc.SetReferenceLoc(0); + rloc.SetDistance(0); +} + +void +MissionElement::SetRLoc(const RLoc& r) +{ + rloc = r; +} + +// +----------------------------------------------------------------------+ + +void +MissionElement::AddNavPoint(Instruction* pt, Instruction* afterPoint) +{ + if (pt && !navlist.contains(pt)) { + if (afterPoint) { + int index = navlist.index(afterPoint); + + if (index > -1) + navlist.insert(pt, index+1); + else + navlist.append(pt); + } + + else { + navlist.append(pt); + } + } +} + +void +MissionElement::DelNavPoint(Instruction* pt) +{ + if (pt) + delete navlist.remove(pt); +} + +void +MissionElement::ClearFlightPlan() +{ + navlist.destroy(); +} + +// +----------------------------------------------------------------------+ + +int +MissionElement::GetNavIndex(const Instruction* n) +{ + int index = 0; + + if (navlist.size() > 0) { + ListIter navpt = navlist; + while (++navpt) { + index++; + if (navpt.value() == n) + return index; + } + } + + return 0; +} + +// +====================================================================+ + +MissionLoad::MissionLoad(int s, const char* n) +: ship(s) +{ + for (int i = 0; i < 16; i++) + load[i] = -1; // default: no weapon mounted + + if (n) + name = n; +} + +MissionLoad::~MissionLoad() +{ +} + +// +--------------------------------------------------------------------+ + +int +MissionLoad::GetShip() const +{ + return ship; +} + +void +MissionLoad::SetShip(int s) +{ + ship = s; +} + +Text +MissionLoad::GetName() const +{ + return name; +} + +void +MissionLoad::SetName(Text n) +{ + name = n; +} + +int* +MissionLoad::GetStations() +{ + return load; +} + +int +MissionLoad::GetStation(int index) +{ + if (index >= 0 && index < 16) + return load[index]; + + return 0; +} + +void +MissionLoad::SetStation(int index, int selection) +{ + if (index >= 0 && index < 16) + load[index] = selection; +} + + +// +====================================================================+ + +MissionShip::MissionShip() +: loc(-1e9, -1e9, -1e9), respawns(0), heading(0), integrity(100), +decoys(-10), probes(-10), skin(0) +{ + for (int i = 0; i < 16; i++) + ammo[i] = -10; + + for (int i = 0; i < 4; i++) + fuel[i] = -10; +} + +void +MissionShip::SetAmmo(const int* a) +{ + if (a) { + for (int i = 0; i < 16; i++) + ammo[i] = a[i]; + } +} + +void +MissionShip::SetFuel(const int* f) +{ + if (f) { + for (int i = 0; i < 4; i++) + fuel[i] = f[i]; + } +} -- cgit v1.1