##EasyReadMore##

2009年12月11日 星期五

HOW TO MAKE A CAMPAIGN AI.








HOW TO MAKE A CAMPAIGN AI.
By Moyack

原文地址http://wc3campaigns.net/showthread.php?t=87999#intro

翻譯:[wow8]龍小天
文章貼在 http://bbs.wow8.org/viewthread.php?tid=21746&extra=page%3D1%26amp%3Bfilter%3Dtype%26amp%3Btypeid%3D52

介紹
這個手冊主要目的是向大家介紹下發展中的簡單AI,遊戲中一個具有攻擊力的玩家要遵循一個順序,攻擊順序,建築順序,升級順序.

AI的類型:
在開始之前,我先要和大家澄清下所謂的AI分兩種:戰役AI和標準AI。戰役AI是我們能做到的最簡單的一種AI,因為它遵循一個嚴格的可預見的一個特性。但是標準AI主要是模擬人類的特點,,所以會有更大的隨機性。有時候更具有侵略性,許多時候很難調試。(debug)
所以如果我們開始學習JASS AI,推薦大家從戰役AI開始,因為它容易調試。(debug)

需要的工具:
首先WE是肯定需要的,記事本也是必不可少的。
另外還強烈推薦JASSCRAFT,和JASS SHOP PRO
http://www.wow8.org/bbs/viewthread.php?tid=16400&extra=page%3D2 JASS助手
http://www.wow8.org/bbs/viewthread.php?tid=10248&extra=page%3D3 JassCraft簡體中文漢化版1.12

http://www.wow8.org/bbs/viewthread.php?tid=20537&extra=page%3D3 JassShopPro簡體中文版

什麼是JASS AI?
JASS AI是暴雪用來編寫AI程序的一種計算機語言。JASS AI是我們普通所說的JASS的一個關聯。所以如果你懂JASS,那你會更加懂JASS AI了。
AI的主要命令包含在war3.mpq和war3x.mpq pack的common.ai文件中。當然你還可以用common.j中的命令。但是你會發現有些命令在JASS AI scrip中並不運行。唯一的解決辦法就是多加練習了。

正題
講了這麼,現在就讓我們開始學AI吧
打開JASSCRAFT 或者 JASS SHOP PRO和一個新的文件。在寫程序之前,我們必須知道這些代碼是怎麼放置的。下邊是個例子:


globals

// 這個放全局變量

endglobals

function blabla takes blabla returns blabla

// 自定義函數

endfunction

...

function main takes nothing returns nothing

//主程序在這

Endfunction
複製代碼對於新手來說,申明全局變量我們要把代碼寫在全局變量那部分
然後把自定義功能,將用來在腳本和功能上稱為主體,並在遊戲中執行。
在這些定義下,我們可以把用這些腳本來實現我們的工作。首先我們開始在全局中定義一個全局變量。這個變量就是在遊戲中被AI攻擊的玩家.我們命名為MyVictim。

globals

player MyVictim = Player(0) // 這個是紅色玩家一

endglobals
複製代碼
現在我們創建主函數:
主函數

function main takes nothing returns nothing

call CampaignAI( , null )

endfunction
複製代碼


其中CampaignAI的作用是初始化並且使你的戰役地圖裡具有AI功能
這個函數具有兩個變量。farm unitID 負責定義食物的提供者。Hero代碼被引用與當技能獲得升級的時候管理該英雄技能的函數。這個設置我們將會在後邊討論。現在暫時把變量設置為空值null。


現在我們開始設置一些變量在AI裡面,戰役AI系統具有一些默認的特點

◆ 它們不給予英雄的攻擊優先權
◆ 單位不會逃跑
◆ 農民僅僅在瘋狂的模式下修理建築
◆ 採集資源非常的慢(每個農民一次只能採集一個金幣一個木頭)


之所有會有這些特點是因為在戰役地圖你們需要AI玩家一直存活直到被破壞。所以AI就模擬採集,而你利用觸發控制AI的資源。單位不能逃跑,是因為這個AI針對的是困難的或者瘋狂的玩家。

如果你需要改變這些特點,你需要武裝他們利用一些AI函數。列出如下:
基礎設置函數:
‧ SetTargetHeroes(Boolean): 給予英雄優先權
‧ SetUnitsFlee(Boolean): 如果單位受傷嚴重會自行撤退
‧ SetHeroesFlee(Boolean): 同上但是用與英雄
‧ SetGroupsFlee(Boolean): 這個用與單位組,不推薦使用
‧ SetSlowChopping(Boolean): 農民採集很少的資源
‧ SetPeonsRepair(Boolean): 農民會修復損壞的機械單位
‧ SetHeroesBuyItems(Boolean):讓英雄自己買賣物品在自己的種族商店.
‧ SetHeroesTakeItems(Boolean): 讓英雄扔掉物品。

為了測試,還需要在主函數中增加一些變量。
創建主函數:
function main takes nothing returns nothing

call CampaignAI( MOON_WELL, null ) // 個人比較喜歡NE,

// 所以這個AI用NE

call SetSlowChopping( false ) //AI會有標準的資源

call SetPeonsRepair( true ) //AI會自行修復建築

endfunction
複製代碼注意:
你會注意到其中的call CampaignAI( MOON_WELL, null )我們設置這個名字來代替原有單位的名稱。(rawcode)所有魔獸戰役單位會用這個固定的名稱。如果你想創建自己的自定義種族的話可以使用這個rawcode。這個函數可以用下邊的方式寫:
call CampaignAI( 'emow', null )
這個是完全等價的。在整個手冊中我會固定的使用該名稱,讓大家更容易懂。
如何獲得單位,技能,buff,升級等代碼?很容易,打開編輯器WE,按CTRL+D,你會看到所有單位,技能等代碼。想還原的話重複該動作。

如果你希望你的設置更加有組織一點,我們可以創建新的自定義函數。也就是上邊講的主函數。
主函數:

function ConfigureAI takes nothing returns nothing

call SetSlowChopping( false )

call SetPeonsRepair( true )

endfunction

function main takes nothing returns nothing

call CampaignAI( MOON_WELL, null )

call ConfigureAI( )

endfunction
複製代碼

Building Strategy建築戰略:
是時候把AI加入到建築中去了。首先我們必須注意建築的建造順序。以NE為例,我們不能在沒有獵手大廳的情況下建造戰爭古樹。
帶著這個想法,我們開始設置建築順序在腳本中:
NE的戰役AI僅限與建築:globals

player MyVictim = Player( 0 )

endglobals



function ConfigureAI takes nothing returns nothing

call SetSlowChopping( false )

call SetPeonsRepair( true )

endfunction



function main takes nothing returns nothing

call CampaignAI( MOON_WELL, null )

call ConfigureAI( )

// **********************************

// * Building Strategy *

// **********************************

call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )

call SetBuildUnit( 15, WISP )

call SetBuildUnitEx( 1, 2, 3, MOON_WELL )

call SetBuildUnitEx( 1, 1, 2, ANCIENT_WAR )

call SetBuildUnit( 1, ELF_ALTAR )

call SetBuildUnit( 1, HUNTERS_HALL )

// **********************************

// * End Building Strategy *

// **********************************

endfunction
複製代碼現在我們已經完成了一個一級建築。讓我們來看看這個新函數SetBuildUnit( n, UnitID )很容易理解。這個函數是命令AI去訓練或者建造n個單位 單位類型(UnitID),SetBuildUnitEx( e, n, i, UnitID )同上但是效果更好,因為它會讓你設置多少單位會被建造在easy簡單,normal普通,insane瘋狂的模式下。
現在我們需要建造防守我們城堡的單位,所以我要加入訓練單位函數在AI中。

NE Campaign AI - Buildings and defensive units:globals

player MyVictim = Player( 0 )

endglobals



function ConfigureAI takes nothing returns nothing

call SetSlowChopping( false )

call SetPeonsRepair( true )

endfunction



function main takes nothing returns nothing

call CampaignAI( MOON_WELL, null )

call ConfigureAI( )

// **********************************

// * Building Strategy *

// **********************************

call SetReplacements( 1, 2, 3 ) // <==(1)

call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )

call SetBuildUnit( 15, WISP )

call SetBuildUnitEx( 1, 2, 3, MOON_WELL )

call SetBuildUnitEx( 1, 1, 2, ANCIENT_WAR )

call SetBuildUnit( 1, ELF_ALTAR )

call SetBuildUnit( 1, HUNTERS_HALL )

call SetBuildUnitEx( 0, 1, 2, ANCIENT_PROTECT )

call CampaignDefenderEx( 2, 2, 3, ARCHER ) // <==(2)

call CampaignDefenderEx( 1, 1, 1, HUNTRESS )

// **********************************

// * End Building Strategy *

// **********************************

endfunction
複製代碼讓我們來解釋下這個新函數:
1. SetReplacements(e, n, i):設置AI多久會替換被殺的防衛者。在上邊的代碼中。它在容易模式下進行這中替換了一次,普通難度下替換了兩次,瘋狂難度下替換了三次。
2. CampaignDefenderEx(e, n, i, UnitID):和SetUnitBuild相同,但是被訓練的單位如果被殺死n次後會在Replacements作用下被替換。
現在這個防禦戰略被佈置好了。


Defensive Strategy:


Easy
Normal
Insane
Archers
2
2
3
Huntress
1
1
1
Ancient Protector
0
1
2


Attacking Strategy(進攻戰略):

現在我們開始反擊了,所以我們需要設置AI,命令單位去進攻。函數設置如下:

Attack Function Arrangement:


function main takes nothing returns nothing

// 建築代碼在這裡

//*** WAVE 1 ***

call InitAssaultGroup() // <==(1)

call CampaignAttackerEx( 2, 3, 3, ARCHER ) // <==(2)

call CampaignAttackerEx( 0, 1, 2, HUNTRESS )

call CampaignAttackerEx( 0, 1, 1, BALLISTA )

call SuicideOnPlayerEx( M2, M3, M3, MyVictim ) // <==(3)

endfunction
複製代碼

該函數功能如下
InitAssaultGroup():清除前面的攻擊組,增加一個新的空組。
CampaignAttackerEx( e, n, i, UnitID ):像SetBuildUnitEx一樣,但是增加這些單位到攻擊組中。
SuicideOnPlayerEx( te, tn, ti, TargetPlayer ):等待te seconds在簡單難度,tn seconds在普通難度,ti seconds在瘋狂難度攻擊指定玩家。
有人問:M2,M3是什麼意思?M2是2分鐘(2*60sec),M3是3分鐘(3*60sec)以此類推。。。。我們可以用M1~M15。注意:
有另一種方法去攻擊敵人。SuicideOnPlayerEx可以獲得主要玩家的基地(本地玩家),但是你想要一些特殊的單位,這個時候就需要用到AttackMoveKillA( TargetUnit )這個函數。這個腳本可以偷襲建築,也就是所謂的偷襲。

Attack script for creeping:


function main takes nothing returns nothing

local unit crp

// 建築代碼

//*** WAVE 1 ***

call InitAssaultGroup()

set crp = GetCreepCamp(0,9,false) // 存儲目標單位

call CampaignAttackerEx( 2, 3, 3, ARCHER )

call CampaignAttackerEx( 0, 1, 2, HUNTRESS )

call Sleep( M3 ) // 攻擊前等待3分鐘

call AttackMoveKillA(crp) // 命令攻擊組攻擊

endfunction
複製代碼

其中GetCreepCamp( min, max, flyers ):獲取一個潛行單位用min到max包括(flyers=true)或者不包括(flyers=false)。Flyers是飛行單位。
現在我們這個wave1就可以運行了。要增加更多的波數,增加更多的單位數量或者單位類型。

Building + Attacking script. All tiers:


globals

player MyVictim = Player( 0 )

endglobals

function ConfigureAI takes nothing returns nothing

call SetSlowChopping( false )

call SetPeonsRepair( true )

endfunction

function main takes nothing returns nothing

call CampaignAI( MOON_WELL, null )

call ConfigureAI( )

// **********************************

// * Building Strategy *

// **********************************

//

// 一級建築

call SetReplacements( 1, 2, 3 )

call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )

call SetBuildUnit( 15, WISP )

call SetBuildUnitEx( 1, 2, 3, MOON_WELL )

call SetBuildUnitEx( 1, 1, 2, ANCIENT_WAR )

call SetBuildUnit( 1, ELF_ALTAR )

call SetBuildUnit( 1, HUNTERS_HALL )

call CampaignDefenderEx( 2, 2, 3, ARCHER )

call CampaignDefenderEx( 1, 1, 1, HUNTRESS )

call CampaignDefenderEx( 0, 1, 2, ANCIENT_PROTECT )

// 2級建築

call SetBuildUnit( 1, TREE_AGES )

call SetBuildUnitEx( 1, 1, 2, ANCIENT_LORE )

call SetBuildUnit( 1, ANCIENT_WIND )

// 3級建築

call SetBuildUnit( 1, TREE_ETERNITY )

call SetBuildUnitEx( 0, 1, 1, CHIMAERA_ROOST )

// **********************************

// * End Building Strategy *

// **********************************

// **********************************

// * Attack Strategy *

// **********************************

//*** WAVE 1 ***

call InitAssaultGroup()

call CampaignAttackerEx( 2, 3, 3, ARCHER )

call CampaignAttackerEx( 0, 1, 2, HUNTRESS )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 2 *** Between 2 or 3 minutes after Wave 1

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 3 *** Between 2 or 3 minutes after Wave 2

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 4 *** Between 2 or 3 minutes after Wave 3

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 5 *** Between 3 or 4 minutes after Wave 4

call InitAssaultGroup()

call CampaignAttackerEx( 3, 3, 3, ARCHER )

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 0, 1, 2, DRYAD )

call SuicideOnPlayerEx( M4, M3, M3, MyVictim )

//*** WAVE 6 *** Between 3 or 4 minutes after Wave 5

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call SuicideOnPlayerEx( M4, M3, M3, MyVictim )

//*** WAVE 7 *** Between 3 or 5 minutes after Wave 6

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )

call SuicideOnPlayerEx( M5, M4, M3, MyVictim )

//*** WAVE 8 *** Between 3 or 5 minutes after Wave 7

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

//*** WAVE 9 *** Between 4 or 6 minutes after Wave 8

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )

call CampaignAttackerEx( 1, 1, 2, FAERIE_DRAGON )

call CampaignAttackerEx( 0, 1, 2, CHIMAERA )

call SuicideOnPlayerEx( M6, M5, M4, MyVictim )

// **********************************

// * End Attack Strategy *

// **********************************

endfunction
複製代碼

在訓練完最後一波單位後,這個腳本結束了,AI也不會派出更多的單位去攻擊敵人。若你不想他結束我們可以給他加個循環loop,所以他會重複的刷最後三波單位。

Building + Attacking script with infinite loop. All tiers:


function ConfigureAI takes nothing returns nothing

call SetSlowChopping( false )

call SetPeonsRepair( true )

endfunction

function main takes nothing returns nothing

call CampaignAI( MOON_WELL, null )

call ConfigureAI( )

// **********************************

// * Building Strategy *

// **********************************

//

// Tier 1 Buildings

call SetReplacements( 1, 2, 3 )

call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )

call SetBuildUnit( 15, WISP )

call SetBuildUnitEx( 1, 2, 3, MOON_WELL )

call SetBuildUnitEx( 1, 1, 2, ANCIENT_WAR )

call SetBuildUnit( 1, ELF_ALTAR )

call SetBuildUnit( 1, HUNTERS_HALL )

call CampaignDefenderEx( 2, 2, 3, ARCHER )

call CampaignDefenderEx( 1, 1, 1, HUNTRESS )

call CampaignDefenderEx( 0, 1, 2, ANCIENT_PROTECT )

// Tier 2 buildings

call SetBuildUnit( 1, TREE_AGES )

call SetBuildUnitEx( 1, 1, 2, ANCIENT_LORE )

call SetBuildUnit( 1, ANCIENT_WIND )

