87 lines
2.7 KiB
GDScript
87 lines
2.7 KiB
GDScript
## ShopManager — 商店管理(Autoload: ShopManager)
|
||
## S2 范围:3 选 1 法术、金币扣减、刷新费用公式(P6-N23)
|
||
## 权威来源:development_plan.md S2、numerical_design.md §2.3
|
||
extends Node
|
||
|
||
signal shop_refreshed
|
||
signal shop_closed
|
||
|
||
const SLOT_COUNT: int = 3
|
||
const REROLL_BASE_COST: int = 20 # 第 1 次刷新费用
|
||
const REROLL_STEP: int = 10 # 每次递增价格
|
||
|
||
var current_slots: Array = [] # Array[SpellNode] (null 表示已售出)
|
||
var reroll_count: int = 0 # 本波已刷新次数(WAVE_COMPLETE 后重置)
|
||
var _shop_seed: int = 0 # 随机种(ADR-A2 P-S2-07)
|
||
var _rng: RandomNumberGenerator = RandomNumberGenerator.new()
|
||
|
||
func _ready() -> void:
|
||
EventBus.subscribe(EventID.WAVE_COMPLETE, _on_wave_complete)
|
||
|
||
func _on_wave_complete(_payload: Dictionary) -> void:
|
||
reroll_count = 0 # P6-N23:波次结算后重置刷新次数
|
||
|
||
func open_shop(seed_override: int = -1) -> void:
|
||
if seed_override >= 0:
|
||
_shop_seed = seed_override
|
||
else:
|
||
_shop_seed = randi()
|
||
_rng.seed = _shop_seed
|
||
_refresh_slots()
|
||
EventBus.emit(EventID.SHOP_OPENED, {"seed": _shop_seed})
|
||
|
||
func _refresh_slots() -> void:
|
||
# 纯数据驱动池:SpellRegistry(data/spells.json)中可购买(shop_cost>0)的法术
|
||
var pool: Array = SpellRegistry.get_all_ids().filter(func(id):
|
||
var s: SpellNode = SpellRegistry.get_spell(id)
|
||
return s != null and int(s.meta.get("shop_cost", 0)) > 0)
|
||
current_slots.clear()
|
||
for _i in SLOT_COUNT:
|
||
if pool.is_empty():
|
||
current_slots.append(null)
|
||
continue
|
||
var idx: int = _rng.randi_range(0, pool.size() - 1)
|
||
current_slots.append(SpellRegistry.get_spell(pool[idx]))
|
||
pool.remove_at(idx)
|
||
shop_refreshed.emit()
|
||
|
||
## 购买指定槽位的法术,返回购买的 SpellNode、失败返回 null
|
||
func buy_spell(slot_idx: int) -> SpellNode:
|
||
if slot_idx < 0 or slot_idx >= current_slots.size():
|
||
return null
|
||
var spell: SpellNode = current_slots[slot_idx]
|
||
if spell == null:
|
||
return null
|
||
var cost: int = int(spell.meta.get("shop_cost", 20))
|
||
if not PlayerStats.spend_gold(cost):
|
||
return null
|
||
current_slots[slot_idx] = null
|
||
shop_refreshed.emit()
|
||
return spell
|
||
|
||
## 刷新商店,返回 true 表示成功
|
||
func reroll() -> bool:
|
||
var cost: int = get_reroll_cost()
|
||
if not PlayerStats.spend_gold(cost):
|
||
return false
|
||
reroll_count += 1
|
||
_rng.seed = _shop_seed + reroll_count * 31337
|
||
_refresh_slots()
|
||
return true
|
||
|
||
## 刷新费用公式:base + step * reroll_count(P6-N23)
|
||
func get_reroll_cost() -> int:
|
||
return REROLL_BASE_COST + reroll_count * REROLL_STEP
|
||
|
||
func close_shop() -> void:
|
||
current_slots.clear()
|
||
shop_closed.emit()
|
||
|
||
func get_shop_seed() -> int:
|
||
return _shop_seed
|
||
|
||
func reset() -> void:
|
||
current_slots.clear()
|
||
reroll_count = 0
|
||
_shop_seed = 0
|