⚓ Seaworth Games

Remnants of the Precursors · ↑ Systems Map · Design series 08

The Galactic Council and the ends of the game

Every other system in ROTP — colonies, tech, ships, spies, diplomacy — is a means. This is the end. The council is the only subsystem that can stop the game while everyone is still alive, and it works by counting the population you grew and the friends you kept. Refuse its verdict and the galaxy fuses into a single empire pointed at you.

Scope original Java design Core files GalacticCouncil.java · GameStatus.java · Empire.goExtinct() Endings 13 statuses, 6 reachable shapes

01Why a council at all

A 4X game needs a way to end that isn't "kill everyone." ROTP has exactly one.

Conquest victory in ROTP is unforgiving: you win militarily only when every other empire is literally extinct — not reduced, not vassalised, not down to one world. There is no surrender, no capitulation, no capital-capture rule. Left alone, a 4X built that way turns into a two-hour mop-up of undefended one-planet remnants.

The council is the answer. It is a scheduled, galaxy-wide referendum in which every surviving empire spends votes proportional to its population on one of the two largest empires. Win two-thirds of the galaxy's vote weight and the game stops — you have won without firing a shot at the last holdout.

What makes it load-bearing rather than decorative is that the council reads directly from three other subsystems and nothing else. Population comes from colonies. Willingness to vote for you comes from the diplomacy relations scalar and the treaty state built on top of it. The tiebreaking bonuses come from races (the Human council bonus) and from the map (owning Orion). The council does no modelling of its own; it is a scoreboard for everything else, cashed out on a fixed schedule.

The design consequence

Because the council is the only non-genocidal ending, and because it counts population rather than territory or fleet strength, ROTP quietly makes growing tall and staying liked a complete strategy. A player who never wins a battle can win the game. That is unusual for a 4X of this era, and it is why the diplomacy system has teeth: relations are not flavour, they are votes.

02When the council forms, and how often it sits

Not a year. A colonization threshold — and then a metronome.

There is no "the council convenes in 2450" rule. Each turn, while the council is still inactive, checkFormation() counts colonized systems:

// GalacticCouncil.checkFormation()
int limit = (int) Math.ceil(gal.numStarSystems() * pctRequired());
float colonized = 0;
for (int i=0; i<gal.numStarSystems(); i++) {
    StarSystem sys = gal.system(i);
    if (sys.isColonized())
        colonized++;
}
if (colonized >= limit) {
    currentStatus = ACTIVE;
    schedule();
}

pctRequired() defaults to 2/3. So the council forms the turn two-thirds of the galaxy's stars have been settled — which ties the endgame clock to the pace of expansion rather than to a calendar. A cramped small galaxy reaches it fast; a sprawling huge galaxy with a slow start may run a hundred extra years before anyone is asked to vote.

Once formed, the cadence is two constants:

Notice
5
noticeDuration — turns between the GNN announcement and the first session
Interval
20
interval — turns of quiet after a deadlocked session
Cycle
25
20 + 5: a fresh vote every quarter-century until someone wins

Each turn nextTurn() decrements a countdown and steps a tiny three-state machine — CHECK → SCHEDULE → CONVENE — with three guards in front of it:

  • options().noGalacticCouncil() — the council can be switched off entirely at setup, which makes conquest the only ending.
  • galaxy().numActiveEmpires() < 3 — a two-empire galaxy never votes.
  • disbanded() — once ended, permanently ended.

Disbanding

Every turn, checkIfDisband() runs from the galaxy's post-turn pass: if the council is active and fewer than three empires remain, it shuts down for good (with a GNN bulletin when exactly two are left). This is the rule that makes endgame duels always military. Grind the galaxy down to you and one rival and the diplomatic exit disappears — you now have to finish the job.

One knob, two jobs

The option that sets the vote threshold, counciRequiredPct, is the same value used as the colonization fraction in checkFormation(). Lowering "percentage needed to win the council vote" also makes the council appear earlier in the game. The setting's description says nothing about this. (The option name is also missing its 'l'.)

03Candidates and vote weight

Population, rounded up, divided by a hundred.

When a session opens, every active empire is sorted by total planetary population, descending. The top two become the candidates — there is no nomination, no campaigning, no way to decline:

Collections.sort(empires, Empire.TOTAL_POPULATION);
...
candidate1 = empires.get(0);
candidate2 = empires.get(1);

