分享
 
 
 

WOW原始UI代码分析【ActionButton】

王朝other·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

开场白:

1、这是我分析WOW原始UI代码后,对一些比较关键的部分,记录下来的

2、文章里面如果有什么纰漏,希望大家毫不客气的提出来,我一定查究!

3、关于基础问题可以参考

WOW UI

《UI制作入门》http://www.pcgames.com.cn/netgames/zhuanti/wow/expert/Ui.htm

《WOW UI定制入门》http://202.113.13.169/site/mybbs/read.php?tid=33

《WOW插件制作指南》http://www.cnblogs.com/bluefee/archive/2005/04/14/137217.html

《ADDONS编写普及》http://wowbbs.game.mop.com/viewthread.php?tid=216755&extra=page%3D1

《动手写个属于自己的UI》http://wowbbs.game.mop.com/viewthread.php?tid=149814&fpage=1&highlight=

XML

《XML初学进阶》http://www.chinausd.com/code/code.asp?id=173/5058

《XMLSpy 2005 Enterprise Edition》http://www.altova.com/download_spy_enterprise.html

Lua

《Lua5.0参考手册中文版》http://www.cnblogs.com/bluefee/archive/2005/04/15/138576.html

《Lua 程序设计初步》http://bbs.battlecn.net/read.php?tid=541871&fpage=1

《通过例子学习Lua》http://www.wowtc.com/bbs/read.php?tid=4999&fpage=2

《Programming in LUA中文版》http://www.wowtc.com/bbs/read.php?tid=4998&fpage=2

《LuaEdit v2.5》http://luaforge.net/projects/luaedit/

4、关于如何提取MPQ文件,如何查看BLP图像,可以参考

《WoW Working Link》http://www.fukt.bth.se/%7Ek/wow/stuff/howto-extract-interface-files.txt

《Win MPQ》http://wow.duowan.com/2005-05-16/007R/26857843.html

《Win BLP Viewer》http://gamedown.yesky.com/game/108/108805.html

5、关于查询资料可以参考

《WoW Wiki》http://www.wowwiki.com/Interface_Customization/

《WOW APIs》http://www.cnblogs.com/bluefee/archive/2005/04/12/136270.html

《UI&Macro Forum》http://forums.worldofwarcraft.com/board.aspx?fn=wow-interface-customization

6、如果该问题是可以类推,或是从上下文能马上理解,或是从字面就知道含义的我就不罗嗦了

7、对于相同的问题我一般只分析一次,或是简要的提示一下,具体内容可以参考我以前的分析

8、如果你对自己查找资料的能力感到抱歉,可以E-mail向我询问,我会努力帮助你

9、联系方式E-mail: asdic.xxs@gmail.com Blog: blog.csdn.net/tcxxs QQ: 35548917

10、做人要厚道,转载请注明出处!

--------------------------------------------------

正式开始:

1、版本:1.7.1 (4659)

2、这次我写的是ActionbuttonTemplate.xml,ActionBarFrame.xml和ActionButton.lua

他们是动作按钮的基础UI,也是大家比较关心的一部分,在Interface/FrameXML里面

3、这次分析用到的名词解释:

【模板】学过C++语言的人都知道虚函数,实际上是一个道理,只是作为子代继承的规范,不可创建实例

【栅格】一个用来放置图标的格子,默认为无图标时隐藏,当然你也可以显示它

【额外栅格】包括了战士姿态,德鲁依外形,盗贼潜行的栅格

【栅格ID】每个栅格都有对应的ID,是该栅格的唯一标示

【图标】每个技能和物品,包括交易技能,食物,宏等都有一个可以拖动的图标

【动作键】当把图标放置到栅格上时,这个整体就叫动作键

【额外动作键】当把图标放置到额外栅格上时,这个整体就叫额外动作键

【动作条】一般12个栅格组成一排或者一列,称这个为动作条

【额外动作条】由12个额外栅格组成一排或者一列,称这个为额外动作条

【动作条ID】在默认动作条中每个动作条都有页码,是这个动作条的唯一标示

这里解释一下各个动作条的位置,主动作条包括1,2页

然后右边1,右边2,右下,左下依次为3到6页,栅格ID排列如图

61-72(左下)49-60(右下)37 25

(右边2) I I (右边1)

1-12(主AB)13-24(2页) 48 36

这里注意一个问题,为什么有的UI可以实现96个(FB,DUF等)或者更多呢

这是因为额外栅格的存在,这些UI把空闲的额外栅格加以利用罢了

调用这些额外栅格的动作键应该用其对应的函数

【闪动】当执行自动攻击或者自动射击技能时,改动作键就处于闪动状态

【CD】CoolDown的简写

【信息提示】即GameTooltip,当鼠标指向某个东西时显示的提示信息

【光环】包括buff,debuff,物品附加属性等

【arg1..N】arg为事件触发是传入的参数,可以为0到多个

--------------------------------------------

源代码及注释

-----------------------ActionButtonTemplate.xml

<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/

..\FrameXML\UI.xsd">

<CheckButton name="ActionButtonTemplate" virtual="true">

【动作键】【模板】

<Size>

<AbsDimension x="36" y="36"/>

</Size>

<Layers>

<Layer level="BACKGROUND">

<Texture name="$parentIcon"/>

背景层放置【图标】

</Layer>

<Layer level="ARTWORK">

层的从下到上为:BackGround,ArtWork,OverLay

<Texture name="$parentFlash" file="Interface\Buttons\UI-QuickslotRed" hidden="true"/>

【闪动】效果的纹理

<FontString name="$parentHotKey" inherits="NumberFontNormalSmallGray" justifyH="RIGHT">

该【动作键】的快捷键信息

<Size>

<AbsDimension x="32" y="10"/>

</Size>

<Anchors>

<Anchor point="TOPLEFT">

<Offset>

<AbsDimension x="2" y="-2"/>

</Offset>

</Anchor>

</Anchors>

</FontString>

<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT">

该【动作键】数量信息

<Anchors>

注意,这里没有Size标签,所以它为自动大小

<Anchor point="BOTTOMRIGHT">

<Offset>

<AbsDimension x="-2" y="2"/>

</Offset>

</Anchor>

</Anchors>

</FontString>

</Layer>

<Layer level="OVERLAY">

<FontString name="$parentName" inherits="GameFontHighlightSmallOutline">

该【动作键】名字,例如:宏的名字

<Size>

<AbsDimension x="36" y="10"/>

</Size>

<Anchors>

<Anchor point="BOTTOM">

<Offset>

<AbsDimension x="0" y="2"/>

</Offset>

</Anchor>

</Anchors>

</FontString>

</Layer>

</Layers>

<Frames>

<Model name="$parentCooldown" inherits="CooldownFrameTemplate"/>

直接应用【CD】模板,没有测试过,还望高人赐教,或者等我以后试

</Frames>

<NormalTexture name="$parentNormalTexture" file="Interface\Buttons\UI-Quickslot2">

【图标】边框纹理,如果该【栅格】已放置【图标】,则显示这个纹理

若没有放置,则显示UI-Quickslot,它比UI-Quickslot2稍微小点

<Size>

<AbsDimension x="64" y="64"/>

</Size>

<Anchors>

<Anchor point="CENTER">

<Offset>

<AbsDimension x="0" y="-1"/>

立体效果,而且UI-Quickslot的显示位置也依赖UI-Quickslot2

但是【图标】的实际放置位置却并不依赖这个位置,由BackGround层决定

</Offset>

</Anchor>

</Anchors>

</NormalTexture>

<PushedTexture file="Interface\Buttons\UI-Quickslot-Depress"/>

点击【动作键】时的纹理

<HighlightTexture alphaMode="ADD" file="Interface\Buttons\ButtonHilight-Square"/>

鼠标经过【栅格】时的纹理

<CheckedTexture alphaMode="ADD" file="Interface\Buttons\CheckButtonHilight"/>

等待施法时【栅格】的纹理,例如:你点击加血法术到选择目标那段时间显示

</CheckButton>

</Ui>

------------------------ActionBarFrame.xml

<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/

..\FrameXML\UI.xsd">

<Script file="ActionButton.lua"/>

<CheckButton name="ActionBarButtonTemplate" inherits="ActionButtonTemplate" virtual="true">

<Scripts>

<OnLoad>

ActionButton_OnLoad();

</OnLoad>

<OnEvent>

ActionButton_OnEvent(event);

</OnEvent>

<OnClick>

if ( IsShiftKeyDown() ) then

安住shift再点【动作键】,即拖拉【图标】

PickupAction(ActionButton_GetPagedID(this));

鼠标吸附该【图标】

else

否则执行该【动作键】命令

MacroFrame_EditMacro();

UseAction(ActionButton_GetPagedID(this), 1);

UseAction(slot [,checkCursor] [,onSelf])函数

slot参数为该【动作键】ID号

checkCursor参数为是否在其他事件中返回是鼠标点击,0或者1

onSelf参数为是否对自己施法,0或者1

end

ActionButton_UpdateState();

点击后应该更新【动作键】状态

</OnClick>

<OnDragStart>

if ( LOCK_ACTIONBAR ~= "1" ) then

如果【动作键】并未设定为锁定

PickupAction(ActionButton_GetPagedID(this));

ActionButton_UpdateState();

end

</OnDragStart>

<OnReceiveDrag>

if ( LOCK_ACTIONBAR ~= "1" ) then

PlaceAction(ActionButton_GetPagedID(this));

PlaceAction,放下鼠标上吸附的【动作键】

注意,这里并不要求一定要放在栅格上,因为你可以摧毁一个【动作键】

ActionButton_UpdateState();

end

</OnReceiveDrag>

<OnEnter>

ActionButton_SetTooltip();

经过【动作键】时,显示【信息提示】

</OnEnter>

<OnLeave>

this.updateTooltip = nil;

GameTooltip:Hide();

</OnLeave>

<OnUpdate>

ActionButton_OnUpdate(arg1);

更新【闪动】效果

</OnUpdate>

</Scripts>

</CheckButton>

下面定义了主【动作条】

<CheckButton name="ActionButton1" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="1">

MainMenuBarArtFrame,即默认最下面的一条工具栏,包括了主【动作条】,人物工具条,背包

但是注意,并不包括两旁的2只鹰的纹理

<Anchors>

<Anchor point="BOTTOMLEFT">

<Offset>

<AbsDimension x="8" y="4"/>

左下和右下的【动作条】都依据主【动作条】的位置

【信息提示】和【额外栅格】并不依据这个偏移,但是它会根据左下和右下【动作条】的出现而更改高度

若仅改变该偏移,则如果该人物有【额外栅格】,则人物的主【动作条】将会在原位又出现一个

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<CheckButton name="ActionButton2" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="2">

<Anchors>

<Anchor point="LEFT" relativeTo="ActionButton1" relativePoint="RIGHT">

<Offset>

<AbsDimension x="6" y="0"/>

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<CheckButton name="ActionButton3" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="3">

<Anchors>

<Anchor point="LEFT" relativeTo="ActionButton2" relativePoint="RIGHT">

<Offset>

<AbsDimension x="6" y="0"/>

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<CheckButton name="ActionButton4" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="4">

<Anchors>

<Anchor point="LEFT" relativeTo="ActionButton3" relativePoint="RIGHT">

<Offset>

<AbsDimension x="6" y="0"/>

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<CheckButton name="ActionButton5" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="5">

<Anchors>

<Anchor point="LEFT" relativeTo="ActionButton4" relativePoint="RIGHT">

