refactor(victory): ♻️ Restructure victory logic to handle elimination-based wins immediately and add grace turns for non-elimination victory types
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
3f945c6053
commit
ffdb4c82e8
1 changed files with 40 additions and 10 deletions
|
|
@ -50,14 +50,30 @@ func _resolved_max_turns() -> int:
|
|||
func check_all(_game_map: RefCounted) -> void:
|
||||
if _game_over:
|
||||
return
|
||||
if GameState.turn_number < VICTORY_GRACE_TURNS:
|
||||
|
||||
# Elimination ALWAYS fires regardless of grace — once a player is the only
|
||||
# one alive, the game is structurally over (eliminated players can't
|
||||
# recover). Forcing surviving players to keep playing past elimination
|
||||
# until the grace turn just stalls games (warcouncil p1-29 H2 v1 bug:
|
||||
# T42 elimination + 100-turn grace → games stalled in_progress until
|
||||
# safety_timeout). Elimination victories are inherently a sign that
|
||||
# rush-domination already won; no game-development purpose served by
|
||||
# delay.
|
||||
var elim_winner: int = _check_elimination_winner()
|
||||
if elim_winner >= 0:
|
||||
_game_over = true
|
||||
EventBus.victory_achieved.emit(elim_winner, "domination")
|
||||
return
|
||||
|
||||
var winner_index: int = _check_domination()
|
||||
if winner_index >= 0:
|
||||
_game_over = true
|
||||
EventBus.victory_achieved.emit(winner_index, "domination")
|
||||
return
|
||||
# Capture-all-capitals victory IS gated by grace turns. Slows
|
||||
# rush-domination so games reach mid-game tech development before a
|
||||
# captor can secure all capitals.
|
||||
if GameState.turn_number >= VICTORY_GRACE_TURNS:
|
||||
var winner_index: int = _check_capture_winner()
|
||||
if winner_index >= 0:
|
||||
_game_over = true
|
||||
EventBus.victory_achieved.emit(winner_index, "domination")
|
||||
return
|
||||
|
||||
# Score fallback: at max turns, award the highest-scoring player.
|
||||
if GameState.turn_number >= _resolved_max_turns():
|
||||
|
|
@ -68,9 +84,10 @@ func check_all(_game_map: RefCounted) -> void:
|
|||
return
|
||||
|
||||
|
||||
## Domination: a player owns every opponent's original capital, OR is the
|
||||
## last player with at least one city (elimination fallback).
|
||||
func _check_domination() -> int:
|
||||
## Capture-all-capitals: a player owns every opponent's original capital.
|
||||
## Gated by VICTORY_GRACE_TURNS — early-game capture wins before mid-game
|
||||
## tech development are blocked.
|
||||
func _check_capture_winner() -> int:
|
||||
var capital_owner_by_player: Dictionary = {} # player_index → current city.owner
|
||||
for player: Variant in GameState.players:
|
||||
if not player is PlayerScript:
|
||||
|
|
@ -94,8 +111,12 @@ func _check_domination() -> int:
|
|||
break
|
||||
if owns_all_other_capitals and candidate.cities.size() > 0:
|
||||
return idx
|
||||
return -1
|
||||
|
||||
# Elimination fallback.
|
||||
|
||||
## Elimination: only one player has cities or a living founder. Always
|
||||
## eligible regardless of grace — see check_all() docstring.
|
||||
func _check_elimination_winner() -> int:
|
||||
var alive_players: Array[int] = []
|
||||
for player: Variant in GameState.players:
|
||||
if not player is PlayerScript:
|
||||
|
|
@ -111,6 +132,15 @@ func _check_domination() -> int:
|
|||
return -1
|
||||
|
||||
|
||||
## Legacy combined check kept for any external callers that referenced the
|
||||
## previous API. Delegates to the split functions; respects no grace.
|
||||
func _check_domination() -> int:
|
||||
var capture_winner: int = _check_capture_winner()
|
||||
if capture_winner >= 0:
|
||||
return capture_winner
|
||||
return _check_elimination_winner()
|
||||
|
||||
|
||||
func _has_living_founder(player: RefCounted) -> bool:
|
||||
for unit: Variant in player.units:
|
||||
if unit is UnitScript and unit.is_alive() and unit.can_found_city:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue