文档 指南
职业打法食谱
高手的优势大多来自几十个「小习惯」。这一页把常见的职业打法逐条落到 SDK 代码上,每段都能直接抄进 on_tick。
约定:g 是 Game,home 是我方主基地(g.my_buildings({"htow", "hkee", "hcas"})[0]),now = g.clock()。接口细节见 接口目录,完整可跑的例子在 示例 Bot。
让大模型加某种打法时,把对应那一招连同代码一起贴给它,比描述「打得职业一点」有效得多。
一、运营
1. 农民永不空闲、一矿 5 人
for w in g.idle_workers(): # 只派空闲的(有活的重下会打断采集)
mine = g.nearest([m for m in g.gold_mines() if crew[m.addr] < 5], w)
g.gather(w, mine) if mine else g.gather(w, g.trees(w.x, w.y, limit=1)[0])
自己记每座矿派了几个(crew):进了金矿的工人不在快照里。整例见 hello_bot.py。
2. 队列只排 1 个,钱不锁死
for b in g.my_buildings({"hbar"}):
if not g.queue(b): # 空了才排下一个
g.train(b, "hfoo")
3. 人口永远不卡
stuck = any(p.blocked for _b, p in g.all_production("me")) # 有排队但没开始 = 人口不够
res = g.resources()
if stuck or res["food_cap"] - res["food_used"] <= 6:
g.build_near(builder, "hhou", home.x, home.y)
blocked 比「快满了」早一步:打仗掉了一片兵、再补兵时队列一卡就知道。
4. 建造顺序 + 盖完自己回矿(Shift 回矿)
spot = g.build_near(w, "hbar", home.x, home.y)
if spot:
g.gather(w, mine, queue="after") # 盖完回去采矿,不用下一拍再找它
一个农民连盖几座:g.build_queue(w, [("hhou", x1, y1), ("hhou", x2, y2)])。钱在开工时才扣。
5. 升本时机、攻防升级
if not g.queue(hall) and g.can_do(hall, "hkee") in (0, 220): # 大厅队列空了才能升(否则 185)
g.upgrade(hall, "hkee")
p = g.production(hall) # 升本进度
if p and p.kind == "upgrade":
print(f"主城还要 {p.remaining:.0f} 秒")
for sm in g.my_buildings({"hbla"}):
if not g.queue(sm):
ok = [u for u, v in zip(UPS, g.can_do_many([(sm, u) for u in UPS])) if v in (0, 220)]
if ok:
g.research(sm, ok[0])
6. 开分矿:按走路距离选最近的矿
mines = [m for m in g.gold_mines() if g.dist(m, home) > 1500 and not taken(m)]
best = min(mines, key=lambda m: g.path_distance(home, m) or 1e9) # 岛上的矿返回 None -> 排到最后
二、侦察与信息
7. 看对手在干嘛
for b, p in g.all_production("enemy"): # 看得见的对手建筑在练什么 / 研究什么 / 升什么
print(b.type, p.kind, p.queue, f"{p.progress:.0%}" if p.progress is not None else "卡住")
配合事件:ev.kind == "production.done" and ev.owner != g.me() —— 对手刚出了什么。
8. 记住看到过的东西(战争迷雾)
for u, t, age in g.last_seen(max_age=60): # 60 游戏秒内看到过的敌人(最后的位置和血量)
...
hero_seen = [r for r in g.last_seen() if r[0].is_hero] # 对面英雄上次在哪
公平模式下这是你唯一的对手信息来源,和人类玩家一样。
9. 电脑对手要打哪(只对电脑 AI 有效)
plan = g.enemy_ai_plan(some_enemy_soldier) # 它的电脑队长要去的地方
电脑出门前就定好了目标点 —— 提前把兵带回那里。
三、打野
10. 夜里打野
if g.is_night(): # 18 点 ~ 6 点:野怪睡觉(先手不被围)、所有人视野变短
...
wait = g.seconds_until(18) # 离天黑还有几游戏秒(一天 480 秒)
11. 只打打得过的点
from openwar3 import combat
mine = [g.stats(u) for u in army]
def ttk(target): return combat.time_to_kill(mine, g.stats(target), target_hp=target.hp) or 1e9
camp = [c for c in g.creeps() if g.dist(c, center) < 600]
ours = max(ttk(c) for c in camp) # 打光这个点要多久(粗算)
theirs = g.time_to_kill(camp, weakest_of_mine) or 1e9 # 它们打死我方最弱的要多久
if ours < theirs and g.reachable(center, camp[0]):
g.attack_move(army, camp[0].x, camp[0].y)
整例:micro_bot.py 的 _maybe_creep。
四、微操
12. 集火:打「最快能打死的」,不是最近的
target = min(visible_enemies, key=lambda e: g.time_to_kill(fighters, e) or 1e9)
g.attack([u for u in fighters if (g.current_target(u) or target).handle != target.handle], target)
只给「没在打它」的人下令(current_target),别打断已经在打的。
13. 拉残血
for u in army:
if u.hp < u.hp_max * 0.35:
g.move(u, *toward(home, u, 500)) # 往家的方向退 500;3 秒内别重复拉
被集火的判断:damage 事件里同一个单位短时间内来自多个来源 = 被围了。
14. 英雄保命、别送经验
for h in g.my_heroes():
if h.hp < h.hp_max * 0.4:
g.move(h, home.x, home.y)
g.use_item(h, slot_of(h, "phea")) # 血瓶:inventory(h) 找格号
15. 克制:让对的兵打对的目标
s = g.stats(u)
best = max(enemies, key=lambda e: s.dps_vs(g.stats(e))) # 火枪打狮鹫(穿刺打小甲 ×2)、狮鹫打步兵(魔法打大甲 ×2)
克制表来自游戏数据:combat.damage_multiplier("pierce", "small") == 2.0。
16. 包夹与路径:绕过塔走
route = g.walk_path(army_center, target) # 地面最短路的拐点
g.path(army, route, attack=True) # 按顺序攻击移动过每个点
要绕开塔:在寻路网格上把塔周围标成不能走再算:
grid = g.grid().copy()
for t in towers:
grid.block_area(t.x, t.y, 800) # 塔射程 700 + 余量
route = grid.path((army_x, army_y), (target.x, target.y))
17. 一拍的命令一批发
with g.batch():
g.attack(melee, target_a)
g.attack(ranged, target_b)
g.move(wounded, *home_xy)
g.cast(hero, "thunderclap")
几十条命令只等一次游戏线程(实测 8 条移动 68 ms → 6.5 ms)。
18. 攻城:炮打地面
g.attack_ground(mortars, tower.x, tower.y) # 迫击炮 / 投石车对一块地方开火(树林后面、隐形单位)
五、英雄
19. 加点表
SKILLS = {"Hamg": ["AHwe", "AHbz", "AHwe", "AHbz", "AHwe", "AHmt"]} # 水元素、暴风雪……6 级大招群体传送
info = g.hero_info(h)
if info and info["skill_points"]:
g.learn(h, SKILLS[h.type][learned_count]) # 被拒(等级不够学大招)就等下一级
20. 技能放没放出来
r = g.cast(h, "thunderbolt", target=enemy_hero)
# 下一拍:
if g.cooldown(h, "AHtb"): # 进冷却 = 真放出去了;接下 ≠ 放出
...
21. 买药、回城
g.buy(shop, "phea") # 英雄站在商店旁边
g.use_item(hero, slot, x=home.x, y=home.y) # 回城卷轴(对点用物品)
六、复盘
- 每拍把决策写进日志(
print会进运行窗口),配合g.say(单位, "撤")在游戏里看; production.done事件带「用了多少秒」—— 统计自己的建造时间线(第几秒出第一个英雄、第几秒升本),和高手的对比;- 让 Agent 自己复盘:见 Agent 自主迭代 里的对局报告。