diff --git a/aregion.cpp b/aregion.cpp index d20d35ca..3d6e794c 100644 --- a/aregion.cpp +++ b/aregion.cpp @@ -407,9 +407,9 @@ void ARegion::RunDecayEvent(Object *o, ARegionList *pRegs) pFactions = PresentFactions(); forlist (pFactions) { Faction *f = ((FactionPtr *) elem)->ptr; - f->Event(GetDecayFlavor() + *o->name + " " + - ObjectDefs[o->type].name + " in " + - ShortPrint(pRegs)); + stringstream tmp; + tmp << GetDecayFlavor() << o->name << " " << ObjectDefs[o->type].name << " in " << ShortPrint(pRegs); + f->event(tmp.str()); } } @@ -1181,7 +1181,7 @@ void ARegion::WriteProducts(ostream& f, Faction *fac, int present) forlist((&products)) { Production *p = ((Production *) elem); if (ItemDefs[p->itemtype].type & IT_ADVANCED) { - if (CanMakeAdv(fac, p->itemtype) || (fac->IsNPC())) { + if (CanMakeAdv(fac, p->itemtype) || fac->is_npc) { if (has) { temp += AString(", ") + p->WriteReport(); } else { @@ -1319,19 +1319,191 @@ void ARegion::WriteExits(ostream& f, ARegionList *pRegs, int *exits_seen) f << '\n'; } -void ARegion::write_json_report(json& j, Faction *fac, int month, ARegionList *pRegions) { - // for now, just set a name which would be the name of the region from a text report. - // ie "Alioth Plains (1, 2) in Alioth contains Alioth City [City]." - // This will get broken down and become more json-y when I flesh this code out. - j["name"] = Print(pRegions).const_str(); - return; +void ARegion::write_json_report(json& j, Faction *fac, int month, ARegionList *regions) { + Farsight *farsight = GetFarsight(&farsees, fac); + Farsight *passer = GetFarsight(&passers, fac); + int present = Present(fac) || fac->is_npc; + + // this faction cannot see this region, why are we even here? + if (!farsight && !passer && !present) return; + + // The region is visible to the faction + j["terrain"] = TerrainDefs[type].name; + + ARegionArray *level = regions->pRegionArrays[zloc]; + string label = (level->strName ? level->strName->const_str() : "surface"); + j["coordinates"] = { { "x", xloc }, { "y", yloc }, { "z", zloc }, { "label", label } }; + + j["province"] = name->const_str(); + if (town) { + j["settlement"] = { { "name", town->name->const_str() }, { "size", TownString(town->TownType()).const_str() } }; + } + + if (Population() && (present || farsight || (Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_PEASANTS))) { + j["population"] = { { "amount", Population() } }; + if (Globals->RACES_EXIST) { + j["population"]["race"] = ItemDefs[race].names; + } else { + j["population"]["race"] = "men"; + } + j["tax"] = (present || farsight || Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_REGION_MONEY) ? wealth : 0; + } + + if (Globals->WEATHER_EXISTS) { + string weather_name = clearskies ? "unnaturally clear" : SeasonNames[weather]; + j["weather"] = { { "current", weather_name }, { "next", SeasonNames[regions->GetWeather(this, (month + 1) % 12)] } }; + } + + if (type == R_NEXUS) { + stringstream desc; + desc << Globals->WORLD_NAME << " Nexus is a magical place: the entryway to the world of " + << Globals->WORLD_NAME << ". Enjoy your stay; the city guards should keep you safe as long " + << "as you should choose to stay. However, rumor has it that once you have left the Nexus, " + << "you can never return."; + j["description"] = desc.str(); + } + + // hold off on writing out other stuff for now.. Just the top level region info. + /* + WriteEconomy(f, fac, present || farsight); + + int exits_seen[NDIRS]; + if (present || farsight || + (Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_ALL_EXITS)) { + for (int i = 0; i < NDIRS; i++) + exits_seen[i] = 1; + } else { + // This is just a transit report and we're not showing all + // exits. See if we are showing used exits. + + // Show none by default. + int i; + for (i = 0; i < NDIRS; i++) + exits_seen[i] = 0; + // Now, if we should, show the ones actually used. + if (Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_USED_EXITS) { + forlist(&passers) { + Farsight *p = (Farsight *)elem; + if (p->faction == fac) { + for (i = 0; i < NDIRS; i++) { + exits_seen[i] |= p->exits_used[i]; + } + } + } + } + } + + WriteExits(f, pRegions, exits_seen); + + if (Globals->GATES_EXIST && gate && gate != -1) { + int sawgate = 0; + if (fac->is_npc) + sawgate = 1; + if (Globals->IMPROVED_FARSIGHT && farsight) { + forlist(&farsees) { + Farsight *watcher = (Farsight *)elem; + if (watcher && watcher->faction == fac && watcher->unit) { + if (watcher->unit->GetSkill(S_GATE_LORE)) { + sawgate = 1; + } + } + } + } + if (Globals->TRANSIT_REPORT & GameDefs::REPORT_USE_UNIT_SKILLS) { + forlist(&passers) { + Farsight *watcher = (Farsight *)elem; + if (watcher && watcher->faction == fac && watcher->unit) { + if (watcher->unit->GetSkill(S_GATE_LORE)) { + sawgate = 1; + } + } + } + } + forlist(&objects) { + Object *o = (Object *) elem; + forlist(&o->units) { + Unit *u = (Unit *) elem; + if (!sawgate && + ((u->faction == fac) && + u->GetSkill(S_GATE_LORE))) { + sawgate = 1; + } + } + } + if (sawgate) { + if (gateopen) { + f << "There is a Gate here (Gate " << gate; + if (!Globals->DISPERSE_GATE_NUMBERS) { + f << " of " << pRegions->numberofgates; + } + f << ").\n\n"; + } else if (Globals->SHOW_CLOSED_GATES) { + f << "There is a closed Gate here.\n\n"; + } + } + } + + int obs = GetObservation(fac, 0); + int truesight = GetTrueSight(fac, 0); + int detfac = 0; + + int passobs = GetObservation(fac, 1); + int passtrue = GetTrueSight(fac, 1); + int passdetfac = detfac; + + if (fac->is_npc) { + obs = 10; + passobs = 10; + } + + forlist (&objects) { + Object *o = (Object *) elem; + forlist(&o->units) { + Unit *u = (Unit *) elem; + if (u->faction == fac && u->GetSkill(S_MIND_READING) > 1) { + detfac = 1; + } + } + } + if (Globals->IMPROVED_FARSIGHT && farsight) { + forlist(&farsees) { + Farsight *watcher = (Farsight *)elem; + if (watcher && watcher->faction == fac && watcher->unit) { + if (watcher->unit->GetSkill(S_MIND_READING) > 1) { + detfac = 1; + } + } + } + } + + if ((Globals->TRANSIT_REPORT & GameDefs::REPORT_USE_UNIT_SKILLS) && + (Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_UNITS)) { + forlist(&passers) { + Farsight *watcher = (Farsight *)elem; + if (watcher && watcher->faction == fac && watcher->unit) { + if (watcher->unit->GetSkill(S_MIND_READING) > 1) { + passdetfac = 1; + } + } + } + } + + { + forlist (&objects) { + ((Object *) elem)->Report(f, fac, obs, truesight, detfac, + passobs, passtrue, passdetfac, + present || farsight); + } + f << '\n'; + } + */ } -void ARegion::WriteReport(ostream &f, Faction *fac, int month, ARegionList *pRegions) +void ARegion::write_text_report(ostream &f, Faction *fac, int month, ARegionList *pRegions) { Farsight *farsight = GetFarsight(&farsees, fac); Farsight *passer = GetFarsight(&passers, fac); - int present = Present(fac) || fac->IsNPC(); + int present = Present(fac) || fac->is_npc; if (farsight || passer || present) { AString temp = Print(pRegions); @@ -1418,7 +1590,7 @@ void ARegion::WriteReport(ostream &f, Faction *fac, int month, ARegionList *pReg if (Globals->GATES_EXIST && gate && gate != -1) { int sawgate = 0; - if (fac->IsNPC()) + if (fac->is_npc) sawgate = 1; if (Globals->IMPROVED_FARSIGHT && farsight) { forlist(&farsees) { @@ -1472,7 +1644,7 @@ void ARegion::WriteReport(ostream &f, Faction *fac, int month, ARegionList *pReg int passtrue = GetTrueSight(fac, 1); int passdetfac = detfac; - if (fac->IsNPC()) { + if (fac->is_npc) { obs = 10; passobs = 10; } @@ -1853,8 +2025,9 @@ int ARegion::NotifySpell(Unit *caster, char const *spell, ARegionList *pRegs) forlist_reuse (&flist) { FactionPtr *fp = (FactionPtr *) elem; - fp->ptr->Event(AString(*(caster->name)) + " uses " + SkillStrs(sp) + - " in " + Print(pRegs) + "."); + stringstream tmp; + tmp << caster->name << " uses " << SkillStrs(sp) << " in " << Print(pRegs) << "."; + fp->ptr->event(tmp.str()); } return 1; } @@ -1879,8 +2052,9 @@ void ARegion::NotifyCity(Unit *caster, AString& oldname, AString& newname) { forlist(&flist) { FactionPtr *fp = (FactionPtr *) elem; - fp->ptr->Event(AString(*(caster->name)) + " renames " + - oldname + " to " + newname + "."); + stringstream tmp; + tmp << caster->name << " renames " << oldname << " to " << newname << "."; + fp->ptr->event(tmp.str()); } } } diff --git a/aregion.h b/aregion.h index 85588a8b..63f07a68 100644 --- a/aregion.h +++ b/aregion.h @@ -201,7 +201,7 @@ class ARegion : public AListElem void WriteMarkets(ostream& f, Faction *, int); void WriteEconomy(ostream& f, Faction *, int); void WriteExits(ostream& f, ARegionList *pRegs, int *exits_seen); - void WriteReport(ostream& f, Faction *fac, int month, ARegionList *pRegions); + void write_text_report(ostream& f, Faction *fac, int month, ARegionList *pRegions); void write_json_report(json& j, Faction *fac, int month, ARegionList *pRegions); // DK void WriteTemplate(ostream& f, Faction *, ARegionList *, int); diff --git a/battle.cpp b/battle.cpp index 5f2a35b7..d9af070c 100644 --- a/battle.cpp +++ b/battle.cpp @@ -119,18 +119,8 @@ void WriteStats(Battle &battle, Army &army, StatsCategory category) { } } -Battle::Battle() -{ - asstext = 0; -} - -Battle::~Battle() -{ - if (asstext) - { - delete asstext; - } -} +Battle::Battle() { } +Battle::~Battle() { } // Checks if army A is overwhelmed by army B bool IsArmyOverwhelmedBy(Army * a, Army * b) { @@ -607,10 +597,10 @@ int Battle::Run(Events* events, (!armies[1]->NumAlive() && armies[0]->NumAlive())) { if (ass) { assassination = ASS_SUCC; - asstext = new AString(*(armies[1]->leader->name) + - " is assassinated in " + - region->ShortPrint( pRegs ) + - "!"); + asstext = armies[1]->leader->name->const_str(); + asstext += " is assassinated in "; + asstext += region->ShortPrint(pRegs).const_str(); + asstext += "!"; } if (armies[1]->NumAlive()) { AddLine(*(armies[1]->leader->name) + " is routed!"); @@ -742,19 +732,28 @@ void Battle::WriteSides(ARegion * r, AddLine(""); } -void Battle::Report(ostream& f,Faction * fac) { +void Battle::write_json_report(json& j, Faction *fac) { + if(assassination == ASS_SUCC && fac != attacker) { + j["type"] = "assassination"; + j["report"] = asstext; + return; + } + j["type"] = "battle"; + j["report"] = text; +} + +void Battle::write_text_report(ostream& f,Faction * fac) { if (assassination == ASS_SUCC && fac != attacker) { - f << asstext->const_str() << "\n"; + f << asstext << "\n"; return; } - forlist(&text) { - f << ((AString *)elem)->const_str() << '\n'; + for(auto line: text) { + f << line << '\n'; } } void Battle::AddLine(const AString & s) { - AString * temp = new AString(s); - text.Add(temp); + text.push_back(s.const_str()); } void Game::GetDFacs(ARegion * r,Unit * t,AList & facs) @@ -1158,15 +1157,12 @@ int Game::RunBattle(ARegion * r,Unit * attacker,Unit * target,int ass, Battle * b = new Battle; b->WriteSides(r,attacker,target,&atts,&defs,ass, ®ions ); - battles.Add(b); + battles.push_back(b); { forlist(&factions) { Faction * f = (Faction *) elem; - if (GetFaction2(&afacs,f->num) || GetFaction2(&dfacs,f->num) || - r->Present(f)) { - BattlePtr * p = new BattlePtr; - p->ptr = b; - f->battles.Add(p); + if (GetFaction2(&afacs,f->num) || GetFaction2(&dfacs,f->num) || r->Present(f)) { + f->battles.push_back(b); } } } diff --git a/battle.h b/battle.h index ed166edf..3f7bb11b 100644 --- a/battle.h +++ b/battle.h @@ -35,6 +35,9 @@ class Battle; #include "events.h" #include +#include "external/nlohmann/json.hpp" +using json = nlohmann::json; + enum { ASS_NONE, ASS_SUCC, @@ -48,19 +51,14 @@ enum { BATTLE_DRAW }; -class BattlePtr : public AListElem -{ - public: - Battle * ptr; -}; - class Battle : public AListElem { public: Battle(); ~Battle(); - void Report(ostream& f,Faction *fac); + void write_text_report(ostream& f, Faction *fac); + void write_json_report(json &j, Faction *fac); void AddLine(const AString &); int Run(Events* events, ARegion *, Unit *, AList *, Unit *, AList *, int ass, @@ -86,8 +84,8 @@ class Battle : public AListElem int assassination; Faction * attacker; /* Only matters in the case of an assassination */ - AString * asstext; - AList text; + std::string asstext; + std::vector text; }; #endif diff --git a/faction.cpp b/faction.cpp index 07eaf63b..4c800d67 100644 --- a/faction.cpp +++ b/faction.cpp @@ -27,8 +27,11 @@ #include "game.h" #include "indenter.hpp" #include +#include #include +using namespace std; + char const *as[] = { "Hostile", "Unfriendly", @@ -191,8 +194,12 @@ void Faction::Writeout(ostream& f) { f << num << '\n'; + // Right now, the faction type data in the file is what determines npc/non-npc with -1 in the types + // signifying NPCs. We should eventually persist the is_npc flag directly, but for now, let's just + // not break things. Having it based on the faction type data is pretty bogus, but it's what we + // have for now so if this is an NPC faction, right out -1 for all types. for (auto &ft : *FactionTypes) { - f << type[ft] << '\n'; + f << (is_npc ? -1 : type[ft]) << '\n'; } f << lastchange << '\n'; @@ -219,6 +226,11 @@ void Faction::Readin(istream& f) for (auto &ft : *FactionTypes) { f >> type[ft]; } + // Right now, the faction type data in the file is what determines npc/non-npc. + // We should eventually persist this flag directly, but for now, let's just not break things. + // Having it based on the faction type data is pretty bogus, but it's what we have for now. + // A faction is an NPC if it has -1 for either MARTIAL or WAR (NPCs will actually have -1 for all types) + is_npc = ((type[F_WAR] == -1) || (type[F_MARTIAL] == -1)); f >> lastchange; f >> lastorders; @@ -285,7 +297,7 @@ void Faction::SetAddress(AString &strNewAddress) AString Faction::FactionTypeStr() { AString temp; - if (IsNPC()) return AString("NPC"); + if (is_npc) return AString("NPC"); if (Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_UNLIMITED) { return (AString("Unlimited")); @@ -340,7 +352,7 @@ vector Faction::compute_faction_statistics(Game *game, size_t } inline bool Faction::gets_gm_report(Game *game) { - return IsNPC() && num == 1 && (Globals->GM_REPORT || (game->month == 0 && game->year == 1)); + return is_npc && num == 1 && (Globals->GM_REPORT || (game->month == 0 && game->year == 1)); } struct GmData { @@ -411,14 +423,14 @@ void Faction::write_text_gm_report(ostream& f, Game *game) { { // extra block because of foreach macro. forlist(&present_regions) { - ((ARegionPtr*)elem)->ptr->WriteReport(f, this, game->month, &(game->regions)); + ((ARegionPtr*)elem)->ptr->write_text_report(f, this, game->month, &(game->regions)); } } present_regions.DeleteAll(); - errors.DeleteAll(); - events.DeleteAll(); - battles.DeleteAll(); + errors.clear(); + events.clear(); + battles.clear(); } void Faction::write_json_gm_report(json& j, Game *game) { @@ -457,9 +469,9 @@ void Faction::write_json_gm_report(json& j, Game *game) { j["regions"] = regions; present_regions.DeleteAll(); - errors.DeleteAll(); - events.DeleteAll(); - battles.DeleteAll(); + errors.clear(); + events.clear(); + battles.clear(); } void Faction::write_json_report(json& j, Game *game, size_t **citems) { @@ -473,12 +485,10 @@ void Faction::write_json_report(json& j, Game *game, size_t **citems) { } // This can be better, but for now.. - AString engine_ver = ATL_VER_STRING(CURRENT_ATL_VER); - AString rules_ver = ATL_VER_STRING(Globals->RULESET_VERSION); j["engine"] = { - { "version", engine_ver.const_str() }, + { "version", (ATL_VER_STRING(CURRENT_ATL_VER)).const_str() }, { "ruleset", Globals->RULESET_NAME }, - { "ruleset_version", rules_ver.const_str() } + { "ruleset_version", (ATL_VER_STRING(Globals->RULESET_VERSION)).const_str() } }; string s = name->const_str(); @@ -498,7 +508,7 @@ void Faction::write_json_report(json& j, Game *game, size_t **citems) { j["password_unset"] = (!password || *password == "none"); if(Globals->MAX_INACTIVE_TURNS) { int cturn = game->TurnNumber() - lastorders; - if ((cturn >= (Globals->MAX_INACTIVE_TURNS - 3)) && !IsNPC()) { + if ((cturn >= (Globals->MAX_INACTIVE_TURNS - 3)) && !is_npc) { cturn = Globals->MAX_INACTIVE_TURNS - cturn; j["administrative"]["inactivity_deletion_turns"] = cturn; } @@ -566,40 +576,27 @@ void Faction::write_json_report(json& j, Game *game, size_t **citems) { } } - // Handle errors, battles, events etc in the next cuts. - /* - if (errors.Num()) { + if (!errors.empty()) { // Handle errors better. For now, just put them into an 'errors' vector. // We could give nice json'y output like which unit, which region, etc. - j["errors"] = json::array(); - forlist((&errors)) { - j["errors"].push_back(((AString *)elem)->const_str()); - } - errors.DeleteAll(); + j["errors"] = errors; } - if (battles.Num()) { + if (!battles.empty()) { json jbattles = json::array(); - forlist(&battles) { + for(auto battle: battles) { json jbattle = json::object(); // we will obviously want to make this into json-y output - ((BattlePtr *) elem)->ptr->report_json(jbattle, this); + battle->write_json_report(jbattle, this); jbattles.push_back(jbattle); } j["battles"] = jbattles; - battles.DeleteAll(); } - if (events.Num()) { + if (!events.empty()) { // events can also be handled as json objects rather than just strings. - f << "Events during turn:\n"; - forlist((&events)) { - f << ((AString *) elem)->const_str() << '\n'; - } - events.DeleteAll(); - f << '\n'; + j["events"] = events; } - */ /* Attitudes */ j["attitudes"] = json::object(); @@ -695,7 +692,7 @@ void Faction::write_text_report(ostream& f, Game *pGame, size_t ** citems) if (Globals->MAX_INACTIVE_TURNS != -1) { int cturn = pGame->TurnNumber() - lastorders; - if ((cturn >= (Globals->MAX_INACTIVE_TURNS - 3)) && !IsNPC()) { + if ((cturn >= (Globals->MAX_INACTIVE_TURNS - 3)) && !is_npc) { cturn = Globals->MAX_INACTIVE_TURNS - cturn; f << "WARNING: You have " << cturn << " turns until your faction is automatically removed due to inactivity!\n\n"; @@ -764,29 +761,22 @@ void Faction::write_text_report(ostream& f, Game *pGame, size_t ** citems) } f << '\n'; - if (errors.Num()) { + if (!errors.empty()) { f << "Errors during turn:\n"; - forlist((&errors)) { - f << ((AString *)elem)->const_str() << '\n'; - } - errors.DeleteAll(); + for(auto &error : errors) f << error << '\n'; f << '\n'; } - if (battles.Num()) { + if (!battles.empty()) { f << "Battles during turn:\n"; - forlist(&battles) { - ((BattlePtr *) elem)->ptr->Report(f, this); + for(auto battle: battles) { + battle->write_text_report(f, this); } - battles.DeleteAll(); } - if (events.Num()) { + if (!events.empty()) { f << "Events during turn:\n"; - forlist((&events)) { - f << ((AString *) elem)->const_str() << '\n'; - } - events.DeleteAll(); + for(auto &event: events) f << event << '\n'; f << '\n'; } @@ -835,7 +825,7 @@ void Faction::write_text_report(ostream& f, Game *pGame, size_t ** citems) f << "Unclaimed silver: " << unclaimed << ".\n\n"; forlist(&present_regions) { - ((ARegionPtr *) elem)->ptr->WriteReport(f, this, pGame->month, &(pGame->regions)); + ((ARegionPtr *) elem)->ptr->write_text_report(f, this, pGame->month, &(pGame->regions)); } f << '\n'; } @@ -845,7 +835,7 @@ void Faction::WriteTemplate(ostream& f, Game *pGame) { AString temp; if (temformat == TEMPLATE_OFF) return; - if (IsNPC()) return; + if (is_npc) return; f << indent::wrap; f << '\n'; @@ -893,7 +883,7 @@ void Faction::WriteFacInfo(ostream &f) void Faction::CheckExist(ARegionList* regs) { - if (IsNPC()) return; + if (is_npc) return; exists = 0; forlist(regs) { ARegion* reg = (ARegion *) elem; @@ -904,25 +894,17 @@ void Faction::CheckExist(ARegionList* regs) } } -void Faction::Error(const AString &s) -{ - if (IsNPC()) return; - if (errors.Num() > 1000) { - if (errors.Num() == 1001) { - errors.Add(new AString("Too many errors!")); - } - return; - } - - AString *temp = new AString(s); - errors.Add(temp); +void Faction::error(const string& s) { + if (is_npc) return; + auto count = errors.size(); + if (count == 1000) errors.push_back("Too many errors!"); + if (count < 1000) errors.push_back(s); } -void Faction::Event(const AString &s) +void Faction::event(const string& s) { - if (IsNPC()) return; - AString *temp = new AString(s); - events.Add(temp); + if (is_npc) return; + events.push_back(s); } void Faction::RemoveAttitude(int f) @@ -1052,24 +1034,11 @@ void Faction::DefaultOrders() void Faction::TimesReward() { if (Globals->TIMES_REWARD) { - Event(AString("Times reward of ") + Globals->TIMES_REWARD + " silver."); + event("Times reward of " + to_string(Globals->TIMES_REWARD) + " silver."); unclaimed += Globals->TIMES_REWARD; } } -void Faction::SetNPC() -{ - for (auto &ft : *FactionTypes) { - type[ft] = -1; - } -} - -int Faction::IsNPC() -{ - if (type[F_WAR] == -1 || type[F_MARTIAL] == -1) return 1; - return 0; -} - Faction *GetFaction(AList *facs, int n) { forlist(facs) diff --git a/faction.h b/faction.h index b39e07e1..8fa152a1 100644 --- a/faction.h +++ b/faction.h @@ -168,8 +168,8 @@ class Faction : public AListElem void SetAddress( AString &strNewAddress ); void CheckExist(ARegionList *); - void Error(const AString &); - void Event(const AString &); + void error(const string& s); + void event(const string& s); AString FactionTypeStr(); void write_text_report(ostream& f, Game *pGame, size_t **citems); @@ -191,8 +191,7 @@ class Faction : public AListElem void DefaultOrders(); void TimesReward(); - void SetNPC(); - int IsNPC(); + bool is_npc = false; // by default factions are not NPCs void DiscoverItem(int item, int force, int full); @@ -238,6 +237,7 @@ class Faction : public AListElem AList present_regions; int defaultattitude; + // TODO: Convert this to a hashmap of > AList attitudes; SkillList skills; ItemList items; @@ -246,10 +246,10 @@ class Faction : public AListElem // Both are lists of AStrings // AList extraPlayers; - AList errors; - AList events; - AList battles; + vector errors; + vector events; + vector battles; vector shows; vector itemshows; vector objectshows; diff --git a/game.cpp b/game.cpp index 6552329a..56864882 100644 --- a/game.cpp +++ b/game.cpp @@ -92,7 +92,7 @@ void Game::DefaultWorkOrder() Object *o = (Object *) elem; forlist(&o->units) { Unit *u = (Unit *) elem; - if (u->monthorders || u->faction->IsNPC() || + if (u->monthorders || u->faction->is_npc || (Globals->TAX_PILLAGE_MONTH_LONG && u->taxing != TAX_NONE)) continue; @@ -759,7 +759,7 @@ int Game::ReadPlayersLine(AString *pToken, AString *pLine, Faction *pFac, } else if (*pToken == "Reward:") { pTemp = pLine->gettoken(); int nAmt = pTemp->value(); - pFac->Event(AString("Reward of ") + nAmt + " silver."); + pFac->event("Reward of " + to_string(nAmt) + " silver."); pFac->unclaimed += nAmt; } else if (*pToken == "SendTimes:") { // get the token, but otherwise ignore it @@ -1069,7 +1069,7 @@ int Game::RunGame() Awrite("Writing order templates..."); WriteTemplates(); Awrite(""); - battles.DeleteAll(); + battles.clear(); EmptyHell(); @@ -1136,7 +1136,7 @@ void Game::ReadOrders() { forlist(&factions) { Faction *fac = (Faction *) elem; - if (!fac->IsNPC()) { + if (!fac->is_npc) { AString str = "orders."; str += fac->num; @@ -1213,7 +1213,7 @@ void Game::WriteReport() Faction *fac = (Faction *) elem; string str = "report." + to_string(fac->num); - if (!fac->IsNPC() || fac->gets_gm_report(this)) { + if (!fac->is_npc || fac->gets_gm_report(this)) { if (Globals->REPORT_FORMAT & GameDefs::REPORT_FORMAT_TEXT) { ofstream f(str, ios::out|ios::ate); if (f.is_open()) { @@ -1244,7 +1244,7 @@ void Game::WriteTemplates() { forlist(&factions) { Faction *fac = (Faction *) elem; - if (!fac->IsNPC()) { + if (!fac->is_npc) { string str = "template." + to_string(fac->num); ofstream f(str.c_str(), ios::out|ios::ate); if (f.is_open()) { @@ -1261,7 +1261,7 @@ void Game::DeleteDeadFactions() { forlist(&factions) { Faction *fac = (Faction *) elem; - if (!fac->IsNPC() && !fac->exists) { + if (!fac->is_npc && !fac->exists) { factions.Remove(fac); forlist((&factions)) ((Faction *) elem)->RemoveAttitude(fac->num); @@ -1453,8 +1453,7 @@ void Game::RemoveInactiveFactions() cturn = TurnNumber(); forlist(&factions) { Faction *fac = (Faction *) elem; - if ((cturn - fac->lastorders) >= Globals->MAX_INACTIVE_TURNS && - !fac->IsNPC()) { + if ((cturn - fac->lastorders) >= Globals->MAX_INACTIVE_TURNS && !fac->is_npc) { fac->quit = QUIT_BY_GM; } } @@ -1863,7 +1862,7 @@ void Game::CreateNPCFactions() guardfaction = f->num; temp = new AString("The Guardsmen"); f->SetName(temp); - f->SetNPC(); + f->is_npc = true; f->lastorders = 0; factions.Add(f); } else @@ -1875,7 +1874,7 @@ void Game::CreateNPCFactions() monfaction = f->num; temp = new AString("Creatures"); f->SetName(temp); - f->SetNPC(); + f->is_npc = true; f->lastorders = 0; factions.Add(f); } else @@ -2139,7 +2138,7 @@ void Game::CountItems(size_t ** citems) forlist (&factions) { Faction * fac = (Faction *) elem; - if (!fac->IsNPC()) + if (!fac->is_npc) { for (int j = 0; j < NITEMS; j++) { diff --git a/game.h b/game.h index c0fe7e72..05eeee35 100644 --- a/game.h +++ b/game.h @@ -295,7 +295,7 @@ class Game AList factions; AList newfactions; /* List of strings */ - AList battles; + vector battles; ARegionList regions; int factionseq; unsigned int unitseq; diff --git a/gamedefs.cpp b/gamedefs.cpp index 286dc738..648a01f3 100644 --- a/gamedefs.cpp +++ b/gamedefs.cpp @@ -23,6 +23,7 @@ // // END A3HEADER #include "gamedefs.h" +#include char const *dr[] = { "North", @@ -63,11 +64,9 @@ char const *mn[] = { char const ** MonthNames = mn; -char const *weath[] = { +std::string SeasonNames[] = { "clear", "winter", "monsoon season", "blizzard" }; - -char const ** SeasonNames = weath; diff --git a/gamedefs.h b/gamedefs.h index 87d0d106..73b5d3e6 100644 --- a/gamedefs.h +++ b/gamedefs.h @@ -26,6 +26,7 @@ #ifndef GAME_DEFS #define GAME_DEFS +#include #include "helper.h" /* Directions */ @@ -44,7 +45,7 @@ extern char const **DirectionAbrs; extern char const **MonthNames; -extern char const **SeasonNames; +extern std::string SeasonNames[]; extern int *allowedMages; extern int allowedMagesSize; diff --git a/havilah/extra.cpp b/havilah/extra.cpp index 9bfd7e1b..5474b83c 100644 --- a/havilah/extra.cpp +++ b/havilah/extra.cpp @@ -594,7 +594,7 @@ Faction *Game::CheckVictory() f = (Faction *) elem; // No accidentally sending all the Guardsmen // or Creatures to the Eternal City! - if (f->IsNPC()) + if (f->is_npc) continue; reliccount = 0; forlist(®ions) { @@ -674,7 +674,7 @@ Faction *Game::CheckVictory() temp += " and returned to the Eternal City."; message = AString("You") + temp; times = *f->name + temp; - f->Event(message); + f->event(message.const_str()); message = "You"; times += "\n\nThey"; temp = " returned after "; @@ -750,7 +750,7 @@ Faction *Game::CheckVictory() times += " They"; times += temp; } - f->Event(message); + f->event(message.const_str()); WriteTimesArticle(times); string filename = "winner." + to_string(f->num); diff --git a/monthorders.cpp b/monthorders.cpp index 84475dca..a0c64a8b 100644 --- a/monthorders.cpp +++ b/monthorders.cpp @@ -330,23 +330,18 @@ Location *Game::Do1SailOrder(ARegion *reg, Object *fleet, Unit *cap) forlist_reuse(&facs) { Faction * f = ((FactionPtr *) elem)->ptr; - if (x->dir == MOVE_PAUSE) { - f->Event(*fleet->name + - AString(" performs maneuvers in ") + - reg->ShortPrint(®ions) + - AString(".")); - } else { - f->Event(*fleet->name + - AString(" sails from ") + - reg->ShortPrint(®ions) + - AString(" to ") + - newreg->ShortPrint(®ions) + - AString(".")); + stringstream tmp; + tmp << fleet->name << (x->dir == MOVE_PAUSE ? " performs maneuvers in " : " sails from ") + << reg->ShortPrint(®ions); + if(x->dir != MOVE_PAUSE) { + tmp << " to " << newreg->ShortPrint(®ions); } + tmp << "."; + f->event(tmp.str()); } if (Globals->TRANSIT_REPORT != GameDefs::REPORT_NOTHING && x->dir != MOVE_PAUSE) { - if (!(cap->faction->IsNPC())) newreg->visited = 1; + if (!(cap->faction->is_npc)) newreg->visited = 1; forlist(&fleet->units) { // Everyone onboard gets to see the sights unit = (Unit *) elem; @@ -371,10 +366,9 @@ Location *Game::Do1SailOrder(ARegion *reg, Object *fleet, Unit *cap) } reg = newreg; if (newreg->ForbiddenShip(fleet)) { - cap->faction->Event(*fleet->name + - AString(" is stopped by guards in ") + - newreg->ShortPrint(®ions) + - AString(".")); + stringstream tmp; + tmp << fleet->name << " is stopped by guards in " << newreg->ShortPrint(®ions) << "."; + cap->faction->event(tmp.str()); stop = 1; } o->dirs.Remove(x); @@ -2000,7 +1994,7 @@ Location *Game::DoAMoveOrder(Unit *unit, ARegion *region, Object *obj) // TODO: Should we get a transit report on the starting region? if (Globals->TRANSIT_REPORT != GameDefs::REPORT_NOTHING) { - if (!(unit->faction->IsNPC())) newreg->visited = 1; + if (!(unit->faction->is_npc)) newreg->visited = 1; // Update our visit record in the region we are leaving. Farsight *f; forlist(®ion->passers) { diff --git a/object.cpp b/object.cpp index 9cfb5340..5554b135 100644 --- a/object.cpp +++ b/object.cpp @@ -156,7 +156,7 @@ void Object::Readin(istream& f, AList *facs) if (!temp->faction) continue; temp->MoveUnit(this); - if (!(temp->faction->IsNPC())) region->visited = 1; + if (!(temp->faction->is_npc)) region->visited = 1; } mages = ObjectDefs[type].maxMages; ReadinFleet(f); diff --git a/parseorders.cpp b/parseorders.cpp index 6a5d275f..998b9fef 100644 --- a/parseorders.cpp +++ b/parseorders.cpp @@ -197,7 +197,7 @@ void Game::ParseError(OrdersCheck *pCheck, Unit *pUnit, Faction *pFaction, { if (pCheck) pCheck->Error(strError); else if (pUnit) pUnit->Error(strError); - else if (pFaction) pFaction->Error(strError); + else if (pFaction) pFaction->error(strError.const_str()); } void Game::ParseOrders(int faction, istream& f, OrdersCheck *pCheck) @@ -321,7 +321,9 @@ void Game::ParseOrders(int faction, istream& f, OrdersCheck *pCheck) } else { unit = GetUnit(token->value()); if (!unit || unit->faction != fac) { - fac->Error(*token + " is not your unit."); + // as we get rid of more uses of astring, these will become unnecessary + string tmp(token->const_str()); + fac->error(tmp + " is not your unit."); unit = 0; } else { unit->ClearOrders(); @@ -659,10 +661,12 @@ void Game::ProcessPasswordOrder(Unit *u, AString *o, OrdersCheck *pCheck) if (u->faction->password) delete u->faction->password; if (token) { u->faction->password = token; - u->faction->Event(AString("Password is now: ") + *token); + string tmp = "Password is now: "; + tmp += token->const_str(); + u->faction->event(tmp); } else { u->faction->password = new AString("none"); - u->faction->Event("Password cleared."); + u->faction->event("Password cleared."); } } @@ -677,7 +681,7 @@ void Game::ProcessOptionOrder(Unit *u, AString *o, OrdersCheck *pCheck) if (*token == "times") { delete token; if (!pCheck) { - u->faction->Event("Times will be sent to your faction."); + u->faction->event("Times will be sent to your faction."); u->faction->times = 1; } return; @@ -686,7 +690,7 @@ void Game::ProcessOptionOrder(Unit *u, AString *o, OrdersCheck *pCheck) if (*token == "notimes") { delete token; if (!pCheck) { - u->faction->Event("Times will not be sent to your faction."); + u->faction->event("Times will not be sent to your faction."); u->faction->times = 0; } return; @@ -695,8 +699,7 @@ void Game::ProcessOptionOrder(Unit *u, AString *o, OrdersCheck *pCheck) if (*token == "showattitudes") { delete token; if (!pCheck) { - u->faction->Event("Units will now have a leading sign to show your " - "attitude to them."); + u->faction->event("Units will now have a leading sign to show your attitude to them."); u->faction->showunitattitudes = 1; } return; @@ -705,8 +708,7 @@ void Game::ProcessOptionOrder(Unit *u, AString *o, OrdersCheck *pCheck) if (*token == "dontshowattitudes") { delete token; if (!pCheck) { - u->faction->Event("Units will now have a leading minus sign regardless" - " of your attitude to them."); + u->faction->event("Units will now have a leading minus sign regardless of your attitude to them."); u->faction->showunitattitudes = 0; } return; @@ -1299,13 +1301,13 @@ void Game::ProcessQuitOrder(Unit *u, AString *o, OrdersCheck *pCheck) if (u->faction->password && !(*(u->faction->password) == "none")) { AString *token = o->gettoken(); if (!token) { - u->faction->Error("QUIT: Must give the correct password."); + u->faction->error("QUIT: Must give the correct password."); return; } if (!(*token == *(u->faction->password))) { delete token; - u->faction->Error("QUIT: Must give the correct password."); + u->faction->error("QUIT: Must give the correct password."); return; } @@ -1324,13 +1326,13 @@ void Game::ProcessRestartOrder(Unit *u, AString *o, OrdersCheck *pCheck) if (u->faction->password && !(*(u->faction->password) == "none")) { AString *token = o->gettoken(); if (!token) { - u->faction->Error("RESTART: Must give the correct password."); + u->faction->error("RESTART: Must give the correct password."); return; } if (!(*token == *(u->faction->password))) { delete token; - u->faction->Error("RESTART: Must give the correct password."); + u->faction->error("RESTART: Must give the correct password."); return; } @@ -1908,7 +1910,7 @@ void Game::ProcessDeclareOrder(Faction *f, AString *o, OrdersCheck *pCheck) } else { fac = token->strict_value(); if (fac == -1) { - f->Error(AString("DECLARE: Non-existent faction.")); + f->error("DECLARE: Non-existent faction."); return; } } @@ -1919,12 +1921,11 @@ void Game::ProcessDeclareOrder(Faction *f, AString *o, OrdersCheck *pCheck) if (fac != -1) { target = GetFaction(&factions, fac); if (!target) { - f->Error(AString("DECLARE: Non-existent faction ")+fac+"."); + f->error("DECLARE: Non-existent faction " + to_string(fac) + "."); return; } if (target == f) { - f->Error(AString("DECLARE: Can't declare towards your own " - "faction.")); + f->error("DECLARE: Can't declare towards your own faction."); return; } } diff --git a/runorders.cpp b/runorders.cpp index 94fe6169..d1478928 100644 --- a/runorders.cpp +++ b/runorders.cpp @@ -296,11 +296,12 @@ void Game::Do1Assassinate(ARegion *r, Object *o, Unit *u) } } if (!succ) { - AString temp = *(u->name) + " is caught attempting to assassinate " + - *(tar->name) + " in " + *(r->name) + "."; + stringstream temp; + temp << u->name << " is caught attempting to assassinate " << tar->name << " in " << r->name << "."; + string temp2 = temp.str(); forlist(seers) { Faction *f = ((FactionPtr *) elem)->ptr; - f->Event(temp); + f->event(temp2); } // One learns from one's mistakes. Surviving them is another matter! u->PracticeAttribute("stealth"); @@ -370,11 +371,12 @@ void Game::Do1Steal(ARegion *r, Object *o, Unit *u) } if (!succ) { - AString temp = *(u->name) + " is caught attempting to steal from " + - *(tar->name) + " in " + *(r->name) + "."; + stringstream temp; + temp << u->name << " is caught attempting to steal from " << tar->name << " in " << r->name << "."; + string temp2 = temp.str(); forlist(seers) { Faction *f = ((FactionPtr *) elem)->ptr; - f->Event(temp); + f->event(temp2); } // One learns from one's mistakes. Surviving them is another matter! u->PracticeAttribute("stealth"); @@ -408,11 +410,12 @@ void Game::Do1Steal(ARegion *r, Object *o, Unit *u) tar->items.SetNum(so->item, tar->items.GetNum(so->item) - amt); { - AString temp = *(u->name) + " steals " + - ItemString(so->item, amt) + " from " + *(tar->name) + "."; + stringstream temp; + temp << u->name << " steals " << ItemString(so->item, amt) << " from " << tar->name << "."; + string temp2 = temp.str(); forlist(seers) { Faction *f = ((FactionPtr *) elem)->ptr; - f->Event(temp); + f->event(temp2); } } @@ -639,8 +642,9 @@ void Game::RunFindUnit(Unit *u) if (!all) { fac = GetFaction(&factions, f->find); if (fac) { - u->faction->Event(AString("The address of ") + *(fac->name) + - " is " + *(fac->address) + "."); + stringstream temp; + temp << "The address of " << fac->name << " is " << fac->address << "."; + u->faction->event(temp.str()); } else { u->Error(AString("FIND: ") + f->find + " is not a valid " "faction number."); @@ -649,8 +653,9 @@ void Game::RunFindUnit(Unit *u) forlist(&factions) { fac = (Faction *)elem; if (fac) { - u->faction->Event(AString("The address of ") + - *(fac->name) + " is " + *(fac->address) + "."); + stringstream temp; + temp << "The address of " << fac->name << " is " << fac->address << "."; + u->faction->event(temp.str()); } } } @@ -844,8 +849,9 @@ void Game::RunPillageRegion(ARegion *reg) forlist(facs) { Faction *fp = ((FactionPtr *) elem)->ptr; if (fp != u->faction) { - fp->Event(*(u->name) + " pillages " + - *(reg->name) + "."); + stringstream temp; + temp << u->name << " pillages " << reg->name << "."; + fp->event(temp.str()); } } } @@ -1168,10 +1174,11 @@ void Game::EndGame(Faction *pVictor) else pFac->quit = QUIT_GAME_OVER; - if (pVictor) - pFac->Event(*(pVictor->name) + " has won the game!"); - else - pFac->Event("The game has ended with no winner."); + if (pVictor) { + string temp(pVictor->name->const_str()); + pFac->event(temp + " has won the game!"); + } else + pFac->event("The game has ended with no winner."); } gameStatus = GAME_STATUS_FINISHED; @@ -2023,7 +2030,7 @@ void Game::AssessMaintenance() Object *obj = (Object *) elem; forlist((&obj->units)) { Unit *u = (Unit *) elem; - if (!(u->faction->IsNPC())) { + if (!(u->faction->is_npc)) { r->visited = 1; if (quests.CheckQuestVisitTarget(r, u, &quest_rewards)) { u->Event(AString("You have completed a pilgrimage!") + quest_rewards); @@ -2576,7 +2583,7 @@ int Game::DoGiveOrder(ARegion *r, Unit *u, GiveOrder *o) u->Error(ord + ": " + o->target->Print() + " is not a member of your faction."); return 0; - } else if (u->faction != t->faction && t->faction->IsNPC()) { + } else if (u->faction != t->faction && t->faction->is_npc) { u->Error(ord + ": Can't give to non-player unit (" + o->target->Print() + ")."); return 0; @@ -2822,7 +2829,7 @@ int Game::DoGiveOrder(ARegion *r, Unit *u, GiveOrder *o) u->Error(ord + ": " + o->target->Print() + " is not a member of your faction."); return 0; - } else if (u->faction != t->faction && t->faction->IsNPC()) { + } else if (u->faction != t->faction && t->faction->is_npc) { u->Error(ord + ": Can't give to non-player unit (" + o->target->Print() + ")."); return 0; diff --git a/unit.cpp b/unit.cpp index 88644819..c5e8ff6d 100644 --- a/unit.cpp +++ b/unit.cpp @@ -1588,7 +1588,7 @@ void Unit::Short(int needed, int hunger) { int i, n = 0, levels; - if (faction->IsNPC()) + if (faction->is_npc) return; // Don't starve monsters and the city guard! if (needed < 1 && hunger < 1) return; @@ -2462,14 +2462,14 @@ void Unit::DiscardUnfinishedShips() { void Unit::Event(const AString & s) { - AString temp = *name + ": " + s; - faction->Event(temp); + string temp(name->const_str()); + faction->event(temp + ": " + s.const_str()); } void Unit::Error(const AString & s) { - AString temp = *name + ": " + s; - faction->Error(temp); + string temp(name->const_str()); + faction->error(temp + ": " + s.const_str()); } int Unit::GetAttribute(char const *attrib) diff --git a/unittest/json_report_test.cpp b/unittest/json_report_test.cpp index e736e79d..8cb1888c 100644 --- a/unittest/json_report_test.cpp +++ b/unittest/json_report_test.cpp @@ -19,7 +19,7 @@ ut::suite<"JSON Report"> json_report_suite = [] { using namespace ut; - "Report contains basic faction information for a new faction"_test = [] + "Faction json contains basic faction information"_test = [] { UnitTestHelper helper; helper.initialize_game(); @@ -38,18 +38,135 @@ ut::suite<"JSON Report"> json_report_suite = [] // pick some of the data out of the report for checking string data_name = json_report["name"]; int data_num = json_report["number"]; - string data_month = json_report["date"]["month"]; - int new_items = json_report["item_reports"].size(); - int new_skills = json_report["skill_reports"].size(); - int regions = json_report["regions"].size(); + auto new_items = json_report["item_reports"].size(); + auto new_skills = json_report["skill_reports"].size(); + auto regions = json_report["regions"].size(); - expect(data_name == name); - expect(data_num == 3_i); - expect(new_items == 1_i); // should just be the new leader - expect(new_skills == 3_i); // should be combat 1, 2, and 3 - expect(regions == 1_i); // and we should only have 1 region we know about (our start region) + expect(data_name == name); // faction name should match our name. + expect(data_num == 3_i); // faction num should be 3 since we have guards and wandering monsters. + expect(new_items == 1_ul); // should just be the new leader + expect(new_skills == 3_ul); // should be combat 1, 2, and 3 based on the test game setup. + // Verify that the game date is correct. string expected_month("January"); + string data_month = json_report["date"]["month"]; expect(data_month == expected_month); + + // Verify the basic region info is correct. + expect(regions == 1_ul); // and we should only have 1 region we know about (our start region) + }; + + "Errors are reported"_test = [] + { + UnitTestHelper helper; + helper.initialize_game(); + helper.setup_turn(); + + Faction *faction = helper.create_faction("Test Faction"); + faction->error("This is an error"); + + json json_report; + faction->write_json_report(json_report, &helper.game_object(), nullptr); + + auto count = json_report["errors"].size(); + expect(count == 1_ul); + string error = json_report["errors"][0]; + string expected = "This is an error"; + expect(error == expected); + }; + + "More than 1000 errors will log a too many errors and ignore the rest"_test = [] + { + UnitTestHelper helper; + helper.initialize_game(); + helper.setup_turn(); + + Faction *faction = helper.create_faction("Test Faction"); + for(auto i = 0; i < 1003; i++) faction->error("This is error #" + to_string(i+1)); + + json json_report; + faction->write_json_report(json_report, &helper.game_object(), nullptr); + + auto count = json_report["errors"].size(); + expect(count == 1001_ul); + string error = json_report["errors"][1000]; + string expected = "Too many errors!"; + expect(error == expected); + + error = json_report["errors"][999]; + expected = "This is error #1000"; + expect(error == expected); }; + + "Events are reported"_test = [] + { + UnitTestHelper helper; + helper.initialize_game(); + helper.setup_turn(); + + Faction *faction = helper.create_faction("Test Faction"); + faction->event("This is event 1"); + faction->event("This is event 2"); + + json json_report; + faction->write_json_report(json_report, &helper.game_object(), nullptr); + + auto count = json_report["events"].size(); + expect(count == 2_ul); + + // make sure they are in the right order + string event = json_report["events"][0]; + string expected = "This is event 1"; + expect(event == expected); + + event = json_report["events"][1]; + expected = "This is event 2"; + expect(event == expected); + }; + + + "Region json contains basic region information"_test = [] + { + UnitTestHelper helper; + helper.initialize_game(); + helper.setup_turn(); + + helper.setup_reports(); + + // Generate just this single regions json object. + Faction *faction = helper.create_faction("Test Faction"); + ARegion *region = helper.get_region(0, 0, 0); + ARegionList *regions = helper.get_regions(); + + json json_report; + region->write_json_report(json_report, faction, helper.get_month(), regions); + + string expected_provice("Testing Wilds"); // name given in the unit test setup + string province = json_report["province"]; + expect(province == expected_provice); + + string expected_terrain("plain"); // should be the terrain set up in the unit test + string terrain = json_report["terrain"]; + expect(terrain == expected_terrain); + + auto x = json_report["coordinates"]["x"]; + auto y = json_report["coordinates"]["y"]; + auto z = json_report["coordinates"]["z"]; + expect(x == 0_i); + expect(y == 0_i); + expect(z == 0_i); + + string expected_label("surface"); + string label = json_report["coordinates"]["label"]; + expect(label == expected_label); + + string settlement_name = json_report["settlement"]["name"]; + string expected_settlement_name("Basictown"); // name given in the unit test setup + expect(settlement_name == expected_settlement_name); + + string settlement_size = json_report["settlement"]["size"]; + string expected_settlement_size("city"); + expect(settlement_size == expected_settlement_size); + }; + }; diff --git a/unittest/testhelper.cpp b/unittest/testhelper.cpp index 38de1855..a9e9f51d 100644 --- a/unittest/testhelper.cpp +++ b/unittest/testhelper.cpp @@ -39,6 +39,11 @@ Faction *UnitTestHelper::create_faction(string name) { return fac; } +ARegion *UnitTestHelper::get_region(int x, int y, int z) { + ARegionArray *level = game.regions.pRegionArrays[z]; + return level->GetRegion(x, y); +} + string UnitTestHelper::cout_data() { return cout_buffer.str(); } diff --git a/unittest/testhelper.hpp b/unittest/testhelper.hpp index ff603282..7d279d37 100644 --- a/unittest/testhelper.hpp +++ b/unittest/testhelper.hpp @@ -33,6 +33,12 @@ class UnitTestHelper { int get_region_count(); // Create a faction that we can use for testing. Faction *create_faction(string name); + // Get a region by coordinates + ARegion *get_region(int x, int y, int level); + // Get all regions + ARegionList *get_regions() { return &game.regions; } + // get the game month + int get_month() { return game.month; } // Get the contents of cout as a string. string cout_data(); diff --git a/unittest/world.cpp b/unittest/world.cpp index a711b7f1..5a801e90 100644 --- a/unittest/world.cpp +++ b/unittest/world.cpp @@ -37,7 +37,7 @@ void Game::CreateWorld() { Awrite("Creating world"); regions.CreateLevels(1); // because of the way regions are numbered, if you want 4 hexes you need a height of 4 and a width of 2. - regions.CreateSurfaceLevel(0, 2, 4, "Surface"); + regions.CreateSurfaceLevel(0, 2, 4, nullptr); } int ARegionList::GetRegType( ARegion *pReg ) { return 0; }