<Offset>

<AbsDimension x="6" y="0"/>

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<CheckButton name="ActionButton6" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="6">

<Anchors>

<Anchor point="LEFT" relativeTo="ActionButton5" relativePoint="RIGHT">

<Offset>

<AbsDimension x="6" y="0"/>

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<CheckButton name="ActionButton7" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="7">

<Anchors>

<Anchor point="LEFT" relativeTo="ActionButton6" relativePoint="RIGHT">

<Offset>

<AbsDimension x="6" y="0"/>

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<CheckButton name="ActionButton8" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="8">

<Anchors>

<Anchor point="LEFT" relativeTo="ActionButton7" relativePoint="RIGHT">

<Offset>

<AbsDimension x="6" y="0"/>

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<CheckButton name="ActionButton9" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="9">

<Anchors>

<Anchor point="LEFT" relativeTo="ActionButton8" relativePoint="RIGHT">

<Offset>

<AbsDimension x="6" y="0"/>

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<CheckButton name="ActionButton10" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="10">

<Anchors>

<Anchor point="LEFT" relativeTo="ActionButton9" relativePoint="RIGHT">

<Offset>

<AbsDimension x="6" y="0"/>

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<CheckButton name="ActionButton11" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="11">

<Anchors>

<Anchor point="LEFT" relativeTo="ActionButton10" relativePoint="RIGHT">

<Offset>

<AbsDimension x="6" y="0"/>

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<CheckButton name="ActionButton12" inherits="ActionBarButtonTemplate" parent="MainMenuBarArtFrame" id="12">

<Anchors>

<Anchor point="LEFT" relativeTo="ActionButton11" relativePoint="RIGHT">

<Offset>

<AbsDimension x="6" y="0"/>

</Offset>

</Anchor>

</Anchors>

</CheckButton>

<Button name="ActionBarUpButton" parent="MainMenuBarArtFrame">

主【动作条】位置上的上翻页按钮

<Size>

<AbsDimension x="32" y="32"/>

</Size>

<Anchors>

<Anchor point="CENTER" relativeTo="MainMenuBarArtFrame" relativePoint="TOPLEFT">

<Offset>

<AbsDimension x="522" y="-22"/>

</Offset>

</Anchor>

</Anchors>

<HitRectInsets>

<AbsInset left="6" right="6" top="7" bottom="7"/>

这个一直没有测试成功,还望高人指点迷津

</HitRectInsets>

<Scripts>

<OnLoad>

MainMenuBarPageNumber:SetText(CURRENT_ACTIONBAR_PAGE);

CURRENT_ACTIONBAR_PAGE,当前【动作条ID】

当你显示了其他【动作条】如:左下【动作条】,那么它将不会在翻页中重复出现

this:RegisterEvent("ACTIONBAR_PAGE_CHANGED");

当主【动作条】的页码改变时触发

</OnLoad>

<OnEvent>

if ( event == "ACTIONBAR_PAGE_CHANGED" ) then

MainMenuBarPageNumber:SetText(CURRENT_ACTIONBAR_PAGE);

end

</OnEvent>

<OnClick>

ActionBar_PageUp();

PlaySound("UChatScrollButton");

PlaySound(SoundName),播放一个WOW内置的声音

SoundName为内置参数的名字,可以参考下面地址

http://www.wowwiki.com/API_PlaySound

注意,你不要试图在MPQ文件中找到这个名字

</OnClick>

</Scripts>

<NormalTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Up"/>

<PushedTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Down"/>

<DisabledTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Disabled"/>

被锁定时的纹理,未测试成功,望高人指点一二

<HighlightTexture alphaMode="ADD" file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Highlight"/>

</Button>

<Button name="ActionBarDownButton" parent="MainMenuBarArtFrame">

<Size>

<AbsDimension x="32" y="32"/>

</Size>

<Anchors>

<Anchor point="CENTER" relativeTo="MainMenuBarArtFrame" relativePoint="TOPLEFT">

<Offset>

<AbsDimension x="522" y="-42"/>

</Offset>

</Anchor>

</Anchors>

<HitRectInsets>

<AbsInset left="6" right="6" top="7" bottom="7"/>

</HitRectInsets>

<Scripts>

上翻中已经注册并处理了事件,这里不重复

<OnClick>

ActionBar_PageDown();

PlaySound("UChatScrollButton");

</OnClick>

</Scripts>

<NormalTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Up"/>

<PushedTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Down"/>

<DisabledTexture file="Interface\Buttons\UI-ScrollBar-ScrollDownButton-Disabled"/>

<HighlightTexture alphaMode="ADD" file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Highlight"/>

</Button>

</Ui>

------------------------ActionButton.lua

CURRENT_ACTIONBAR_PAGE = 1;

当前【动作条ID】

NUM_ACTIONBAR_PAGES = 6;

【动作条ID】总数

NUM_ACTIONBAR_BUTTONS = 12;

每个【动作条】的【动作键】数

ATTACK_BUTTON_FLASH_TIME = 0.4;

【闪动】效果时间间隔,为0.4S

BOTTOMLEFT_ACTIONBAR_PAGE = 6;

初始左下【动作条ID】

BOTTOMRIGHT_ACTIONBAR_PAGE = 5;

初始右下【动作条ID】

LEFT_ACTIONBAR_PAGE = 4;

初始右边2【动作条ID】

RIGHT_ACTIONBAR_PAGE = 3;

初始右边1【动作条ID】

-- Table of actionbar pages and whether they're viewable or not

VIEWABLE_ACTION_BAR_PAGES = {1, 1, 1, 1, 1, 1};

初始化为每页【动作条】都能够显示,0为隐藏

function ActionButtonDown(id)

实现按下【动作键】

if ( BonusActionBarFrame:IsVisible() ) then

如果是【额外动作键】

