132 lines
4.3 KiB
GDScript
132 lines
4.3 KiB
GDScript
class_name GameState
|
|
extends Resource
|
|
|
|
class PlayerData:
|
|
var commands: Array[Command] = []
|
|
|
|
class PlanetData:
|
|
var position: Vector2i
|
|
var grow_every_ticks: int
|
|
var player_id: int
|
|
var population: int
|
|
|
|
class FleetData:
|
|
var count: int
|
|
var player_id: int
|
|
var to_planet_id: int
|
|
var arrives_at_tick: int
|
|
|
|
enum CommandType {
|
|
DISPATCH_FLEET,
|
|
}
|
|
|
|
class Command:
|
|
var type: CommandType
|
|
var wait_tick: int
|
|
|
|
class DispatchFleedCommand extends Command:
|
|
var from_planet_id: int
|
|
var to_planet_id: int
|
|
var max_count: int
|
|
func _init():
|
|
type = CommandType.DISPATCH_FLEET
|
|
|
|
const NEUTRAL_PLAYER_ID := 0
|
|
const FLEET_TAKEOFF_PLUS_LANDING_TIME := 20 # ticks
|
|
const FLEET_SPEED := 2 # pixels/tick
|
|
|
|
signal game_ticked(tick: int)
|
|
signal planet_population_changed(planet_id: int, population: int)
|
|
signal planet_player_changed(planet_id: int, player_id: int)
|
|
signal fleet_dispatched(from_planet_id: int, to_planet_id: int, count: int, player_id: int, departed_at_tick: int, arrives_at_tick: int)
|
|
|
|
var _players: Array[PlayerData] = []
|
|
var _planets: Array[PlanetData] = []
|
|
var _fleets: Array[FleetData] = []
|
|
|
|
var current_tick: int
|
|
|
|
## Add a player to the game.
|
|
## The first player is expected to be the game master / neutral player,
|
|
## who does not play and for whom the population never increases.
|
|
func add_player(data := PlayerData.new()) -> int:
|
|
_players.push_back(data)
|
|
return _players.size() - 1
|
|
|
|
## Add a planet to the game.
|
|
func add_planet(data := PlanetData.new()) -> int:
|
|
_planets.push_back(data)
|
|
return _planets.size() - 1
|
|
|
|
## Advance game status by one tick.
|
|
func tick() -> void:
|
|
current_tick += 1
|
|
|
|
# Handle planets growth.
|
|
for planet_id in range(_planets.size()):
|
|
var planet := _planets[planet_id]
|
|
if planet.player_id != NEUTRAL_PLAYER_ID and current_tick % planet.grow_every_ticks == 0:
|
|
planet.population += 1
|
|
planet_population_changed.emit(planet_id, planet.population)
|
|
|
|
# Handle player commands.
|
|
for player_id in range(_players.size()):
|
|
var player := _players[player_id]
|
|
if player.commands.size() > 0 && current_tick >= player.commands[0].wait_tick:
|
|
var command: Command = player.commands.pop_back()
|
|
match command.type:
|
|
CommandType.DISPATCH_FLEET:
|
|
_handle_dispatch_fleet(player_id, command)
|
|
_:
|
|
assert(false, "Unknown command: %s" % [command])
|
|
|
|
# Handle fleets arrival.
|
|
while _fleets.size() > 0 && current_tick >= _fleets[0].arrives_at_tick:
|
|
var fleet: FleetData = _fleets.pop_back()
|
|
_handle_fleet_arrival(fleet)
|
|
|
|
game_ticked.emit(current_tick)
|
|
|
|
## Dispatch a fleet.
|
|
func dispatch_fleet(player_id: int, from_planet_id: int, to_planet_id: int, max_count: int) -> void:
|
|
var dispatch := DispatchFleedCommand.new()
|
|
dispatch.from_planet_id = from_planet_id
|
|
dispatch.to_planet_id = to_planet_id
|
|
dispatch.max_count = max_count
|
|
_issue_command(player_id, dispatch)
|
|
|
|
func _issue_command(player_id: int, command: Command) -> void:
|
|
var commands := _players[player_id].commands
|
|
var index := commands.map(func (x): return x.wait_tick).bsearch(command.wait_tick, false)
|
|
commands.insert(index, command)
|
|
|
|
func _handle_dispatch_fleet(player_id: int, dispatch: DispatchFleedCommand) -> void:
|
|
var from = _planets[dispatch.from_planet_id]
|
|
if from.player_id == player_id:
|
|
var to = _planets[dispatch.to_planet_id]
|
|
var count = min(dispatch.max_count, from.population)
|
|
from.population -= count
|
|
planet_population_changed.emit(dispatch.from_planet_id, from.population)
|
|
|
|
var fleet := FleetData.new()
|
|
fleet.count = count
|
|
fleet.player_id = player_id
|
|
fleet.to_planet_id = dispatch.to_planet_id
|
|
fleet.arrives_at_tick = current_tick + FLEET_TAKEOFF_PLUS_LANDING_TIME + ceili(from.position.distance_to(to.position) / FLEET_SPEED)
|
|
|
|
var index := _fleets.map(func (x): return x.arrives_at_tick).bsearch(fleet.arrives_at_tick, false)
|
|
_fleets.insert(index, fleet)
|
|
|
|
fleet_dispatched.emit(dispatch.from_planet_id, fleet.to_planet_id, fleet.count, fleet.player_id, current_tick, fleet.arrives_at_tick)
|
|
|
|
func _handle_fleet_arrival(fleet: FleetData) -> void:
|
|
var to = _planets[fleet.to_planet_id]
|
|
if fleet.player_id == to.player_id:
|
|
to.population += fleet.count
|
|
else:
|
|
to.population -= fleet.count
|
|
if to.population <= 0:
|
|
to.player_id = fleet.player_id
|
|
to.population = abs(to.population)
|
|
planet_player_changed.emit(fleet.to_planet_id, to.player_id)
|
|
planet_population_changed.emit(fleet.to_planet_id, to.population)
|