105 lines
6.0 KiB
GDScript
105 lines
6.0 KiB
GDScript
extends Node
|
||
const PROFILES := preload("res://scripts/planets/planet_profiles.gd")
|
||
const RULES := preload("res://scripts/planets/poi_rules.gd")
|
||
const CAPTAIN := preload("res://scripts/captain/captain_progress.gd")
|
||
var failures: Array[String] = []
|
||
|
||
func check(value: bool, message: String) -> void:
|
||
if not value:
|
||
failures.append(message)
|
||
push_error(message)
|
||
|
||
func equip(captain: Resource, rank: int) -> void:
|
||
for item in captain.gear_items: item.level = rank
|
||
|
||
func _ready() -> void:
|
||
var captain := CAPTAIN.new()
|
||
var state: Resource = captain.expedition
|
||
var statistics: Array[Dictionary] = []
|
||
for level in [1,10,30,60,120]:
|
||
equip(captain,level)
|
||
captain.level = level
|
||
var ore := 0.0
|
||
var damage := 0.0
|
||
var recovery := 0.0
|
||
var difficulty := 0.0
|
||
for seed_value in 200:
|
||
var profile := PROFILES.generate(seed_value+711,0,"Test",level)
|
||
var poi := {"id":seed_value,"kind":"deposit","complete":false,"bonus_available":false}
|
||
var plan := RULES.preview(profile,captain,poi,1234)
|
||
for amount in plan.materials.values(): ore += float(amount)
|
||
damage += (plan.damage.x+plan.damage.y)*0.5
|
||
recovery += float(RULES.report("deposit",profile,captain).multiplier)
|
||
difficulty += float(profile.difficulty)
|
||
if level == 1:
|
||
check(profile.easy and profile.landing_damage == 5,"first-level planets are gentle")
|
||
check(is_equal_approx(RULES.report("deposit",profile,captain).multiplier,1.0),"starter equipment recovers 100 percent")
|
||
check(plan.damage == Vector2i(2,4),"first-level ordinary damage stays 2–4 HP")
|
||
statistics.append({"level":level,"mean_materials":ore/200,"mean_damage":damage/200,"mean_recovery":recovery/200,"mean_difficulty":difficulty/200})
|
||
for index in range(1,statistics.size()):
|
||
check(statistics[index].mean_materials > statistics[index-1].mean_materials,"rewards grow with planet level")
|
||
check(statistics[index].mean_damage > statistics[index-1].mean_damage,"matched-equipment wear grows gradually")
|
||
check(statistics[index].mean_difficulty > statistics[index-1].mean_difficulty,"planet difficulty grows gradually")
|
||
equip(captain,1)
|
||
captain.level = 1
|
||
var profile := PROFILES.generate(123,0,"Pierwsza planeta",1)
|
||
state.lander_hp = 100
|
||
check(state.begin_visit(profile),"first expedition begins")
|
||
var permanent := captain.minerals.duplicate()
|
||
for index in 10:
|
||
var poi := {"id":index,"kind":"deposit","complete":false,"bonus_available":false}
|
||
var hp: float = state.lander_hp
|
||
var plan := RULES.preview(profile,captain,poi,state.visit_seed)
|
||
check(plan == RULES.preview(profile,captain,poi,state.visit_seed),"reopening forecast never rerolls")
|
||
check(state.lander_hp == hp and not poi.complete,"forecast is read-only")
|
||
var result: Dictionary = state.resolve_poi(captain,poi)
|
||
check(result.materials == plan.materials,"actual resources match forecast exactly")
|
||
check(result.damage >= plan.damage.x and result.damage <= plan.damage.y,"damage stays within forecast")
|
||
check(is_equal_approx(state.lander_hp,hp-result.damage),"ordinary POI damages lander")
|
||
var cargo: Dictionary = state.cargo.duplicate()
|
||
check(state.resolve_poi(captain,poi).is_empty() and state.cargo == cargo,"ordinary rewards cannot repeat")
|
||
check(state.lander_hp >= 55 and state.lander_hp <= 75,"ten starter POIs leave 55–75 HP")
|
||
check(captain.minerals == permanent,"loot remains pending until return")
|
||
state.finish_visit(captain,true)
|
||
check(captain.minerals != permanent,"safe return delivers cargo")
|
||
var advanced := PROFILES.generate(123,0,"Trudna planeta",120)
|
||
equip(captain,50)
|
||
check(RULES.report("cave",advanced,captain).multiplier < 0.9,"level 50 gear does not neutralize endgame planets")
|
||
check(RULES.damage_range("cave",advanced,captain).x > 8,"outdated gear increases damage")
|
||
equip(captain,20)
|
||
var middle := PROFILES.generate(123,0,"Test sprzętu",20)
|
||
var cave_before := RULES.damage_range("cave",middle,captain).x
|
||
var warehouse_before := RULES.damage_range("warehouse",middle,captain).x
|
||
captain.gear_items[0].level = 1
|
||
check(RULES.damage_range("cave",middle,captain).x-cave_before > RULES.damage_range("warehouse",middle,captain).x-warehouse_before,"breathing gear matters most in caves")
|
||
equip(captain,1)
|
||
state.lander_hp = 100
|
||
check(state.begin_visit(profile),"bonus expedition begins")
|
||
var bonus_poi := {"id":100,"kind":"deposit","complete":false,"bonus_available":true}
|
||
check(state.resolve_poi(captain,bonus_poi,null,true).is_empty(),"bonus requires initial exploration")
|
||
state.resolve_poi(captain,bonus_poi)
|
||
var bonus_plan := RULES.preview(profile,captain,bonus_poi,state.visit_seed,true)
|
||
check(bonus_plan.damage == Vector2i(8,18),"starter bonus damage is 8–18 HP")
|
||
var cargo_before: Dictionary = state.cargo.duplicate()
|
||
state.resolve_poi(captain,bonus_poi,null,true)
|
||
check(bonus_poi.bonus_complete and state.cargo != cargo_before,"optional bonus awards extra loot once")
|
||
check(state.resolve_poi(captain,bonus_poi,null,true).is_empty(),"bonus cannot repeat")
|
||
var lethal := {"id":101,"kind":"village","complete":false,"bonus_available":true}
|
||
state.resolve_poi(captain,lethal)
|
||
state.lander_hp = 1
|
||
var credits: int = captain.credits
|
||
var minerals: Dictionary = captain.minerals.duplicate()
|
||
state.resolve_poi(captain,lethal,null,true)
|
||
check(state.lander_hp == 0,"greedy exploration can destroy the lander")
|
||
var returned: Dictionary = state.finish_visit(captain,true)
|
||
check(not returned.success and captain.credits == credits and captain.minerals == minerals,"destruction loses expedition loot without touching owned resources")
|
||
var bonus_count := 0
|
||
for index in 2000:
|
||
if RULES.has_bonus({"id":index,"kind":"deposit"},profile): bonus_count += 1
|
||
check(bonus_count >= 400 and bonus_count <= 600,"roughly one quarter of POIs offer bonus exploration")
|
||
var file := FileAccess.open("res://artifacts/planet_exploration_balance.json",FileAccess.WRITE)
|
||
file.store_string(JSON.stringify({"statistics":statistics,"bonus_fraction":bonus_count/2000.0,"failures":failures},"\t"))
|
||
file.close()
|
||
print("PLANET_EXPLORATION_BALANCE: ","PASS" if failures.is_empty() else "FAIL"," ",JSON.stringify(statistics))
|
||
get_tree().quit(0 if failures.is_empty() else 1)
|