From 86bca1424651deb17c1d4a0664cf99a355159262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valdis=20Zob=C4=93la?= Date: Wed, 21 Aug 2024 19:42:36 +0300 Subject: [PATCH 1/3] [WIP] regions are connected through the RegionEdge object --- Makefile | 12 +- aregion.cpp | 486 ++++++++++++------------- aregion.h | 151 +++++++- basic/map.cpp | 92 ++--- basic/world.cpp | 14 +- battle.cpp | 44 +-- economy.cpp | 156 ++++---- edges.cpp | 100 +++++ edit.cpp | 850 +++++++++++++++++++++---------------------- fracas/map.cpp | 92 ++--- fracas/world.cpp | 14 +- havilah/map.cpp | 118 +++--- havilah/world.cpp | 18 +- kingdoms/map.cpp | 144 ++++---- kingdoms/world.cpp | 14 +- monthorders.cpp | 84 ++--- neworigins/extra.cpp | 16 +- neworigins/world.cpp | 22 +- object.cpp | 24 +- orders.h | 2 +- runorders.cpp | 24 +- spells.cpp | 14 +- standard/map.cpp | 90 ++--- standard/world.cpp | 16 +- unit.cpp | 46 +-- 25 files changed, 1436 insertions(+), 1207 deletions(-) create mode 100644 edges.cpp diff --git a/Makefile b/Makefile index c001952b..8e6d1713 100644 --- a/Makefile +++ b/Makefile @@ -13,9 +13,9 @@ CPLUS = g++ CC = gcc CFLAGS = -g -I. -I.. -Wall -Werror -std=c++20 -RULESET_OBJECTS = extra.o map.o monsters.o rules.o world.o +RULESET_OBJECTS = extra.o map.o monsters.o rules.o world.o -ENGINE_OBJECTS = alist.o aregion.o army.o astring.o battle.o economy.o \ +ENGINE_OBJECTS = alist.o aregion.o edges.o army.o astring.o battle.o economy.o \ edit.o faction.o game.o gamedata.o gamedefs.o gameio.o \ genrules.o i_rand.o items.o main.o market.o modify.o monthorders.o \ npc.o object.o orders.o parseorders.o production.o quests.o runorders.o \ @@ -38,7 +38,7 @@ basic: FORCE standard: FORCE $(MAKE) GAME=standard - + kingdoms: FORCE $(MAKE) GAME=kingdoms @@ -65,7 +65,7 @@ standard-clean: fracas-clean: $(MAKE) GAME=fracas clean - + kingdoms-clean: $(MAKE) GAME=kingdoms clean @@ -97,7 +97,7 @@ standard-rules: fracas-rules: $(MAKE) GAME=fracas rules - + kingdoms-rules: $(MAKE) GAME=kingdoms rules @@ -117,7 +117,7 @@ unittest: $(MAKE) GAME=unittest unittest-build unittest-build: unittest-objdir $(filter-out obj/main.o,$(OBJECTS)) $(UNITTEST_OBJECTS) - $(CPLUS) $(CFLAGS) -o unittest/unittest $(filter-out obj/main.o,$(OBJECTS)) $(UNITTEST_OBJECTS) + $(CPLUS) $(CFLAGS) -o unittest/unittest $(filter-out obj/main.o,$(OBJECTS)) $(UNITTEST_OBJECTS) FORCE: diff --git a/aregion.cpp b/aregion.cpp index 2de22987..c9f88543 100644 --- a/aregion.cpp +++ b/aregion.cpp @@ -141,8 +141,6 @@ ARegion::ARegion() clearskies = 0; earthlore = 0; phantasmal_entertainment = 0; - for (int i=0; iptr = neighbors[j]; + p->ptr = neighbors(j); r2ptr->Add(p); } } @@ -295,10 +286,10 @@ void ARegion::MakeLair(int t) int ARegion::GetPoleDistance(int dir) { int ct = 1; - ARegion *nreg = neighbors[dir]; + ARegion *nreg = neighbors(dir); while (nreg) { ct++; - nreg = nreg->neighbors[dir]; + nreg = nreg->neighbors(dir); } return ct; } @@ -365,7 +356,7 @@ int ARegion::TraceConnectedRoad(int dir, int sum, AList *con, int range, int dev if (range > 0) { for (int d=0; dGetRealDirComp(d)) continue; if (HasConnectingRoad(d)) sum = r->TraceConnectedRoad(d, sum, con, range-1, dev+2); @@ -383,11 +374,11 @@ int ARegion::RoadDevelopmentBonus(int range, int dev) con->Add(rp); for (int d=0; dTraceConnectedRoad(d, bonus, con, range-1, dev); } - return bonus; + return bonus; } // AS @@ -658,7 +649,7 @@ int ARegion::CountConnectingRoads() { int connections = 0; for (int i = 0; i < NDIRS; i++) { - if (HasExitRoad(i) && neighbors[i] && + if (HasExitRoad(i) && neighbors(i) && HasConnectingRoad(i)) connections ++; } @@ -670,7 +661,7 @@ int ARegion::HasConnectingRoad(int realDirection) { int opposite = GetRealDirComp(realDirection); - if (neighbors[realDirection] && neighbors[realDirection]->HasExitRoad(opposite)) { + if (neighbors(realDirection) && neighbors(realDirection)->HasExitRoad(opposite)) { return 1; } @@ -709,10 +700,10 @@ int ARegion::GetRealDirComp(int realDirection) { int complementDirection = 0; - if (neighbors[realDirection]) { - ARegion *n = neighbors[realDirection]; + if (neighbors(realDirection)) { + ARegion *n = neighbors(realDirection); for (int i = 0; i < NDIRS; i++) - if (n->neighbors[i] == this) + if (n->neighbors(i) == this) return i; } @@ -1069,7 +1060,7 @@ void ARegion::Writeout(ostream& f) f << products.size() << '\n'; for (const auto& product : products) product->Writeout(f); f << markets.size() << '\n'; - for (const auto& market : markets) market->Writeout(f); + for (const auto& market : markets) market->Writeout(f); f << objects.Num() << '\n'; forlist ((&objects)) ((Object *) elem)->Writeout(f); @@ -1364,9 +1355,9 @@ void ARegion::build_json_report(json& j, Faction *fac, int month, ARegionList *r j["exits"] = json::array(); for (int i=0; ibasic_region_data() } } + { { "direction", DirectionStrs[i] }, { "region", neighbors(i)->basic_region_data() } } ); } @@ -1555,8 +1546,8 @@ int ARegion::IsCoastal() return 1; int seacount = 0; for (int i=0; itype].similar_type == R_OCEAN) { - if (!Globals->LAKESIDE_IS_COASTAL && neighbors[i]->type == R_LAKE) continue; + if (neighbors(i) && TerrainDefs[neighbors(i)->type].similar_type == R_OCEAN) { + if (!Globals->LAKESIDE_IS_COASTAL && neighbors(i)->type == R_LAKE) continue; seacount++; } } @@ -1568,7 +1559,7 @@ int ARegion::IsCoastalOrLakeside() if (TerrainDefs[type].similar_type == R_OCEAN) return 1; int seacount = 0; for (int i=0; itype].similar_type == R_OCEAN) { + if (neighbors(i) && TerrainDefs[neighbors(i)->type].similar_type == R_OCEAN) { seacount++; } } @@ -1817,7 +1808,7 @@ void ARegion::AddFleet(Object * fleet) objects.Add(fleet); //Awrite(AString("Setting up fleet alias #") + fleetalias + ": " + fleet->num); newfleets.insert(make_pair(fleetalias++, fleet->num)); - + } int ARegion::ResolveFleetAlias(int alias) @@ -1829,6 +1820,10 @@ int ARegion::ResolveFleetAlias(int alias) return f->second; } +ARegion* ARegion::neighbors(const int dir) { + return this->edges.get_neighbor(this, dir); +} + ARegionList::ARegionList() { pRegionArrays = 0; @@ -1868,7 +1863,7 @@ void ARegionList::WriteRegions(ostream& f) forlist(this) { ARegion *reg = (ARegion *) elem; for (int i = 0; i < NDIRS; i++) { - f << (reg->neighbors[i] ? reg->neighbors[i]->num : -1) << '\n'; + f << (reg->neighbors(i) ? reg->neighbors(i)->num : -1) << '\n'; } } } @@ -1922,9 +1917,9 @@ int ARegionList::ReadRegions(istream &f, AList *factions) int j; f >> j; if (j != -1) { - reg->neighbors[i] = fa.GetRegion(j); + reg->neighbors(i) = fa.GetRegion(j); } else { - reg->neighbors[i] = 0; + reg->neighbors(i) = 0; } } } @@ -1994,199 +1989,200 @@ void ARegionList::NeighSetup(ARegion *r, ARegionArray *ar) } } +[[deprecated("Icosahedral world is no longer supported")]] void ARegionList::IcosahedralNeighSetup(ARegion *r, ARegionArray *ar) { - int scale, x, y, x2, y2, x3, neighX, neighY; - - scale = ar->x / 10; - - r->ZeroNeighbors(); - - y = r->yloc; - x = r->xloc; - // x2 is the x-coord of this hex inside its "wedge" - if (y < 5 * scale) - x2 = x % (2 * scale); - else - x2 = (x + 1) % (2 * scale); - // x3 is the distance of this hex from the right side of its "wedge" - x3 = (2 * scale - x2) % (2 * scale); - // y2 is the distance from the SOUTH pole - y2 = 10 * scale - 1 - y; - // Always try to connect in the standard way... - if (y > 1) { - r->neighbors[D_NORTH] = ar->GetRegion(x, y - 2); - } - // but if that fails, use the special icosahedral connections: - if (!r->neighbors[D_NORTH]) { - if (y > 0 && y < 3 * scale) - { - if (y == 2) { - neighX = 0; - neighY = 0; - } - else if (y == 3 * x2) { - neighX = x + 2 * (scale - x2) + 1; - neighY = y - 1; - } - else { - neighX = x + 2 * (scale - x2); - neighY = y - 2; - } - neighX %= (scale * 10); - r->neighbors[D_NORTH] = ar->GetRegion(neighX, neighY); - } - } - if (y > 0) { - neighX = x + 1; - neighY = y - 1; - neighX %= (scale * 10); - r->neighbors[D_NORTHEAST] = ar->GetRegion(neighX, neighY); - } - if (!r->neighbors[D_NORTHEAST]) { - if (y == 0) { - neighX = 4 * scale; - neighY = 2; - } - else if (y < 3 * scale) { - if (y == 3 * x2) { - neighX = x + 2 * (scale - x2) + 1; - neighY = y + 1; - } - else { - neighX = x + 2 * (scale - x2); - neighY = y; - } - } - else if (y2 < 1) { - neighX = x + 2 * scale; - neighY = y - 2; - } - else if (y2 < 3 * scale) { - neighX = x + 2 * (scale - x2); - neighY = y - 2; - } - neighX %= (scale * 10); - r->neighbors[D_NORTHEAST] = ar->GetRegion(neighX, neighY); - } - if (y2 > 0) { - neighX = x + 1; - neighY = y + 1; - neighX %= (scale * 10); - r->neighbors[D_SOUTHEAST] = ar->GetRegion(neighX, neighY); - } - if (!r->neighbors[D_SOUTHEAST]) { - if (y == 0) { - neighX = 2 * scale; - neighY = 2; - } - else if (y2 < 1) { - neighX = x + 4 * scale; - neighY = y - 2; - } - else if (y2 < 3 * scale) { - if (y2 == 3 * x2) { - neighX = x + 2 * (scale - x2) + 1; - neighY = y - 1; - } - else { - neighX = x + 2 * (scale - x2); - neighY = y; - } - } - else if (y < 3 * scale) { - neighX = x + 2 * (scale - x2); - neighY = y + 2; - } - neighX %= (scale * 10); - r->neighbors[D_SOUTHEAST] = ar->GetRegion(neighX, neighY); - } - if (y2 > 1) { - r->neighbors[D_SOUTH] = ar->GetRegion(x, y + 2); - } - if (!r->neighbors[D_SOUTH]) { - if (y2 > 0 && y2 < 3 * scale) - { - if (y2 == 2) { - neighX = 10 * scale - 1; - neighY = y + 2; - } - else if (y2 == 3 * x2) { - neighX = x + 2 * (scale - x2) + 1; - neighY = y + 1; - } - else { - neighX = x + 2 * (scale - x2); - neighY = y + 2; - } - neighX = (neighX + scale * 10) % (scale * 10); - r->neighbors[D_SOUTH] = ar->GetRegion(neighX, neighY); - } - } - if (y2 > 0) { - neighX = x - 1; - neighY = y + 1; - neighX = (neighX + scale * 10) % (scale * 10); - r->neighbors[D_SOUTHWEST] = ar->GetRegion(neighX, neighY); - } - if (!r->neighbors[D_SOUTHWEST]) { - if (y == 0) { - neighX = 8 * scale; - neighY = 2; - } - else if (y2 < 1) { - neighX = x + 6 * scale; - neighY = y - 2; - } - else if (y2 < 3 * scale) { - if (y2 == 3 * x3 + 4) { - neighX = x + 2 * (x3 - scale) + 1; - neighY = y + 1; - } - else { - neighX = x + 2 * (x3 - scale); - neighY = y; - } - } - else if (y < 3 * scale) { - neighX = x - 2 * (scale - x3) + 1; - neighY = y + 1; - } - neighX = (neighX + scale * 10) % (scale * 10); - r->neighbors[D_SOUTHWEST] = ar->GetRegion(neighX, neighY); - } - if (y > 0) { - neighX = x - 1; - neighY = y - 1; - neighX = (neighX + scale * 10) % (scale * 10); - r->neighbors[D_NORTHWEST] = ar->GetRegion(neighX, neighY); - } - if (!r->neighbors[D_NORTHWEST]) { - if (y == 0) { - neighX = 6 * scale; - neighY = 2; - } - else if (y < 3 * scale) { - if (y == 3 * x3 + 4) { - neighX = x + 2 * (x3 - scale) + 1; - neighY = y - 1; - } - else { - neighX = x + 2 * (x3 - scale); - neighY = y; - } - } - else if (y2 < 1) { - neighX = x + 8 * scale; - neighY = y - 2; - } - else if (y2 < 3 * scale) { - neighX = x - 2 * (scale - x3) + 1; - neighY = y - 1; - } - neighX = (neighX + scale * 10) % (scale * 10); - r->neighbors[D_NORTHWEST] = ar->GetRegion(neighX, neighY); - } + // int scale, x, y, x2, y2, x3, neighX, neighY; + + // scale = ar->x / 10; + + // r->ZeroNeighbors(); + + // y = r->yloc; + // x = r->xloc; + // // x2 is the x-coord of this hex inside its "wedge" + // if (y < 5 * scale) + // x2 = x % (2 * scale); + // else + // x2 = (x + 1) % (2 * scale); + // // x3 is the distance of this hex from the right side of its "wedge" + // x3 = (2 * scale - x2) % (2 * scale); + // // y2 is the distance from the SOUTH pole + // y2 = 10 * scale - 1 - y; + // // Always try to connect in the standard way... + // if (y > 1) { + // r->neighbors[D_NORTH] = ar->GetRegion(x, y - 2); + // } + // // but if that fails, use the special icosahedral connections: + // if (!r->neighbors[D_NORTH]) { + // if (y > 0 && y < 3 * scale) + // { + // if (y == 2) { + // neighX = 0; + // neighY = 0; + // } + // else if (y == 3 * x2) { + // neighX = x + 2 * (scale - x2) + 1; + // neighY = y - 1; + // } + // else { + // neighX = x + 2 * (scale - x2); + // neighY = y - 2; + // } + // neighX %= (scale * 10); + // r->neighbors[D_NORTH] = ar->GetRegion(neighX, neighY); + // } + // } + // if (y > 0) { + // neighX = x + 1; + // neighY = y - 1; + // neighX %= (scale * 10); + // r->neighbors[D_NORTHEAST] = ar->GetRegion(neighX, neighY); + // } + // if (!r->neighbors[D_NORTHEAST]) { + // if (y == 0) { + // neighX = 4 * scale; + // neighY = 2; + // } + // else if (y < 3 * scale) { + // if (y == 3 * x2) { + // neighX = x + 2 * (scale - x2) + 1; + // neighY = y + 1; + // } + // else { + // neighX = x + 2 * (scale - x2); + // neighY = y; + // } + // } + // else if (y2 < 1) { + // neighX = x + 2 * scale; + // neighY = y - 2; + // } + // else if (y2 < 3 * scale) { + // neighX = x + 2 * (scale - x2); + // neighY = y - 2; + // } + // neighX %= (scale * 10); + // r->neighbors[D_NORTHEAST] = ar->GetRegion(neighX, neighY); + // } + // if (y2 > 0) { + // neighX = x + 1; + // neighY = y + 1; + // neighX %= (scale * 10); + // r->neighbors[D_SOUTHEAST] = ar->GetRegion(neighX, neighY); + // } + // if (!r->neighbors[D_SOUTHEAST]) { + // if (y == 0) { + // neighX = 2 * scale; + // neighY = 2; + // } + // else if (y2 < 1) { + // neighX = x + 4 * scale; + // neighY = y - 2; + // } + // else if (y2 < 3 * scale) { + // if (y2 == 3 * x2) { + // neighX = x + 2 * (scale - x2) + 1; + // neighY = y - 1; + // } + // else { + // neighX = x + 2 * (scale - x2); + // neighY = y; + // } + // } + // else if (y < 3 * scale) { + // neighX = x + 2 * (scale - x2); + // neighY = y + 2; + // } + // neighX %= (scale * 10); + // r->neighbors[D_SOUTHEAST] = ar->GetRegion(neighX, neighY); + // } + // if (y2 > 1) { + // r->neighbors[D_SOUTH] = ar->GetRegion(x, y + 2); + // } + // if (!r->neighbors[D_SOUTH]) { + // if (y2 > 0 && y2 < 3 * scale) + // { + // if (y2 == 2) { + // neighX = 10 * scale - 1; + // neighY = y + 2; + // } + // else if (y2 == 3 * x2) { + // neighX = x + 2 * (scale - x2) + 1; + // neighY = y + 1; + // } + // else { + // neighX = x + 2 * (scale - x2); + // neighY = y + 2; + // } + // neighX = (neighX + scale * 10) % (scale * 10); + // r->neighbors[D_SOUTH] = ar->GetRegion(neighX, neighY); + // } + // } + // if (y2 > 0) { + // neighX = x - 1; + // neighY = y + 1; + // neighX = (neighX + scale * 10) % (scale * 10); + // r->neighbors[D_SOUTHWEST] = ar->GetRegion(neighX, neighY); + // } + // if (!r->neighbors[D_SOUTHWEST]) { + // if (y == 0) { + // neighX = 8 * scale; + // neighY = 2; + // } + // else if (y2 < 1) { + // neighX = x + 6 * scale; + // neighY = y - 2; + // } + // else if (y2 < 3 * scale) { + // if (y2 == 3 * x3 + 4) { + // neighX = x + 2 * (x3 - scale) + 1; + // neighY = y + 1; + // } + // else { + // neighX = x + 2 * (x3 - scale); + // neighY = y; + // } + // } + // else if (y < 3 * scale) { + // neighX = x - 2 * (scale - x3) + 1; + // neighY = y + 1; + // } + // neighX = (neighX + scale * 10) % (scale * 10); + // r->neighbors[D_SOUTHWEST] = ar->GetRegion(neighX, neighY); + // } + // if (y > 0) { + // neighX = x - 1; + // neighY = y - 1; + // neighX = (neighX + scale * 10) % (scale * 10); + // r->neighbors[D_NORTHWEST] = ar->GetRegion(neighX, neighY); + // } + // if (!r->neighbors[D_NORTHWEST]) { + // if (y == 0) { + // neighX = 6 * scale; + // neighY = 2; + // } + // else if (y < 3 * scale) { + // if (y == 3 * x3 + 4) { + // neighX = x + 2 * (x3 - scale) + 1; + // neighY = y - 1; + // } + // else { + // neighX = x + 2 * (x3 - scale); + // neighY = y; + // } + // } + // else if (y2 < 1) { + // neighX = x + 8 * scale; + // neighY = y - 2; + // } + // else if (y2 < 3 * scale) { + // neighX = x - 2 * (scale - x3) + 1; + // neighY = y - 1; + // } + // neighX = (neighX + scale * 10) % (scale * 10); + // r->neighbors[D_NORTHWEST] = ar->GetRegion(neighX, neighY); + // } } void ARegionList::CalcDensities() @@ -2223,7 +2219,7 @@ void ARegionList::TownStatistics() break; case TOWN_CITY: cities++; - } + } } } int tot = villages + towns + cities; @@ -2273,8 +2269,8 @@ ARegion *ARegionList::FindConnectedRegions(ARegion *r, ARegion *tail, int shaft) ARegion *inner; for (i = 0; i < NDIRS; i++) { - if (r->neighbors[i] && r->neighbors[i]->distance == -1) { - tail->next = r->neighbors[i]; + if (r->neighbors(i) && r->neighbors(i)->distance == -1) { + tail->next = r->neighbors(i); tail = tail->next; tail->distance = r->distance + 1; } @@ -2401,7 +2397,7 @@ int ARegionList::get_connected_distance(ARegion *start, ARegion *target, int pen // Add all neighbors to the queue as long as we haven't visited them yet for (int i = 0; i < NDIRS; i++) { - ARegion *n = cur->neighbors[i]; + ARegion *n = cur->neighbors(i); if (n == nullptr) continue; // edge of map has missing neighbors // cur and n *should* have the same zloc, but ... let's just future-proof in case that changes sometime int cost = (cur->zloc == n->zloc ? 1 : penalty); @@ -2490,7 +2486,7 @@ int ARegionList::GetPlanarDistance(ARegion *one, ARegion *two, int penalty, int r->distance = -1; r->next = 0; } - + zdist = (one->zloc - two->zloc); if (zdist < 0) zdist = -zdist; start->distance = zdist * penalty; @@ -2670,11 +2666,11 @@ int ParseTerrain(AString *token) for (int i = 0; i < R_NUM; i++) { if (*token == TerrainDefs[i].type) return i; } - + for (int i = 0; i < R_NUM; i++) { if (*token == TerrainDefs[i].name) return i; } - + return (-1); } @@ -2735,7 +2731,7 @@ int findWaterBody(std::vector& waterBodies, ARegion* reg) { bool isInnerWater(ARegion* reg) { for (int i = 0; i < NDIRS; i++) { - auto n = reg->neighbors[i]; + auto n = reg->neighbors(i); if (n && n->type != R_OCEAN) { return false; } @@ -2746,7 +2742,7 @@ bool isInnerWater(ARegion* reg) { bool isNearWater(ARegion* reg) { for (int i = 0; i < NDIRS; i++) { - auto n = reg->neighbors[i]; + auto n = reg->neighbors(i); if (n && n->type == R_OCEAN) { return true; } @@ -2757,7 +2753,7 @@ bool isNearWater(ARegion* reg) { bool isNearWaterBody(ARegion* reg, WaterBody* wb) { for (int i = 0; i < NDIRS; i++) { - auto n = reg->neighbors[i]; + auto n = reg->neighbors(i); if (n && wb->includes(n)) { return true; } @@ -2857,7 +2853,7 @@ void makeRivers(Map* map, ARegionArray* arr, std::vector& waterBodie if (otherWater < 0) { continue; } - + int currentDist = distances[water->name][otherWater]; if (newDist < currentDist ) { distances[water->name][otherWater] = newDist; @@ -3065,7 +3061,7 @@ void cleanupIsolatedPlaces(ARegionArray* arr, std::vector& waterBodi std::vector nearbyRivers; bool clear = true; for (int i = 0; i < NDIRS; i++) { - auto next = reg->neighbors[i]; + auto next = reg->neighbors(i); if (next == NULL) { continue; } @@ -3102,7 +3098,7 @@ void cleanupIsolatedPlaces(ARegionArray* arr, std::vector& waterBodi int countNeighbors(ARegionGraph& graph, ARegion* reg, int ofType, int distance) { graphs::Location2D loc = { reg->xloc, reg->yloc }; - + int count = 0; auto result = graphs::breadthFirstSearch(graph, loc); @@ -3174,7 +3170,7 @@ std::vector getPoints(const int w, const int h, int minDist = initialMinDist; int cellSize = ceil(minDist / sqrt(2)); - + graphs::Location2D loc; do { loc = { .x = getrandom(w), .y = getrandom(h) }; @@ -3424,7 +3420,7 @@ void nameArea(int width, int height, ARegionGraph &graph, std::unordered_settype, 1, false); } usedNames.emplace(volcanoName); - + std::cout << volcanoName << std::endl; r->SetName(volcanoName.c_str()); } @@ -3762,7 +3758,7 @@ void ARegionList::AddHistoricalBuildings(ARegionArray* arr, const int w, const i } ARegionGraph graph = ARegionGraph(arr); - + graph.setInclusion([](ARegion* current, ARegion* next) { return next->type != R_OCEAN && next->type != R_VOLCANO; }); @@ -3860,7 +3856,7 @@ void ARegionList::AddHistoricalBuildings(ARegionArray* arr, const int w, const i int dir; for (dir = 0; dir < NDIRS; dir++) { - if (current->neighbors[dir] == endReg) { + if (current->neighbors(dir) == endReg) { break; } } @@ -3933,7 +3929,7 @@ void ARegionList::CreateNaturalSurfaceLevel(Map* map) { const int h = map->map.height / 2; MakeRegions(level, w, h); - + pRegionArrays[level]->SetName(0); pRegionArrays[level]->levelType = ARegionArray::LEVEL_SURFACE; @@ -3960,13 +3956,13 @@ void ARegionList::CreateNaturalSurfaceLevel(Map* map) { const int maxRiverReach = std::min(w, h) / 4; makeRivers(map, arr, waterBodies, rivers, w, h, maxRiverReach); - + cleanupIsolatedPlaces(arr, waterBodies, rivers, w, h); placeVolcanoes(arr, w, h); GrowRaces(arr); - + giveNames(arr, waterBodies, rivers, w, h); assertAllRegionsHaveName(w, h, arr); @@ -3994,7 +3990,7 @@ std::vector ARegionGraph::neighbors(graphs::Location2D id) { std::vector list; for (int i = 0; i < NDIRS; i++) { - ARegion* next = current->neighbors[i]; + ARegion* next = current->neighbors(i); if (next == NULL) { continue; } @@ -4028,7 +4024,7 @@ void ARegionList::ResourcesStatistics() { forlist(this) { ARegion* reg = (ARegion*) elem; - + for (const auto& p : reg->products) { resources[p->itemtype] += p->amount; } @@ -4094,7 +4090,7 @@ const std::unordered_map> breadthFirstSearch(AR } for (int i = 0; i < NDIRS; i++) { - auto next = current.key->neighbors[i]; + auto next = current.key->neighbors(i); if (!next) { continue; } diff --git a/aregion.h b/aregion.h index 6b25c03e..2261570c 100644 --- a/aregion.h +++ b/aregion.h @@ -177,6 +177,121 @@ struct RegionSetup { int settlementSize; }; +/** + * @brief Represents a connection between two regions. + * + * This is a tuple of two regions; an edge in the region graph. + * The edge is bidirectional, it is not important which region is the left and which is the right. + * + * Edge allows to add additional information to the connection between the regions. + * + */ +class RegionEdge { +public: + /** + * @brief A unique identifier for this connection. + * + * This is used to identify the edge in the edges list of the region graph. + * Also MOVE order can use this id to specify the destination of the movement. + * + */ + const int get_id(); + + /** + * @brief The left region of the edge. + */ + ARegion* get_left(); + + /** + * @brief The right region of the edge. + */ + ARegion* get_right(); + + /** + * @brief Direction of the edge from the left region to the right region. + */ + const int get_left_dir(); + + /** + * @brief Direction of the edge from the right region to the left region. + */ + const int get_right_dir(); + + /** + * @brief Creates a new edge between two regions. + * + * This is the only way to create a new edge. + * + * @param id A unique identifier for the edge. + * @param left The left region of the edge. + * @param right The right region of the edge. + * @param left_dir The direction of the edge from the left region to the right region. + * @param right_dir The direction of the edge from the right region to the left region. + * @return const Edge* The new edge. + */ + static const RegionEdge* create(const int id, ARegion *left, ARegion *right, const int left_dir, const int right_dir); + +private: + RegionEdge(const int id, ARegion* left, ARegion* right, const int left_dir, const int right_dir) + : id(id), left(left), right(right), left_dir(left_dir), right_dir(right_dir) {} + + int id; + ARegion* left; + ARegion* right; + int left_dir; + int right_dir; +}; + +/** + * @brief Represents connections to other regions and locations. + */ +class RegionEdges { +public: + using itemType = RegionEdge *; + using itemsMapType = std::unordered_map; + using regionType = ARegion *; + using regionArrayType = std::array; + using cacheType = std::unordered_map; + using iterator = itemsMapType::iterator; + + const int size() const { return items.size(); } + + /** + * @brief Adds a new edge to the list of edges. + * + * @param edge The edge to add. + */ + void add(const itemType edge); + + /** + * @brief Returns the neighbors of a region. + * + * This function is for the compatibility with the old code. + * Missing directions will be set to nullptr. + * + * @param region The region to get the neighbors of. + * @return const std::array The neighbors of the region. + */ + const regionArrayType& neighbors(const regionType region); + + /** + * @brief Returns the neighboring region in the given direction. + * + * This function is for the compatibility with the old code. + * + * @param dir The direction to get the neighbor of. + * @return ARegion* The neighboring region in the given direction or nullptr if there is no neighbor. + */ + regionType get_neighbor(const RegionEdges::regionType region, const int dir); + + iterator begin(); + iterator end(); + +private: + itemsMapType items; + cacheType neighborsCache; +}; + class ARegion : public AListElem { friend class Game; @@ -186,11 +301,10 @@ class ARegion : public AListElem ARegion(); //ARegion(int, int); ~ARegion(); - + void Setup(); void ManualSetup(const RegionSetup& settings); - void ZeroNeighbors(); void SetName(char const *); void Writeout(ostream& f); @@ -317,7 +431,7 @@ class ARegion : public AListElem int wages; int maxwages; int wealth; - + /* Economy */ int habitat; int development; @@ -335,14 +449,28 @@ class ARegion : public AListElem int emigrants; // economic improvement int improvement; - + /* Potential bonuses to economy */ int clearskies; int earthlore; int phantasmal_entertainment; - ARegion *neighbors[NDIRS]; - AList objects; + /** + * The edges of the region graph that connect this region to other regions and locations. + */ + RegionEdges edges; + + /** + * @brief Returns the neighboring region in the given direction. + * + * This function is for the compatibility with the old code. + * + * @param dir The direction to get the neighbor of. + * @return ARegion* The neighboring region in the given direction or nullptr if there is no neighbor. + */ + ARegion* neighbors(const int dir); + + AList objects; map newfleets; int fleetalias; AList hell; /* Where dead units go */ @@ -446,10 +574,10 @@ class GeoMap int GetVegetation(int, int); int GetCulture(int, int); void ApplyGeography(ARegionArray *pArr); - + int size, xscale, yscale, xoff, yoff; map geomap; - + }; class ARegionList : public AList @@ -481,6 +609,8 @@ class ARegionList : public AList ARegionArray **pRegionArrays; public: + using iterator = AListIterator; + // // Public world creation stuff // @@ -515,7 +645,7 @@ class ARegionList : public AList void UnsetRace(ARegionArray *pRegs); void RaceAnchors(ARegionArray *pRegs); void GrowRaces(ARegionArray *pRegs); - + void TownStatistics(); void ResourcesStatistics(); @@ -525,6 +655,9 @@ class ARegionList : public AList void AddHistoricalBuildings(ARegionArray* arr, const int w, const int h); + iterator begin() { return iterator((ARegion *) this->First()); } + iterator end() { return iterator(); } + private: // // Private world creation stuff diff --git a/basic/map.cpp b/basic/map.cpp index 9ef424e8..1349ae46 100644 --- a/basic/map.cpp +++ b/basic/map.cpp @@ -34,7 +34,7 @@ int ARegion::CheckSea(int dir, int range, int remainocean) if (range-- < 1) return 1; for (int d2 = -1; d2< 2; d2++) { int direc = (dir + d2 + NDIRS) % NDIRS; - ARegion *newregion = neighbors[direc]; + ARegion *newregion = neighbors(direc); if (!newregion) continue; remainocean += newregion->CheckSea(dir, range, remainocean); if (remainocean) break; @@ -155,21 +155,21 @@ void ARegionList::CreateSurfaceLevel(int level, int xSize, int ySize, char const int sea = Globals->OCEAN; if (Globals->SEA_LIMIT) sea = sea * (100 + 2 * Globals->SEA_LIMIT) / 100; - + MakeLand(pRegionArrays[level], sea, Globals->CONTINENT_SIZE); - + CleanUpWater(pRegionArrays[level]); SetupAnchors(pRegionArrays[level]); - + GrowTerrain(pRegionArrays[level], 0); - + AssignTypes(pRegionArrays[level]); SeverLandBridges(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); FinalSetup(pRegionArrays[level]); @@ -281,8 +281,8 @@ void ARegionList::MakeRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; - reg->wages = -1; + reg->race = -1; + reg->wages = -1; reg->level = arr; Add(reg); @@ -376,7 +376,7 @@ void ARegionList::MakeIcosahedralRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; // + reg->race = -1; // reg->wages = -1; // initially store: name reg->population = -1; // initially used as flag reg->elevation = -1; @@ -431,7 +431,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if (!reg) continue; ARegion *newreg = reg; ARegion *seareg = reg; - + // Archipelago or Continent? if (getrandom(100) < Globals->ARCHIPELAGO) { // Make an Archipelago: @@ -440,21 +440,21 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int tries = 0; for (int i=0; ineighbors[direc]; + newreg = reg->neighbors(direc); while (!newreg) { direc = getrandom(6); - newreg = reg->neighbors[direc]; + newreg = reg->neighbors(direc); } tries++; for (int m = 0; m < 2; m++) { seareg = newreg; - newreg = seareg->neighbors[direc]; + newreg = seareg->neighbors(direc); if (!newreg) break; } if (!newreg) break; if (newreg) { seareg = newreg; - newreg = seareg->neighbors[getrandom(NDIRS)]; + newreg = seareg->neighbors(getrandom(NDIRS)); if (!newreg) break; // island start point (~3 regions away from last island) seareg = newreg; @@ -481,11 +481,11 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int newdir = getrandom(NDIRS); while (direc == reg->GetRealDirComp(newdir)) newdir = getrandom(NDIRS); - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); while ((!newreg) && (tries < 36)) { while (direc == reg->GetRealDirComp(newdir)) newdir = getrandom(NDIRS); - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); tries++; } if (!newreg) continue; @@ -511,12 +511,12 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if ((reg->yloc < yoff*2) && ((dir < 2) || (dir == (NDIRS-1))) && (getrandom(4) < 3)) continue; if ((reg->yloc > (yband+yoff)*2) && ((dir < 5) && (dir > 1)) - && (getrandom(4) < 3)) continue; - ARegion *newreg = reg->neighbors[dir]; + && (getrandom(4) < 3)) continue; + ARegion *newreg = reg->neighbors(dir); if (!newreg) break; int polecheck = 0; for (int v=0; v < NDIRS; v++) { - ARegion *creg = newreg->neighbors[v]; + ARegion *creg = newreg->neighbors(v); if (!creg) polecheck = 1; } if (polecheck) break; @@ -635,7 +635,7 @@ void ARegionList::RemoveCoastalLakes(ARegionArray *pRegs) int count2 = 0; int temp = 0; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; // name after neighboring lake regions preferrentially if ((newregion->wages > 0) && @@ -682,7 +682,7 @@ void ARegionList::SeverLandBridges(ARegionArray *pRegs) if (reg->IsCoastal() != 4) continue; int tidych = Globals->SEVER_LAND_BRIDGES; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if ((!newregion) || (TerrainDefs[newregion->type].similar_type == R_OCEAN)) continue; @@ -774,7 +774,7 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) if (!reg) continue; if ((j > 0) && (j < 21) && (getrandom(3) < 2)) continue; if (reg->type == R_NUM) { - + // Check for Lakes if (Globals->LAKES && (getrandom(100) < (Globals->LAKES/10 + 1))) { @@ -788,11 +788,11 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) reg->wages = AGetName(0, reg); break; } - + int init = getrandom(6); for (int i=0; ineighbors[(i+init) % NDIRS]; + ARegion *t = reg->neighbors((i+init) % NDIRS); if (t) { if (t->population < 1) continue; if (t->type != R_NUM && @@ -833,7 +833,7 @@ void ARegionList::RandomTerrain(ARegionArray *pArr) int adjtype = 0; int adjname = -1; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; if ((TerrainDefs[newregion->type].similar_type != R_OCEAN) && (newregion->type != R_NUM) && @@ -866,21 +866,21 @@ void ARegionList::MakeUWMaze(ARegionArray *pArr) for (int i=D_NORTH; i<= NDIRS; i++) { int count = 0; for (int j=D_NORTH; j< NDIRS; j++) - if (reg->neighbors[j]) count++; + if (reg->neighbors(j)) count++; if (count <= 1) break; - ARegion *n = reg->neighbors[i]; + ARegion *n = reg->neighbors(i); if (n) { if (n->xloc < x || (n->xloc == x && n->yloc < y)) continue; if (!CheckRegionExit(reg, n)) { count = 0; for (int k = D_NORTH; kneighbors[k]) count++; + if (n->neighbors(k)) count++; } if (count <= 1) break; - n->neighbors[reg->GetRealDirComp(i)] = 0; - reg->neighbors[i] = 0; + n->neighbors(reg->GetRealDirComp(i)) = 0; + reg->neighbors(i) = 0; } } } @@ -920,24 +920,24 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) int xoff = x + 2 - getrandom(3) - getrandom(3); ARegion *reg = pArr->GetRegion(xoff, y); if (!reg) continue; - + if ((reg->type == R_LAKE) && (!Globals->LAKESIDE_IS_COASTAL)) continue; if (TerrainDefs[reg->type].flags & TerrainType::BARREN) continue; - + reg->race = -1; wigout = 0; // reset sanity - + if (TerrainDefs[reg->type].similar_type == R_OCEAN) { // setup near coastal race here int d = getrandom(NDIRS); int ctr = 0; - ARegion *nreg = reg->neighbors[d]; + ARegion *nreg = reg->neighbors(d); if (!nreg) continue; while((ctr++ < 20) && (reg->race == -1)) { if (TerrainDefs[nreg->type].similar_type != R_OCEAN) { int rnum = sizeof(TerrainDefs[nreg->type].coastal_races) / sizeof(TerrainDefs[nreg->type].coastal_races[0]); - + while ( reg->race == -1 || (ItemDefs[reg->race].flags & ItemType::DISABLED)) { reg->race = TerrainDefs[nreg->type].coastal_races[getrandom(rnum)]; if (++wigout > 100) break; @@ -945,21 +945,21 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) } else { int dir = getrandom(NDIRS); if (d == nreg->GetRealDirComp(dir)) continue; - if (!(nreg->neighbors[dir])) continue; - nreg = nreg->neighbors[dir]; + if (!(nreg->neighbors(dir))) continue; + nreg = nreg->neighbors(dir); } } } else { // setup noncoastal race here int rnum = sizeof(TerrainDefs[reg->type].races)/sizeof(TerrainDefs[reg->type].races[0]); - - while ( reg->race == -1 || + + while ( reg->race == -1 || (ItemDefs[reg->race].flags & ItemType::DISABLED)) { reg->race = TerrainDefs[reg->type].races[getrandom(rnum)]; if (++wigout > 100) break; } } - + /* leave out this sort of check for the moment if (wigout > 100) { // do something! @@ -968,10 +968,10 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) Awrite(" region type"); } */ - + if (reg->race == -1) { - cout << "Hey! No race anchor got assigned to the " - << TerrainDefs[reg->type].name + cout << "Hey! No race anchor got assigned to the " + << TerrainDefs[reg->type].name << " at " << x << "," << y << "\n"; } } @@ -990,7 +990,7 @@ void ARegionList::GrowRaces(ARegionArray *pArr) if ((!reg) || (reg->race == -1)) continue; for (int dir = 0; dir < NDIRS; dir++) { - ARegion *nreg = reg->neighbors[dir]; + ARegion *nreg = reg->neighbors(dir); if ((!nreg) || (nreg->race != -1)) continue; int iscoastal = 0; int cnum = sizeof(TerrainDefs[reg->type].coastal_races) / @@ -1119,10 +1119,10 @@ void ARegionList::SetACNeighbors(int levelSrc, int levelTo, int maxX, int maxY) if (!AC) continue; if (Globals->START_CITIES_EXIST) { for (int i=0; ineighbors[i]) continue; + if (AC->neighbors(i)) continue; ARegion *pReg = GetStartingCity(AC, i, levelTo, maxX, maxY); if (!pReg) continue; - AC->neighbors[i] = pReg; + AC->neighbors(i) = pReg; pReg->MakeStartingCity(); if (Globals->GATES_EXIST) { numberofgates++; diff --git a/basic/world.cpp b/basic/world.cpp index e23da39c..b914e663 100644 --- a/basic/world.cpp +++ b/basic/world.cpp @@ -2481,7 +2481,7 @@ int ARegion::CanBeStartingCity( ARegionArray *pRA ) ARegionPtr * reg = (ARegionPtr *) inlist.First(); for (int i=0; iptr->neighbors[i]; + ARegion * r2 = reg->ptr->neighbors(i); if (!r2) continue; if (r2->type == R_OCEAN) continue; if (GetRegion(&inlist,r2->num)) continue; @@ -2503,9 +2503,9 @@ void ARegion::MakeStartingCity() if (!Globals->TOWNS_EXIST) return; if (Globals->GATES_EXIST) gate = -1; - + if (town) delete town; - + AddTown(TOWN_CITY); if (!Globals->START_CITIES_EXIST) return; @@ -2597,8 +2597,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; @@ -2624,8 +2624,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; diff --git a/battle.cpp b/battle.cpp index 7ceb2b7d..32edadc1 100644 --- a/battle.cpp +++ b/battle.cpp @@ -40,13 +40,13 @@ enum StatsCategory { void WriteStats(Battle &battle, Army &army, StatsCategory category) { auto leaderName = std::string(army.leader->name->Str()); std::string header = std::string(army.leader->name->Str()) + " army:"; - + battle.AddLine(AString(header.c_str())); auto stats = category == StatsCategory::ROUND ? army.stats.roundStats : army.stats.battleStats; - + int statLines = 0; for (auto &uskv : stats) { UnitStat us = uskv.second; @@ -81,7 +81,7 @@ void WriteStats(Battle &battle, Army &army, StatsCategory category) { case MAGIC_ENERGY: s += "magic"; break; case MAGIC_SPIRIT: s += "magic"; break; case MAGIC_WEATHER: s += "magic"; break; - + default: s += "unknown"; break; } @@ -92,7 +92,7 @@ void WriteStats(Battle &battle, Army &army, StatsCategory category) { case ATTACK_ENERGY: s += " energy"; break; case ATTACK_SPIRIT: s += " spirit"; break; case ATTACK_WEATHER: s += " weather"; break; - + default: s += " unknown"; break; } @@ -278,10 +278,10 @@ void Battle::NormalRound(int round,Army * a,Army * b) AddLine(AString("Round ") + round + ":"); if (a->tactics_bonus > b->tactics_bonus) { - AddLine(*(a->leader->name) + " tactics bonus " + a->tactics_bonus + "."); + AddLine(*(a->leader->name) + " tactics bonus " + a->tactics_bonus + "."); } if (b->tactics_bonus > a->tactics_bonus) { - AddLine(*(b->leader->name) + " tactics bonus " + b->tactics_bonus + "."); + AddLine(*(b->leader->name) + " tactics bonus " + b->tactics_bonus + "."); } /* Update both army's shields */ @@ -355,7 +355,7 @@ void Battle::NormalRound(int round,Army * a,Army * b) a->Reset(); a->stats.ClearRound(); - + b->Reset(); b->stats.ClearRound(); } @@ -415,7 +415,7 @@ void Battle::GetSpoils(AList *losers, ItemList *spoils, int ass) } void AddBattleFact( - Events* events, + Events* events, ARegion* region, Unit* attacker, Unit* defender, @@ -428,10 +428,10 @@ void AddBattleFact( auto fact = new BattleFact(); fact->location = EventLocation::Create(region); - + fact->attacker.AssignUnit(attacker); fact->attacker.AssignArmy(attackerArmy); - + fact->defender.AssignUnit(defender); fact->defender.AssignArmy(defenderArmy); @@ -470,13 +470,13 @@ void AddBattleFact( fact->fortification = name; fact->fortificationType = fortType; } - + events->AddFact(fact); } void AddAssassinationFact( - Events* events, + Events* events, ARegion* region, Unit* defender, Army* defenderArmy, @@ -487,16 +487,16 @@ void AddAssassinationFact( auto fact = new AssassinationFact(); fact->location = EventLocation::Create(region); - + // fact->victim.AssignUnit(defender); // fact->victim.AssignArmy(defenderArmy); - + fact->outcome = outcome; events->AddFact(fact); } -int Battle::Run(Events* events, +int Battle::Run(Events* events, ARegion * region, Unit * att, AList * atts, @@ -583,7 +583,7 @@ int Battle::Run(Events* events, } armies[1]->Win(this, spoils); - + AddLine(""); AddLine(temp); AddLine(""); @@ -672,7 +672,7 @@ int Battle::Run(Events* events, } AddLine("Total Casualties:"); - + armies[0]->Tie(this); armies[1]->Tie(this); temp = "Spoils: none."; @@ -741,7 +741,7 @@ void Battle::build_json_report(json& j, Faction *fac) { return; } j["type"] = "battle"; - j["report"] = text; + j["report"] = text; } void Battle::AddLine(const AString & s) { @@ -751,7 +751,7 @@ void Battle::AddLine(const AString & s) { void Game::GetDFacs(ARegion * r,Unit * t,AList & facs) { int AlliesIncluded = 0; - + // First, check whether allies should assist in this combat if (Globals->ALLIES_NOAID == 0) { AlliesIncluded = 1; @@ -776,14 +776,14 @@ void Game::GetDFacs(ARegion * r,Unit * t,AList & facs) //delete obj; //delete u; } - + forlist((&r->objects)) { Object * obj = (Object *) elem; forlist((&obj->units)) { Unit * u = (Unit *) elem; if (u->IsAlive()) { if (u->faction == t->faction || - (AlliesIncluded == 1 && + (AlliesIncluded == 1 && u->guard != GUARD_AVOID && u->GetAttitude(r,t) == A_ALLY) ) { @@ -896,7 +896,7 @@ void Game::GetSides(ARegion *r, AList &afacs, AList &dfacs, AList &atts, // Check if neighbor exists and assign r2 to a neighbor if (i>=0) { - r2 = r->neighbors[i]; + r2 = r->neighbors(i); if (!r2) continue; } diff --git a/economy.cpp b/economy.cpp index 0499bdee..4e152ec2 100644 --- a/economy.cpp +++ b/economy.cpp @@ -72,7 +72,7 @@ int ARegion::Wages() } wages *= 10; if (dv > last) - wages += 10 * (dv - last) / (level - last); + wages += 10 * (dv - last) / (level - last); return wages; } @@ -94,7 +94,7 @@ void ARegion::SetupHabitat(TerrainType* terrain) { int pop = terrain->pop; int mw = terrain->wages; - + // fix economy when MAINTENANCE_COST has been adjusted mw += Globals->MAINTENANCE_COST - 10; if (mw < 0) mw = 0; @@ -136,7 +136,7 @@ void ARegion::SetupHabitat(TerrainType* terrain) { basepopulation = habitat / 3; // hmm... somewhere not too far off equilibrium pop population = habitat * (60 + getrandom(6) + getrandom(6)) / 100; - + // Setup development int level = 1; development = 1; @@ -196,7 +196,7 @@ void ARegion::SetupEconomy() { e->baseamount = maxent / Globals->ENTERTAIN_FRACTION; // raise entertainment income by productivity factor 10 e->productivity = Globals->ENTERTAIN_INCOME * 10; - + // note: wage factor 10, population factor 5 - included as "/ 50" /* More wealth in safe Starting Cities */ if ((Globals->SAFE_START_CITIES) && (IsStartingCity())) { @@ -241,7 +241,7 @@ void ARegion::SetupPop() int townch = (int) 80000 / prob; if (Globals->TOWNS_NOT_ADJACENT) { for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = neighbors[d]; + ARegion *newregion = neighbors(d); if ((newregion) && (newregion->town)) adjacent++; } } @@ -276,12 +276,12 @@ void ARegion::SetIncome() if (basepopulation == 0) return; maxwages = Wages(); - + /* taxable region wealth */ wealth = (int) ((float) (Population() * (Wages() - 10 * Globals->MAINTENANCE_COST) / 50)); if (wealth < 0) wealth = 0; - + /* Wages */ // wage-relevant population (/10 wages /5 popfactor) int pp = Population(); @@ -327,7 +327,7 @@ void ARegion::SetIncome() e->skill = S_ENTERTAINMENT; // raise entertainment income by productivity factor 10 e->productivity = Globals->ENTERTAIN_INCOME * 10; - + // note: wage factor 10, population factor 5 - included as "/ 50" /* More wealth in safe Starting Cities */ if ((Globals->SAFE_START_CITIES) && (IsStartingCity())) { @@ -337,7 +337,7 @@ void ARegion::SetIncome() w->baseamount += wbonus / Globals->WORK_FRACTION; e->amount += wbonus / Globals->ENTERTAIN_FRACTION; e->baseamount += wbonus / Globals->ENTERTAIN_FRACTION; - } + } } void ARegion::DisbandInRegion(int item, int amt) @@ -393,7 +393,7 @@ void ARegion::SetupCityMarket() ManType *locals = FindRace(ItemDefs[race].abr); if (!locals) locals = FindRace("SELF"); /* compose array of possible supply & demand items */ - int supply[NITEMS]; + int supply[NITEMS]; int demand[NITEMS]; /* possible advanced and magic items */ int rare[NITEMS]; @@ -425,7 +425,7 @@ void ARegion::SetupCityMarket() break; } } - } + } // Non-raw goods else { canProduceHere = 1; @@ -454,9 +454,9 @@ void ARegion::SetupCityMarket() isUseful = locals->CanUse(i); //Normal Items if (ItemDefs[ i ].type & IT_NORMAL) { - + if (i==I_GRAIN || i==I_LIVESTOCK || i==I_FISH) { - // Add foodstuffs directly to market + // Add foodstuffs directly to market int amt = Globals->CITY_MARKET_NORMAL_AMT; int price; @@ -500,7 +500,7 @@ void ARegion::SetupCityMarket() } else if (isUseful) demand[i] = 4; } } else { - + // Tool, weapon or armor if (isUseful) { // Add to supply? @@ -576,7 +576,7 @@ void ARegion::SetupCityMarket() } else { price = ItemDefs[ i ].baseprice; } - + cap = (citymax *3/4) - 5000; if (cap < citymax/2) cap = citymax / 2; offset = (citymax/20) + ((citymax/5) * 2); @@ -584,7 +584,7 @@ void ARegion::SetupCityMarket() markets.push_back(m); } } - + /* Add demand (normal) items */ int num = 4; int sum = 1; @@ -599,11 +599,11 @@ void ARegion::SetupCityMarket() if (dm < sum) break; } if (dm >= sum) continue; - + int amt = Globals->CITY_MARKET_NORMAL_AMT; amt = demand[i] * amt / 4; int price; - + if (Globals->RANDOM_ECONOMY) { amt += getrandom(amt); price = (ItemDefs[i].baseprice * @@ -611,15 +611,15 @@ void ARegion::SetupCityMarket() } else { price = ItemDefs[i].baseprice; } - + cap = (citymax/4); offset = - (citymax/20) + ((5-num) * citymax * 3/40); Market * m = new Market (M_SELL, i, price, amt/6, population+cap+offset, population+citymax, 0, amt); markets.push_back(m); demand[i] = 0; - num--; + num--; } - + /* Add supply (normal) items */ num = 2; sum = 1; @@ -646,7 +646,7 @@ void ARegion::SetupCityMarket() } else { price = ItemDefs[ i ].baseprice; } - + cap = (citymax/4); offset = ((3-num) * citymax * 3 / 40); if (supply[i] < 4) offset += citymax / 20; @@ -708,7 +708,7 @@ void ARegion::SetupCityMarket() } else { price = ItemDefs[ i ].baseprice; } - + cap = (citymax/2); tradesell++; offset = - (citymax/20) + tradesell * (tradesell * tradesell * citymax/40); @@ -798,14 +798,14 @@ void ARegion::AddTown() void ARegion::AddTown(AString * tname) { int size = DetermineTownSize(); - AddTown(size, tname); + AddTown(size, tname); } /* Create a town of given Town Type */ void ARegion::AddTown(int size) { AString *tname = new AString(AGetNameString(AGetName(1, this))); - AddTown(size, tname); + AddTown(size, tname); } /* Create a town of specific type with name @@ -852,10 +852,10 @@ void ARegion::SetTownType(int level) town->hab = TownHabitat(); town->pop = town->hab * 2 / 3; town->dev = TownDevelopment(); - + // Sanity check if ((level < TOWN_VILLAGE) || (level > TOWN_CITY)) return; - + // increment values int poptown = getrandom((level -1) * (level -1) * Globals->CITY_POP/12) + level * level * Globals->CITY_POP/12; town->hab += poptown; @@ -883,7 +883,7 @@ void ARegion::SetTownType(int level) int popdecr = getrandom(Globals->CITY_POP/3) + getrandom(Globals->CITY_POP/3); // don't depopulate while ((town->pop < popdecr) || (town->hab < popdecr)) { - popdecr = popdecr / 2; + popdecr = popdecr / 2; } town->hab -= popdecr; town->pop = town->hab * 2 / 3; @@ -899,7 +899,7 @@ void ARegion::UpdateEditRegion() // redo markets and entertainment/tax income for extra people. SetIncome(); for (auto& m : markets) m->PostTurn(Population(), Wages()); - + //Replace man selling markets.erase( remove_if(markets.begin(), markets.end(), [](const Market * m) { return ItemDefs[m->item].type & IT_MAN; }), @@ -916,7 +916,7 @@ void ARegion::UpdateEditRegion() // hack: include wage factor of 10 in float calculation above m = new Market(M_BUY, I_LEADERS, (int)(Wages()*4*ratio), Population()/125, 0, 10000, 0, 400); markets.push_back(m); - } + } } void ARegion::SetupEditRegion() @@ -930,7 +930,7 @@ void ARegion::SetupEditRegion() int pop = typer->pop; int mw = typer->wages; - + // fix economy when MAINTENANCE_COST has been adjusted mw += Globals->MAINTENANCE_COST - 10; if (mw < 0) mw = 0; @@ -972,7 +972,7 @@ void ARegion::SetupEditRegion() basepopulation = habitat / 3; // hmm... somewhere not too far off equilibrium pop population = habitat * (60 + getrandom(6) + getrandom(6)) / 100; - + // Setup development int level = 1; development = 1; @@ -995,7 +995,7 @@ void ARegion::SetupEditRegion() int townch = (int) 80000 / prob; if (Globals->TOWNS_NOT_ADJACENT) { for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = neighbors[d]; + ARegion *newregion = neighbors(d); if ((newregion) && (newregion->town)) adjacent++; } } @@ -1076,7 +1076,7 @@ int ARegion::BaseDev() prev = 0; } } - + basedev = (Globals->MAINTENANCE_COST + basedev) / 2; return basedev; } @@ -1124,14 +1124,14 @@ int ARegion::TownHabitat() if (temple) build++; if (caravan) build++; if (build > 2) build = 2; - + build++; hab = (build * build + 1) * hab * hab + habitat / 4 + 50; - + // Effect of town development on habitat: int totalhab = hab + (TownDevelopment() * (habitat + 800 + hab + Globals->CITY_POP / 2)) / 100; - + return totalhab; } @@ -1177,9 +1177,9 @@ int ARegion::TownDevelopment() int df = development - basedev; if (df < 0) df = 0; if (df > 100) df = 100; - + return df; -} +} // Checks the growth potential of towns // and cancels unlimited markets for Starting Cities @@ -1218,12 +1218,12 @@ int ARegion::TownGrowth() } } } - + if (amt > tot) amt = tot; if (tot) { tarpop += (Globals->CITY_POP * amt) / tot; - } + } // Let's bump tarpop up // tarpop = (tarpop * 5) / 4; if (tarpop > Globals->CITY_POP) tarpop = Globals->CITY_POP; @@ -1254,15 +1254,15 @@ void ARegion::Grow() // We don't need to grow 0 pop regions if (basepopulation == 0) return; - // growpop is the overall population growth + // growpop is the overall population growth int growpop = 0; - + // Init migration parameters - // immigrants = entering this region, + // immigrants = entering this region, // emigrants = leaving immigrants = habitat - basepopulation; emigrants = population - basepopulation; - + // First, check regional population growth // Check resource production activity int activity = 0; @@ -1273,29 +1273,29 @@ void ARegion::Grow() // bonuses for productivity are calculated from // the _baseamount_ of all resources. // because trade structures increase the produceable - // amount and not the baseamount this creates an + // amount and not the baseamount this creates an // effective advantage for trade structures amount += p->baseamount; } } - + // Now set the target population for the hex // Ant: I'm not sure why population's being subtracted here.. // Shouldn't it be something like : // tarpop = habitat + basepopulation? int tarpop = habitat - population + basepopulation; - + // Ant: Increase tarpop for any trading that's going on? // Not sure why (habitat - basepopulation) is included if (amount) tarpop += ((habitat - basepopulation) * 2 * activity) / (3 * amount); - + // diff is the amount we can grow? int diff = tarpop - population; int adiff = abs(diff); //if (adiff < 0) adiff = adiff * (- 1); - - // Adjust basepop? + + // Adjust basepop? // raise basepop depending on production // absolute basepop increase if (diff > (basepopulation / 20)) { @@ -1308,28 +1308,28 @@ void ARegion::Grow() // lower basepop for extremely low levels of population if (population < basepopulation) { int depop = (basepopulation - population) / 4; - basepopulation -= depop + getrandom(depop); + basepopulation -= depop + getrandom(depop); } - + // debug strings //Awrite(AString("immigrants = ") + immigrants); //Awrite(AString("emigrants = ") + emigrants); //Awrite(AString("adiff = ") + adiff); //Awrite(AString("diff = ") + diff); //Awrite(AString("habitat = ") + habitat); - + // Limit excessive growth at low pop / hab ratios // and avoid overflowing // What are grow2 and grow representing? Maybe these formulae // could be broken up a bit more and commented? long int grow2 = 5 * ((long int) habitat + (3 * (long int) adiff)); //Awrite(AString("grow2 = ") + (unsigned int) grow2); // debug string - + // Ant: In the following formula, dgrow is almost always 0! long int dgrow = ((long int) adiff * (long int) habitat ) / grow2; //if (diff < 0) dgrow = dgrow * (- 1); //Awrite(AString("dgrow = ") + (unsigned int) dgrow); // debug string - + // long int dgrow = ((long int) diff) * ((long int) habitat) // / (5 * (long int) ((long int) habitat + 3 * (long int) abs(diff))); if (diff < 0) growpop -= (int) dgrow; @@ -1344,7 +1344,7 @@ void ARegion::Grow() // update emigrants - only if region has a decent population level if (emigrants > 0) emigrants += diff; - + // Now check town population growth if (town) { int maxpop = TownGrowth(); @@ -1367,14 +1367,14 @@ void ARegion::Grow() // ((2 * town->hab) - town->pop) seems clearer float increase = tgrowth * (2 * town->hab - town->pop); float limitingfactor = (10 * town->hab); - + // Ant: Not sure whether we still need the typecasts here growpop += (int) (increase / limitingfactor); } // Update population AdjustPop(growpop); - + /* Initialise the migration variables */ migdev = 0; migfrom.DeleteAll(); @@ -1388,13 +1388,13 @@ void ARegion::FindMigrationDestination(int round) { // is emigration possible? if (emigrants < 0) return; - + int maxattract = 0; ARegion *target = this; // Check all hexes within 2 hexes // range one neighbours for (int d=0; d < NDIRS; d++) { - ARegion *nb = neighbors[d]; + ARegion *nb = neighbors(d); if (!nb) continue; if (TerrainDefs[nb->type].similar_type == R_OCEAN) continue; int ma = nb->MigrationAttractiveness(development, 1, round); @@ -1407,7 +1407,7 @@ void ARegion::FindMigrationDestination(int round) } // range two neighbours for (int d2=0; d2 < NDIRS; d2++) { - ARegion *nb2 = nb->neighbors[d2]; + ARegion *nb2 = nb->neighbors(d2); if (!nb2) continue; if (TerrainDefs[nb2->type].similar_type == R_OCEAN) continue; ma = nb2->MigrationAttractiveness(development, 2, round); @@ -1418,11 +1418,11 @@ void ARegion::FindMigrationDestination(int round) target = nb2; maxattract = ma; } - } + } } // do we have a target? if (target == this) return; - + // then add this region to the target's migfrom list ARegion *self = this; target->migfrom.Add(self); @@ -1434,7 +1434,7 @@ int ARegion::MigrationAttractiveness(int homedev, int range, int round) int attractiveness = 0; int mdev = development; /* Is there enough immigration capacity? */ - if (immigrants < 100) return 0; + if (immigrants < 100) return 0; /* on the second round, consider as a mid-way target */ if (round > 1) mdev = migdev; /* minimum development difference 8 x range */ @@ -1454,8 +1454,8 @@ int ARegion::MigrationAttractiveness(int homedev, int range, int round) } /* attractiveness due to development */ attractiveness += (int) (space * ((float) 100 * (mdev - homedev) / homedev + entertain)); - - return attractiveness; + + return attractiveness; } /* Performs migration for each region with a migration @@ -1472,16 +1472,16 @@ void ARegion::Migrate() totalmig += r->emigrants; } } - + // is there any migration to perform? if (totalmig == 0) return; - + // do each migration int totalimm = 0; forlist(&migfrom) { ARegion *r = (ARegion *) elem; if (!r) continue; - + // figure range int xdist = r->xloc - xloc; if (xdist < 0) xdist = - xdist; @@ -1489,7 +1489,7 @@ void ARegion::Migrate() if (ydist < 0) ydist = - ydist; ydist = (ydist - xdist) / 2; int range = xdist + ydist; - + // sanity check - huh? if (range < 1) continue; int migrants = (int) (immigrants * ((float) (r->emigrants / totalmig))); @@ -1505,7 +1505,7 @@ void ARegion::Migrate() r->emigrants -= migrants; totalimm += migrants; AString wout = AString("Migrating from ") /* + (r->name) + " in " */ + r->xloc - + "," + (r->yloc) + " to " /* + name + " in " */ + (xloc) + "," + yloc + + "," + (r->yloc) + " to " /* + name + " in " */ + (xloc) + "," + yloc + ": " + migrants + " migrants."; Awrite(wout); // set the region's mid-way migration development @@ -1525,7 +1525,7 @@ void ARegion::PostTurn(ARegionList *pRegs) if (Globals->DECAY) { DoDecayCheck(pRegs); } - + /* Development increase due to player activity */ // scale improvement float imp1 = improvement / 25; @@ -1540,7 +1540,7 @@ void ARegion::PostTurn(ARegionList *pRegs) for (int a=0; a<3; a++) if (getrandom(progress) < diff) development++; if (development > maxdevelopment) maxdevelopment = development; } - + /* Development increase for very poor regions */ int recoveryRounds = 1 + earthlore + clearskies; @@ -1548,13 +1548,13 @@ void ARegion::PostTurn(ARegionList *pRegs) while (recoveryRounds-- > 0) { if (maxdevelopment > development) { - if (getrandom(maxdevelopment) > development) development++; + if (getrandom(maxdevelopment) > development) development++; } if (maxdevelopment > development) { - if (getrandom(maxdevelopment) > development) development++; + if (getrandom(maxdevelopment) > development) development++; } if (maxdevelopment > development) { - if (getrandom(3) == 1) development++; + if (getrandom(3) == 1) development++; } } @@ -1589,7 +1589,7 @@ void ARegion::PostTurn(ARegionList *pRegs) if (type != R_NEXUS) { SetIncome(); } - + /* update markets */ for (auto& m : markets) m->PostTurn(Population(), Wages()); diff --git a/edges.cpp b/edges.cpp new file mode 100644 index 00000000..128c14a8 --- /dev/null +++ b/edges.cpp @@ -0,0 +1,100 @@ +// START A3HEADER +// +// This source file is part of the Atlantis PBM game program. +// Copyright (C) 2024 Valdis Zobēla +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program, in the file license.txt. If not, write +// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. +// +// See the Atlantis Project web page for details: +// http://www.prankster.com/project +// +// END A3HEADER + +#include "aregion.h" + +const RegionEdge* RegionEdge::create(const int id, ARegion* left, ARegion* right, const int left_dir, const int right_dir) { + RegionEdge *edge = new RegionEdge(id, left, right, left_dir, right_dir); + return edge; +} + +const int RegionEdge::get_id() { + return this->id; +} + +ARegion* RegionEdge::get_left() { + return this->left; +} + +ARegion* RegionEdge::get_right() { + return this->right; +} + +const int RegionEdge::get_left_dir() { + return this->left_dir; +} + +const int RegionEdge::get_right_dir() { + return this->right_dir; +} + +void RegionEdges::add(const RegionEdges::itemType edge) { + this->items.insert({ edge->get_id(), edge }); + + add_to_cache(this->neighborsCache, edge->get_left(), edge->get_right(), edge->get_left_dir()); + add_to_cache(this->neighborsCache, edge->get_right(), edge->get_left(), edge->get_right_dir()); +} + +void add_to_cache(RegionEdges::cacheType& cache, const RegionEdges::regionType source, RegionEdges::regionType target, const int dir) { + auto rec = cache.find(source); + if (rec == cache.end()) { + RegionEdges::regionArrayType neighbors; + std::fill(neighbors.begin(), neighbors.end(), nullptr); + + cache.insert({ source, neighbors }); + rec = cache.find(source); + } + + rec->second[dir] = target; +} + +const RegionEdges::regionArrayType& RegionEdges::neighbors(const RegionEdges::regionType region) { + auto rec = this->neighborsCache.find(region); + if (rec == this->neighborsCache.end()) { + RegionEdges::regionArrayType neighbors; + std::fill(neighbors.begin(), neighbors.end(), nullptr); + + return neighbors; + } + + return rec->second; +} + +RegionEdges::iterator RegionEdges::begin() { + return this->items.begin(); +} + +RegionEdges::iterator RegionEdges::end() { + return this->items.end(); +} + +RegionEdges::regionType RegionEdges::get_neighbor(const RegionEdges::regionType region, const int dir) { + auto rec = this->neighborsCache.find(region); + if (rec == this->neighborsCache.end()) { + return nullptr; + } + + return rec->second[dir]; +} diff --git a/edit.cpp b/edit.cpp index cdb5fd3b..0294d2ea 100644 --- a/edit.cpp +++ b/edit.cpp @@ -41,7 +41,7 @@ int Game::EditGame(int *pSaveGame) } else if (*pStr == "2") { EditGameFindUnit(); } else if (*pStr == "3") { - EditGameCreateUnit(); + EditGameCreateUnit(); } else { Awrite("Select from the menu."); } @@ -120,97 +120,97 @@ void Game::EditGameFindUnit() void Game::EditGameRegion(ARegion *pReg) //copied direct from AtlantisDev 030730 post -{ +{ do { Awrite( AString("Region ") + pReg->num + ": " + - pReg->Print() ); - Awrite( " 1) Edit objects..." ); + pReg->Print() ); + Awrite( " 1) Edit objects..." ); Awrite( " 2) Edit terrain..." ); - Awrite( " q) Return to previous menu." ); + Awrite( " q) Return to previous menu." ); - int exit = 0; - AString *pStr = AGetString(); + int exit = 0; + AString *pStr = AGetString(); if ( *pStr == "1" ) { - EditGameRegionObjects( pReg ); - } + EditGameRegionObjects( pReg ); + } else if ( *pStr == "2" ) { - EditGameRegionTerrain( pReg ); - } + EditGameRegionTerrain( pReg ); + } else if ( *pStr == "q" ) { - exit = 1; - } + exit = 1; + } else { - Awrite( "Select from the menu." ); - } - if (pStr) delete pStr; + Awrite( "Select from the menu." ); + } + if (pStr) delete pStr; if ( exit ) { - break; - } - } - while( 1 ); -} + break; + } + } + while( 1 ); +} /* RegionEdit Patch 030829 BS */ -void Game::EditGameRegionObjects( ARegion *pReg ) +void Game::EditGameRegionObjects( ARegion *pReg ) //template copied from AtlantisDev 030730 post. Modified option a, added option h, m. -{ +{ do { - Awrite( AString( "Region: " ) + pReg->ShortPrint() ); - Awrite( "" ); - int i = 0; + Awrite( AString( "Region: " ) + pReg->ShortPrint() ); + Awrite( "" ); + int i = 0; AString temp = AString(""); - forlist (&(pReg->objects)) { - Object * obj = (Object *)elem; + forlist (&(pReg->objects)) { + Object * obj = (Object *)elem; temp = AString ((AString(i) + ". " + *obj->name + " : " + ObjectDefs[obj->type].name)); -// if (Globals->HEXSIDE_TERRAIN && obj->hexside>-1) temp += AString( AString(" (side:") + DirectionAbrs[obj->hexside] + ")."); +// if (Globals->HEXSIDE_TERRAIN && obj->hexside>-1) temp += AString( AString(" (side:") + DirectionAbrs[obj->hexside] + ")."); Awrite(temp); - i++; - } - Awrite( "" ); - - Awrite( " [a] [object type] [dir] to add object" ); - Awrite( " [d] [index] to delete object" ); -// if (Globals->HEXSIDE_TERRAIN) Awrite( " [h] [index] [dir] to change the hexside of an object" ); - Awrite( " [n] [index] [name] to rename object" ); + i++; + } + Awrite( "" ); + + Awrite( " [a] [object type] [dir] to add object" ); + Awrite( " [d] [index] to delete object" ); +// if (Globals->HEXSIDE_TERRAIN) Awrite( " [h] [index] [dir] to change the hexside of an object" ); + Awrite( " [n] [index] [name] to rename object" ); // if (Globals->HEXSIDE_TERRAIN) Awrite( " [m] [index] to add/delete a mirrored object" ); - Awrite( " q) Return to previous menu." ); - - int exit = 0; - AString *pStr = AGetString(); - if ( *pStr == "q" ) { - exit = 1; - } else { - AString *pToken = 0; - do { - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } - - // add object - if (*pToken == "a") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } - - int objType = ParseObject(pToken, 0); - if ( (objType == -1) || (ObjectDefs[objType].flags & ObjectType::DISABLED) ) { - Awrite( "No such object." ); - break; - } - SAFE_DELETE( pToken ); - + Awrite( " q) Return to previous menu." ); + + int exit = 0; + AString *pStr = AGetString(); + if ( *pStr == "q" ) { + exit = 1; + } else { + AString *pToken = 0; + do { + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } + + // add object + if (*pToken == "a") { + SAFE_DELETE( pToken ); + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } + + int objType = ParseObject(pToken, 0); + if ( (objType == -1) || (ObjectDefs[objType].flags & ObjectType::DISABLED) ) { + Awrite( "No such object." ); + break; + } + SAFE_DELETE( pToken ); + /* int dir=-1; if (ObjectDefs[objType].hexside && Globals->HEXSIDE_TERRAIN ) { if (!ObjectIsShip(objType) || !(TerrainDefs[pReg->type].similar_type == R_OCEAN) ) { - pToken = pStr->gettoken(); + pToken = pStr->gettoken(); if (!pToken) { Awrite( "Specify direction" ); break; @@ -223,91 +223,91 @@ void Game::EditGameRegionObjects( ARegion *pReg ) } } */ - - Object *o = new Object(pReg); - o->type = objType; - o->incomplete = 0; - o->inner = -1; + + Object *o = new Object(pReg); + o->type = objType; + o->incomplete = 0; + o->inner = -1; // o->hexside = dir; - if (o->IsFleet()) { - o->num = shipseq++; - o->name = new AString(AString("Fleet") + " [" + o->num + "]"); - } - else { - o->num = pReg->buildingseq++; - o->name = new AString(AString("Building") + " [" + o->num + "]"); - } - pReg->objects.Add(o); - } - // delete object - else if (*pToken == "d") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } - - int index = pToken->value(); + if (o->IsFleet()) { + o->num = shipseq++; + o->name = new AString(AString("Fleet") + " [" + o->num + "]"); + } + else { + o->num = pReg->buildingseq++; + o->name = new AString(AString("Building") + " [" + o->num + "]"); + } + pReg->objects.Add(o); + } + // delete object + else if (*pToken == "d") { + SAFE_DELETE( pToken ); + + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } + + int index = pToken->value(); if ( (index < 0) || (index >= pReg->objects.Num()) ) { //modified minimum to <0 to allow deleting object 0. 030824 BS - Awrite( "Incorrect index." ); - break; - } - SAFE_DELETE( pToken ); - - int i = 0; - AListElem *tmp = pReg->objects.First(); - for (i = 0; i < index; i++) tmp = pReg->objects.Next(tmp); - pReg->objects.Remove(tmp); - } + Awrite( "Incorrect index." ); + break; + } + SAFE_DELETE( pToken ); + + int i = 0; + AListElem *tmp = pReg->objects.First(); + for (i = 0; i < index; i++) tmp = pReg->objects.Next(tmp); + pReg->objects.Remove(tmp); + } //hexside change - /* else if (*pToken == "h") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } - - int index = pToken->value(); - if ( (index < 1) || (index >= pReg->objects.Num()) ) { - Awrite( "Incorrect index." ); - break; - } - SAFE_DELETE( pToken ); - - int i = 0; - Object *tmp = (Object *)pReg->objects.First(); - for (i = 0; i < index; i++) tmp = (Object *)pReg->objects.Next(tmp); - + /* else if (*pToken == "h") { + SAFE_DELETE( pToken ); + + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } + + int index = pToken->value(); + if ( (index < 1) || (index >= pReg->objects.Num()) ) { + Awrite( "Incorrect index." ); + break; + } + SAFE_DELETE( pToken ); + + int i = 0; + Object *tmp = (Object *)pReg->objects.First(); + for (i = 0; i < index; i++) tmp = (Object *)pReg->objects.Next(tmp); + if (!(ObjectDefs[tmp->type].hexside)) { Awrite("Not a hexside object."); break; } - + if (!Globals->HEXSIDE_TERRAIN) { Awrite("Hexside terrain disabled under game rules."); break; } - + pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Specify Direction." ); - break; - } - + if ( !pToken ) { + Awrite( "Specify Direction." ); + break; + } + int dir=-1; dir = ParseHexside(pToken); if (dir==-1) { Awrite("Incorrect direction. Use N,NE,SE,S,SW,NW"); break; } - - SAFE_DELETE(pToken); - if (dir) { - tmp->hexside = dir; + + SAFE_DELETE(pToken); + if (dir) { + tmp->hexside = dir; if (tmp->mirror) { // reset mirrors, else problems later tmp->mirror->mirror = NULL; tmp->mirror->mirrornum = -1; @@ -318,35 +318,35 @@ void Game::EditGameRegionObjects( ARegion *pReg ) } } //mirror change - else if (*pToken == "m") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } - - int index = pToken->value(); - if ( (index < 1) || (index >= pReg->objects.Num()) ) { - Awrite( "Incorrect index." ); - break; - } - SAFE_DELETE( pToken ); - - int i = 0; - Object *tmp = (Object *)pReg->objects.First(); - for (i = 0; i < index; i++) tmp = (Object *)pReg->objects.Next(tmp); - + else if (*pToken == "m") { + SAFE_DELETE( pToken ); + + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } + + int index = pToken->value(); + if ( (index < 1) || (index >= pReg->objects.Num()) ) { + Awrite( "Incorrect index." ); + break; + } + SAFE_DELETE( pToken ); + + int i = 0; + Object *tmp = (Object *)pReg->objects.First(); + for (i = 0; i < index; i++) tmp = (Object *)pReg->objects.Next(tmp); + // if has a mirror, delete the mirror if (tmp->mirror) { // Awrite(AString(AString("Mirror ") + tmp->mirror->name + " deleted.")); Awrite("Mirror deleted"); - tmp->mirror->region->objects.Remove(tmp->mirror); + tmp->mirror->region->objects.Remove(tmp->mirror); tmp->mirror == NULL; tmp->mirrornum == -1; } - + else { if (!(ObjectDefs[tmp->type].hexside)) { Awrite("Not a hexside object."); @@ -355,23 +355,23 @@ void Game::EditGameRegionObjects( ARegion *pReg ) if (tmp->hexside < 0) { Awrite("Object not on a hexside."); break; - } + } if (tmp->IsFleet()) { Awrite("Fleets cannot be mirrored."); break; - } + } if (!Globals->HEXSIDE_TERRAIN) { Awrite("Hexside terrain disabled under game rules."); break; } - - if (!pReg->neighbors[tmp->hexside]) { + + if (!pReg->neighbors(tmp->hexside)) { Awrite("No neighbouring region."); break; } - - Object *o = new Object(pReg->neighbors[tmp->hexside]); - o->num = pReg->neighbors[tmp->hexside]->buildingseq++; + + Object *o = new Object(pReg->neighbors(tmp->hexside)); + o->num = pReg->neighbors(tmp->hexside)->buildingseq++; o->type = ObjectDefs[tmp->type].mirror; o->name = new AString(AString("Building [") + o->num + "]"); o->incomplete = 0; @@ -379,73 +379,73 @@ void Game::EditGameRegionObjects( ARegion *pReg ) o->inner = -1; o->mirrornum = tmp->num; o->mirror = tmp; - pReg->neighbors[tmp->hexside]->objects.Add(o); - + pReg->neighbors(tmp->hexside)->objects.Add(o); + tmp->mirrornum = o->num; - tmp->mirror = o; - Awrite("Mirror added"); + tmp->mirror = o; + Awrite("Mirror added"); } } */ - // rename object - else if (*pToken == "n") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } - - int index = pToken->value(); - if ( (index < 1) || (index >= pReg->objects.Num()) ) { - Awrite( "Incorrect index." ); - break; - } - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "No name given." ); - break; - } - - int i = 0; - Object *tmp = (Object *)pReg->objects.First(); - for (i = 0; i < index; i++) tmp = (Object *)pReg->objects.Next(tmp); - - AString * newname = pToken->getlegal(); - SAFE_DELETE(pToken); - if (newname) { - delete tmp->name; - *newname += AString(" [") + tmp->num + "]"; - tmp->name = newname; - } - } - - } while( 0 ); - if (pToken) delete pToken; - } - if (pStr) delete pStr; - - if (exit) { - break; - } - } - while( 1 ); -} - -void Game::EditGameRegionTerrain( ARegion *pReg ) -{ + // rename object + else if (*pToken == "n") { + SAFE_DELETE( pToken ); + + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } + + int index = pToken->value(); + if ( (index < 1) || (index >= pReg->objects.Num()) ) { + Awrite( "Incorrect index." ); + break; + } + SAFE_DELETE( pToken ); + + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "No name given." ); + break; + } + + int i = 0; + Object *tmp = (Object *)pReg->objects.First(); + for (i = 0; i < index; i++) tmp = (Object *)pReg->objects.Next(tmp); + + AString * newname = pToken->getlegal(); + SAFE_DELETE(pToken); + if (newname) { + delete tmp->name; + *newname += AString(" [") + tmp->num + "]"; + tmp->name = newname; + } + } + + } while( 0 ); + if (pToken) delete pToken; + } + if (pStr) delete pStr; + + if (exit) { + break; + } + } + while( 1 ); +} + +void Game::EditGameRegionTerrain( ARegion *pReg ) +{ do { - Awrite(""); - Awrite( AString( "Region: " ) + pReg->Print() ); - Awrite( "" ); + Awrite(""); + Awrite( AString( "Region: " ) + pReg->Print() ); + Awrite( "" ); // write pop stuff Awrite( AString("") + pReg->population + " " + ItemDefs[pReg->race].names + " basepop"); if (pReg->town) Awrite( AString("") + pReg->town->pop + " " + ItemDefs[pReg->race].names + " townpop"); Awrite( AString("") + pReg->Population() + " " + ItemDefs[pReg->race].names + " totalpop"); - + // write wages Awrite(AString("Wages: ") + pReg->WagesForReport() + "."); Awrite(AString("Maxwages: ") + pReg->maxwages + "."); @@ -480,7 +480,7 @@ void Game::EditGameRegionTerrain( ARegion *pReg ) if (has==0) temp += "none"; temp += "."; Awrite(temp); - Awrite( "" ); + Awrite( "" ); if (Globals->GATES_EXIST && pReg->gate && pReg->gate != -1) { Awrite(AString("There is a Gate here (Gate ") + pReg->gate + @@ -491,67 +491,67 @@ void Game::EditGameRegionTerrain( ARegion *pReg ) } - Awrite( " [t] [terrain type] to modify terrain type" ); + Awrite( " [t] [terrain type] to modify terrain type" ); Awrite( " [r] [race] to modify local race" ); Awrite( " (use none, None or 0 to unset)" ); Awrite( " [w] [maxwages] to modify local wages" ); - Awrite( " [p] to regenerate products according to terrain type" ); + Awrite( " [p] to regenerate products according to terrain type" ); Awrite( " [g] to regenerate all according to terrain type" ); if (pReg->gate > 0) Awrite( " [dg] to delete the gate in this region" ); else Awrite( " [ag] to add a gate to this region" ); Awrite( " [n] [name] to modify region name" ); if (pReg->town) { - Awrite( " [town] to regenerate a town" ); + Awrite( " [town] to regenerate a town" ); Awrite( " [deltown] to remove a town" ); Awrite( " [tn] [name] to rename a town" ); Awrite( " [v] to view/modify town markets" ); - } else Awrite( " [town] to add a town" ); - Awrite( " q) Return to previous menu." ); - - int exit = 0; - AString *pStr = AGetString(); - if ( *pStr == "q" ) { - exit = 1; - } else { - AString *pToken = 0; - do { - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + } else Awrite( " [town] to add a town" ); + Awrite( " q) Return to previous menu." ); + + int exit = 0; + AString *pStr = AGetString(); + if ( *pStr == "q" ) { + exit = 1; + } else { + AString *pToken = 0; + do { + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } // modify terrain - if (*pToken == "t") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + if (*pToken == "t") { + SAFE_DELETE( pToken ); + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } int terType = ParseTerrain(pToken); - if (terType == -1) { - Awrite( "No such terrain." ); - break; - } - SAFE_DELETE( pToken ); - + if (terType == -1) { + Awrite( "No such terrain." ); + break; + } + SAFE_DELETE( pToken ); + pReg->type = terType; - } - else if (*pToken == "r") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + } + else if (*pToken == "r") { + SAFE_DELETE( pToken ); + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } int prace = 0; prace = ParseAllItems(pToken); if (!(ItemDefs[prace].type & IT_MAN) || (ItemDefs[prace].flags & ItemType::DISABLED) ) { if (!(*pToken == "none" || *pToken == "None" || *pToken == "0")) { - Awrite( "No such race." ); + Awrite( "No such race." ); break; } else { prace = -1; @@ -561,8 +561,8 @@ void Game::EditGameRegionTerrain( ARegion *pReg ) pReg->UpdateEditRegion(); SAFE_DELETE( pToken ); } - else if (*pToken == "dg") { - SAFE_DELETE( pToken ); + else if (*pToken == "dg") { + SAFE_DELETE( pToken ); if (Globals->DISPERSE_GATE_NUMBERS) { pReg->gate = 0; regions.numberofgates--; @@ -582,7 +582,7 @@ void Game::EditGameRegionTerrain( ARegion *pReg ) } } } - else if (*pToken == "ag") { + else if (*pToken == "ag") { SAFE_DELETE( pToken ); if (pReg->gate > 0) break; regions.numberofgates++; @@ -622,15 +622,15 @@ void Game::EditGameRegionTerrain( ARegion *pReg ) } pReg->gate = gatenum; } - pReg->gatemonth = getrandom(12); + pReg->gatemonth = getrandom(12); } else if (*pToken == "w") { SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } int val = pToken->value(); SAFE_DELETE( pToken ); if (val) { @@ -639,8 +639,8 @@ void Game::EditGameRegionTerrain( ARegion *pReg ) pReg->wages += change; } pReg->UpdateEditRegion(); - } - else if (*pToken == "p") { + } + else if (*pToken == "p") { SAFE_DELETE(pToken); auto removes = remove_if( pReg->products.begin(), @@ -650,8 +650,8 @@ void Game::EditGameRegionTerrain( ARegion *pReg ) for_each (removes, pReg->products.end(), [](Production *p) mutable { delete p; }); pReg->products.erase(removes, pReg->products.end()); pReg->SetupProds(1); - } - else if (*pToken == "g") { + } + else if (*pToken == "g") { SAFE_DELETE(pToken); if (pReg->town) delete pReg->town; @@ -665,35 +665,35 @@ void Game::EditGameRegionTerrain( ARegion *pReg ) pReg->markets.clear(); // empty the vector. pReg->SetupEditRegion(); - pReg->UpdateEditRegion(); + pReg->UpdateEditRegion(); } - else if (*pToken == "n") { + else if (*pToken == "n") { SAFE_DELETE(pToken); - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } - + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } + *pReg->name = *pToken; - SAFE_DELETE(pToken); - } - else if (*pToken == "tn") { SAFE_DELETE(pToken); - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } - + } + else if (*pToken == "tn") { + SAFE_DELETE(pToken); + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } + if (pReg->town) *pReg->town->name = *pToken; - SAFE_DELETE(pToken); - } - else if (*pToken == "town") { SAFE_DELETE(pToken); - + } + else if (*pToken == "town") { + SAFE_DELETE(pToken); + if (pReg->race<0) pReg->race = 9; - + AString *townname = new AString("name"); if (pReg->town) { *townname = *pReg->town->name; @@ -702,10 +702,10 @@ void Game::EditGameRegionTerrain( ARegion *pReg ) pReg->markets.clear(); // empty the vector. } pReg->AddTown(townname); - + pReg->UpdateEditRegion(); // financial stuff! Does markets } - else if (*pToken == "deltown") { + else if (*pToken == "deltown") { SAFE_DELETE(pToken); if (pReg->town) { delete pReg->town; @@ -720,28 +720,28 @@ void Game::EditGameRegionTerrain( ARegion *pReg ) if (pReg->town) EditGameRegionMarkets(pReg); } } - while( 0 ); - if (pToken) delete pToken; - } - if (pStr) delete pStr; - - if ( exit ) { - break; - } - } - while( 1 ); -} + while( 0 ); + if (pToken) delete pToken; + } + if (pStr) delete pStr; + + if ( exit ) { + break; + } + } + while( 1 ); +} void Game::EditGameRegionMarkets( ARegion *pReg ) { /* This only gets called if pReg->town exists! */ do { - Awrite(""); + Awrite(""); Awrite( AString( "Region: " ) + pReg->Print() ); - Awrite( "" ); + Awrite( "" ); // write pop stuff Awrite( AString("") + pReg->town->pop + " " + ItemDefs[pReg->race].names + " townpop"); - + //write markets Awrite(AString("Market Format: ... price(base). minpop/maxpop. minamt/maxamt.")); @@ -764,31 +764,31 @@ void Game::EditGameRegionMarkets( ARegion *pReg ) } } - Awrite( "" ); + Awrite( "" ); - Awrite( " [g] to regenerate all markets" ); - Awrite( " [p] [item] [minpop] [maxpop] to add/modify market population" ); + Awrite( " [g] to regenerate all markets" ); + Awrite( " [p] [item] [minpop] [maxpop] to add/modify market population" ); Awrite( " [a] [item] [minamt] [maxamt] to add/modify market amounts" ); Awrite( " [c] [item] [price] [baseprice] to add/modify item prices" ); Awrite( " [s] [item] to swop an item between wanted and sold" ); Awrite( " [d] [item] to delete an item from the market" ); - Awrite( " q) Return to previous menu." ); - - int exit = 0; - AString *pStr = AGetString(); - if ( *pStr == "q" ) { - exit = 1; - } else { - AString *pToken = 0; + Awrite( " q) Return to previous menu." ); + + int exit = 0; + AString *pStr = AGetString(); + if ( *pStr == "q" ) { + exit = 1; + } else { + AString *pToken = 0; do { - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } // regenerate markets - if (*pToken == "g") { + if (*pToken == "g") { SAFE_DELETE(pToken); for (auto& m : pReg->markets) delete m; // Free the allocated object @@ -797,14 +797,14 @@ void Game::EditGameRegionMarkets( ARegion *pReg ) pReg->SetupCityMarket(); pReg->UpdateEditRegion(); } - else if (*pToken == "p") { + else if (*pToken == "p") { SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } int mitem = ParseEnabledItem(pToken); if (mitem<0) { Awrite("No such item"); @@ -812,23 +812,23 @@ void Game::EditGameRegionMarkets( ARegion *pReg ) } SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); + pToken = pStr->gettoken(); int minimum = pToken->value(); SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); + + pToken = pStr->gettoken(); int maximum = pToken->value(); SAFE_DELETE( pToken ); int done = 0; - + if (minimum + 1 > maximum) { Awrite("Maximum must be more than minimum"); break; } int population = pReg->Population(); - + for (auto& m : pReg->markets) { if (m->item == mitem) { m->minpop = minimum; @@ -856,14 +856,14 @@ void Game::EditGameRegionMarkets( ARegion *pReg ) } } - else if (*pToken == "a") { + else if (*pToken == "a") { SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } int mitem = ParseEnabledItem(pToken); if (mitem<0) { Awrite("No such item"); @@ -871,28 +871,28 @@ void Game::EditGameRegionMarkets( ARegion *pReg ) } SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); + pToken = pStr->gettoken(); int minimum = pToken->value(); SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); + + pToken = pStr->gettoken(); int maximum = pToken->value(); SAFE_DELETE( pToken ); int done = 0; - + if (minimum + 1 > maximum) { Awrite("Maximum must be more than minimum"); break; } - + int population = pReg->Population(); - + for (auto& m: pReg->markets) { if (m->item == mitem) { m->minamt = minimum; m->maxamt = maximum; - + if (population <= m->minpop) m->amount = m->minamt; else { @@ -916,14 +916,14 @@ void Game::EditGameRegionMarkets( ARegion *pReg ) } } - else if (*pToken == "c") { + else if (*pToken == "c") { SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } int mitem = ParseEnabledItem(pToken); if (mitem<0) { Awrite("No such item"); @@ -931,11 +931,11 @@ void Game::EditGameRegionMarkets( ARegion *pReg ) } SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); + pToken = pStr->gettoken(); int price = pToken->value(); SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); + + pToken = pStr->gettoken(); int baseprice = pToken->value(); SAFE_DELETE( pToken ); @@ -959,22 +959,22 @@ void Game::EditGameRegionMarkets( ARegion *pReg ) pReg->markets.push_back(m); } - } - else if (*pToken == "s") { + } + else if (*pToken == "s") { SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } int mitem = ParseEnabledItem(pToken); if (mitem<0) { Awrite("No such item"); break; } SAFE_DELETE( pToken ); - + // remove all duplicate market items of the same type. std::unordered_set s; auto dupes = remove_if( @@ -992,24 +992,24 @@ void Game::EditGameRegionMarkets( ARegion *pReg ) if (m != pReg->markets.end()) { (*m)->type = (*m)->type == M_SELL ? M_BUY : M_SELL; } else { - Awrite("No such market"); + Awrite("No such market"); } } - else if (*pToken == "d") { + else if (*pToken == "d") { SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } int mitem = ParseEnabledItem(pToken); if (mitem<0) { Awrite("No such item"); break; } SAFE_DELETE( pToken ); - + auto m = find_if( pReg->markets.begin(), pReg->markets.end(), @@ -1024,20 +1024,20 @@ void Game::EditGameRegionMarkets( ARegion *pReg ) for_each (dupes, pReg->markets.end(), [](Market *m) mutable { delete m; }); pReg->markets.erase(dupes, pReg->markets.end()); } else { - Awrite("No such market"); + Awrite("No such market"); } - } + } } - while( 0 ); - if (pToken) delete pToken; - } - if (pStr) delete pStr; - - if ( exit ) { - break; - } - } - while( 1 ); + while( 0 ); + if (pToken) delete pToken; + } + if (pStr) delete pStr; + + if ( exit ) { + break; + } + } + while( 1 ); } @@ -1051,8 +1051,8 @@ void Game::EditGameUnit(Unit *pUnit) Awrite(" 1) Edit items..."); Awrite(" 2) Edit skills..."); Awrite(" 3) Move unit..."); - Awrite(" 4) Edit details..."); - + Awrite(" 4) Edit details..."); + Awrite(" q) Stop editing this unit."); int exit = 0; @@ -1064,7 +1064,7 @@ void Game::EditGameUnit(Unit *pUnit) } else if (*pStr == "3") { EditGameUnitMove(pUnit); } else if (*pStr == "4") { - EditGameUnitDetails(pUnit); + EditGameUnitDetails(pUnit); } else if (*pStr == "q") { exit = 1; } else { @@ -1205,7 +1205,7 @@ void Game::EditGameUnitDetails(Unit *pUnit) { do { int exit = 0; - Awrite(AString("Unit: ") + *(pUnit->name)); + Awrite(AString("Unit: ") + *(pUnit->name)); Awrite(AString("Unit faction: ") + *(pUnit->faction->name)); AString temp = " ("; @@ -1221,26 +1221,26 @@ void Game::EditGameUnitDetails(Unit *pUnit) break; case U_WMON: temp += "monster"; - break; + break; case U_GUARDMAGE: temp += "guardmage"; break; case U_APPRENTICE: temp += Globals->APPRENTICE_NAME; - break; + break; } temp += ")"; Awrite(AString("Unit type: ") + pUnit->type + temp); - + Awrite(""); Awrite(" [f] [num] to change the unit's faction."); - Awrite(" [t] [num] to change the unit's type."); + Awrite(" [t] [num] to change the unit's type."); Awrite(" [q] Go back one screen."); - + AString *pStr = AGetString(); if (*pStr == "q") { exit = 1; - } + } else { AString *pToken = 0; do { @@ -1250,33 +1250,33 @@ void Game::EditGameUnitDetails(Unit *pUnit) break; } // change faction - if (*pToken == "f") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + if (*pToken == "f") { + SAFE_DELETE( pToken ); + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } int fnum = pToken->value(); - SAFE_DELETE( pToken ); + SAFE_DELETE( pToken ); if (fnum<1) { Awrite("Invalid Faction Number"); break; } - + Faction *fac = GetFaction(&factions, fnum); if (fac) pUnit->faction = fac; else Awrite("Cannot Find Faction"); } - else if (*pToken == "t") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if ( !pToken ) { - Awrite( "Try again." ); - break; - } + else if (*pToken == "t") { + SAFE_DELETE( pToken ); + pToken = pStr->gettoken(); + if ( !pToken ) { + Awrite( "Try again." ); + break; + } int newtype = pToken->value(); - SAFE_DELETE( pToken ); + SAFE_DELETE( pToken ); if (newtype<0 || newtype>NUNITTYPES-1) { Awrite("Invalid Type"); break; diff --git a/fracas/map.cpp b/fracas/map.cpp index 39b83bd9..70c80d18 100644 --- a/fracas/map.cpp +++ b/fracas/map.cpp @@ -34,7 +34,7 @@ int ARegion::CheckSea(int dir, int range, int remainocean) if (range-- < 1) return 1; for (int d2 = -1; d2< 2; d2++) { int direc = (dir + d2 + NDIRS) % NDIRS; - ARegion *newregion = neighbors[direc]; + ARegion *newregion = neighbors(direc); if (!newregion) continue; remainocean += newregion->CheckSea(dir, range, remainocean); if (remainocean) break; @@ -155,21 +155,21 @@ void ARegionList::CreateSurfaceLevel(int level, int xSize, int ySize, char const int sea = Globals->OCEAN; if (Globals->SEA_LIMIT) sea = sea * (100 + 2 * Globals->SEA_LIMIT) / 100; - + MakeLand(pRegionArrays[level], sea, Globals->CONTINENT_SIZE); - + CleanUpWater(pRegionArrays[level]); SetupAnchors(pRegionArrays[level]); - + GrowTerrain(pRegionArrays[level], 0); - + AssignTypes(pRegionArrays[level]); SeverLandBridges(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); FinalSetup(pRegionArrays[level]); @@ -281,9 +281,9 @@ void ARegionList::MakeRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; - reg->wages = -1; - + reg->race = -1; + reg->wages = -1; + reg->level = arr; Add(reg); arr->SetRegion(x, y, reg); @@ -376,7 +376,7 @@ void ARegionList::MakeIcosahedralRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; // + reg->race = -1; // reg->wages = -1; // initially store: name reg->population = -1; // initially used as flag reg->elevation = -1; @@ -431,7 +431,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if (!reg) continue; ARegion *newreg = reg; ARegion *seareg = reg; - + // Archipelago or Continent? if (getrandom(100) < Globals->ARCHIPELAGO) { // Make an Archipelago: @@ -440,21 +440,21 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int tries = 0; for (int i=0; ineighbors[direc]; + newreg = reg->neighbors(direc); while (!newreg) { direc = getrandom(6); - newreg = reg->neighbors[direc]; + newreg = reg->neighbors(direc); } tries++; for (int m = 0; m < 2; m++) { seareg = newreg; - newreg = seareg->neighbors[direc]; + newreg = seareg->neighbors(direc); if (!newreg) break; } if (!newreg) break; if (newreg) { seareg = newreg; - newreg = seareg->neighbors[getrandom(NDIRS)]; + newreg = seareg->neighbors(getrandom(NDIRS)); if (!newreg) break; // island start point (~3 regions away from last island) seareg = newreg; @@ -481,11 +481,11 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int newdir = getrandom(NDIRS); while (direc == reg->GetRealDirComp(newdir)) newdir = getrandom(NDIRS); - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); while ((!newreg) && (tries < 36)) { while (direc == reg->GetRealDirComp(newdir)) newdir = getrandom(NDIRS); - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); tries++; } if (!newreg) continue; @@ -511,12 +511,12 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if ((reg->yloc < yoff*2) && ((dir < 2) || (dir == (NDIRS-1))) && (getrandom(4) < 3)) continue; if ((reg->yloc > (yband+yoff)*2) && ((dir < 5) && (dir > 1)) - && (getrandom(4) < 3)) continue; - ARegion *newreg = reg->neighbors[dir]; + && (getrandom(4) < 3)) continue; + ARegion *newreg = reg->neighbors(dir); if (!newreg) break; int polecheck = 0; for (int v=0; v < NDIRS; v++) { - ARegion *creg = newreg->neighbors[v]; + ARegion *creg = newreg->neighbors(v); if (!creg) polecheck = 1; } if (polecheck) break; @@ -635,7 +635,7 @@ void ARegionList::RemoveCoastalLakes(ARegionArray *pRegs) int count2 = 0; int temp = 0; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; // name after neighboring lake regions preferrentially if ((newregion->wages > 0) && @@ -682,7 +682,7 @@ void ARegionList::SeverLandBridges(ARegionArray *pRegs) if (reg->IsCoastal() != 4) continue; int tidych = Globals->SEVER_LAND_BRIDGES; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if ((!newregion) || (TerrainDefs[newregion->type].similar_type == R_OCEAN)) continue; @@ -774,7 +774,7 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) if (!reg) continue; if ((j > 0) && (j < 21) && (getrandom(3) < 2)) continue; if (reg->type == R_NUM) { - + // Check for Lakes if (Globals->LAKES && (getrandom(100) < (Globals->LAKES/10 + 1))) { @@ -788,11 +788,11 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) reg->wages = AGetName(0, reg); break; } - + int init = getrandom(6); for (int i=0; ineighbors[(i+init) % NDIRS]; + ARegion *t = reg->neighbors((i+init) % NDIRS); if (t) { if (t->population < 1) continue; if (t->type != R_NUM && @@ -833,7 +833,7 @@ void ARegionList::RandomTerrain(ARegionArray *pArr) int adjtype = 0; int adjname = -1; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; if ((TerrainDefs[newregion->type].similar_type != R_OCEAN) && (newregion->type != R_NUM) && @@ -866,21 +866,21 @@ void ARegionList::MakeUWMaze(ARegionArray *pArr) for (int i=D_NORTH; i<= NDIRS; i++) { int count = 0; for (int j=D_NORTH; j< NDIRS; j++) - if (reg->neighbors[j]) count++; + if (reg->neighbors(j)) count++; if (count <= 1) break; - ARegion *n = reg->neighbors[i]; + ARegion *n = reg->neighbors(i); if (n) { if (n->xloc < x || (n->xloc == x && n->yloc < y)) continue; if (!CheckRegionExit(reg, n)) { count = 0; for (int k = D_NORTH; kneighbors[k]) count++; + if (n->neighbors(k)) count++; } if (count <= 1) break; - n->neighbors[reg->GetRealDirComp(i)] = 0; - reg->neighbors[i] = 0; + n->neighbors(reg->GetRealDirComp(i)) = 0; + reg->neighbors(i) = 0; } } } @@ -920,25 +920,25 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) int xoff = x + 2 - getrandom(3) - getrandom(3); ARegion *reg = pArr->GetRegion(xoff, y); if (!reg) continue; - + if ((reg->type == R_LAKE) && (!Globals->LAKESIDE_IS_COASTAL)) continue; if (TerrainDefs[reg->type].flags & TerrainType::BARREN) continue; - + reg->race = -1; wigout = 0; // reset sanity - + if (TerrainDefs[reg->type].similar_type == R_OCEAN) { // setup near coastal race here int d = getrandom(NDIRS); int ctr = 0; - ARegion *nreg = reg->neighbors[d]; + ARegion *nreg = reg->neighbors(d); if (!nreg) continue; while((ctr++ < 20) && (reg->race == -1)) { if (TerrainDefs[nreg->type].similar_type != R_OCEAN) { int rnum = sizeof(TerrainDefs[nreg->type].coastal_races) / sizeof(TerrainDefs[nreg->type].coastal_races[0]); - + while ( reg->race == -1 || (ItemDefs[reg->race].flags & ItemType::DISABLED)) { reg->race = TerrainDefs[nreg->type].coastal_races[getrandom(rnum)]; if (++wigout > 100) break; @@ -946,20 +946,20 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) } else { int dir = getrandom(NDIRS); if (d == nreg->GetRealDirComp(dir)) continue; - if (!(nreg->neighbors[dir])) continue; - nreg = nreg->neighbors[dir]; + if (!(nreg->neighbors(dir))) continue; + nreg = nreg->neighbors(dir); } } } else { // setup noncoastal race here int rnum = sizeof(TerrainDefs[reg->type].races)/sizeof(TerrainDefs[reg->type].races[0]); - + while ( reg->race == -1 || (ItemDefs[reg->race].flags & ItemType::DISABLED)) { reg->race = TerrainDefs[reg->type].races[getrandom(rnum)]; if (++wigout > 100) break; } } - + /* leave out this sort of check for the moment if (wigout > 100) { // do something! @@ -968,10 +968,10 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) Awrite(" region type"); } */ - + if (reg->race == -1) { - cout << "Hey! No race anchor got assigned to the " - << TerrainDefs[reg->type].name + cout << "Hey! No race anchor got assigned to the " + << TerrainDefs[reg->type].name << " at " << x << "," << y << "\n"; } } @@ -990,7 +990,7 @@ void ARegionList::GrowRaces(ARegionArray *pArr) if ((!reg) || (reg->race == -1)) continue; for (int dir = 0; dir < NDIRS; dir++) { - ARegion *nreg = reg->neighbors[dir]; + ARegion *nreg = reg->neighbors(dir); if ((!nreg) || (nreg->race != -1)) continue; int iscoastal = 0; int cnum = sizeof(TerrainDefs[reg->type].coastal_races) / @@ -1118,10 +1118,10 @@ void ARegionList::SetACNeighbors(int levelSrc, int levelTo, int maxX, int maxY) ARegion *AC = ar->GetRegion(x, y); if (!AC) continue; for (int i=0; ineighbors[i]) continue; + if (AC->neighbors(i)) continue; ARegion *pReg = GetStartingCity(AC, i, levelTo, maxX, maxY); if (!pReg) continue; - AC->neighbors[i] = pReg; + AC->neighbors(i) = pReg; pReg->MakeStartingCity(); if (Globals->GATES_EXIST) { numberofgates++; diff --git a/fracas/world.cpp b/fracas/world.cpp index f83d51bf..3cf81a89 100644 --- a/fracas/world.cpp +++ b/fracas/world.cpp @@ -2484,7 +2484,7 @@ int ARegion::CanBeStartingCity( ARegionArray *pRA ) while(inlist.Num()) { ARegionPtr * reg = (ARegionPtr *) inlist.First(); for (int i=0; iptr->neighbors[i]; + ARegion * r2 = reg->ptr->neighbors(i); if (!r2) continue; if (r2->type == R_OCEAN) continue; if (GetRegion(&inlist,r2->num)) continue; @@ -2506,9 +2506,9 @@ void ARegion::MakeStartingCity() if (!Globals->TOWNS_EXIST) return; if (Globals->GATES_EXIST) gate = -1; - + if (town) delete town; - + AddTown(TOWN_CITY); if (!Globals->START_CITIES_EXIST) return; @@ -2599,8 +2599,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; @@ -2626,8 +2626,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; diff --git a/havilah/map.cpp b/havilah/map.cpp index f669d22e..35da31ef 100644 --- a/havilah/map.cpp +++ b/havilah/map.cpp @@ -34,7 +34,7 @@ int ARegion::CheckSea(int dir, int range, int remainocean) if (range-- < 1) return 1; for (int d2 = -1; d2< 2; d2++) { int direc = (dir + d2 + NDIRS) % NDIRS; - ARegion *newregion = neighbors[direc]; + ARegion *newregion = neighbors(direc); if (!newregion) continue; remainocean += newregion->CheckSea(dir, range, remainocean); if (remainocean) break; @@ -155,21 +155,21 @@ void ARegionList::CreateSurfaceLevel(int level, int xSize, int ySize, char const int sea = Globals->OCEAN; if (Globals->SEA_LIMIT) sea = sea * (100 + 2 * Globals->SEA_LIMIT) / 100; - + MakeLand(pRegionArrays[level], sea, Globals->CONTINENT_SIZE); - + CleanUpWater(pRegionArrays[level]); SetupAnchors(pRegionArrays[level]); - + GrowTerrain(pRegionArrays[level], 0); - + AssignTypes(pRegionArrays[level]); SeverLandBridges(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); FinalSetup(pRegionArrays[level]); @@ -191,7 +191,7 @@ void ARegionList::CreateIslandLevel(int level, int nPlayers, char const *name) RandomTerrain(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); FinalSetup(pRegionArrays[level]); @@ -230,7 +230,7 @@ void ARegionList::CreateUnderworldLevel(int level, int xSize, int ySize, MakeUWMaze(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); FinalSetup(pRegionArrays[level]); @@ -259,7 +259,7 @@ void ARegionList::CreateUnderdeepLevel(int level, int xSize, int ySize, MakeUWMaze(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); FinalSetup(pRegionArrays[level]); @@ -287,9 +287,9 @@ void ARegionList::MakeRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; - reg->wages = -1; - + reg->race = -1; + reg->wages = -1; + reg->level = arr; Add(reg); arr->SetRegion(x, y, reg); @@ -382,7 +382,7 @@ void ARegionList::MakeIcosahedralRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; // + reg->race = -1; // reg->wages = -1; // initially store: name reg->population = -1; // initially used as flag reg->elevation = -1; @@ -437,7 +437,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if (!reg) continue; ARegion *newreg = reg; ARegion *seareg = reg; - + // Archipelago or Continent? if (getrandom(100) < Globals->ARCHIPELAGO) { // Make an Archipelago: @@ -446,21 +446,21 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int tries = 0; for (int i=0; ineighbors[direc]; + newreg = reg->neighbors(direc); while (!newreg) { direc = getrandom(NDIRS); - newreg = reg->neighbors[direc]; + newreg = reg->neighbors(direc); } tries++; for (int m = 0; m < 2; m++) { seareg = newreg; - newreg = seareg->neighbors[direc]; + newreg = seareg->neighbors(direc); if (!newreg) break; } if (!newreg) break; if (newreg) { seareg = newreg; - newreg = seareg->neighbors[getrandom(NDIRS)]; + newreg = seareg->neighbors(getrandom(NDIRS)); if (!newreg) break; // island start point (~3 regions away from last island) seareg = newreg; @@ -488,12 +488,12 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, while (direc == reg->GetRealDirComp(newdir)) { newdir = getrandom(NDIRS); } - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); while ((!newreg) && (tries < 36)) { while (direc == reg->GetRealDirComp(newdir)) { newdir = getrandom(NDIRS); } - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); tries++; } if (!newreg) continue; @@ -519,12 +519,12 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if ((reg->yloc < yoff*2) && ((dir < 2) || (dir == (NDIRS-1))) && (getrandom(4) < 3)) continue; if ((reg->yloc > (yband+yoff)*2) && ((dir < 5) && (dir > 1)) - && (getrandom(4) < 3)) continue; - ARegion *newreg = reg->neighbors[dir]; + && (getrandom(4) < 3)) continue; + ARegion *newreg = reg->neighbors(dir); if (!newreg) break; int polecheck = 0; for (int v=0; v < NDIRS; v++) { - ARegion *creg = newreg->neighbors[v]; + ARegion *creg = newreg->neighbors(v); if (!creg) polecheck = 1; } if (polecheck) break; @@ -643,7 +643,7 @@ void ARegionList::RemoveCoastalLakes(ARegionArray *pRegs) int count2 = 0; int temp = 0; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; // name after neighboring lake regions preferrentially if ((newregion->wages > 0) && @@ -690,7 +690,7 @@ void ARegionList::SeverLandBridges(ARegionArray *pRegs) if (reg->IsCoastal() != 4) continue; int tidych = Globals->SEVER_LAND_BRIDGES; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if ((!newregion) || (TerrainDefs[newregion->type].similar_type == R_OCEAN)) continue; @@ -782,7 +782,7 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) if (!reg) continue; if ((j > 0) && (j < 21) && (getrandom(3) < 2)) continue; if (reg->type == R_NUM) { - + // Check for Lakes if (Globals->LAKES && (getrandom(100) < (Globals->LAKES/10 + 1))) { @@ -796,11 +796,11 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) reg->wages = AGetName(0, reg); break; } - + int init = getrandom(6); for (int i=0; ineighbors[(i+init) % NDIRS]; + ARegion *t = reg->neighbors((i+init) % NDIRS); if (t) { if (t->population < 1) continue; if (t->type != R_NUM && @@ -841,7 +841,7 @@ void ARegionList::RandomTerrain(ARegionArray *pArr) int adjtype = 0; int adjname = -1; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; if ((TerrainDefs[newregion->type].similar_type != R_OCEAN) && (newregion->type != R_NUM) && @@ -874,21 +874,21 @@ void ARegionList::MakeUWMaze(ARegionArray *pArr) for (int i=D_NORTH; i<= NDIRS; i++) { int count = 0; for (int j=D_NORTH; j< NDIRS; j++) - if (reg->neighbors[j]) count++; + if (reg->neighbors(j)) count++; if (count <= 1) break; - ARegion *n = reg->neighbors[i]; + ARegion *n = reg->neighbors(i); if (n) { if (n->xloc < x || (n->xloc == x && n->yloc < y)) continue; if (!CheckRegionExit(reg, n)) { count = 0; for (int k = D_NORTH; kneighbors[k]) count++; + if (n->neighbors(k)) count++; } if (count <= 1) break; - n->neighbors[reg->GetRealDirComp(i)] = 0; - reg->neighbors[i] = 0; + n->neighbors(reg->GetRealDirComp(i)) = 0; + reg->neighbors(i) = 0; } } } @@ -928,25 +928,25 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) int xoff = x + 2 - getrandom(3) - getrandom(3); ARegion *reg = pArr->GetRegion(xoff, y); if (!reg) continue; - + if ((reg->type == R_LAKE) && (!Globals->LAKESIDE_IS_COASTAL)) continue; if (TerrainDefs[reg->type].flags & TerrainType::BARREN) continue; - + reg->race = -1; wigout = 0; // reset sanity - + if (TerrainDefs[reg->type].similar_type == R_OCEAN) { // setup near coastal race here int d = getrandom(NDIRS); int ctr = 0; - ARegion *nreg = reg->neighbors[d]; + ARegion *nreg = reg->neighbors(d); if (!nreg) continue; while((ctr++ < 20) && (reg->race == -1)) { if (TerrainDefs[nreg->type].similar_type != R_OCEAN) { int rnum = sizeof(TerrainDefs[nreg->type].coastal_races) / sizeof(TerrainDefs[nreg->type].coastal_races[0]); - + while ( reg->race == -1 || (ItemDefs[reg->race].flags & ItemType::DISABLED)) { reg->race = TerrainDefs[nreg->type].coastal_races[getrandom(rnum)]; if (++wigout > 100) break; @@ -954,20 +954,20 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) } else { int dir = getrandom(NDIRS); if (d == nreg->GetRealDirComp(dir)) continue; - if (!(nreg->neighbors[dir])) continue; - nreg = nreg->neighbors[dir]; + if (!(nreg->neighbors(dir))) continue; + nreg = nreg->neighbors(dir); } } } else { // setup noncoastal race here int rnum = sizeof(TerrainDefs[reg->type].races)/sizeof(TerrainDefs[reg->type].races[0]); - + while ( reg->race == -1 || (ItemDefs[reg->race].flags & ItemType::DISABLED)) { reg->race = TerrainDefs[reg->type].races[getrandom(rnum)]; if (++wigout > 100) break; } } - + /* leave out this sort of check for the moment if (wigout > 100) { // do something! @@ -976,10 +976,10 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) Awrite(" region type"); } */ - + if (reg->race == -1) { - cout << "Hey! No race anchor got assigned to the " - << TerrainDefs[reg->type].name + cout << "Hey! No race anchor got assigned to the " + << TerrainDefs[reg->type].name << " at " << x << "," << y << "\n"; } } @@ -998,7 +998,7 @@ void ARegionList::GrowRaces(ARegionArray *pArr) if ((!reg) || (reg->race == -1)) continue; for (int dir = 0; dir < NDIRS; dir++) { - ARegion *nreg = reg->neighbors[dir]; + ARegion *nreg = reg->neighbors(dir); if ((!nreg) || (nreg->race != -1)) continue; int iscoastal = 0; int cnum = sizeof(TerrainDefs[reg->type].coastal_races) / @@ -1127,10 +1127,10 @@ void ARegionList::SetACNeighbors(int levelSrc, int levelTo, int maxX, int maxY) if (!AC) continue; if (Globals->START_CITIES_EXIST) { for (int i=0; ineighbors[i]) continue; + if (AC->neighbors(i)) continue; ARegion *pReg = GetStartingCity(AC, i, levelTo, maxX, maxY); if (!pReg) continue; - AC->neighbors[i] = pReg; + AC->neighbors(i) = pReg; pReg->MakeStartingCity(); if (Globals->GATES_EXIST) { numberofgates++; @@ -1155,7 +1155,7 @@ void ARegionList::SetACNeighbors(int levelSrc, int levelTo, int maxX, int maxY) found = 1; Object *o = new Object(AC); o->num = AC->buildingseq++; - o->name = new AString(AString("Gateway to ") + + o->name = new AString(AString("Gateway to ") + TerrainDefs[type].name + " [" + o->num + "]"); o->type = O_GATEWAY; o->incomplete = 0; @@ -1196,7 +1196,7 @@ void ARegionList::InitSetupGates(int level) void ARegionList::FixUnconnectedRegions() { - ARegion *r, *head, *tail, *neighbors[NDIRS], *n; + ARegion *r, *head, *tail, *neighbors(NDIRS), *n; int attempts, max, i, j, count, offset, x, y, xscale, yscale; Object *o; @@ -1252,7 +1252,7 @@ void ARegionList::FixUnconnectedRegions() // first, see if we can knock down a wall // sadly we can only knock down all the walls at once for (i = 0; i < NDIRS; i++) - neighbors[i] = r->neighbors[i]; + neighbors(i) = r->neighbors(i); if (Globals->ICOSAHEDRAL_WORLD) { IcosahedralNeighSetup(r, pRegionArrays[r->zloc]); } else { @@ -1260,8 +1260,8 @@ void ARegionList::FixUnconnectedRegions() } offset = getrandom(NDIRS); for (i = 0; i < NDIRS; i++) { - if (r->neighbors[(i + offset) % NDIRS] && - r->neighbors[(i + offset) % NDIRS]->distance != -1) { + if (r->neighbors((i + offset) % NDIRS) && + r->neighbors((i + offset) % NDIRS)->distance != -1) { break; } } @@ -1269,21 +1269,21 @@ void ARegionList::FixUnconnectedRegions() // restore all the walls other than the one // we meant to break if (i != j) - r->neighbors[(j + offset) % NDIRS] = neighbors[(j + offset) % NDIRS]; + r->neighbors((j + offset) % NDIRS) = neighbors((j + offset) % NDIRS); } if (i < NDIRS) { // also restore the link on the other side - n = r->neighbors[(i + offset) % NDIRS]; + n = r->neighbors((i + offset) % NDIRS); for (j = 0; j < NDIRS; j++) - neighbors[j] = n->neighbors[j]; + neighbors(j) = n->neighbors(j); if (Globals->ICOSAHEDRAL_WORLD) { IcosahedralNeighSetup(n, pRegionArrays[r->zloc]); } else { NeighSetup(n, pRegionArrays[n->zloc]); } for (j = 0; j < NDIRS; j++) - if (n->neighbors[j] != r) - n->neighbors[j] = neighbors[j]; + if (n->neighbors(j) != r) + n->neighbors(j) = neighbors(j); } else if (TerrainDefs[r->type].similar_type != R_OCEAN) { // couldn't break a wall // so try to put in a shaft diff --git a/havilah/world.cpp b/havilah/world.cpp index ce64ab2e..567c57ff 100644 --- a/havilah/world.cpp +++ b/havilah/world.cpp @@ -248,8 +248,8 @@ int AGetName(int town, ARegion *reg) port = 0; if (town) { for (i = 0; i < NDIRS; i++) - if (reg->neighbors[i] && - TerrainDefs[reg->neighbors[i]->type].similar_type == R_OCEAN) + if (reg->neighbors(i) && + TerrainDefs[reg->neighbors(i)->type].similar_type == R_OCEAN) port = 1; } @@ -754,7 +754,7 @@ int ARegion::CanBeStartingCity( ARegionArray *pRA ) while(inlist.Num()) { ARegionPtr * reg = (ARegionPtr *) inlist.First(); for (int i=0; iptr->neighbors[i]; + ARegion * r2 = reg->ptr->neighbors(i); if (!r2) continue; if (r2->type == R_OCEAN) continue; if (GetRegion(&inlist,r2->num)) continue; @@ -776,9 +776,9 @@ void ARegion::MakeStartingCity() if (!Globals->TOWNS_EXIST) return; if (Globals->GATES_EXIST) gate = -1; - + if (town) delete town; - + AddTown(TOWN_CITY); if (!Globals->START_CITIES_EXIST) return; @@ -868,8 +868,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; @@ -895,8 +895,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; diff --git a/kingdoms/map.cpp b/kingdoms/map.cpp index 602b3a4d..674164c4 100644 --- a/kingdoms/map.cpp +++ b/kingdoms/map.cpp @@ -41,7 +41,7 @@ int ARegion::CheckSea(int dir, int range, int remainocean) if (range-- < 1) return 1; for (int d2 = -1; d2< 2; d2++) { int direc = (dir + d2 + NDIRS) % NDIRS; - ARegion *newregion = neighbors[direc]; + ARegion *newregion = neighbors(direc); if (!newregion) continue; remainocean += newregion->CheckSea(dir, range, remainocean); if (remainocean) break; @@ -53,7 +53,7 @@ int ARegion::Slope() { int retval = 0; for (int i=0; ielevation - elevation); if (d > retval) retval = d; @@ -65,7 +65,7 @@ int ARegion::SurfaceWater() { int retval = 0; for (int i=0; ihumidity - humidity); if (d > retval) retval = d; @@ -77,7 +77,7 @@ int ARegion::Soil() { int retval = 0; for (int i=0; ivegetation - vegetation); if (d > retval) retval = d; @@ -89,7 +89,7 @@ int ARegion::Winds() { int retval = 0; for (int i=0; itemperature - temperature); if (d > retval) retval = d; @@ -172,7 +172,7 @@ int ARegion::TerrainProbability(int terrain) break; default: // LAKE for (int i=0; i < NDIRS; i++) { - ARegion *nr = neighbors[i]; + ARegion *nr = neighbors(i); if (!nr) continue; if (nr->type == R_OCEAN) retval += 500; } @@ -295,25 +295,25 @@ void ARegionList::CreateSurfaceLevel(int level, int xSize, int ySize, char const int sea = Globals->OCEAN; if (Globals->SEA_LIMIT) sea = sea * (100 + 2 * Globals->SEA_LIMIT) / 100; - + InitGeographicMap(pRegionArrays[level]); - + MakeLand(pRegionArrays[level], sea, Globals->CONTINENT_SIZE); - + RescaleFractalParameters(pRegionArrays[level]); CleanUpWater(pRegionArrays[level]); - SetFractalTerrain(pRegionArrays[level]); - + SetFractalTerrain(pRegionArrays[level]); + GrowTerrain(pRegionArrays[level], 0); - + AssignTypes(pRegionArrays[level]); SeverLandBridges(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + NameRegions(pRegionArrays[level]); if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); @@ -407,18 +407,18 @@ void ARegionList::MakeRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; // + reg->race = -1; // reg->wages = -1; // initially store: name reg->population = -1; // initially used as flag reg->elevation = -1; - + reg->level = arr; Add(reg); arr->SetRegion(x, y, reg); } } } - + SetupNeighbors(arr); Awrite(""); @@ -504,7 +504,7 @@ void ARegionList::MakeIcosahedralRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; // + reg->race = -1; // reg->wages = -1; // initially store: name reg->population = -1; // initially used as flag reg->elevation = -1; @@ -551,7 +551,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, for (int y=0; y < pRegs->y; y++) { ARegion *r = pRegs->GetRegion(x,y); if (!r) continue; - total++; + total++; } } ocean = total; @@ -573,7 +573,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if (!reg) continue; ARegion *newreg = reg; ARegion *seareg = reg; - + // Archipelago or Continent? if (getrandom(100) < Globals->ARCHIPELAGO) { // Make an Archipelago: @@ -582,21 +582,21 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int tries = 0; for (int i=0; ineighbors[direc]; + newreg = reg->neighbors(direc); while (!newreg) { direc = getrandom(6); - newreg = reg->neighbors[direc]; + newreg = reg->neighbors(direc); } tries++; for (int m = 0; m < 2; m++) { seareg = newreg; - newreg = seareg->neighbors[direc]; + newreg = seareg->neighbors(direc); if (!newreg) break; } if (!newreg) break; if (newreg) { seareg = newreg; - newreg = seareg->neighbors[getrandom(NDIRS)]; + newreg = seareg->neighbors(getrandom(NDIRS)); if (!newreg) break; // island start point (~3 regions away from last island) seareg = newreg; @@ -623,11 +623,11 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int newdir = getrandom(NDIRS); while (direc == reg->GetRealDirComp(newdir)) newdir = getrandom(NDIRS); - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); while ((!newreg) && (tries < 36)) { while (direc == reg->GetRealDirComp(newdir)) newdir = getrandom(NDIRS); - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); tries++; } if (!newreg) continue; @@ -644,7 +644,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, } } else { // make a continent - + if (reg->type == -1) { reg->type = R_NUM; ocean--; @@ -654,12 +654,12 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if ((reg->yloc < yoff*2) && ((dir < 2) || (dir == (NDIRS-1))) && (getrandom(4) < 3)) continue; if ((reg->yloc > (yband+yoff)*2) && ((dir < 5) && (dir > 1)) - && (getrandom(4) < 3)) continue; - ARegion *newreg = reg->neighbors[dir]; + && (getrandom(4) < 3)) continue; + ARegion *newreg = reg->neighbors(dir); if (!newreg) break; int polecheck = 0; for (int v=0; v < NDIRS; v++) { - ARegion *creg = newreg->neighbors[v]; + ARegion *creg = newreg->neighbors(v); if (!creg) polecheck = 1; } if (polecheck) break; @@ -668,7 +668,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, reg->type = R_NUM; ocean--; } - } + } } } } else { @@ -687,7 +687,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if ((reg->type == -1) && (reg->elevation > sealevel)) { int cont = 0; for (int i=0; i < NDIRS; i++) { - ARegion *nr = reg->neighbors[i]; + ARegion *nr = reg->neighbors(i); if (!nr) continue; if (nr->elevation > sealevel) { cont++; @@ -696,7 +696,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int d = i + k; if (d < 0) d += NDIRS; if (d >= NDIRS) d = NDIRS - d; - ARegion *ar = nr->neighbors[d]; + ARegion *ar = nr->neighbors(d); if (!ar) continue; if (ar->elevation > sealevel) cont++; } @@ -707,14 +707,14 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, reg->type = R_NUM; ocean--; } - } + } } } sealevel--; Adot(); } Awrite(""); - + Awrite("Add further land"); int coast = sealevel; int dotter = 0; @@ -743,15 +743,15 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, sealevel--; margin = getrandom(sealevel/10 + 2) + 2; } - + int cont = 0; for (int i=0; ineighbors[i]; + ARegion *nr = reg->neighbors(i); if (!nr) continue; if (nr->elevation >= reg->elevation-3) cont++; } if (cont < 3) continue; - + if (dotter%50 == 0) Adot(); // make a continent if (reg->type == -1) { @@ -765,7 +765,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, for (int d=0; d= NDIRS) dir -= NDIRS; - newreg = reg->neighbors[dir]; + newreg = reg->neighbors(dir); if (!newreg) continue; if ((newreg->type == -1) && (newreg->elevation > sealevel/2)) { if (newreg->elevation+getrandom(10) > maxe1) { @@ -776,16 +776,16 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, } if (d1 >= 0) dir = d1; else dir = getrandom(NDIRS); - + if ((reg->yloc < yoff*2) && ((dir < 2) || (dir = NDIRS-1)) && (getrandom(4) < 3)) continue; if ((reg->yloc > (yband+yoff)*2) && ((dir < 5) && (dir > 1)) - && (getrandom(4) < 3)) continue; - ARegion *newreg = reg->neighbors[dir]; + && (getrandom(4) < 3)) continue; + ARegion *newreg = reg->neighbors(dir); if (!newreg) break; int polecheck = 0; for (int v=0; v < NDIRS; v++) { - ARegion *creg = newreg->neighbors[v]; + ARegion *creg = newreg->neighbors(v); if (!creg) polecheck = 1; } if (polecheck) break; @@ -797,7 +797,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, } } } - + // At this point, go back through and set all the rest to ocean SetRegTypes(pRegs, R_OCEAN); Awrite(""); @@ -845,7 +845,7 @@ void ARegionList::RemoveCoastalLakes(ARegionArray *pRegs) int count2 = 0; int temp = 0; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; // name after neighboring lake regions preferrentially if ((newregion->wages > 0) && @@ -892,7 +892,7 @@ void ARegionList::SeverLandBridges(ARegionArray *pRegs) if (reg->IsCoastal() != 4) continue; int tidych = Globals->SEVER_LAND_BRIDGES; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if ((!newregion) || (TerrainDefs[newregion->type].similar_type == R_OCEAN)) continue; @@ -969,7 +969,7 @@ void ARegionList::RescaleFractalParameters(ARegionArray *pArr) reg->culture = 100 * (old - cult_min) / (cult_max - cult_min); if (getrandom(cult_max - cult_min) < (100 * (old - cult_min) % (cult_max - cult_min))) reg->culture++; - + } } } @@ -989,7 +989,7 @@ void ARegionList::SetFractalTerrain(ARegionArray *pArr) for (int l=0; l < 2; l++) { int set = 0; //Awrite(AString("Fractal Terrain: run #") + (l+1) + "."); - + int skip = 250; int f = 2; if (Globals->TERRAIN_GRANULARITY) { @@ -1113,12 +1113,12 @@ void ARegionList::NameRegions(ARegionArray *pArr) r1->wages = AGetName(0, r1); r1->population = (getrandom(2) + sz / 2) * (getrandom(2) + sz); - + if (r1->xloc > xmin) tnamedx[TerrainDefs[r1->type].similar_type] = r1->xloc; if (r1->yloc > ymin) tnamedy[TerrainDefs[r1->type].similar_type] = r1->yloc; - unnamed = 1; + unnamed = 1; } } } @@ -1128,14 +1128,14 @@ void ARegionList::NameRegions(ARegionArray *pArr) for (int x = 0; x < pArr->x; x++) { for (int y = 0; y < pArr->y; y++) { ARegion *reg = pArr->GetRegion(x,y); - if ((!reg) || (reg->type == R_OCEAN) + if ((!reg) || (reg->type == R_OCEAN) || (reg->wages >= 0) || (reg->type == R_NUM)) continue; int name1 = -99, name2 = -99; int nw1 = 0, nw2 = 0, nc1 = 0, nc2 = 0, nn = 0; int db = getrandom(NDIRS); for (int d=0; d < NDIRS; d++) { int dir = (d + db + NDIRS) % NDIRS; - ARegion *n = reg->neighbors[dir]; + ARegion *n = reg->neighbors(dir); if ((!n) || (n->type == R_NUM)) continue; if (TerrainDefs[n->type].similar_type != TerrainDefs[reg->type].similar_type) { nn++; @@ -1236,7 +1236,7 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) if (!reg) continue; if ((j > 0) && (j < 21) && (getrandom(3) < 2)) continue; if (reg->type == R_NUM) { - + // Check for Lakes if (Globals->LAKES && (getrandom(100) < (Globals->LAKES/10 + 1))) { @@ -1250,11 +1250,11 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) // reg->wages = AGetName(0, reg); break; } - + int init = getrandom(6); for (int i=0; ineighbors[(i+init) % NDIRS]; + ARegion *t = reg->neighbors((i+init) % NDIRS); if (t) { if (t->population < 1) continue; if (t->type != R_NUM && @@ -1295,7 +1295,7 @@ void ARegionList::RandomTerrain(ARegionArray *pArr) int adjtype = 0; int adjname = -1; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; if ((TerrainDefs[newregion->type].similar_type != R_OCEAN) && (newregion->type != R_NUM) && @@ -1328,21 +1328,21 @@ void ARegionList::MakeUWMaze(ARegionArray *pArr) for (int i=D_NORTH; i<= NDIRS; i++) { int count = 0; for (int j=D_NORTH; j< NDIRS; j++) - if (reg->neighbors[j]) count++; + if (reg->neighbors(j)) count++; if (count <= 1) break; - ARegion *n = reg->neighbors[i]; + ARegion *n = reg->neighbors(i); if (n) { if (n->xloc < x || (n->xloc == x && n->yloc < y)) continue; if (!CheckRegionExit(reg, n)) { count = 0; for (int k = D_NORTH; kneighbors[k]) count++; + if (n->neighbors(k)) count++; } if (count <= 1) break; - n->neighbors[reg->GetRealDirComp(i)] = 0; - reg->neighbors[i] = 0; + n->neighbors(reg->GetRealDirComp(i)) = 0; + reg->neighbors(i) = 0; } } } @@ -1391,7 +1391,7 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) // setup near coastal race here int d = getrandom(NDIRS); int ctr = 0; - ARegion *nreg = reg->neighbors[d]; + ARegion *nreg = reg->neighbors(d); if (!nreg) continue; while((ctr++ < 20) && (reg->race == -1)) { if (TerrainDefs[nreg->type].similar_type != R_OCEAN) { @@ -1401,8 +1401,8 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) } else { int dir = getrandom(NDIRS); if (d == nreg->GetRealDirComp(dir)) continue; - if (!(nreg->neighbors[dir])) continue; - nreg = nreg->neighbors[dir]; + if (!(nreg->neighbors(dir))) continue; + nreg = nreg->neighbors(dir); } } } else { @@ -1425,7 +1425,7 @@ void ARegionList::GrowRaces(ARegionArray *pArr) if ((!reg) || (reg->race == -1)) continue; for (int dir = 0; dir < NDIRS; dir++) { - ARegion *nreg = reg->neighbors[dir]; + ARegion *nreg = reg->neighbors(dir); if ((!nreg) || (nreg->race != -1)) continue; int iscoastal = 0; int cnum = sizeof(TerrainDefs[reg->type].coastal_races) / @@ -1553,10 +1553,10 @@ void ARegionList::SetACNeighbors(int levelSrc, int levelTo, int maxX, int maxY) ARegion *AC = ar->GetRegion(x, y); if (!AC) continue; for (int i=0; ineighbors[i]) continue; + if (AC->neighbors(i)) continue; ARegion *pReg = GetStartingCity(AC, i, levelTo, maxX, maxY); if (!pReg) continue; - AC->neighbors[i] = pReg; + AC->neighbors(i) = pReg; pReg->MakeStartingCity(); if (Globals->GATES_EXIST) { numberofgates++; @@ -1763,7 +1763,7 @@ void GeoMap::Generate(int spread, int smoothness) long int coords = (size+1) * xcoor + ycoor; geomap.erase(coords); geomap.insert(make_pair(coords, g)); - + } } Adot(); @@ -1833,7 +1833,7 @@ void GeoMap::Generate(int spread, int smoothness) nb++; } } - + Geography g; int r1 = getrandom(2*frac) - frac; int r2 = getrandom(2*frac) - frac; @@ -1857,11 +1857,11 @@ void GeoMap::Generate(int spread, int smoothness) g.temperature = 100 - getrandom(4); } if (g.humidity < 1) g.humidity = getrandom(5); - if (g.humidity > 100) g.humidity = 100 - getrandom(4); + if (g.humidity > 100) g.humidity = 100 - getrandom(4); long int coords = (size+1) * dx + dy; geomap.erase(coords); geomap.insert(make_pair(coords, g)); - + } } } @@ -1926,7 +1926,7 @@ int GeoMap::GetCulture(int x, int y) return 0; } -void GeoMap::ApplyGeography(ARegionArray *pArr) +void GeoMap::ApplyGeography(ARegionArray *pArr) { int x, y; int hmin = 100; @@ -1958,7 +1958,7 @@ void GeoMap::ApplyGeography(ARegionArray *pArr) reg->humidity = reg->humidity / ctr; reg->temperature = reg->temperature / ctr; reg->vegetation = reg->vegetation / ctr; - reg->culture = reg->culture / ctr; + reg->culture = reg->culture / ctr; if (reg->humidity > hmax) hmax = reg->humidity; if (reg->humidity < hmin) hmin = reg->humidity; } diff --git a/kingdoms/world.cpp b/kingdoms/world.cpp index e38f1843..6b2b4ceb 100644 --- a/kingdoms/world.cpp +++ b/kingdoms/world.cpp @@ -2481,7 +2481,7 @@ int ARegion::CanBeStartingCity( ARegionArray *pRA ) ARegionPtr * reg = (ARegionPtr *) inlist.First(); for (int i=0; iptr->neighbors[i]; + ARegion * r2 = reg->ptr->neighbors(i); if (!r2) continue; if (r2->type == R_OCEAN) continue; if (GetRegion(&inlist,r2->num)) continue; @@ -2503,9 +2503,9 @@ void ARegion::MakeStartingCity() if (!Globals->TOWNS_EXIST) return; if (Globals->GATES_EXIST) gate = -1; - + if (town) delete town; - + AddTown(TOWN_CITY); if (!Globals->START_CITIES_EXIST) return; @@ -2596,8 +2596,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; @@ -2622,8 +2622,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, continue; } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; diff --git a/monthorders.cpp b/monthorders.cpp index dffe76a7..6bdfbcf1 100644 --- a/monthorders.cpp +++ b/monthorders.cpp @@ -166,7 +166,7 @@ void Game::RunMovementOrders() u->savedmovement = 0; u->savedmovedir = -1; } - if (u->monthorders && + if (u->monthorders && (u->monthorders->type == O_MOVE || u->monthorders->type == O_ADVANCE)) { mo = (MoveOrder *) u->monthorders; @@ -190,7 +190,7 @@ void Game::RunMovementOrders() } u = o->GetOwner(); if (o->IsFleet() && u && !u->nomove && - u->monthorders && + u->monthorders && u->monthorders->type == O_SAIL) { so = (SailOrder *) u->monthorders; if (so->dirs.Num() > 0) { @@ -260,7 +260,7 @@ Location *Game::Do1SailOrder(ARegion *reg, Object *fleet, Unit *cap) if (x->dir == MOVE_PAUSE) { newreg = reg; } else { - newreg = reg->neighbors[x->dir]; + newreg = reg->neighbors(x->dir); } cost = 1; @@ -369,7 +369,7 @@ Location *Game::Do1SailOrder(ARegion *reg, Object *fleet, Unit *cap) forlist(&fleet->units) { // Everyone onboard gets to see the sights unit = (Unit *) elem; - + Farsight *f; // Note the hex being left forlist(®->passers) { @@ -566,7 +566,7 @@ void Game::Run1BuildOrder(ARegion *r, Object *obj, Unit *u) u->monthorders = 0; return; } - + int needed = buildobj->incomplete; int type = buildobj->type; // AS @@ -635,7 +635,7 @@ void Game::Run1BuildOrder(ARegion *r, Object *obj, Unit *u) } /* Perform the build */ - + if (obj != buildobj) u->MoveUnit(buildobj); @@ -650,7 +650,7 @@ void Game::Run1BuildOrder(ARegion *r, Object *obj, Unit *u) } else { u->ConsumeShared(it, num); } - + /* Regional economic improvement */ r->improvement += num; @@ -685,7 +685,7 @@ void Game::RunBuildShipOrder(ARegion * r,Object * obj,Unit * u) // get needed to complete maxbuild = 0; - if ((u->monthorders) && + if ((u->monthorders) && (u->monthorders->type == O_BUILD)) { BuildOrder *border = (BuildOrder *) u->monthorders; maxbuild = border->needtocomplete; @@ -696,16 +696,16 @@ void Game::RunBuildShipOrder(ARegion * r,Object * obj,Unit * u) unfinished = 0; } else { output = ShipConstruction(r, u, u, level, maxbuild, ship); - + if (output < 1) return; - + // are there unfinished ship items of the given type? unfinished = u->items.GetNum(ship); - + if (unfinished == 0) { // Start a new ship's construction from scratch unfinished = ItemDefs[ship].pMonths; - u->items.SetNum(ship, unfinished); + u->items.SetNum(ship, unfinished); } // Now reduce unfinished by produced amount @@ -824,7 +824,7 @@ void Game::RunBuildHelpers(ARegion *r) int skill = LookupSkill(&skname); int level = u->GetSkill(skill); int needed = 0; - if ((target->monthorders) && + if ((target->monthorders) && (target->monthorders->type == O_BUILD)) { BuildOrder *border = (BuildOrder *) target->monthorders; needed = border->needtocomplete; @@ -837,21 +837,21 @@ void Game::RunBuildHelpers(ARegion *r) } int output = ShipConstruction(r, u, target, level, needed, ship); if (output < 1) continue; - + int unfinished = target->items.GetNum(ship); if (unfinished == 0) { // Start construction on a new ship unfinished = ItemDefs[ship].pMonths; - target->items.SetNum(ship, unfinished); + target->items.SetNum(ship, unfinished); } unfinished -= output; - + // practice u->Practice(skill); - + if (unfinished > 0) { target->items.SetNum(ship, unfinished); - if ((target->monthorders) && + if ((target->monthorders) && (target->monthorders->type == O_BUILD)) { BuildOrder *border = (BuildOrder *) target->monthorders; border->needtocomplete = unfinished; @@ -860,16 +860,16 @@ void Game::RunBuildHelpers(ARegion *r) // CreateShip(r, target, ship); // don't create the ship yet; leave that for the unit we're helping target->items.SetNum(ship, 1); - if ((target->monthorders) && + if ((target->monthorders) && (target->monthorders->type == O_BUILD)) { BuildOrder *border = (BuildOrder *) target->monthorders; border->needtocomplete = 0; } - } + } int percent = 100 * output / ItemDefs[ship].pMonths; - u->event("Helps " + string(target->name->const_str()) + " with construction of a " + + u->event("Helps " + string(target->name->const_str()) + " with construction of a " + ItemDefs[ship].name + " (" + to_string(percent) + "%) in " + - r->ShortPrint().const_str() + ".", "build", r); + r->ShortPrint().const_str() + ".", "build", r); } // no need to move unit if item-type ships // are being built. (leave this commented out) @@ -880,7 +880,7 @@ void Game::RunBuildHelpers(ARegion *r) Object *buildobj; if (u->build > 0) { buildobj = r->GetObject(u->build); - if (buildobj && + if (buildobj && buildobj != r->GetDummy() && buildobj != u->object) { @@ -894,7 +894,7 @@ void Game::RunBuildHelpers(ARegion *r) } } -/* Creates a new ship - either by adding it to a +/* Creates a new ship - either by adding it to a * compatible fleet object or creating a new fleet * object with Unit u as owner consisting of exactly * ONE ship of the given type. @@ -958,10 +958,10 @@ int Game::ShipConstruction(ARegion *r, Unit *u, Unit *target, int level, int nee // don't adjust for pMonths // - pMonths represents total requirement maxproduced = number; - + // adjust maxproduced for items needed until completion if (needed < maxproduced) maxproduced = needed; - + // adjust maxproduced for unfinished ships if ((unfinished > 0) && (maxproduced > unfinished)) maxproduced = unfinished; @@ -978,7 +978,7 @@ int Game::ShipConstruction(ARegion *r, Unit *u, Unit *target, int level, int nee if (maxproduced > count) maxproduced = count; count = maxproduced; - + // no required materials? if (count < 1) { u->error("BUILD: Don't have the required materials."); @@ -986,7 +986,7 @@ int Game::ShipConstruction(ARegion *r, Unit *u, Unit *target, int level, int nee u->monthorders = 0; return 0; } - + /* regional economic improvement */ r->improvement += count; @@ -1018,7 +1018,7 @@ int Game::ShipConstruction(ARegion *r, Unit *u, Unit *target, int level, int nee } } } - + // no required materials? if (maxproduced < 1) { u->error("BUILD: Don't have the required materials."); @@ -1026,10 +1026,10 @@ int Game::ShipConstruction(ARegion *r, Unit *u, Unit *target, int level, int nee u->monthorders = 0; return 0; } - + /* regional economic improvement */ r->improvement += maxproduced; - + // Deduct the items spent for (c = 0; c < sizeof(ItemDefs->pInput)/sizeof(ItemDefs->pInput[0]); c++) { int i = ItemDefs[ship].pInput[c].item; @@ -1045,7 +1045,7 @@ int Game::ShipConstruction(ARegion *r, Unit *u, Unit *target, int level, int nee delete u->monthorders; u->monthorders = 0; - + return output; } @@ -1138,7 +1138,7 @@ void Game::RunUnitProduce(ARegion *r, Unit *u) if (maxproduced > count) maxproduced = count; count = maxproduced; - + /* regional economic improvement */ r->improvement += count; @@ -1170,10 +1170,10 @@ void Game::RunUnitProduce(ARegion *r, Unit *u) } } } - + /* regional economic improvement */ r->improvement += maxproduced; - + // Deduct the items spent for (c = 0; c < sizeof(ItemDefs->pInput)/sizeof(ItemDefs->pInput[0]); c++) { int i = ItemDefs[o->item].pInput[c].item; @@ -1191,7 +1191,7 @@ void Game::RunUnitProduce(ARegion *r, Unit *u) if (ItemDefs[o->item].flags & ItemType::SKILLOUT_HALF) { output *= (level + 1) / 2; } - + u->items.SetNum(o->item,u->items.GetNum(o->item) + output); u->event("Produces " + ItemString(o->item,output) + " in " + r->ShortPrint().const_str() + ".", "produce", r); @@ -1440,7 +1440,7 @@ void Game::Do1StudyOrder(Unit *u,Object *obj) u->error("STUDY: " + SkillDefs[sk].name + " cannot be studied."); return; } - + // Small patch for Ceran Mercs if (u->GetMen(I_MERC)) { u->error("STUDY: Mercenaries are not allowed to study."); @@ -1539,7 +1539,7 @@ void Game::Do1StudyOrder(Unit *u,Object *obj) // If TACTICS_NEEDS_WAR is enabled, and the unit is trying to study to tact-5, // check that there's still space... - if (Globals->TACTICS_NEEDS_WAR && sk == S_TACTICS && + if (Globals->TACTICS_NEEDS_WAR && sk == S_TACTICS && u->GetSkill(sk) == 4 && u->skills.GetDays(sk)/u->GetMen() >= 300) { if (CountTacticians(u->faction) >= AllowedTacticians(u->faction)) { @@ -1550,9 +1550,9 @@ void Game::Do1StudyOrder(Unit *u,Object *obj) u->error("STUDY: Only 1-man units can study to level 5 in tactics."); return; } - + } // end tactics check - + // adjust teaching for study rate taughtdays = ((long int) o->days * u->skills.GetStudyRate(sk, u->GetMen()) / 30); @@ -1603,7 +1603,7 @@ void Game::Do1StudyOrder(Unit *u,Object *obj) } else { string msg = "Completes study to level " + to_string(o->level) + " in " + SkillDefs[sk].name + "."; u->event(msg, "study"); - } + } } } else { // if we just tried to become a mage or apprentice, but @@ -1785,7 +1785,7 @@ Location *Game::DoAMoveOrder(Unit *unit, ARegion *region, Object *obj) } else if (x->dir == MOVE_PAUSE) { newreg = region; } else { - newreg = region->neighbors[x->dir]; + newreg = region->neighbors(x->dir); } if (!newreg) { diff --git a/neworigins/extra.cpp b/neworigins/extra.cpp index 9b39a9cf..e4087687 100644 --- a/neworigins/extra.cpp +++ b/neworigins/extra.cpp @@ -194,7 +194,7 @@ static void CreateQuest(ARegionList *regions, int monfaction) reward_count = (QUEST_MAX_REWARD + getrandom(QUEST_MAX_REWARD / 2)) / ItemDefs[i].baseprice; printf("\nQuest reward: %s x %d.\n", ItemDefs[i].name.c_str(), reward_count); - + // Setup reward item = new Item; item->type = i; @@ -317,7 +317,7 @@ static void CreateQuest(ARegionList *regions, int monfaction) forlist(regions) { r = (ARegion *) elem; // No need to check if quests do not require exploration - if (r->Population() > 0 && (r->visited || QUEST_EXPLORATION_PERCENT == 0)) { + if (r->Population() > 0 && (r->visited || QUEST_EXPLORATION_PERCENT == 0)) { stlstr = r->name->Str(); // This looks like a null operation, but // actually forces the map<> element creation @@ -1199,11 +1199,11 @@ void Game::ModifyTablesPerRuleset(void) EnableItem(I_ILLYRTHID); EnableItem(O_ILAIR); EnableItem(I_DEVIL); - + EnableItem(I_STORMGIANT); EnableItem(I_CLOUDGIANT); EnableItem(O_GIANTCASTLE); - + EnableItem(I_WARRIORS); EnableItem(I_DARKMAGE); @@ -1241,7 +1241,7 @@ void Game::ModifyTablesPerRuleset(void) ModifyRaceSkills("HUMN", 3, "MINI"); ModifyRaceSkills("HUMN", 4, "FARM"); ModifyRaceSkills("HUMN", 5, "COOK"); - + EnableItem(I_HILLDWARF); ModifyItemBasePrice(I_HILLDWARF, 40); ModifyRaceSkillLevels("HDWA", 5, 2); @@ -1259,7 +1259,7 @@ void Game::ModifyTablesPerRuleset(void) ModifyRaceSkills("IDWA", 2, "MINI"); ModifyRaceSkills("IDWA", 3, "FISH"); ModifyRaceSkills("IDWA", 4, "ARMO"); - + EnableItem(I_HIGHELF); ModifyItemBasePrice(I_HIGHELF, 40); ModifyRaceSkillLevels("HELF", 5, 2); @@ -1412,7 +1412,7 @@ void Game::ModifyTablesPerRuleset(void) ModifyTerrainCoastRace(R_JUNGLE, 1, I_WOODELF); ModifyTerrainCoastRace(R_JUNGLE, 2, I_LIZARDMAN); ModifyTerrainEconomy(R_JUNGLE, 500, 11, 20, 2); - + ClearTerrainRaces(R_DESERT); ModifyTerrainRace(R_DESERT, 0, I_GNOLL); ModifyTerrainRace(R_DESERT, 1, I_GOBLINMAN); @@ -1510,7 +1510,7 @@ const char *ARegion::movement_forbidden_by_ruleset(Unit *u, ARegion *origin, ARe int count = 0; for (int i = 0; i < 6; i++) { - ARegion *r = surface_center->neighbors[i]; + ARegion *r = surface_center->neighbors(i); // search that region for an altar forlist(&r->objects) { Object *o = (Object *)elem; diff --git a/neworigins/world.cpp b/neworigins/world.cpp index 3ffff58d..7fbb3a1b 100644 --- a/neworigins/world.cpp +++ b/neworigins/world.cpp @@ -249,8 +249,8 @@ int AGetName(int town, ARegion *reg) port = 0; if (town) { for (i = 0; i < NDIRS; i++) - if (reg->neighbors[i] && - TerrainDefs[reg->neighbors[i]->type].similar_type == R_OCEAN) + if (reg->neighbors(i) && + TerrainDefs[reg->neighbors(i)->type].similar_type == R_OCEAN) port = 1; } @@ -522,10 +522,10 @@ void Game::CreateWorld() regions.FinalSetupGates(); // do final modifications to add in the victory objects (the ritual altars and the deactivated monolith) - + regions.CalcDensities(); - + regions.TownStatistics(); regions.ResourcesStatistics(); @@ -791,7 +791,7 @@ int ARegion::CanBeStartingCity( ARegionArray *pRA ) while(inlist.Num()) { ARegionPtr * reg = (ARegionPtr *) inlist.First(); for (int i=0; iptr->neighbors[i]; + ARegion * r2 = reg->ptr->neighbors(i); if (!r2) continue; if (r2->type == R_OCEAN) continue; if (GetRegion(&inlist,r2->num)) continue; @@ -813,9 +813,9 @@ void ARegion::MakeStartingCity() if (!Globals->TOWNS_EXIST) return; if (Globals->GATES_EXIST) gate = -1; - + if (town) delete town; - + AddTown(TOWN_CITY); if (!Globals->START_CITIES_EXIST) return; @@ -906,8 +906,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; @@ -933,8 +933,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; diff --git a/object.cpp b/object.cpp index 85076c10..190fd8a5 100644 --- a/object.cpp +++ b/object.cpp @@ -491,11 +491,11 @@ void Object::SetNumShips(int type, int num) /* Adds one ship of the given type. */ void Object::AddShip(int type) -{ +{ if (CheckShip(type) == 0) return; int num = GetNumShips(type); num++; - SetNumShips(type, num); + SetNumShips(type, num); } /* Returns the String 'Fleet' for multi-ship fleets @@ -589,10 +589,10 @@ int Object::SailThroughCheck(int dir) { if (IsFleet()) { // if target region doesn't exist, cannot be sailed into - if (!region->neighbors[dir]) { + if (!region->neighbors(dir)) { return 0; } - + // flying fleets always can sail through if (flying == 1) { return 1; @@ -605,7 +605,7 @@ int Object::SailThroughCheck(int dir) // fleet is not flying and it is in a land region. Check that it // doesn's sail inland - if (TerrainDefs[region->neighbors[dir]->type].similar_type != R_OCEAN) { + if (TerrainDefs[region->neighbors(dir)->type].similar_type != R_OCEAN) { return 0; } @@ -640,7 +640,7 @@ int Object::SailThroughCheck(int dir) } for (int k = d1+1; k < d2; k++) { - ARegion *land1 = region->neighbors[k]; + ARegion *land1 = region->neighbors(k); if ((!land1) || (TerrainDefs[land1->type].similar_type != R_OCEAN)) @@ -651,7 +651,7 @@ int Object::SailThroughCheck(int dir) for (int l = d2+1; l <= d2 + sides; l++) { int dl = l; if (dl >= NDIRS) dl -= NDIRS; - ARegion *land2 = region->neighbors[dl]; + ARegion *land2 = region->neighbors(dl); if ((!land2) || (TerrainDefs[land2->type].similar_type != R_OCEAN)) @@ -743,7 +743,7 @@ int Object::GetFleetSpeed(int report) // check for sufficient sailing skill! if (tskill < (weight / 50)) return 0; - + // count wind mages forlist(&units) { Unit * unit = (Unit *) elem; @@ -770,7 +770,7 @@ int Object::GetFleetSpeed(int report) // check for being overloaded if (FleetLoad() > capacity) return 0; - + // speed bonus due to low load: int loadfactor = (capacity / FleetLoad()); bonus = 0; @@ -833,7 +833,7 @@ AString *ObjectDescription(int obj) *temp += AString(" This structure provides defense to the first ") + o->protect + " men inside it."; // Now do the defences. First, figure out how many to do. - int totaldef = 0; + int totaldef = 0; for (int i=0; idefenceArray[i] != 0); } @@ -844,7 +844,7 @@ AString *ObjectDescription(int obj) totaldef--; *temp += AString(o->defenceArray[i]) + " against " + AttType(i) + AString(" attacks"); - + if (totaldef >= 2) { *temp += AString(", "); } else { @@ -853,7 +853,7 @@ AString *ObjectDescription(int obj) } else { // last bonus *temp += AString("."); } - } // end if + } // end if } } // end for diff --git a/orders.h b/orders.h index 4e9decb4..0ff50fc1 100644 --- a/orders.h +++ b/orders.h @@ -129,7 +129,7 @@ enum { NORDERS }; -enum { +enum MovementType { M_NONE, M_WALK, M_RIDE, diff --git a/runorders.cpp b/runorders.cpp index af8bf708..dd5f3196 100644 --- a/runorders.cpp +++ b/runorders.cpp @@ -368,7 +368,7 @@ void Game::Do1Steal(ARegion *r, Object *o, Unit *u) } // Make sure we dispose of the allocated AList properly until we get rid of alists entirely. - std::unique_ptr seers(CanSeeSteal(r, u)); + std::unique_ptr seers(CanSeeSteal(r, u)); int succ = 1; forlist(seers) { Faction *f = ((FactionPtr *) elem)->ptr; @@ -610,7 +610,7 @@ void Game::Do1Destroy(ARegion *r, Object *o, Unit *u) { } else { u->event("Destroys " + string(o->name->const_str()) + ".", "destroy"); - + Object *dest = r->GetDummy(); forlist(&o->units) { Unit *u = (Unit *) elem; @@ -702,7 +702,7 @@ int Game::FortTaxBonus(Object *o, Unit *u) } } protect -= men; - if (protect < 0) protect = 0; + if (protect < 0) protect = 0; } return(fortbonus); } @@ -1151,7 +1151,7 @@ void Game::RemoveEmptyObjects() ARegion *r = (ARegion *) elem; forlist(&r->objects) { Object *o = (Object *) elem; - if ((o->IsFleet()) && + if ((o->IsFleet()) && (TerrainDefs[r->type].similar_type != R_OCEAN)) continue; if (ObjectDefs[o->type].cost && o->incomplete >= ObjectDefs[o->type].cost) { @@ -1600,7 +1600,7 @@ void Game::RunBuyOrders() ARegion *r = (ARegion *) elem; for (const auto& m : r->markets) { if (m->type == M_BUY) DoBuy(r, m); - } + } forlist((&r->objects)) { Object *obj = (Object *) elem; forlist((&obj->units)) { @@ -1725,8 +1725,8 @@ void Game::DoBuy(ARegion *r, Market *m) if (skill == -1) continue; int curxp = u->skills.GetExp(skill); u->skills.SetExp(skill,exp+curxp); - } - } + } + } } /* region economy effects */ r->Recruit(temp); @@ -2490,7 +2490,7 @@ int Game::DoGiveOrder(ARegion *r, Unit *u, GiveOrder *o) if (ship > 0) u->items.SetNum(ship,0); return 0; // abandon fleet ships - } else if (!(u->object->IsFleet()) || + } else if (!(u->object->IsFleet()) || (u->num != u->object->GetOwner()->num)) { u->error(ord + ": only fleet owner can give ships."); return 0; @@ -2529,7 +2529,7 @@ int Game::DoGiveOrder(ARegion *r, Unit *u, GiveOrder *o) u->event("Abandons " + ItemString(o->item, num - o->amount) + ".", event_type); return 0; } - // GIVE to unit: + // GIVE to unit: t = r->GetUnitId(o->target, u->faction->num); if (!t) { u->error(ord + ": Nonexistant target (" + o->target->Print() + ")."); @@ -2704,7 +2704,7 @@ int Game::DoGiveOrder(ARegion *r, Unit *u, GiveOrder *o) } return 0; } - + if (o->target->unitnum == -1) { /* Give 0 */ // Check there is enough to give @@ -3120,7 +3120,7 @@ void Game::CheckTransportOrders() } else { // sender isn't a valid QM if (!target_is_valid_qm) { // Non-qms or invalid qms can only send to valid QMs // Give a specific error message depending on why they aren't considered a quartermaster - string temp = "TRANSPORT: Target " + string(tar->unit->name->const_str()); + string temp = "TRANSPORT: Target " + string(tar->unit->name->const_str()); temp += ( target_owns_qm_building ? " does not own a transport structure." : @@ -3544,7 +3544,7 @@ void Game::RunAnnihilateOrders() { // annihilate our neigbors for (auto n = 0; n < NDIRS; n++) { - ARegion *neigh = r->neighbors[n]; + ARegion *neigh = r->neighbors(n); if (neigh == nullptr) continue; Do1Annihilate(neigh); } diff --git a/spells.cpp b/spells.cpp index ea4d6182..55be044a 100644 --- a/spells.cpp +++ b/spells.cpp @@ -1308,7 +1308,7 @@ int Game::RunBirdLore(ARegion *r,Unit *u) if (order->level < 3) { int dir = order->target; - ARegion *tar = r->neighbors[dir]; + ARegion *tar = r->neighbors(dir); if (!tar) { u->error("CAST: No such region."); return 0; @@ -1638,7 +1638,7 @@ int Game::RunDetectGates(ARegion *r,Object *o,Unit *u) string(r->ShortPrint().const_str()) + ".", "spell"); } for (int i=0; ineighbors[i]; + ARegion *tar = r->neighbors(i); if (tar) { if (tar->gate) { if (Globals->DETECT_GATE_NUMBERS) { @@ -1978,7 +1978,7 @@ int Game::RunTransmutation(ARegion *r, Unit *u) u->error("CAST: Can't create that by transmutation."); return 0; } - + switch(order->item) { case I_ADMANTIUM: case I_MITHRIL: @@ -1998,7 +1998,7 @@ int Game::RunTransmutation(ARegion *r, Unit *u) source = I_HORSE; break; } - + num = u->GetSharedNum(source); if (num > ItemDefs[order->item].mOut * level) num = ItemDefs[order->item].mOut * level; @@ -2034,13 +2034,13 @@ int Game::RunBlasphemousRitual(ARegion *r, Unit *mage) tower = 0; sactype = IT_LEADER; sacrifices = 0; - + forlist(&r->objects) { o = (Object *) elem; if (o->type == O_BKEEP && !o->incomplete) { tower = o; } - + forlist(&o->units) { u = (Unit *) elem; if (u->faction->num == mage->faction->num) { @@ -2099,7 +2099,7 @@ int Game::RunBlasphemousRitual(ARegion *r, Unit *mage) r->Kill(victim); if (!mage->GetMen()) break; - + relics = mage->items.GetNum(I_RELICOFGRACE); mage->items.SetNum(I_RELICOFGRACE, relics + 1); } diff --git a/standard/map.cpp b/standard/map.cpp index 57f59fc1..35c2a8f1 100644 --- a/standard/map.cpp +++ b/standard/map.cpp @@ -34,7 +34,7 @@ int ARegion::CheckSea(int dir, int range, int remainocean) if (range-- < 1) return 1; for (int d2 = -1; d2< 2; d2++) { int direc = (dir + d2 + NDIRS) % NDIRS; - ARegion *newregion = neighbors[direc]; + ARegion *newregion = neighbors(direc); if (!newregion) continue; remainocean += newregion->CheckSea(dir, range, remainocean); if (remainocean) break; @@ -142,21 +142,21 @@ void ARegionList::CreateSurfaceLevel(int level, int xSize, int ySize, char const int sea = Globals->OCEAN; if (Globals->SEA_LIMIT) sea = sea * (100 + 2 * Globals->SEA_LIMIT) / 100; - + MakeLand(pRegionArrays[level], sea, Globals->CONTINENT_SIZE); - + CleanUpWater(pRegionArrays[level]); SetupAnchors(pRegionArrays[level]); - + GrowTerrain(pRegionArrays[level], 0); - + AssignTypes(pRegionArrays[level]); SeverLandBridges(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); FinalSetup(pRegionArrays[level]); @@ -268,8 +268,8 @@ void ARegionList::MakeRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; - reg->wages = -1; + reg->race = -1; + reg->wages = -1; reg->level = arr; Add(reg); @@ -363,7 +363,7 @@ void ARegionList::MakeIcosahedralRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; // + reg->race = -1; // reg->wages = -1; // initially store: name reg->population = -1; // initially used as flag reg->elevation = -1; @@ -418,7 +418,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if (!reg) continue; ARegion *newreg = reg; ARegion *seareg = reg; - + // Archipelago or Continent? if (getrandom(100) < Globals->ARCHIPELAGO) { // Make an Archipelago: @@ -427,21 +427,21 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int tries = 0; for (int i=0; ineighbors[direc]; + newreg = reg->neighbors(direc); while (!newreg) { direc = getrandom(6); - newreg = reg->neighbors[direc]; + newreg = reg->neighbors(direc); } tries++; for (int m = 0; m < 2; m++) { seareg = newreg; - newreg = seareg->neighbors[direc]; + newreg = seareg->neighbors(direc); if (!newreg) break; } if (!newreg) break; if (newreg) { seareg = newreg; - newreg = seareg->neighbors[getrandom(NDIRS)]; + newreg = seareg->neighbors(getrandom(NDIRS)); if (!newreg) break; // island start point (~3 regions away from last island) seareg = newreg; @@ -468,11 +468,11 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int newdir = getrandom(NDIRS); while (direc == reg->GetRealDirComp(newdir)) newdir = getrandom(NDIRS); - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); while ((!newreg) && (tries < 36)) { while (direc == reg->GetRealDirComp(newdir)) newdir = getrandom(NDIRS); - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); tries++; } if (!newreg) continue; @@ -498,12 +498,12 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if ((reg->yloc < yoff*2) && ((dir < 2) || (dir == (NDIRS-1))) && (getrandom(4) < 3)) continue; if ((reg->yloc > (yband+yoff)*2) && ((dir < 5) && (dir > 1)) - && (getrandom(4) < 3)) continue; - ARegion *newreg = reg->neighbors[dir]; + && (getrandom(4) < 3)) continue; + ARegion *newreg = reg->neighbors(dir); if (!newreg) break; int polecheck = 0; for (int v=0; v < NDIRS; v++) { - ARegion *creg = newreg->neighbors[v]; + ARegion *creg = newreg->neighbors(v); if (!creg) polecheck = 1; } if (polecheck) break; @@ -622,7 +622,7 @@ void ARegionList::RemoveCoastalLakes(ARegionArray *pRegs) int count2 = 0; int temp = 0; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; // name after neighboring lake regions preferrentially if ((newregion->wages > 0) && @@ -669,7 +669,7 @@ void ARegionList::SeverLandBridges(ARegionArray *pRegs) if (reg->IsCoastal() != 4) continue; int tidych = Globals->SEVER_LAND_BRIDGES; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if ((!newregion) || (TerrainDefs[newregion->type].similar_type == R_OCEAN)) continue; @@ -761,7 +761,7 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) if (!reg) continue; if ((j > 0) && (j < 21) && (getrandom(3) < 2)) continue; if (reg->type == R_NUM) { - + // Check for Lakes if (Globals->LAKES && (getrandom(100) < (Globals->LAKES/10 + 1))) { @@ -775,11 +775,11 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) reg->wages = AGetName(0, reg); break; } - + int init = getrandom(6); for (int i=0; ineighbors[(i+init) % NDIRS]; + ARegion *t = reg->neighbors((i+init) % NDIRS); if (t) { if (t->population < 1) continue; if (t->type != R_NUM && @@ -820,7 +820,7 @@ void ARegionList::RandomTerrain(ARegionArray *pArr) int adjtype = 0; int adjname = -1; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; if ((TerrainDefs[newregion->type].similar_type != R_OCEAN) && (newregion->type != R_NUM) && @@ -853,21 +853,21 @@ void ARegionList::MakeUWMaze(ARegionArray *pArr) for (int i=D_NORTH; i< NDIRS; i++) { int count = 0; for (int j=D_NORTH; j< NDIRS; j++) - if (reg->neighbors[j]) count++; + if (reg->neighbors(j)) count++; if (count <= 1) break; - ARegion *n = reg->neighbors[i]; + ARegion *n = reg->neighbors(i); if (n) { if (n->xloc < x || (n->xloc == x && n->yloc < y)) continue; if (!CheckRegionExit(reg, n)) { count = 0; for (int k = D_NORTH; kneighbors[k]) count++; + if (n->neighbors(k)) count++; } if (count <= 1) break; - n->neighbors[reg->GetRealDirComp(i)] = 0; - reg->neighbors[i] = 0; + n->neighbors(reg->GetRealDirComp(i)) = 0; + reg->neighbors(i) = 0; } } } @@ -907,25 +907,25 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) int xoff = x + 2 - getrandom(3) - getrandom(3); ARegion *reg = pArr->GetRegion(xoff, y); if (!reg) continue; - + if ((reg->type == R_LAKE) && (!Globals->LAKESIDE_IS_COASTAL)) continue; if (TerrainDefs[reg->type].flags & TerrainType::BARREN) continue; - + reg->race = -1; wigout = 0; // reset sanity - + if (TerrainDefs[reg->type].similar_type == R_OCEAN) { // setup near coastal race here int d = getrandom(NDIRS); int ctr = 0; - ARegion *nreg = reg->neighbors[d]; + ARegion *nreg = reg->neighbors(d); if (!nreg) continue; while((ctr++ < 20) && (reg->race == -1)) { if (TerrainDefs[nreg->type].similar_type != R_OCEAN) { int rnum = sizeof(TerrainDefs[nreg->type].coastal_races) / sizeof(TerrainDefs[nreg->type].coastal_races[0]); - + while ( reg->race == -1 || (ItemDefs[reg->race].flags & ItemType::DISABLED)) { reg->race = TerrainDefs[nreg->type].coastal_races[getrandom(rnum)]; if (++wigout > 100) break; @@ -933,20 +933,20 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) } else { int dir = getrandom(NDIRS); if (d == nreg->GetRealDirComp(dir)) continue; - if (!(nreg->neighbors[dir])) continue; - nreg = nreg->neighbors[dir]; + if (!(nreg->neighbors(dir))) continue; + nreg = nreg->neighbors(dir); } } } else { // setup noncoastal race here int rnum = sizeof(TerrainDefs[reg->type].races)/sizeof(TerrainDefs[reg->type].races[0]); - + while ( reg->race == -1 || (ItemDefs[reg->race].flags & ItemType::DISABLED)) { reg->race = TerrainDefs[reg->type].races[getrandom(rnum)]; if (++wigout > 100) break; } } - + /* leave out this sort of check for the moment if (wigout > 100) { // do something! @@ -955,10 +955,10 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) Awrite(" region type"); } */ - + if (reg->race == -1) { - cout << "Hey! No race anchor got assigned to the " - << TerrainDefs[reg->type].name + cout << "Hey! No race anchor got assigned to the " + << TerrainDefs[reg->type].name << " at " << x << "," << y << "\n"; } } @@ -977,7 +977,7 @@ void ARegionList::GrowRaces(ARegionArray *pArr) if ((!reg) || (reg->race == -1)) continue; for (int dir = 0; dir < NDIRS; dir++) { - ARegion *nreg = reg->neighbors[dir]; + ARegion *nreg = reg->neighbors(dir); if ((!nreg) || (nreg->race != -1)) continue; int iscoastal = 0; int cnum = sizeof(TerrainDefs[reg->type].coastal_races) / @@ -1106,10 +1106,10 @@ void ARegionList::SetACNeighbors(int levelSrc, int levelTo, int maxX, int maxY) if (!AC) continue; if (Globals->START_CITIES_EXIST) { for (int i=0; ineighbors[i]) continue; + if (AC->neighbors(i)) continue; ARegion *pReg = GetStartingCity(AC, i, levelTo, maxX, maxY); if (!pReg) continue; - AC->neighbors[i] = pReg; + AC->neighbors(i) = pReg; pReg->MakeStartingCity(); if (Globals->GATES_EXIST) { numberofgates++; diff --git a/standard/world.cpp b/standard/world.cpp index ef73133c..ae71f7f3 100644 --- a/standard/world.cpp +++ b/standard/world.cpp @@ -2142,7 +2142,7 @@ void Game::CreateWorld() SetupNames(); regions.CreateNexusLevel( 0, nx, ny, "nexus" ); - + regions.CreateSurfaceLevel(1, xx, yy, 0); // Create underworld levels @@ -2475,7 +2475,7 @@ int ARegion::CanBeStartingCity( ARegionArray *pRA ) while(inlist.Num()) { ARegionPtr * reg = (ARegionPtr *) inlist.First(); for (int i=0; iptr->neighbors[i]; + ARegion * r2 = reg->ptr->neighbors(i); if (!r2) continue; if (r2->type == R_OCEAN) continue; if (GetRegion(&inlist,r2->num)) continue; @@ -2497,9 +2497,9 @@ void ARegion::MakeStartingCity() if (!Globals->TOWNS_EXIST) return; if (Globals->GATES_EXIST) gate = -1; - + if (town) delete town; - + AddTown(TOWN_CITY); if (!Globals->START_CITIES_EXIST) return; @@ -2589,8 +2589,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; @@ -2616,8 +2616,8 @@ ARegion *ARegionList::GetStartingCity( ARegion *AC, } for (int j=0; jneighbors[j]) continue; - if (GetPlanarDistance(reg,AC->neighbors[j], 0, maxY / 10 + 2) < maxY / 10 + 2 ) { + if (!AC->neighbors(j)) continue; + if (GetPlanarDistance(reg,AC->neighbors(j), 0, maxY / 10 + 2) < maxY / 10 + 2 ) { reg = 0; tries++; break; diff --git a/unit.cpp b/unit.cpp index 5cf82f6a..246a9580 100644 --- a/unit.cpp +++ b/unit.cpp @@ -386,7 +386,7 @@ int Unit::CanGetSpoil(Item *i) return 0; load = items.Weight(); - + if (flags & FLAG_FLYSPOILS) { capacity = ItemDefs[i->type].fly; if (FlyingCapacity() + capacity < load + weight) @@ -670,7 +670,7 @@ void Unit::build_json_report(json& j, int obs, int truesight, int detfac, int au } } } - + if ((type == U_MAGE || type == U_GUARDMAGE) && combat != -1) { j["combat_spell"] = { { "name", SkillDefs[combat].name }, { "tag", SkillDefs[combat].abbr } }; } @@ -705,7 +705,7 @@ void Unit::build_json_report(json& j, int obs, int truesight, int detfac, int au // For the JSON report, the best location for order information is on the unit itself. j["orders"] = write_json_orders(); - + } j["items"] = json::array(); @@ -878,7 +878,7 @@ void Unit::DefaultOrders(Object *obj) directions.push_back(-1); for (i = 0; i < NDIRS; i++) { - n = r->neighbors[i]; + n = r->neighbors(i); if (!n) { continue; } @@ -911,7 +911,7 @@ void Unit::DefaultOrders(Object *obj) bool connectedToGoodTerrain = false; for (int j = 0; j < NDIRS; j++) { - auto region = n->neighbors[j]; + auto region = n->neighbors(j); if (!region) { continue; } @@ -1119,7 +1119,7 @@ int Unit::GetSharedNum(int item) Object *obj = (Object *) elem; forlist((&obj->units)) { Unit *u = (Unit *) elem; - if ((u->num == num) || + if ((u->num == num) || (u->faction == faction && u->GetFlag(FLAG_SHARING))) count += u->items.GetNum(item); } @@ -1348,7 +1348,7 @@ int Unit::GetAvailSkill(int sk) grant = ItemDefs[i->type].minGrant; if (grant > ItemDefs[i->type].maxGrant) grant = ItemDefs[i->type].maxGrant; - + if (grant > retval) retval = grant; } @@ -1423,7 +1423,7 @@ int Unit::CanStudy(int sk) !(SkillDefs[sk].flags & SkillType::MAGIC)) return 0; } - + int curlev = GetRealSkill(sk); if (SkillDefs[sk].flags & SkillType::DISABLED) return 0; @@ -1974,7 +1974,7 @@ static int ContributesToMovement(int movetype, int item) return ItemDefs[item].swim; break; } - + return 0; } @@ -2042,7 +2042,7 @@ int Unit::CanMoveTo(ARegion *r1, ARegion *r2) int dir; for (i=0; ineighbors[i] == r2) { + if (r1->neighbors(i) == r2) { exit = 0; dir = i; break; @@ -2051,7 +2051,7 @@ int Unit::CanMoveTo(ARegion *r1, ARegion *r2) if (exit) return 0; exit = 1; for (i=0; ineighbors[i] == r1) { + if (r2->neighbors(i) == r1) { exit = 0; break; } @@ -2142,7 +2142,7 @@ int Unit::Taxers(int numtaxers) int basetax = 0; int weapontax = 0; int armortax = 0; - + // check out items int numMelee= 0; int numUsableMelee = 0; @@ -2232,7 +2232,7 @@ int Unit::Taxers(int numtaxers) else creatures += pItem->num; } - + if (ItemDefs[pItem->type].type & IT_ARMOR) { numArmor += pItem->num; } @@ -2251,7 +2251,7 @@ int Unit::Taxers(int numtaxers) GetSkill(S_STEALTH))) { basetax = totalMen; taxers = totalMen; - + // Weapon tax bonus if ((Globals->WHO_CAN_TAX & GameDefs::TAX_ANYONE) || ((Globals->WHO_CAN_TAX & GameDefs::TAX_COMBAT_SKILL) && @@ -2265,7 +2265,7 @@ int Unit::Taxers(int numtaxers) } weapontax += numMelee; } - + if (((Globals->WHO_CAN_TAX & GameDefs::TAX_BOW_SKILL) && (GetSkill(S_CROSSBOW) || GetSkill(S_LONGBOW)))) { weapontax += numUsableBows; @@ -2274,7 +2274,7 @@ int Unit::Taxers(int numtaxers) GetSkill(S_RIDING)) { if (weapontax < numUsableMounts) weapontax = numUsableMounts; } - + } else { if (Globals->WHO_CAN_TAX & GameDefs::TAX_USABLE_WEAPON) { @@ -2335,7 +2335,7 @@ int Unit::Taxers(int numtaxers) weapontax += numUsableBattle; taxers += numUsableBattle; } - + } // Ok, all the items categories done - check for mages taxing @@ -2388,13 +2388,13 @@ int Unit::Taxers(int numtaxers) } } } - + armortax = numArmor; - + // Check for overabundance if (weapontax > totalMen) weapontax = totalMen; if (armortax > weapontax) armortax = weapontax; - + // Adjust basetax in case of weapon taxation if (basetax < weapontax) basetax = weapontax; @@ -2411,7 +2411,7 @@ int Unit::Taxers(int numtaxers) basetax += illusions; taxers += illusions; } - + if (numtaxers) return(taxers); int taxes = Globals->TAX_BASE_INCOME * basetax @@ -2614,7 +2614,7 @@ void Unit::DiscardUnfinishedShips() { items.SetNum(i,0); } } - if (discard > 0) event("discards all unfinished ships.", "discard"); + if (discard > 0) event("discards all unfinished ships.", "discard"); } void Unit::event(const string& message, const string& category, ARegion *r) @@ -2722,7 +2722,7 @@ int Unit::GetAttribute(char const *attrib) } else base = monbase; // monster units have no men - } + } return base; } From 0077a5d386763606d3bd3b5c4751529a6ccf9b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valdis=20Zob=C4=93la?= Date: Thu, 22 Aug 2024 00:39:04 +0300 Subject: [PATCH 2/3] saving and loading edges --- aregion.cpp | 160 +++++++++++++++++++++++++++++++------------- aregion.h | 71 ++++++++++++-------- edges.cpp | 82 +++++++++++++---------- game.cpp | 48 +++++++------- neworigins/map.cpp | 162 ++++++++++++++++++++++----------------------- 5 files changed, 308 insertions(+), 215 deletions(-) diff --git a/aregion.cpp b/aregion.cpp index c9f88543..cf37e852 100644 --- a/aregion.cpp +++ b/aregion.cpp @@ -142,6 +142,8 @@ ARegion::ARegion() earthlore = 0; phantasmal_entertainment = 0; visited = 0; + + edges = RegionEdges(this); } ARegion::~ARegion() @@ -1821,7 +1823,7 @@ int ARegion::ResolveFleetAlias(int alias) } ARegion* ARegion::neighbors(const int dir) { - return this->edges.get_neighbor(this, dir); + return this->edges.get_neighbor(dir); } ARegionList::ARegionList() @@ -1829,6 +1831,7 @@ ARegionList::ARegionList() pRegionArrays = 0; numLevels = 0; numberofgates = 0; + last_edge_id = 1000; } ARegionList::~ARegionList() @@ -1855,18 +1858,24 @@ void ARegionList::WriteRegions(ostream& f) } f << numberofgates << "\n"; - forlist(this) ((ARegion *) elem)->Writeout(f); - { - // because forlist is a macro we need this extra block for now. - f << "Neighbors\n"; - forlist(this) { - ARegion *reg = (ARegion *) elem; - for (int i = 0; i < NDIRS; i++) { - f << (reg->neighbors(i) ? reg->neighbors(i)->num : -1) << '\n'; - } - } - } + for (auto reg : this->iter()) { + reg->Writeout(f); + } + + f << "Edges\n"; + f << this->last_edge_id << '\n'; + f << this->edges.size() << '\n'; + + for (auto kv : this->edges) { + auto edge = kv.second; + + f << edge->get_id() << '\n'; + f << edge->get_left()->num << '\n'; + f << edge->get_right()->num << '\n'; + f << edge->get_left_dir() << '\n'; + f << edge->get_right_dir() << '\n'; + } } int ARegionList::ReadRegions(istream &f, AList *factions) @@ -1908,23 +1917,29 @@ int ARegionList::ReadRegions(istream &f, AList *factions) } Awrite("Setting up the neighbors..."); - { - AString temp; - f >> ws >> temp; // eat the "Neighbors" line - forlist(this) { - ARegion *reg = (ARegion *) elem; - for (i = 0; i < NDIRS; i++) { - int j; - f >> j; - if (j != -1) { - reg->neighbors(i) = fa.GetRegion(j); - } else { - reg->neighbors(i) = 0; - } - } - } - } - return 1; + + AString temp; + int numfOfEdges; + + f >> ws >> temp; // eat the "Edges" line + f >> this->last_edge_id; + f >> numfOfEdges; + + // Load all edges + for (int i = 0; i < numfOfEdges; i++) { + int edge_id, left_num, left_dir, right_num, right_dir; + f >> edge_id >> left_num >> right_num >> left_dir >> right_dir; + + RegionEdge* edge = RegionEdge::create(edge_id, fa.GetRegion(left_num), fa.GetRegion(right_num), left_dir, right_dir); + + this->edges.insert({ edge->get_id(), edge }); + + // Assign edge to the regions + edge->get_left()->edges.add(edge); + edge->get_right()->edges.add(edge); + } + + return 1; } ARegion *ARegionList::GetRegion(int n) @@ -1969,24 +1984,24 @@ Location *ARegionList::FindUnit(int i) return 0; } -void ARegionList::NeighSetup(ARegion *r, ARegionArray *ar) -{ - r->ZeroNeighbors(); +void ARegionList::NeighSetup(ARegion *r, ARegionArray *ar) { + if (r->yloc != 0 && r->yloc != 1) { + this->create_edge(r, ar->GetRegion(r->xloc, r->yloc - 2), D_NORTH, D_SOUTH); + } - if (r->yloc != 0 && r->yloc != 1) { - r->neighbors[D_NORTH] = ar->GetRegion(r->xloc, r->yloc - 2); - } - if (r->yloc != 0) { - r->neighbors[D_NORTHEAST] = ar->GetRegion(r->xloc + 1, r->yloc - 1); - r->neighbors[D_NORTHWEST] = ar->GetRegion(r->xloc - 1, r->yloc - 1); - } - if (r->yloc != ar->y - 1) { - r->neighbors[D_SOUTHEAST] = ar->GetRegion(r->xloc + 1, r->yloc + 1); - r->neighbors[D_SOUTHWEST] = ar->GetRegion(r->xloc - 1, r->yloc + 1); - } - if (r->yloc != ar->y - 1 && r->yloc != ar->y - 2) { - r->neighbors[D_SOUTH] = ar->GetRegion(r->xloc, r->yloc + 2); - } + if (r->yloc != 0) { + this->create_edge(r, ar->GetRegion(r->xloc + 1, r->yloc - 1), D_NORTHEAST, D_SOUTHWEST); + this->create_edge(r, ar->GetRegion(r->xloc - 1, r->yloc - 1), D_NORTHWEST, D_SOUTHEAST); + } + + if (r->yloc != ar->y - 1) { + this->create_edge(r, ar->GetRegion(r->xloc + 1, r->yloc + 1), D_SOUTHEAST, D_NORTHWEST); + this->create_edge(r, ar->GetRegion(r->xloc - 1, r->yloc + 1), D_SOUTHWEST, D_NORTHEAST); + } + + if (r->yloc != ar->y - 1 && r->yloc != ar->y - 2) { + this->create_edge(r, ar->GetRegion(r->xloc, r->yloc + 2), D_SOUTH, D_NORTH); + } } [[deprecated("Icosahedral world is no longer supported")]] @@ -2324,7 +2339,7 @@ ARegion *ARegionList::FindNearestStartingCity(ARegion *start, int *dir) if (dir) { offset = getrandom(NDIRS); for (i = 0; i < NDIRS; i++) { - r = start->neighbors[(i + offset) % NDIRS]; + r = start->neighbors((i + offset) % NDIRS); if (!r) continue; if (r->distance + 1 == start->distance) { @@ -4134,3 +4149,54 @@ int ARegionList::FindDistanceToNearestObject(int object_type, ARegion *start) } return min_dist; } + +int ARegionList::next_edge_id() { + return ++this->last_edge_id; +} + +void ARegionList::create_edge(ARegion *left, ARegion *right, const int left_dir, const int right_dir) { + if (has_edge(left, right)) { + return; + } + + RegionEdge *edge = RegionEdge::create(this->next_edge_id(), left, right, left_dir, right_dir); + + this->edges.insert({ edge->get_id(), edge }); + + left->edges.add(edge); + right->edges.add(edge); +} + +const bool ARegionList::has_edge(const ARegion *left, const ARegion *right) const { + for (const auto& kv : this->edges) { + auto edge = kv.second; + + if (edge->get_left() == left && edge->get_right() == right) { + return true; + } + + if (edge->get_left() == right && edge->get_right() == left) { + return true; + } + } + + return false; +} + +void ARegionList::remove_edge(const int id) { + auto kv = this->edges.find(id); + if (kv == this->edges.end()) { + return; + } + + auto edge = kv->second; + auto left = edge->get_left(); + auto right = edge->get_right(); + + left->edges.remove(edge->get_id()); + right->edges.remove(edge->get_id()); + + this->edges.erase(kv); + + delete edge; +} diff --git a/aregion.h b/aregion.h index 2261570c..4848db9b 100644 --- a/aregion.h +++ b/aregion.h @@ -195,27 +195,27 @@ class RegionEdge { * Also MOVE order can use this id to specify the destination of the movement. * */ - const int get_id(); + int get_id() const; /** * @brief The left region of the edge. */ - ARegion* get_left(); + ARegion* get_left() const; /** * @brief The right region of the edge. */ - ARegion* get_right(); + ARegion* get_right() const; /** * @brief Direction of the edge from the left region to the right region. */ - const int get_left_dir(); + int get_left_dir() const; /** * @brief Direction of the edge from the right region to the left region. */ - const int get_right_dir(); + int get_right_dir() const; /** * @brief Creates a new edge between two regions. @@ -229,7 +229,7 @@ class RegionEdge { * @param right_dir The direction of the edge from the right region to the left region. * @return const Edge* The new edge. */ - static const RegionEdge* create(const int id, ARegion *left, ARegion *right, const int left_dir, const int right_dir); + static RegionEdge* create(const int id, ARegion *left, ARegion *right, const int left_dir, const int right_dir); private: RegionEdge(const int id, ARegion* left, ARegion* right, const int left_dir, const int right_dir) @@ -243,36 +243,48 @@ class RegionEdge { }; /** - * @brief Represents connections to other regions and locations. + * @brief Represents connections to other regions and locations from a region. */ class RegionEdges { +friend class ARegion; +private: + RegionEdges(); + public: - using itemType = RegionEdge *; - using itemsMapType = std::unordered_map; + using itemType = const RegionEdge *; using regionType = ARegion *; using regionArrayType = std::array; - using cacheType = std::unordered_map; - using iterator = itemsMapType::iterator; - const int size() const { return items.size(); } + RegionEdges(regionType owner); /** - * @brief Adds a new edge to the list of edges. + * @brief Returns the number of connections to other regions and locations. * - * @param edge The edge to add. + * @return const int The number of connections. */ - void add(const itemType edge); + const int size() const; /** - * @brief Returns the neighbors of a region. + * @brief Returns the edge with the given id. * - * This function is for the compatibility with the old code. - * Missing directions will be set to nullptr. + * @param id The id of the edge to get. + * @return itemType The edge with the given id or nullptr if there is no such edge. + */ + itemType get(const int id) const; + + /** + * @brief Adds a new edge to the local list of edges. * - * @param region The region to get the neighbors of. - * @return const std::array The neighbors of the region. + * @param edge The edge to add. + */ + void add(itemType edge); + + /** + * @brief Removes an edge from the local list of edges of the region. + * + * @param id The id of the edge to remove. */ - const regionArrayType& neighbors(const regionType region); + void remove(const int id); /** * @brief Returns the neighboring region in the given direction. @@ -282,14 +294,12 @@ class RegionEdges { * @param dir The direction to get the neighbor of. * @return ARegion* The neighboring region in the given direction or nullptr if there is no neighbor. */ - regionType get_neighbor(const RegionEdges::regionType region, const int dir); - - iterator begin(); - iterator end(); + regionType get_neighbor(const int dir); private: - itemsMapType items; - cacheType neighborsCache; + regionType owner; + std::unordered_map items; + regionArrayType neighbors; }; class ARegion : public AListElem @@ -693,6 +703,13 @@ class ARegionList : public AList int GetRegType(ARegion *pReg); int CheckRegionExit(ARegion *pFrom, ARegion *pTo); + // Region Edges + std::unordered_map edges; + int last_edge_id; + int next_edge_id(); + void create_edge(ARegion *left, ARegion *right, const int left_dir, const int right_dir); + const bool has_edge(const ARegion *left, const ARegion *right) const; + void remove_edge(const int id); }; int LookupRegionType(AString *); diff --git a/edges.cpp b/edges.cpp index 128c14a8..8d47f92d 100644 --- a/edges.cpp +++ b/edges.cpp @@ -25,76 +25,86 @@ #include "aregion.h" -const RegionEdge* RegionEdge::create(const int id, ARegion* left, ARegion* right, const int left_dir, const int right_dir) { - RegionEdge *edge = new RegionEdge(id, left, right, left_dir, right_dir); - return edge; +//////////////////// +///// RegionEdge + +RegionEdge* RegionEdge::create(const int id, ARegion* left, ARegion* right, const int left_dir, const int right_dir) { + return new RegionEdge(id, left, right, left_dir, right_dir); } -const int RegionEdge::get_id() { +int RegionEdge::get_id() const { return this->id; } -ARegion* RegionEdge::get_left() { +ARegion* RegionEdge::get_left() const { return this->left; } -ARegion* RegionEdge::get_right() { +ARegion* RegionEdge::get_right() const { return this->right; } -const int RegionEdge::get_left_dir() { +int RegionEdge::get_left_dir() const { return this->left_dir; } -const int RegionEdge::get_right_dir() { +int RegionEdge::get_right_dir() const { return this->right_dir; } -void RegionEdges::add(const RegionEdges::itemType edge) { - this->items.insert({ edge->get_id(), edge }); - add_to_cache(this->neighborsCache, edge->get_left(), edge->get_right(), edge->get_left_dir()); - add_to_cache(this->neighborsCache, edge->get_right(), edge->get_left(), edge->get_right_dir()); +//////////////////// +///// RegionEdges + +RegionEdges::RegionEdges() { + this->owner = nullptr; + std::fill(neighbors.begin(), neighbors.end(), nullptr); } -void add_to_cache(RegionEdges::cacheType& cache, const RegionEdges::regionType source, RegionEdges::regionType target, const int dir) { - auto rec = cache.find(source); - if (rec == cache.end()) { - RegionEdges::regionArrayType neighbors; - std::fill(neighbors.begin(), neighbors.end(), nullptr); +RegionEdges::RegionEdges(RegionEdges::regionType owner) { + this->owner = owner; + std::fill(neighbors.begin(), neighbors.end(), nullptr); +} - cache.insert({ source, neighbors }); - rec = cache.find(source); - } +void RegionEdges::add(const RegionEdges::itemType edge) { + this->items.insert({ edge->get_id(), edge }); - rec->second[dir] = target; + if (edge->get_left() == this->owner) { + this->neighbors[edge->get_left_dir()] = edge->get_right(); + } else { + this->neighbors[edge->get_right_dir()] = edge->get_left(); + } } -const RegionEdges::regionArrayType& RegionEdges::neighbors(const RegionEdges::regionType region) { - auto rec = this->neighborsCache.find(region); - if (rec == this->neighborsCache.end()) { - RegionEdges::regionArrayType neighbors; - std::fill(neighbors.begin(), neighbors.end(), nullptr); +void RegionEdges::remove(const int id) { + auto rec = this->items.find(id); + if (rec == this->items.end()) { + return; + } - return neighbors; + auto edge = rec->second; + if (edge->get_left() == this->owner) { + this->neighbors[edge->get_left_dir()] = nullptr; + } else { + this->neighbors[edge->get_right_dir()] = nullptr; } - return rec->second; + this->items.erase(rec); } -RegionEdges::iterator RegionEdges::begin() { - return this->items.begin(); +RegionEdges::regionType RegionEdges::get_neighbor(const int dir) { + return this->neighbors[dir]; } -RegionEdges::iterator RegionEdges::end() { - return this->items.end(); +const int RegionEdges::size() const { + return items.size(); } -RegionEdges::regionType RegionEdges::get_neighbor(const RegionEdges::regionType region, const int dir) { - auto rec = this->neighborsCache.find(region); - if (rec == this->neighborsCache.end()) { +RegionEdges::itemType RegionEdges::get(const int id) const { + auto rec = this->items.find(id); + if (rec == this->items.end()) { return nullptr; } - return rec->second[dir]; + return rec->second; } diff --git a/game.cpp b/game.cpp index 4eef4551..ec1ab902 100644 --- a/game.cpp +++ b/game.cpp @@ -185,15 +185,15 @@ void Game::WriteUnderworldMap(ostream& f, ARegionArray *pArr, int type) reg2 = pArr->GetRegion(x+xx*32+1,y+yy*16+1); temp += AString(GetRChar(reg)); temp += GetXtraMap(reg,type); - if (reg2 && reg2->neighbors[D_NORTH]) temp += "|"; + if (reg2 && reg2->neighbors(D_NORTH)) temp += "|"; else temp += " "; temp += " "; - if (reg && reg->neighbors[D_SOUTHWEST]) temp2 += "/"; + if (reg && reg->neighbors(D_SOUTHWEST)) temp2 += "/"; else temp2 += " "; temp2 += " "; - if (reg && reg->neighbors[D_SOUTHEAST]) temp2 += "\\"; + if (reg && reg->neighbors(D_SOUTHEAST)) temp2 += "\\"; else temp2 += " "; temp2 += " "; @@ -206,18 +206,18 @@ void Game::WriteUnderworldMap(ostream& f, ARegionArray *pArr, int type) reg = pArr->GetRegion(x+xx*32,y+yy*16+1); reg2 = pArr->GetRegion(x+xx*32-1,y+yy*16); - if (reg2 && reg2->neighbors[D_SOUTH]) temp += "|"; + if (reg2 && reg2->neighbors(D_SOUTH)) temp += "|"; else temp += " "; temp += AString(" "); temp += AString(GetRChar(reg)); temp += GetXtraMap(reg,type); - if (reg && reg->neighbors[D_SOUTHWEST]) temp2 += "/"; + if (reg && reg->neighbors(D_SOUTHWEST)) temp2 += "/"; else temp2 += " "; temp2 += " "; - if (reg && reg->neighbors[D_SOUTHEAST]) temp2 += "\\"; + if (reg && reg->neighbors(D_SOUTHEAST)) temp2 += "\\"; else temp2 += " "; temp2 += " "; @@ -315,7 +315,7 @@ int Game::ViewMap(const AString & typestr,const AString & mapfile) }; // Fill in the exits for (auto d = 0; d < NDIRS; d++) { - hexout["exits"].push_back(reg->neighbors[d] != nullptr); + hexout["exits"].push_back(reg->neighbors(d) != nullptr); } if (reg->town) { hexout["town"] = data["settlement"]["size"]; @@ -384,14 +384,14 @@ int Game::NewGame() if (Globals->LAIR_MONSTERS_EXIST) CreateVMons(); - - /* + + /* if (Globals->PLAYER_ECONOMY) { Equilibrate(); } */ - - + + return(1); } @@ -577,7 +577,7 @@ int Game::WritePlayers() f << "TurnNumber: " << TurnNumber() << "\n"; if (gameStatus == GAME_STATUS_UNINIT) return(0); - + if (gameStatus == GAME_STATUS_NEW) f << "GameStatus: New\n\n"; else if (gameStatus == GAME_STATUS_RUNNING) @@ -1263,7 +1263,7 @@ void Game::WriteReport() CountAllSpecialists(); size_t ** citems = nullptr; - + if (Globals->FACTION_STATISTICS) { citems = new size_t * [factionseq]; for (int i = 0; i < factionseq; i++) @@ -1677,7 +1677,7 @@ int Game::AllowedTrades(Faction *pFac) int Game::AllowedMartial(Faction *pFac) { int points = pFac->type[F_MARTIAL]; - + if (points < 0) points = 0; if (points > allowedMartialSize - 1) points = allowedMartialSize - 1; @@ -1960,17 +1960,17 @@ void Game::CreateCityMon(ARegion *pReg, int percent, int needmage) Unit *u = GetNewUnit(pFac); Unit *u2; AString *s = new AString("City Guard"); - + /* Awrite(AString("Begin setting up city guard in...")); - + AString temp = TerrainDefs[pReg->type].name; temp += AString(" (") + pReg->xloc + "," + pReg->yloc; temp += ")"; temp += AString(" in ") + *pReg->name; Awrite(temp); */ - + if ((Globals->LEADERS_EXIST) || (pReg->type == R_NEXUS)) { /* standard Leader-type guards */ u->SetMen(I_LEADERS,num); @@ -2004,8 +2004,8 @@ void Game::CreateCityMon(ARegion *pReg, int percent, int needmage) u2->type = U_GUARD; u2->guard = GUARD_GUARD; u2->reveal = REVEAL_FACTION; - } - + } + if (AC) { if (Globals->START_CITY_GUARDS_PLATE) { if (Globals->LEADERS_EXIST) u->items.SetNum(I_PLATEARMOR, num); @@ -2090,20 +2090,20 @@ void Game::AdjustCityMon(ARegion *r, Unit *u) } if ((ItemDefs[i].type & IT_ARMOR) && (num > maxarmor)) { - armor = i; + armor = i; maxarmor = num; } } int skill = S_COMBAT; - + if (weapon != -1) { WeaponType *wp = FindWeapon(ItemDefs[weapon].abr); if (FindSkill(wp->baseSkill) == FindSkill("XBOW")) skill = S_CROSSBOW; if (FindSkill(wp->baseSkill) == FindSkill("LBOW")) skill = S_LONGBOW; } - + int sl = u->GetRealSkill(skill); - + if (r->type == R_NEXUS || r->IsStartingCity()) { towntype = TOWN_CITY; AC = 1; @@ -2204,7 +2204,7 @@ void Game::CountItems(size_t ** citems) int Game::CountItem (Faction * fac, int item) { if (ItemDefs[item].type & IT_SHIP) return 0; - + size_t all = 0; for (const auto& r : fac->present_regions) { forlist(&r->objects) { diff --git a/neworigins/map.cpp b/neworigins/map.cpp index b8a2e4b5..9ccc5cfe 100644 --- a/neworigins/map.cpp +++ b/neworigins/map.cpp @@ -134,7 +134,7 @@ int ZoneRegion::CountNeighbors(Province* province) { std::vector ZoneRegion::GetNeihborZones() { std::vector items; items.reserve(NDIRS); - + for (int i = 0; i < NDIRS; i++) { auto n = this->neighbors[i]; if (n == NULL) continue; @@ -227,7 +227,7 @@ std::unordered_set Province::GetNeighbors() { std::unordered_set Province::GetNeighborBiomes() { std::unordered_set biomes; - + auto tmp = this->GetNeighbors(); for (auto &n : tmp) { if (n->biome != -1) biomes.insert(n->biome); @@ -253,7 +253,7 @@ Coords Province::GetLocation() { continue; } - + xMin = std::min(xMin, reg->location.x); yMin = std::min(yMin, reg->location.y); xMax = std::max(xMax, reg->location.x); @@ -441,7 +441,7 @@ void Zone::AddNeighbor(Zone* zone) { void Zone::SetConnections() { std::unordered_set visited; - + for (auto ®ion : this->regions) { for (auto &n : region.second->neighbors) { if (n == NULL) continue; @@ -557,7 +557,7 @@ int EstimateMaxZones(int area, int radius) { int GetRegionIndex(const int x, const int y, const int w, const int h) { int xx = (x + w) % w; int yy = (y + h) % h; - + if ((xx + yy) % 2) { return -1; } @@ -624,9 +624,9 @@ MapBuilder::MapBuilder(ARegionArray* aregs) { for (auto &item : this->regions) { ARegion* areg = item->region; for (int i = 0; i < NDIRS; i++) { - ARegion* nreg = areg->neighbors[i]; + ARegion* nreg = areg->neighbors(i); - item->neighbors[i] = nreg == NULL + item->neighbors(i) = nreg == NULL ? NULL : this->GetRegion(nreg->xloc, nreg->yloc); } @@ -781,14 +781,14 @@ void MapBuilder::GrowZones() { ClearEmptyZones(); ConnectZones(); -} +} void MapBuilder::MergeZoneInto(Zone* src, Zone* dest) { if (src == NULL) { Awrite("src cannot be null"); exit(1); } - + if (dest == NULL) { Awrite("dest cannot be null"); exit(1); @@ -829,7 +829,7 @@ void MapBuilder::SplitZone(Zone* zone) { auto blob = zone->TraverseRegions(); while (zone->regions.size() != blob.size()) { Zone* newZone = CreateZone(zone->type); - + for (auto ®ion : blob) { zone->RemoveRegion(region); newZone->AddRegion(region); @@ -874,7 +874,7 @@ std::vector FindBorderRegions(Zone* zone, Zone* borderZone, const int roll = makeRoll(1, 5); if (roll < diff) continue; } - + visited.insert(region); } @@ -892,7 +892,7 @@ std::vector FindBorderRegions(Zone* zone, Zone* borderZone, const int roll = makeRoll(1, 5); if (roll < diff) continue; } - + v.push_back(region); } } @@ -1011,11 +1011,11 @@ void MapBuilder::SpecializeZones(size_t continents, int continentAreaFraction) { if (depthRoll == 1) { if (sideADepth == 0) { sideADepth = 1; - sideARandom = true; + sideARandom = true; } else { sideBDepth = 1; - sideBRandom = true; + sideBRandom = true; } } else if (depthRoll == 2) { @@ -1045,7 +1045,7 @@ void MapBuilder::SpecializeZones(size_t continents, int continentAreaFraction) { otherZone->RemoveRegion(r); strait->AddRegion(r); } - + SplitZone(strait); if (sideADepth > 0) SplitZone(nonIsland); @@ -1275,7 +1275,7 @@ void MapBuilder::AddVolcanoes() { candidates.clear(); for (auto &kv : zone->regions) { auto region = kv.second; - + if (region->IsInner()) continue; for (int i = 0; i < NDIRS; i++) { @@ -1450,7 +1450,7 @@ void MapBuilder::GrowLandInZone(Zone* zone) { while (attempts++ < 1000) { ZoneRegion* next = candidates[getrandom(candidates.size())]; if (next->province != NULL) continue; - + provinces.push_back(zone->CreateProvince(next, this->h)); break; } @@ -1525,7 +1525,7 @@ void MapBuilder::GrowLandInZone(Zone* zone) { while (small != NULL); } - // set biomes for provinces + // set biomes for provinces std::unordered_set biomes; for (auto &kv : zone->provinces) { auto p = kv.second; @@ -1634,7 +1634,7 @@ int ARegion::CheckSea(int dir, int range, int remainocean) if (range-- < 1) return 1; for (int d2 = -1; d2< 2; d2++) { int direc = (dir + d2 + NDIRS) % NDIRS; - ARegion *newregion = neighbors[direc]; + ARegion *newregion = neighbors(direc); if (!newregion) continue; remainocean += newregion->CheckSea(dir, range, remainocean); if (remainocean) break; @@ -1742,21 +1742,21 @@ void ARegionList::CreateSurfaceLevel(int level, int xSize, int ySize, char const int sea = Globals->OCEAN; if (Globals->SEA_LIMIT) sea = sea * (100 + 2 * Globals->SEA_LIMIT) / 100; - + MakeLand(pRegionArrays[level], sea, Globals->CONTINENT_SIZE); - + CleanUpWater(pRegionArrays[level]); SetupAnchors(pRegionArrays[level]); - + GrowTerrain(pRegionArrays[level], 0); - + AssignTypes(pRegionArrays[level]); SeverLandBridges(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); FinalSetup(pRegionArrays[level]); @@ -1847,7 +1847,7 @@ void ARegionList::CreateIslandLevel(int level, int nPlayers, char const *name) RandomTerrain(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); FinalSetup(pRegionArrays[level]); @@ -1879,7 +1879,7 @@ void ARegionList::CreateIslandRingLevel(int level, int xSize, int ySize, char co // Put the altars in the ring around the center ARegion *center = pRegionArrays[level]->GetRegion(xSize/2, ySize/2); for (int i = 0; i < NDIRS; i++) { - ARegion *n = center->neighbors[i]; + ARegion *n = center->neighbors(i); if (n) { Object *o = new Object(n); o->num = n->buildingseq++; @@ -1909,10 +1909,10 @@ void ARegionList::CreateUnderworldRingLevel(int level, int xSize, int ySize, cha // Break all connections between barrens and surrounding hexes for (int i = 0; i < NDIRS; i++) { - ARegion *n = reg->neighbors[i]; + ARegion *n = reg->neighbors(i); if (n) { - reg->neighbors[i] = nullptr; - n->neighbors[reg->GetRealDirComp(i)] = nullptr; + reg->neighbors(i) = nullptr; + n->neighbors(reg->GetRealDirComp(i)) = nullptr; } } @@ -1984,7 +1984,7 @@ void ARegionList::CreateUnderworldLevel(int level, int xSize, int ySize, char co MakeUWMaze(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); FinalSetup(pRegionArrays[level]); @@ -2013,7 +2013,7 @@ void ARegionList::CreateUnderdeepLevel(int level, int xSize, int ySize, MakeUWMaze(pRegionArrays[level]); if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); FinalSetup(pRegionArrays[level]); @@ -2041,9 +2041,9 @@ void ARegionList::MakeRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; - reg->wages = -1; - + reg->race = -1; + reg->wages = -1; + reg->level = arr; Add(reg); arr->SetRegion(x, y, reg); @@ -2136,7 +2136,7 @@ void ARegionList::MakeIcosahedralRegions(int level, int xSize, int ySize) // Some initial values; these will get reset // reg->type = -1; - reg->race = -1; // + reg->race = -1; // reg->wages = -1; // initially store: name reg->population = -1; // initially used as flag reg->elevation = -1; @@ -2191,7 +2191,7 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if (!reg) continue; ARegion *newreg = reg; ARegion *seareg = reg; - + // Archipelago or Continent? if (getrandom(100) < Globals->ARCHIPELAGO) { // Make an Archipelago: @@ -2200,21 +2200,21 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int tries = 0; for (int i=0; ineighbors[direc]; + newreg = reg->neighbors(direc); while (!newreg) { direc = getrandom(NDIRS); - newreg = reg->neighbors[direc]; + newreg = reg->neighbors(direc); } tries++; for (int m = 0; m < 2; m++) { seareg = newreg; - newreg = seareg->neighbors[direc]; + newreg = seareg->neighbors(direc); if (!newreg) break; } if (!newreg) break; if (newreg) { seareg = newreg; - newreg = seareg->neighbors[getrandom(NDIRS)]; + newreg = seareg->neighbors(getrandom(NDIRS)); if (!newreg) break; // island start point (~3 regions away from last island) seareg = newreg; @@ -2242,12 +2242,12 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, while (direc == reg->GetRealDirComp(newdir)) { newdir = getrandom(NDIRS); } - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); while ((!newreg) && (tries < 36)) { while (direc == reg->GetRealDirComp(newdir)) { newdir = getrandom(NDIRS); } - newreg = reg->neighbors[newdir]; + newreg = reg->neighbors(newdir); tries++; } if (!newreg) continue; @@ -2273,12 +2273,12 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, if ((reg->yloc < yoff*2) && ((dir < 2) || (dir == (NDIRS-1))) && (getrandom(4) < 3)) continue; if ((reg->yloc > (yband+yoff)*2) && ((dir < 5) && (dir > 1)) - && (getrandom(4) < 3)) continue; - ARegion *newreg = reg->neighbors[dir]; + && (getrandom(4) < 3)) continue; + ARegion *newreg = reg->neighbors(dir); if (!newreg) break; int polecheck = 0; for (int v=0; v < NDIRS; v++) { - ARegion *creg = newreg->neighbors[v]; + ARegion *creg = newreg->neighbors(v); if (!creg) polecheck = 1; } if (polecheck) break; @@ -2330,7 +2330,7 @@ void ARegionList::MakeRingLand(ARegionArray *pRegs, int minDistance, int maxDist int distance = GetPlanarDistance(center, reg, 1000, -1); int different = 0; for (int d = 0; d < NDIRS; d++) { - ARegion *newreg = reg->neighbors[d]; + ARegion *newreg = reg->neighbors(d); if (!newreg) continue; if (newreg->type != reg->type) different++; } @@ -2365,7 +2365,7 @@ void ARegionList::MakeRingLand(ARegionArray *pRegs, int minDistance, int maxDist Awrite("Adding the barrens"); center->type = R_BARREN; for (int d = 0; d < NDIRS; d++) { - ARegion *newreg = center->neighbors[d]; + ARegion *newreg = center->neighbors(d); if (!newreg) continue; newreg->type = R_BARREN; } @@ -2472,7 +2472,7 @@ void ARegionList::RemoveCoastalLakes(ARegionArray *pRegs) int count2 = 0; int temp = 0; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; // name after neighboring lake regions preferrentially if ((newregion->wages > 0) && @@ -2519,7 +2519,7 @@ void ARegionList::SeverLandBridges(ARegionArray *pRegs) if (reg->IsCoastal() != 4) continue; int tidych = Globals->SEVER_LAND_BRIDGES; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if ((!newregion) || (TerrainDefs[newregion->type].similar_type == R_OCEAN)) continue; @@ -2611,7 +2611,7 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) if (!reg) continue; if ((j > 0) && (j < 21) && (getrandom(3) < 2)) continue; if (reg->type == R_NUM) { - + // Check for Lakes if (Globals->LAKES && (getrandom(100) < (Globals->LAKES/10 + 1))) { @@ -2625,11 +2625,11 @@ void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) reg->wages = AGetName(0, reg); break; } - + int init = getrandom(6); for (int i=0; ineighbors[(i+init) % NDIRS]; + ARegion *t = reg->neighbors((i+init) % NDIRS); if (t) { if (t->population < 1) continue; if (t->type != R_NUM && t->type != R_BARREN && @@ -2670,7 +2670,7 @@ void ARegionList::RandomTerrain(ARegionArray *pArr) int adjtype = 0; int adjname = -1; for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; + ARegion *newregion = reg->neighbors(d); if (!newregion) continue; if ((TerrainDefs[newregion->type].similar_type != R_OCEAN) && (newregion->type != R_NUM) && @@ -2704,10 +2704,10 @@ void ARegionList::MakeUWMaze(ARegionArray *pArr) for (int i=D_NORTH; i<= NDIRS; i++) { int count = 0; for (int j=D_NORTH; j< NDIRS; j++) - if (reg->neighbors[j]) count++; + if (reg->neighbors(j)) count++; if (count <= 1) break; - ARegion *n = reg->neighbors[i]; + ARegion *n = reg->neighbors(i); if (n) { if (n->type == R_BARREN) continue; if (n->xloc < x || (n->xloc == x && n->yloc < y)) @@ -2715,11 +2715,11 @@ void ARegionList::MakeUWMaze(ARegionArray *pArr) if (!CheckRegionExit(reg, n)) { count = 0; for (int k = D_NORTH; kneighbors[k]) count++; + if (n->neighbors(k)) count++; } if (count <= 1) break; - n->neighbors[reg->GetRealDirComp(i)] = 0; - reg->neighbors[i] = 0; + n->neighbors(reg->GetRealDirComp(i)) = 0; + reg->neighbors(i) = 0; } } } @@ -2759,25 +2759,25 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) int xoff = x + 2 - getrandom(3) - getrandom(3); ARegion *reg = pArr->GetRegion(xoff, y); if (!reg) continue; - + if ((reg->type == R_LAKE) && (!Globals->LAKESIDE_IS_COASTAL)) continue; if (TerrainDefs[reg->type].flags & TerrainType::BARREN) continue; - + reg->race = -1; wigout = 0; // reset sanity - + if (TerrainDefs[reg->type].similar_type == R_OCEAN) { // setup near coastal race here int d = getrandom(NDIRS); int ctr = 0; - ARegion *nreg = reg->neighbors[d]; + ARegion *nreg = reg->neighbors(d); if (!nreg) continue; while((ctr++ < 20) && (reg->race == -1)) { if (TerrainDefs[nreg->type].similar_type != R_OCEAN) { int rnum = sizeof(TerrainDefs[nreg->type].coastal_races) / sizeof(TerrainDefs[nreg->type].coastal_races[0]); - + while (reg->race == -1 || (ItemDefs[reg->race].flags & ItemType::DISABLED)) { reg->race = TerrainDefs[nreg->type].coastal_races[getrandom(rnum)]; if (++wigout > 100) break; @@ -2785,20 +2785,20 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) } else { int dir = getrandom(NDIRS); if (d == nreg->GetRealDirComp(dir)) continue; - if (!(nreg->neighbors[dir])) continue; - nreg = nreg->neighbors[dir]; + if (!(nreg->neighbors(dir))) continue; + nreg = nreg->neighbors(dir); } } } else { // setup noncoastal race here int rnum = sizeof(TerrainDefs[reg->type].races)/sizeof(TerrainDefs[reg->type].races[0]); - + while ( reg->race == -1 || (ItemDefs[reg->race].flags & ItemType::DISABLED)) { reg->race = TerrainDefs[reg->type].races[getrandom(rnum)]; if (++wigout > 100) break; } } - + /* leave out this sort of check for the moment if (wigout > 100) { // do something! @@ -2807,10 +2807,10 @@ void ARegionList::RaceAnchors(ARegionArray *pArr) Awrite(" region type"); } */ - + if (reg->race == -1) { - cout << "Hey! No race anchor got assigned to the " - << TerrainDefs[reg->type].name + cout << "Hey! No race anchor got assigned to the " + << TerrainDefs[reg->type].name << " at " << x << "," << y << "\n"; } } @@ -2829,7 +2829,7 @@ void ARegionList::GrowRaces(ARegionArray *pArr) if ((!reg) || (reg->race == -1)) continue; for (int dir = 0; dir < NDIRS; dir++) { - ARegion *nreg = reg->neighbors[dir]; + ARegion *nreg = reg->neighbors(dir); if ((!nreg) || (nreg->race != -1)) continue; int iscoastal = 0; int cnum = sizeof(TerrainDefs[reg->type].coastal_races) / @@ -2960,10 +2960,10 @@ void ARegionList::SetACNeighbors(int levelSrc, int levelTo, int maxX, int maxY) if (!AC) continue; if (Globals->START_CITIES_EXIST) { for (int i=0; ineighbors[i]) continue; + if (AC->neighbors(i)) continue; ARegion *pReg = GetStartingCity(AC, i, levelTo, maxX, maxY); if (!pReg) continue; - AC->neighbors[i] = pReg; + AC->neighbors(i) = pReg; pReg->MakeStartingCity(); if (Globals->GATES_EXIST) { numberofgates++; @@ -3127,7 +3127,7 @@ void ARegionList::FixUnconnectedRegions() // first, see if we can knock down a wall // sadly we can only knock down all the walls at once for (i = 0; i < NDIRS; i++) - neighbors[i] = r->neighbors[i]; + neighbors(i) = r->neighbors(i); if (Globals->ICOSAHEDRAL_WORLD) { IcosahedralNeighSetup(r, pRegionArrays[r->zloc]); } else { @@ -3135,8 +3135,8 @@ void ARegionList::FixUnconnectedRegions() } offset = getrandom(NDIRS); for (i = 0; i < NDIRS; i++) { - if (r->neighbors[(i + offset) % NDIRS] && - r->neighbors[(i + offset) % NDIRS]->distance != -1) { + if (r->neighbors((i + offset) % NDIRS) && + r->neighbors((i + offset) % NDIRS)->distance != -1) { break; } } @@ -3144,21 +3144,21 @@ void ARegionList::FixUnconnectedRegions() // restore all the walls other than the one // we meant to break if (i != j) - r->neighbors[(j + offset) % NDIRS] = neighbors[(j + offset) % NDIRS]; + r->neighbors((j + offset) % NDIRS) = neighbors((j + offset) % NDIRS); } if (i < NDIRS) { // also restore the link on the other side - n = r->neighbors[(i + offset) % NDIRS]; + n = r->neighbors((i + offset) % NDIRS); for (j = 0; j < NDIRS; j++) - neighbors[j] = n->neighbors[j]; + neighbors(j) = n->neighbors(j); if (Globals->ICOSAHEDRAL_WORLD) { IcosahedralNeighSetup(n, pRegionArrays[r->zloc]); } else { NeighSetup(n, pRegionArrays[n->zloc]); } for (j = 0; j < NDIRS; j++) - if (n->neighbors[j] != r) - n->neighbors[j] = neighbors[j]; + if (n->neighbors(j) != r) + n->neighbors(j) = neighbors(j); } else if (TerrainDefs[r->type].similar_type != R_OCEAN) { // couldn't break a wall // so try to put in a shaft From 1b408c2782f5c28188b1911f28c12e7ca2794ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valdis=20Zob=C4=93la?= Date: Sat, 24 Aug 2024 22:43:20 +0300 Subject: [PATCH 3/3] some progress in makeing it all work, still not finished --- aregion.cpp | 293 ++++++++++++++++++++++++++++----------------- aregion.h | 291 +++++++++++++++++++++++++++++++++++++------- edges.cpp | 278 +++++++++++++++++++++++++++++++++++++----- neworigins/map.cpp | 220 ++++++++++++++++++++++++---------- object.h | 11 +- 5 files changed, 846 insertions(+), 247 deletions(-) diff --git a/aregion.cpp b/aregion.cpp index cf37e852..3d519202 100644 --- a/aregion.cpp +++ b/aregion.cpp @@ -1831,7 +1831,7 @@ ARegionList::ARegionList() pRegionArrays = 0; numLevels = 0; numberofgates = 0; - last_edge_id = 1000; + edges.set_last_edge_id(1000); } ARegionList::~ARegionList() @@ -1864,17 +1864,15 @@ void ARegionList::WriteRegions(ostream& f) } f << "Edges\n"; - f << this->last_edge_id << '\n'; + f << this->edges.get_last_edge_id() << '\n'; f << this->edges.size() << '\n'; - for (auto kv : this->edges) { - auto edge = kv.second; - - f << edge->get_id() << '\n'; + for (auto edge : this->edges) { + f << edge->id << '\n'; + f << edge->is_undirected << '\n'; f << edge->get_left()->num << '\n'; f << edge->get_right()->num << '\n'; - f << edge->get_left_dir() << '\n'; - f << edge->get_right_dir() << '\n'; + f << edge->left_dir << '\n'; } } @@ -1920,23 +1918,26 @@ int ARegionList::ReadRegions(istream &f, AList *factions) AString temp; int numfOfEdges; + GameEdges::id_type last_edge_id; f >> ws >> temp; // eat the "Edges" line - f >> this->last_edge_id; + f >> last_edge_id; f >> numfOfEdges; + this->edges.set_last_edge_id(last_edge_id); + // Load all edges for (int i = 0; i < numfOfEdges; i++) { - int edge_id, left_num, left_dir, right_num, right_dir; - f >> edge_id >> left_num >> right_num >> left_dir >> right_dir; + int edge_id, left_num, right_num, dir; + bool is_undirected; - RegionEdge* edge = RegionEdge::create(edge_id, fa.GetRegion(left_num), fa.GetRegion(right_num), left_dir, right_dir); + f >> edge_id >> is_undirected >> left_num >> right_num >> dir; - this->edges.insert({ edge->get_id(), edge }); + RegionEdge *edge = is_undirected + ? RegionEdge::create(edge_id, fa.GetRegion(left_num), fa.GetRegion(right_num), dir) + : RegionEdge::create_directed(edge_id, fa.GetRegion(left_num), fa.GetRegion(right_num), dir); - // Assign edge to the regions - edge->get_left()->edges.add(edge); - edge->get_right()->edges.add(edge); + edges.add(edge); } return 1; @@ -1986,21 +1987,21 @@ Location *ARegionList::FindUnit(int i) void ARegionList::NeighSetup(ARegion *r, ARegionArray *ar) { if (r->yloc != 0 && r->yloc != 1) { - this->create_edge(r, ar->GetRegion(r->xloc, r->yloc - 2), D_NORTH, D_SOUTH); + edges.create(r, ar->GetRegion(r->xloc, r->yloc - 2), D_NORTH); } if (r->yloc != 0) { - this->create_edge(r, ar->GetRegion(r->xloc + 1, r->yloc - 1), D_NORTHEAST, D_SOUTHWEST); - this->create_edge(r, ar->GetRegion(r->xloc - 1, r->yloc - 1), D_NORTHWEST, D_SOUTHEAST); + edges.create(r, ar->GetRegion(r->xloc + 1, r->yloc - 1), D_NORTHEAST); + edges.create(r, ar->GetRegion(r->xloc - 1, r->yloc - 1), D_NORTHWEST); } if (r->yloc != ar->y - 1) { - this->create_edge(r, ar->GetRegion(r->xloc + 1, r->yloc + 1), D_SOUTHEAST, D_NORTHWEST); - this->create_edge(r, ar->GetRegion(r->xloc - 1, r->yloc + 1), D_SOUTHWEST, D_NORTHEAST); + edges.create(r, ar->GetRegion(r->xloc + 1, r->yloc + 1), D_SOUTHEAST); + edges.create(r, ar->GetRegion(r->xloc - 1, r->yloc + 1), D_SOUTHWEST); } if (r->yloc != ar->y - 1 && r->yloc != ar->y - 2) { - this->create_edge(r, ar->GetRegion(r->xloc, r->yloc + 2), D_SOUTH, D_NORTH); + edges.create(r, ar->GetRegion(r->xloc, r->yloc + 2), D_SOUTH); } } @@ -2279,32 +2280,35 @@ ARegion *ARegionList::FindGate(int x) ARegion *ARegionList::FindConnectedRegions(ARegion *r, ARegion *tail, int shaft) { - int i; - Object *o; - ARegion *inner; + int i; + Object *o; + ARegion *inner; + + for (i = 0; i < NDIRS; i++) { + if (r->neighbors(i) && r->neighbors(i)->distance == -1) { + tail->next = r->neighbors(i); + tail = tail->next; + tail->distance = r->distance + 1; + } + } + + if (shaft) { + forlist(&r->objects) { + o = (Object *) elem; + + if (o->inner != -1) { + inner = GetRegion(o->inner); - for (i = 0; i < NDIRS; i++) { - if (r->neighbors(i) && r->neighbors(i)->distance == -1) { - tail->next = r->neighbors(i); - tail = tail->next; - tail->distance = r->distance + 1; + if (inner && inner->distance == -1) { + tail->next = inner; + tail = tail->next; + tail->distance = r->distance + 1; } + } } - if (shaft) { - forlist(&r->objects) { - o = (Object *) elem; - if (o->inner != -1) { - inner = GetRegion(o->inner); - if (inner && inner->distance == -1) { - tail->next = inner; - tail = tail->next; - tail->distance = r->distance + 1; - } - } - } - } + } - return tail; + return tail; } ARegion *ARegionList::FindNearestStartingCity(ARegion *start, int *dir) @@ -4001,23 +4005,42 @@ ARegion* ARegionGraph::get(graphs::Location2D id) { } std::vector ARegionGraph::neighbors(graphs::Location2D id) { - ARegion* current = regions->GetRegion(id.x, id.y); + std::vector list; + list.reserve(NDIRS); - std::vector list; - for (int i = 0; i < NDIRS; i++) { - ARegion* next = current->neighbors(i); - if (next == NULL) { - continue; - } + ARegion* current = regions->GetRegion(id.x, id.y); - if (!includeFn(current, next)) { - continue; - } + // go through all edges + for (auto &edge : current->edges) { + auto [next, _] = edge->other_side(current); - list.push_back({ next->xloc, next->yloc }); - } + if (!includeFn(current, next)) { + continue; + } + + list.push_back({ next->xloc, next->yloc }); + } + + ///// 3D vesion will require the code below to go through all shafts and other objects that link to regions + // // go through all shafts and other objects that link to regions + // for (auto &obj : current->objects.iter()) { + // if (obj->inner == -1) { + // continue; + // } - return list; + // ARegion *next = obj->region; + // if (!next) { + // continue; + // } + + // if (!includeFn(current, next)) { + // continue; + // } + + // list.push_back({ next->xloc, next->yloc }); + // } + + return list; } double ARegionGraph::cost(graphs::Location2D current, graphs::Location2D next) { @@ -4032,6 +4055,107 @@ void ARegionGraph::setInclusion(ARegionInclusionFunction includeFn) { this->includeFn = includeFn; } +ARegion* RegionGraph::get(graphs::Location3D id) { + return regions->GetRegion(id.x, id.y, id.z); +} + +std::vector RegionGraph::neighbors(graphs::Location3D id) { + ARegion* current = get(id); + + // prepare a list of candidate neighbors + std::vector candidates; + candidates.reserve(NDIRS); + + // go through all edges + for (auto &edge : current->edges) { + auto [next, _] = edge->other_side(current); + candidates.push_back(next); + } + + // go through all shafts and other objects that link to regions + if (follow_inner_location) { + for (auto &obj : current->objects.iter()) { + if (obj->inner == -1) { + continue; + } + + if (std::find(ignore_objects.begin(), ignore_objects.end(), obj->type) != ignore_objects.end()) { + continue; + } + + ARegion *next = obj->region; + if (!next) { + continue; + } + + candidates.push_back(next); + } + } + + // go through all gates + if (follow_gates) { + bool hasGate = current->gate > 0 + || ( + follow_nexus_gate + && Globals->NEXUS_GATE_OUT + && TerrainDefs[current->type].similar_type == R_NEXUS + ); + + if (hasGate) { + for (auto &next : regions->iter()) { + if (!next->gate) { + continue; + } + + candidates.push_back(next); + } + } + } + + // filter all candidates based on the inclusion function + std::vector list; + list.reserve(candidates.size()); + + for (auto &next : candidates) { + if (stay_in_same_level && next->zloc != current->zloc) { + continue; + } + + if (!includeFn(current, next)) { + continue; + } + + list.push_back({ next->xloc, next->yloc, next->zloc }); + } + + return list; +} + +ARegion* SingleLayerRegionGraph::get(graphs::Location2D id) { + return regions->GetRegion(id.x, id.y); +} + +std::vector SingleLayerRegionGraph::neighbors(graphs::Location2D id) { + std::vector list; + list.reserve(NDIRS); + + ARegion* current = get(id); + + // go through all edges + for (auto &edge : current->edges) { + auto [next, _] = edge->other_side(current); + + if (!includeFn(current, next)) { + continue; + } + + list.push_back({ next->xloc, next->yloc }); + } + + return list; +} + + void ARegionList::ResourcesStatistics() { std::unordered_map resources; std::unordered_map forSale; @@ -4089,7 +4213,7 @@ void ARegionList::ResourcesStatistics() { std::cout << std::endl << std::endl; } -const std::unordered_map> breadthFirstSearch(ARegion* start, const int maxDistance) { +const std::unordered_map> &breadthFirstSearch(ARegion* start, const int maxDistance) { std::queue> frontier; frontier.push({ start, 0 }); @@ -4100,7 +4224,7 @@ const std::unordered_map> breadthFirstSearch(AR graphs::Node current = frontier.front(); frontier.pop(); - if (current.distance > maxDistance) { + if (maxDistance >= 0 && current.distance > maxDistance) { continue; } @@ -4149,54 +4273,3 @@ int ARegionList::FindDistanceToNearestObject(int object_type, ARegion *start) } return min_dist; } - -int ARegionList::next_edge_id() { - return ++this->last_edge_id; -} - -void ARegionList::create_edge(ARegion *left, ARegion *right, const int left_dir, const int right_dir) { - if (has_edge(left, right)) { - return; - } - - RegionEdge *edge = RegionEdge::create(this->next_edge_id(), left, right, left_dir, right_dir); - - this->edges.insert({ edge->get_id(), edge }); - - left->edges.add(edge); - right->edges.add(edge); -} - -const bool ARegionList::has_edge(const ARegion *left, const ARegion *right) const { - for (const auto& kv : this->edges) { - auto edge = kv.second; - - if (edge->get_left() == left && edge->get_right() == right) { - return true; - } - - if (edge->get_left() == right && edge->get_right() == left) { - return true; - } - } - - return false; -} - -void ARegionList::remove_edge(const int id) { - auto kv = this->edges.find(id); - if (kv == this->edges.end()) { - return; - } - - auto edge = kv->second; - auto left = edge->get_left(); - auto right = edge->get_right(); - - left->edges.remove(edge->get_id()); - right->edges.remove(edge->get_id()); - - this->edges.erase(kv); - - delete edge; -} diff --git a/aregion.h b/aregion.h index 4848db9b..1104ce25 100644 --- a/aregion.h +++ b/aregion.h @@ -181,13 +181,37 @@ struct RegionSetup { * @brief Represents a connection between two regions. * * This is a tuple of two regions; an edge in the region graph. - * The edge is bidirectional, it is not important which region is the left and which is the right. + * If the edge is bidirectional, it is not important which region is the left and which is the right. * * Edge allows to add additional information to the connection between the regions. * */ class RegionEdge { +private: + RegionEdge(const bool undirected, const int id, ARegion* left, ARegion* right, const int left_dir, const int right_dir) + : left(left), right(right), is_undirected(undirected), id(id), left_dir(left_dir), right_dir(right_dir) {} + + ARegion* left; + ARegion* right; + public: + using regionType = ARegion *; + + /** + * @brief Represents the other side of the edge. + */ + struct side { + regionType region; + int direction; + }; + + /** + * @brief True if the edge is bidirectional, false if it is directed. + * + * If the edge is directed, the left region is the source and the right region is the destination. + */ + const bool is_undirected; + /** * @brief A unique identifier for this connection. * @@ -195,7 +219,17 @@ class RegionEdge { * Also MOVE order can use this id to specify the destination of the movement. * */ - int get_id() const; + const int id; + + /** + * @brief Direction of the edge from the left region to the right region. + */ + const int left_dir; + + /** + * @brief Direction of the edge from the right region to the left region. + */ + const int right_dir; /** * @brief The left region of the edge. @@ -208,14 +242,14 @@ class RegionEdge { ARegion* get_right() const; /** - * @brief Direction of the edge from the left region to the right region. - */ - int get_left_dir() const; - - /** - * @brief Direction of the edge from the right region to the left region. + * @brief Returns the other side of the edge connected to the source region. + * + * @param source The region to get the other side of. + * @param side The other side of the edge and the direction from the source to the other side. + * @return const bool True if the source region is connected to the other side of the edge, + * false otherwise. */ - int get_right_dir() const; + const bool other_side(const regionType source, side &side) const; /** * @brief Creates a new edge between two regions. @@ -229,17 +263,9 @@ class RegionEdge { * @param right_dir The direction of the edge from the right region to the left region. * @return const Edge* The new edge. */ - static RegionEdge* create(const int id, ARegion *left, ARegion *right, const int left_dir, const int right_dir); - -private: - RegionEdge(const int id, ARegion* left, ARegion* right, const int left_dir, const int right_dir) - : id(id), left(left), right(right), left_dir(left_dir), right_dir(right_dir) {} + static RegionEdge* create(const int id, regionType left, regionType right, const int dir); - int id; - ARegion* left; - ARegion* right; - int left_dir; - int right_dir; + static RegionEdge* create_directed(const int id, regionType left, regionType right, const int dir); }; /** @@ -251,11 +277,37 @@ friend class ARegion; RegionEdges(); public: - using itemType = const RegionEdge *; - using regionType = ARegion *; - using regionArrayType = std::array; - - RegionEdges(regionType owner); + using id_type = unsigned int; + using value_type = const RegionEdge *; + using map_type = std::unordered_map; + using region_type = ARegion *; + using region_array_type = std::array; + + class iterator + { + public: + using iterator_category = std::forward_iterator_tag ; + using value_type = RegionEdges::value_type; + using pointer = const value_type *; + using reference = const value_type &; + using difference_type = map_type::iterator::difference_type; + + reference operator*() const; + pointer operator&() const; + iterator& operator++ (); + iterator operator++(int); + bool operator==(const iterator &that) const noexcept; + bool operator!=(const iterator &that) const noexcept; + + private: + map_type::const_iterator internal_iterator; + + iterator( map_type::const_iterator iter ) : internal_iterator(iter) {} + + friend RegionEdges; + }; + + RegionEdges(region_type owner); /** * @brief Returns the number of connections to other regions and locations. @@ -270,21 +322,21 @@ friend class ARegion; * @param id The id of the edge to get. * @return itemType The edge with the given id or nullptr if there is no such edge. */ - itemType get(const int id) const; + value_type get(const id_type id) const; /** * @brief Adds a new edge to the local list of edges. * * @param edge The edge to add. */ - void add(itemType edge); + void add(value_type edge); /** * @brief Removes an edge from the local list of edges of the region. * * @param id The id of the edge to remove. */ - void remove(const int id); + void remove(const id_type id); /** * @brief Returns the neighboring region in the given direction. @@ -294,12 +346,80 @@ friend class ARegion; * @param dir The direction to get the neighbor of. * @return ARegion* The neighboring region in the given direction or nullptr if there is no neighbor. */ - regionType get_neighbor(const int dir); + region_type get_neighbor(const int dir) const; + + /** + * @brief Returns the edge in the given direction. + * + * @param dir The direction to get the edge of. + * @return itemType The edge in the given direction or nullptr if there is no edge. + */ + value_type get_edge(const int dir) const; + + iterator begin() const noexcept; + iterator end() const noexcept; + +private: + region_type owner; + map_type _edges; + region_array_type neighbors; +}; + +class GameEdges { +public: + using id_type = unsigned int; + using value_type = const RegionEdge *; + using map_type = std::unordered_map; + + class iterator + { + public: + using iterator_category = std::forward_iterator_tag ; + using value_type = GameEdges::value_type; + using pointer = const value_type *; + using reference = const value_type &; + using difference_type = map_type::iterator::difference_type; + + reference operator*() const; + pointer operator&() const; + iterator& operator++ (); + iterator operator++(int); + bool operator==(const iterator &that) const noexcept; + bool operator!=(const iterator &that) const noexcept; + + private: + map_type::const_iterator internal_iterator; + + iterator( map_type::const_iterator iter ) : internal_iterator(iter) {} + + friend GameEdges; + }; + + iterator begin() const noexcept; + iterator end() const noexcept; + + ~GameEdges(); + + const std::size_t size() const; + + const id_type get_last_edge_id() const; + void set_last_edge_id(const id_type id); + + value_type get(const id_type id) const; + value_type create(ARegion *left, ARegion *right, const int dir); + value_type create_directed(ARegion *left, ARegion *right, const int dir); + void add(value_type edge); + value_type find(const ARegion *left, const ARegion *right) const; + const bool has(const ARegion *left, const ARegion *right) const; + const bool has(const id_type id) const; + const bool remove(const id_type id); + const bool remove(value_type edge); private: - regionType owner; - std::unordered_map items; - regionArrayType neighbors; + id_type _last_edge_id; + map_type _edges; + + const id_type next_edge_id(); }; class ARegion : public AListElem @@ -406,12 +526,15 @@ class ARegion : public AListElem int RoadDevelopment(); int TownDevelopment(); int CheckSea(int, int, int); + + // TODO: Functions below should be belong to the map generator not the Region class. int Slope(); int SurfaceWater(); int Soil(); int Winds(); int TerrainFactor(int, int); int TerrainProbability(int); + void AddFleet(Object *); int ResolveFleetAlias(int); @@ -488,15 +611,18 @@ class ARegion : public AListElem // List of units which passed through the region AList passers; std::vector products; - std::vector markets; + std::vector markets; int xloc, yloc, zloc; int visited; // Used for calculating distances using an A* search + // TODO: Remove this! A* distance calculation should be done outside of the region class. int distance; ARegion *next; - // A link to the region's level to make some things easier. + /** + * @brief A link to the region's level to make some things easier. + */ ARegionArray *level; // find a production for a certain skill. @@ -704,12 +830,7 @@ class ARegionList : public AList int CheckRegionExit(ARegion *pFrom, ARegion *pTo); // Region Edges - std::unordered_map edges; - int last_edge_id; - int next_edge_id(); - void create_edge(ARegion *left, ARegion *right, const int left_dir, const int right_dir); - const bool has_edge(const ARegion *left, const ARegion *right) const; - void remove_edge(const int id); + GameEdges edges; }; int LookupRegionType(AString *); @@ -718,6 +839,89 @@ int ParseTerrain(AString *); using ARegionCostFunction = std::function; using ARegionInclusionFunction = std::function; +template +class BaseRegionGraph : public graphs::Graph { +public: + BaseRegionGraph(TContainer* regions) : regions(regions) { + this->costFn = [](ARegion* current, ARegion* next) { return 1; }; + this->includeFn = [](ARegion* current, ARegion* next) { return true; }; + } + + virtual double cost(TLoc current, TLoc next) { + return this->costFn(get(current), get(next)); + } + + virtual void setCost(ARegionCostFunction costFn) { + this->costFn = costFn; + } + + virtual void setInclusion(ARegionInclusionFunction includeFn) { + this->includeFn = includeFn; + } + +protected: + TContainer* regions; + ARegionCostFunction costFn; + ARegionInclusionFunction includeFn; +}; + +class RegionGraph : public BaseRegionGraph { +public: + RegionGraph(ARegionList* regions) : + BaseRegionGraph(regions), + follow_inner_location(false), + follow_gates(false), + follow_nexus_gate(true), + stay_in_same_level(false), + ignore_objects({}) + { } + + ARegion* get(graphs::Location3D id); + std::vector neighbors(graphs::Location3D id); + + /** + * @brief If true, the graph will follow the inner location of the region. + * + * Default is `false`. + */ + bool follow_inner_location; + + /** + * @brief If true, the graph will follow the gates of the region. + * + * Default is `false`. + */ + bool follow_gates; + + /** + * @brief If true, the graph will follow the Nexus gate and connect + * the regions in the Nexus level to all other regions with a gate. + * + * Default is `true`. + */ + bool follow_nexus_gate; + + /** + * @brief If true, the graph will stay in the same level when following the gates. + * + * Default is `false`. + */ + bool stay_in_same_level; + + /** + * @brief List of object types to ignore when following the inner locations. + */ + std::vector ignore_objects; +}; + +class SingleLayerRegionGraph : public BaseRegionGraph { +public: + SingleLayerRegionGraph(ARegionArray* regions) : BaseRegionGraph(regions) { } + + ARegion* get(graphs::Location2D id); + std::vector neighbors(graphs::Location2D id); +}; + class ARegionGraph : public graphs::Graph { public: ARegionGraph(ARegionArray* regions); @@ -736,6 +940,13 @@ class ARegionGraph : public graphs::Graph { ARegionInclusionFunction includeFn; }; -const std::unordered_map> breadthFirstSearch(ARegion* start, const int maxDistance); +/** + * @brief Performs a breadth-first search from the start region. + * + * @param start The region to start the search from. + * @param maxDistance The maximum distance to search. -1 means no limit. + * @return const std::unordered_map>& Distance map from the start region. + */ +const std::unordered_map> &breadthFirstSearch(ARegion* start, const int maxDistance); #endif diff --git a/edges.cpp b/edges.cpp index 8d47f92d..cea02ffd 100644 --- a/edges.cpp +++ b/edges.cpp @@ -25,17 +25,26 @@ #include "aregion.h" + //////////////////// ///// RegionEdge -RegionEdge* RegionEdge::create(const int id, ARegion* left, ARegion* right, const int left_dir, const int right_dir) { - return new RegionEdge(id, left, right, left_dir, right_dir); +inline const int opposite_dir(const int dir) { + return (dir + 3) % 6; +} + +RegionEdge* RegionEdge::create(const int id, ARegion* left, ARegion* right, const int dir) { + return new RegionEdge(true, id, left, right, dir, opposite_dir(dir)); } -int RegionEdge::get_id() const { - return this->id; +RegionEdge* RegionEdge::create_directed(const int id, ARegion* left, ARegion* right, const int dir) { + return new RegionEdge(false, id, left, right, dir, opposite_dir(dir)); } +// int RegionEdge::get_id() const { +// return this->id; +// } + ARegion* RegionEdge::get_left() const { return this->left; } @@ -44,14 +53,31 @@ ARegion* RegionEdge::get_right() const { return this->right; } -int RegionEdge::get_left_dir() const { - return this->left_dir; -} +// int RegionEdge::get_left_dir() const { +// return this->left_dir; +// } -int RegionEdge::get_right_dir() const { - return this->right_dir; -} +// int RegionEdge::get_right_dir() const { +// return this->right_dir; +// } + +const bool RegionEdge::other_side(const RegionEdge::regionType source, RegionEdge::side &side) const { + if (source == left) { + side.region = right; + side.direction = left_dir; + return true; + } + + if (source == right && !is_undirected) { + side.region = left; + side.direction = right_dir; + + return true; + } + + return false; +} //////////////////// ///// RegionEdges @@ -61,50 +87,238 @@ RegionEdges::RegionEdges() { std::fill(neighbors.begin(), neighbors.end(), nullptr); } -RegionEdges::RegionEdges(RegionEdges::regionType owner) { +RegionEdges::RegionEdges(RegionEdges::region_type owner) : RegionEdges() { this->owner = owner; - std::fill(neighbors.begin(), neighbors.end(), nullptr); } -void RegionEdges::add(const RegionEdges::itemType edge) { - this->items.insert({ edge->get_id(), edge }); +void RegionEdges::add(const RegionEdges::value_type edge) { + this->_edges.insert({ edge->id, edge }); - if (edge->get_left() == this->owner) { - this->neighbors[edge->get_left_dir()] = edge->get_right(); - } else { - this->neighbors[edge->get_right_dir()] = edge->get_left(); + RegionEdge::side side; + if (edge->other_side(this->owner, side)) { + this->neighbors[side.direction] = side.region; } } -void RegionEdges::remove(const int id) { - auto rec = this->items.find(id); - if (rec == this->items.end()) { +void RegionEdges::remove(const RegionEdges::id_type id) { + auto rec = this->_edges.find(id); + if (rec == this->_edges.end()) { return; } - auto edge = rec->second; - if (edge->get_left() == this->owner) { - this->neighbors[edge->get_left_dir()] = nullptr; - } else { - this->neighbors[edge->get_right_dir()] = nullptr; + RegionEdge::side side; + if (rec->second->other_side(this->owner, side)) { + this->neighbors[side.direction] = nullptr; } - this->items.erase(rec); + this->_edges.erase(rec); } -RegionEdges::regionType RegionEdges::get_neighbor(const int dir) { +RegionEdges::region_type RegionEdges::get_neighbor(const int dir) const { return this->neighbors[dir]; } const int RegionEdges::size() const { - return items.size(); + return _edges.size(); } -RegionEdges::itemType RegionEdges::get(const int id) const { - auto rec = this->items.find(id); - if (rec == this->items.end()) { +RegionEdges::value_type RegionEdges::get(const RegionEdges::id_type id) const { + auto rec = this->_edges.find(id); + if (rec == this->_edges.end()) { return nullptr; } return rec->second; } + +RegionEdges::value_type RegionEdges::get_edge(const int dir) const { + for (auto& [_, edge] : this->_edges) { + RegionEdge::side side; + if (edge->other_side(this->owner, side) && side.direction == dir) { + return edge; + } + } + + return nullptr; +} + +RegionEdges::iterator RegionEdges::begin() const noexcept { + return RegionEdges::iterator(_edges.begin()); +} + +RegionEdges::iterator RegionEdges::end() const noexcept { + return RegionEdges::iterator(_edges.end()); +} + +RegionEdges::iterator::reference RegionEdges::iterator::operator*() const { + return internal_iterator->second; +} + +RegionEdges::iterator::pointer RegionEdges::iterator::operator&() const { + return std::addressof(**this); +} + +RegionEdges::iterator &RegionEdges::iterator::operator++() { + ++internal_iterator; + return *this; +} + +RegionEdges::iterator RegionEdges::iterator::operator++(int) { + const iterator ov = *this; + ++*this; + return ov; +} + +bool RegionEdges::iterator::operator== (const RegionEdges::iterator& that) const noexcept { + return internal_iterator == that.internal_iterator; +} + +bool RegionEdges::iterator::operator!= (const RegionEdges::iterator& that) const noexcept { + return !(*this == that); +} + + +//////////////////// +///// GameEdges + +GameEdges::~GameEdges() { + for (auto& kv : _edges) { + delete kv.second; + } + + _edges.clear(); +} + +const std::size_t GameEdges::size() const { + return _edges.size(); +} + +const GameEdges::id_type GameEdges::get_last_edge_id() const { + return this->_last_edge_id; +} + +void GameEdges::set_last_edge_id(const GameEdges::id_type id) { + this->_last_edge_id = id; +} + +GameEdges::value_type GameEdges::get(const GameEdges::id_type id) const { + auto kv = _edges.find(id); + if (kv == _edges.end()) { + return nullptr; + } + + return kv->second; +} + +GameEdges::value_type GameEdges::create(ARegion *left, ARegion *right, const int dir) { + auto edge = find(left, right); + if (edge == nullptr) { + edge = RegionEdge::create(this->next_edge_id(), left, right, dir); + add(edge); + } + + return edge; +} + +GameEdges::value_type GameEdges::create_directed(ARegion *left, ARegion *right, const int dir) { + auto edge = find(left, right); + if (edge == nullptr) { + edge = RegionEdge::create_directed(this->next_edge_id(), left, right, dir); + add(edge); + } + + return edge; +} + +void GameEdges::add(GameEdges::value_type edge) { + _edges.insert({ edge->id, edge }); + + edge->get_left()->edges.add(edge); + + if (edge->is_undirected) { + edge->get_right()->edges.add(edge); + } +} + +GameEdges::value_type GameEdges::find(const ARegion *left, const ARegion *right) const { + for (const auto& kv : _edges) { + auto edge = kv.second; + + if (edge->get_left() == left && edge->get_right() == right) { + return edge; + } + + if (edge->get_left() == right && edge->get_right() == left) { + return edge; + } + } + + return nullptr; +} + +const bool GameEdges::has(const ARegion *left, const ARegion *right) const { + return find(left, right) != nullptr; +} + +const bool GameEdges::remove(const GameEdges::id_type id) { + const auto kv = _edges.find(id); + if (kv == _edges.end()) { + return false; + } + + const auto edge = kv->second; + const auto left = edge->get_left(); + const auto right = edge->get_right(); + + left->edges.remove(id); + right->edges.remove(id); + + _edges.erase(kv); + delete edge; + + return true; +} + +const bool GameEdges::remove(const RegionEdge *edge) { + return this->remove(edge->id); +} + +const GameEdges::id_type GameEdges::next_edge_id() { + return ++this->_last_edge_id; +} + + +GameEdges::iterator GameEdges::begin() const noexcept { + return GameEdges::iterator(_edges.begin()); +} + +GameEdges::iterator GameEdges::end() const noexcept { + return GameEdges::iterator(_edges.end()); +} + +GameEdges::iterator::reference GameEdges::iterator::operator*() const { + return internal_iterator->second; +} + +GameEdges::iterator::pointer GameEdges::iterator::operator&() const { + return std::addressof(**this); +} + +GameEdges::iterator &GameEdges::iterator::operator++() { + ++internal_iterator; + return *this; +} + +GameEdges::iterator GameEdges::iterator::operator++(int) { + const iterator ov = *this; + ++*this; + return ov; +} + +bool GameEdges::iterator::operator== (const GameEdges::iterator& that) const noexcept { + return internal_iterator == that.internal_iterator; +} + +bool GameEdges::iterator::operator!= (const GameEdges::iterator& that) const noexcept { + return !(*this == that); +} diff --git a/neworigins/map.cpp b/neworigins/map.cpp index 9ccc5cfe..c46a61bd 100644 --- a/neworigins/map.cpp +++ b/neworigins/map.cpp @@ -626,7 +626,7 @@ MapBuilder::MapBuilder(ARegionArray* aregs) { for (int i = 0; i < NDIRS; i++) { ARegion* nreg = areg->neighbors(i); - item->neighbors(i) = nreg == NULL + item->neighbors[i] = nreg == NULL ? NULL : this->GetRegion(nreg->xloc, nreg->yloc); } @@ -1909,10 +1909,9 @@ void ARegionList::CreateUnderworldRingLevel(int level, int xSize, int ySize, cha // Break all connections between barrens and surrounding hexes for (int i = 0; i < NDIRS; i++) { - ARegion *n = reg->neighbors(i); - if (n) { - reg->neighbors(i) = nullptr; - n->neighbors(reg->GetRealDirComp(i)) = nullptr; + auto e = reg->edges.get_edge(i); + if (e) { + edges.remove(e); } } @@ -2718,8 +2717,8 @@ void ARegionList::MakeUWMaze(ARegionArray *pArr) if (n->neighbors(k)) count++; } if (count <= 1) break; - n->neighbors(reg->GetRealDirComp(i)) = 0; - reg->neighbors(i) = 0; + + edges.remove(reg->edges.get_edge(i)); } } } @@ -2963,8 +2962,14 @@ void ARegionList::SetACNeighbors(int levelSrc, int levelTo, int maxX, int maxY) if (AC->neighbors(i)) continue; ARegion *pReg = GetStartingCity(AC, i, levelTo, maxX, maxY); if (!pReg) continue; - AC->neighbors(i) = pReg; - pReg->MakeStartingCity(); + + auto edge = AC->edges.get_edge(i); + if (edge) { + edges.remove(edge); + } + edges.create_directed(AC, pReg, i); + + pReg->MakeStartingCity(); if (Globals->GATES_EXIST) { numberofgates++; } @@ -3071,95 +3076,175 @@ void ARegionList::InitSetupGates(int level) void ARegionList::FixUnconnectedRegions() { - ARegion *r, *head, *tail, *neighbors[NDIRS], *n; - int attempts, max, i, j, count, offset, x, y, xscale, yscale; - Object *o; - - forlist(this) { - r = (ARegion *) elem; - r->distance = -1; - r->next = 0; - } + ARegion *r, *head, *tail, *neighbors[NDIRS], *n; + int attempts, max, i, j, count, offset, x, y, xscale, yscale; + Object *o; + + RegionGraph graph = RegionGraph(this); + graph.follow_gates = true; + graph.follow_nexus_gate = true; + graph.follow_inner_location = true; + + // iterator for all regions + auto regions = this->iter(); + + + for (auto r : regions) { + r->distance = -1; + r->next = nullptr; + } + + // The region we start from + ARegion *startRegion = nullptr; + + // Start from nexus + std::find_if(regions.begin(), regions.end(), [&startRegion](ARegion *r) { + if (r->zloc == ARegionArray::LEVEL_NEXUS) { + startRegion = r; + return true; + } + + return false; + }); + + + if (!startRegion) { + // Nexus not found, start from a gate + std::find_if(regions.begin(), regions.end(), [&startRegion](ARegion *r) { + if (r->gate) { + startRegion = r; + return true; + } + + return false; + }); + } + + if (!startRegion) { + // No nexus or gate found, start from the first region + startRegion = this->GetRegion(0); + } + + if (!startRegion) { + // No start region found, throw an error + throw std::runtime_error("No start region found"); + } + + // Get distances from the start region + auto distances = graphs::breadthFirstSearch(graph, startRegion); + + // Find all the regions that we couldn't reach + std::vector unconnected; + for (auto r : regions) { + if (distances.find(r) == distances.end()) { + unconnected.push_back(r); + } + } + + // Now we have a list of all the unconnected regions + // We need to connect them to the rest of the world somehow + std::shuffle(unconnected.begin(), unconnected.end(), std::default_random_engine()); + for (auto r : unconnected) { + + } + + // Build a list of all the regions we know we can get to: + // The nexus and anywhere that has a gate + head = nullptr; + tail = nullptr; + for (auto r : this->iter()) { + if (r->zloc == ARegionArray::LEVEL_NEXUS || r->gate == -1) { + r->distance = 0; + r->next = head; + head = r; + if (!tail) { + tail = r; + } + } + } - // Build a list of all the regions we know we can get to: - // The nexus and anywhere that has a gate - head = 0; - tail = 0; - forlist_reuse(this) { - r = (ARegion *) elem; - if (r->zloc == ARegionArray::LEVEL_NEXUS || r->gate == -1) { - r->distance = 0; - r->next = head; - head = r; - if (!tail) - tail = r; - } - } while (head) { tail = FindConnectedRegions(head, tail, 1); head = head->next; } - attempts = 0; + + attempts = 0; do { max = 0; count = 0; - forlist(this) { - r = (ARegion *) elem; + + for (auto r : this->iter()) { if (r->distance == -1) { count++; } - if (r->distance > max) - max = r->distance; + + max = std::max(max, r->distance); } + if (count > 0) { i = getrandom(count); - forlist(this) { - r = (ARegion *) elem; + + for (auto r : this->iter()) { if (r->distance == -1) { - if (!i) + if (!i) { break; + } + i--; } } + // Found an unconnected region // Try to link it in n = 0; + // first, see if we can knock down a wall // sadly we can only knock down all the walls at once - for (i = 0; i < NDIRS; i++) - neighbors(i) = r->neighbors(i); - if (Globals->ICOSAHEDRAL_WORLD) { + for (i = 0; i < NDIRS; i++) { + neighbors[i] = r->neighbors(i); + } + + if (Globals->ICOSAHEDRAL_WORLD) { IcosahedralNeighSetup(r, pRegionArrays[r->zloc]); } else { NeighSetup(r, pRegionArrays[r->zloc]); } - offset = getrandom(NDIRS); + + offset = getrandom(NDIRS); for (i = 0; i < NDIRS; i++) { - if (r->neighbors((i + offset) % NDIRS) && - r->neighbors((i + offset) % NDIRS)->distance != -1) { + if (r->neighbors((i + offset) % NDIRS) && r->neighbors((i + offset) % NDIRS)->distance != -1) { break; } } - for (j = 0; j < NDIRS; j++) { + + for (j = 0; j < NDIRS; j++) { // restore all the walls other than the one // we meant to break - if (i != j) - r->neighbors((j + offset) % NDIRS) = neighbors((j + offset) % NDIRS); + if (i != j) { + r->neighbors((j + offset) % NDIRS) = neighbors[(j + offset) % NDIRS]; + } } - if (i < NDIRS) { + + if (i < NDIRS) { // also restore the link on the other side n = r->neighbors((i + offset) % NDIRS); - for (j = 0; j < NDIRS; j++) - neighbors(j) = n->neighbors(j); + for (j = 0; j < NDIRS; j++) { + neighbors[j] = n->neighbors(j); + } + if (Globals->ICOSAHEDRAL_WORLD) { IcosahedralNeighSetup(n, pRegionArrays[r->zloc]); } else { NeighSetup(n, pRegionArrays[n->zloc]); } - for (j = 0; j < NDIRS; j++) - if (n->neighbors(j) != r) - n->neighbors(j) = neighbors(j); - } else if (TerrainDefs[r->type].similar_type != R_OCEAN) { + + for (j = 0; j < NDIRS; j++) { + if (n->neighbors(j) != r) { + n->neighbors(j) = neighbors[j]; + } + } + } + else if (TerrainDefs[r->type].similar_type != R_OCEAN) { // couldn't break a wall // so try to put in a shaft if (r->zloc > ARegionArray::LEVEL_SURFACE) { @@ -3167,12 +3252,17 @@ void ARegionList::FixUnconnectedRegions() y = r->yloc * GetLevelYScale(r->zloc) / GetLevelYScale(r->zloc - 1); xscale = GetLevelXScale(r->zloc) / GetLevelXScale(r->zloc - 1); yscale = 2 * GetLevelYScale(r->zloc) / GetLevelYScale(r->zloc - 1); - for (i = 0; !n && i < xscale; i++) + + for (i = 0; !n && i < xscale; i++) { for (j = 0; !n && j < yscale; j++) { n = pRegionArrays[r->zloc - 1]->GetRegion(x + i, y + j); - if (n && TerrainDefs[n->type].similar_type == R_OCEAN) + + if (n && TerrainDefs[n->type].similar_type == R_OCEAN) { n = 0; + } } + } + if (n) { o = new Object(n); o->num = n->buildingseq++; @@ -3191,34 +3281,40 @@ void ARegionList::FixUnconnectedRegions() r->objects.Add(o); } } + if (!n) { // None of that worked // can we put in a gate? - if (Globals->GATES_EXIST && - !getrandom(10)) { + if (Globals->GATES_EXIST && !getrandom(10)) { r->gate = -1; r->distance = 0; n = r; } } } + if (n) { head = n; head->next = 0; tail = head; + while (head) { tail = FindConnectedRegions(head, tail, 1); head = head->next; } - attempts = 0; + + attempts = 0; } } + attempts++; - } while (count > 0 && attempts < 1000); + } + while (count > 0 && attempts < 1000); if (count > 0) { printf("Unable to link up %d hexes!\n", count); } + printf("Maximum distance from the Nexus: %d.\n", max); } diff --git a/object.h b/object.h index 5b0660bd..5f02ae81 100644 --- a/object.h +++ b/object.h @@ -134,7 +134,7 @@ class Object : public AListElem void SetPrevDir(int); void MoveObject(ARegion *toreg); - + // Fleets void ReadinFleet(istream &f); void WriteoutFleet(ostream &f); @@ -149,7 +149,7 @@ class Object : public AListElem int FleetSailingSkill(int); int GetFleetSize(); int GetFleetSpeed(int); - + AString *name; AString *describe; ARegion *region; @@ -165,7 +165,12 @@ class Object : public AListElem int mages; int shipno; int movepoints; - int destroyed; // how much points was destroyed so far this turn + + /** + * @brief how much points was destroyed so far this turn + */ + int destroyed; + AList units; AList ships; };