local button = getglobal("BonusActionButton"..id);

if ( button:GetButtonState() == "NORMAL" ) then

若未按下

button:SetButtonState("PUSHED");

end

return;

该函数用if-else是同样的

end

local button = getglobal("ActionButton"..id);

if ( button:GetButtonState() == "NORMAL" ) then

button:SetButtonState("PUSHED");

end

end

由上下2个函数可以看出,暴雪对【动作键】和【额外动作键】同样对待

这个也是其他UI可以利用【额外栅格】的基础

function ActionButtonUp(id, onSelf)

if ( BonusActionBarFrame:IsVisible() ) then

local button = getglobal("BonusActionButton"..id);

if ( button:GetButtonState() == "PUSHED" ) then

button:SetButtonState("NORMAL");

-- Used to save a macro

MacroFrame_EditMacro();

UseAction(ActionButton_GetPagedID(button), 0);

if ( IsCurrentAction(ActionButton_GetPagedID(button)) ) then

IsCurrentAction,等待施法,并不是正在吟唱

button:SetChecked(1);

设定该【动作键】正处于等待状态

else

button:SetChecked(0);

end

end

return;

end

local button = getglobal("ActionButton"..id);

if ( button:GetButtonState() == "PUSHED" ) then

button:SetButtonState("NORMAL");

-- Used to save a macro

MacroFrame_EditMacro();

UseAction(ActionButton_GetPagedID(button), 0, onSelf);

if ( IsCurrentAction(ActionButton_GetPagedID(button)) ) then

button:SetChecked(1);

else

button:SetChecked(0);

end

end

end

function ActionBar_PageUp()

CURRENT_ACTIONBAR_PAGE = CURRENT_ACTIONBAR_PAGE + 1;

local nextPage;

for i=CURRENT_ACTIONBAR_PAGE, NUM_ACTIONBAR_PAGES do

if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then

如果该页能显示

nextPage = i;

break;

end

end

if ( not nextPage ) then

如果没有找到能够显示的下一页

CURRENT_ACTIONBAR_PAGE = 1;

else

CURRENT_ACTIONBAR_PAGE = nextPage;

end

ChangeActionBarPage();

这个函数变换将当主【动作条】变换到CURRENT_ACTIONBAR_PAGE指向的【动作条】

end

function ActionBar_PageDown()

CURRENT_ACTIONBAR_PAGE = CURRENT_ACTIONBAR_PAGE - 1;

local prevPage;

for i=CURRENT_ACTIONBAR_PAGE, 1, -1 do

if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then

prevPage = i;

break;

end

end

if ( not prevPage ) then

for i=NUM_ACTIONBAR_PAGES, 1, -1 do

把“1”换成“CURRENT_ACTIONBAR_PAGE+1”也是可以的

把这个for循环对比ActionBar_PageUp的同一地方

可见,暴雪员工相当的肯定在上翻的时候第1页是可以显示的

而在下翻的时候显得信心不足,还重复检查了一次NUM_ACTIONBAR_PAGES到CURRENT_ACTIONBAR_PAGE

这是因为左下、右下AB的出现只是修改5,6页的可见性,并不影响1页的可见性

所以在下翻的时候需要对1到6页均做可见性检查

但是,重复检查的区间的确是多余的,估计是暴雪员工偷懒

因为“1”比“CURRENT_ACTIONBAR_PAGE+1”要好写得多

if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then

prevPage = i;

break;

end

end

end

CURRENT_ACTIONBAR_PAGE = prevPage;

ChangeActionBarPage();

end

function ActionButton_OnLoad()

this.showgrid = 0;

显示空【栅格】的标志

this.flashing = 0;

处于【闪动】的标志

this.flashtime = 0;

【闪动】时间间隔计算的中间量

ActionButton_Update();

this:RegisterForDrag("LeftButton", "RightButton");

对this所指向的窗体注册鼠标拖拉行为,参数至少一个,也可以注册多个

参数为LeftButton,RightButton,表示使用某个鼠标键执行

this:RegisterForClicks("LeftButtonUp", "RightButtonUp");

对this所指向的窗体注册鼠标点击行为,参数至少一个,也可以注册多个

参数为LeftButtonDown,LeftButtonUp,RightButtonDown,RightButtonUp

注意,在OnClick标签中传入的arg1参数只返回LeftButton或者RightButton

this:RegisterEvent("PLAYER_ENTERING_WORLD");

this:RegisterEvent("UPDATE_BONUS_ACTIONBAR");

当【额外栅格】更新时触发

this:RegisterEvent("ACTIONBAR_SHOWGRID");

当拖拉【图标】时触发,arg1为LeftButton或者RightButton

this:RegisterEvent("ACTIONBAR_HIDEGRID");

当停止拖拉【图标】时触发

this:RegisterEvent("ACTIONBAR_PAGE_CHANGED");

this:RegisterEvent("ACTIONBAR_SLOT_CHANGED");

当【栅格】内容变更时触发,arg1为变更【栅格ID】

this:RegisterEvent("ACTIONBAR_UPDATE_STATE");

当【栅格】状态更新时触发,包括了【CD】和可用性鉴定

但是不包括自动攻击和自动射击事件

arg1为鼠标LeftButton,RightButton,也可能为nil

this:RegisterEvent("ACTIONBAR_UPDATE_USABLE");

当更新【图标】可用性后触发

this:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");

当更新【CD】后触发

当【CD】开始的时候,arg1返回使用的鼠标按钮LeftButton或者RightButton

当【CD】结束的时候,arg1返回nil

this:RegisterEvent("UPDATE_INVENTORY_ALERTS");

当变更装备时或者经过一定时间后触发

this:RegisterEvent("PLAYER_AURAS_CHANGED");

当玩家【光环】改变时触发,包括了【光环】的消失和出现

注意,属性完全相同【光环】重复释放并不能触发该事件

