mirror of
https://github.com/edubart/otclient.git
synced 2025-09-14 23:03:34 +02:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8536c61c01 | ||
![]() |
a83be17bfe | ||
![]() |
261dd40b96 | ||
![]() |
eae002ea71 | ||
![]() |
f0e9cf070e | ||
![]() |
5756f20026 | ||
![]() |
fa8b77f0c8 | ||
![]() |
ced5c035b9 | ||
![]() |
526885f70d | ||
![]() |
6c2539bbd4 | ||
![]() |
737001264d |
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(otclient)
|
||||
|
||||
set(VERSION "0.5.3")
|
||||
set(VERSION "0.5.4")
|
||||
|
||||
set(FRAMEWORK_SOUND ON)
|
||||
set(FRAMEWORK_GRAPHICS ON)
|
||||
|
@@ -31,7 +31,8 @@ In short, if you need to compile OTClient, follow these tutorials:
|
||||
|
||||
### Need help?
|
||||
|
||||
Try to ask questions in [otland](http://otland.net/forum.php) or talk with us at #otclient irc.freenode.net
|
||||
Try to ask questions in [otland](http://otland.net/f494/), now we have a board for the project there,
|
||||
or talk with us at #otclient irc.freenode.net
|
||||
|
||||
### Bugs
|
||||
|
||||
|
@@ -71,6 +71,7 @@ function UIScrollArea:setVerticalScrollBar(scrollbar)
|
||||
local virtualOffset = self:getVirtualOffset()
|
||||
virtualOffset.y = value
|
||||
self:setVirtualOffset(virtualOffset)
|
||||
if self.onScrollbarChange then self:onScrollbarChange(value) end
|
||||
end
|
||||
self:updateScrollBars()
|
||||
end
|
||||
@@ -81,6 +82,7 @@ function UIScrollArea:setHorizontalScrollBar(scrollbar)
|
||||
local virtualOffset = self:getVirtualOffset()
|
||||
virtualOffset.x = value
|
||||
self:setVirtualOffset(virtualOffset)
|
||||
if self.onScrollbarChange then self:onScrollbarChange(value) end
|
||||
end
|
||||
self:updateScrollBars()
|
||||
end
|
||||
|
@@ -41,6 +41,7 @@ function init()
|
||||
connect(Creature, {
|
||||
onSkullChange = updateCreatureSkull,
|
||||
onEmblemChange = updateCreatureEmblem,
|
||||
onOutfitChange = onCreatureOutfitChange,
|
||||
onHealthPercentChange = onCreatureHealthPercentChange,
|
||||
onPositionChange = onCreaturePositionChange,
|
||||
onAppear = onCreatureAppear,
|
||||
@@ -67,6 +68,7 @@ function terminate()
|
||||
disconnect(Creature, {
|
||||
onSkullChange = updateCreatureSkull,
|
||||
onEmblemChange = updateCreatureEmblem,
|
||||
onOutfitChange = onCreatureOutfitChange,
|
||||
onHealthPercentChange = onCreatureHealthPercentChange,
|
||||
onPositionChange = onCreaturePositionChange,
|
||||
onAppear = onCreatureAppear,
|
||||
@@ -126,6 +128,8 @@ function doCreatureFitFilters(creature)
|
||||
return false
|
||||
end
|
||||
|
||||
if not creature:canBeSeen() then return false end
|
||||
|
||||
local hidePlayers = hidePlayersButton:isChecked()
|
||||
local hideNPCs = hideNPCsButton:isChecked()
|
||||
local hideMonsters = hideMonstersButton:isChecked()
|
||||
@@ -168,9 +172,17 @@ function onCreaturePositionChange(creature, newPos, oldPos)
|
||||
end
|
||||
end
|
||||
|
||||
function onCreatureOutfitChange(creature, outfit, oldOutfit)
|
||||
if not creature:canBeSeen() then
|
||||
removeCreature(creature)
|
||||
elseif doCreatureFitFilters(creature) then
|
||||
removeCreature(creature)
|
||||
addCreature(creature)
|
||||
end
|
||||
end
|
||||
|
||||
function onCreatureAppear(creature)
|
||||
local player = g_game.getLocalPlayer()
|
||||
if creature ~= player and creature:getPosition().z == player:getPosition().z and doCreatureFitFilters(creature) then
|
||||
if doCreatureFitFilters(creature) then
|
||||
addCreature(creature)
|
||||
end
|
||||
end
|
||||
|
@@ -271,6 +271,38 @@ function addText(text, speaktype, tabName, creatureName)
|
||||
end
|
||||
end
|
||||
|
||||
-- Contains letter width for font "verdana-11px-antialised" as console is based on it
|
||||
local letterWidth = {
|
||||
[32] = 4, [33] = 3, [34] = 6, [35] = 8, [36] = 7, [37] = 13, [38] = 9, [39] = 3, [40] = 5, [41] = 5, [42] = 6, [43] = 8, [44] = 4, [45] = 5, [46] = 3, [47] = 8,
|
||||
[48] = 7, [49] = 6, [50] = 7, [51] = 7, [52] = 7, [53] = 7, [54] = 7, [55] = 7, [56] = 7, [57] = 7, [58] = 3, [59] = 4, [60] = 8, [61] = 8, [62] = 8, [63] = 6,
|
||||
[64] = 10, [65] = 9, [66] = 7, [67] = 7, [68] = 8, [69] = 7, [70] = 7, [71] = 8, [72] = 8, [73] = 5, [74] = 5, [75] = 7, [76] = 7, [77] = 9, [78] = 8, [79] = 8,
|
||||
[80] = 7, [81] = 8, [82] = 8, [83] = 7, [84] = 8, [85] = 8, [86] = 8, [87] = 12, [88] = 8, [89] = 8, [90] = 7, [91] = 5, [92] = 8, [93] = 5, [94] = 9, [95] = 8,
|
||||
[96] = 5, [97] = 7, [98] = 7, [99] = 6, [100] = 7, [101] = 7, [102] = 5, [103] = 7, [104] = 7, [105] = 3, [106] = 4, [107] = 7, [108] = 3, [109] = 11, [110] = 7,
|
||||
[111] = 7, [112] = 7, [113] = 7, [114] = 6, [115] = 6, [116] = 5, [117] = 7, [118] = 8, [119] = 10, [120] = 8, [121] = 8, [122] = 6, [123] = 7, [124] = 4, [125] = 7, [126] = 8,
|
||||
[127] = 1, [128] = 7, [129] = 6, [130] = 3, [131] = 7, [132] = 6, [133] = 11, [134] = 7, [135] = 7, [136] = 7, [137] = 13, [138] = 7, [139] = 4, [140] = 11, [141] = 6, [142] = 6,
|
||||
[143] = 6, [144] = 6, [145] = 4, [146] = 3, [147] = 7, [148] = 6, [149] = 6, [150] = 7, [151] = 10, [152] = 7, [153] = 10, [154] = 6, [155] = 5, [156] = 11, [157] = 6, [158] = 6,
|
||||
[159] = 8, [160] = 4, [161] = 3, [162] = 7, [163] = 7, [164] = 7, [165] = 8, [166] = 4, [167] = 7, [168] = 6, [169] = 10, [170] = 6, [171] = 8, [172] = 8, [173] = 16, [174] = 10,
|
||||
[175] = 8, [176] = 5, [177] = 8, [178] = 5, [179] = 5, [180] = 6, [181] = 7, [182] = 7, [183] = 3, [184] = 5, [185] = 6, [186] = 6, [187] = 8, [188] = 12, [189] = 12, [190] = 12,
|
||||
[191] = 6, [192] = 9, [193] = 9, [194] = 9, [195] = 9, [196] = 9, [197] = 9, [198] = 11, [199] = 7, [200] = 7, [201] = 7, [202] = 7, [203] = 7, [204] = 5, [205] = 5, [206] = 6,
|
||||
[207] = 5, [208] = 8, [209] = 8, [210] = 8, [211] = 8, [212] = 8, [213] = 8, [214] = 8, [215] = 8, [216] = 8, [217] = 8, [218] = 8, [219] = 8, [220] = 8, [221] = 8, [222] = 7,
|
||||
[223] = 7, [224] = 7, [225] = 7, [226] = 7, [227] = 7, [228] = 7, [229] = 7, [230] = 11, [231] = 6, [232] = 7, [233] = 7, [234] = 7, [235] = 7, [236] = 3, [237] = 4, [238] = 4,
|
||||
[239] = 4, [240] = 7, [241] = 7, [242] = 7, [243] = 7, [244] = 7, [245] = 7, [246] = 7, [247] = 9, [248] = 7, [249] = 7, [250] = 7, [251] = 7, [252] = 7, [253] = 8, [254] = 7, [255] = 8
|
||||
}
|
||||
|
||||
-- Return information about start, end in the string and the highlighted words
|
||||
function getHighlightedText(text)
|
||||
local tmpData = {}
|
||||
|
||||
repeat
|
||||
local tmp = {string.find(text, "{([^}]+)}", tmpData[#tmpData-1])}
|
||||
for _, v in pairs(tmp) do
|
||||
table.insert(tmpData, v)
|
||||
end
|
||||
until not(string.find(text, "{([^}]+)}", tmpData[#tmpData-1]))
|
||||
|
||||
return tmpData
|
||||
end
|
||||
|
||||
function addTabText(text, speaktype, tab, creatureName)
|
||||
if Options.getOption('showTimestampsInConsole') then
|
||||
text = os.date('%H:%M') .. ' ' .. text
|
||||
@@ -284,11 +316,56 @@ function addTabText(text, speaktype, tab, creatureName)
|
||||
label:setColor(speaktype.color)
|
||||
consoleTabBar:blinkTab(tab)
|
||||
|
||||
-- Overlay for consoleBuffer which shows highlighted words only
|
||||
local consoleBufferHighlight = panel:getChildById('consoleBufferHighlight')
|
||||
local labelHighlight = g_ui.createWidget('ConsoleLabel', consoleBufferHighlight)
|
||||
labelHighlight:setId('consoleLabel' .. panel:getChildCount())
|
||||
labelHighlight:setColor("#1f9ffe")
|
||||
|
||||
|
||||
local player = g_game.getLocalPlayer()
|
||||
if speaktype.npcChat and player:getName() ~= creatureName then -- Check if it is the npc who is talking
|
||||
local highlightData = getHighlightedText(text)
|
||||
if #highlightData == 0 then
|
||||
labelHighlight:setText("")
|
||||
else
|
||||
-- Remove the curly braces
|
||||
for i = 1, #highlightData / 3 do
|
||||
local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] }
|
||||
text = text:gsub("{"..dataBlock.words.."}", dataBlock.words)
|
||||
|
||||
-- Recalculate positions as braces are removed
|
||||
highlightData[(i-1)*3+1] = dataBlock._start - ((i-1) * 2)
|
||||
highlightData[(i-1)*3+2] = dataBlock._end - (1 + (i-1) * 2)
|
||||
end
|
||||
label:setText(text)
|
||||
|
||||
-- Calculate the positions of the highlighted text and fill with string.char(127) [Width: 1]
|
||||
local tmpText = ""
|
||||
for i = 1, #highlightData / 3 do
|
||||
local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] }
|
||||
local lastBlockEnd = (highlightData[(i-2)*3+2] or 1)
|
||||
|
||||
for letter = lastBlockEnd, dataBlock._start-1 do
|
||||
tmpText = tmpText .. string.rep(string.char(127), letterWidth[string.byte(text:sub(letter, letter))])
|
||||
end
|
||||
tmpText = tmpText .. dataBlock.words
|
||||
end
|
||||
labelHighlight:setText(tmpText)
|
||||
end
|
||||
else
|
||||
labelHighlight:setText("")
|
||||
end
|
||||
|
||||
label.onMouseRelease = function (self, mousePos, mouseButton) popupMenu(mousePos, mouseButton, creatureName, text) end
|
||||
|
||||
if consoleBuffer:getChildCount() > MAX_LINES then
|
||||
consoleBuffer:getFirstChild():destroy()
|
||||
end
|
||||
|
||||
if consoleBufferHighlight:getChildCount() > MAX_LINES then
|
||||
consoleBufferHighlight:getFirstChild():destroy()
|
||||
end
|
||||
end
|
||||
|
||||
function popupMenu(mousePos, mouseButton, creatureName, text)
|
||||
@@ -577,7 +654,7 @@ function onGameStart()
|
||||
if savedChannels then
|
||||
for channelName, channelId in pairs(savedChannels) do
|
||||
channelId = tonumber(channelId)
|
||||
if channelId ~= 0 then
|
||||
if channelId ~= 0 and channelId < 100 then
|
||||
if not table.find(channels, channelId) then
|
||||
g_game.joinChannel(channelId)
|
||||
end
|
||||
|
@@ -24,6 +24,31 @@ ConsoleTabBarPanel < TabBarRoundedPanel
|
||||
inverted-scroll: true
|
||||
padding: 1
|
||||
|
||||
ScrollablePanel
|
||||
id: consoleBufferHighlight
|
||||
anchors.fill: parent
|
||||
margin-right: 12
|
||||
vertical-scrollbar: consoleScrollBarHighlight
|
||||
layout:
|
||||
type: verticalBox
|
||||
align-bottom: true
|
||||
border-width: 1
|
||||
border-color: #202327
|
||||
inverted-scroll: true
|
||||
padding: 1
|
||||
@onScrollbarChange: |
|
||||
local consoleScrollBar = self:getParent():getChildById('consoleScrollBar')
|
||||
local consoleScrollBarHighlight = self:getParent():getChildById('consoleScrollBarHighlight')
|
||||
consoleScrollBar:setValue(consoleScrollBarHighlight:getValue())
|
||||
|
||||
VerticalScrollBar
|
||||
id: consoleScrollBarHighlight
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
step: 14
|
||||
pixels-scroll: true
|
||||
|
||||
VerticalScrollBar
|
||||
id: consoleScrollBar
|
||||
anchors.top: parent.top
|
||||
|
@@ -70,6 +70,7 @@ function bindKeys()
|
||||
g_keyboard.bindKeyDown('Ctrl+W', function() g_map.cleanTexts() modules.game_textmessage.clearMessages() end, gameRootPanel)
|
||||
g_keyboard.bindKeyDown('Ctrl+;', toggleDash, gameRootPanel)
|
||||
g_keyboard.bindKeyDown('Ctrl+.', toggleAspectRatio, gameRootPanel)
|
||||
g_keyboard.bindKeyDown('Ctrl+N', function() gameMapPanel:setDrawTexts(not gameMapPanel:isDrawingTexts()) end, gameRootPanel)
|
||||
end
|
||||
|
||||
function terminate()
|
||||
|
@@ -28,5 +28,6 @@ Module
|
||||
- game_playerdeath
|
||||
- game_playermount
|
||||
- game_market
|
||||
- game_spelllist
|
||||
@onLoad: init()
|
||||
@onUnload: terminate()
|
||||
|
BIN
modules/game_spelllist/icons/icons.png
Normal file
BIN
modules/game_spelllist/icons/icons.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 340 KiB |
355
modules/game_spelllist/spelllist.lua
Normal file
355
modules/game_spelllist/spelllist.lua
Normal file
@@ -0,0 +1,355 @@
|
||||
spelllistWindow = nil
|
||||
spelllistButton = nil
|
||||
spellList = nil
|
||||
nameValueLabel = nil
|
||||
formulaValueLabel = nil
|
||||
vocationValueLabel = nil
|
||||
groupValueLabel = nil
|
||||
typeValueLabel = nil
|
||||
cooldownValueLabel = nil
|
||||
levelValueLabel = nil
|
||||
manaValueLabel = nil
|
||||
premiumValueLabel = nil
|
||||
|
||||
vocationBoxAny = nil
|
||||
vocationBoxSorcerer = nil
|
||||
vocationBoxDruid = nil
|
||||
vocationBoxPaladin = nil
|
||||
vocationBoxKnight = nil
|
||||
|
||||
groupBoxAny = nil
|
||||
groupBoxAttack = nil
|
||||
groupBoxHealing = nil
|
||||
groupBoxSupport = nil
|
||||
|
||||
premiumBoxAny = nil
|
||||
premiumBoxNo = nil
|
||||
premiumBoxYes = nil
|
||||
|
||||
vocationRadioGroup = nil
|
||||
groupRadioGroup = nil
|
||||
premiumRadioGroup = nil
|
||||
|
||||
-- consts
|
||||
FILTER_PREMIUM_ANY = 0
|
||||
FILTER_PREMIUM_NO = 1
|
||||
FILTER_PREMIUM_YES = 2
|
||||
|
||||
FILTER_VOCATION_ANY = 0
|
||||
FILTER_VOCATION_SORCERER = 1
|
||||
FILTER_VOCATION_DRUID = 2
|
||||
FILTER_VOCATION_PALADIN = 3
|
||||
FILTER_VOCATION_KNIGHT = 4
|
||||
|
||||
FILTER_GROUP_ANY = 0
|
||||
FILTER_GROUP_ATTACK = 1
|
||||
FILTER_GROUP_HEALING = 2
|
||||
FILTER_GROUP_SUPPORT = 3
|
||||
|
||||
-- Filter Settings
|
||||
local filters = {
|
||||
level = false,
|
||||
vocation = false,
|
||||
|
||||
vocationId = FILTER_VOCATION_ANY,
|
||||
premium = FILTER_PREMIUM_ANY,
|
||||
groupId = FILTER_GROUP_ANY
|
||||
}
|
||||
|
||||
local spellDisplayOrder = {'Animate Dead', 'Annihilation', 'Avalanche', 'Berserk', 'Blood Rage', 'Brutal Strike', 'Cancel Invisibility', 'Challenge', 'Chameleon', 'Charge', 'Conjure Arrow', 'Conjure Bolt', 'Conjure Explosive Arrow', 'Conjure Piercing Bolt', 'Conjure Poisoned Arrow', 'Conjure Power Bolt', 'Conjure Sniper Arrow', 'Convince Creature', 'Creature Illusion', 'Cure Bleeding', 'Cure Burning', 'Cure Curse', 'Cure Electrification', 'Cure Poison', 'Cure Poison Rune', 'Curser', 'Death Strike', 'Desintegrate', 'Destroy Field', 'Divine Caldera', 'Divine Healing', 'Divine Missile', 'Electrify', 'Enchant Party', 'Enchant Spear', 'Enchant Staff', 'Energy Beam', 'Energy Field', 'Energy Strike', 'Energy Wall', 'Energy Wave', 'Energybomb', 'Envenom', 'Eternal Winter', 'Ethereal Spear', 'Explosion', 'Fierce Berserk', 'Find Person', 'Fire Field', 'Fire Wall', 'Fire Wave', 'Fireball', 'Firebomb', 'Flame Strike', 'Food', 'Front Sweep', 'Great Energy Beam', 'Great Fireball', 'Great Light', 'Groundshaker', 'Haste', 'Heal Friend', 'Heal Party', 'Heavy Magic Missile', 'Hells Core', 'Holy Flash', 'Holy Missile', 'Ice Strike', 'Ice Wave', 'Icicle', 'Ignite', 'Inflict Wound', 'Intense Healing', 'Intense Healing Rune', 'Intense Recovery', 'Intense Wound Cleansing', 'Invisibility', 'Levitate', 'Light', 'Light Healing', 'Light Magic Missile', 'Lightning', 'Magic Rope', 'Magic Shield', 'Magic Wall', 'Mass Healing', 'Paralyze', 'Physical Strike', 'Poison Bomb', 'Poison Field', 'Poison Wall', 'Protect Party', 'Protector', 'Rage of the Skies', 'Recovery', 'Salvation', 'Sharpshooter', 'Soulfire', 'Stalagmite', 'Stone Shower', 'Strong Energy Strike', 'Strong Ethereal Spear', 'Strong Flame Strike', 'Strong Haste', 'Strong Ice Strike', 'Strong Ice Wave', 'Strong Terra Strike', 'Sudden Death', 'Summon Creature', 'Swift Foot', 'Terra Strike', 'Terra Wave', 'Thunderstorm', 'Train Party', 'Ultimate Energy Strike', 'Ultimate Flame Strike', 'Ultimate Healing', 'Ultimate Healing Rune', 'Ultimate Ice Strike', 'Ultimate Light', 'Ultimate Terra Strike', 'Whirlwind Throw', 'Wild Growth', 'Wound Cleansing', 'Wrath of Nature'}
|
||||
|
||||
function getIconImageClip(id)
|
||||
return (((id-1)%12)*32) .. ' ' .. ((math.ceil(id/12)-1)*32) .. ' 32 32'
|
||||
end
|
||||
|
||||
function setupOptions()
|
||||
if g_game.getClientVersion() >= 950 then -- Vocation is only send in newer clients
|
||||
spelllistWindow:getChildById('buttonFilterVocation'):setVisible(true)
|
||||
else
|
||||
spelllistWindow:getChildById('buttonFilterVocation'):setVisible(false)
|
||||
end
|
||||
end
|
||||
|
||||
function init()
|
||||
connect(g_game, { onGameStart = setupOptions,
|
||||
onGameEnd = resetWindow })
|
||||
|
||||
spelllistWindow = g_ui.displayUI('spelllist.otui', modules.game_interface.getRightPanel())
|
||||
spelllistWindow:hide()
|
||||
|
||||
spelllistButton = TopMenu.addRightGameToggleButton('spelllistButton', tr('Spell List'), 'spelllist.png', toggle)
|
||||
spelllistButton:setOn(false)
|
||||
|
||||
nameValueLabel = spelllistWindow:getChildById('labelNameValue')
|
||||
formulaValueLabel = spelllistWindow:getChildById('labelFormulaValue')
|
||||
vocationValueLabel = spelllistWindow:getChildById('labelVocationValue')
|
||||
groupValueLabel = spelllistWindow:getChildById('labelGroupValue')
|
||||
typeValueLabel = spelllistWindow:getChildById('labelTypeValue')
|
||||
cooldownValueLabel = spelllistWindow:getChildById('labelCooldownValue')
|
||||
levelValueLabel = spelllistWindow:getChildById('labelLevelValue')
|
||||
manaValueLabel = spelllistWindow:getChildById('labelManaValue')
|
||||
premiumValueLabel = spelllistWindow:getChildById('labelPremiumValue')
|
||||
|
||||
vocationBoxAny = spelllistWindow:getChildById('vocationBoxAny')
|
||||
vocationBoxSorcerer = spelllistWindow:getChildById('vocationBoxSorcerer')
|
||||
vocationBoxDruid = spelllistWindow:getChildById('vocationBoxDruid')
|
||||
vocationBoxPaladin = spelllistWindow:getChildById('vocationBoxPaladin')
|
||||
vocationBoxKnight = spelllistWindow:getChildById('vocationBoxKnight')
|
||||
|
||||
groupBoxAny = spelllistWindow:getChildById('groupBoxAny')
|
||||
groupBoxAttack = spelllistWindow:getChildById('groupBoxAttack')
|
||||
groupBoxHealing = spelllistWindow:getChildById('groupBoxHealing')
|
||||
groupBoxSupport = spelllistWindow:getChildById('groupBoxSupport')
|
||||
|
||||
premiumBoxAny = spelllistWindow:getChildById('premiumBoxAny')
|
||||
premiumBoxYes = spelllistWindow:getChildById('premiumBoxYes')
|
||||
premiumBoxNo = spelllistWindow:getChildById('premiumBoxNo')
|
||||
|
||||
vocationRadioGroup = UIRadioGroup.create()
|
||||
vocationRadioGroup:addWidget(vocationBoxAny)
|
||||
vocationRadioGroup:addWidget(vocationBoxSorcerer)
|
||||
vocationRadioGroup:addWidget(vocationBoxDruid)
|
||||
vocationRadioGroup:addWidget(vocationBoxPaladin)
|
||||
vocationRadioGroup:addWidget(vocationBoxKnight)
|
||||
|
||||
groupRadioGroup = UIRadioGroup.create()
|
||||
groupRadioGroup:addWidget(groupBoxAny)
|
||||
groupRadioGroup:addWidget(groupBoxAttack)
|
||||
groupRadioGroup:addWidget(groupBoxHealing)
|
||||
groupRadioGroup:addWidget(groupBoxSupport)
|
||||
|
||||
premiumRadioGroup = UIRadioGroup.create()
|
||||
premiumRadioGroup:addWidget(premiumBoxAny)
|
||||
premiumRadioGroup:addWidget(premiumBoxYes)
|
||||
premiumRadioGroup:addWidget(premiumBoxNo)
|
||||
|
||||
premiumRadioGroup:selectWidget(premiumBoxAny)
|
||||
vocationRadioGroup:selectWidget(vocationBoxAny)
|
||||
groupRadioGroup:selectWidget(groupBoxAny)
|
||||
|
||||
vocationRadioGroup.onSelectionChange = toggleFilter
|
||||
groupRadioGroup.onSelectionChange = toggleFilter
|
||||
premiumRadioGroup.onSelectionChange = toggleFilter
|
||||
|
||||
spellList = spelllistWindow:getChildById('spellList')
|
||||
|
||||
g_keyboard.bindKeyPress('Down', function() spellList:focusNextChild(KeyboardFocusReason) end, spelllistWindow)
|
||||
g_keyboard.bindKeyPress('Up', function() spellList:focusPreviousChild(KeyboardFocusReason) end, spelllistWindow)
|
||||
|
||||
for i = 1, #spellDisplayOrder do
|
||||
local spell = spellDisplayOrder[i]
|
||||
local info = SpellInfo[spell]
|
||||
local tmpLabel = g_ui.createWidget('SpellListLabel', spellList)
|
||||
tmpLabel:setId(spell)
|
||||
tmpLabel:setText(spell .. '\n\'' .. info.words .. '\'')
|
||||
tmpLabel:setPhantom(false)
|
||||
|
||||
if not(SpellIcons[info.icon]) then
|
||||
perror('Spell icon \'' .. info.icon .. '\' not found.')
|
||||
else
|
||||
tmpLabel:setImageClip(getIconImageClip(SpellIcons[info.icon][1]))
|
||||
end
|
||||
|
||||
tmpLabel.onClick = updateSpellInformation
|
||||
end
|
||||
|
||||
connect(spellList, { onChildFocusChange = function(self, focusedChild)
|
||||
if focusedChild == nil then return end
|
||||
updateSpellInformation(focusedChild)
|
||||
end })
|
||||
|
||||
setupOptions()
|
||||
end
|
||||
|
||||
function terminate()
|
||||
disconnect(g_game, { onGameStart = setupOptions,
|
||||
onGameEnd = resetWindow })
|
||||
|
||||
disconnect(spellList, { onChildFocusChange = function(self, focusedChild)
|
||||
if focusedChild == nil then return end
|
||||
updateSpellInformation(focusedChild)
|
||||
end })
|
||||
|
||||
spelllistButton:destroy()
|
||||
spelllistButton = nil
|
||||
spelllistWindow:destroy()
|
||||
spelllistWindow = nil
|
||||
|
||||
vocationRadioGroup:destroy()
|
||||
vocationRadioGroup = nil
|
||||
groupRadioGroup:destroy()
|
||||
groupRadioGroup = nil
|
||||
premiumRadioGroup:destroy()
|
||||
premiumRadioGroup = nil
|
||||
|
||||
spellList = nil
|
||||
nameValueLabel = nil
|
||||
formulaValueLabel = nil
|
||||
vocationValueLabel = nil
|
||||
groupValueLabel = nil
|
||||
typeValueLabel = nil
|
||||
cooldownValueLabel = nil
|
||||
levelValueLabel = nil
|
||||
manaValueLabel = nil
|
||||
premiumValueLabel = nil
|
||||
|
||||
vocationBoxAny = nil
|
||||
vocationBoxSorcerer = nil
|
||||
vocationBoxDruid = nil
|
||||
vocationBoxPaladin = nil
|
||||
vocationBoxKnight = nil
|
||||
|
||||
groupBoxAny = nil
|
||||
groupBoxAttack = nil
|
||||
groupBoxHealing = nil
|
||||
groupBoxSupport = nil
|
||||
|
||||
premiumBoxAny = nil
|
||||
premiumBoxNo = nil
|
||||
premiumBoxYes = nil
|
||||
end
|
||||
|
||||
function updateSpelllist()
|
||||
for i = 1, #spellDisplayOrder do
|
||||
local spell = spellDisplayOrder[i]
|
||||
local info = SpellInfo[spell]
|
||||
local tmpLabel = spellList:getChildById(spell)
|
||||
|
||||
local localPlayer = g_game.getLocalPlayer()
|
||||
if (not(filters.level) or info.level <= localPlayer:getLevel()) and (not(filters.vocation) or table.find(info.vocations, localPlayer:getVocation())) and (filters.vocationId == FILTER_VOCATION_ANY or table.find(info.vocations, filters.vocationId) or table.find(info.vocations, filters.vocationId+4)) and (filters.groupId == FILTER_GROUP_ANY or info.group[filters.groupId]) and (filters.premium == FILTER_PREMIUM_ANY or (info.premium and filters.premium == FILTER_PREMIUM_YES) or (not(info.premium) and filters.premium == FILTER_PREMIUM_NO)) then
|
||||
tmpLabel:setVisible(true)
|
||||
else
|
||||
tmpLabel:setVisible(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function updateSpellInformation(widget)
|
||||
local spell = widget:getId()
|
||||
|
||||
local name = ''
|
||||
local formula = ''
|
||||
local vocation = ''
|
||||
local group = ''
|
||||
local type = ''
|
||||
local cooldown = ''
|
||||
local level = ''
|
||||
local mana = ''
|
||||
local premium = ''
|
||||
|
||||
if SpellInfo[spell] then
|
||||
local info = SpellInfo[spell]
|
||||
|
||||
name = spell
|
||||
formula = info.words
|
||||
|
||||
for i = 1, #info.vocations do
|
||||
local vocationId = info.vocations[i]
|
||||
if vocationId <= 4 or not(table.find(info.vocations, (vocationId-4))) then
|
||||
vocation = vocation .. (vocation:len() == 0 and '' or ', ') .. VocationNames[vocationId]
|
||||
end
|
||||
end
|
||||
|
||||
cooldown = (info.exhaustion / 1000) .. 's'
|
||||
for groupId, groupName in ipairs(SpellGroups) do
|
||||
if info.group[groupId] then
|
||||
group = group .. (group:len() == 0 and '' or ' / ') .. groupName
|
||||
cooldown = cooldown .. ' / ' .. (info.group[groupId] / 1000) .. 's'
|
||||
end
|
||||
end
|
||||
|
||||
type = info.type
|
||||
level = info.level
|
||||
mana = info.mana .. ' / ' .. info.soul
|
||||
premium = (info.premium and 'yes' or 'no')
|
||||
end
|
||||
|
||||
nameValueLabel:setText(name)
|
||||
formulaValueLabel:setText(formula)
|
||||
vocationValueLabel:setText(vocation)
|
||||
groupValueLabel:setText(group)
|
||||
typeValueLabel:setText(type)
|
||||
cooldownValueLabel:setText(cooldown)
|
||||
levelValueLabel:setText(level)
|
||||
manaValueLabel:setText(mana)
|
||||
premiumValueLabel:setText(premium)
|
||||
end
|
||||
|
||||
function toggle()
|
||||
if spelllistButton:isOn() then
|
||||
spelllistWindow:hide()
|
||||
spelllistButton:setOn(false)
|
||||
else
|
||||
spelllistWindow:show()
|
||||
spelllistButton:setOn(true)
|
||||
end
|
||||
end
|
||||
|
||||
function toggleFilter(widget, selectedWidget)
|
||||
if widget == vocationRadioGroup then
|
||||
local boxId = selectedWidget:getId()
|
||||
if boxId == 'vocationBoxAny' then
|
||||
filters.vocationId = FILTER_VOCATION_ANY
|
||||
elseif boxId == 'vocationBoxSorcerer' then
|
||||
filters.vocationId = FILTER_VOCATION_SORCERER
|
||||
elseif boxId == 'vocationBoxDruid' then
|
||||
filters.vocationId = FILTER_VOCATION_DRUID
|
||||
elseif boxId == 'vocationBoxPaladin' then
|
||||
filters.vocationId = FILTER_VOCATION_PALADIN
|
||||
elseif boxId == 'vocationBoxKnight' then
|
||||
filters.vocationId = FILTER_VOCATION_KNIGHT
|
||||
end
|
||||
elseif widget == groupRadioGroup then
|
||||
local boxId = selectedWidget:getId()
|
||||
if boxId == 'groupBoxAny' then
|
||||
filters.groupId = FILTER_GROUP_ANY
|
||||
elseif boxId == 'groupBoxAttack' then
|
||||
filters.groupId = FILTER_GROUP_ATTACK
|
||||
elseif boxId == 'groupBoxHealing' then
|
||||
filters.groupId = FILTER_GROUP_HEALING
|
||||
elseif boxId == 'groupBoxSupport' then
|
||||
filters.groupId = FILTER_GROUP_SUPPORT
|
||||
end
|
||||
elseif widget == premiumRadioGroup then
|
||||
local boxId = selectedWidget:getId()
|
||||
if boxId == 'premiumBoxAny' then
|
||||
filters.premium = FILTER_PREMIUM_ANY
|
||||
elseif boxId == 'premiumBoxNo' then
|
||||
filters.premium = FILTER_PREMIUM_NO
|
||||
elseif boxId == 'premiumBoxYes' then
|
||||
filters.premium = FILTER_PREMIUM_YES
|
||||
end
|
||||
else
|
||||
local id = widget:getId()
|
||||
if id == 'buttonFilterLevel' then
|
||||
filters.level = not(filters.level)
|
||||
widget:setOn(filters.level)
|
||||
elseif id == 'buttonFilterVocation' then
|
||||
filters.vocation = not(filters.vocation)
|
||||
widget:setOn(filters.vocation)
|
||||
end
|
||||
end
|
||||
|
||||
updateSpelllist()
|
||||
end
|
||||
|
||||
function resetWindow()
|
||||
spelllistWindow:hide()
|
||||
spelllistButton:setOn(false)
|
||||
|
||||
-- Resetting filters
|
||||
filters.level = false
|
||||
filters.vocation = false
|
||||
|
||||
local buttonFilterLevel = spelllistWindow:getChildById('buttonFilterLevel')
|
||||
buttonFilterLevel:setOn(filters.level)
|
||||
|
||||
local buttonFilterVocation = spelllistWindow:getChildById('buttonFilterVocation')
|
||||
buttonFilterVocation:setOn(filters.vocation)
|
||||
|
||||
vocationRadioGroup:selectWidget(vocationBoxAny)
|
||||
groupRadioGroup:selectWidget(groupBoxAny)
|
||||
premiumRadioGroup:selectWidget(premiumBoxAny)
|
||||
|
||||
updateSpelllist()
|
||||
end
|
9
modules/game_spelllist/spelllist.otmod
Normal file
9
modules/game_spelllist/spelllist.otmod
Normal file
@@ -0,0 +1,9 @@
|
||||
Module
|
||||
name: game_spelllist
|
||||
description: View available spells
|
||||
author: Summ, Edubart
|
||||
website: www.otclient.info
|
||||
sandboxed: true
|
||||
scripts: [ spelllist.lua ]
|
||||
@onLoad: init()
|
||||
@onUnload: terminate()
|
317
modules/game_spelllist/spelllist.otui
Normal file
317
modules/game_spelllist/spelllist.otui
Normal file
@@ -0,0 +1,317 @@
|
||||
SpellListLabel < Label
|
||||
font: verdana-11px-monochrome
|
||||
background-color: alpha
|
||||
text-offset: 42 3
|
||||
focusable: true
|
||||
height: 36
|
||||
image-clip: 0 0 32 32
|
||||
image-size: 32 32
|
||||
image-offset: 2 2
|
||||
image-source: /game_spelllist/icons/icons.png
|
||||
|
||||
$focus:
|
||||
background-color: #ffffff22
|
||||
color: #ffffff
|
||||
|
||||
SpellInfoLabel < Label
|
||||
width: 70
|
||||
font: verdana-11px-monochrome
|
||||
text-align: right
|
||||
margin-left: 10
|
||||
margin-top: 5
|
||||
|
||||
SpellInfoValueLabel < Label
|
||||
text-align: left
|
||||
width: 190
|
||||
margin-left: 10
|
||||
margin-top: 5
|
||||
|
||||
MainWindow
|
||||
id: spelllistWindow
|
||||
!text: tr('Spell List')
|
||||
size: 500 400
|
||||
@onEscape: toggle()
|
||||
|
||||
TextList
|
||||
id: spellList
|
||||
vertical-scrollbar: spellsScrollBar
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: next.top
|
||||
margin-bottom: 10
|
||||
padding: 1
|
||||
width: 210
|
||||
focusable: false
|
||||
|
||||
Button
|
||||
id: buttonCancel
|
||||
!text: tr('Close')
|
||||
width: 64
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
@onClick: toggle()
|
||||
|
||||
VerticalScrollBar
|
||||
id: spellsScrollBar
|
||||
anchors.top: spellList.top
|
||||
anchors.bottom: spellList.bottom
|
||||
anchors.right: spellList.right
|
||||
step: 50
|
||||
pixels-scroll: true
|
||||
|
||||
SpellInfoLabel
|
||||
id: labelName
|
||||
anchors.left: spellList.right
|
||||
anchors.top: spellList.top
|
||||
text: Name:
|
||||
|
||||
Button
|
||||
id: buttonFilterLevel
|
||||
!text: tr('Level')
|
||||
!tooltip: tr('Hide spells for higher exp. levels')
|
||||
width: 64
|
||||
anchors.left: spellList.left
|
||||
anchors.top: spellList.bottom
|
||||
@onClick: toggleFilter(self)
|
||||
margin-left: 10
|
||||
margin-top: 5
|
||||
color: #FF0000D0
|
||||
$on:
|
||||
color: green
|
||||
|
||||
Button
|
||||
id: buttonFilterVocation
|
||||
!text: tr('Vocation')
|
||||
!tooltip: tr('Hide spells for other vocations')
|
||||
width: 64
|
||||
anchors.left: prev.right
|
||||
anchors.top: spellList.bottom
|
||||
@onClick: toggleFilter(self)
|
||||
margin-left: 10
|
||||
margin-top: 5
|
||||
color: #FF0000D0
|
||||
$on:
|
||||
color: green
|
||||
|
||||
SpellInfoLabel
|
||||
id: labelFormula
|
||||
anchors.left: spellList.right
|
||||
anchors.top: labelName.bottom
|
||||
text: Formula:
|
||||
|
||||
|
||||
SpellInfoLabel
|
||||
id: labelVocation
|
||||
anchors.left: spellList.right
|
||||
anchors.top: labelFormula.bottom
|
||||
text: Vocation:
|
||||
|
||||
SpellInfoLabel
|
||||
id: labelGroup
|
||||
anchors.left: spellList.right
|
||||
anchors.top: labelVocation.bottom
|
||||
text: Group:
|
||||
|
||||
SpellInfoLabel
|
||||
id: labelType
|
||||
anchors.left: spellList.right
|
||||
anchors.top: labelGroup.bottom
|
||||
text: Type:
|
||||
|
||||
SpellInfoLabel
|
||||
id: labelCooldown
|
||||
anchors.left: spellList.right
|
||||
anchors.top: labelType.bottom
|
||||
text: Cooldown:
|
||||
|
||||
SpellInfoLabel
|
||||
id: labelLevel
|
||||
anchors.left: spellList.right
|
||||
anchors.top: labelCooldown.bottom
|
||||
text: Level:
|
||||
|
||||
SpellInfoLabel
|
||||
id: labelMana
|
||||
anchors.left: spellList.right
|
||||
anchors.top: labelLevel.bottom
|
||||
text: Mana / Soul:
|
||||
|
||||
SpellInfoLabel
|
||||
id: labelPremium
|
||||
anchors.left: spellList.right
|
||||
anchors.top: labelMana.bottom
|
||||
text: Premium:
|
||||
|
||||
SpellInfoValueLabel
|
||||
id: labelNameValue
|
||||
anchors.left: labelName.right
|
||||
anchors.top: spellList.top
|
||||
|
||||
SpellInfoValueLabel
|
||||
id: labelFormulaValue
|
||||
anchors.left: labelFormula.right
|
||||
anchors.top: labelNameValue.bottom
|
||||
|
||||
SpellInfoValueLabel
|
||||
id: labelVocationValue
|
||||
anchors.left: labelVocation.right
|
||||
anchors.top: labelFormulaValue.bottom
|
||||
|
||||
SpellInfoValueLabel
|
||||
id: labelGroupValue
|
||||
anchors.left: labelGroup.right
|
||||
anchors.top: labelVocationValue.bottom
|
||||
|
||||
SpellInfoValueLabel
|
||||
id: labelTypeValue
|
||||
anchors.left: labelType.right
|
||||
anchors.top: labelGroupValue.bottom
|
||||
|
||||
SpellInfoValueLabel
|
||||
id: labelCooldownValue
|
||||
anchors.left: labelCooldown.right
|
||||
anchors.top: labelTypeValue.bottom
|
||||
|
||||
SpellInfoValueLabel
|
||||
id: labelLevelValue
|
||||
anchors.left: labelLevel.right
|
||||
anchors.top: labelCooldownValue.bottom
|
||||
|
||||
SpellInfoValueLabel
|
||||
id: labelManaValue
|
||||
anchors.left: labelMana.right
|
||||
anchors.top: labelLevelValue.bottom
|
||||
|
||||
SpellInfoValueLabel
|
||||
id: labelPremiumValue
|
||||
anchors.left: labelPremium.right
|
||||
anchors.top: labelManaValue.bottom
|
||||
|
||||
Label
|
||||
id: labelVocationFilter
|
||||
anchors.top: labelPremium.bottom
|
||||
anchors.left: spellList.right
|
||||
width: 70
|
||||
font: verdana-11px-monochrome
|
||||
text: Vocation
|
||||
margin-top: 25
|
||||
margin-left: 20
|
||||
|
||||
CheckBox
|
||||
id: vocationBoxAny
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
margin-left: 3
|
||||
text: Any
|
||||
width: 50
|
||||
|
||||
CheckBox
|
||||
id: vocationBoxSorcerer
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
text: Sorcerer
|
||||
width: 50
|
||||
|
||||
CheckBox
|
||||
id: vocationBoxDruid
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
text: Druid
|
||||
width: 50
|
||||
|
||||
CheckBox
|
||||
id: vocationBoxPaladin
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
text: Paladin
|
||||
width: 50
|
||||
|
||||
CheckBox
|
||||
id: vocationBoxKnight
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
text: Knight
|
||||
width: 50
|
||||
|
||||
Label
|
||||
id: labelGroupFilter
|
||||
anchors.top: labelPremium.bottom
|
||||
anchors.left: labelVocationFilter.right
|
||||
width: 70
|
||||
font: verdana-11px-monochrome
|
||||
text: Group
|
||||
margin-top: 25
|
||||
margin-left: 20
|
||||
|
||||
CheckBox
|
||||
id: groupBoxAny
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
margin-left: 3
|
||||
text: Any
|
||||
width: 50
|
||||
|
||||
CheckBox
|
||||
id: groupBoxAttack
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
text: Attack
|
||||
width: 50
|
||||
|
||||
CheckBox
|
||||
id: groupBoxHealing
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
text: Healing
|
||||
width: 50
|
||||
|
||||
CheckBox
|
||||
id: groupBoxSupport
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
text: Support
|
||||
width: 50
|
||||
|
||||
Label
|
||||
id: labelPremiumFilter
|
||||
anchors.top: labelPremium.bottom
|
||||
anchors.left: labelGroupFilter.right
|
||||
width: 70
|
||||
font: verdana-11px-monochrome
|
||||
text: Premium
|
||||
margin-top: 25
|
||||
margin-left: 20
|
||||
|
||||
CheckBox
|
||||
id: premiumBoxAny
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
margin-left: 3
|
||||
text: Any
|
||||
width: 50
|
||||
|
||||
CheckBox
|
||||
id: premiumBoxNo
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
text: No
|
||||
width: 50
|
||||
|
||||
CheckBox
|
||||
id: premiumBoxYes
|
||||
anchors.left: prev.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 3
|
||||
text: Yes
|
||||
width: 50
|
BIN
modules/game_spelllist/spelllist.png
Normal file
BIN
modules/game_spelllist/spelllist.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 860 B |
@@ -19,5 +19,6 @@ Module
|
||||
dofile 'player'
|
||||
dofile 'market'
|
||||
dofile 'thing'
|
||||
dofile 'spells'
|
||||
|
||||
dofiles 'ui'
|
||||
|
288
modules/gamelib/spells.lua
Normal file
288
modules/gamelib/spells.lua
Normal file
@@ -0,0 +1,288 @@
|
||||
-- ['Spell Name'] = {words = '', exhaustion = spellCooldown, premium = true/false, type = 'Instant'/'Conjure', icon = iconName, mana = manaCost, level = levelRequirement, soul = soulCost, group = {[groupId] = groupCooldown}, vocation = {vocationIds}}
|
||||
SpellInfo = {
|
||||
['Death Strike'] = {words = 'exori mort', exhaustion = 2000, premium = true, type = 'Instant', icon = 'deathstrike', mana = 20, level = 16, soul = 0, group = {[1] = 2000}, vocations = {1, 5}},
|
||||
['Flame Strike'] = {words = 'exori flam', exhaustion = 2000, premium = true, type = 'Instant', icon = 'flamestrike', mana = 20, level = 14, soul = 0, group = {[1] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Strong Flame Strike'] = {words = 'exori gran flam', exhaustion = 8000, premium = true, type = 'Instant', icon = 'strongflamestrike', mana = 60, level = 70, soul = 0, group = {[1] = 2000, [4] = 8000}, vocations = {1, 5}},
|
||||
['Ultimate Flame Strike'] = {words = 'exori max flam', exhaustion = 30000, premium = true, type = 'Instant', icon = 'ultimateflamestrike', mana = 100, level = 90, soul = 0, group = {[1] = 4000}, vocations = {1, 5}},
|
||||
['Energy Strike'] = {words = 'exori vis', exhaustion = 2000, premium = true, type = 'Instant', icon = 'energystrike', mana = 20, level = 12, soul = 0, group = {[1] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Strong Energy Strike'] = {words = 'exori gran vis', exhaustion = 8000, premium = true, type = 'Instant', icon = 'strongenergystrike', mana = 60, level = 80, soul = 0, group = {[1] = 2000, [4] = 8000}, vocations = {1, 5}},
|
||||
['Ultimate Energy Strike'] = {words = 'exori max vis', exhaustion = 30000, premium = true, type = 'Instant', icon = 'ultimateenergystrike', mana = 100, level = 100,soul = 0, group = {[1] = 4000}, vocations = {1, 5}},
|
||||
['Whirlwind Throw'] = {words = 'exori hur', exhaustion = 6000, premium = true, type = 'Instant', icon = 'whirlwindthrow', mana = 40, level = 28, soul = 0, group = {[1] = 2000}, vocations = {4, 8}},
|
||||
['Fire Wave'] = {words = 'exevo flam hur', exhaustion = 4000, premium = false, type = 'Instant', icon = 'firewave', mana = 25, level = 18, soul = 0, group = {[1] = 2000}, vocations = {1, 5}},
|
||||
['Ethereal Spear'] = {words = 'exori con', exhaustion = 2000, premium = true, type = 'Instant', icon = 'eterealspear', mana = 25, level = 23, soul = 0, group = {[1] = 2000}, vocations = {3, 7}},
|
||||
['Strong Ethereal Spear'] = {words = 'exori gran con', exhaustion = 8000, premium = true, type = 'Instant', icon = 'strongetherealspear', mana = 55, level = 90, soul = 0, group = {[1] = 2000}, vocations = {3, 7}},
|
||||
['Energy Beam'] = {words = 'exevo vis lux', exhaustion = 4000, premium = false, type = 'Instant', icon = 'energybeam', mana = 40, level = 23, soul = 0, group = {[1] = 2000}, vocations = {1, 5}},
|
||||
['Great Energy Beam'] = {words = 'exevo gran vis lux', exhaustion = 6000, premium = false, type = 'Instant', icon = 'greatenergybeam', mana = 110, level = 29, soul = 0, group = {[1] = 2000}, vocations = {1, 5}},
|
||||
['Groundshaker'] = {words = 'exori mas', exhaustion = 8000, premium = true, type = 'Instant', icon = 'groundshaker', mana = 160, level = 33, soul = 0, group = {[1] = 2000}, vocations = {4, 8}},
|
||||
['Berserk'] = {words = 'exori', exhaustion = 4000, premium = true, type = 'Instant', icon = 'berserk', mana = 115, level = 35, soul = 0, group = {[1] = 2000}, vocations = {4, 8}},
|
||||
['Annihilation'] = {words = 'exori gran ico', exhaustion = 30000, premium = true, type = 'Instant', icon = 'annihilation', mana = 300, level = 110,soul = 0, group = {[1] = 4000}, vocations = {4, 8}},
|
||||
['Brutal Strike'] = {words = 'exori ico', exhaustion = 6000, premium = true, type = 'Instant', icon = 'brutalstrike', mana = 30, level = 16, soul = 0, group = {[1] = 2000}, vocations = {4, 8}},
|
||||
['Front Sweep'] = {words = 'exori min', exhaustion = 6000, premium = true, type = 'Instant', icon = 'frontsweep', mana = 200, level = 70, soul = 0, group = {[1] = 2000}, vocations = {4, 8}},
|
||||
['Inflict Wound'] = {words = 'utori kor', exhaustion = 30000, premium = true, type = 'Instant', icon = 'inflictwound', mana = 30, level = 40, soul = 0, group = {[1] = 2000}, vocations = {4, 8}},
|
||||
['Ignite'] = {words = 'utori flam', exhaustion = 30000, premium = true, type = 'Instant', icon = 'ignite', mana = 30, level = 26, soul = 0, group = {[1] = 2000}, vocations = {1, 5}},
|
||||
['Lightning'] = {words = 'exori amp vis', exhaustion = 8000, premium = true, type = 'Instant', icon = 'lightning', mana = 60, level = 55, soul = 0, group = {[1] = 2000, [4] = 8000}, vocations = {1, 5}},
|
||||
['Curser'] = {words = 'utori mort', exhaustion = 50000, premium = true, type = 'Instant', icon = 'curse', mana = 30, level = 75, soul = 0, group = {[1] = 2000}, vocations = {1, 5}},
|
||||
['Electrify'] = {words = 'utori vis', exhaustion = 30000, premium = true, type = 'Instant', icon = 'electrify', mana = 30, level = 34, soul = 0, group = {[1] = 2000}, vocations = {1, 5}},
|
||||
['Energy Wave'] = {words = 'exevo vis hur', exhaustion = 8000, premium = false, type = 'Instant', icon = 'energywave', mana = 170, level = 38, soul = 0, group = {[1] = 2000}, vocations = {1, 5}},
|
||||
['Rage of the Skies'] = {words = 'exevo gran mas vis', exhaustion = 40000, premium = true, type = 'Instant', icon = 'rageoftheskies', mana = 600, level = 55, soul = 0, group = {[1] = 4000}, vocations = {1, 5}},
|
||||
['Fierce Berserk'] = {words = 'exori gran', exhaustion = 6000, premium = true, type = 'Instant', icon = 'fierceberserk', mana = 340, level = 90, soul = 0, group = {[1] = 2000}, vocations = {4, 8}},
|
||||
['Hells Core'] = {words = 'exevo gran mas flam', exhaustion = 40000, premium = true, type = 'Instant', icon = 'hellscore', mana = 1100, level = 60, soul = 0, group = {[1] = 4000}, vocations = {1, 5}},
|
||||
['Holy Flash'] = {words = 'utori san', exhaustion = 40000, premium = true, type = 'Instant', icon = 'holyflash', mana = 30, level = 70, soul = 0, group = {[1] = 2000}, vocations = {3, 7}},
|
||||
['Divine Missile'] = {words = 'exori san', exhaustion = 2000, premium = true, type = 'Instant', icon = 'divinemissile', mana = 20, level = 40, soul = 0, group = {[1] = 2000}, vocations = {3, 7}},
|
||||
['Divine Caldera'] = {words = 'exevo mas san', exhaustion = 4000, premium = true, type = 'Instant', icon = 'divinecaldera', mana = 160, level = 50, soul = 0, group = {[1] = 2000}, vocations = {3, 7}},
|
||||
['Physical Strike'] = {words = 'exori moe ico', exhaustion = 2000, premium = true, type = 'Instant', icon = 'physicalstrike', mana = 20, level = 16, soul = 0, group = {[1] = 2000}, vocations = {2, 6}},
|
||||
['Eternal Winter'] = {words = 'exevo gran mas frigo',exhaustion = 40000, premium = true, type = 'Instant', icon = 'eternalwinter', mana = 1050, level = 60, soul = 0, group = {[1] = 4000}, vocations = {2, 6}},
|
||||
['Ice Strike'] = {words = 'exori frigo', exhaustion = 2000, premium = true, type = 'Instant', icon = 'icestrike', mana = 20, level = 15, soul = 0, group = {[1] = 2000}, vocations = {1, 5, 2, 6}},
|
||||
['Strong Ice Strike'] = {words = 'exori gran frigo', exhaustion = 8000, premium = true, type = 'Instant', icon = 'strongicestrike', mana = 60, level = 80, soul = 0, group = {[1] = 2000, [4] = 8000}, vocations = {2, 6}},
|
||||
['Ultimate Ice Strike'] = {words = 'exori max frigo', exhaustion = 30000, premium = true, type = 'Instant', icon = 'ultimateicestrike', mana = 100, level = 100,soul = 0, group = {[1] = 4000}, vocations = {2, 6}},
|
||||
['Ice Wave'] = {words = 'exevo frigo hur', exhaustion = 4000, premium = false, type = 'Instant', icon = 'icewave', mana = 25, level = 18, soul = 0, group = {[1] = 2000}, vocations = {2, 6}},
|
||||
['Strong Ice Wave'] = {words = 'exevo gran frigo hur',exhaustion = 8000, premium = true, type = 'Instant', icon = 'strongicewave', mana = 170, level = 40, soul = 0, group = {[1] = 2000}, vocations = {2, 6}},
|
||||
['Envenom'] = {words = 'utori pox', exhaustion = 40000, premium = true, type = 'Instant', icon = 'envenom', mana = 30, level = 50, soul = 0, group = {[1] = 2000}, vocations = {2, 6}},
|
||||
['Terra Strike'] = {words = 'exori tera', exhaustion = 2000, premium = true, type = 'Instant', icon = 'terrastrike', mana = 20, level = 13, soul = 0, group = {[1] = 2000}, vocations = {1, 5, 2, 6}},
|
||||
['Strong Terra Strike'] = {words = 'exori gran tera', exhaustion = 8000, premium = true, type = 'Instant', icon = 'strongterrastrike', mana = 60, level = 70, soul = 0, group = {[1] = 2000, [4] = 8000}, vocations = {2, 6}},
|
||||
['Ultimate Terra Strike'] = {words = 'exori max tera', exhaustion = 30000, premium = true, type = 'Instant', icon = 'ultimateterrastrike', mana = 100, level = 90, soul = 0, group = {[1] = 4000}, vocations = {2, 6}},
|
||||
['Terra Wave'] = {words = 'exevo tera hur', exhaustion = 4000, premium = false, type = 'Instant', icon = 'terrawave', mana = 210, level = 38, soul = 0, group = {[1] = 2000}, vocations = {2, 6}},
|
||||
['Wrath of Nature'] = {words = 'exevo gran mas tera', exhaustion = 40000, premium = true, type = 'Instant', icon = 'wrathofnature', mana = 700, level = 55, soul = 0, group = {[1] = 4000}, vocations = {2, 6}},
|
||||
['Light Healing'] = {words = 'exura', exhaustion = 1000, premium = false, type = 'Instant', icon = 'lighthealing', mana = 20, level = 9, soul = 0, group = {[2] = 1000}, vocations = {1, 2, 3, 5, 6, 7}},
|
||||
['Wound Cleansing'] = {words = 'exura ico', exhaustion = 1000, premium = false, type = 'Instant', icon = 'woundcleansing', mana = 40, level = 10, soul = 0, group = {[2] = 1000}, vocations = {4, 8}},
|
||||
['Intense Wound Cleansing'] = {words = 'exura gran ico', exhaustion = 600000,premium = true, type = 'Instant', icon = 'intensewoundcleansing', mana = 200, level = 80, soul = 0, group = {[2] = 1000}, vocations = {4, 8}},
|
||||
['Cure Bleeding'] = {words = 'exana kor', exhaustion = 6000, premium = true, type = 'Instant', icon = 'curebleeding', mana = 30, level = 30, soul = 0, group = {[2] = 1000}, vocations = {4, 8}},
|
||||
['Cure Electrification'] = {words = 'exana vis', exhaustion = 6000, premium = true, type = 'Instant', icon = 'curseelectrification', mana = 30, level = 22, soul = 0, group = {[2] = 1000}, vocations = {2, 6}},
|
||||
['Cure Poison'] = {words = 'exana pox', exhaustion = 6000, premium = false, type = 'Instant', icon = 'curepoison', mana = 30, level = 10, soul = 0, group = {[2] = 1000}, vocations = {1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
['Cure Burning'] = {words = 'exana flam', exhaustion = 6000, premium = true, type = 'Instant', icon = 'cureburning', mana = 30, level = 30, soul = 0, group = {[2] = 1000}, vocations = {2, 6}},
|
||||
['Cure Curse'] = {words = 'exana mort', exhaustion = 6000, premium = true, type = 'Instant', icon = 'curecurse', mana = 40, level = 80, soul = 0, group = {[2] = 1000}, vocations = {3, 7}},
|
||||
['Recovery'] = {words = 'utura', exhaustion = 60000, premium = true, type = 'Instant', icon = 'recovery', mana = 75, level = 50, soul = 0, group = {[2] = 1000}, vocations = {4, 8, 3, 7}},
|
||||
['Intense Recovery'] = {words = 'utura gran', exhaustion = 60000, premium = true, type = 'Instant', icon = 'intenserecovery', mana = 165, level = 100,soul = 0, group = {[2] = 1000}, vocations = {4, 8, 3, 7}},
|
||||
['Salvation'] = {words = 'exura gran san', exhaustion = 1000, premium = true, type = 'Instant', icon = 'salvation', mana = 210, level = 60, soul = 0, group = {[2] = 1000}, vocations = {3, 7}},
|
||||
['Intense Healing'] = {words = 'exura gran', exhaustion = 1000, premium = false, type = 'Instant', icon = 'intensehealing', mana = 70, level = 20, soul = 0, group = {[2] = 1000}, vocations = {1, 2, 3, 5, 6, 7}},
|
||||
['Heal Friend'] = {words = 'exura sio', exhaustion = 1000, premium = true, type = 'Instant', icon = 'healfriend', mana = 140, level = 18, soul = 0, group = {[2] = 1000}, vocations = {2, 6}},
|
||||
['Ultimate Healing'] = {words = 'exura vita', exhaustion = 1000, premium = false, type = 'Instant', icon = 'ultimatehealing', mana = 160, level = 30, soul = 0, group = {[2] = 1000}, vocations = {1, 2, 5, 6}},
|
||||
['Mass Healing'] = {words = 'exura gran mas res', exhaustion = 2000, premium = true, type = 'Instant', icon = 'masshealing', mana = 150, level = 36, soul = 0, group = {[2] = 1000}, vocations = {2, 6}},
|
||||
['Divine Healing'] = {words = 'exura san', exhaustion = 1000, premium = false, type = 'Instant', icon = 'divinehealing', mana = 160, level = 35, soul = 0, group = {[2] = 1000}, vocations = {3, 7}},
|
||||
['Light'] = {words = 'utevo lux', exhaustion = 2000, premium = false, type = 'Instant', icon = 'light', mana = 20, level = 8, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
['Find Person'] = {words = 'exiva', exhaustion = 2000, premium = false, type = 'Instant', icon = 'findperson', mana = 20, level = 8, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
['Magic Rope'] = {words = 'exani tera', exhaustion = 2000, premium = true, type = 'Instant', icon = 'magicrope', mana = 20, level = 9, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
['Levitate'] = {words = 'exani hur', exhaustion = 2000, premium = true, type = 'Instant', icon = 'levitate', mana = 50, level = 12, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
['Great Light'] = {words = 'utevo gran lux', exhaustion = 2000, premium = false, type = 'Instant', icon = 'greatlight', mana = 60, level = 13, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
['Magic Shield'] = {words = 'utamo vita', exhaustion = 2000, premium = false, type = 'Instant', icon = 'magicshield', mana = 50, level = 14, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Haste'] = {words = 'utani hur', exhaustion = 2000, premium = true, type = 'Instant', icon = 'haste', mana = 60, level = 14, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 3, 4, 5, 6, 7, 8}},
|
||||
['Charge'] = {words = 'utani tempo hur', exhaustion = 2000, premium = true, type = 'Instant', icon = 'charge', mana = 100, level = 25, soul = 0, group = {[3] = 2000}, vocations = {4, 8}},
|
||||
['Swift Foot'] = {words = 'utamo tempo san', exhaustion = 2000, premium = true, type = 'Instant', icon = 'swiftfoot', mana = 400, level = 55, soul = 0, group = {[1] = 10000, [3] = 2000}, vocations = {3, 7}},
|
||||
['Challenge'] = {words = 'exeta res', exhaustion = 2000, premium = true, type = 'Instant', icon = 'challenge', mana = 30, level = 20, soul = 0, group = {[3] = 2000}, vocations = {8}},
|
||||
['Strong Haste'] = {words = 'utani gran hur', exhaustion = 2000, premium = true, type = 'Instant', icon = 'stronghaste', mana = 100, level = 20, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Creature Illusion'] = {words = 'utevo res ina', exhaustion = 2000, premium = false, type = 'Instant', icon = 'creatureillusion', mana = 100, level = 23, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Ultimate Light'] = {words = 'utevo vis lux', exhaustion = 2000, premium = true, type = 'Instant', icon = 'ultimatelight', mana = 140, level = 26, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Cancel Invisibility'] = {words = 'exana ina', exhaustion = 2000, premium = true, type = 'Instant', icon = 'cancelinvisibility', mana = 200, level = 26, soul = 0, group = {[3] = 2000}, vocations = {3, 7}},
|
||||
['Invisibility'] = {words = 'utana vid', exhaustion = 2000, premium = false, type = 'Instant', icon = 'invisible', mana = 440, level = 35, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Sharpshooter'] = {words = 'utito tempo san', exhaustion = 2000, premium = true, type = 'Instant', icon = 'sharpshooter', mana = 450, level = 60, soul = 0, group = {[2] = 10000, [3] = 10000}, vocations = {3, 7}},
|
||||
['Protector'] = {words = 'utamo tempo', exhaustion = 2000, premium = true, type = 'Instant', icon = 'protector', mana = 200, level = 55, soul = 0, group = {[1] = 10000, [3] = 2000}, vocations = {4, 8}},
|
||||
['Blood Rage'] = {words = 'utito tempo', exhaustion = 2000, premium = true, type = 'Instant', icon = 'bloodrage', mana = 290, level = 60, soul = 0, group = {[3] = 2000}, vocations = {4, 8}},
|
||||
['Train Party'] = {words = 'utito mas sio', exhaustion = 2000, premium = true, type = 'Instant', icon = 'trainparty', mana = 'Var.', level = 32, soul = 0, group = {[3] = 2000}, vocations = {8}},
|
||||
['Protect Party'] = {words = 'utamo mas sio', exhaustion = 2000, premium = true, type = 'Instant', icon = 'protectparty', mana = 'Var.', evel = 32, soul = 0, group = {[3] = 2000}, vocations = {7}},
|
||||
['Heal Party'] = {words = 'utura mas sio', exhaustion = 2000, premium = true, type = 'Instant', icon = 'healparty', mana = 'Var.', level = 32, soul = 0, group = {[3] = 2000}, vocations = {6}},
|
||||
['Enchant Party'] = {words = 'utori mas sio', exhaustion = 2000, premium = true, type = 'Instant', icon = 'enchantparty', mana = 'Var.', level = 32, soul = 0, group = {[3] = 2000}, vocations = {5}},
|
||||
['Summon Creature'] = {words = 'utevo res', exhaustion = 2000, premium = false, type = 'Instant', icon = 'summoncreature', mana = 'Var.', level = 25, soul = 0, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Conjure Arrow'] = {words = 'exevo con', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'conjurearrow', mana = 100, level = 13, soul = 1, group = {[3] = 2000}, vocations = {3, 7}},
|
||||
['Food'] = {words = 'exevo pan', exhaustion = 2000, premium = false, type = 'Instant', icon = 'food', mana = 120, level = 14, soul = 1, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Conjure Poisoned Arrow'] = {words = 'exevo con pox', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'poisonedarrow', mana = 130, level = 16, soul = 2, group = {[3] = 2000}, vocations = {3, 7}},
|
||||
['Conjure Bolt'] = {words = 'exevo con mort', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'conjurebolt', mana = 140, level = 17, soul = 2, group = {[3] = 2000}, vocations = {3, 7}},
|
||||
['Conjure Sniper Arrow'] = {words = 'exevo con hur', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'sniperarrow', mana = 160, level = 24, soul = 3, group = {[3] = 2000}, vocations = {3, 7}},
|
||||
['Conjure Explosive Arrow'] = {words = 'exevo con flam', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'explosivearrow', mana = 290, level = 25, soul = 3, group = {[3] = 2000}, vocations = {3, 7}},
|
||||
['Conjure Piercing Bolt'] = {words = 'exevo con grav', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'piercingbolt', mana = 180, level = 33, soul = 3, group = {[3] = 2000}, vocations = {3, 7}},
|
||||
['Enchant Staff'] = {words = 'exeta vis', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'enchantstaff', mana = 80, level = 41, soul = 0, group = {[3] = 2000}, vocations = {5}},
|
||||
['Enchant Spear'] = {words = 'exeta con', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'enchantspear', mana = 350, level = 45, soul = 3, group = {[3] = 2000}, vocations = {3, 7}},
|
||||
['Conjure Power Bolt'] = {words = 'exevo con vis', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'powerbolt', mana = 800, level = 59, soul = 3, group = {[3] = 2000}, vocations = {7}},
|
||||
['Poison Field'] = {words = 'adevo grav pox', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'poisonfield', mana = 200, level = 14, soul = 1, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Light Magic Missile'] = {words = 'adori min vis', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'lightmagicmissile', mana = 120, level = 15, soul = 1, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Fire Field'] = {words = 'adevo grav flam', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'firefield', mana = 240, level = 15, soul = 1, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Fireball'] = {words = 'adori flam', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'fireball', mana = 460, level = 27, soul = 3, group = {[3] = 2000}, vocations = {1, 5}},
|
||||
['Energy Field'] = {words = 'adevo grav vis', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'energyfield', mana = 320, level = 18, soul = 2, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Stalagmite'] = {words = 'adori tera', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'stalagmite', mana = 400, level = 24, soul = 2, group = {[3] = 2000}, vocations = {1, 5, 2, 6}},
|
||||
['Great Fireball'] = {words = 'adori mas flam', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'greatfireball', mana = 530, level = 30, soul = 3, group = {[3] = 2000}, vocations = {1, 5}},
|
||||
['Heavy Magic Missile'] = {words = 'adori vis', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'heavymagicmissile', mana = 350, level = 25, soul = 2, group = {[3] = 2000}, vocations = {1, 5, 2, 6}},
|
||||
['Poison Bomb'] = {words = 'adevo mas pox', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'poisonbomb', mana = 520, level = 25, soul = 2, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Firebomb'] = {words = 'adevo mas flam', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'firebomb', mana = 600, level = 27, soul = 3, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Soulfire'] = {words = 'adevo res flam', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'soulfire', mana = 600, level = 27, soul = 3, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Poison Wall'] = {words = 'adevo mas grav pox', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'poisonwall', mana = 640, level = 29, soul = 3, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Explosion'] = {words = 'adevo mas hur', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'explosion', mana = 570, level = 31, soul = 3, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Fire Wall'] = {words = 'adevo mas grav flam', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'firewall', mana = 780, level = 33, soul = 3, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Energybomb'] = {words = 'adevo mas vis', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'energybomb', mana = 880, level = 37, soul = 5, group = {[3] = 2000}, vocations = {1, 5}},
|
||||
['Energy Wall'] = {words = 'adevo mas grav vis', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'energywall', mana = 1000, level = 41, soul = 5, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Sudden Death'] = {words = 'adori gran mort', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'suddendeath', mana = 985, level = 45, soul = 5, group = {[3] = 2000}, vocations = {1, 5}},
|
||||
['Cure Poison Rune'] = {words = 'adana pox', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'antidote', mana = 200, level = 15, soul = 1, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Intense Healing Rune'] = {words = 'adura gran', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'intensehealingrune', mana = 240, level = 15, soul = 2, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Ultimate Healing Rune'] = {words = 'adura vita', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'ultimatehealingrune', mana = 400, level = 24, soul = 3, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Convince Creature'] = {words = 'adeta sio', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'convincecreature', mana = 200, level = 16, soul = 3, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Animate Dead'] = {words = 'adana mort', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'animatedead', mana = 600, level = 27, soul = 5, group = {[3] = 2000}, vocations = {1, 2, 5, 6}},
|
||||
['Chameleon'] = {words = 'adevo ina', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'chameleon', mana = 600, level = 27, soul = 2, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Destroy Field'] = {words = 'adito grav', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'destroyfield', mana = 120, level = 17, soul = 2, group = {[3] = 2000}, vocations = {1, 2, 3, 5, 6, 7}},
|
||||
['Desintegrate'] = {words = 'adito tera', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'desintegrate', mana = 200, level = 21, soul = 3, group = {[3] = 2000}, vocations = {1, 2, 3, 5, 6, 7}},
|
||||
['Magic Wall'] = {words = 'adevo grav tera', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'magicwall', mana = 750, level = 32, soul = 5, group = {[3] = 2000}, vocations = {1, 5}},
|
||||
['Wild Growth'] = {words = 'adevo grav vita', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'wildgrowth', mana = 600, level = 27, soul = 5, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Paralyze'] = {words = 'adana ani', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'paralyze', mana = 1400, level = 54, soul = 3, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Icicle'] = {words = 'adori frigo', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'icicle', mana = 460, level = 28, soul = 3, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Avalanche'] = {words = 'adori mas frigo', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'avalanche', mana = 530, level = 30, soul = 3, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Stone Shower'] = {words = 'adori mas tera', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'stoneshower', mana = 430, level = 28, soul = 3, group = {[3] = 2000}, vocations = {2, 6}},
|
||||
['Thunderstorm'] = {words = 'adori mas vis', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'thunderstorm', mana = 430, level = 28, soul = 3, group = {[3] = 2000}, vocations = {1, 5}},
|
||||
['Holy Missile'] = {words = 'adori san', exhaustion = 2000, premium = false, type = 'Conjure', icon = 'holymissile', mana = 350, level = 27, soul = 3, group = {[3] = 2000}, vocations = {3, 7}}
|
||||
}
|
||||
|
||||
-- ['const_name'] = {client_id, TFS_id}
|
||||
-- Conversion from TFS icon id to the id used by client (icons.png order)
|
||||
SpellIcons = {
|
||||
['intenserecovery'] = {16, 160},
|
||||
['recovery'] = {15, 159},
|
||||
['intensewoundcleansing'] = {4, 158},
|
||||
['ultimateterrastrike'] = {37, 157},
|
||||
['ultimateicestrike'] = {34, 156},
|
||||
['ultimateenergystrike'] = {31, 155},
|
||||
['ultimateflamestrike'] = {28, 154},
|
||||
['strongterrastrike'] = {36, 153},
|
||||
['strongicestrike'] = {33, 152},
|
||||
['strongenergystrike'] = {30, 151},
|
||||
['strongflamestrike'] = {27, 150},
|
||||
['lightning'] = {51, 149},
|
||||
['physicalstrike'] = {17, 148},
|
||||
['curecurse'] = {11, 147},
|
||||
['curseelectrification'] = {14, 146},
|
||||
['cureburning'] = {13, 145},
|
||||
['curebleeding'] = {12, 144},
|
||||
['holyflash'] = {53, 143},
|
||||
['envenom'] = {58, 142},
|
||||
['inflictwound'] = {57, 141},
|
||||
['electrify'] = {56, 140},
|
||||
['curse'] = {54, 139},
|
||||
['ignite'] = {55, 138},
|
||||
-- [[ 136 / 137 Unknown ]]
|
||||
['sharpshooter'] = {121, 135},
|
||||
['swiftfoot'] = {119, 134},
|
||||
['bloodrage'] = {96, 133},
|
||||
['protector'] = {122, 132},
|
||||
['charge'] = {98, 131},
|
||||
['holymissile'] = {76, 130},
|
||||
['enchantparty'] = {113, 129},
|
||||
['healparty'] = {126, 128},
|
||||
['protectparty'] = {123, 127},
|
||||
['trainparty'] = {120, 126},
|
||||
['divinehealing'] = {2, 125},
|
||||
['divinecaldera'] = {40, 124},
|
||||
['woundcleansing'] = {3, 123},
|
||||
['divinemissile'] = {39, 122},
|
||||
['icewave'] = {45, 121},
|
||||
['terrawave'] = {47, 120},
|
||||
['rageoftheskies'] = {52, 119},
|
||||
['eternalwinter'] = {50, 118},
|
||||
['thunderstorm'] = {63, 117},
|
||||
['stoneshower'] = {65, 116},
|
||||
['avalanche'] = {92, 115},
|
||||
['icicle'] = {75, 114},
|
||||
['terrastrike'] = {35, 113},
|
||||
['icestrike'] = {32, 112},
|
||||
['eterealspear'] = {18, 111},
|
||||
['enchantspear'] = {104, 110},
|
||||
['piercingbolt'] = {110, 109},
|
||||
['sniperarrow'] = {112, 108},
|
||||
['whirlwindthrow'] = {19, 107},
|
||||
['groundshaker'] = {25, 106},
|
||||
['fierceberserk'] = {22, 105},
|
||||
-- [[ 96 - 104 Unknown ]]
|
||||
['powerbolt'] = {108, 95},
|
||||
['wildgrowth'] = {61, 94},
|
||||
['challenge'] = {97, 93},
|
||||
['enchantstaff'] = {103, 92},
|
||||
['poisonbomb'] = {70, 91},
|
||||
['cancelinvisibility'] = {95, 90},
|
||||
['flamestrike'] = {26, 89},
|
||||
['energystrike'] = {29, 88},
|
||||
['deathstrike'] = {38, 87},
|
||||
['magicwall'] = {72, 86},
|
||||
['healfriend'] = {8, 84},
|
||||
['animatedead'] = {93, 83},
|
||||
['masshealing'] = {9, 82},
|
||||
['levitate'] = {125, 81},
|
||||
['berserk'] = {21, 80},
|
||||
['conjurebolt'] = {107, 79},
|
||||
['desintegrate'] = {88, 78},
|
||||
['stalagmite'] = {66, 77},
|
||||
['magicrope'] = {105, 76},
|
||||
['ultimatelight'] = {115, 75},
|
||||
-- [[ 71 - 64 TFS House Commands ]]
|
||||
-- [[ 63 - 70 Unknown ]]
|
||||
['annihilation'] = {24, 62},
|
||||
['brutalstrike'] = {23, 61},
|
||||
-- [[ 60 Unknown ]]
|
||||
['frontsweep'] = {20, 59},
|
||||
-- [[ 58 Unknown ]]
|
||||
['strongetherealspear'] = {59, 57},
|
||||
['wrathofnature'] = {48, 56},
|
||||
['energybomb'] = {86, 55},
|
||||
['paralyze'] = {71, 54},
|
||||
-- [[ 53 Unknown ]]
|
||||
-- [[ 52 TFS Retrieve Friend ]]
|
||||
['conjurearrow'] = {106, 51},
|
||||
['soulfire'] = {67, 50},
|
||||
['explosivearrow'] = {109, 49},
|
||||
['poisonedarrow'] = {111, 48},
|
||||
-- [[ 46 / 47 Unknown ]]
|
||||
['invisible'] = {94, 45},
|
||||
['magicshield'] = {124, 44},
|
||||
['strongicewave'] = {46, 43},
|
||||
['food'] = {99, 42},
|
||||
-- [[ 40 / 41 Unknown ]]
|
||||
['stronghaste'] = {102, 39},
|
||||
['creatureillusion'] = {100, 38},
|
||||
-- [[ 37 TFS Move ]]
|
||||
['salvation'] = {60, 36},
|
||||
-- [[ 34 / 35 Unknown ]]
|
||||
['energywall'] = {84, 33},
|
||||
['poisonwall'] = {68, 32},
|
||||
['antidote'] = {10, 31},
|
||||
['destroyfield'] = {87, 30},
|
||||
['curepoison'] = {10, 29},
|
||||
['firewall'] = {80, 28},
|
||||
['energyfield'] = {85, 27},
|
||||
['poisonfield'] = {69, 26},
|
||||
['firefield'] = {81, 25},
|
||||
['hellscore'] = {49, 24},
|
||||
['greatenergybeam'] = {42, 23},
|
||||
['energybeam'] = {41, 22},
|
||||
['suddendeath'] = {64, 21},
|
||||
['findperson'] = {114, 20},
|
||||
['firewave'] = {44, 19},
|
||||
['explosion'] = {83, 18},
|
||||
['firebomb'] = {82, 17},
|
||||
['greatfireball'] = {78, 16},
|
||||
['fireball'] = {79, 15},
|
||||
['chameleon'] = {91, 14},
|
||||
['energywave'] = {43, 13},
|
||||
['convincecreature'] = {90, 12},
|
||||
['greatlight'] = {116, 11},
|
||||
['light'] = {117, 10},
|
||||
['summoncreature'] = {118, 9},
|
||||
['heavymagicmissile'] = {77, 8},
|
||||
['lightmagicmissile'] = {73, 7},
|
||||
['haste'] = {101, 6},
|
||||
['ultimatehealingrune'] = {62, 5},
|
||||
['intensehealingrune'] = {74, 4},
|
||||
['ultimatehealing'] = {1, 3},
|
||||
['intensehealing'] = {7, 2},
|
||||
['lighthealing'] = {6, 1}
|
||||
}
|
||||
|
||||
VocationNames = {
|
||||
[1] = 'Sorcerer',
|
||||
[2] = 'Druid',
|
||||
[3] = 'Paladin',
|
||||
[4] = 'Knight',
|
||||
[5] = 'Master Sorcerer',
|
||||
[6] = 'Elder Druid',
|
||||
[7] = 'Royal Paladin',
|
||||
[8] = 'Elite Knight'
|
||||
}
|
||||
|
||||
SpellGroups = {
|
||||
[1] = 'Attack',
|
||||
[2] = 'Healing',
|
||||
[3] = 'Support',
|
||||
[4] = 'Powerstrikes'
|
||||
}
|
@@ -52,6 +52,9 @@ void BitmapFont::load(const OTMLNodePtr& fontNode)
|
||||
m_glyphsSize[32].setWidth(spaceWidth);
|
||||
m_glyphsSize[160].setWidth(spaceWidth);
|
||||
|
||||
// use 127 as spacer [Width: 1]
|
||||
m_glyphsSize[127].setWidth(1);
|
||||
|
||||
// new line actually has a size that will be useful in multiline algorithm
|
||||
m_glyphsSize[(uchar)'\n'] = Size(1, m_glyphHeight);
|
||||
|
||||
|
@@ -60,6 +60,9 @@ Creature::Creature() : Thing()
|
||||
|
||||
void Creature::draw(const Point& dest, float scaleFactor, bool animate)
|
||||
{
|
||||
if(!canBeSeen())
|
||||
return;
|
||||
|
||||
Point animationOffset = animate ? m_walkOffset : Point(0,0);
|
||||
|
||||
if(m_showTimedSquare && animate) {
|
||||
@@ -523,6 +526,7 @@ void Creature::setDirection(Otc::Direction direction)
|
||||
|
||||
void Creature::setOutfit(const Outfit& outfit)
|
||||
{
|
||||
Outfit oldOutfit = outfit;
|
||||
if(outfit.getCategory() != ThingCategoryCreature) {
|
||||
if(!g_things.isValidDatId(outfit.getAuxId(), outfit.getCategory()))
|
||||
return;
|
||||
@@ -534,6 +538,8 @@ void Creature::setOutfit(const Outfit& outfit)
|
||||
m_outfit = outfit;
|
||||
}
|
||||
m_walkAnimationPhase = 0; // might happen when player is walking and outfit is changed.
|
||||
|
||||
callLuaField("onOutfitChange", m_outfit, oldOutfit);
|
||||
}
|
||||
|
||||
void Creature::setSpeed(uint16 speed)
|
||||
|
@@ -102,6 +102,8 @@ public:
|
||||
|
||||
bool isWalking() { return m_walking; }
|
||||
bool isRemoved() { return m_removed; }
|
||||
bool isInvisible() { return m_outfit.getCategory() == ThingCategoryEffect && m_outfit.getAuxId() == 13; }
|
||||
bool canBeSeen() { return !isInvisible() || isPlayer(); }
|
||||
|
||||
bool isCreature() { return true; }
|
||||
|
||||
|
@@ -368,6 +368,8 @@ void OTClient::registerLuaFunctions()
|
||||
g_lua.bindClassMemberFunction<Creature>("showStaticSquare", &Creature::showStaticSquare);
|
||||
g_lua.bindClassMemberFunction<Creature>("hideStaticSquare", &Creature::hideStaticSquare);
|
||||
g_lua.bindClassMemberFunction<Creature>("isWalking", &Creature::isWalking);
|
||||
g_lua.bindClassMemberFunction<Creature>("isInvisible", &Creature::isInvisible);
|
||||
g_lua.bindClassMemberFunction<Creature>("canBeSeen", &Creature::canBeSeen);
|
||||
|
||||
g_lua.registerClass<ItemType>();
|
||||
g_lua.bindClassMemberFunction<ItemType>("getServerId", &ItemType::getServerId);
|
||||
|
@@ -28,6 +28,8 @@ int push_luavalue(const Outfit& outfit)
|
||||
g_lua.newTable();
|
||||
g_lua.pushInteger(outfit.getId());
|
||||
g_lua.setField("type");
|
||||
g_lua.pushInteger(outfit.getAuxId());
|
||||
g_lua.setField("auxType");
|
||||
g_lua.pushInteger(outfit.getAddons());
|
||||
g_lua.setField("addons");
|
||||
g_lua.pushInteger(outfit.getHead());
|
||||
@@ -50,6 +52,8 @@ bool luavalue_cast(int index, Outfit& outfit)
|
||||
if(g_lua.isTable(index)) {
|
||||
g_lua.getField("type", index);
|
||||
outfit.setId(g_lua.popInteger());
|
||||
g_lua.getField("auxType", index);
|
||||
outfit.setAuxId(g_lua.popInteger());
|
||||
g_lua.getField("addons", index);
|
||||
outfit.setAddons(g_lua.popInteger());
|
||||
g_lua.getField("head", index);
|
||||
|
@@ -175,6 +175,9 @@ void MapView::draw(const Rect& rect)
|
||||
// avoid drawing texts on map in far zoom outs
|
||||
if(m_viewMode == NEAR_VIEW && m_drawTexts) {
|
||||
for(const CreaturePtr& creature : m_cachedFloorVisibleCreatures) {
|
||||
if(!creature->canBeSeen())
|
||||
continue;
|
||||
|
||||
Point creatureOffset = Point(16 - creature->getDisplacementX(), -3 - creature->getDisplacementY());
|
||||
Position pos = creature->getPosition();
|
||||
Point p = transformPositionTo2D(pos, cameraPosition) - drawOffset;
|
||||
@@ -378,7 +381,7 @@ void MapView::updateVisibleTilesCache(int start)
|
||||
m_spiral.clear();
|
||||
}
|
||||
|
||||
if(start == 0 && m_drawTexts && m_viewMode <= NEAR_VIEW)
|
||||
if(start == 0 && m_viewMode <= NEAR_VIEW)
|
||||
m_cachedFloorVisibleCreatures = g_map.getSpectators(cameraPosition, false);
|
||||
}
|
||||
|
||||
|
@@ -40,13 +40,13 @@ void buildMessageModesMap(int version) {
|
||||
messageModesMap[Otc::MessageNpcFrom] = 5;
|
||||
messageModesMap[Otc::MessagePrivateFrom] = 6;
|
||||
messageModesMap[Otc::MessagePrivateTo] = 6;
|
||||
messageModesMap[Otc::MessageChannelHighlight] = 7;
|
||||
messageModesMap[Otc::MessageChannel] = 8;
|
||||
messageModesMap[Otc::MessageChannel] = 7;
|
||||
messageModesMap[Otc::MessageChannelManagement] = 8;
|
||||
messageModesMap[Otc::MessageGamemasterBroadcast] = 9;
|
||||
messageModesMap[Otc::MessageGamemasterChannel] = 10;
|
||||
messageModesMap[Otc::MessageGamemasterPrivateFrom] = 11;
|
||||
messageModesMap[Otc::MessageGamemasterPrivateTo] = 11;
|
||||
messageModesMap[Otc::MessageChannelManagement] = 12;
|
||||
messageModesMap[Otc::MessageChannelHighlight] = 12;
|
||||
messageModesMap[Otc::MessageMonsterSay] = 13;
|
||||
messageModesMap[Otc::MessageMonsterYell] = 14;
|
||||
messageModesMap[Otc::MessageWarning] = 15;
|
||||
|
@@ -109,15 +109,15 @@ void ThingTypeManager::loadOtb(const std::string& file)
|
||||
if(signature != 0)
|
||||
stdext::throw_exception("invalid otb file");
|
||||
|
||||
root->getU32(); // flags
|
||||
root->skip(4);
|
||||
|
||||
m_otbMajorVersion = root->getU32();
|
||||
m_otbMinorVersion = root->getU32();
|
||||
root->getU32(); // build number
|
||||
root->skip(4);
|
||||
root->skip(128); // description
|
||||
|
||||
m_reverseItemTypes.clear();
|
||||
m_itemTypes.resize(root->getChildren().size(), m_nullItemType);
|
||||
m_itemTypes.resize(root->getChildren().size() + 1, m_nullItemType);
|
||||
|
||||
for(const BinaryTreePtr& node : root->getChildren()) {
|
||||
ItemTypePtr itemType(new ItemType);
|
||||
@@ -185,7 +185,7 @@ void ThingTypeManager::parseItemType(uint16 id, TiXmlElement* elem)
|
||||
{
|
||||
uint16 serverId = id;
|
||||
ItemTypePtr itemType = nullptr;
|
||||
if(serverId > 20000 && id < 20100) {
|
||||
if(serverId > 20000 && serverId < 20100) {
|
||||
serverId -= 20000;
|
||||
|
||||
itemType = ItemTypePtr(new ItemType);
|
||||
@@ -193,15 +193,8 @@ void ThingTypeManager::parseItemType(uint16 id, TiXmlElement* elem)
|
||||
addItemType(itemType);
|
||||
}
|
||||
|
||||
if(!itemType) {
|
||||
itemType = getItemType(serverId);
|
||||
if(itemType == m_nullItemType) {
|
||||
itemType = ItemTypePtr(new ItemType);
|
||||
itemType->setServerId(id);
|
||||
addItemType(itemType);
|
||||
}
|
||||
}
|
||||
|
||||
itemType = getItemType(serverId);
|
||||
assert(itemType && "Internal error");
|
||||
itemType->setName(elem->Attribute("name"));
|
||||
for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
|
||||
std::string key = attrib->Attribute("key");
|
||||
@@ -238,8 +231,8 @@ void ThingTypeManager::parseItemType(uint16 id, TiXmlElement* elem)
|
||||
void ThingTypeManager::addItemType(const ItemTypePtr& itemType)
|
||||
{
|
||||
uint16 id = itemType->getServerId();
|
||||
if(m_itemTypes.size() <= id)
|
||||
m_itemTypes.resize((id * 3) / 2 + 1, m_nullItemType);
|
||||
if(id > m_itemTypes.size())
|
||||
m_itemTypes.resize(id + 1, m_nullItemType);
|
||||
m_itemTypes[id] = itemType;
|
||||
}
|
||||
|
||||
|
@@ -451,7 +451,7 @@ bool Tile::isWalkable()
|
||||
|
||||
if(thing->isCreature()) {
|
||||
CreaturePtr creature = thing->static_self_cast<Creature>();
|
||||
if(!creature->isPassable())
|
||||
if(!creature->isPassable() && creature->canBeSeen())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user