关键字搜索 | 社区 | 首页

WoWTC - 战网中国魔兽世界 -> 宏和UI
转贴:WOW進階討論 (Advance Programming)
2005-02-21 02:16
ckone / 人气:3761
加为IE收藏  收藏文章
上一文章     下一文章


WOW進階討論 (Advance Programming)
原帖出处:http://pc.gamebase.com.tw:
作者: cherngje(宇桐)    
日期: 2004/12/31 02:10:07

Chapter One

玩了WOW有一段時間了,除了遊戲本身所提供的基本功能之外,其他WOW的功能我都盡量的嘗試.在這裡我提供一下我個人的心得.

相信很多的玩家都知道,WOW有所謂的合法外掛(COSMOS),但是WOW又非常的嚴格的抓所謂的非法外掛,那麼合法的外掛與非法的外掛差別在哪?

其實所謂的合法外掛,只是在於一些有心的玩家利用了WOW所提供的功能,以及指令,另外在WOW的遊戲核心上,另外寫了一些輔助性質的SCRIPT來幫助遊戲介面的簡易操作.至於非法外掛,就是利用任合遊戲本身所沒提供的功能來增加自身的利益(包括了所謂第三者程式third party program).

既然WOW本身有提供這樣的功能,身為玩家的我們為什麼不盡量的利用這些好處呢?有鑒於台灣玩家在獲得這些資訊上的困難(因為有關於這方面的討論,大部分都是英文),我在這裡提出討論,或許能帶給台灣的玩家另外一種的遊戲體驗.

暴風雪在WOW的官方網站上有很明確的提到,UI的修改是玩家對於遊戲整體體驗中的一部分.但是什麼是UI?UI修改又是什麼?

UI是USER INTERFACE(使用者介面),在WOW中,所有的UI都是模組化的,每一個按鈕,每一個視窗都是屬於某一個模組的定義.玩家在玩遊戲的時候,並不是直接的對於遊戲核心下達遊戲指令,而是先在UI上面的動作,然後在藉由UI的模組上下達遊戲核心指令.例如我們按下遊戲中攻擊的按鈕,WOW會先檢查這個按鈕的定義是什麼,然後才執行這個定義下的指令.

那麼修改UI的好處又是什麼呢?這樣說好了.WOW本身所提供的UI,其背後的定義都是最基本的,最簡化的.比如說快捷鍵按鈕的設計,以及每個指令動作. 在按鈕以及視窗的設計上,使以簡單容易上手為主要目的.但是對於進階玩家而言,又會覺得WOW所提供的快捷鍵按鈕不夠用,所以自己在UI上面加以修改,這樣就不但可以自行決定快捷鍵按鈕的數目,也可以把這些按鈕擺在自己最喜歡的地方.

另外關於指令動作上(鍵盤與老鼠在UI上面的指令),WOW基本的UI設定都是一個指令一個動作.我們按一個按鈕,WOW做一個動作.但是我們可以自行設定UI,達到玩家的下達一個指令,WOW同時做很多動作.

比如說,WOW給玩家在攻擊上的選擇是,按TAB會幫玩家找出畫面上距離最近的敵人(原始設定是20碼的距離範圍內),然後玩家必須按攻擊的按鈕或是T, 在這樣的情況下才會攻擊.玩家下達了兩個指令,做了兩個動作.但是在UI的修改上,我們不但可以修改畫面上距離最近的敵人的距離範圍(適合遠距離攻擊的玩家),我們還可以設定按下TAB按鍵,不但會自動定位距離最近的敵人,還會自動開始攻擊.

在這個討論串當中,我主要是針對指令UI上的設定提出討論,因為關於畫面上的設定已經有很多現成的選擇(COSMOS).因此我將針對CLASS上面輔助型的UI設定.在藉由討論上,讓台灣的玩家們也有機會自行設計出最方便,最有效率的攻擊,法術施展,以及寵物控制.

當然我絕對歡迎玩家針對任何的UI設定提出討論,但是我不見得有能力回答.畢竟我個人比較不喜歡去研究畫面的排列,所以這方面花的功夫也比較少.



Chapter Two

上一篇文章介紹了UI修改的最基本觀念,在這篇文章中我將提供UI修改上的最基本的動作,工具以及資料來源.


在我們要對UI做任何的修改或是製作模組之前,我們必須先了結WOW的UI基本結構.在WOW的資料夾裡面,我們可以找的一個DATA的子目錄.在這個子目錄裡面,包括了所有WOW會運用到的檔案,包括了模組,圖形,字型等等.這些都壓縮在所謂的MPQ檔案裡面.拿我個人的檔案來做例子,我的MPQ檔在 C:Program FilesWorld of WarcraftData下面.而所有UI可以運用到的檔案都壓縮在interface.mpq檔裡.

要檢查MPQ檔案裡面有些什麼,我個人建議WinMPQ這個程式.為了避免大家擔心我放病毒,在這裡我建議大家自行上GOOGLE查哪裡可以下載WinMPQ.

因為遊戲的UI的基本設定都在interface.mpq,所以我不建議大家直接對於interface.mpq裡面的檔案直接修改.大家可以把所需要的檔案解壓出來.只要做完修改後不存回interface.mpq裡面,在這樣的情況下,都不會影響到基本設定.

那麼大家會問修改完之後的檔案該存在哪呢?首先到WOW的目錄裡面,然後開一個先的子目錄叫做interface.以我個人的例子是C:Program FilesWorld of Warcraftinterface.然後大家可以把修改好或是製作好的檔案存在這個資料夾下面.當WOW載入遊戲資料的時候,WOW會自動到這個資料夾裡面檢查哪些模組因該載入.

雖然UI修改可以運用到WOW現有的檔案,但是為了方便教學,我在這裡提出的例子將不會用到WOW現有的檔案.事實上,除了要做遊戲畫面上的設定,大部分的情況下,我們不見得要用到WOW現有的UI檔案,只要我們製作模組用的都是WOW所提供的核心指令就可以了.

在製作模組之前,我先介紹一下每一個模組所需要的最基本的檔案.每個模組都需要一個介紹檔,toc檔.定義檔,xml,以及核心檔,lua檔.這三種檔案都可以用筆記本或是任何的文書處理程式來做修改.