this:RegisterEvent("PLAYER_TARGET_CHANGED");

当玩家的目标变更时触发,包括取消和选定目标

arg1为该目标持续时间,单位分钟,小数保留3位

this:RegisterEvent("UNIT_AURASTATE");

当某单位短时间【光环】改变时触发,需进一步测试

this:RegisterEvent("UNIT_INVENTORY_CHANGED");

当玩家装备变更时或者当观察玩家装备并发生装备变更时触发

this:RegisterEvent("CRAFT_SHOW");

this:RegisterEvent("CRAFT_CLOSE");

工艺窗口的显示与关闭,arg1为鼠标点击键

this:RegisterEvent("TRADE_SKILL_SHOW");

this:RegisterEvent("TRADE_SKILL_CLOSE");

交易技能制作物品窗口的显示与关闭,arg1为鼠标点击键

this:RegisterEvent("UNIT_HEALTH");

当任何一个单位的血量发生变化时触发,arg1参数为该单位ID

player,pet,target,mouseover,party1..4,partypet1..4,raid1..40,raidpet1..40,npc

注意,该事件拥有很高的优先级,特别当参数为player时

this:RegisterEvent("UNIT_MANA");

当任何一个单位的魔法量发生变化时触发,arg1参数为该单位ID

this:RegisterEvent("UNIT_RAGE");

当任何一个单位的怒气值发生变化时触发,arg1参数为该单位ID

this:RegisterEvent("UNIT_FOCUS");

当任何一个单位的焦距值发生变化时触发,arg1参数为该单位ID

注意,该事件实际上已经废除,因为现在猎人使用MANA,而不是FOCUS

this:RegisterEvent("UNIT_ENERGY");

当任何一个单位的能量发生变化时触发,arg1参数为该单位ID

this:RegisterEvent("PLAYER_ENTER_COMBAT");

当玩家进入自动攻击状态时触发,自动射击不包括在内

注意,仅当你使用自动攻击时触发该事件

使用其他任何技能或者攻击行为都不可触发

this:RegisterEvent("PLAYER_LEAVE_COMBAT");

离开自动攻击状态或者死亡时触发

this:RegisterEvent("PLAYER_COMBO_POINTS");

当连击点变更时触发,arg1总返回player,而并不时连击点数

this:RegisterEvent("UPDATE_BINDINGS");

当快捷键更改时触发

this:RegisterEvent("START_AUTOREPEAT_SPELL");

当自动射击开始时触发,而不是自动攻击

this:RegisterEvent("STOP_AUTOREPEAT_SPELL");

离开自动射击状态或者死亡时触发

ActionButton_UpdateHotkeys();

end

function ActionButton_UpdateHotkeys(actionButtonType)

if ( not actionButtonType ) then

actionButtonType = "ACTIONBUTTON";

end

local hotkey = getglobal(this:GetName().."HotKey");

该对象在模板中为Fontstring

local action = actionButtonType..this:GetID();

actionButtonType,为该类命令的名字

this:GetID,得到该命令在该类中的ID号

注意,这2个字符串组成了最终的命令的名字

如NUMPAD2,NUMPAD为类型,2为ID

但是有些类型就一个命令无ID,如LEFT

hotkey:SetText(KeyBindingFrame_GetLocalizedName(GetBindingKey(action), "KEY_"));

GetBindingKey得到命令的快捷键名字,后面加上KEY_是为了显示命令的字串

例如:KEY_NUMPAD2就显示为“数字键盘2”

KeyBindingFrame_GetLocalizedName,由这个函数在快捷键窗口中显示该命令的快捷键

end

function ActionButton_Update()

-- Special case code for bonus bar buttons

-- Prevents the button from updating if the bonusbar is still in an animation transition

if ( this.isBonus and this.inTransition ) then

ActionButton_UpdateUsable();

ActionButton_UpdateCooldown();

return;

end

local icon = getglobal(this:GetName().."Icon");

local buttonCooldown = getglobal(this:GetName().."Cooldown");

local texture = GetActionTexture(ActionButton_GetPagedID(this));

if ( texture ) then

icon:SetTexture(texture);

icon:Show();

如果该【栅格】有【图标】,即若为【动作键】则显示

this.rangeTimer = TOOLTIP_UPDATE_TIME;

每隔TOOLTIP_UPDATE_TIME事件间隔更新一次距离信息

TOOLTIP_UPDATE_TIME为0.2S

this:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2");

-- Save texture if the button is a bonus button, will be needed later

if ( this.isBonus ) then

判断自己是否为【额外栅格】

this.texture = texture;

end

else

icon:Hide();

buttonCooldown:Hide();

this.rangeTimer = nil;

this:SetNormalTexture("Interface\\Buttons\\UI-Quickslot");

getglobal(this:GetName().."HotKey"):SetVertexColor(0.6, 0.6, 0.6);

end

ActionButton_UpdateCount();

if ( HasAction(ActionButton_GetPagedID(this)) ) then

判断该【栅格】是否有【图标】,即是否为【动作键】

this:Show();

ActionButton_UpdateState();

ActionButton_UpdateUsable();

ActionButton_UpdateCooldown();

ActionButton_UpdateFlash();

elseif ( this.showgrid == 0 ) then

this:Hide();

else

这里表示,当该【栅格】没有【图标】

但是显示空【栅格】选项开启时,不显示公共CD效果

buttonCooldown:Hide();

end

if ( GameTooltip:IsOwned(this) ) then

判断该【动作键】是否拥有【信息提示】

ActionButton_SetTooltip();

else

this.updateTooltip = nil;

end

-- Update Macro Text

local macroName = getglobal(this:GetName().."Name");

macroName:SetText(GetActionText(ActionButton_GetPagedID(this)));

GetActionText返回宏的名字

end

function ActionButton_ShowGrid(button)