// Tier 3 buildings

call SetBuildUnit( 1, TREE_ETERNITY )

call SetBuildUnitEx( 0, 1, 1, CHIMAERA_ROOST )

// **********************************

// * End Building Strategy *

// **********************************

// **********************************

// * Attack Strategy *

// **********************************

//*** WAVE 1 ***

call InitAssaultGroup()

call CampaignAttackerEx( 2, 3, 3, ARCHER )

call CampaignAttackerEx( 0, 1, 2, HUNTRESS )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 2 *** Between 2 or 3 minutes after Wave 1

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 3 *** Between 2 or 3 minutes after Wave 2

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 4 *** Between 2 or 3 minutes after Wave 3

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 5 *** Between 3 or 4 minutes after Wave 4

call InitAssaultGroup()

call CampaignAttackerEx( 3, 3, 3, ARCHER )

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 0, 1, 2, DRYAD )

call SuicideOnPlayerEx( M4, M3, M3, MyVictim )

//*** WAVE 6 *** Between 3 or 4 minutes after Wave 5

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call SuicideOnPlayerEx( M4, M3, M3, MyVictim )

loop //Init the infinite attack loop

//*** WAVE 7 *** Between 3 or 5 minutes after Wave 6

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )

call SuicideOnPlayerEx( M5, M4, M3, MyVictim )

//*** WAVE 8 *** Between 3 or 5 minutes after Wave 7

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

//*** WAVE 9 *** Between 4 or 6 minutes after Wave 8

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )

call CampaignAttackerEx( 1, 1, 2, FAERIE_DRAGON )

call CampaignAttackerEx( 0, 1, 2, CHIMAERA )

call SuicideOnPlayerEx( M6, M5, M4, MyVictim )

endloop

// **********************************

// * Attack Strategy never ends *

// **********************************

endfunction
複製代碼

Upgrading Strategy(升級戰略):
我們有了幾乎所有的東西在AI中,現在我們要加入升級這項。在代碼中它們可以放在任何地方,但是我建議大家放在相臨兩波單位之間。所以AI就會看起來對敵人的攻擊越來越厲害。
讓我們來看看我們即將去使用的代碼:SetBuildUpgrEx( e, n, i, UpgradeID ):設置升級等級在簡單,普通,瘋狂三種難度下。

Building + Attacking script with infinite loop + Upgrading scripts. All tiers:


globals

player MyVictim = Player( 0 )

endglobals

function ConfigureAI takes nothing returns nothing

call SetSlowChopping( false )

call SetPeonsRepair( true )

endfunction

function main takes nothing returns nothing

call CampaignAI( MOON_WELL, null )

call ConfigureAI( )

// **********************************

// * Building Strategy *

// **********************************

//

// Tier 1 Buildings

call SetReplacements( 1, 2, 3 )

call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )

call SetBuildUnit( 15, WISP )

call SetBuildUnitEx( 1, 2, 3, MOON_WELL )

call SetBuildUnitEx( 1, 1, 2, ANCIENT_WAR )

call SetBuildUnit( 1, ELF_ALTAR )

call SetBuildUnit( 1, HUNTERS_HALL )

call CampaignDefenderEx( 2, 2, 3, ARCHER )

call CampaignDefenderEx( 1, 1, 1, HUNTRESS )

call SetBuildUnitEx( 0, 1, 2, ANCIENT_PROTECT )

// Tier 2 buildings

call SetBuildUnit( 1, TREE_AGES )

call SetBuildUnitEx( 1, 1, 2, ANCIENT_LORE )

call SetBuildUnit( 1, ANCIENT_WIND )

// Tier 3 buildings

call SetBuildUnit( 1, TREE_ETERNITY )

call SetBuildUnitEx( 0, 1, 1, CHIMAERA_ROOST )

// **********************************

// * End Building Strategy *

// **********************************

// **********************************

// * Attack Strategy *

// **********************************

//*** WAVE 1 *** AI will begin to attack in 5 minutes

call InitAssaultGroup()

call CampaignAttackerEx( 2, 3, 3, ARCHER )

