文档 玩法扩展

玩法模组

方案不只是一个替你打的 AI,也可以是一套规则:你自己在游戏窗口里玩,模组负责布置开局、刷怪、给奖励、在屏幕上给你按钮和选项卡、判胜负。继承 openwar3.Mod,一个文件就是一套玩法。

AI 方案 有两种:kind: bot 是一个 AI,替你打;kind: mod 是一套规则 —— 你自己在游戏窗口里玩,模组出题:开局怎么布置、按时间或事件刷怪、给什么奖励、屏幕上给你哪些按钮和选项卡、什么时候算赢。

模组用到的全是现成的能力:界面与输入(能点的按钮、卡片、热键、点地面)、画板(面板、进度条、路线)、JASS 通道(刷单位、改属性、给物品)、事件流(死亡、升级、放技能、聊天)。

两个示例

在远见的「AI 方案」→「内置」里就能选:

模组玩法用到的能力
英雄肉鸽 builtin/hero-roguelike你只有一个圣骑士,怪一波波从四面围上来;每升一级,屏幕中间三选一强化(选的时候游戏暂停);撑过 10 波就赢,英雄死了就输g.ui.choice(可点卡片 + 暂停)、hero.levelup / killed / spell.cast 事件、聊天 -help、JASS 改英雄属性、给物品
无尽守城 builtin/endless-defense怪从对面出生点沿地上的红线冲向主城;每守住一波给金子;点屏幕按钮或按 F7 提前叫下一波,奖励 ×1.5;按 F8 再左键点地面,放一座免费箭塔(右键取消)g.ui.button、g.ui.hotkey、g.ui.mouse(抓地面点击)、画板面板 / 进度条 / 路线、JASS 刷怪和加金子

两个示例各 150 行左右,代码在 brains/examples/mod_hero_roguelike.py 和 brains/examples/mod_endless_defense.py。

python tools/play.py --bot brains/examples/mod_hero_roguelike.py --inst 9     # 起一局,模组接管,你在游戏窗口里玩

写一个模组

from openwar3 import Mod

class Survive(Mod):
    name = "survive"

    def on_start(self, g):
        super().on_start(g)                        # 单人局检查 + 压住电脑对手
        self.foe = self.wave_player(g)             # 一个空槽玩家当「刷怪方」:和谁都不结盟、没有电脑 AI
        self.every(30, self.wave)                  # 每 30 游戏秒一波(暂停时不走)
        g.ui.hotkey("F7", lambda g, ev: self.wave(g))

    def wave(self, g):
        self.spawn_ring(g, self.foe, "ugho", 6, self.home(g), 1400, attack_to=self.home(g))

    def on_event(self, g, ev):
        if ev.kind == "unit.died" and ev.type == "htow":
            self.finish("loss", "主城被推了")

Mod 在 Bot 的基础上多了这些:

方法 / 属性说明
on_start / on_tick / on_event / on_end和 Bot 一样;覆盖 on_start / on_tick 时记得先调 super()
every(秒, fn, first=) / after(秒, fn)按游戏时间走的定时器,回调是 fn(g)
finish(result, reason)结束这一局('win' / 'loss' / 'unknown'):运行器下一拍停,屏幕中间画结果面板,方案战绩按它记
wave_player(g)第一个空槽玩家,拿来当刷怪方
spawn_ring(g, 玩家, 单位, 个数, 中心, 半径, attack_to=)在一圈上刷单位,一波几十个也不卡;返回 JASS 句柄
alive_of(g, 玩家) / attack_move_all(g, 玩家, 点)某个玩家的活单位 / 全部攻击移动过去(隔几秒调一次,怪就会追着走)
home(g) / hud(g, 标题, 行)我方主城的位置 / 右上角的信息面板
neutralize_ai = True开局把电脑对手压住:它的单位每 5 秒暂停一遍,金木清零。对战图里总有一个电脑,模组自己定规则时不要它搅局
single_player_only = True有别的真人玩家就拒绝运行(改世界的 JASS 会让别人不同步)
linger_s = 6分出胜负后,在结果画面停几秒再结束

finish() 在 Bot 上也能用:普通 Bot 也可以自己宣布结束。

做成方案、分享

scheme.json 里写 "kind": "mod",入口文件里定义一个 Mod 的子类:

{"id": "survive", "name": "坚守 10 波", "kind": "mod", "entry": "survive.py", "class": "Survive"}

模组固定不走公平模式(它是出题的裁判,要看全图、改世界),也不按对战规则判胜负(胜负由 finish 报);说明书里写了 fair / judge 也不起作用。导出 zip、导入、信任、战绩和 Bot 方案完全一样,见 AI 方案。模组也是代码,别人的模组第一次运行前同样要确认信任。

实测

2026-09-25,演练实例上:

  • 英雄肉鸽:第一波刷出来,右上角面板在走;把英雄提到 3 级 → 屏幕中间弹出卡片、游戏时钟停住;点两次卡片 → 两次强化生效(力量 22 → 27),时钟恢复。
  • 无尽守城:面板、地上的路线、按钮都在;F8 + 点地面 → 主城边上多了一座防御塔;这一波还没清完就点按钮 → 提示「这一波还没清完」。

边界

  • 只能单人局:刷单位、改属性走 JASS 通道,多人局里会不同步。这是锁步模型决定的,多人玩法要等同步通道(见 路线图)。
  • 模组看全图 —— 它是出题的,不是玩家。
  • 对战图里的电脑对手只是被「压住」,没有被移除(移除会触发对战规则的胜利判定)。