為了方便介紹,我舉出一個簡單的例子來解釋這三個檔案.現在讓我們設計個 Hi 模組.這個模組當你執行的時候,他會在你的遊戲畫面上出現一個 Hi 的資訊.

因為我們這個模組叫做Hi,所以我們需要三個檔案

hi.toc
hi.xml
hi.lua
(模組的名稱最好與檔案的名稱相對應)

現在讓我介紹一下hi.toc的格式:

## Interface: 4150
## Title: Hi
## Notes: just want to say hi
## OptionalDeps:
## Dependencies:
hi.xml

在## Interface:後面的數字代表了目前WOW的版本.製作模組的作者有義務維持模組支援最新版的WOW,所以每當WOW做出更新的時候,模組的製作人得檢查模組是否還能工作,當確定還能工作的時候,就可以更新射個數字.更新這個數字有兩個意義:第一,WOW會檢查每個模組的這個數字,如果與WOW版本相輔合,那麼就會載入,不然就會檔掉.第二,玩家可以確定這個模組的版本是可以使用的版本.

我在這裡不建議除了模組的製作人修改這個數字.因為有時候模組的設計可能很複雜,在不是製作人的情況下,很可能不知道到底沒有更新的模組是否還跟最新版的 WOW相容.如果玩家自行更改這個數字讓它跟WOW的版本數字一樣的話,WOW就會自動載入這個模組.如果模組不相容的情況下,很可能會造成遊戲上的困擾.

寫到這裡,玩家可能會問要去哪裡找WOW最新的版本數字.當執行WOW遊戲的時候,在登入的畫面上的最左下方,可以找到這個資訊.以目前我寫這個教學的時間而言,WOW最新版所提供的資訊是Version 1.2.1 (4150).大家要用的是4150這個數字,而不是1.2.1這個數字.

在## Title:後面,模組製作人打的字元就是這個模組的名稱.

在## Notes:後面,模組製作人打的字元就是這個模組的簡介

## OptionalDeps:後面, 模組製作人標示出這個模組是否有其他的額外的模組可以支援這個模組.當這個地方有標示其他的模組的時候,並不代表玩家們也必須要有這個額外模組,只是有了這個額外的模組,可以讓這個麼模組的功能更加完整.

## Dependencies:後面, 模組製作人得標示出這個模組必須要使用的的檔案(包括了必須使用到其他模組的檔案,請注意,上面選擇性模組的檔案並不需要在這裡標示).

因為這個教學模組並不需要用到其他的模組,所以只需要標示出模組定義檔 hi.xml.

hi.xml的介紹:

基本上XML可以當做網頁設計檔案(HTML)來看,可是嚴格的來說,XML是拿來作為定義上或是資料傳輸上所使用的.如果玩家對於XML的語法以及如何運用有興趣,可以到http://www.w3.org/XML/查詢更詳細的資料

現在我只介紹XML在WOW模組設計上該如何運用.

Code:      [Copy to clipboard]
<Ui xmlns="http://www.blizzard.com/wow/ui/"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
  <Script file="hi.lua"/>

  <Frame name="hi_core">
    <Scripts>
      <OnLoad>
        this:RegisterEvent("VARIABLES_LOADED");
      </OnLoad>
      <OnEvent>
        if (event == "VARIABLES_LOADED") then
          hi_initialize();
        end
      </OnEvent>
    </Scripts>
  </Frame>
</Ui>

大家可以忽略前面幾行<Ui xmlns ......... />.基本上每一個WOW模組XML檔都必須要有這幾行.

重要的是   <Script file="hi.lua"/> 在這裡大家得定義出模組的核心檔案是什麼.以我們目前的例子,核心檔案是hi.lua.

在 <Frame name="hi_core"> 這裡定義出模組在遊戲畫面中要使用的的子畫面的名稱.這個名稱必須是獨一無二的,避免與其他的模組畫面衝突到.

在上面的例子中我們可以看到<OnLoad>和<OnEvent>的標示,基本上<OnLoad>的意思是當WOW 在載入遊戲介面的時候,因該要做出什麼動作.以我們的例子,我們要在WOW遊戲裡註冊一個變數叫做"VARIABLES_LOADED".
<OnEvent>的意思是,如果發生了什麼事件,那麼該做出什麼動作來反應.以我們的例子,如果註冊"VARIABLES_LOADED" 成功的話,我們就執行hi_initialize(). 當然,如果沒有註冊成功,也就不會有事件發生,這代表了我們的模組沒有載入到遊戲裡面,所以我們也就沒有後續動作.

hi.lua的介紹:
lua 是一個script語言.WOW所有的UI模組都是建立在這個語言之上.對於lua想要更深入的了解,請到官方網站:http://www.lua.org/manual/5.0/ 在這裡可以查到所有關於lua的語法以及使用方式.

現在讓我介紹我們目前的例子:

Code:      [Copy to clipboard]
function hi_initialize()
SlashCmdList["HIHI"] = hi_command;
SLASH_HIHI1 = "/hihi";
SLASH_HIHI2 = "/您好";
end

function hi_command(msg)
message(msg);
end

大家可以看到我們寫兩個小function 一個叫hi_initialize 一個叫 hi_command. 在hi.xml裡面,如果模組順利在入的話hi_initialize是第一個被呼叫的.在這裡我們自行設定了一些"/"指令.我想大家因該對於遊戲裡面的一些"/"指令並不陌生.