if ( not button ) then

button = this;

end

button.showgrid = button.showgrid+1;

getglobal(button:GetName().."NormalTexture"):SetVertexColor(1.0, 1.0, 1.0, 0.5);

SetVertexColor(R,G,B)这个函数需要注意,可能学过3D的都知道,这个是顶点着色,取值0到1小数

顶点着色并不是直接设置RGB的数值,而是在原有的RGB数值上乘以顶点着色指定的RGB百分比修正值

例如:一个色块RGB为50,100,30,如果你写入SetVertexColor(0.5,0,1),结果RGB为25,0,30

button:Show();

end

function ActionButton_HideGrid(button)

if ( not button ) then

button = this;

end

button.showgrid = button.showgrid-1;

if ( button.showgrid == 0 and not HasAction(ActionButton_GetPagedID(button)) ) then

把这里判断showgrid变量为0和这一对函数对showgrid的操作联系起来看

就像是用堆栈实现括号配对一样保证了显示和隐藏的规范

button:Hide();

end

end

function ActionButton_UpdateState()

if ( IsCurrentAction(ActionButton_GetPagedID(this)) or IsAutoRepeatAction(ActionButton_GetPagedID(this)) ) then

IsAutoRepeatAction,自动射击

IsAttackAction,自动攻击

this:SetChecked(1);

else

this:SetChecked(0);

end

end

function ActionButton_UpdateUsable()

注意,这个函数的主体是个技能按钮模板,所以针对的是一个【动作键】

所以,当你拖动某个【图标】时,其他【图标】并不会跟着更新

local icon = getglobal(this:GetName().."Icon");

模板中定义

local normalTexture = getglobal(this:GetName().."NormalTexture");

local isUsable, notEnoughMana = IsUsableAction(ActionButton_GetPagedID(this));

得到当前技能栅格的ID,这个是所有栅格ID号,包括73~96的

if ( isUsable ) then

是否在射程,当前在其他游戏规则中是否可用,是否在CD等

icon:SetVertexColor(1.0, 1.0, 1.0);

normalTexture:SetVertexColor(1.0, 1.0, 1.0);

elseif ( notEnoughMana ) then

是否足够魔法、怒气、能量

icon:SetVertexColor(0.5, 0.5, 1.0);

normalTexture:SetVertexColor(0.5, 0.5, 1.0);

else

icon:SetVertexColor(0.4, 0.4, 0.4);

这个是灰色效果,当你拖拉【图标】时,原【栅格】则为这个效果

normalTexture:SetVertexColor(1.0, 1.0, 1.0);

end

end

function ActionButton_UpdateCount()

local text = getglobal(this:GetName().."Count");

在模板中数量为Fontstring

if ( IsConsumableAction(ActionButton_GetPagedID(this)) ) then

判断是否改【栅格】的物品为消费品

text:SetText(GetActionCount(ActionButton_GetPagedID(this)));

else

text:SetText("");

end

end

function ActionButton_UpdateCooldown()

local cooldown = getglobal(this:GetName().."Cooldown");

在模板中该【CD】定义为一个Model

local start, duration, enable = GetActionCooldown(ActionButton_GetPagedID(this));

CooldownFrame_SetTimer(cooldown, start, duration, enable);

end

function ActionButton_OnEvent(event)

if ( event == "ACTIONBAR_SLOT_CHANGED" ) then

if ( arg1 == -1 or arg1 == ActionButton_GetPagedID(this) ) then

如果变更的【栅格】不明或者变更的【栅格】为自己则更新

ActionButton_Update();

end

return;

end

if ( event == "PLAYER_ENTERING_WORLD" or event == "ACTIONBAR_PAGE_CHANGED" ) then

总结起来是,当游戏环境有大的变化时,更新自己

ActionButton_Update();

return;

end

if ( event == "UPDATE_BONUS_ACTIONBAR" ) then

if ( this.isBonus ) then

ActionButton_Update();

end

return;

end

if ( event == "ACTIONBAR_SHOWGRID" ) then

ActionButton_ShowGrid();

return;

end

if ( event == "ACTIONBAR_HIDEGRID" ) then

ActionButton_HideGrid();

return;

end

if ( event == "UPDATE_BINDINGS" ) then

ActionButton_UpdateHotkeys();

return;

end

-- All event handlers below this line MUST only be valid when the button is visible

if ( not this:IsVisible() ) then

如果该【图标】不可见,那么直接返回,即下面的所有事件均要求该【图标】可见,即应该为一个【动作键】

return;

end

if ( event == "UNIT_HEALTH" or event == "UNIT_MANA" or event == "UNIT_RAGE" or event == "UNIT_FOCUS" or event == "UNIT_ENERGY" ) then

if ( arg1 == "player" ) then

如果发生在玩家身上,应该判断所有技能的可用性

ActionButton_UpdateUsable();

end

elseif ( event == "PLAYER_TARGET_CHANGED" or event == "PLAYER_AURAS_CHANGED" ) then

ActionButton_UpdateUsable();

elseif ( event == "UNIT_AURASTATE" ) then

if ( arg1 == "player" or arg1 == "target" ) then

ActionButton_UpdateUsable();

end

elseif ( event == "UNIT_INVENTORY_CHANGED" ) then

if ( arg1 == "player" ) then

ActionButton_Update();

end

elseif ( event == "ACTIONBAR_UPDATE_STATE" ) then

ActionButton_UpdateState();

elseif ( event == "ACTIONBAR_UPDATE_USABLE" or event == "UPDATE_INVENTORY_ALERTS" or event == "ACTIONBAR_UPDATE_COOLDOWN" ) then

ActionButton_UpdateUsable();

ActionButton_UpdateCooldown();

elseif ( event == "CRAFT_SHOW" or event == "CRAFT_CLOSE" or event == "TRADE_SKILL_SHOW" or event == "TRADE_SKILL_CLOSE" ) then