call CampaignAttackerEx( 0, 1, 2, HUNTRESS )

call SuicideOnPlayerEx( M5, M5, M5, MyVictim )

//*** Basic upgrades from HUNTERS HALL ***

call SetBuildUpgrEx( 1, 2, 3, UPG_STR_MOON )

call SetBuildUpgrEx( 1, 2, 3, UPG_MOON_ARMOR )

call SetBuildUpgrEx( 1, 2, 3, UPG_STR_WILD )

call SetBuildUpgrEx( 1, 2, 3, UPG_HIDES )

//*** WAVE 2 *** Between 2 or 3 minutes after Wave 1

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 3 *** Between 2 or 3 minutes after Wave 2

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 4 *** Between 2 or 3 minutes after Wave 3

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call CampaignAttackerEx( 0, 1, 1, BALLISTA )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** Dryad Upgrade

call SetBuildUpgrEx( 1, 1, 1, UPG_ABOLISH )

//*** WAVE 5 *** Between 3 or 4 minutes after Wave 4

call InitAssaultGroup()

call CampaignAttackerEx( 3, 3, 3, ARCHER )

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 0, 1, 2, DRYAD )

call SuicideOnPlayerEx( M4, M3, M3, MyVictim )

//*** Druid of the Claw Upgrade

call SetBuildUpgrEx( 0, 1, 2, UPG_DRUID_CLAW )

//*** WAVE 6 *** Between 3 or 4 minutes after Wave 5

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call SuicideOnPlayerEx( M4, M3, M3, MyVictim )

//*** chimaera Upgrade

call SetBuildUpgrEx( 0, 0, 1, UPG_CHIM_ACID )

loop //Init the infinite attack loop

//*** WAVE 7 *** Between 3 or 5 minutes after Wave 6

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )

call SuicideOnPlayerEx( M5, M4, M3, MyVictim )

//*** WAVE 8 *** Between 3 or 5 minutes after Wave 7

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

//*** WAVE 9 *** Between 4 or 6 minutes after Wave 8

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )

call CampaignAttackerEx( 1, 1, 2, FAERIE_DRAGON )

call CampaignAttackerEx( 0, 1, 2, CHIMAERA )

call SuicideOnPlayerEx( M6, M5, M4, MyVictim )

endloop

// **********************************

// * Attack Strategy never ends *

// **********************************

endfunction
複製代碼
Hero Abilities.(英雄技能)
如果我們測試該地圖,我們會發現英雄不會學習任何技能。解決這個問題就需要我們加入一個增加英雄學習技能這個腳本。下邊以訓練惡魔獵手為例:
Hero Leveling Script:

function hero_levels takes nothing returns integer

local integer hero = GetHeroId()

local integer level = GetHeroLevelAI()

local integer a = 0

if hero == DEMON_HUNTER then

if level == 1 or level == 3 or level == 5 then

set a = IMMOLATION

endif

if level == 2 or level == 4 or level == 7 then

set a = MANA_BURN

endif

if level >= 8 then

set a = EVASION

endif

if level == 6 then

set a = METAMORPHOSIS

endif

endif

if hero == MOON_CHICK then

if level == 1 or level == 3 or level == 5 then

set a = TRUESHOT

endif

if level == 2 or level == 4 or level == 7 then

set a = SEARING_ARROWS

endif

if level >= 8 then

set a = SCOUT

endif

if level == 6 then

set a = STARFALL

endif

endif

return a

endfunction
複製代碼
注意這個函數必須總是return一個整數。
現在我們設置好以後,必須把它放入主函數中去,這樣主函數才可以調用,設置在主函數中,我們需要用到下邊這個函數:

call CampaignAI( MOON_WELL, function hero_levels )

整個程序代碼如下:
Building + Attacking script with infinite loop + Upgrading (including heroes) scripts. All tiers:


globals

player MyVictim = Player( 0 )

endglobals

function ConfigureAI takes nothing returns nothing

call SetSlowChopping( false )

call SetPeonsRepair( true )

endfunction

function hero_levels takes nothing returns integer

local integer hero = GetHeroId()

