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( 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的東西。 |
暴雪英霸是未來很看好的遊戲! 站長最近都玩 英雄聯盟 或 Mstar 。 以前站長擅長幫熱門的 魔獸3 地圖加入 AI, 可以和電腦英雄對戰,電腦懂的和人對話。
##EasyReadMore##
2009年12月11日 星期五
HOW TO MAKE A CAMPAIGN AI.
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言