ActionButton_UpdateState();

elseif ( event == "PLAYER_ENTER_COMBAT" ) then

if ( IsAttackAction(ActionButton_GetPagedID(this)) ) then

ActionButton_StartFlash();

end

elseif ( event == "PLAYER_LEAVE_COMBAT" ) then

if ( IsAttackAction(ActionButton_GetPagedID(this)) ) then

ActionButton_StopFlash();

end

elseif ( event == "PLAYER_COMBO_POINTS" ) then

ActionButton_UpdateUsable();

elseif ( event == "START_AUTOREPEAT_SPELL" ) then

if ( IsAutoRepeatAction(ActionButton_GetPagedID(this)) ) then

ActionButton_StartFlash();

end

elseif ( event == "STOP_AUTOREPEAT_SPELL" ) then

if ( ActionButton_IsFlashing() and not IsAttackAction(ActionButton_GetPagedID(this)) ) then

如果该技能在【闪动】,并且不是自动攻击

ActionButton_StopFlash();

end

end

end

function ActionButton_SetTooltip()

if ( GetCVar("UberTooltips") == "1" ) then

Uber,乳房。。。。。

这句应该是判断是否属于一般类型,母类型

UberTooltips详细信息提示

GameTooltip_SetDefaultAnchor(GameTooltip, this);

一般位于屏幕右下角,会根据【动作条】的多少自动改变位置

else

如果这个【栅格】的【信息提示】不属于默认的形式则

if ( this:GetParent() == MultiBarBottomRight or this:GetParent() == MultiBarRight or this:GetParent() == MultiBarLeft ) then

【动作条】MultiBarBottomRight右下,MultiBarRight右方,MultiBarLeft左边下

GameTooltip:SetOwner(this, "ANCHOR_LEFT");

这里解释下SetOwner函数,GameTooltip:SetOwner(owner, anchor);

其中owner是参照物,anchor是对齐方式,取值如下:

ANCHOR_TOPRIGHT 相当于 SetPoint("BOTTOMRIGHT",object,"TOPRIGHT")

ANCHOR_RIGHT 相当于 SetPoint("BOTTOMLEFT",object,"TOPRIGHT")

ANCHOR_BOTTOMRIGHT 相当于 SetPoint("TOPLEFT",object,"BOTTOMRIGHT")

ANCHOR_TOPLEFT 相当于 SetPoint("BOTTOMLEFT",object,"TOPLEFT")

ANCHOR_LEFT 相当于 SetPoint("BOTTOMRIGHT",object,"TOPLEFT")

ANCHOR_BOTTOMLEFT 相当于 SetPoint("TOPRIGHT",object,"BOTTOMLEFT")

else

GameTooltip:SetOwner(this, "ANCHOR_RIGHT");

end

end

if ( GameTooltip:SetAction(ActionButton_GetPagedID(this)) ) then

SetAction,返回值为该【信息提示】是否需要实时更新

this.updateTooltip = TOOLTIP_UPDATE_TIME;

else

this.updateTooltip = nil;

end

end

function ActionButton_OnUpdate(elapsed)

if ( ActionButton_IsFlashing() ) then

this.flashtime = this.flashtime - elapsed;

if ( this.flashtime <= 0 ) then

flashtime初始为0,即第一次flash的时间并不为0.4,而是第一个elapsed决定

local overtime = -this.flashtime;

overtime,该函数的一个中间量,用语变化符号

if ( overtime >= ATTACK_BUTTON_FLASH_TIME ) then

这个if为了下面给flashtime更新是不出现负数考虑

注意,ERROR文本框的文本并不和这里的时间挂钩

overtime = 0;

end

this.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime;

更新flashtime,使得从第二次开始间隔一个ATTACK_BUTTON_FLASH_TIME

local flashTexture = getglobal(this:GetName().."Flash");

if ( flashTexture:IsVisible() ) then

效果的实现即为反复显示这个flash纹理

flashTexture:Hide();

else

flashTexture:Show();

end

end

end

-- Handle range indicator

if ( this.rangeTimer ) then

if ( this.rangeTimer < 0 ) then

local count = getglobal(this:GetName().."HotKey");

if ( IsActionInRange( ActionButton_GetPagedID(this)) == 0 ) then

IsActionInRange,返回指定【动作键】是否在距离之内

返回nil表示该【栅格】无【图标】,或者没有选定目标

返回0表示不在距离之内,返回1表示在距离之内

注意,如果你没有试图释放这个【动作键】在目标身上,它可能总返回1

count:SetVertexColor(1.0, 0.1, 0.1);

else

count:SetVertexColor(0.6, 0.6, 0.6);

end

this.rangeTimer = TOOLTIP_UPDATE_TIME;

else

this.rangeTimer = this.rangeTimer - elapsed;

end

end

if ( not this.updateTooltip ) then

return;

end

this.updateTooltip = this.updateTooltip - elapsed;

if ( this.updateTooltip > 0 ) then

return;

end

if ( GameTooltip:IsOwned(this) ) then

ActionButton_SetTooltip();

else

this.updateTooltip = nil;

end

end

function ActionButton_GetPagedID(button)

if( button == nil ) then

message("nil button passed into ActionButton_GetPagedID(), contact Jeff");

严重错误需要弹出消息框

return 0;

end

if ( button.isBonus and CURRENT_ACTIONBAR_PAGE == 1 ) then

如果是【额外动作条】并且当前【动作条ID】为1

local offset = GetBonusBarOffset();

GetBonusBarOffset,得到【额外动作条】的偏移量

返回1到3,分别对应1到3号战士姿态,或者德鲁依外形,或者是盗贼状态

if ( offset == 0 and BonusActionBarFrame and BonusActionBarFrame.lastBonusBar ) then