local integer level = GetHeroLevelAI()

local integer a = 0

if hero == DEMON_HUNTER then

if level == 1 or level == 3 or level == 5 then

set a = IMMOLATION

endif

if level == 2 or level == 4 or level == 7 then

set a = MANA_BURN

endif

if level >= 8 then

set a = EVASION

endif

if level == 6 then

set a = METAMORPHOSIS

endif

endif

if hero == MOON_CHICK then

if level == 1 or level == 3 or level == 5 then

set a = TRUESHOT

endif

if level == 2 or level == 4 or level == 7 then

set a = SEARING_ARROWS

endif

if level >= 8 then

set a = SCOUT

endif

if level == 6 then

set a = STARFALL

endif

endif

return a

endfunction

function main takes nothing returns nothing

call CampaignAI( MOON_WELL, function hero_levels ) //<== Now this function upgrades heroes

call ConfigureAI( )

// **********************************

// * Building Strategy *

// **********************************

//

// Tier 1 Buildings

call SetReplacements( 1, 2, 3 )

call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )

call SetBuildUnit( 15, WISP )

call SetBuildUnitEx( 1, 2, 3, MOON_WELL )

call SetBuildUnitEx( 1, 2, 2, ANCIENT_WAR )

call SetBuildUnit( 1, ELF_ALTAR )

call SetBuildUnit( 1, HUNTERS_HALL )

call CampaignDefenderEx( 2, 2, 3, ARCHER )

call CampaignDefenderEx( 1, 1, 1, HUNTRESS )

call SetBuildUnitEx( 1, 2, 3, ANCIENT_PROTECT )

// Tier 2 buildings

call SetBuildUnit( 1, TREE_AGES )

call SetBuildUnitEx( 1, 2, 2, ANCIENT_LORE )

call SetBuildUnit( 1, ANCIENT_WIND )

// Tier 3 buildings

call SetBuildUnit( 1, TREE_ETERNITY )

call SetBuildUnitEx( 0, 1, 1, CHIMAERA_ROOST )

// **********************************

// * End Building Strategy *

// **********************************

// **********************************

// * Attack Strategy *

// **********************************

//*** WAVE 1 *** AI will begin to attack in 5 minutes

call InitAssaultGroup()

call CampaignAttackerEx( 2, 3, 3, ARCHER )

call CampaignAttackerEx( 0, 1, 2, HUNTRESS )

call SuicideOnPlayerEx( M5, M5, M5, MyVictim )

//*** Basic upgrades from HUNTERS HALL ***

call SetBuildUpgrEx( 1, 2, 3, UPG_STR_MOON )

call SetBuildUpgrEx( 1, 2, 3, UPG_MOON_ARMOR )

call SetBuildUpgrEx( 1, 2, 3, UPG_STR_WILD )

call SetBuildUpgrEx( 1, 2, 3, UPG_HIDES )

//*** WAVE 2 *** Between 2 or 3 minutes after Wave 1

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 3 *** Between 2 or 3 minutes after Wave 2

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** WAVE 4 *** Between 2 or 3 minutes after Wave 3

call InitAssaultGroup()

call CampaignAttackerEx( 3, 4, 4, ARCHER )

call CampaignAttackerEx( 1, 2, 3, HUNTRESS )

call CampaignAttackerEx( 0, 1, 1, BALLISTA )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call SuicideOnPlayerEx( M3, M2, M2, MyVictim )

//*** Dryad Upgrade

call SetBuildUpgrEx( 1, 1, 1, UPG_ABOLISH )

//*** WAVE 5 *** Between 3 or 4 minutes after Wave 4

call InitAssaultGroup()

call CampaignAttackerEx( 3, 3, 3, ARCHER )

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 0, 1, 2, DRYAD )

call SuicideOnPlayerEx( M4, M3, M3, MyVictim )

//*** Druid of the Claw Upgrade

call SetBuildUpgrEx( 0, 1, 2, UPG_DRUID_CLAW )

//*** WAVE 6 *** Between 3 or 4 minutes after Wave 5

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call SuicideOnPlayerEx( M4, M3, M3, MyVictim )

