Server-authoritative Godot 4.6 strategy game. Includes the headless WebSocket game server, the browser client, and Nix packaging (server and web-export derivations plus a NixOS module) for deployment.
161 lines
6.1 KiB
GDScript
161 lines
6.1 KiB
GDScript
extends TestCase
|
|
|
|
## Covers technologies: the prerequisite tree and effect model of the
|
|
## Technology resource, the catalogue resources, and the research requests plus
|
|
## modifier wiring in GameState. A small deterministic map keeps the fixtures
|
|
## stable.
|
|
|
|
const FRANCE := preload("res://data/civilisations/civ_france.tres")
|
|
const BRITAIN := preload("res://data/civilisations/civ_britain.tres")
|
|
const SEED := 12345
|
|
const BIG_RESEARCH := 100000.0
|
|
|
|
|
|
func _config() -> MapGenerationConfig:
|
|
var config := MapGenerationConfig.new()
|
|
config.map_size = Vector2i(24, 16)
|
|
config.terrain_seed = SEED
|
|
config.min_capital_landmass = 1
|
|
config.min_capital_distance = 2.0
|
|
config.cities_per_civ = 2
|
|
config.city_spacing = 2
|
|
return config
|
|
|
|
|
|
func _state() -> GameState:
|
|
var state := GameState.new()
|
|
state.map_config = _config()
|
|
state.configure([FRANCE, BRITAIN], SEED)
|
|
return state
|
|
|
|
|
|
func test_catalogue_resources_load_and_link_prerequisites() -> void:
|
|
var method := load("res://data/technologies/scientific_method.tres") as Technology
|
|
assert_not_null(method)
|
|
assert_empty(method.prerequisites, "the root technology has no prerequisites")
|
|
assert_true(method.cost > 0.0)
|
|
var automation := load("res://data/technologies/industrial_automation.tres") as Technology
|
|
assert_not_null(automation)
|
|
assert_size(automation.prerequisites, 1)
|
|
assert_eq(automation.prerequisites[0].name, method.name)
|
|
|
|
|
|
func test_prerequisites_met_requires_every_technology() -> void:
|
|
var state := _state()
|
|
var space := state.technologies.find(GameState.SPACE_PROGRAM)
|
|
assert_true(space >= 0)
|
|
assert_false(
|
|
state.technologies[space].prerequisites_met(state.technologies, {}),
|
|
"nothing is researched yet"
|
|
)
|
|
var method := state.technologies.find(GameState.SCIENTIFIC_METHOD)
|
|
var automation := state.technologies.find(GameState.INDUSTRIAL_AUTOMATION)
|
|
var quantum := state.technologies.find(GameState.QUANTUM_COMPUTING)
|
|
assert_true(
|
|
state.technologies[space].prerequisites_met(
|
|
state.technologies, {method: true, automation: true, quantum: true}
|
|
)
|
|
)
|
|
|
|
|
|
func test_partial_prerequisites_do_not_unlock_a_technology() -> void:
|
|
var state := _state()
|
|
var space := state.technologies.find(GameState.SPACE_PROGRAM)
|
|
var method := state.technologies.find(GameState.SCIENTIFIC_METHOD)
|
|
var automation := state.technologies.find(GameState.INDUSTRIAL_AUTOMATION)
|
|
assert_false(
|
|
state.technologies[space].prerequisites_met(
|
|
state.technologies, {method: true, automation: true}
|
|
),
|
|
"one of two prerequisites is not enough"
|
|
)
|
|
|
|
|
|
func test_every_civilisation_starts_with_nothing_researched() -> void:
|
|
var state := _state()
|
|
assert_eq(state.technologies.size(), GameState.TECHNOLOGIES.size())
|
|
assert_false(state.is_researched(0, 0))
|
|
assert_empty(state.get_researched_indices(0))
|
|
|
|
|
|
func test_request_research_spends_points_and_marks_it_known() -> void:
|
|
var state := _state()
|
|
var index := state.technologies.find(GameState.SCIENTIFIC_METHOD)
|
|
state.research[0] = BIG_RESEARCH
|
|
var cost: float = state.technologies[index].cost
|
|
assert_true(state.request_research_technology(0, index))
|
|
assert_true(state.is_researched(0, index))
|
|
assert_approx(state.get_research(0), BIG_RESEARCH - cost, 0.00001, "cost was spent")
|
|
assert_false(state.request_research_technology(0, index), "already known")
|
|
|
|
|
|
func test_request_research_rejects_unknown_and_unaffordable() -> void:
|
|
var state := _state()
|
|
state.research[0] = BIG_RESEARCH
|
|
assert_false(state.request_research_technology(0, 999), "unknown technology")
|
|
assert_false(state.request_research_technology(999, 0), "unknown civilisation")
|
|
state.research[0] = 0.0
|
|
assert_false(state.request_research_technology(0, 0), "cannot afford it")
|
|
|
|
|
|
func test_request_research_rejects_when_prerequisites_are_missing() -> void:
|
|
var state := _state()
|
|
state.research[0] = BIG_RESEARCH
|
|
var space := state.technologies.find(GameState.SPACE_PROGRAM)
|
|
assert_false(state.can_research_technology(0, space))
|
|
assert_false(state.request_research_technology(0, space))
|
|
|
|
|
|
func test_prerequisites_unlock_the_tree() -> void:
|
|
var state := _state()
|
|
state.research[0] = BIG_RESEARCH
|
|
var method := state.technologies.find(GameState.SCIENTIFIC_METHOD)
|
|
var automation := state.technologies.find(GameState.INDUSTRIAL_AUTOMATION)
|
|
var quantum := state.technologies.find(GameState.QUANTUM_COMPUTING)
|
|
var space := state.technologies.find(GameState.SPACE_PROGRAM)
|
|
assert_true(state.request_research_technology(0, automation) == false, "locked before its prerequisite")
|
|
assert_true(state.request_research_technology(0, method))
|
|
assert_true(state.request_research_technology(0, automation))
|
|
assert_true(state.request_research_technology(0, quantum))
|
|
assert_true(state.request_research_technology(0, space))
|
|
|
|
|
|
func test_technology_effects_are_folded_into_gdp() -> void:
|
|
var state := _state()
|
|
state.research[0] = BIG_RESEARCH
|
|
var before := state.get_player_gdp(0)
|
|
var method := state.technologies.find(GameState.SCIENTIFIC_METHOD)
|
|
assert_true(state.request_research_technology(0, method))
|
|
assert_approx(
|
|
state.get_player_gdp(0),
|
|
before * 1.07 / 1.05,
|
|
0.01,
|
|
"scientific method's +2% GDP compounds with the government's +5%"
|
|
)
|
|
|
|
|
|
func test_researched_technology_adds_its_research_rate() -> void:
|
|
var with_tech := _state()
|
|
var without := _state()
|
|
with_tech.research[0] = BIG_RESEARCH
|
|
var method := with_tech.technologies.find(GameState.SCIENTIFIC_METHOD)
|
|
assert_true(with_tech.request_research_technology(0, method))
|
|
var base := with_tech.get_research(0)
|
|
with_tech.advance_hour()
|
|
without.advance_hour()
|
|
var gain_with := with_tech.get_research(0) - base
|
|
var delta := gain_with - without.get_research(0)
|
|
assert_approx(delta, 1.0, 0.00001, "scientific method adds 1 research per hour")
|
|
|
|
|
|
func test_snapshot_exposes_technologies_and_progress() -> void:
|
|
var state := _state()
|
|
state.research[0] = BIG_RESEARCH
|
|
var index := state.technologies.find(GameState.SCIENTIFIC_METHOD)
|
|
assert_true(state.request_research_technology(0, index))
|
|
var snapshot := state.snapshot(0)
|
|
assert_eq(snapshot["technologies"].size(), state.technologies.size())
|
|
assert_eq(snapshot["researched"].size(), state.civilisations.size())
|
|
assert_true((snapshot["researched"][0] as Array).has(index))
|
|
assert_empty(snapshot["researched"][1])
|