应该是判断当意外失去【额外动作条】定位时,定位于最近一次改变的

注意,如果该职业无【额外动作条】时,偏移量也为0

offset = BonusActionBarFrame.lastBonusBar;

end

return (button:GetID() + ((NUM_ACTIONBAR_PAGES + offset - 1) * NUM_ACTIONBAR_BUTTONS));

注意NUM_ACTIONBAR_PAGES + offset用的是加法,所以我们肯定暴雪偷偷藏了24个【额外栅格】

elseif ( button:GetParent():GetName() == "MultiBarBottomLeft" ) then

return (button:GetID() + ((BOTTOMLEFT_ACTIONBAR_PAGE - 1) * NUM_ACTIONBAR_BUTTONS));

elseif ( button:GetParent():GetName() == "MultiBarBottomRight" ) then

return (button:GetID() + ((BOTTOMRIGHT_ACTIONBAR_PAGE - 1) * NUM_ACTIONBAR_BUTTONS));

elseif ( button:GetParent():GetName() == "MultiBarLeft" ) then

return (button:GetID() + ((LEFT_ACTIONBAR_PAGE - 1) * NUM_ACTIONBAR_BUTTONS));

elseif ( button:GetParent():GetName() == "MultiBarRight" ) then

return (button:GetID() + ((RIGHT_ACTIONBAR_PAGE - 1) * NUM_ACTIONBAR_BUTTONS));

else

return (button:GetID() + ((CURRENT_ACTIONBAR_PAGE - 1) * NUM_ACTIONBAR_BUTTONS))

end

end

function ActionButton_UpdateFlash()

local pagedID = ActionButton_GetPagedID(this);

if ( (IsAttackAction(pagedID) and IsCurrentAction(pagedID)) or IsAutoRepeatAction(pagedID) ) then

ActionButton_StartFlash();

else

ActionButton_StopFlash();

end

end

function ActionButton_StartFlash()

this.flashing = 1;

this.flashtime = 0;

ActionButton_UpdateState();

end

function ActionButton_StopFlash()

this.flashing = 0;

getglobal(this:GetName().."Flash"):Hide();

ActionButton_UpdateState();

end

function ActionButton_IsFlashing()

if ( this.flashing == 1 ) then

return 1;

else

return nil;

end

end

---------------------总结一下

常量

TOOLTIP_UPDATE_TIME 【信息提示】更新间隔

CURRENT_ACTIONBAR_PAGE 当前【动作条ID】

NUM_ACTIONBAR_PAGES 总页码

NUM_ACTIONBAR_BUTTONS 一个【动作条】的【栅格】数

ATTACK_BUTTON_FLASH_TIME 【闪动】间隔

BOTTOMLEFT_ACTIONBAR_PAGE 左下【动作条ID】

BOTTOMRIGHT_ACTIONBAR_PAGE 右下【动作条ID】

LEFT_ACTIONBAR_PAGE 右边2【动作条ID】

RIGHT_ACTIONBAR_PAGE 右边1【动作条ID】

事件

ACTIONBAR_PAGE_CHANGED 【动作条】翻页

UPDATE_BONUS_ACTIONBAR 【额外动作条】更新

ACTIONBAR_SHOWGRID 显示【栅格】

ACTIONBAR_HIDEGRID 隐藏【栅格】

ACTIONBAR_SLOT_CHANGED 【栅格】内容变更

ACTIONBAR_UPDATE_STATE 【动作键】更新状态

ACTIONBAR_UPDATE_USABLE 【动作键】更新可用性

ACTIONBAR_UPDATE_COOLDOWN 【动作键】更新【CD】

UPDATE_INVENTORY_ALERTS 装备警告

PLAYER_AURAS_CHANGED 【光环】改变

PLAYER_TARGET_CHANGED 目标改变

UNIT_AURASTATE 单位【光环】改变

UNIT_INVENTORY_CHANGED 单位装备改变

CRAFT_SHOW 工艺窗口显示

CRAFT_CLOSE 工艺窗口隐藏

TRADE_SKILL_SHOW 交易技能窗口显示

TRADE_SKILL_CLOSE 交易技能窗口隐藏

UNIT_HEALTH 单位血量改变(优先级极高)

UNIT_MANA 单位魔法改变

UNIT_RAGE 单位怒气改变

UNIT_FOCUS 单位焦距改变(已废除)

UNIT_ENERGY 单位能量改变

PLAYER_ENTER_COMBAT 开始自动攻击

PLAYER_LEAVE_COMBAT 结束自动攻击

PLAYER_COMBO_POINTS 连击点改变

UPDATE_BINDINGS 快捷键更新

START_AUTOREPEAT_SPELL 开始自动射击

STOP_AUTOREPEAT_SPELL 结束自动射击

函数

IsShiftKeyDown Shift键是否按下

PickupAction 吸附【图标】

PlaceAction 放置【图标】

UseAction 使用【动作键】

GetButtonState 得到【动作键】状态

SetButtonState 设置【动作键】状态

Frame:RegisterForDrag 注册拖拉行为

Frame:RegisterForClicks 注册点击行为

GetBindingKey 得到快捷键

HasAction 【栅格】是否放置了【图标】

Frame:SetVertexColor 顶点色彩修正

IsAutoRepeatAction 是否正在自动射击

IsAttackAction 是否正在自动攻击

IsUsableAction 【动作键】是否可用

IsConsumableAction 是否为消费品

GetActionCooldown 得到【CD】

GetCVar 有待测试

GameTooltip:SetAction 设置【信息提示】

Frame:IsVisible 是否可见

IsActionInRange 是否在距离之内

GetBonusBarOffset 得到【额外动作条】偏移量

累死了。。。。。。明天再贴图片和排版彩色

http://wowbbs.game.mop.com/forumdisplay.php?fid=138

这个帖子我已经贴了图片

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有