158 lines
6.0 KiB
GDScript
158 lines
6.0 KiB
GDScript
extends Resource
|
|
const EQUIPMENT := preload("res://scripts/planets/captain_equipment.gd")
|
|
const PROFILES := preload("res://scripts/planets/planet_profiles.gd")
|
|
@export var lander_hp := 100.0
|
|
@export var visits: Dictionary = {}
|
|
@export var scans: Dictionary = {}
|
|
@export var delivered_modules: Array[Resource] = []
|
|
@export var research_records: Dictionary = {}
|
|
var active := false
|
|
var cargo: Dictionary = {}
|
|
var cargo_modules: Array[Resource] = []
|
|
var cargo_records: Dictionary = {}
|
|
var active_profile: Dictionary = {}
|
|
var visit_seed := 0
|
|
var last_result: Dictionary = {}
|
|
|
|
func repair_cost() -> int:
|
|
return maxi(0, ceili(100.0 - lander_hp - 0.00001))
|
|
|
|
func repair(captain: Resource) -> bool:
|
|
var cost := repair_cost()
|
|
if active or captain.parts < cost:
|
|
return false
|
|
captain.parts -= cost
|
|
lander_hp = 100
|
|
captain.emit_changed()
|
|
return true
|
|
|
|
func scan(profile: Dictionary) -> void:
|
|
scans[str(profile.id)] = profile.duplicate(true)
|
|
emit_changed()
|
|
|
|
func begin_visit(profile: Dictionary) -> bool:
|
|
if active or repair_cost() > 0:
|
|
return false
|
|
active_profile = profile.duplicate(true)
|
|
var count := int(visits.get(profile.id, 0)) + 1
|
|
visits[profile.id] = count
|
|
visit_seed = int(profile.seed) ^ (count * 7919)
|
|
cargo.clear()
|
|
cargo_modules.clear()
|
|
cargo_records.clear()
|
|
active = true
|
|
lander_hp = maxf(0, lander_hp - float(profile.landing_damage))
|
|
last_result.clear()
|
|
return true
|
|
|
|
func damage(amount: float) -> void:
|
|
if active:
|
|
lander_hp = clampf(lander_hp - maxf(0, amount), 0, 100)
|
|
emit_changed()
|
|
|
|
func add_material(key: String, amount: int) -> void:
|
|
if active and amount > 0:
|
|
cargo[key] = int(cargo.get(key, 0)) + amount
|
|
emit_changed()
|
|
|
|
func resolve_poi(captain: Resource, poi: Dictionary, rng: RandomNumberGenerator) -> Dictionary:
|
|
if not active or bool(poi.get("complete", false)):
|
|
return {}
|
|
var stage := int(poi.get("stage", 0))
|
|
var chance := PROFILES.success_chance(active_profile, captain, stage)
|
|
var success := rng.randf() < chance
|
|
var result := {"success": success, "chance": chance, "damage": 0, "materials": {}, "module": null}
|
|
if success:
|
|
var difficulty := float(active_profile.difficulty)
|
|
var multiplier := (1.0 + difficulty * 2.0) * (1.0 + stage * 0.65)
|
|
var ordinary: Array = ["iron", "titanium", "aluminium", "uranium", "sulfur"]
|
|
var pool: Array = PROFILES.MATERIALS if rng.randf() < 0.55 else ordinary
|
|
var key: String = pool[rng.randi_range(0, pool.size() - 1)]
|
|
var amount := maxi(1, roundi(rng.randi_range(5, 12) * multiplier))
|
|
add_material(key, amount)
|
|
result.materials[key] = amount
|
|
if rng.randf() < 0.15 + difficulty * 0.25:
|
|
var generator := preload("res://scripts/items/item_generator.gd")
|
|
var definitions: Array = generator.DEFINITIONS.filter(func(d): return d.category != ItemDefinition.Category.WEAPON)
|
|
var level := mini(1000, GameState.system_level + roundi(difficulty * 6.0) + stage)
|
|
var item: ItemInstance = generator.generate_loot(level, 1 if difficulty > 0.5 or stage >= 2 else 0, definitions[rng.randi_range(0, definitions.size() - 1)])
|
|
cargo_modules.append(item)
|
|
result.module = item
|
|
if str(poi.kind) == "ruins":
|
|
var record := "Archiwum %s" % str(active_profile.name)
|
|
cargo_records[record] = int(cargo_records.get(record, 0)) + 1
|
|
poi.stage = stage + 1
|
|
if int(poi.stage) >= 3:
|
|
poi.complete = true
|
|
else:
|
|
var loss := rng.randi_range(8, 15) + stage * 5 + roundi(float(active_profile.difficulty) * 10)
|
|
damage(loss)
|
|
result.damage = loss
|
|
# Failure closes this location; previously collected loot stays until return.
|
|
poi.complete = true
|
|
emit_changed()
|
|
return result
|
|
|
|
func finish_visit(captain: Resource, success: bool) -> Dictionary:
|
|
if not active:
|
|
return last_result
|
|
success = success and lander_hp > 0
|
|
var result := {"success": success, "materials": cargo.duplicate(), "modules": cargo_modules.size(), "hp": lander_hp}
|
|
if success:
|
|
for key in cargo:
|
|
captain.minerals[key] = int(captain.minerals.get(key, 0)) + int(cargo[key])
|
|
delivered_modules.append_array(cargo_modules)
|
|
for key in cargo_records:
|
|
research_records[key] = int(research_records.get(key, 0)) + int(cargo_records[key])
|
|
active = false
|
|
cargo.clear()
|
|
cargo_modules.clear()
|
|
cargo_records.clear()
|
|
active_profile.clear()
|
|
last_result = result
|
|
captain.emit_changed()
|
|
emit_changed()
|
|
return result
|
|
|
|
func deliver_modules(inventory: Node) -> int:
|
|
var delivered := 0
|
|
for index in range(delivered_modules.size() - 1, -1, -1):
|
|
if inventory.add_item(delivered_modules[index]):
|
|
delivered_modules.remove_at(index)
|
|
delivered += 1
|
|
emit_changed()
|
|
return delivered
|
|
|
|
const ENGINEER_PRICE := 100
|
|
const ENGINEER_LEVEL_RATIO := 0.75
|
|
|
|
static func roll_engineer_bonus(rng: RandomNumberGenerator) -> int:
|
|
var total := 0.0
|
|
for bonus in 21:
|
|
total += pow(ENGINEER_LEVEL_RATIO,bonus)
|
|
var roll := rng.randf()*total
|
|
for bonus in 21:
|
|
roll -= pow(ENGINEER_LEVEL_RATIO,bonus)
|
|
if roll < 0:
|
|
return bonus
|
|
return 20
|
|
|
|
func buy_engineer_offer(captain: Resource, event: Dictionary, rng: RandomNumberGenerator) -> Dictionary:
|
|
if not active or lander_hp <= 0 or str(event.get("kind","")) != "engineer" or bool(event.get("complete",false)):
|
|
return {"success":false,"reason":"Oferta jest już niedostępna."}
|
|
if captain.credits < ENGINEER_PRICE:
|
|
return {"success":false,"reason":"Potrzebujesz 100 kredytów."}
|
|
var generator := preload("res://scripts/items/item_generator.gd")
|
|
var categories := [ItemDefinition.Category.SHIELD,ItemDefinition.Category.ARMOR,ItemDefinition.Category.ENGINE,ItemDefinition.Category.REACTOR,ItemDefinition.Category.COMPUTER]
|
|
var definitions: Array = generator.DEFINITIONS.filter(func(definition): return definition.category in categories)
|
|
var level := mini(1000,GameState.system_level+roll_engineer_bonus(rng))
|
|
# Generate the exact offered level; captain luck must not bypass the +20 limit.
|
|
var item: ItemInstance = generator.generate_for_definition(definitions[rng.randi_range(0,definitions.size()-1)],level,0)
|
|
captain.credits -= ENGINEER_PRICE
|
|
cargo_modules.append(item)
|
|
event.complete = true
|
|
captain.emit_changed()
|
|
emit_changed()
|
|
return {"success":true,"item":item}
|
|
|