同樣的我們也可以幫我們的模組設定這些"/"指令.
SlashCmdList["HIHI"] = hi_command; 代表的意思是如果我們麼組的"/"指令被呼叫的話,我們因該執行hi_command這一個function.
SLASH_HIHI1 = "/hihi";
SLASH_HIHI2 = "/您好";
這裡是幫我們的"/"指令定出名稱,目前我還不確定我們是否可以自行自做出中文指令,但是我想只要可以在WOW輸入中文,上面的設計就因該沒問題.(所以還請可以在WOW輸入中文的玩家測試一下.
這裡要稍微注意的一點是SlashCmdList["HIHI"]裡面的HIHI必須要和SLASH_HIHI1和SLASH_HIHI2 的HIHI依樣.如果我們把HIHI改成NIHAO 那麼就會變成SlashCmdList["NIHAO"], SLASH_NIHAO1, 以及SLASH_NIHAO2. 至於HIHI 或是 NIHAO 後面的 1 和 2 只是變數,代表了同樣的指令,有哪些變種的指令.

當我們打入了"/hihi"或是"/您好" 就會執行下面的function
function hi_command(msg)
message(msg);
end
基本上只是在遊戲畫面上出現一個視窗,然後視窗上面顯示我們在指令後面打入的訊息.

例如我們輸入"/hihi 測試"

那麼出現的視窗就會顯示 "測試" 在那上面.

好了,我們寫好這三個檔案了.現在我們要告訴WOW載入我們的HI模組.
首先,到"C:Program FilesWorld of Warcraftinterface"這個子目錄裡面.如果還沒有這個子目錄的話,自行開一個新的.然後在這個目錄裡面開一個新的目錄叫做 "AddOns"所有玩家設計的模組都因該擺在這個目錄裡面.然後在"AddOns"這個目錄裡面在開一個目錄叫做"HI".最後把我們做好的三個檔案存到這個目錄裡面.
"C:Program FilesWorld of WarcraftinterfaceAddOnsHI"

現在我們可以測試這個模組了喔.

稍微介紹一下WOW簡易管理模組的方式.如果當玩家有安裝自行設計的模組的話(比如說COSMOS),在進入角色選單的時候,我們可以看到畫面的左下方有一個Addons的按鈕.大家可以在者裡自行選擇所希望開啟的模組.在模組名子前面打勾,表示選擇角色之後,遊戲就會開始載入模組.沒打勾就代表不會載入. 請注意,WOW有模組載入的上限.所果所有載入的模組用到的資源超過32MB,遊戲會自動關閉.這時候就需要去管理介面關掉一些模組喔.

下一篇文章,我將教大家如何在lua檔案裡面運用WOW的核心指令,以及如何只使用3個檔案,就可以寫出很有幫助的SCRIPT.



Chapter Three

在來一系列的文章,我要教獵人的玩家如何利用模組設計,有效率的執行遠距離,近距離,以及寵物攻擊. 順便介紹一些WOW的核心指令.


我想玩過網路遊戲的玩家,多多少少都因該聽過外掛.什麼是外掛?其實就是能自動的幫助玩家執行一些指令.基本上很類似MACRO(沒聽過MACRO的人,因該有聽過EZSCRIPT吧)

WOW本身就有提供MACRO這樣的功能.只要我們在遊戲中輸入"MACRO"之後,我們就可以開始設計我們自己的輔助指令.但是WOW的MACRO有很多限制.第一,WOW的MACRO是半自動的,意思就是說,你一定要按下某一個鍵盤按鍵,或是老鼠按鍵,才能執行你所設定的MACRO.第二,遊戲中的 MACRO有字數上的限制.最多只能輸入255個英文字元.第三,WOW的MACRO無法設定時間上面的間隔.在MACRO裡面的所有的指令會被一次執行.第四,如果你所執行的很多指令中有很多都有指令冷卻時間(例如魔法的COOLDOWM),那麼MACRO只會執行第一個可以執行的指令.

同樣的,當我們設計模組的時候,我們也同樣受限於這樣的限制,但是卻沒有255個英文字元的限定,在這樣的情況下,我們可以自做更複雜的指令方式.

今天我要教大家的模組是獵人輔助模組.

WOW的獵人是屬於遠距離攻擊的單位,最需要控制的是如何有要的利用各式的ASPECT以及寵物攻擊.當近距離攻擊的時候,獵人需要用到ASPECT OF MONKEY,當遠距離攻擊的時候,需要用到ASPECT OF HAWK. 但是我想很多人因該都會遇到,同時指示寵物攻擊,玩家攻擊,以及轉換ASPECT的時候,會手忙腳亂.現在我們的目標是如何設計一個模組可以讓我們在操作上更順暢.

獵人輔助模組設計目標:
1:玩家主動攻擊的時候,寵物也會主動攻擊(WOW的基本模式是,玩家按攻擊,然後還要按寵物攻擊).

2:玩家與寵物永遠是攻擊同一個目標,以最快最有效率的方式來減少戰鬥畫面上的危機.避免寵物與玩家通時攻擊不同的敵人,造成最後的結果是玩家與寵物同時陣亡.

3:有效的辨識玩家的攻擊方式,然後執行最有效率的ASPECT.例如玩家近距離攻擊的時候不是在ASPECT OF HAWK的狀況下.

4:有效的運用遠距離攻擊技能(包括了節省MANA,快速選擇敵人目標等等)

好了,有了以上的目標,現在開始讓我們來設計.首先,來製作模組所需要的最基本的三個檔案.因為我替我的模組設計的名稱叫做HunterAssistant(獵人輔助),所以我的三個基本檔案叫做:
HunterAssistant.toc
HunterAssistant.xml
HunterAssistant.lua

Code:      [Copy to clipboard]
HunterAssistant.toc:
## Interface: 4150
## Title: Hunter Assistant V0.1
## Notes: Macro scripts for assisting Hunter
## OptionalDeps:
## Dependencies:
HunterAssistant.xml

HunterAssistant.xml:
<?xml version="1.0" encoding="utf-8" ?>
<Ui xmlns="http://www.blizzard.com/wow/ui/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
<Script file="HunterAssistant.lua"/>

<Frame name="HunterAssistantFrame">
<Scripts>
<OnLoad>
this:RegisterEvent("VARIABLES_LOADED");
</OnLoad>
<OnEvent>
if (event == "VARIABLES_LOADED") then
HunterAssistant_init();
end
</OnEvent>
</Scripts>
</Frame>
</Ui>

我將不在第這兩個檔案多做解釋.有疑問的,請參考上一篇文章.畢竟我只使用的最簡單的設計.


現在的重點LUA核心檔.我先把檔案內容列出來,然後在以另外的文章詳細的解釋每個指令.

HunterAssistant.lua:

Code:      [Copy to clipboard]
function HunterAssistant_init()
-- define slash command here
SlashCmdList["HA_HunterMarkI"] = HA_HunterMarkI;
SLASH_HA_HunterMarkI1 = "/HAHunterMarkI";
SLASH_HA_HunterMarkI2 = "/hahmi";

SlashCmdList["HA_HunterMarkII"] = HA_HunterMarkII;
SLASH_HA_HunterMarkII1 = "/HAHunterMarkII";
SLASH_HA_HunterMarkII2 = "/hahmii";

SlashCmdList["HA_AttackMelee"] = HA_AttackMelee;
SLASH_HA_AttackMelee1 = "/HAAttackMelee";
SLASH_HA_AttackMelee2 = "/haam";

SlashCmdList["HA_AttackRangeI"] = HA_AttackRangeI;
SLASH_HA_AttackRangeI1 = "/HAAttackRangeI";
SLASH_HA_AttackRangeI2 = "/haari";

SlashCmdList["HA_AttackRangeII"] = HA_AttackRangeII;
SLASH_HA_AttackRangeII1 = "/HAAttackRangeII";
SLASH_HA_AttackRangeII2 = "/haarii";

SlashCmdList["HA_StingSerpentI"] = HA_StingSerpentI;
SLASH_HA_StingSerpentI1 = "/HAStingSerpentI";
SLASH_HA_StingSerpentI2 = "/hasseri";

SlashCmdList["HA_StingSerpentII"] = HA_StingSerpentII;
SLASH_HA_StingSerpentII1 = "/HAStingSerpentII";
SLASH_HA_StingSerpentII2 = "/hasserii";

SlashCmdList["HA_StingSerpentIII"] = HA_StingSerpentIII;
SLASH_HA_StingSerpentII1 = "/HAStingSerpentIII";
SLASH_HA_StingSerpentII2 = "/hasseriii";

SlashCmdList["HunterTest"] = HunterTest_command;
SLASH_HunterTest1 = "/HunterTest";
SLASH_HunterTest2 = "/ht";
end



Code:      [Copy to clipboard]
function HA_AttackMelee()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Attack");
x=1
found=false;
while (UnitBuff("player",x)) do
if(string.find(UnitBuff("player",x), "Monkey")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Monkey");
end;
end;
end



Code:      [Copy to clipboard]
function HA_AttackRangeI()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Auto Shot");
x=1
found=false;
while (UnitBuff("player",x)) do
if(string.find(UnitBuff("player",x), "Raven")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Hawk(Rank 1)");
end;
end;
end



Code:      [Copy to clipboard]
function HA_AttackRangeII()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Auto Shot");
x=1
found=false;
while (UnitBuff("player",x)) do
if(string.find(UnitBuff("player",x), "Raven")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Hawk(Rank 2)");
end;
end;
end



Code:      [Copy to clipboard]
function HA_HunterMarkI()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Hunter's Mark(Rank 1)");
end;
end



Code:      [Copy to clipboard]
function HA_HunterMarkII()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Hunter's Mark(Rank 2)");
end;
end



Code:      [Copy to clipboard]
function HA_StingSerpentI()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
x=1
found=false;
while (UnitDebuff("target",x)) do
if(string.find(UnitDebuff("target",x), "Quickshot")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Serpent Sting(Rank 1)");
end;
end;
end



Code:      [Copy to clipboard]
function HA_StingSerpentII()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
x=1
found=false;
while (UnitDebuff("target",x)) do
if(string.find(UnitDebuff("target",x), "Quickshot")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Serpent Sting(Rank 2)");
end;
end;
end



Code:      [Copy to clipboard]
function HA_StingSerpentIII()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
x=1
found=false;
while (UnitDebuff("target",x)) do
if(string.find(UnitDebuff("target",x), "Quickshot")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Serpent Sting(Rank 3)");
end;
end;
end



Code:      [Copy to clipboard]
function HunterTest_command()
x=1
found=false;
while(UnitBuff("player",x)) do
if(string.find(UnitBuff("player",x), "Raven")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Hawk(Rank 1)");
end;
if(found) then
CastSpellByName("Aspect of the Monkey");
end;
end


Chapter Four
首先我要說聲抱歉,因為我沒注意到基地的文章發表沒有辦法顯示"TAB"的空格.這樣在查看程式碼,一定會造成困擾.如果大家在看程式碼會眼睛痛的時候,還請見諒.

現在,讓我們研究一下HunterAssistant.lua第一段:

function HunterAssistant_init()
-- define slash command here
SlashCmdList["HA_HunterMarkI"] = HA_HunterMarkI;
SLASH_HA_HunterMarkI1 = "/HAHunterMarkI";
SLASH_HA_HunterMarkI2 = "/hahmi";

SlashCmdList["HA_HunterMarkII"] = HA_HunterMarkII;
SLASH_HA_HunterMarkII1 = "/HAHunterMarkII";
SLASH_HA_HunterMarkII2 = "/hahmii";

SlashCmdList["HA_AttackMelee"] = HA_AttackMelee;
SLASH_HA_AttackMelee1 = "/HAAttackMelee";
SLASH_HA_AttackMelee2 = "/haam";

SlashCmdList["HA_AttackRangeI"] = HA_AttackRangeI;
SLASH_HA_AttackRangeI1 = "/HAAttackRangeI";
SLASH_HA_AttackRangeI2 = "/haari";

SlashCmdList["HA_AttackRangeII"] = HA_AttackRangeII;
SLASH_HA_AttackRangeII1 = "/HAAttackRangeII";
SLASH_HA_AttackRangeII2 = "/haarii";

SlashCmdList["HA_StingSerpentI"] = HA_StingSerpentI;
SLASH_HA_StingSerpentI1 = "/HAStingSerpentI";
SLASH_HA_StingSerpentI2 = "/hasseri";

SlashCmdList["HA_StingSerpentII"] = HA_StingSerpentII;
SLASH_HA_StingSerpentII1 = "/HAStingSerpentII";
SLASH_HA_StingSerpentII2 = "/hasserii";

SlashCmdList["HA_StingSerpentIII"] = HA_StingSerpentIII;
SLASH_HA_StingSerpentII1 = "/HAStingSerpentIII";
SLASH_HA_StingSerpentII2 = "/hasseriii";

SlashCmdList["HunterTest"] = HunterTest_command;
SLASH_HunterTest1 = "/HunterTest";
SLASH_HunterTest2 = "/ht";
end

附註:HA_代表的意思是HunterAssistant的縮寫.

其實這裡沒有什麼特別的.這裡只是幫模組設定一些簡單的"/"指令.將來我們可以直接把這些指令運用到遊戲的MACRO中. 請注意的一點是,每一個指令都有一個FUNCTION相對應.另外,我每一個指令都一個全名指令,以及一個簡寫指令(方便使用).在指令命名設計上,我以看到指令名稱就大概能猜到使用的結果是什麼.還有就是每個指令前面加上HA_這樣能有效的避免跟其他模組的指令衝突到.另外有幾個指令後面有羅馬數字,這些是代表了所使用到的獵人技能是有等級高低的.比如說HA_HunterMarkI使用的是等級1的Hunter's Mark,HA_HunterMarkII使用的是等級2的Hunter's Mark.

另外,我的指令排列是以英文順序為主.這樣方便我個人尋找BUG.

現在讓我們繼續往下看.

function HA_AttackMelee()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Attack");
x=1
found=false;
while (UnitBuff("player",x)) do
if(string.find(UnitBuff("player",x), "Monkey")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Monkey");
end;
end;
end

這一個function的主要目的是近距離攻擊.首先第一行是AssistUnit("pet");這代表了什麼?其實這是WOW的核心指令之一. AssistUnit()的意思是幫助某一個單位的意思.這個指令可以接受不同的變數,包括玩家單位,NPC友好單位,以及寵物單位.當執行了這個指令之後,你的敵人對象就會變成你所幫助的那個單位的敵人是同一個.在這裡"pet"的意思就是主角單位的寵物.

我在這裡會用AssistUnit("pet")開頭的原因是,當你的寵物在攻擊的時候敵人的時候,你跟你的寵物所選擇的敵人不見得是同一個,所以我們要確定主角跟寵物攻擊的對象是同一個.

(注意:目前我這樣的設計好像有點邏輯上的問題.思考邏輯到底是主角該幫主寵物還是寵物幫助主角?遊戲中的基本設定是主角受到攻擊,寵物就會自動幫助第一個攻擊主角的敵人,可是如果好幾個人攻擊主角,寵物還是會先專心的把第一個敵人解決掉.所以我一開始會這樣設計,專心的先幫助寵物解決掉第一個敵人.可是當遇到我就是有特殊原因要先解決掉其他的敵人的時候(例如某些特殊任務),我這樣的設計反而造成困擾,因為只要我一攻擊,我的對象就就轉換到寵物的敵人了.所以在未來的版本中,我可能會設定另一種攻擊是,寵物永遠幫助主角攻擊同一個敵人,使用的指令是 PetAssistUnit("Player"). "Player"就是代表主角的意思.)

下一行, if(not UnitExists("target")) then
TargetNearestEnemy();
end;
這裡的意思是檢查執行幫忙的指令之後(AssistUnit())到底有沒有敵人?如果主角的寵物沒有在戰鬥狀態,那麼我們敵人的狀態就是沒有選擇. UnitExists("target")) 就是檢查我們有沒有選擇任何的目標.這個也是WOW的核心指令之一. 當然如果我們有選擇目標,可是目標是有好單位呢?不用擔心,WOW的設計本來就是無法攻擊友好單位的.那麼TargetNearestEnemy()又是什麼意思呢?就是自動選擇距離最近的非有好單位當作目標選項.所以這一段的意思就是,如果主角跟主角的寵物都沒有目標的話,幫主角動挑一個最近的非有好單位當作目標.

在來
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Attack");
這裡代表的是,如果有目標的話,寵物攻擊,然後主角攻擊.PetAttack()是寵物攻擊的指令,CastSpellByName("Attack")的意思是主角施展技能,這個技能是攻擊(Attack). 這些全都是WOW的核心指令喔,酷吧.

繼續
x=1
found=false;
while (UnitBuff("player",x)) do

found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Monkey");
end;
end;
end

這裡我定義了一個變數X,以及一個變數FOUND(中文是找到的意思),這兩個變數不是WOW的專有變數,而是LUA的語法喔.為什麼需要這兩個變數?因為當我們在近距離攻擊的時候,我必須要確定主角是在於ASPECT OF MONKEY 之下,有了這些變數可以方便我來做檢查.

while (UnitBuff("player",x))的意思就是如果在主角的身上可以找到Buff的話. UnitBuff("player",1)會在尋找主角身上第一個buff的資料,然後傳回訊息.如果沒找到,就會傳回一個否定的訊息.UnitBuff ("player",2)就是尋找第二個buff的資料.

if(string.find(UnitBuff("player",x), "Monkey"))
string.find是lua語言上的指令,不是WOW的核心指令.這個指令的目的是尋找一個訊息中的字串是否有特殊的字元.所以這一整段的意思是找尋主角身上的buff的資訊是否有MONKEY(猴子)的字串.如果有的話,就把FOUND設定為TRUE.

if(not found) then
CastSpellByName("Aspect of the Monkey");
這一段就是如果從頭到尾都沒有找相關的buff的話,代表了主角沒有施展"Aspect of the Monkey",所以我們就執行施展技能的指令CastSpellByName("Aspect of the Monkey").

寫到這裡,讓我順便提出一些要點.不曉得大家有沒有發現到,在這個function裡面,從頭到尾只有一個指令需要冷卻時間那就是 CastSpellByName("Aspect of the Monkey").其他,比如說攻擊,全部都不需要冷卻時間.這也就是為什麼這麼多指令都可以轉變成一個單一指令.但是因為 CastSpellByName("Aspect of the Monkey")需要冷卻時間,所以我把她擺在最後執行,避免錯誤.另外一點就是,很多人在找尋主角身上的buff資料的時候,喜歡直接用 UnitBuff("player",1)卻沒有想到其實主角身上可能有很多的buff呢.

所以我這樣的設計一定可以確保如果主角已經施展了Aspect of the Monkey,就絕對不會重複施展第二次(浪費mana喔).


至於這個function 裡面的一些IF, WHILE, NOT等等的運用以及正確的語法,就請大家到LUA的官方網站去看.我就不多解釋了.

在來是獵人的普通遠距離攻擊
function HA_AttackRangeI()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Auto Shot");
x=1
found=false;
while (UnitBuff("player",x)) do
if(string.find(UnitBuff("player",x), "Raven")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Hawk(Rank 1)");
end;
end;
end

這一段其實跟近距離的普通攻擊是同樣的邏輯,但是CastSpellByName("Auto Shot") 這個是獵人專有的遠距離自動攻擊的指令.同樣的這個指令可以跟其他需要冷卻時間的指令同時使用.另外CastSpellByName("Aspect of the Hawk(Rank 1)") 這是執行第一級的ASPECT OF THE HAWK. 在我們模組function HA_AttackRangeII()裡面就會執行第二級的ASPECT OF THE HAWK, CastSpellByName("Aspect of the Hawk(Rank 2)")


function HA_HunterMarkI()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
CastSpellByName("Hunter's Mark(Rank 1)");
end;
end
這一段沒有什麼特別的,唯一的好處就是當主角開始使用MARK的技能的時候,就開始命令寵物攻擊.我們不需要按兩個動作.另外,Hunter's Mark 也是有等級之分的,所以我寫了其他相對應的等級指令
注意:(這個FUNCTION我還沒有完全的完成,因為我沒有檢查是否敵人已經被MARK過了,也就是說這個指令允許重複MARK敵人,浪費MANA)

function HA_StingSerpentI()
AssistUnit("pet");
if(not UnitExists("target")) then
TargetNearestEnemy();
end;
if(UnitExists("target")) then
PetAttack();
x=1
found=false;
while (UnitDebuff("target",x)) do
if(string.find(UnitDebuff("target",x), "Quickshot")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Serpent Sting(Rank 1)");
end;
end;
end

這一個跟普通遠距離攻擊的指令很像,但是並不是使用普通的AUTO SHOT,而是使用了Serpent Sting.另外這一個指令不會檢查主角本身是否施展了ASPECT OF HAWK.因為Serpent Sting跟aspect of the hawk都要冷卻時間,兩個寫在一起,只會執行其中的一個,那麼就一點意義都沒有了.既然這樣,為什麼要寫這一個指令?其實這個指令會檢查敵人身上是否已經被施展了Serpent Sting,畢竟Serpent Sting沒有加成效過,所以我們要避免重複施展Serpent Sting.而WOW的基本Serpent Sting指令是不會做這樣的檢查的,所以我們還得一直盯著敵人的資訊看著,避免浪費MANA.可是設計了另外的這個指令,玩家根本不用擔心浪費 MANA,只要想到了就執行一下,反證會自動檢查,也不會中斷AOTU SHOT的動作,更不會浪費MANA.另外,這個指令也有設計其他不同等級的相對應指令.

最後
function HunterTest_command()
x=1
found=false;
while(UnitBuff("player",x)) do
if(string.find(UnitBuff("player",x), "Raven")) then
found=true;
end;
x=x+1;
end;
if(not found) then
CastSpellByName("Aspect of the Hawk(Rank 1)");
end;
if(found) then
CastSpellByName("Aspect of the Monkey");
end;
end
這個指令只是我設計好玩拿來測試用的,當執行這個指令的時候,主角會交互的使用ASPECT OF MONKEY 或者 ASPECT OF HAWK.

模組的核心指令介紹到這裡,下一篇文章將教玩家如何在遊戲裡運用這些指令.

目前我們的模組有了最基本的三個檔案了.現在讓我們把這三個檔案放入C:Program FilesWorld of WarcraftInterfaceAddOnsHunterAssistant這個資料夾裡面.然後執行遊戲.

現在讓我解釋一下WOW上面所謂的斜線指令("/指令")該如何運用.

大家因該都清楚如何的運用感情指令,或是交談指令.這些都是斜線指令.但是WOW還有一些斜線指令是無法直接的輸入, 比如說"/attack". 基本上這是WOW官方設計的攻擊指令,其背後只是很簡單的呼叫了CastSpellByName("Attack"). 但是為什麼我們無法直接使用這些指令呢?因為暴風雪為了避免玩家利用其他的程式來設計非法的MACRO.

怎麼說呢?因為WOW的MACRO沒有時間間隔設計,避免玩家設計機器人,那麼玩家設計機器人就必須利用其他的程式.如果,設計機器人,機器人程式就可以直接的模擬鍵盤輸入指令,而不會影響到玩家對於滑鼠的操做.所以WOW把很多的斜線指令的操作設定成只有在WOW的MACRO下才能使用.你設計一個 MACRO以及MACRO圖像按鈕,你要執行這個MACRO,你就必須對這個按鈕按一下,WOW才會執行這個動作.

當然,還是有其他的辦法擺脫暴風雪這樣的設計,但是我不會對類似這樣的問題做出任和解說.因為暴風雪盡力的維護遊戲免於外掛的侵入,身為玩家的我也有義務要幫助暴風雪.

有這樣的限制的斜線指令包括了所有的會使用到執行特殊技能的指令.所以當我們設計的模組有用到執行特殊技能的時候,我們的斜線指令也只能在WOW下面的 MACRO才能執行.(當然,我們的獵人輔助模組還是運用在MACRO下面比較好,畢竟在戰鬥的時候誰還有時間慢慢的的用鍵盤輸入指令,我們又不是機器人)

要使用WOW的MACRO很簡單,只要在遊戲中輸入"/macro"或是按下Esc 然後選擇macro的選項

在macor的畫面,我們必須幫macro選擇一個圖像按鈕,替macro命名,然後輸入我們想要給macro的指令.

現在讓我列出獵人輔助模組的簡易斜線指令:
Hunter's Mark 包括了不同的等級
/hahmi
/hahmii

Melee Attack(近距離攻擊)
/haam"

Range Attack (遠距離攻擊)包括了不同的等級
/haari
/haarii

Serpent Sting(遠距離特技)包括了不同的等級
/hasseri
/hasserii
/hasseriii

現在我們只要把macro的圖像按鈕選擇好,然後給個名子,最後在底下輸入指令的地方,挑一個你想要執行的輔助指令輸入就好了. 注意喔,一個macro只能使用模組的一個指令喔,因為就算你輸入了很多個,在執行macro的時候,遊戲也只會執行情中的一個而已.(冷卻時間的考量)

當你設定好了macro之後,WALA~~~,你就可以把這個圖形按鈕抓到快捷列上面使用了~~~就像是使用任何其他的基本圖形按鈕依樣喔.好處是,你按一次按鈕,卻等於其他沒有用輔助模組人按好幾次按鈕依樣喔.還會自動幫你做一些額外的檢查呢.有效率了多吧.


下一次,我將教大家如何設計輔助模組可以幫大家在半自動的施展BUFF,對象也會半自動的選擇隊友,寵物,或是自己.


附註1:因為我個人玩了10角色,包括了聯盟的每一個CLASS,在未來的日子裡,我將會不定期的替自己寫模組.如此同時,我也會拿上來與大家分享.但是我將不會再花這麼多的時間詳細解釋每一個指令.除非有網友提出問題,那時我會在盡力回答.

附註2:有關WOW的核心開放給玩家使用的指令,大家可以到這個網頁找到.但是這裡不是完整的列表,說明也不是很清楚,不過大家將就的用嚕.
http://www.wowwiki.com/World_of_Warcraft_API

附註3:最有效率的研究模組的方式,就是到官網的UI Customization的論壇參與討論喔.也許大家會找到一些意想不到,但是又很有幫助的模組喔.我個人就已經發現有人設計了一個挖礦採要的模組,這個模組會把你最到過的挖礦以及採藥的地點紀錄下來,然後顯示在地圖上.怎麼樣,很有用吧.
http://forums.worldofwarcraft.com/board.aspx?fn=wow-interface-customization

Chapter Five
或許我在模組解釋以及使用教學方面,因該採用更簡單的例子來讓大家能更容易上手.所以我決定不要直接的把我個人寫好的模組拿上來,而是先的教大家如何使用WOW的MACRO,以及呼叫一些WOW的指令.



首先讓我重新的介紹一下WOW的MACOR
(基本資料來源 魔獸台灣:http://www.wowtw.game.tw/)


在"魔獸台灣"的網頁裡,我們可以找到很清楚的MACOR中文定義以及解釋:

宏[Macro]使你能夠創建自己獨創且非常酷的命令集,你可以通過點擊一個按鈕便完成一系列的命令。宏擁有許多用法。

宏的創建

輸入“/macro”或者點擊談話[talk]按鈕并且選擇宏[Macro]選項,將會彈出一個對話框,里面記錄著你現有的宏。在開始的時候里面應該沒有任何宏。
點擊對話框底部的”new”按鈕,將會彈出另外一個對話框,其中要求你輸入宏的名稱并且為這個宏選擇一個圖標。
給你的宏命名,選擇一個容易記憶的名字。例如,輸入“assist[協助]”。
選擇一個圖標。這里我們選擇的是一把劍。
點擊“Okay”按鈕。你現在能夠在你的宏對話框里看到這個宏的名稱(assist),在名稱的旁邊有你剛才選擇的圖標(劍)。
現在在assist[協助]圖標上點鼠標左鍵加亮它。除了“new”按鈕外,同時也有一個按鈕用來改變你的宏的名稱和圖標,以便你以后想改變它的名稱或者選擇一個不同的圖標。
一旦你的“assist”圖標是加亮狀態,你就可以向下移動你的鼠標指針進入“enter macro commands[輸入宏命令]的區域。在這里你可以輸入你想讓這個宏按鈕實現的命令。
輸入“/assist Nebu[協助Nebu]”。
現在移動你的鼠標指針回到劍的圖標(assist[協助]宏),在這個圖標上壓下鼠標的左鍵不鬆開。
現在拖動圖標到你的動作條的空槽里去。
當你要使用這個新的宏的時候,鍵入這個動作按鈕對應的數字或者直接右鍵點擊按鈕本身。
現在你擁有了一個宏按鈕,它將在其他玩家(Nebu)攻擊的時候協助他。無論何時,當Nebu攻擊目標的時候,點擊這個按鈕后你的目標將會變為他正在攻擊的目標。


以上是"魔獸台灣"給予MACRO的中文解釋,以及一個很簡單的例子.

現在讓我們稍微加強一下上面的例子.

上面的例子裡面,我們看到了MACRO的內容只有一行

/assist Nebu

現在我們來加強一下,讓這個MACRO不但會協助,還會馬上攻擊.改過的MACRO會像底下這樣.

/assist Nebu
/attack

好了,現在我們的MACRO有兩行了.這個MACRO的目的是,協助Nebu(指定Nebu的敵人),然後攻擊.

那麼現在讓我們寫一個很簡單以及實用的MACRO.加設Nebu是一個牧師,我們要幫Nebu寫一個自動幫自己使用基本治療的MACRO.

/target Nebu
/cast Lesser Heal(Rank 1)

以上的MACRO在執行的時候,每次都會選擇Nebu作為治療的對象.其中,/target Nebu 是選擇Nebu為對象,/cast Lesser Heal(Rank 1)是對於對象施展Lesser Heal第一級的法術.

我想以上的例子因該已經很清楚的解釋了基本的MACRO該如何使用.可是在在"魔獸台灣"的網頁裡也有提到:

宏的限制
宏是有長度限制的,如果你的信息太長了,就縮減一些!(顯然)

這一點是沒有錯的,因為WOW的MACRO有255個英文字元的限制.我們該如何突破這個限制呢?

首先讓我們先了解一下WOW的官方斜線指令.

上面那些MACRO裡所用到的斜線指令,其實背後都有呼叫一些核心指令.例如:

/assist Nebu 呼叫了 AssistUnit("Nebu")
/attack 呼叫了 Attack("Target")
/target Nebu 呼叫了 TargetByName("Nebu")
/cast Lesser Heal(Rank 1) 呼叫了 CastSpellByName("Lesser Heal(Rank 1)")

這些核心指令除了可以使用官方的斜線指令來呼叫之外,我們還有其他幾種方式來使用這些核心指令.

第一種方式,直接在MACRO裡使用這些核心指令.要直接使用這些核心指令,我們必須用到一個斜線指令叫做/Script.

以下是把上面的MACRO例子改成使用核心指令的方式.
第一個MACRO 幫助Nebu攻擊敵人
/Script AssistUnit("Nebu");
/Script Attack("Target");
第二個MACRO選擇Nebu作為治療的對象
/Script TargetByName("Nebu");
/Script CastSpellByName("Lesser Heal(Rank 1)");


要注意的一點是,當使用了/Script的時候,MACRO的每一行指令都要有";"作為結尾.

直接使用核心指令的好處是什麼?因為WOW並沒有幫每一個核心指令寫對應的斜線指令,而很多的核心指令的功能卻是非常強大的.

核心指令除了能直接利用在MACRO之外,另一個用途就是可以使用在模組裡面使用.關於使用上的例子,大家可以參考我前幾篇文章所提供的獵人輔助模組.在這裡我們就可以利用模組所提供的斜線指令來變相的突破了MACRO上面的字元限制了.

希望這一篇文章能更容易的讓大家了解斜線指令,核心指令,MACRO,以及模組的用途.

>※littlethe(東周小星星)提到:
>我是個programmer,
>macro在程式中是指巨集指令,
>若我沒有弄錯的話,
>這個macro是不是用於制定"連續動作"用的?
>
>按個鍵,
>人物就會做出連續預設動作,
>
>若是這樣,
>那wow可還真特別,
>開放玩家編寫macro,
>
>等我拿到wow時,
>要好好的來玩看看

恩~沒有錯喔

可是WOW本身的MACRO有很多的限制.可是如果玩家使用非遊戲本身的MACRO來玩WOW,暴風雪就可以砍此玩家的帳號.

WOW本身的MACRO先天上就沒有時間的設計.也就是說,MACRO裡面所有的動作指令,通通當作及時指令(當然,非常嚴格的來說還是會有先後順序上的差別,可是時間上的差別只有不到0.1秒.)這樣的設計是避免玩家製作機器人.

另外,WOW很多的技能有冷卻時間,如果把多個有冷卻時間的技能寫入MACRO,那麼MACRO只會執行第一個達到條件的技能,其他有冷卻時間的技能都會被忽略.
>※littlethe(東周小星星)提到:
>蝦米??
>那這樣的話,
>那豈不就不能使用連續法術了?
>法術也有cast time不是麼?
>還是wow的法術都是direct的?
>哇累...
>本來想說能不能來個先閃電再插補血丈後嗜血之類的


WOW的技能大約能分為三種,即時的,有冷卻時間的,需要施展時間的.

即時的就是可以一直連續使用.

有冷卻時間的就是在使用過後,有一個時間限制是不能使用同一招.另外,使用這種技能之後,還會有大約不到一秒的時間無法使用任何其他的技能.

需要施展時間的,當使用的時候,在技能完全施展之前,無法使用任何其他的技能,除非先取消掉.

所以只要是有被時間限制上的技能,在MACRO裡,就只有一個可以被驅動,而且最好是擺在MACRO的最後一行.如果擺在太前面,那麼很可能就會使得後面的即時技能被擋掉.

>※willllee(balmung)提到:
>那可以用macro來配合其他程式嗎?


使用任何不是魔獸紀元本身所提供的功能來執行遊戲,都違反了魔獸紀元的使用條約.所以我無法在這裡回答您所提出的其他的相關問題.


但是有一點可以確定的是,魔獸紀元所提供的核心指令,已經可以做出廣大的環境判斷了.包括判定血量多少,隊友以及其寵物的狀態,敵人的狀態,等等.

目前官方論壇上已經有很多的模組能提供類似的功能.包括當自身血量低於某百分比,執行動作的時候,會先幫自己補血(魔法或是物件,取決於是否在戰鬥中),以及根據隊友的血量百分比來決定寵物會先幫助哪個隊友攻擊.

如果有興趣的網友,甚至可以寫出根據敵人的狀態做出不同的攻擊或是反應的模組.

基本上,這些都可以只用到核心指令來達到的.




相关评论
wilimye 认为: 2005-02-21 23:29

不错..学习ing..

ps ck混的不错嘛 斑斑了..

ps又ps 头像是哀啊..来不来aptx4869.net的?
frankz 认为: 2005-02-22 00:51

正在认真学习ING!
killerking 认为: 2005-02-22 11:10

有些用起来貌似有点问题,
以前试牧师给自己加BUFF老不成功,也8知道哪有问题
ckone 认为: 2005-02-22 14:51

QUOTE:
下面是引用wilimye于2005-02-21 23:29发表的:
不错..学习ing..

ps ck混的不错嘛 斑斑了..

ps又ps 头像是哀啊..来不来aptx4869.net的?


卡卡
battlecn.net和这里是一个站的 我从哪里的非常技术来这里的非常技术又什么不好的
卡卡

aptx4869.net
卡卡 你没看到我的头像就是从哪里下的吗? 卡卡
ckone 认为: 2005-02-22 14:52

QUOTE:
下面是引用killerking于2005-02-22 11:10发表的:
有些用起来貌似有点问题,
以前试牧师给自己加BUFF老不成功,也8知道哪有问题


放出代码来看看撒...
wilimye 认为: 2005-02-22 15:21

QUOTE:
下面是引用ckone于2005-02-22 14:51发表的:


卡卡
battlecn.net和这里是一个站的 我从哪里的非常技术来这里的非常技术又什么不好的
卡卡
.......


晕..在那混了一年竟然没注意斑竹叫ckone..

再晕..做conan的又不是就一家 我怎么知道你说的是不是呢?
cure_steve 认为: 2005-02-24 19:04

这个要学习学习,eq好像有n多ui
天才人人 认为: 2005-02-24 21:18

QUOTE:
下面是引用killerking于2005-02-22 11:10发表的:
有些用起来貌似有点问题,
以前试牧师给自己加BUFF老不成功,也8知道哪有问题

给自己加buff不用去做宏了 大脚插件提供这个功能的 按住alt就行
billrun 认为: 2005-06-30 09:54

谢谢楼主 认真读完 晕倒 玩游戏也要coding
9条评论
编辑文章     论坛模式     联系作者     推荐给好友

发表评论 顶端
标题
参与评论



Powered by PHPWind v4.3.2 Code © 2003-05 PHPWind
Time is now:,

You can contact us