//*** chimaera Upgrade

call SetBuildUpgrEx( 0, 0, 1, UPG_CHIM_ACID )

loop //Init the infinite attack loop

//*** WAVE 7 *** Between 3 or 5 minutes after Wave 6

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )

call SuicideOnPlayerEx( M5, M4, M3, MyVictim )

//*** WAVE 8 *** Between 3 or 5 minutes after Wave 7

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

//*** WAVE 9 *** Between 4 or 6 minutes after Wave 8

call InitAssaultGroup()

call CampaignAttackerEx( 2, 2, 2, HUNTRESS )

call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )

call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )

call CampaignAttackerEx( 1, 2, 3, DRYAD )

call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )

call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )

call CampaignAttackerEx( 1, 1, 2, FAERIE_DRAGON )

call CampaignAttackerEx( 0, 1, 2, CHIMAERA )

call SuicideOnPlayerEx( M6, M5, M4, MyVictim )

endloop

// **********************************

// * Attack Strategy never ends *

// **********************************

endfunction
複製代碼


Controlling the AI via triggers


當我們創建個戰役時候,我們需要用某種方式保持AI的控制,例如當某個單位進入一個區域時候我們需要AI去殺死它。


在接到命令時候我們希望AI可以啟動。這裡需要用到WaitForSignal(),這個函數要放在AI的攻擊腳本之前。This function takes nothing and returns an integer that is the command received( return的是一個整數表示命令收到),這樣一來我們可以用兩種方法用它。


function main takes nothing returns nothing

local integer cmd // <==僅僅設置是否用選項 2

... // 這放建築代碼

// 選項 1

call WaitForSignal() // <== 等到地圖發出一個命令

// 選項 2

set cmd = WaitForSignal() // <== 得到命令被承認,讓AI起作用

if cmd == 0 then

//選擇選項0

elseif cmd == 1 then

//do option 1. etc

...

endif

endfunction
複製代碼


第二種方式更有意思我們可以使AI起反映在不同的方式下。(例如在某一時刻攻擊玩家一,在下次就攻擊玩家3或其他)

Testing the AI.
現在我們開始做最重要的一項,如果我們想要測試這個AI有兩種方法。最慢也最精確的辦法就是把AI放進地圖裡,運行它,檢查它的連通性。
另一種是最快的方式,做法如下:
1. 保存你的AI腳本文件名為*.AI file.
2. 打開WE。
3. 按F8或者點開AI editor.
4. 選擇第四項測試的配置
5. 設置遊戲速度在3X(現在你明白了為什麼它是最快的方式)
6. 設置需要測試AI在你的地圖,默認的WE測試地圖是the PlunderIsle map,更改為你的地圖。
7. 設置你的玩家,記住若你設置的是AI攻擊玩家1(Player(0) in JASS),你必須設置自己的玩家不同於玩家1才能運行。聽起來像是多餘,但是我們經常容易忽略它。
8. 對應你的AI設置相應的種族。
9. 設置敵對的玩家為電腦並帶有當前的AI
10. 確認你的AI玩家和目標玩家不在一個聯盟
11. 設置一個裁判或者觀看者的位置
12. CTRL+F9

當運行的時候你看到電腦農民開始建造建築,說明你的AI成功了。
如果你看到農民僅僅採集資源不做其他,那說明你有一個JASS錯誤,檢查語法,保存,再測試。
記住JASS像是個很敏感的外殼一點點小小的字母錯誤都會使它出錯。
希望這個手冊可以幫助每個人,如果我有空 我會做其他關於AI的文章。歡迎建議和問題。玩這個AI的同時,改變單位,做些實驗,這些都可以幫助你學到更多的關於魔獸AI的東西。




沒有留言:

張貼留言

※怎麼下載?Xuite硬碟MediaFireBadongoSendSpace
※文章可以轉貼嗎?可以,不過要註明出處、標示本站連結。
※載點可以轉貼嗎?不可以,不能盜連。
※建議瀏覽器:Chrome 或 Firefox 或 Opera 或 IE7以上
!請按+1來支持本站!