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/MissionTemplate.cpp | 1716 ++++++++++++++++++++++--------------------- 1 file changed, 870 insertions(+), 846 deletions(-) (limited to 'Stars45/MissionTemplate.cpp') diff --git a/Stars45/MissionTemplate.cpp b/Stars45/MissionTemplate.cpp index 9bff8ba..0aac015 100644 --- a/Stars45/MissionTemplate.cpp +++ b/Stars45/MissionTemplate.cpp @@ -1,846 +1,870 @@ -/* Project Starshatter 4.5 - Destroyer Studios LLC - Copyright © 1997-2004. All Rights Reserved. - - SUBSYSTEM: Stars.exe - FILE: Mission.cpp - AUTHOR: John DiCamillo - - - OVERVIEW - ======== - Mission Template classes -*/ - -#include "MemDebug.h" -#include "MissionTemplate.h" -#include "MissionEvent.h" -#include "StarSystem.h" -#include "Galaxy.h" -#include "Callsign.h" -#include "Campaign.h" -#include "Combatant.h" -#include "CombatGroup.h" -#include "CombatUnit.h" -#include "Starshatter.h" -#include "Ship.h" -#include "ShipDesign.h" -#include "Element.h" -#include "Instruction.h" -#include "Random.h" - -#include "Game.h" -#include "DataLoader.h" -#include "ParseUtil.h" - -// +--------------------------------------------------------------------+ - -MissionTemplate::MissionTemplate(int identity, const char* fname, const char* pname) -: Mission(identity, fname, pname) -{ -} - -MissionTemplate::~MissionTemplate() -{ - callsigns.destroy(); - aliases.destroy(); -} - -// +--------------------------------------------------------------------+ - -void -MissionTemplate::AddElement(MissionElement* elem) -{ - if (elem) { - elements.append(elem); - aliases.append(new(__FILE__,__LINE__) MissionAlias(elem->Name(), elem)); - } -} - -bool -MissionTemplate::MapElement(MissionElement* elem) -{ - bool result = false; - - if (elem && !elem->GetCombatUnit()) { - if (elem->IsDropship()) { - Text callsign = MapCallsign(elem->Name(), elem->GetIFF()); - - if (callsign.length()) - elem->SetName(callsign); - } - - ListIter obj = elem->Objectives(); - while (++obj) { - Instruction* i = obj.value(); - if (strlen(i->TargetName())) { - // find a callsign, only if one already exists: - Text callsign = MapCallsign(i->TargetName(), -1); - if (callsign.length()) - i->SetTarget(callsign.data()); - } - } - - ListIter nav = elem->NavList(); - while (++nav) { - Instruction* i = nav.value(); - if (strlen(i->TargetName())) { - // find a callsign, only if one already exists: - Text callsign = MapCallsign(i->TargetName(), -1); - if (callsign.length()) - i->SetTarget(callsign.data()); - } - } - - CombatGroup* g = FindCombatGroup(elem->GetIFF(), elem->GetDesign()); - - if (g) { - CombatUnit* u = g->GetNextUnit(); - - if (u) { - elem->SetCombatGroup(g); - elem->SetCombatUnit(u); - } - } - - if (elem->GetCombatUnit()) { - MissionElement* cmdr = FindElement(elem->Commander()); - if (cmdr) - elem->SetCommander(cmdr->Name()); - - MissionElement* sqdr = FindElement(elem->Squadron()); - if (sqdr) - elem->SetSquadron(sqdr->Name()); - - if (!elem->IsDropship()) { - aliases.append(new(__FILE__,__LINE__) MissionAlias(elem->Name(), elem)); - elem->SetName(elem->GetCombatUnit()->Name()); - } - - result = true; - } - } - - return result; -} - -Text -MissionTemplate::MapShip(Text name) -{ - Text result = name; - int len = name.length(); - - if (len) { - MissionElement* elem = 0; - - // single ship from an element (e.g. "Alpha 1")? - if (isdigit(name[len-1]) && isspace(name[len-2])) { - Text elem_name = name.substring(0, len-2); - - elem = FindElement(elem_name); - if (elem) - result = elem->Name() + name.substring(len-2, 2); - } - - // full element name - // (also used to try again if single-ship search fails) - if (!elem) { - elem = FindElement(name); - - if (elem) - result = elem->Name(); - } - } - - return result; -} - -// +--------------------------------------------------------------------+ - -bool -MissionTemplate::MapEvent(MissionEvent* event) -{ - bool result = false; - - if (event) { - event->event_ship = MapShip(event->event_ship); - event->event_source = MapShip(event->event_source); - event->event_target = MapShip(event->event_target); - event->trigger_ship = MapShip(event->trigger_ship); - event->trigger_target = MapShip(event->trigger_target); - - result = true; - } - - return result; -} - -// +--------------------------------------------------------------------+ - -Text -MissionTemplate::MapCallsign(const char* name, int iff) -{ - for (int i = 0; i < callsigns.size(); i++) { - if (callsigns[i]->Name() == name) - return callsigns[i]->Callsign(); - } - - if (iff >= 0) { - const char* callsign = Callsign::GetCallsign(iff); - MissionCallsign* mc = new(__FILE__,__LINE__) MissionCallsign(callsign, name); - callsigns.append(mc); - - return mc->Callsign(); - } - - return name; -} - -// +--------------------------------------------------------------------+ - -static void SelectCombatGroups(CombatGroup* g, const ShipDesign* d, List& list) -{ - if (g->IntelLevel() <= Intel::RESERVE) - return; - - if (g->GetUnits().size() > 0) { - for (int i = 0; i < g->GetUnits().size(); i++) { - CombatUnit* u = g->GetUnits().at(i); - if (u->GetDesign() == d && u->Count() - u->DeadCount() > 0) { - list.append(g); - } - } - } - - ListIter subgroup = g->GetComponents(); - while (++subgroup) - SelectCombatGroups(subgroup.value(), d, list); -} - -CombatGroup* -MissionTemplate::FindCombatGroup(int iff, const ShipDesign* d) -{ - CombatGroup* result = 0; - Campaign* campaign = Campaign::GetCampaign(); - List group_list; - static int combat_group_index = 0; - - if (campaign) { - ListIter combatant = campaign->GetCombatants(); - while (++combatant) { - if (combatant->GetIFF() == iff) { - ::SelectCombatGroups(combatant->GetForce(), d, group_list); - } - } - - if (group_list.size() > 0) - result = group_list[combat_group_index++ % group_list.size()]; - } - - return result; -} - -// +--------------------------------------------------------------------+ - -MissionElement* -MissionTemplate::FindElement(const char* n) -{ - Text name = n; - - ListIter c_iter = callsigns; - while (++c_iter) { - MissionCallsign* c = c_iter.value(); - if (c->Name() == name) { - name = c->Callsign(); - break; - } - } - - ListIter a_iter = aliases; - while (++a_iter) { - MissionAlias* a = a_iter.value(); - if (a->Name() == name) - return a->Element(); - } - - ListIter e_iter = elements; - while (++e_iter) { - MissionElement* elem = e_iter.value(); - if (elem->Name() == name) - return elem; - } - - return 0; -} - -// +--------------------------------------------------------------------+ - -bool -MissionTemplate::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 Template, script unspecified.\n"); - return ok; - } - - Print("\nLoad Mission Template: '%s'\n", filename); - - int max_ships = (int) 1e6; - - 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); - - Parser parser(new(__FILE__,__LINE__) BlockReader((const char*) block)); - - Term* term = parser.ParseTerm(); - - if (!term) { - Print("ERROR: could not parse '%s'\n", filename); - return ok; - } - else { - TermText* file_type = term->isText(); - if (!file_type || file_type->value() != "MISSION_TEMPLATE") { - Print("ERROR: invalid MISSION TEMPLATE file '%s'\n", filename); - 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(); - - if (defname == "name") - GetDefText(name, def, filename); - - 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); - - Campaign* campaign = Campaign::GetCampaign(); - - if (campaign) { - Galaxy* galaxy = Galaxy::GetInstance(); - - if (galaxy) { - star_system = 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); - - else if (defname == "sitrep") - GetDefText(sitrep, def, filename); - - else if (defname == "start") - GetDefTime(start, 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 == "alias")) { - if (!def->term() || !def->term()->isStruct()) { - Print("WARNING: alias struct missing in '%s'\n", filename); - ok = false; - } - else { - TermStruct* val = def->term()->isStruct(); - ParseAlias(val); - } - } - - else if ((defname == "callsign")) { - if (!def->term() || !def->term()->isStruct()) { - Print("WARNING: callsign struct missing in '%s'\n", filename); - ok = false; - } - else { - TermStruct* val = def->term()->isStruct(); - ParseCallsign(val); - } - } - - else if (defname == "optional") { - if (!def->term() || !def->term()->isStruct()) { - Print("WARNING: optional group struct missing in '%s'\n", filename); - ok = false; - } - else { - TermStruct* val = def->term()->isStruct(); - ParseOptional(val); - } - } - - else if (defname == "element") { - if (!def->term() || !def->term()->isStruct()) { - Print("WARNING: element struct missing in '%s'\n", filename); - ok = false; - } - else { - TermStruct* val = def->term()->isStruct(); - MissionElement* elem = ParseElement(val); - if (MapElement(elem)) { - AddElement(elem); - } - else { - Print("WARNING: failed to map element %s '%s' in '%s'\n", - elem->GetDesign() ? elem->GetDesign()->name : "NO DSN", - elem->Name().data(), - filename); - val->print(); - Print("\n"); - delete elem; - ok = false; - } - } - } - - else if (defname == "event") { - if (!def->term() || !def->term()->isStruct()) { - Print("WARNING: event struct missing in '%s'\n", filename); - ok = false; - } - else { - TermStruct* val = def->term()->isStruct(); - MissionEvent* event = ParseEvent(val); - - if (MapEvent(event)) - AddEvent(event); - } - } - } // def - } // term - } - while (term); - - loader->ReleaseBuffer(block); - - if (ok) { - CheckObjectives(); - - if (target_name[0]) - target = FindElement(target_name); - - if (ward_name[0]) - ward = FindElement(ward_name); - - Print("Mission Template Loaded.\n\n"); - } - - return ok; -} - -// +--------------------------------------------------------------------+ - -void -MissionTemplate::ParseAlias(TermStruct* val) -{ - Text name; - Text design; - Text code; - Text elem_name; - int iff = -1; - int player = 0; - RLoc* rloc = 0; - bool use_loc = false; - Vec3 loc; - - 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(name, pdef, filename); - - else if (defname == "elem") - GetDefText(elem_name, pdef, filename); - - else if (defname == "code") - GetDefText(code, pdef, filename); - - else if (defname == "design") - GetDefText(design, pdef, filename); - - else if (defname == "iff") - GetDefNumber(iff, pdef, filename); - - else if (defname == "loc") { - loc; - GetDefVec(loc, pdef, filename); - use_loc = true; - } - - else if (defname == "rloc") { - if (pdef->term()->isStruct()) { - rloc = ParseRLoc(pdef->term()->isStruct()); - } - } - - else if (defname == "player") { - GetDefNumber(player, pdef, filename); - - if (player && !code.length()) - code = "player"; - } - } - } - - MissionElement* elem = 0; - - // now find element and create alias: - if (name.length()) { - for (int i = 0; i < aliases.size(); i++) - if (aliases[i]->Name() == name) - return; - - // by element name? - if (elem_name.length()) { - elem = FindElement(elem_name); - } - - // by special code? - else if (code.length()) { - code.toLower(); - Campaign* campaign = Campaign::GetCampaign(); - - if (code == "player") { - for (int i = 0; !elem && i < elements.size(); i++) { - MissionElement* e = elements[i]; - if (e->Player() > 0) { - elem = e; - } - } - } - - else if (campaign && code == "player_carrier") { - CombatGroup* player_group = campaign->GetPlayerGroup(); - - if (player_group) { - CombatGroup* carrier = player_group->FindCarrier(); - - if (carrier) { - elem = FindElement(carrier->Name()); - } - } - } - - else if (campaign && code == "player_squadron") { - CombatGroup* player_group = player_squadron; - - if (!player_group) - player_group = campaign->GetPlayerGroup(); - - if (player_group && - (player_group->Type() == CombatGroup::INTERCEPT_SQUADRON || - player_group->Type() == CombatGroup::FIGHTER_SQUADRON || - player_group->Type() == CombatGroup::ATTACK_SQUADRON)) { - elem = FindElement(player_group->Name()); - } - } - - else if (campaign && code == "strike_target") { - CombatGroup* player_group = campaign->GetPlayerGroup(); - - if (player_group) { - CombatGroup* strike_target = campaign->FindStrikeTarget(player_group->GetIFF(), player_group); - - if (strike_target) { - elem = FindElement(strike_target->Name()); - } - } - } - } - - // by design and team? - else { - MissionElement* first_match = 0; - - for (int i = 0; !elem && i < elements.size(); i++) { - MissionElement* e = elements[i]; - if (e->GetIFF() == iff && design == e->GetDesign()->name) { - // do we already have an alias for this element? - bool found = false; - for (int a = 0; !found && a < aliases.size(); a++) - if (aliases[a]->Element() == e) - found = true; - - if (!found) - elem = e; - - else if (!first_match) - first_match = e; - } - } - - if (first_match && !elem) - elem = first_match; - } - - if (elem) { - if (rloc) elem->SetRLoc(*rloc); - else if (use_loc) elem->SetLocation(loc); - - delete rloc; - - aliases.append(new(__FILE__,__LINE__) MissionAlias(name, elem)); - } - else { - ::Print("WARNING: Could not resolve mission alias '%s'\n", (const char*) name); - ok = false; - } - } - - if (!elem || !ok) return; - - // re-parse the struct, dealing with stuff - // that needs to be attached to the 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 == "objective") { - if (!pdef->term() || !pdef->term()->isStruct()) { - Print("WARNING: order struct missing for element '%s' in '%s'\n", (const char*) elem->Name(), filename); - ok = false; - } - else { - TermStruct* val = pdef->term()->isStruct(); - Instruction* obj = ParseInstruction(val, elem); - elem->Objectives().append(obj); - } - } - - else if (defname == "instr") { - Text* obj = new(__FILE__,__LINE__) Text; - if (GetDefText(*obj, pdef, filename)) - elem->Instructions().append(obj); - } - - else if (defname == "order" || defname == "navpt") { - if (!pdef->term() || !pdef->term()->isStruct()) { - Print("WARNING: order struct missing for element '%s' in '%s'\n", (const char*) elem->Name(), filename); - ok = false; - } - else { - TermStruct* val = pdef->term()->isStruct(); - Instruction* npt = ParseInstruction(val, elem); - elem->NavList().append(npt); - } - } - - else if (defname == "loadout") { - if (!pdef->term() || !pdef->term()->isStruct()) { - Print("WARNING: loadout struct missing for element '%s' in '%s'\n", (const char*) elem->Name(), filename); - ok = false; - } - else { - TermStruct* val = pdef->term()->isStruct(); - ParseLoadout(val, elem); - } - } - } - } -} - -// +--------------------------------------------------------------------+ - -void -MissionTemplate::ParseCallsign(TermStruct* val) -{ - Text name; - int iff = -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 == "name") - GetDefText(name, pdef, filename); - - else if (defname == "iff") - GetDefNumber(iff, pdef, filename); - } - } - - if (name.length() > 0 && iff >= 0) - MapCallsign(name, iff); -} - -// +--------------------------------------------------------------------+ - -bool -MissionTemplate::ParseOptional(TermStruct* val) -{ - int n = 0; - int min = 0; - int max = 1000; - int skip = 0; - int total = val->elements()->size(); - - 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 == "min") { - GetDefNumber(min, pdef, filename); - total--; - } - - else if (defname == "max") { - GetDefNumber(max, pdef, filename); - total--; - } - - - else if ((defname == "optional")) { - bool select; - - if (n >= max) - select = false; - else if (total - n - skip <= min) - select = true; - else - select = RandomChance(); - - if (select) { - if (!pdef->term() || !pdef->term()->isStruct()) { - Print("WARNING: optional group struct missing in '%s'\n", filename); - ok = false; - skip++; - } - else { - TermStruct* val = pdef->term()->isStruct(); - if (ParseOptional(val)) - n++; - else - skip++; - } - } - else { - skip++; - } - } - - else if (defname == "element") { - bool select; - - if (n >= max) - select = false; - else if (total - n - skip <= min) - select = true; - else - select = RandomChance(); - - if (select) { - if (!pdef->term() || !pdef->term()->isStruct()) { - Print("WARNING: element struct missing in '%s'\n", filename); - ok = false; - skip++; - } - else { - TermStruct* es = pdef->term()->isStruct(); - MissionElement* elem = ParseElement(es); - if (MapElement(elem)) { - AddElement(elem); - n++; - } - else { - delete elem; - skip++; - } - } - } - else { - skip++; - } - } - } - } - - return n > 0 && n >= min; -} - -// +--------------------------------------------------------------------+ - -void -MissionTemplate::CheckObjectives() -{ - ListIter iter = elements; - while (++iter) { - MissionElement* elem = iter.value(); - - ListIter obj = elem->Objectives(); - while (++obj) { - Instruction* o = obj.value(); - Text tgt = o->TargetName(); - - MissionElement* tgt_elem = 0; - - if (tgt.length()) { - tgt_elem = FindElement(tgt); - - if (!tgt_elem) - obj.removeItem(); - else - o->SetTarget(tgt_elem->Name()); - } - } - } -} +/* 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 Template classes +*/ + +#include "MemDebug.h" +#include "MissionTemplate.h" +#include "MissionEvent.h" +#include "StarSystem.h" +#include "Galaxy.h" +#include "Callsign.h" +#include "Campaign.h" +#include "Combatant.h" +#include "CombatGroup.h" +#include "CombatUnit.h" +#include "Starshatter.h" +#include "Ship.h" +#include "ShipDesign.h" +#include "Element.h" +#include "Instruction.h" +#include "Random.h" + +#include "Game.h" +#include "DataLoader.h" +#include "ParseUtil.h" + +// +--------------------------------------------------------------------+ + +MissionTemplate::MissionTemplate(int identity, const char* fname, const char* pname) +: Mission(identity, fname, pname) +{ +} + +MissionTemplate::~MissionTemplate() +{ + callsigns.destroy(); + aliases.destroy(); +} + +// +--------------------------------------------------------------------+ + +void +MissionTemplate::AddElement(MissionElement* elem) +{ + if (elem) { + elements.append(elem); + aliases.append(new(__FILE__,__LINE__) MissionAlias(elem->Name(), elem)); + } +} + +bool +MissionTemplate::MapElement(MissionElement* elem) +{ + bool result = false; + + if (elem && !elem->GetCombatUnit()) { + if (elem->IsDropship()) { + Text callsign = MapCallsign(elem->Name(), elem->GetIFF()); + + if (callsign.length()) + elem->SetName(callsign); + } + + ListIter obj = elem->Objectives(); + while (++obj) { + Instruction* i = obj.value(); + if (strlen(i->TargetName())) { + // find a callsign, only if one already exists: + Text callsign = MapCallsign(i->TargetName(), -1); + if (callsign.length()) + i->SetTarget(callsign.data()); + } + } + + ListIter nav = elem->NavList(); + while (++nav) { + Instruction* i = nav.value(); + if (strlen(i->TargetName())) { + // find a callsign, only if one already exists: + Text callsign = MapCallsign(i->TargetName(), -1); + if (callsign.length()) + i->SetTarget(callsign.data()); + } + } + + CombatGroup* g = FindCombatGroup(elem->GetIFF(), elem->GetDesign()); + + if (g) { + CombatUnit* u = g->GetNextUnit(); + + if (u) { + elem->SetCombatGroup(g); + elem->SetCombatUnit(u); + } + } + + if (elem->GetCombatUnit()) { + MissionElement* cmdr = FindElement(elem->Commander()); + if (cmdr) + elem->SetCommander(cmdr->Name()); + + MissionElement* sqdr = FindElement(elem->Squadron()); + if (sqdr) + elem->SetSquadron(sqdr->Name()); + + if (!elem->IsDropship()) { + aliases.append(new(__FILE__,__LINE__) MissionAlias(elem->Name(), elem)); + elem->SetName(elem->GetCombatUnit()->Name()); + } + + result = true; + } + } + + return result; +} + +Text +MissionTemplate::MapShip(Text name) +{ + Text result = name; + int len = name.length(); + + if (len) { + MissionElement* elem = 0; + + // single ship from an element (e.g. "Alpha 1")? + if (isdigit(name[len-1]) && isspace(name[len-2])) { + Text elem_name = name.substring(0, len-2); + + elem = FindElement(elem_name); + if (elem) + result = elem->Name() + name.substring(len-2, 2); + } + + // full element name + // (also used to try again if single-ship search fails) + if (!elem) { + elem = FindElement(name); + + if (elem) + result = elem->Name(); + } + } + + return result; +} + +// +--------------------------------------------------------------------+ + +bool +MissionTemplate::MapEvent(MissionEvent* event) +{ + bool result = false; + + if (event) { + event->event_ship = MapShip(event->event_ship); + event->event_source = MapShip(event->event_source); + event->event_target = MapShip(event->event_target); + event->trigger_ship = MapShip(event->trigger_ship); + event->trigger_target = MapShip(event->trigger_target); + + result = true; + } + + return result; +} + +// +--------------------------------------------------------------------+ + +Text +MissionTemplate::MapCallsign(const char* name, int iff) +{ + for (int i = 0; i < callsigns.size(); i++) { + if (callsigns[i]->Name() == name) + return callsigns[i]->Callsign(); + } + + if (iff >= 0) { + const char* callsign = Callsign::GetCallsign(iff); + MissionCallsign* mc = new(__FILE__,__LINE__) MissionCallsign(callsign, name); + callsigns.append(mc); + + return mc->Callsign(); + } + + return name; +} + +// +--------------------------------------------------------------------+ + +static void SelectCombatGroups(CombatGroup* g, const ShipDesign* d, List& list) +{ + if (g->IntelLevel() <= Intel::RESERVE) + return; + + if (g->GetUnits().size() > 0) { + for (int i = 0; i < g->GetUnits().size(); i++) { + CombatUnit* u = g->GetUnits().at(i); + if (u->GetDesign() == d && u->Count() - u->DeadCount() > 0) { + list.append(g); + } + } + } + + ListIter subgroup = g->GetComponents(); + while (++subgroup) + SelectCombatGroups(subgroup.value(), d, list); +} + +CombatGroup* +MissionTemplate::FindCombatGroup(int iff, const ShipDesign* d) +{ + CombatGroup* result = 0; + Campaign* campaign = Campaign::GetCampaign(); + List group_list; + static int combat_group_index = 0; + + if (campaign) { + ListIter combatant = campaign->GetCombatants(); + while (++combatant) { + if (combatant->GetIFF() == iff) { + ::SelectCombatGroups(combatant->GetForce(), d, group_list); + } + } + + if (group_list.size() > 0) + result = group_list[combat_group_index++ % group_list.size()]; + } + + return result; +} + +// +--------------------------------------------------------------------+ + +MissionElement* +MissionTemplate::FindElement(const char* n) +{ + Text name = n; + + ListIter c_iter = callsigns; + while (++c_iter) { + MissionCallsign* c = c_iter.value(); + if (c->Name() == name) { + name = c->Callsign(); + break; + } + } + + ListIter a_iter = aliases; + while (++a_iter) { + MissionAlias* a = a_iter.value(); + if (a->Name() == name) + return a->Element(); + } + + ListIter e_iter = elements; + while (++e_iter) { + MissionElement* elem = e_iter.value(); + if (elem->Name() == name) + return elem; + } + + return 0; +} + +// +--------------------------------------------------------------------+ + +bool +MissionTemplate::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 Template, script unspecified.\n"); + return ok; + } + + Print("\nLoad Mission Template: '%s'\n", filename); + + int max_ships = (int) 1e6; + + 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); + + Parser parser(new(__FILE__,__LINE__) BlockReader((const char*) block)); + + Term* term = parser.ParseTerm(); + + if (!term) { + Print("ERROR: could not parse '%s'\n", filename); + return ok; + } + else { + TermText* file_type = term->isText(); + if (!file_type || file_type->value() != "MISSION_TEMPLATE") { + Print("ERROR: invalid MISSION TEMPLATE file '%s'\n", filename); + 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(); + + if (defname == "name") + GetDefText(name, def, filename); + + 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); + + Campaign* campaign = Campaign::GetCampaign(); + + if (campaign) { + Galaxy* galaxy = Galaxy::GetInstance(); + + if (galaxy) { + star_system = 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); + + else if (defname == "sitrep") + GetDefText(sitrep, def, filename); + + else if (defname == "start") + GetDefTime(start, 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 == "alias")) { + if (!def->term() || !def->term()->isStruct()) { + Print("WARNING: alias struct missing in '%s'\n", filename); + ok = false; + } + else { + TermStruct* val = def->term()->isStruct(); + ParseAlias(val); + } + } + + else if ((defname == "callsign")) { + if (!def->term() || !def->term()->isStruct()) { + Print("WARNING: callsign struct missing in '%s'\n", filename); + ok = false; + } + else { + TermStruct* val = def->term()->isStruct(); + ParseCallsign(val); + } + } + + else if (defname == "optional") { + if (!def->term() || !def->term()->isStruct()) { + Print("WARNING: optional group struct missing in '%s'\n", filename); + ok = false; + } + else { + TermStruct* val = def->term()->isStruct(); + ParseOptional(val); + } + } + + else if (defname == "element") { + if (!def->term() || !def->term()->isStruct()) { + Print("WARNING: element struct missing in '%s'\n", filename); + ok = false; + } + else { + TermStruct* val = def->term()->isStruct(); + MissionElement* elem = ParseElement(val); + if (MapElement(elem)) { + AddElement(elem); + } + else { + Print("WARNING: failed to map element %s '%s' in '%s'\n", + elem->GetDesign() ? elem->GetDesign()->name : "NO DSN", + elem->Name().data(), + filename); + val->print(); + Print("\n"); + delete elem; + ok = false; + } + } + } + + else if (defname == "event") { + if (!def->term() || !def->term()->isStruct()) { + Print("WARNING: event struct missing in '%s'\n", filename); + ok = false; + } + else { + TermStruct* val = def->term()->isStruct(); + MissionEvent* event = ParseEvent(val); + + if (MapEvent(event)) + AddEvent(event); + } + } + } // def + } // term + } + while (term); + + loader->ReleaseBuffer(block); + + if (ok) { + CheckObjectives(); + + if (target_name[0]) + target = FindElement(target_name); + + if (ward_name[0]) + ward = FindElement(ward_name); + + Print("Mission Template Loaded.\n\n"); + } + + return ok; +} + +// +--------------------------------------------------------------------+ + +void +MissionTemplate::ParseAlias(TermStruct* val) +{ + Text name; + Text design; + Text code; + Text elem_name; + int iff = -1; + int player = 0; + RLoc* rloc = 0; + bool use_loc = false; + Vec3 loc; + + 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(name, pdef, filename); + + else if (defname == "elem") + GetDefText(elem_name, pdef, filename); + + else if (defname == "code") + GetDefText(code, pdef, filename); + + else if (defname == "design") + GetDefText(design, pdef, filename); + + else if (defname == "iff") + GetDefNumber(iff, pdef, filename); + + else if (defname == "loc") { + loc; + GetDefVec(loc, pdef, filename); + use_loc = true; + } + + else if (defname == "rloc") { + if (pdef->term()->isStruct()) { + rloc = ParseRLoc(pdef->term()->isStruct()); + } + } + + else if (defname == "player") { + GetDefNumber(player, pdef, filename); + + if (player && !code.length()) + code = "player"; + } + } + } + + MissionElement* elem = 0; + + // now find element and create alias: + if (name.length()) { + for (int i = 0; i < aliases.size(); i++) + if (aliases[i]->Name() == name) + return; + + // by element name? + if (elem_name.length()) { + elem = FindElement(elem_name); + } + + // by special code? + else if (code.length()) { + code.toLower(); + Campaign* campaign = Campaign::GetCampaign(); + + if (code == "player") { + for (int i = 0; !elem && i < elements.size(); i++) { + MissionElement* e = elements[i]; + if (e->Player() > 0) { + elem = e; + } + } + } + + else if (campaign && code == "player_carrier") { + CombatGroup* player_group = campaign->GetPlayerGroup(); + + if (player_group) { + CombatGroup* carrier = player_group->FindCarrier(); + + if (carrier) { + elem = FindElement(carrier->Name()); + } + } + } + + else if (campaign && code == "player_squadron") { + CombatGroup* player_group = player_squadron; + + if (!player_group) + player_group = campaign->GetPlayerGroup(); + + if (player_group && + (player_group->Type() == CombatGroup::INTERCEPT_SQUADRON || + player_group->Type() == CombatGroup::FIGHTER_SQUADRON || + player_group->Type() == CombatGroup::ATTACK_SQUADRON)) { + elem = FindElement(player_group->Name()); + } + } + + else if (campaign && code == "strike_target") { + CombatGroup* player_group = campaign->GetPlayerGroup(); + + if (player_group) { + CombatGroup* strike_target = campaign->FindStrikeTarget(player_group->GetIFF(), player_group); + + if (strike_target) { + elem = FindElement(strike_target->Name()); + } + } + } + } + + // by design and team? + else { + MissionElement* first_match = 0; + + for (int i = 0; !elem && i < elements.size(); i++) { + MissionElement* e = elements[i]; + if (e->GetIFF() == iff && design == e->GetDesign()->name) { + // do we already have an alias for this element? + bool found = false; + for (int a = 0; !found && a < aliases.size(); a++) + if (aliases[a]->Element() == e) + found = true; + + if (!found) + elem = e; + + else if (!first_match) + first_match = e; + } + } + + if (first_match && !elem) + elem = first_match; + } + + if (elem) { + if (rloc) elem->SetRLoc(*rloc); + else if (use_loc) elem->SetLocation(loc); + + delete rloc; + + aliases.append(new(__FILE__,__LINE__) MissionAlias(name, elem)); + } + else { + ::Print("WARNING: Could not resolve mission alias '%s'\n", (const char*) name); + ok = false; + } + } + + if (!elem || !ok) return; + + // re-parse the struct, dealing with stuff + // that needs to be attached to the 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 == "objective") { + if (!pdef->term() || !pdef->term()->isStruct()) { + Print("WARNING: order struct missing for element '%s' in '%s'\n", (const char*) elem->Name(), filename); + ok = false; + } + else { + TermStruct* val = pdef->term()->isStruct(); + Instruction* obj = ParseInstruction(val, elem); + elem->Objectives().append(obj); + } + } + + else if (defname == "instr") { + Text* obj = new(__FILE__,__LINE__) Text; + if (GetDefText(*obj, pdef, filename)) + elem->Instructions().append(obj); + } + + else if (defname == "order" || defname == "navpt") { + if (!pdef->term() || !pdef->term()->isStruct()) { + Print("WARNING: order struct missing for element '%s' in '%s'\n", (const char*) elem->Name(), filename); + ok = false; + } + else { + TermStruct* val = pdef->term()->isStruct(); + Instruction* npt = ParseInstruction(val, elem); + elem->NavList().append(npt); + } + } + + else if (defname == "loadout") { + if (!pdef->term() || !pdef->term()->isStruct()) { + Print("WARNING: loadout struct missing for element '%s' in '%s'\n", (const char*) elem->Name(), filename); + ok = false; + } + else { + TermStruct* val = pdef->term()->isStruct(); + ParseLoadout(val, elem); + } + } + } + } +} + +// +--------------------------------------------------------------------+ + +void +MissionTemplate::ParseCallsign(TermStruct* val) +{ + Text name; + int iff = -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 == "name") + GetDefText(name, pdef, filename); + + else if (defname == "iff") + GetDefNumber(iff, pdef, filename); + } + } + + if (name.length() > 0 && iff >= 0) + MapCallsign(name, iff); +} + +// +--------------------------------------------------------------------+ + +bool +MissionTemplate::ParseOptional(TermStruct* val) +{ + int n = 0; + int min = 0; + int max = 1000; + int skip = 0; + int total = val->elements()->size(); + + 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 == "min") { + GetDefNumber(min, pdef, filename); + total--; + } + + else if (defname == "max") { + GetDefNumber(max, pdef, filename); + total--; + } + + + else if ((defname == "optional")) { + bool select; + + if (n >= max) + select = false; + else if (total - n - skip <= min) + select = true; + else + select = RandomChance(); + + if (select) { + if (!pdef->term() || !pdef->term()->isStruct()) { + Print("WARNING: optional group struct missing in '%s'\n", filename); + ok = false; + skip++; + } + else { + TermStruct* val = pdef->term()->isStruct(); + if (ParseOptional(val)) + n++; + else + skip++; + } + } + else { + skip++; + } + } + + else if (defname == "element") { + bool select; + + if (n >= max) + select = false; + else if (total - n - skip <= min) + select = true; + else + select = RandomChance(); + + if (select) { + if (!pdef->term() || !pdef->term()->isStruct()) { + Print("WARNING: element struct missing in '%s'\n", filename); + ok = false; + skip++; + } + else { + TermStruct* es = pdef->term()->isStruct(); + MissionElement* elem = ParseElement(es); + if (MapElement(elem)) { + AddElement(elem); + n++; + } + else { + delete elem; + skip++; + } + } + } + else { + skip++; + } + } + } + } + + return n > 0 && n >= min; +} + +// +--------------------------------------------------------------------+ + +void +MissionTemplate::CheckObjectives() +{ + ListIter iter = elements; + while (++iter) { + MissionElement* elem = iter.value(); + + ListIter obj = elem->Objectives(); + while (++obj) { + Instruction* o = obj.value(); + Text tgt = o->TargetName(); + + MissionElement* tgt_elem = 0; + + if (tgt.length()) { + tgt_elem = FindElement(tgt); + + if (!tgt_elem) + obj.removeItem(); + else + o->SetTarget(tgt_elem->Name()); + } + } + } +} -- cgit v1.1