1
0
Fork 0
space-capture/scripts/game_state.gd
2024-08-15 21:45:07 +02:00

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)