Then every empire, candidates included, is assigned votes:

votes[i] = (int) Math.ceil(voter.totalPlanetaryPopulation() / 100);

Three details matter here:

  • ceil, not floor. Any surviving empire, however small, gets at least one vote. A dying two-planet remnant is still a voice in the chamber — and in a close vote, a kingmaker.
  • Planetary population only. totalPlanetaryPopulation() sums colony population across colonized systems. Population riding in transports is not counted (the separate totalEmpirePopulation() does count it, and is not the method used here). Mass-shipping colonists on the turn the council sits costs you votes.
  • The total is not fixed. totalVotes is recomputed every session from that turn's populations, and the winning threshold is derived from it. There is no fixed senate of N seats.

Voting order is descending population by default, so the giants commit first and the small empires watch the tally build — a setup option lets the human vote first or last instead. Ties in the population sort are not broken explicitly; Java's stable sort just leaves equal empires in empire-id order.

04How an AI decides its vote

Four hard rules, then one probabilistic roll built from five terms.

This is the function the whole diplomacy system feeds into. In the default AI it is entirely deterministic until the last step:

// AIDiplomat.councilVoteFor(civ1, civ2) — hard rules
if (civ1 == empire)   return castVoteFor(civ1);   // always vote for yourself
if (civ2 == empire)   return castVoteFor(civ2);

if (cv1.embassy().alliance() && !cv2.embassy().alliance()) return castVoteFor(civ1);
if (cv2.embassy().alliance() && !cv1.embassy().alliance()) return castVoteFor(civ2);

if (cv1.embassy().anyWar() && !cv2.embassy().anyWar()) {
    if (cv2.embassy().contact()) return castVoteFor(civ2);
    else                         return castVoteFor(null);   // abstain
}

So: an alliance is an unconditional vote, and a war is an unconditional vote for the other guy — unless you have never met the other guy, in which case you abstain rather than endorse a stranger. Everything else falls through to a weighted coin flip, evaluated for candidate 1 first and candidate 2 second:

pct = cv1.embassy().relations()/100.0f
    + civ1.councilBonus()
    + civ1.orionCouncilBonus()
    + previousVoteBonus(civ1)
    + powerBonus1;

if (random() <= Math.abs(pct)) {
    if (pct > 0)
        return castVoteFor(civ1);
}
// ... same for civ2, then:
return castVoteFor(null);   // undecided → abstain
TermRangeWhere it comes from
relations()/100−1.00 … +1.00The diplomacy relations scalar, clamped to ±100. The dominant term, and the one every treaty, gift, incident and betrayal has been quietly adjusting all game.
councilBonus()0 … +0.20A race trait, from the 4th field of diplomod in definition.txt, divided by 100. Humans have 0.20. Every other classic race has 0.00.
orionCouncilBonus()0 or +0.20Flat 0.2 if you own the Orion system. The map's single most politically valuable star.
previousVoteBonus()0 or +0.600.6 if this empire voted for the same candidate at the last council. Incumbency is the largest single bonus in the formula.
powerBonus0 … +1.00The candidate's share of galaxy-wide military + industrial power, as seen through this empire's spies. Bandwagoning.

Read together, the shape is clear. A candidate at neutral relations (0.0) with a quarter of the galaxy's power (0.25) gets a one-in-four vote. Add last council's endorsement (+0.6) and it's a lock. Add Orion (+0.2) and being Human (+0.2) and pct exceeds 1.0 — the roll can no longer fail.

Why the second council matters more than the first

The previousVoteBonus of 0.6 means the first council session is not really about winning — it is about establishing a bloc. Every empire that votes for you once becomes dramatically more likely to vote for you again 25 years later. The first vote is the expensive one; subsequent ones compound. A player who understands this front-loads gifts and tech trades into the years immediately before the first session, not the last.

Notably absent from this function: leader personality, diplomat traits, empire size, and any awareness of whether the vote would actually elect someone. AIs do not vote tactically to deny a majority — an unfinished helper for exactly that (nextVoteWouldElect) sits commented out in the source with the note "Never used not updated for new options!"

05The threshold, abstention, and deadlock

Abstaining is not neutral. It is a vote against everybody.

public int votesToElect() {
    return (int) Math.ceil(totalVotes * pctRequired());   // default 2/3
}

The critical detail is the denominator. totalVotes is fixed when the session opens, from every empire's population — including the empires that will go on to abstain. Abstained weight is simply never added to either tally. So:

The blocking third

If empires holding more than one-third of the galaxy's vote weight abstain, the council mathematically cannot elect anyone, no matter how the rest vote. Abstention is the galaxy's veto, and it is the default outcome of "I have no strong feelings and I've met neither of you well." A fragmented galaxy of lukewarm mid-sized empires deadlocks forever.

When no one clears the bar, the session closes, incidents are filed (below), and the council is rescheduled 25 turns out. Nothing else changes. The game continues.

The tie

The election test is not symmetric:

if (votes1 > votes2) {            // both can be above the threshold!
    if (votes1 >= minVotes) { leader = candidate1; rebelLeader = candidate2; }
}
else if (votes2 >= minVotes) { leader = candidate2; rebelLeader = candidate1; }

On an exact tie the first branch is false, so control falls to the else if — and candidate 2, the smaller of the two empires, wins. The vote-total panel in the UI uses the opposite comparison (votes1 >= votes2 && votes1 >= votesToElect) and highlights candidate 1 as the winner in exactly that case. Model and display disagree on ties.

06The vote is remembered — and resented

A deadlocked council fires ten years of diplomatic fallout.

If nobody is elected, each voter earns an incident in both candidates' ledgers. CouncilVoteIncident lasts 10 years and its severity depends on the relationship that already existed:

Candidate's relationship to the voterVoted FORAbstainedVoted AGAINST
Allied with the voter+5−5−15
At war with the voter+250−5
Neutral / any other state+250−15

Voting for yourself scores zero, and a candidate never files an incident about their own vote. The asymmetries are all deliberate and all sharp:

  • Backing an enemy is worth five times backing an ally (+25 vs +5). Supporting someone you are already allied with is expected; crossing the floor to support a rival you are at war with is a genuine olive branch, and the ledger says so.
  • Abstaining is only punished by allies (−5). To everyone else, staying out of it is free. This is what makes the blocking third stable: the safe play carries no diplomatic cost.
  • Voting against an ally (−15) hurts as much as voting against a stranger, and considerably more than voting against someone you are at war with (−5), who expected it anyway.

Because these incidents fire only in the no-winner branch, they exist purely to shape the next council. A deadlocked session redraws the relations map, which redraws the next vote, which — with the 0.6 incumbency bonus layered on top — is why councils tend to deadlock twice and then resolve decisively.

07Elected — and then everyone gets a choice

The vote does not end the game. The submission does.

Winning the vote makes you Emperor on paper only. The moment a leader is declared, the code does something counterintuitive:

if (leader != null) {
    rebels.addAll(allVoters);                      // EVERYONE starts as a rebel
    for (Empire c : allVoters)
        c.diplomatAI().acceptCouncilRuling(this);
    return;
}

Every empire in the galaxy is placed in the rebel list, and then each is asked, one at a time, whether to submit. Submitting moves you from rebels to allies. Defying leaves you where you are. Legitimacy is opt-in.

What an AI does when asked

An elected AI always accepts its own coronation. Otherwise it runs giveLoyaltyTo() — five unconditional yes-rules, then a personality-weighted roll:

float powerBonus = 0.5f * (empire.powerLevel(c) / (empire.powerLevel(c) + empire.powerLevel(empire)) - 0.5f);
// ranges −0.25 (I dwarf him) … +0.25 (he dwarfs me)

if (empire.lastCouncilVoteEmpId() == c.id)  return true;   // I voted for him
if (c.orionCouncilBonus() > 0)              return true;   // he holds Orion
if (cv1.embassy().alliance())               return true;
if (empire.leader().isPacifist())           return true;
if (cv1.embassy().pact() && empire.leader().isHonorable()) return true;

if (cv1.embassy().anyWar()) {
    if (empire.leader().isXenophobic())      return random() < powerBonus;
    else if (empire.leader().isAggressive()) return random() < 0.50f + powerBonus;
    else                                     return random() < 0.75f + powerBonus;
}
if (empire.leader().isXenophobic())      return random() < 0.50f + powerBonus;
else if (empire.leader().isErratic())    return random() < 0.75f + powerBonus;
return random() < 0.90f + powerBonus;

A peaceful galaxy submits almost automatically — 90% base, plus up to 25% more if the new emperor towers over you. A xenophobe you are already at war with essentially never submits: their acceptance chance is powerBonus alone, which is at most 0.25 and is negative whenever they are the stronger party.

This is where the leader-personality system finally pays off. Personality plays no part in voting — it decides only whether you accept the result. The council counts populations; the war that follows is decided by temperament.

Rejecting your own crown

The human player is always offered the accept/defy prompt — including when the player is the empire that just won. Reject your own election and the "crazy leader" branch fires: leadership transfers to the runner-up, every other rebel is conscripted into the loyalist camp, and you become the sole rebel against a unified galaxy. It is the hardest start position in the game and it is entirely opt-in.

When the game ends right here

SituationResult
Player elected, nobody defiesWIN_DIPLOMATIC — the clean diplomatic victory
Player elected, "immediate council win" or "Realms Beyond" option setWIN_DIPLOMATIC — rebellion is disallowed
Player accepts an AI's rule, while allied to that AIWIN_COUNCIL_ALLIANCE — junior partner in the new order
Player accepts an AI's rule with no allianceLOSS_DIPLOMATIC — submission
Player defies, or player is leader with ≥1 AI rebelGame continues → Final War

That third row is the subtle one. Bowing to the winner is scored a win if you were already their ally when the vote closed, and a loss if you weren't. The mechanical difference is one treaty. It is the game's clearest statement that being second in a coalition you helped build is a legitimate way to finish.

08The Final War

Everything the game has been carefully keeping separate gets fused into two blocs — one of which is not actually a bloc.

Flow from a council session through election, submission, and the Final War to each ending Council sits every 25 turns Vote: ceil(pop/100) threshold = 2/3 of all votes cast or not no 2/3 majority — adjourn, file vote incidents Leader elected all empires marked rebel, then each asked to submit All submit → game over diplomatic win · council-alliance win · diplomatic loss anyone defies THE FINAL WAR New Republic leader + everyone who submitted · mutual Unity treaties, no spying · full tech pooled and redistributed · all system info shared one empire in all but name Rebels everyone who refused · no unity, no shared tech · no treaties with each other · at final war with every ally a list, not an alliance rebel list empties every rebel extinct → New Republic wins ally list empties every loyalist extinct → Rebellion wins
The council's two exits. The left branch is the only way the game ends without extinction.

Six things happen the moment the last empire has answered and at least one has defied:

  1. A permanent incident. FinalWarIncident is filed by every loyalist against every rebel with severity = -200 and duration = 9999999. Ordinary diplomacy is over; incident processing short-circuits once final war is declared.
  2. War declared, both directions. declareFinalWar() installs a TreatyFinalWar on both sides of every loyalist–rebel pair and stops the trade routes between them. There is no peace treaty that ends it.
  3. Unity among loyalists. Every pair of allies gets establishUnity() — a TreatyUnity, forced mutual contact, war preparations cancelled, full star-system intelligence shared, and spying zeroed out (max spies set to 0, allocation set to 0, active spies cleared).
  4. Tech pooled upward. Every ally gives the leader every technology the leader lacks.
  5. Tech redistributed downward. The leader then gives every ally everything they lack — which, after step 4, is the union of the entire coalition's research.
  6. Rebels get nothing. No unity loop runs over the rebel list. No shared tech, no shared maps, no treaties with each other, no coordination.
The asymmetry is the point

The New Republic is not an alliance — it is functionally a single empire with the combined tech tree of everyone in it, perfect mutual intelligence, and no internal espionage overhead. The rebels are just a list of empires that all said no. Two rebels are not allies; they may even still be at war with each other. Defying the council is therefore never a coalition play. It is a bet that you personally can outfight a fused galaxy.

How it resolves

Once finalWar() is true — which is simply "the rebel list is non-empty" — extinction stops being evaluated by the normal military rules and routes through GalacticCouncil.removeEmpire() instead. The two win conditions are set-emptiness:

  • Rebel list empties → the New Republic wins. Every rebel must be extinct, not merely beaten.
  • Ally list empties → the rebellion wins. Every loyalist including the emperor must be extinct.

The precise ending you get depends on which side you were on and which role you held, producing five distinct statuses: WIN_NEW_REPUBLIC, WIN_REBELLION, WIN_REBELLION_ALLIANCE, LOSS_NEW_REPUBLIC, LOSS_REBELLION. Losing in a final war still means literal extinction of your empire — there is no "you lost the war" state short of that.

09Every way the game ends

Thirteen statuses, five ways to reach them.

