職業打法食譜
高手的優勢大多來自幾十個「小習慣」。這一頁把常見的職業打法逐條落實到 SDK 程式碼上,每段都能直接貼進 on_tick。
約定:g 是 Game,home 是我方主基地(g.my_buildings({"htow", "hkee", "hcas"})[0]),now = g.clock()。API 細節見 API 目錄,完整可執行的範例在 範例 Bot。
要讓 LLM 加入某種打法時,把對應的那一招連同程式碼一起貼給它,比描述「打得職業一點」有效得多。
一、運營
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 自主迭代 裡的對局報告。