Skip to content

Commit

Permalink
Remove the freezing code & add city counting for winner
Browse files Browse the repository at this point in the history
A common New Origins win condition is percent of cities voting.
Add a global define to enable this, and put the counting and automatic
victory declaration, as well as a times message once someone has made
good progress towards it.   While this won't be used for NO7, I suspect
it will be good to have for the future.

Also, the freezing code was highly NO6 specific, so it shouldn't be
on the master branch.
  • Loading branch information
jt-traub committed May 5, 2024
1 parent 74111b8 commit ba48ada
Showing 1 changed file with 80 additions and 22 deletions.
102 changes: 80 additions & 22 deletions neworigins/extra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <string>
#include <iterator>

using namespace std;

#define MINIMUM_ACTIVE_QUESTS 5
#define MAXIMUM_ACTIVE_QUESTS 20
#define QUEST_EXPLORATION_PERCENT 30
Expand All @@ -39,6 +41,10 @@
#define QUEST_SPAWN_CHANCE 70
#define MAX_DESTINATIONS 5

// If this is set to true, then the game will end if a faction has > 50% of all cities in the game with their id
// in the name.
#define CITY_VOTE_WIN false

int Game::SetupFaction( Faction *pFac )
{
pFac->unclaimed = Globals->START_MONEY + TurnNumber() * 300;
Expand Down Expand Up @@ -417,17 +423,17 @@ Faction *Game::CheckVictory()
string stlstr;
set<string> intersection, un;
set<string>::iterator it2;
Faction *winner = nullptr;

forlist(&quests) {
q = (Quest *) elem;
if (q->type != Quest::VISIT)
continue;
for (it2 = q->destinations.begin();
it2 != q->destinations.end();
it2++) {
for (it2 = q->destinations.begin(); it2 != q->destinations.end(); it2++) {
un.insert(*it2);
}
}

visited = 0;
unvisited = 0;
forlist_reuse(&regions) {
Expand Down Expand Up @@ -465,14 +471,14 @@ Faction *Game::CheckVictory()
if (visited >= (unvisited + visited) * QUEST_EXPLORATION_PERCENT / 100) {
// Exploration phase complete: start creating relic quests
for (i = 0; i < QUEST_SPAWN_RATE; i++) {
if (quests.Num() < MAXIMUM_ACTIVE_QUESTS &&
getrandom(100) < QUEST_SPAWN_CHANCE)
if (quests.Num() < MAXIMUM_ACTIVE_QUESTS && getrandom(100) < QUEST_SPAWN_CHANCE)
CreateQuest(&regions, monfaction);
}
while (quests.Num() < MINIMUM_ACTIVE_QUESTS) {
CreateQuest(&regions, monfaction);
}
}

if (unvisited) {
// Tell the players to get exploring :-)
if (visited > 9 * unvisited) {
Expand Down Expand Up @@ -728,30 +734,82 @@ Faction *Game::CheckVictory()
}
}

if (TurnNumber() >= 29) { // 29 is just a number to avoid breaking snapshots
// Freezing effect
forlist_reuse(&regions) {
ARegion *r = (ARegion *) elem;

// No effect for regions with clear skies
if (r->clearskies) {
continue;
// Check for victory conditions based on the current game
if (CITY_VOTE_WIN) {
std::map <int, int> votes; // track votes per faction id
int total_cities = 0; // total cities possible for vote count

forlist(&regions) {
ARegion *r = (ARegion *)elem;
// Ignore anything but the surface
if (r->level->levelType != ARegionArray::LEVEL_SURFACE) continue;
if (!r->town || (r->town->TownType() != TOWN_CITY)) continue;

total_cities++;

string name = r->town->name->const_str();
string possible_faction = name.substr(0, s.find_first_of(" \t\n"));
// The first word of the name was not all numeric, don't count for anyone
if (!all_of(
possible_faction.begin(),
possible_faction.end(),
[](unsigned char ch){ return std::isdigit(ch); }
)) continue;
// Now that we know it's all numeric, convert it to an int
int faction_id = stoi(possible_faction);

// Make sure it's a valid faction
Faction *f = GetFaction(&factions, faction_id);
if (!f || f->is_npc) continue;

auto vote = votes.find(faction_id);
if (vote == votes.end()) {
votes[faction_id] = 1;
} else {
vote->second++;
}
}

// Check if regions in freezing zome in surface
if (r->zloc == ARegionArray::LEVEL_SURFACE && (r->yloc <= 0 || r->yloc >= 71)) {
r->Pillage();
r->SetWeather(W_BLIZZARD);
printf("Freeze (%d,%d) region in %s of %s\n",
r->xloc, r->yloc, r->name->Str(), TerrainDefs[TerrainDefs[r->type].similar_type].name
);
// Set up the voting result to be reported if we are far enough in
string message = "Voting results: \n";

int max_vote = -1;
bool tie = false;
Faction *maxFaction = nullptr;
for (const auto& vote : votes) {
Faction *f = GetFaction(&factions, vote.first);
if (vote.second > max_vote) {
max_vote = vote.second;
maxFaction = f;
tie = false;
} else if (vote.second == max_vote) {
tie = true;
maxFaction = nullptr;
}
message += "Faction " + string(f->name->const_str()) + " has " + to_string(vote.second) + " votes.\n";
}

// TODO: Check if regions in freezing zome in UW
// See if we have enough votes to even report the info. Since a win requires 50% + 1, we can start reporting
// once someone has more than 25% of the cities.
if (max_vote > (total_cities / 4)) {
// Now see if we have a winner at all
if (max_vote > ((total_cities / 2) + 1)) {
winner = maxFaction;
message += "\n" + string(winner->name->const_str()) + " has enough votes and has won the game!";
} else {
percent = (max_vote * 100) / total_cities;
if (tie) {
message += "\nThere is a tie for the most votes with multiple factions having ";
} else {
message += "\n" + "The current leader is " + string(maxFaction->name->const_str()) + " with ";
}
message += to_string(max_vote) + "/" + to_string(total_cities) + " votes (" + to_string(percent) + "%).";
}
WriteTimesArticle(message);
}
}

return NULL;
return winner;
}

void Game::ModifyTablesPerRuleset(void)
Expand Down

0 comments on commit ba48ada

Please sign in to comment.