StatusTriggerDetected in
WIN_MILITARYAn AI goes extinct and exactly one empire is left standing. Literal galactic genocide — no surrender, no threshold.Empire.goExtinct()
WIN_MILITARY_ALLIANCEEvery surviving empire is allied (or in unity) with the player. Checked both when an AI dies and at the moment an alliance is signed.goExtinct(), DiplomaticEmbassy
WIN_DIPLOMATICPlayer elected and no one defies (or rebellion is disabled by option).GalacticCouncil.end()
WIN_COUNCIL_ALLIANCEPlayer accepts an AI's election while allied to that AI.GalacticCouncil.end()
WIN_NEW_REPUBLICPlayer was elected, was defied, and exterminated every rebel.removeEmpire()
WIN_REBELLION / …_ALLIANCEPlayer defied and outlived the entire loyalist bloc. The two variants distinguish a lone survivor from several surviving rebels.removeEmpire()
LOSS_MILITARYPlayer's last colony taken by an enemy.goExtinct()
LOSS_NO_COLONIESPlayer's last colony lost with no attacker — abandonment or self-destruction.goExtinct()
LOSS_DIPLOMATICPlayer accepts a council ruling without an alliance to the winner.GalacticCouncil.end()
LOSS_NEW_REPUBLICPlayer was the elected emperor and was exterminated anyway.removeEmpire()
LOSS_REBELLIONPlayer defied and was exterminated.removeEmpire()
LOSS_OVERTHROWNInternal revolt deposes the player. Never fires — see quirks.—

Notice what is not in this list. There is no economic collapse, no morale defeat, no timeout, no "galaxy exhausted", no score threshold, no cultural or research victory. ROTP recognises exactly two shapes of ending: everyone else is dead, or everyone else agrees.

10How the player actually loses

Extinction means zero colonies, and only zero colonies.

Every military ending in ROTP funnels through Empire.goExtinct(), and that is reached from exactly three places, all of them "your colony count hit zero":

  • removeColonizedSystem() — the list of colonized systems became empty.
  • Empire.nextTurn() — allColonies.isEmpty() && transports.isEmpty(). Note the conjunction: colonists in flight keep a colony-less empire alive for as long as they are in transit. Losing your last world with a transport already launched at an empty planet is survivable.
  • Post-invasion, in Colony: if the defender now has zero colonies, they go extinct immediately.

The distinction between LOSS_MILITARY and LOSS_NO_COLONIES is a single field — whether lastAttacker is null. Die to an invasion and it's a military defeat; abandon or bomb your own last world and the game records it as something else entirely.

The one ending shape the design gestures at but never delivers is internal collapse. Empire.inRevolt() exists and works — it returns true when rebelling population exceeds loyal population — and overthrowLeader() genuinely fires for AI empires, installing a new Leader and breaking every treaty. For the player it is disabled at the first line:

public void overthrowLeader() {
    if (isPlayer()) {
        //session().status().loseOverthrown();
        return;
    }
    leader = new Leader(this);
    // ... AI empires get a new leader and lose all treaties

So rebellion in your own empire is purely an economic problem — lost production, lost votes — and never a lose condition. The LOSS_OVERTHROWN status is annotated in the source with the comment "Never happen!".

11No score, no clock

You win or you don't. Nothing is measured.

ROTP computes no end-of-game number of any kind. There is no points total, no ranking of the final empires, no efficiency grade. The ending screen renders a title and some prose chosen from the status enum and two flavour flags, and offers exit or replay.

The two flavour flags are worth knowing because they change the text you get:

  • Player strength, derived from your share of the council's votes: below 50% is "minor", above 2/3 is "feared", in between is "major".
  • Player role: were you the leading candidate, the challenger, or neither.

The only ranking in the game is journalism. Every 25 years GNN publishes a league table — but it picks one of four categories at random (population, production, average tech level, fleet size) and prints the standings. It affects nothing.

There is likewise no turn limit in the base design. Rotp-Fusion adds an optional one — a chosen end-of-game turn (default 200) and a condition: convene a final council where the threshold is dropped to zero so someone must win, or simply crown the top empire by population, tech-and-industry, or total power. It is a mod-layer bolt-on to a game that was designed to run until it resolves.

12Why this design works

Four properties that make a twenty-line vote carry the whole endgame.

It converts every subsystem into one currency

Population is the vote. Population comes from colonies, which come from planetology and terraforming, which come from the tech tree, which is protected by ships and accelerated by espionage. Relations decide whether that population's votes go to you, and relations are the accumulated ledger of every diplomatic act. The council doesn't add a new game — it prices the one you have been playing.

It is a scheduled crisis, not an ambient state

Because the council sits every 25 turns and not otherwise, the game acquires a rhythm: a long build phase, then a sharp, dated moment where all positions are marked to market. Players plan toward the date. The 0.6 incumbency bonus makes each session mortgage the next. That is a much better dramatic shape than a continuously-visible victory bar.

The loser gets agency

The single best decision in this system is that losing a vote does not lose the game. You are asked. Submitting ends things quietly; defying starts the most lopsided war the engine can construct. It turns a defeat screen into a choice with real, terrible content, and it means an AI landslide never simply deletes your run.

The punishment is proportional and legible

The Final War's design — unity, pooled tech, shared maps, zero espionage on one side, and nothing at all on the other — is exactly what "you defied the galaxy" should feel like mechanically. It is not a difficulty multiplier bolted on; it is the natural consequence of everyone else agreeing, expressed in the same treaty and tech-trade systems the player has used all game.

The one soft spot

Because abstention counts against the two-thirds threshold and costs nothing diplomatically, a galaxy of mid-sized empires with lukewarm relations can deadlock indefinitely — session after session with no winner and no consequence beyond a few incidents. The design's escape hatch is that failing to elect anyone is itself pressure: nothing has been resolved, everyone keeps building, and eventually someone grows large enough to clear the bar alone. But it is the one place where the endgame can stall rather than escalate.

13Quirks, dead code, and things that look wrong

Verified against the source, not inferred.

WhatDetail
One option, two meanings counciRequiredPct (sic) sets both the election threshold and the galaxy colonization fraction that forms the council. Lowering the vote requirement makes the council convene earlier. The setting text mentions only the vote.
Ties favour the smaller empire closeConvention()'s if (votes1 > votes2) … else if (votes2 >= minVotes) hands an exact tie to candidate 2. The UI's vote-total panel uses votes1 >= votes2 and highlights candidate 1 in the same situation.
A vestigial absolute value The AI vote does if (random() <= Math.abs(pct)) { if (pct > 0) … }. For any negative pct both branches are no-ops, so the abs() can only burn a random roll. It is the residue of an older version that voted for the other candidate on a negative check.
Non-candidates are reported as the leader playerIsNonCandidate is declared but never assigned anywhere; playerStatus defaults to playerIsLeader (0). A player who was neither candidate and accepted the ruling gets the leader's ending text, and every "as follower" ending title is unreachable.
A setter with the wrong enum loseNewRepublicAsAllied() assigns Status.LOSS_MILITARY rather than LOSS_NEW_REPUBLIC, making its dedicated ending text dead. The call site is itself annotated "Should not happen!".
LOSS_OVERTHROWN never fires Its only call is commented out inside overthrowLeader()'s player guard. GameStatus labels the setter "// Never happen!".
Two New Republic wins are unreachable winNewRepublicAsAllied() and winNewRepublicAsChampion() are both marked "Not reachable yet" at the branch and at the accessor — accepting a ruling as a non-leader already ended the game before they could fire.
"Immediate council win" is one-sided The option is only consulted inside if (leader.isPlayer()). If an AI is elected, the player can still reject and start a final war. Only the "Realms Beyond" option actually removes the reject button.
The turn limit outranks "no council" isForcedEndOfGame() is tested at the very top of nextTurn(), ahead of the noGalacticCouncil(), three-empire and disbanded() guards. Turning the council off does not disable the turn-limited endgame, and the forced path's empires.get(1) can throw when only one empire remains.
A turn-limited win by an AI writes no status On the direct forced-end path the ally and rebel lists are both empty, so end() matches no win or loss branch and falls through loops that iterate over nothing. No ending is recorded and the block re-runs every subsequent turn.
Tactical vote-denial was cut nextVoteWouldElect() is commented out with "Never used not updated for new options!", along with its only caller in all four classic diplomat AIs. No AI ever withholds a vote to block a majority.
Convention state is transient Voters, vote tallies, candidates and the player's vote ratio are all transient, while the leader, rebel and ally lists persist. acceptRuling() and defyRuling() mutate the transient list directly, so a save taken while the accept/defy prompt is open loses the tallies.