Files
aetherbound-guild/runtime/p10_2/recruit_materializer.gd
T

139 lines
4.4 KiB
GDScript

class_name P102RecruitMaterializer
extends RefCounted
const BaseContent = preload("res://p10_0/content_registry.gd")
const BaseGenerator = preload("res://p10_0/offer_generator.gd")
const BaseMarket = preload("res://p10_0/market_service.gd")
const PROVIDER_CONTRACT_ID := "CTR-R1-01"
var _generator = BaseGenerator.new(BaseContent.snapshot())
func materialize(
run_seed: String,
market_index: int,
refresh_index: int,
slots: Array
) -> Dictionary:
if not _is_hex(run_seed, 32):
return {"ok": false, "code": "invalid_run_seed"}
if market_index < 2 or market_index > 4 or refresh_index < 0:
return {"ok": false, "code": "invalid_market_inputs"}
if slots.size() != 3:
return {"ok": false, "code": "recruit_slot_count"}
for slot_index in range(slots.size()):
var slot = slots[slot_index]
if (
not slot is Dictionary
or int(slot.get("slot", -1)) != slot_index
or not _is_hex(String(slot.get("slot_id", "")), 32)
or not _is_hex(String(slot.get("generation_key", "")), 64)
or int(slot.get("offer_level", 0)) < 1
):
return {"ok": false, "code": "invalid_recruit_slot"}
var generated: Dictionary = _generator.market_board(
run_seed,
PROVIDER_CONTRACT_ID,
market_index,
refresh_index
)
if not generated.ok or generated.board.recruit_offers.size() != 3:
return {"ok": false, "code": "base_recruit_generation_failed"}
var offers: Array[Dictionary] = []
for slot_index in range(3):
var slot: Dictionary = slots[slot_index]
var base: Dictionary = Dictionary(generated.board.recruit_offers[slot_index]).duplicate(true)
var upstream_level := int(base.level)
var offer_level := int(slot.offer_level)
var recruit_id := _low128(_digest(String(slot.generation_key), "p10.2.recruit-instance"))
base["upstream_recruit_id"] = String(base.recruit_id)
base["upstream_source_offer_id"] = String(base.source_offer_id)
base["upstream_generation_key"] = String(base.generation_key)
base["upstream_market_id"] = String(base.market_id)
base["recruit_id"] = recruit_id
base["recruit_instance_id"] = recruit_id
base["generation_key"] = String(slot.generation_key).substr(0, 32)
base["generation_seed"] = String(slot.generation_key).substr(0, 32)
base["source_offer_id"] = String(slot.slot_id)
base["market_id"] = "MKT-CTR-R2-01-%02d-R%02d" % [market_index, refresh_index]
base["region_id"] = "RG-02"
base["contract_id"] = "CTR-R2-01"
base["offer_index"] = slot_index
base["offer_level"] = offer_level
base["profession_tier"] = 0
base["level"] = offer_level
base["xp"] = 0
base["max_hp"] = int(base.max_hp) + 4 * (offer_level - upstream_level)
base["current_hp"] = int(base.max_hp)
base["equipment_instance_id"] = _low128(_digest(
String(slot.generation_key),
"p10.2.starting-equipment-instance",
[String(base.starting_equipment_id)]
))
base["list_price"] = BaseMarket.hire_list_price(offer_level, 0)
base["coin_price_paid"] = 0
base["state"] = "market_offer"
base.erase("canonical_output_hash")
base["canonical_output_hash"] = _hash(base)
offers.append(base)
var materialization := {
"run_seed": run_seed,
"region_id": "RG-02",
"contract_id": "CTR-R2-01",
"market_index": market_index,
"refresh_index": refresh_index,
"provider": "p10_0.offer_generator.recruit_projection.v2",
"provider_contract_id": PROVIDER_CONTRACT_ID,
"offers": offers,
}
materialization["materialization_hash"] = _hash(materialization)
return {
"ok": true,
"code": "recruits_materialized",
"offers": offers,
"materialization": materialization,
}
func _is_hex(value: String, length: int) -> bool:
if value.length() != length:
return false
for character in value:
if character not in "0123456789abcdef":
return false
return true
func _digest(seed: String, label: String, parts: Array = []) -> String:
return _hash({"seed": seed, "label": label, "parts": parts})
func _low128(value: String) -> String:
return value.substr(0, 32)
func _hash(value) -> String:
return JSON.stringify(_canonical(value)).sha256_text()
func _canonical(value):
if value is float and is_equal_approx(value, round(value)):
return int(round(value))
if value is Dictionary:
var result := {}
var keys: Array = value.keys()
keys.sort_custom(func(left, right): return String(left) < String(right))
for key in keys:
result[key] = _canonical(value[key])
return result
if value is Array:
var result: Array = []
for item in value:
result.append(_canonical(item))
return result
return value