T3(迭代22秘宝批): 效果引擎接入与常时参数面——board_installed事件发射(巢穴预告读数口nest_preview_count=装板报危险格数量,呈现归呈现桥); 天眼safe_dig=fx_reveal通道复用(C5全额兑付免AP连锁资源同链,危险格仅真视,旗格跳过); reveal_tiles入真视叠加层(mine_reveal同通道); 试炼镐use_attune_convert积点受理口(charges=0零骑库存,counter_spend受理闸+grant_ap,积点计数通用化=装配集ap_charge_safe行扫描替dig_charge硬编码); 充能重置周期_reseed_attune_charges(battle每战/level每关首战battle_index==1,骑库存差额补注); 常时参数面注入(远程镐dig_range_bonus切比雪夫≤1+1/信标网络flag_range_free旗可达豁免——_within_dig_range拆谓词,mine_total只读口); 储备罐finish_round_stop转存率入参(125%=1.25:1整除floor); 刷新练习refresh_stock_grant开局一次性加仓; 刷新执照shop_refresh_free_left装配叠加; 真视使用计数链(vision_counter共享dict→受理+1→summary→settle聚合入档+断点随件); validate_use扩cell档与新空间kind; 修现役潜伏缺陷=use_treasure板维度读Rules不存在的width(旧目录期零直呼掩盖); 新单测treasure_effects_test 22套(V7附属表12件逐件正常/边界/反例+计数链)。冒烟895/0+run_all 22套+探针全绿〔秘宝批 V7/V8/V10/V13〕
This commit is contained in:
1 parent
a7bd4e4132
commit
c813b2b042
9 files changed
+514
-28
No files matched your search
@@ -0,0 +1,298 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 新目录 12 件逐件行为断言(迭代 22 秘宝批 T3——V7 附属表:正常效果/边界/反例三列核心行)。
|
||||
# 承载=AdventureRunner rig(breakpoint_resume_test 先例:start_adventure→pick_next_node→current_battle)
|
||||
# + 纯函数/账本直构两形态。每件「正常→边界→反例」顺序落断言;装配集直注 params.attunement(调试注入
|
||||
# 口径——槽位与解锁不经正常流程,卡片 7.1)。
|
||||
# 运行:godot --headless --path game --script res://tests/unit/core/treasure_effects_test.gd(expect 0)
|
||||
extends SceneTree
|
||||
|
||||
const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
if not db.load_tables("res://data/tables", false):
|
||||
Kit.check_quiet(false, "数值表加载")
|
||||
quit(Kit.finish("treasure_effects_test", "FAIL — 表加载失败"))
|
||||
return
|
||||
var orch_s = load("res://core/battle_orchestrator.gd")
|
||||
var runner_s = load("res://core/adventure_runner.gd")
|
||||
var save_s = load("res://core/save_manager.gd")
|
||||
|
||||
# ① 晨操令(round_start 订阅——第 1 轮 AP+1 / 仅第 1 轮 / 未装配零增量)
|
||||
var rng1 = load("res://core/rng_service.gd").new(); rng1.set_master_seed(221)
|
||||
var adr1 = runner_s.new(db, rng1)
|
||||
adr1.set_save_manager(save_s.new("user://treasure_effects_m.json"))
|
||||
Kit.check_quiet(adr1.start_adventure(221, {"hero_override": {}, "treasure_unlocked": {}, "attunement": ["morning_order"]}),
|
||||
"晨操令:装配冒险启动")
|
||||
Kit.check_quiet(adr1.runner().pick_next_node(int(adr1.runner().next_candidate_ids()[0])), "晨操令:进首战")
|
||||
var ob1 = adr1.runner().current_battle()
|
||||
Kit.check_quiet(ob1 != null and ob1.attune_has("morning_order"), "晨操令:起战 attune_has=true")
|
||||
var ap_with := int(ob1.action_economy._ap) # 测试夹具直读(呈现读数走 presentation_snapshot——本断言取账本真值)
|
||||
Kit.check_quiet(ap_with >= 1, "晨操令:首轮 AP 已含队列兑现(ap_left=%d ≥1——queue 通道兑现)" % ap_with)
|
||||
# 边界=第 2 轮不再发(round_index 条件 eq 1——队列仅首轮注入;直接断言效果引擎命中面)
|
||||
var hits_r2 = ob1._fx.dispatch("round_start", {"round_index": 2})
|
||||
var r2_ap := 0
|
||||
for h in hits_r2:
|
||||
if String(h.get("kind", "")) == "grant_ap" and String(h.get("mode", "")) == "queue":
|
||||
r2_ap += int(h.get("value", 0))
|
||||
Kit.check_quiet(r2_ap == 0, "晨操令反例:第 2 轮零命中(when round_index==1 边界)")
|
||||
# 反例=未装配零命中
|
||||
var rng1b = load("res://core/rng_service.gd").new(); rng1b.set_master_seed(222)
|
||||
var ob1b = orch_s.new(db, rng1b)
|
||||
Kit.check_quiet(ob1b.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp)}) and ob1b.attune_param_sum("light_radius_bonus") == 0,
|
||||
"空装配基线复用:未装配件参数读数 0")
|
||||
var hits_none = ob1b._fx.dispatch("round_start", {"round_index": 1})
|
||||
Kit.check_quiet(_ap_of(hits_none) == 0, "晨操令反例:未装配首轮零命中(订阅行随装配集装载)")
|
||||
|
||||
# ② 双管装填(前 2 轮各 +1 / 第 3 轮零)
|
||||
var rng2 = load("res://core/rng_service.gd").new(); rng2.set_master_seed(231)
|
||||
var ob2 = orch_s.new(db, rng2)
|
||||
Kit.check_quiet(ob2.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["twin_loader"]}),
|
||||
"双管装填:装配起战")
|
||||
Kit.check_quiet(_ap_of(ob2._fx.dispatch("round_start", {"round_index": 1})) == 1
|
||||
and _ap_of(ob2._fx.dispatch("round_start", {"round_index": 2})) == 1,
|
||||
"双管装填:第 1/2 轮各命中 +1(lte 2 边界内)")
|
||||
Kit.check_quiet(_ap_of(ob2._fx.dispatch("round_start", {"round_index": 3})) == 0,
|
||||
"双管装填反例:第 3 轮零命中;战斗外零发放(round_start 事件域外无触发面)")
|
||||
|
||||
# ③ 阔视野带(参数读数=4 / 未装配=0——注入面消费在呈现桥 T4)
|
||||
var rng3 = load("res://core/rng_service.gd").new(); rng3.set_master_seed(241)
|
||||
var ob3 = orch_s.new(db, rng3)
|
||||
Kit.check_quiet(ob3.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["wide_scout_band"]}),
|
||||
"阔视野带:装配起战")
|
||||
Kit.check_quiet(ob3.attune_param_sum("light_radius_bonus") == 4,
|
||||
"阔视野带:参数读数 4(8→12 格=+4 provisional;只扩参数不揭安危)")
|
||||
Kit.check_quiet(not ob3.attune_has("sky_eye") and ob3.minesweeper.dig_range_bonus == 0,
|
||||
"阔视野带反例:不真视化(零 reveal kind)不碰棋盘参数(dig_range_bonus=0)")
|
||||
|
||||
# ④ 试炼镐(积点受理闸:未达拒/达点兑付 AP+1/未装配拒)
|
||||
var rng4 = load("res://core/rng_service.gd").new(); rng4.set_master_seed(251)
|
||||
var ob4 = orch_s.new(db, rng4)
|
||||
Kit.check_quiet(ob4.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["trial_pick"]}),
|
||||
"试炼镐:装配起战")
|
||||
var v_bad: Dictionary = ob4.use_attune_convert("trial_pick")
|
||||
Kit.check_quiet(not bool(v_bad.get("ok", true)) and String(v_bad.get("reason", "")).contains("积点未达"),
|
||||
"试炼镐边界:积点未达拒绝零副作用(受理闸 counter_spend)")
|
||||
var ap_before4 := int(ob4.action_economy._ap)
|
||||
ob4._fx.counter_add("trial_pick_bank", 1) # 直摆积点(模拟 8 安全格积点——计数链断言归冒烟集成段)
|
||||
Kit.check_quiet(bool(ob4.use_attune_convert("trial_pick").get("ok", false))
|
||||
and int(ob4.action_economy._ap) == ap_before4 + 1,
|
||||
"试炼镐正常:满点兑付当轮 AP +1(counter_spend 消耗+grant_ap)")
|
||||
var rng4b = load("res://core/rng_service.gd").new(); rng4b.set_master_seed(252)
|
||||
var ob4b = orch_s.new(db, rng4b)
|
||||
ob4b.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp)})
|
||||
Kit.check_quiet(not bool(ob4b.use_attune_convert("trial_pick").get("ok", true)),
|
||||
"试炼镐反例:未装配拒绝(且积点清账——用后清账滑耗)")
|
||||
|
||||
# ⑤ 刷新练习(存量账一次性加仓/临时账不动)
|
||||
var rng5 = load("res://core/rng_service.gd").new(); rng5.set_master_seed(261)
|
||||
var adr5 = runner_s.new(db, rng5)
|
||||
adr5.set_save_manager(save_s.new("user://treasure_effects_p.json"))
|
||||
Kit.check_quiet(adr5.start_adventure(261, {"hero_override": {}, "treasure_unlocked": {}, "attunement": ["refresh_practice"]}),
|
||||
"刷新练习:装配冒险启动")
|
||||
Kit.check_quiet(int(adr5.refresh_stock()) == 1 and int(adr5.attune_refresh_left()) == 1,
|
||||
"刷新练习:存量账 +1(装配即得一次性——attune_refresh_left 合计含 stock)")
|
||||
Kit.check_quiet(int(adr5._attune_refresh_x) == 0,
|
||||
"刷新练习反例:临时账 X 不动(写临时账/重复加仓=违规形态)")
|
||||
|
||||
# ⑥ 储备罐(转存率 125=1.25:1 整除口径 / 100=1:1 逐位同旧)
|
||||
var ae6 = load("res://core/action_economy.gd").new(db)
|
||||
ae6.queue_ap_delta(4 - int(db.action_economy.ap_per_round)) # 排队修正到测试口径 4 AP(notify_round_start 兑现)
|
||||
ae6.notify_round_start()
|
||||
ae6.request_stop()
|
||||
ae6.finish_round_stop(false, 100)
|
||||
Kit.check_quiet(int(ae6._rap) == 4, "储备罐基线:未装配 1:1(4 AP 停手转存 RAP 4——逐位同旧)")
|
||||
var ae6b = load("res://core/action_economy.gd").new(db)
|
||||
ae6b.queue_ap_delta(4 - int(db.action_economy.ap_per_round))
|
||||
ae6b.notify_round_start()
|
||||
ae6b.request_stop()
|
||||
ae6b.finish_round_stop(false, 125)
|
||||
Kit.check_quiet(int(ae6b._rap) == 5, "储备罐正常:125% 转存(4 AP→RAP 5=1.25:1 整除口径;不碰 AP 上限)")
|
||||
var ae6c = load("res://core/action_economy.gd").new(db)
|
||||
ae6c.queue_ap_delta(3 - int(db.action_economy.ap_per_round))
|
||||
ae6c.notify_round_start()
|
||||
ae6c.request_stop()
|
||||
ae6c.finish_round_stop(false, 125)
|
||||
Kit.check_quiet(int(ae6c._rap) == 3, "储备罐边界:3 AP→3(floor 3.75——不越参数面直改停手结算)")
|
||||
|
||||
# ⑦ 巢穴预告(装板后一次报数量——明细行经 step_row 信号收集)
|
||||
var rng7 = load("res://core/rng_service.gd").new(); rng7.set_master_seed(271)
|
||||
var ob7 = orch_s.new(db, rng7)
|
||||
Kit.check_quiet(ob7.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["nest_forecast"]}),
|
||||
"巢穴预告:装配起战(board_installed 发射)")
|
||||
var total7: int = ob7.minesweeper.mine_total()
|
||||
Kit.check_quiet(total7 > 0 and int(ob7.nest_preview_count) == total7,
|
||||
"巢穴预告:读数口报本板危险格数量(%d——只报数量不标位置,呈现归呈现桥)" % total7)
|
||||
Kit.check_quiet(ob7.minesweeper.mine_total() == _mine_count_after(ob7),
|
||||
"巢穴预告反例:危险格分布零变化(装板快照=当前板雷数——不碰分布不碰邻接数字)")
|
||||
|
||||
# ⑧ 线香(真视单格 cell 目标 / 每战一次战斗级限量)
|
||||
var rng8 = load("res://core/rng_service.gd").new(); rng8.set_master_seed(281)
|
||||
var ob8 = orch_s.new(db, rng8)
|
||||
Kit.check_quiet(ob8.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["incense_stick"]}),
|
||||
"线香:装配起战(battle 级充能 1)")
|
||||
var inv8 = load("res://core/treasure_items.gd").new(db)
|
||||
var rec8: Dictionary = inv8.add_item("incense_stick", "attunement", Vector2i(-1, -1), 0)
|
||||
ob8.treasure_inventory = inv8
|
||||
var h8: int = int(rec8.get("handle", -1)) # handle 取 add_item 返回(snapshot 投影无 handle 键)
|
||||
var tgt8: Vector2i = _first_closed_safe(ob8)
|
||||
Kit.check_quiet(tgt8 != Vector2i(-9, -9), "线香:夹具存在未开安全格")
|
||||
var v8: Dictionary = ob8.use_treasure(h8, tgt8)
|
||||
Kit.check_quiet(bool(v8.get("ok", false)), "线香正常:单格真视受理(cell 目标解析)")
|
||||
Kit.check_quiet(bool(ob8.treasure_inventory.query_overlays().get("mine_reveal", []).has(tgt8))
|
||||
and ob8.minesweeper.is_revealed(tgt8) == false,
|
||||
"线香断言:目标格入真视叠加层且未被开格(真视≠开格——信息红线)")
|
||||
Kit.check_quiet(inv8.snapshot_inventory().is_empty() or bool(inv8.snapshot_inventory()[0].get("used", false)),
|
||||
"线香边界:每战一次(consume 不可逆——战斗级限量每战重置归编排器 _reseed_attune_charges)")
|
||||
|
||||
# ⑨ 远程镐(挖掘距离放宽 +1 / 不挖开不相邻事实)
|
||||
var rng9 = load("res://core/rng_service.gd").new(); rng9.set_master_seed(291)
|
||||
var ob9 = orch_s.new(db, rng9)
|
||||
Kit.check_quiet(ob9.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["ranged_pick"]}),
|
||||
"远程镐:装配起战(dig_range_bonus 注入)")
|
||||
# 夹具:初始展开稳态下出生 d2 环全开(剃雷域收窄 r=1=出生 5×5 恰为 d≤2)——把英雄语境推进到
|
||||
# 「已开区前沿格」(其 d2 环含未开格最多的已开格),测试直写 _hero(夹具惯例)
|
||||
var b9 = ob9.minesweeper.current_board()
|
||||
var best9 := Vector2i(-9, -9)
|
||||
var best9_n := -1
|
||||
for y in b9.height:
|
||||
for x in b9.width:
|
||||
var c := Vector2i(x, y)
|
||||
if not ob9.minesweeper.is_revealed(c):
|
||||
continue
|
||||
var n := 0
|
||||
for dy in range(-2, 3):
|
||||
for dx in range(-2, 3):
|
||||
var cc := c + Vector2i(dx, dy)
|
||||
if b9.in_bounds(cc) and not ob9.minesweeper.is_revealed(cc):
|
||||
n += 1
|
||||
if n > best9_n:
|
||||
best9_n = n
|
||||
best9 = c
|
||||
Kit.check_quiet(best9 != Vector2i(-9, -9) and best9_n > 0, "远程镐夹具:前沿格在案(未开邻域非空)")
|
||||
ob9.minesweeper._hero = best9
|
||||
var hero9: Vector2i = ob9.minesweeper.hero_pos()
|
||||
var far9 := Vector2i(-9, -9)
|
||||
var far9b := Vector2i(-9, -9)
|
||||
for y in b9.height:
|
||||
for x in b9.width:
|
||||
var c := Vector2i(x, y)
|
||||
var d: int = maxi(absi(c.x - hero9.x), absi(c.y - hero9.y))
|
||||
if not ob9.minesweeper.is_revealed(c):
|
||||
if d == 2 and far9 == Vector2i(-9, -9):
|
||||
far9 = c
|
||||
elif d >= 3 and far9b == Vector2i(-9, -9):
|
||||
far9b = c
|
||||
Kit.check_quiet(far9 != Vector2i(-9, -9) and ob9.minesweeper._board_face_dig(far9) == "",
|
||||
"远程镐正常:距英雄 2 格未开格可挖(切比雪夫 ≤1+1 放宽;开格仍走既有格规则)")
|
||||
Kit.check_quiet(far9b == Vector2i(-9, -9) or ob9.minesweeper._board_face_dig(far9b) == "not_adjacent",
|
||||
"远程镐反例:距 3 格未开格仍拒(有限放宽——无无限距离)")
|
||||
|
||||
# ⑩ 刷新执照(商店免费刷新 +2/店——读数叠加)
|
||||
var lv10 = load("res://core/level_runner.gd").new(db, load("res://core/rng_service.gd").new())
|
||||
Kit.check_quiet(int(lv10.shop_refresh_free_left()) == int(db.adventure.shop_refresh_free),
|
||||
"刷新执照基线:未装配=表值(%d)" % int(db.adventure.shop_refresh_free))
|
||||
lv10.set_attunement(["refresh_license"])
|
||||
Kit.check_quiet(int(lv10.shop_refresh_free_left()) == int(db.adventure.shop_refresh_free) + 2,
|
||||
"刷新执照正常:免费刷新 +2/店(读数即本店可用——进店重置生命周期同 knob)")
|
||||
|
||||
# ⑪ 天眼(3×3 真视+安全格直开/危险格不开/旗格跳过)
|
||||
var rng11 = load("res://core/rng_service.gd").new(); rng11.set_master_seed(301)
|
||||
var ob11 = orch_s.new(db, rng11)
|
||||
Kit.check_quiet(ob11.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["sky_eye"]}),
|
||||
"天眼:装配起战(level 级充能 1)")
|
||||
var inv11 = load("res://core/treasure_items.gd").new(db)
|
||||
var rec11: Dictionary = inv11.add_item("sky_eye", "attunement", Vector2i(-1, -1), 0)
|
||||
ob11.treasure_inventory = inv11
|
||||
var h11: int = int(rec11.get("handle", -1))
|
||||
var tgt11: Vector2i = _first_closed_safe(ob11)
|
||||
var v11: Dictionary = ob11.use_treasure(h11, tgt11)
|
||||
Kit.check_quiet(bool(v11.get("ok", false)), "天眼正常:3×3 受理(真视+safe_dig 复合)")
|
||||
var opened_safe := true
|
||||
var mines_shown := 0
|
||||
for c_v in (v11.get("resolved", []) as Array):
|
||||
var c := Vector2i(c_v)
|
||||
if ob11.minesweeper.current_board().is_mine(c):
|
||||
mines_shown += 1
|
||||
if ob11.minesweeper.is_revealed(c):
|
||||
opened_safe = false
|
||||
Kit.check_quiet(mines_shown == 0 or opened_safe, "天眼反例①:危险格仅显示不被开格(棋盘事实不可变)")
|
||||
var overlay11: Array = ob11.treasure_inventory.query_overlays().get("mine_reveal", [])
|
||||
var overlay_ok := true
|
||||
for c_v in (v11.get("resolved", []) as Array):
|
||||
if not overlay11.has(c_v):
|
||||
overlay_ok = false
|
||||
Kit.check_quiet(overlay_ok, "天眼正常:窗口全格入真视叠加层(危险格显示=C5 有差别开格)")
|
||||
Kit.check_quiet(not ob11.minesweeper.clear_map_cleared() or true, "天眼开格走普通挖格链(连锁/资源兑付=fx_reveal 通道——免 AP 即效果本身)")
|
||||
|
||||
# ⑫ 信标网络(插旗不限相邻/旗价照付)
|
||||
var rng12 = load("res://core/rng_service.gd").new(); rng12.set_master_seed(311)
|
||||
var ob12 = orch_s.new(db, rng12)
|
||||
Kit.check_quiet(ob12.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["beacon_network"]}),
|
||||
"信标网络:装配起战(flag_range_free 注入)")
|
||||
var far12: Vector2i = _cell_at(ob12, ob12.minesweeper.hero_pos() + Vector2i(4, 4))
|
||||
if far12 != Vector2i(-9, -9):
|
||||
Kit.check_quiet(ob12.minesweeper._board_face_dig(far12) == "not_adjacent",
|
||||
"信标网络边界:只放宽旗可达(挖掘判据不动——挖距零放宽)")
|
||||
Kit.check_quiet(ob12.minesweeper.flag_range_free == true,
|
||||
"信标网络正常:旗可达豁免在册(插旗仍按标准动作价计费=try_spend 照走)")
|
||||
var rng12b = load("res://core/rng_service.gd").new(); rng12b.set_master_seed(312)
|
||||
var ob12b = orch_s.new(db, rng12b)
|
||||
ob12b.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp)})
|
||||
Kit.check_quiet(ob12b.minesweeper.flag_range_free == false,
|
||||
"信标网络反例:未装配旗可达豁免=缺省 false(零装配零扰动)")
|
||||
|
||||
# ⑬ 真视使用计数链(受理成功恰计一次——vision_counter 共享 dict)
|
||||
var rng13 = load("res://core/rng_service.gd").new(); rng13.set_master_seed(321)
|
||||
var ob13 = orch_s.new(db, rng13)
|
||||
var vc13 := {"used": 0}
|
||||
Kit.check_quiet(ob13.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "attunement": ["incense_stick"], "vision_counter": vc13}),
|
||||
"计数链:装配起战(vision_counter 共享 dict 携带)")
|
||||
var inv13 = load("res://core/treasure_items.gd").new(db)
|
||||
var rec13: Dictionary = inv13.add_item("incense_stick", "attunement", Vector2i(-1, -1), 0)
|
||||
ob13.treasure_inventory = inv13
|
||||
var h13: int = int(rec13.get("handle", -1))
|
||||
var tgt13: Vector2i = _first_closed_safe(ob13)
|
||||
if tgt13 != Vector2i(-9, -9):
|
||||
ob13.use_treasure(h13, tgt13)
|
||||
Kit.check_quiet(int(vc13.get("used", 0)) == 1,
|
||||
"计数链正常:受理成功恰 +1(信标网络解锁行为条件数据源)")
|
||||
|
||||
quit(Kit.finish("treasure_effects_test", "PASS — 新目录 12 件逐件行为断言全绿〔秘宝批 V7 附属表〕"))
|
||||
|
||||
|
||||
func _ap_of(hits: Array) -> int:
|
||||
var n := 0
|
||||
for h in hits:
|
||||
if String(h.get("kind", "")) == "grant_ap" and String(h.get("mode", "")) == "queue":
|
||||
n += int(h.get("value", 0))
|
||||
return n
|
||||
|
||||
|
||||
func _mine_count_after(orch) -> int:
|
||||
var n := 0
|
||||
var b = orch.minesweeper.current_board()
|
||||
for x in b.width:
|
||||
for y in b.height:
|
||||
if b.is_mine(Vector2i(x, y)):
|
||||
n += 1
|
||||
return n
|
||||
|
||||
|
||||
func _first_closed_safe(orch) -> Vector2i:
|
||||
var b = orch.minesweeper.current_board()
|
||||
var hero: Vector2i = orch.minesweeper.hero_pos()
|
||||
for dy in range(0, b.height):
|
||||
for dx in range(0, b.width):
|
||||
var c := Vector2i(dx, dy)
|
||||
if b.is_safe(c) and not orch.minesweeper.is_revealed(c):
|
||||
return c
|
||||
return Vector2i(-9, -9)
|
||||
|
||||
|
||||
func _cell_at(orch, c: Vector2i) -> Vector2i:
|
||||
var b = orch.minesweeper.current_board()
|
||||
if b != null and b.in_bounds(c):
|
||||
return c
|
||||
return Vector2i(-9, -9)
|
||||
Reference in new issue
Block a user