Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d4370e7c5d | ||
![]() |
8bb115d6d4 | ||
![]() |
c7890e7a49 | ||
![]() |
a6424f3022 | ||
![]() |
7114946278 | ||
![]() |
5f72488eba | ||
![]() |
6acdb0fd64 | ||
![]() |
7f864003d8 | ||
![]() |
053d29a64b | ||
![]() |
3990ee76e7 | ||
![]() |
f48fb4343f | ||
![]() |
478e796dbd | ||
![]() |
95e46dbbaf | ||
![]() |
c0a3b083f6 | ||
![]() |
ba407072a5 | ||
![]() |
286a0fea58 | ||
![]() |
adc89f132f | ||
![]() |
01993c133d | ||
![]() |
5227a65d74 | ||
![]() |
af6a32263c | ||
![]() |
efdfb0e946 | ||
![]() |
b4642f9038 | ||
![]() |
f26b359ae5 | ||
![]() |
ec8a9eddf2 |
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(otclient)
|
||||
|
||||
set(VERSION "0.5.4")
|
||||
set(VERSION "0.5.5")
|
||||
|
||||
set(FRAMEWORK_SOUND ON)
|
||||
set(FRAMEWORK_GRAPHICS ON)
|
||||
|
3
init.lua
@@ -7,9 +7,6 @@ g_logger.setLogFile(g_resources.getWorkDir() .. g_app.getCompactName() .. ".log"
|
||||
-- print first terminal message
|
||||
g_logger.info(g_app.getName() .. ' ' .. g_app.getVersion() .. ' rev ' .. g_app.getBuildRevision() .. ' (' .. g_app.getBuildCommit() .. ') built on ' .. g_app.getBuildDate() .. ' for arch ' .. g_app.getBuildArch())
|
||||
|
||||
--add base folder to search path
|
||||
g_resources.addSearchPath(g_resources.getWorkDir())
|
||||
|
||||
-- add modules directory to the search path
|
||||
if not g_resources.addSearchPath(g_resources.getWorkDir() .. "modules", true) then
|
||||
g_logger.fatal("Unable to add modules directory to the search path.")
|
||||
|
@@ -42,13 +42,17 @@ Panel
|
||||
id: fullscreen
|
||||
!text: tr('Fullscreen')
|
||||
|
||||
OptionCheckBox
|
||||
id: dontStretchShrink
|
||||
!text: tr('Don\'t stretch/shrink Game Window')
|
||||
|
||||
Label
|
||||
id: backgroundFrameRateLabel
|
||||
!text: tr('Game framerate limit: %s', 'max')
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 6
|
||||
margin-top: 16
|
||||
@onSetup: |
|
||||
local value = Options.getOption('backgroundFrameRate')
|
||||
local text = value
|
||||
|
@@ -5,6 +5,7 @@ local defaultOptions = {
|
||||
showFps = true,
|
||||
showPing = true,
|
||||
fullscreen = false,
|
||||
dontStretchShrink = false,
|
||||
classicControl = false,
|
||||
walkBooster = false,
|
||||
smartWalk = false,
|
||||
@@ -144,6 +145,10 @@ function Options.setOption(key, value)
|
||||
end)
|
||||
elseif key == 'fullscreen' then
|
||||
g_window.setFullscreen(value)
|
||||
elseif key == 'dontStretchShrink' then
|
||||
addEvent(function()
|
||||
modules.game_interface.updateStretchShrink()
|
||||
end)
|
||||
elseif key == 'enableMusic' then
|
||||
g_sounds.enableMusic(value)
|
||||
elseif key == 'showLeftPanel' then
|
||||
|
@@ -17,7 +17,7 @@ OptionCheckBox < CheckBox
|
||||
MainWindow
|
||||
id: optionsWindow
|
||||
!text: tr('Options')
|
||||
size: 350 280
|
||||
size: 350 290
|
||||
|
||||
@onEnter: Options.hide()
|
||||
@onEscape: Options.hide()
|
||||
|
@@ -11,13 +11,8 @@ TabBarButton < UIButton
|
||||
color: #aaaaaa
|
||||
anchors.top: parent.top
|
||||
padding: 5
|
||||
anchors.left: parent.left
|
||||
|
||||
$first:
|
||||
anchors.left: parent.left
|
||||
|
||||
$!first:
|
||||
anchors.left: prev.right
|
||||
margin-left: 5
|
||||
|
||||
$hover !checked:
|
||||
image-clip: 0 20 20 20
|
||||
|
@@ -9,7 +9,9 @@ function UISplitter.create()
|
||||
end
|
||||
|
||||
function UISplitter:onHoverChange(hovered)
|
||||
if hovered then
|
||||
-- Check if margin can be changed
|
||||
local margin = (self.vertical and self:getMarginBottom() or self:getMarginRight())
|
||||
if hovered and (self:canUpdateMargin(margin + 1) ~= margin or self:canUpdateMargin(margin - 1) ~= margin) then
|
||||
if g_mouse.isCursorChanged() or g_mouse.isPressed() then return end
|
||||
if self:getWidth() > self:getHeight() then
|
||||
g_mouse.setVerticalCursor()
|
||||
|
@@ -6,6 +6,60 @@ local function onTabClick(tab)
|
||||
tab.tabBar:selectTab(tab)
|
||||
end
|
||||
|
||||
local function updateMargins(tabBar)
|
||||
if #tabBar.tabs == 0 then return end
|
||||
|
||||
local currentMargin = 0
|
||||
for i = 1, #tabBar.tabs do
|
||||
if i == 1 then
|
||||
tabBar.tabs[i]:setMarginLeft(0)
|
||||
else
|
||||
tabBar.tabs[i]:setMarginLeft(5 * (i - 1) + currentMargin)
|
||||
end
|
||||
currentMargin = currentMargin + tabBar.tabs[i]:getWidth()
|
||||
end
|
||||
end
|
||||
|
||||
local function onTabMousePress(tab, mousePos, mouseButton)
|
||||
if mouseButton == MouseLeftButton and tab.tabBar.tabsMoveable then
|
||||
tab.tabBar.selected = tab
|
||||
end
|
||||
end
|
||||
|
||||
local function onTabMouseRelease(tab, mousePos, mouseButton)
|
||||
local tabs = tab.tabBar.tabs
|
||||
if tab.tabBar.selected then
|
||||
local lastMargin = -5
|
||||
for i = 1, #tabs do
|
||||
local nextMargin = tabs[i + 1] and (tabs[i + 1] == tab and (tabs[i]:getMarginLeft() + tabs[i]:getWidth() + 5) or tabs[i + 1]:getMarginLeft()) or tab.tabBar:getWidth()
|
||||
if tab:getMarginLeft() >= lastMargin and tab:getMarginLeft() < nextMargin then
|
||||
if tabs[i] ~= tab then
|
||||
local newIndex = table.find(tab.tabBar.tabs, tab.tabBar.tabs[i])
|
||||
table.remove(tab.tabBar.tabs, table.find(tab.tabBar.tabs, tab))
|
||||
table.insert(tab.tabBar.tabs, newIndex, tab)
|
||||
updateMargins(tab.tabBar)
|
||||
break
|
||||
else
|
||||
updateMargins(tab.tabBar)
|
||||
break
|
||||
end
|
||||
end
|
||||
lastMargin = tab.tabBar.tabs[i]:getMarginLeft() == 0 and -5 or tab.tabBar.tabs[i]:getMarginLeft()
|
||||
end
|
||||
end
|
||||
|
||||
tab.tabBar.selected = nil
|
||||
end
|
||||
|
||||
local function onTabMouseMove(tab, mousePos, mouseMoved)
|
||||
if tab == tab.tabBar.selected then
|
||||
local newMargin = tab:getMarginLeft() + mouseMoved.x
|
||||
if newMargin >= -5 and newMargin < tab.tabBar:getWidth() - tab:getWidth() then
|
||||
tab:setMarginLeft(newMargin)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function tabBlink(tab)
|
||||
if not tab.blinking then return end
|
||||
tab:setOn(not tab:isOn())
|
||||
@@ -17,6 +71,8 @@ function UITabBar.create()
|
||||
local tabbar = UITabBar.internalCreate()
|
||||
tabbar:setFocusable(false)
|
||||
tabbar.tabs = {}
|
||||
tabbar.selected = nil -- dragged tab
|
||||
tabsMoveable = false
|
||||
return tabbar
|
||||
end
|
||||
|
||||
@@ -41,16 +97,52 @@ function UITabBar:addTab(text, panel)
|
||||
tab:setText(text)
|
||||
tab:setWidth(tab:getTextSize().width + tab:getPaddingLeft() + tab:getPaddingRight())
|
||||
tab.onClick = onTabClick
|
||||
tab.onMousePress = onTabMousePress
|
||||
tab.onMouseRelease = onTabMouseRelease
|
||||
tab.onMouseMove = onTabMouseMove
|
||||
tab.onDestroy = function() tab.tabPanel:destroy() end
|
||||
|
||||
table.insert(self.tabs, tab)
|
||||
if #self.tabs == 1 then
|
||||
self:selectTab(tab)
|
||||
tab:setMarginLeft(0)
|
||||
else
|
||||
local newMargin = 5 * (#self.tabs - 1)
|
||||
for i = 1, #self.tabs - 1 do
|
||||
newMargin = newMargin + self.tabs[i]:getWidth()
|
||||
end
|
||||
tab:setMarginLeft(newMargin)
|
||||
end
|
||||
|
||||
return tab
|
||||
end
|
||||
|
||||
-- Additional function to move the tab by lua
|
||||
function UITabBar:moveTab(tab, units)
|
||||
local index = table.find(self.tabs, tab)
|
||||
if index == nil then return end
|
||||
|
||||
local focus = false
|
||||
if self.currentTab == tab then
|
||||
self:selectPrevTab()
|
||||
focus = true
|
||||
end
|
||||
|
||||
table.remove(self.tabs, index)
|
||||
|
||||
local newIndex = math.min(#self.tabs+1, math.max(index + units, 1))
|
||||
table.insert(self.tabs, newIndex, tab)
|
||||
if focus then self:selectTab(tab) end
|
||||
updateMargins(self)
|
||||
return newIndex
|
||||
end
|
||||
|
||||
function UITabBar:onStyleApply(styleName, styleNode)
|
||||
if styleNode['moveable'] then
|
||||
self.tabsMoveable = styleNode['moveable']
|
||||
end
|
||||
end
|
||||
|
||||
function UITabBar:removeTab(tab)
|
||||
local index = table.find(self.tabs, tab)
|
||||
if index == nil then return end
|
||||
|
BIN
modules/game_combatcontrols/Thumbs.db
Normal file
@@ -272,8 +272,8 @@ function addText(text, speaktype, tabName, creatureName)
|
||||
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,
|
||||
local letterWidth = { -- New line (10) and Space (32) have width 1 because they are printed and not replaced with spacer
|
||||
[10] = 1, [32] = 1, [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,
|
||||
@@ -324,7 +324,7 @@ function addTabText(text, speaktype, tab, creatureName)
|
||||
|
||||
|
||||
local player = g_game.getLocalPlayer()
|
||||
if speaktype.npcChat and player:getName() ~= creatureName then -- Check if it is the npc who is talking
|
||||
if speaktype.npcChat and (player:getName() ~= creatureName or player:getName() == 'Account Manager') then -- Check if it is the npc who is talking
|
||||
local highlightData = getHighlightedText(text)
|
||||
if #highlightData == 0 then
|
||||
labelHighlight:setText("")
|
||||
@@ -341,16 +341,30 @@ function addTabText(text, speaktype, tab, creatureName)
|
||||
label:setText(text)
|
||||
|
||||
-- Calculate the positions of the highlighted text and fill with string.char(127) [Width: 1]
|
||||
local drawText = label:getDrawText()
|
||||
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))])
|
||||
local tmpChar = string.byte(drawText:sub(letter, letter))
|
||||
local fillChar = (tmpChar == 10 or tmpChar == 32) and string.char(tmpChar) or string.char(127)
|
||||
|
||||
tmpText = tmpText .. string.rep(fillChar, letterWidth[tmpChar])
|
||||
end
|
||||
tmpText = tmpText .. dataBlock.words
|
||||
end
|
||||
|
||||
-- Fill the highlight label to the same size as default label
|
||||
local finalBlockEnd = (highlightData[(#highlightData/3-1)*3+2] or 1)
|
||||
for letter = finalBlockEnd, drawText:len() do
|
||||
local tmpChar = string.byte(drawText:sub(letter, letter))
|
||||
local fillChar = (tmpChar == 10 or tmpChar == 32) and string.char(tmpChar) or string.char(127)
|
||||
|
||||
tmpText = tmpText .. string.rep(fillChar, letterWidth[tmpChar])
|
||||
end
|
||||
|
||||
labelHighlight:setText(tmpText)
|
||||
end
|
||||
else
|
||||
@@ -530,14 +544,31 @@ function applyMessagePrefixies(name, level, message)
|
||||
end
|
||||
|
||||
function onTalk(name, level, mode, message, channelId, creaturePos)
|
||||
if mode == MessageModes.GamemasterBroadcast then
|
||||
modules.game_textmessage.displayBroadcastMessage(name .. ': ' .. message)
|
||||
return
|
||||
end
|
||||
|
||||
if ignoreNpcMessages and mode == MessageModes.NpcFrom then return end
|
||||
|
||||
if (mode == MessageModes.Say or mode == MessageModes.Whisper or mode == MessageModes.Yell or
|
||||
mode == MessageModes.Spell or mode == MessageModes.MonsterSay or mode == MessageModes.MonsterYell or
|
||||
mode == MessageModes.NpcFrom or mode == MessageModes.BarkLow or mode == MessageModes.BarkLoud) and
|
||||
creaturePos then
|
||||
-- Remove curly braces from screen message
|
||||
local staticMessage = message
|
||||
if mode == MessageModes.NpcFrom then
|
||||
local highlightData = getHighlightedText(staticMessage)
|
||||
if #highlightData > 0 then
|
||||
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] }
|
||||
staticMessage = staticMessage:gsub("{"..dataBlock.words.."}", dataBlock.words)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local staticText = StaticText.create()
|
||||
staticText:addMessage(name, mode, message)
|
||||
staticText:addMessage(name, mode, staticMessage)
|
||||
g_map.addThing(staticText, creaturePos, -1)
|
||||
end
|
||||
|
||||
|
@@ -78,6 +78,7 @@ Panel
|
||||
anchors.top: prev.top
|
||||
anchors.right: next.left
|
||||
margin-left: 5
|
||||
moveable: true
|
||||
|
||||
TabButton
|
||||
id: nextChannelButton
|
||||
|
BIN
modules/game_cooldown/Thumbs.db
Normal file
117
modules/game_cooldown/cooldown.lua
Normal file
@@ -0,0 +1,117 @@
|
||||
cooldownWindow = nil
|
||||
cooldownButton = nil
|
||||
contentsPanel = nil
|
||||
spellCooldownPanel = nil
|
||||
|
||||
function init()
|
||||
connect(g_game, { onGameStart = show,
|
||||
onGameEnd = hide,
|
||||
onSpellGroupCooldown = onSpellGroupCooldown,
|
||||
onSpellCooldown = onSpellCooldown })
|
||||
|
||||
cooldownButton = TopMenu.addRightGameToggleButton('cooldownButton', tr('Cooldowns'), 'cooldown.png', toggle)
|
||||
cooldownButton:setOn(true)
|
||||
cooldownButton:hide()
|
||||
|
||||
cooldownWindow = g_ui.loadUI('cooldown.otui', modules.game_interface.getRightPanel())
|
||||
cooldownWindow:disableResize()
|
||||
cooldownWindow:setup()
|
||||
|
||||
contentsPanel = cooldownWindow:getChildById('contentsPanel')
|
||||
spellCooldownPanel = contentsPanel:getChildById('spellCooldownPanel')
|
||||
|
||||
if g_game.isOnline() then
|
||||
show()
|
||||
end
|
||||
end
|
||||
|
||||
function terminate()
|
||||
disconnect(g_game, { onGameStart = show,
|
||||
onGameEnd = hide,
|
||||
onSpellGroupCooldown = onSpellGroupCooldown,
|
||||
onSpellCooldown = onSpellCooldown })
|
||||
|
||||
cooldownButton:destroy()
|
||||
cooldownWindow:destroy()
|
||||
end
|
||||
|
||||
function onMiniWindowClose()
|
||||
cooldownButton:setOn(false)
|
||||
end
|
||||
|
||||
function toggle()
|
||||
if cooldownButton:isOn() then
|
||||
cooldownWindow:close()
|
||||
cooldownButton:setOn(false)
|
||||
else
|
||||
cooldownWindow:open()
|
||||
cooldownButton:setOn(true)
|
||||
end
|
||||
end
|
||||
|
||||
function show()
|
||||
if g_game.getFeature(GameSpellList) then
|
||||
cooldownWindow:show()
|
||||
cooldownButton:show()
|
||||
end
|
||||
end
|
||||
|
||||
function hide()
|
||||
cooldownWindow:hide()
|
||||
cooldownButton:hide()
|
||||
end
|
||||
|
||||
function updateProgressRect(progressRect, interval, init)
|
||||
if init then
|
||||
progressRect:setPercent(0)
|
||||
else
|
||||
progressRect:setPercent(progressRect:getPercent() + 4)
|
||||
end
|
||||
|
||||
if progressRect:getPercent() < 100 then
|
||||
removeEvent(progressRect.event)
|
||||
progressRect.event = scheduleEvent(function() updateProgressRect(progressRect, interval) end, interval)
|
||||
end
|
||||
end
|
||||
|
||||
function onSpellCooldown(iconId, duration)
|
||||
local spellName = SpelllistSettings[modules.game_spelllist.getSpelllistProfile()].spellIcons[iconId]
|
||||
if not spellName then return end
|
||||
|
||||
local otcIconId = tonumber(SpellInfo[modules.game_spelllist.getSpelllistProfile()][spellName].icon)
|
||||
if not otcIconId and SpellIcons[SpellInfo[modules.game_spelllist.getSpelllistProfile()][spellName].icon] then
|
||||
otcIconId = SpellIcons[SpellInfo[modules.game_spelllist.getSpelllistProfile()][spellName].icon][1]
|
||||
end
|
||||
|
||||
if not otcIconId then return end
|
||||
|
||||
local icon = spellCooldownPanel:getChildById(spellName)
|
||||
if not icon then
|
||||
icon = g_ui.createWidget('SpellIcon', spellCooldownPanel)
|
||||
icon:setId(spellName)
|
||||
icon:setImageSource('/game_cooldown/icons/' .. SpelllistSettings[modules.game_spelllist.getSpelllistProfile()].iconFile)
|
||||
icon:setImageClip(modules.game_spelllist.getIconImageClip(otcIconId))
|
||||
icon.event = scheduleEvent(function() icon:destroy() end, duration)
|
||||
|
||||
local progressRect = g_ui.createWidget('SpellProgressRect', icon)
|
||||
updateProgressRect(progressRect, duration/25, true)
|
||||
progressRect:setTooltip(spellName)
|
||||
end
|
||||
end
|
||||
|
||||
function onSpellGroupCooldown(groupId, duration)
|
||||
if not SpellGroups[groupId] then return end
|
||||
|
||||
local icon = contentsPanel:getChildById('groupIcon' .. SpellGroups[groupId])
|
||||
local progressRect = contentsPanel:getChildById('progressRect' .. SpellGroups[groupId])
|
||||
if icon then
|
||||
icon:setOn(true)
|
||||
removeEvent(icon.event)
|
||||
icon.event = scheduleEvent(function() icon:setOn(false) end, duration)
|
||||
end
|
||||
|
||||
if progressRect then
|
||||
removeEvent(progressRect.event)
|
||||
updateProgressRect(progressRect, duration/25, true)
|
||||
end
|
||||
end
|
9
modules/game_cooldown/cooldown.otmod
Normal file
@@ -0,0 +1,9 @@
|
||||
Module
|
||||
name: game_cooldown
|
||||
description: Spellcooldowns
|
||||
author: OTClient team
|
||||
website: www.otclient.info
|
||||
sandboxed: true
|
||||
scripts: [ cooldown.lua ]
|
||||
@onLoad: init()
|
||||
@onUnload: terminate()
|
102
modules/game_cooldown/cooldown.otui
Normal file
@@ -0,0 +1,102 @@
|
||||
SpellGroupIcon < UIWidget
|
||||
size: 22 22
|
||||
image-size: 22 22
|
||||
image-source: /game_cooldown/icons/cooldownIcons.png
|
||||
focusable: false
|
||||
margin-top: 3
|
||||
|
||||
SpellIcon < UIWidget
|
||||
size: 22 22
|
||||
image-size: 22 22
|
||||
margin-left: 2
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
focusable: false
|
||||
|
||||
$first:
|
||||
margin-top: 3
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
|
||||
SpellProgressRect < UIProgressRect
|
||||
background: #585858AA
|
||||
percent: 100
|
||||
focusable: false
|
||||
|
||||
MiniWindow
|
||||
id: cooldownWindow
|
||||
!text: tr('Spell Cooldowns')
|
||||
height: 85
|
||||
icon: cooldown.png
|
||||
@onClose: modules.game_cooldown.onMiniWindowClose()
|
||||
&save: true
|
||||
|
||||
MiniWindowContents
|
||||
SpellGroupIcon
|
||||
id: groupIconAttack
|
||||
image-clip: 0 0 20 20
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
margin-left: 3
|
||||
$on:
|
||||
image-clip: 0 20 20 20
|
||||
|
||||
SpellProgressRect
|
||||
id: progressRectAttack
|
||||
anchors.fill: groupIconAttack
|
||||
!tooltip: tr('Attack')
|
||||
|
||||
SpellGroupIcon
|
||||
id: groupIconHealing
|
||||
image-clip: 20 0 20 20
|
||||
anchors.top: parent.top
|
||||
anchors.left: groupIconAttack.right
|
||||
margin-left: 3
|
||||
$on:
|
||||
image-clip: 20 20 20 20
|
||||
|
||||
SpellProgressRect
|
||||
id: progressRectHealing
|
||||
anchors.fill: groupIconHealing
|
||||
!tooltip: tr('Healing')
|
||||
|
||||
SpellGroupIcon
|
||||
id: groupIconSupport
|
||||
image-clip: 40 0 20 20
|
||||
anchors.top: parent.top
|
||||
anchors.left: groupIconHealing.right
|
||||
margin-left: 3
|
||||
$on:
|
||||
image-clip: 40 20 20 20
|
||||
|
||||
SpellProgressRect
|
||||
id: progressRectSupport
|
||||
anchors.fill: groupIconSupport
|
||||
!tooltip: tr('Support')
|
||||
|
||||
SpellGroupIcon
|
||||
id: groupIconSpecial
|
||||
image-clip: 60 0 20 20
|
||||
anchors.top: parent.top
|
||||
anchors.left: groupIconSupport.right
|
||||
margin-left: 3
|
||||
$on:
|
||||
image-clip: 60 20 20 20
|
||||
|
||||
SpellProgressRect
|
||||
id: progressRectSpecial
|
||||
anchors.fill: groupIconSpecial
|
||||
!tooltip: tr('Special')
|
||||
|
||||
Panel
|
||||
id: spellCooldownPanel
|
||||
margin-top: 5
|
||||
anchors.top: groupIconSpecial.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 30
|
||||
padding: 1
|
||||
margin-left: 2
|
||||
margin-right: 2
|
||||
border: 1 #444444
|
||||
|
BIN
modules/game_cooldown/cooldown.png
Normal file
After Width: | Height: | Size: 675 B |
BIN
modules/game_cooldown/icons/cooldownIcons.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
modules/game_cooldown/icons/icons.png
Normal file
After Width: | Height: | Size: 340 KiB |
BIN
modules/game_cooldown/icons/sample.png
Normal file
After Width: | Height: | Size: 22 KiB |
@@ -10,6 +10,7 @@ mouseGrabberWidget = nil
|
||||
countWindow = nil
|
||||
logoutWindow = nil
|
||||
exitWindow = nil
|
||||
bottomSplitter = nil
|
||||
|
||||
function init()
|
||||
g_ui.importStyle('styles/countwindow.otui')
|
||||
@@ -21,10 +22,12 @@ function init()
|
||||
gameRootPanel = g_ui.displayUI('gameinterface.otui')
|
||||
gameRootPanel:hide()
|
||||
gameRootPanel:lower()
|
||||
gameRootPanel.onGeometryChange = updateStretchShrink
|
||||
|
||||
mouseGrabberWidget = gameRootPanel:getChildById('mouseGrabber')
|
||||
mouseGrabberWidget.onMouseRelease = onMouseGrabberRelease
|
||||
|
||||
bottomSplitter = gameRootPanel:getChildById('bottomSplitter')
|
||||
gameMapPanel = gameRootPanel:getChildById('gameMapPanel')
|
||||
gameRightPanel = gameRootPanel:getChildById('gameRightPanel')
|
||||
gameLeftPanel = gameRootPanel:getChildById('gameLeftPanel')
|
||||
@@ -90,6 +93,7 @@ function show()
|
||||
gameRootPanel:show()
|
||||
gameRootPanel:focus()
|
||||
gameMapPanel:followCreature(g_game.getLocalPlayer())
|
||||
updateStretchShrink()
|
||||
end
|
||||
|
||||
function hide()
|
||||
@@ -187,6 +191,16 @@ function smartWalk(defaultDir)
|
||||
end
|
||||
end
|
||||
|
||||
function updateStretchShrink()
|
||||
if Options.getOption('dontStretchShrink') then
|
||||
gameMapPanel:setKeepAspectRatio(true)
|
||||
gameMapPanel:setVisibleDimension({ width = 15, height = 11 })
|
||||
|
||||
-- Set gameMapPanel size to height = 11 * 32
|
||||
bottomSplitter:setMarginBottom(bottomSplitter:getMarginBottom() + (gameMapPanel:getHeight() - 32 * 11) - 10)
|
||||
end
|
||||
end
|
||||
|
||||
function toggleAspectRatio()
|
||||
if gameMapPanel:isKeepAspectRatioEnabled() then
|
||||
gameMapPanel:setKeepAspectRatio(false)
|
||||
@@ -544,4 +558,4 @@ function onLeftPanelVisibilityChange(leftPanel, visible)
|
||||
children[i]:setParent(gameRightPanel)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@@ -1,3 +1,4 @@
|
||||
|
||||
GameSidePanel < UIMiniWindowContainer
|
||||
image-source: /images/sidepanel.png
|
||||
image-border: 4
|
||||
@@ -62,10 +63,10 @@ UIWidget
|
||||
anchors.bottom: parent.bottom
|
||||
relative-margin: bottom
|
||||
margin-bottom: 172
|
||||
@canUpdateMargin: function(self, newMargin) return math.max(math.min(newMargin, self:getParent():getHeight() - 300), 100) end
|
||||
@canUpdateMargin: function(self, newMargin) if Options.getOption('dontStretchShrink') then return self:getMarginBottom() end return math.max(math.min(newMargin, self:getParent():getHeight() - 300), 100) end
|
||||
@onGeometryChange: function(self) self:setMarginBottom(math.min(math.max(self:getParent():getHeight() - 300, 100), self:getMarginBottom())) end
|
||||
|
||||
UIWidget
|
||||
id: mouseGrabber
|
||||
focusable: false
|
||||
visible: false
|
||||
visible: false
|
@@ -29,5 +29,6 @@ Module
|
||||
- game_playermount
|
||||
- game_market
|
||||
- game_spelllist
|
||||
- game_cooldown
|
||||
@onLoad: init()
|
||||
@onUnload: terminate()
|
||||
|
190
modules/game_minimap/flagwindow.otui
Normal file
@@ -0,0 +1,190 @@
|
||||
FlagButton < CheckBox
|
||||
size: 15 15
|
||||
margin-left: 2
|
||||
image-source: images/flagcheckbox.png
|
||||
image-size: 15 15
|
||||
image-border: 3
|
||||
icon-source: images/mapflags.png
|
||||
icon-size: 11 11
|
||||
icon-clip: 0 0 11 11
|
||||
icon-offset: 2 4
|
||||
text:
|
||||
|
||||
$!checked:
|
||||
image-clip: 26 0 26 26
|
||||
|
||||
$hover !checked:
|
||||
image-clip: 78 0 26 26
|
||||
|
||||
$checked:
|
||||
image-clip: 0 0 26 26
|
||||
|
||||
$hover checked:
|
||||
image-clip: 52 0 26 26
|
||||
|
||||
|
||||
FlagWindow < MainWindow
|
||||
id: flagWindow
|
||||
!text: tr('Create Map Mark')
|
||||
size: 196 170
|
||||
|
||||
Label
|
||||
id: position
|
||||
!text: tr('Position:')
|
||||
text-auto-resize: true
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
margin-top: 2
|
||||
|
||||
Label
|
||||
!text: tr('Description:')
|
||||
anchors.left: parent.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 7
|
||||
|
||||
TextEdit
|
||||
id: description
|
||||
margin-top: 3
|
||||
anchors.left: parent.left
|
||||
anchors.top: prev.bottom
|
||||
width: 158
|
||||
|
||||
FlagButton
|
||||
id: flag1
|
||||
anchors.left: parent.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 6
|
||||
margin-left: 0
|
||||
|
||||
FlagButton
|
||||
id: flag2
|
||||
icon-clip: 11 0 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag3
|
||||
icon-clip: 22 0 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag4
|
||||
icon-clip: 33 0 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag5
|
||||
icon-clip: 44 0 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag6
|
||||
icon-clip: 55 0 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag7
|
||||
icon-clip: 66 0 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag8
|
||||
icon-clip: 77 0 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag9
|
||||
icon-clip: 88 0 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag10
|
||||
icon-clip: 99 0 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
|
||||
FlagButton
|
||||
id: flag11
|
||||
icon-clip: 0 11 11 11
|
||||
anchors.left: parent.left
|
||||
anchors.top: prev.bottom
|
||||
margin-top: 6
|
||||
margin-left: 0
|
||||
|
||||
FlagButton
|
||||
id: flag12
|
||||
icon-clip: 11 11 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag13
|
||||
icon-clip: 22 11 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag14
|
||||
icon-clip: 33 11 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag15
|
||||
icon-clip: 44 11 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag16
|
||||
icon-clip: 55 11 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag17
|
||||
icon-clip: 66 11 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag18
|
||||
icon-clip: 77 11 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag19
|
||||
icon-clip: 88 11 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
FlagButton
|
||||
id: flag20
|
||||
icon-clip: 99 11 11 11
|
||||
anchors.left: prev.right
|
||||
anchors.top: prev.top
|
||||
|
||||
Button
|
||||
id: okButton
|
||||
!text: tr('Ok')
|
||||
anchors.top: prev.bottom
|
||||
anchors.left: parent.left
|
||||
margin-top: 10
|
||||
width: 60
|
||||
|
||||
Button
|
||||
id: cancelButton
|
||||
!text: tr('Cancel')
|
||||
anchors.top: prev.top
|
||||
anchors.left: prev.right
|
||||
margin-left: 15
|
||||
width: 60
|
BIN
modules/game_minimap/images/flagcheckbox.png
Normal file
After Width: | Height: | Size: 349 B |
BIN
modules/game_minimap/images/mapflags.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
@@ -7,17 +7,24 @@ minimapWidget = nil
|
||||
minimapButton = nil
|
||||
minimapWindow = nil
|
||||
|
||||
flagsPanel = nil
|
||||
flagWindow = nil
|
||||
nextFlagId = 0
|
||||
--[[
|
||||
Known Issue (TODO):
|
||||
If you move the minimap compass directions and
|
||||
you change floor it will not update the minimap.
|
||||
]]
|
||||
function init()
|
||||
g_ui.importStyle('flagwindow.otui')
|
||||
|
||||
connect(g_game, {
|
||||
onGameStart = online,
|
||||
onGameEnd = offline,
|
||||
onAutomapFlag = addMapFlag
|
||||
})
|
||||
connect(LocalPlayer, { onPositionChange = center })
|
||||
connect(LocalPlayer, { onPositionChange = center,
|
||||
onPositionChange = updateMapFlags })
|
||||
|
||||
g_keyboard.bindKeyDown('Ctrl+M', toggle)
|
||||
|
||||
@@ -30,7 +37,9 @@ function init()
|
||||
|
||||
minimapWidget = minimapWindow:recursiveGetChildById('minimap')
|
||||
g_mouse.bindAutoPress(minimapWidget, compassClick, nil, MouseRightButton)
|
||||
g_mouse.bindAutoPress(minimapWidget, compassClick, nil, MouseLeftButton)
|
||||
--g_mouse.bindAutoPress(minimapWidget, compassClick, nil, MouseLeftButton)
|
||||
minimapWidget.onMousePress = createThingMenu
|
||||
|
||||
minimapWidget:setAutoViewMode(false)
|
||||
minimapWidget:setViewMode(1) -- mid view
|
||||
minimapWidget:setDrawMinimapColors(true)
|
||||
@@ -38,18 +47,28 @@ function init()
|
||||
minimapWidget:setKeepAspectRatio(false)
|
||||
minimapWidget.onMouseRelease = onMinimapMouseRelease
|
||||
minimapWidget.onMouseWheel = onMinimapMouseWheel
|
||||
flagsPanel = minimapWindow:recursiveGetChildById('flagsPanel')
|
||||
|
||||
reset()
|
||||
minimapWindow:setup()
|
||||
loadMapFlags()
|
||||
|
||||
if g_game.isOnline() then
|
||||
addEvent(function() updateMapFlags() end)
|
||||
end
|
||||
end
|
||||
|
||||
function terminate()
|
||||
disconnect(g_game, {
|
||||
onGameStart = online,
|
||||
onGameEnd = offline,
|
||||
onAutomapFlag = addMapFlag
|
||||
})
|
||||
disconnect(LocalPlayer, { onPositionChange = center })
|
||||
disconnect(LocalPlayer, { onPositionChange = center,
|
||||
onPositionChange = updateMapFlags })
|
||||
|
||||
destroyFlagWindow()
|
||||
saveMapFlags()
|
||||
if g_game.isOnline() then
|
||||
saveMap()
|
||||
end
|
||||
@@ -60,9 +79,188 @@ function terminate()
|
||||
minimapWindow:destroy()
|
||||
end
|
||||
|
||||
function destroyFlagWindow()
|
||||
if flagWindow then
|
||||
flagWindow:destroy()
|
||||
flagWindow = nil
|
||||
end
|
||||
end
|
||||
|
||||
function createThingMenu(widget, menuPosition, button)
|
||||
if not g_game.isOnline() then return end
|
||||
if button ~= MouseRightButton then return end
|
||||
local menu = g_ui.createWidget('PopupMenu')
|
||||
|
||||
if widget == minimapWidget then
|
||||
menu:addOption(tr('Create mark'), function()
|
||||
local position = minimapWidget:getPosition(menuPosition)
|
||||
if position then
|
||||
showFlagDialog(position)
|
||||
end
|
||||
end)
|
||||
else
|
||||
menu:addOption(tr('Delete mark'), function()
|
||||
widget:destroy()
|
||||
end)
|
||||
end
|
||||
|
||||
menu:display(menuPosition)
|
||||
end
|
||||
|
||||
function showFlagDialog(position)
|
||||
if flagWindow then return end
|
||||
if not position then return end
|
||||
flagWindow = g_ui.createWidget('FlagWindow', rootWidget)
|
||||
|
||||
local positionLabel = flagWindow:getChildById('position')
|
||||
local description = flagWindow:getChildById('description')
|
||||
local okButton = flagWindow:getChildById('okButton')
|
||||
local cancelButton = flagWindow:getChildById('cancelButton')
|
||||
|
||||
positionLabel:setText(tr('Position: %i %i %i', position.x, position.y, position.z))
|
||||
|
||||
flagRadioGroup = UIRadioGroup.create()
|
||||
local flagCheckbox = {}
|
||||
for i = 1, 20 do
|
||||
local checkbox = flagWindow:getChildById('flag' .. i)
|
||||
table.insert(flagCheckbox, checkbox)
|
||||
checkbox.icon = i
|
||||
flagRadioGroup:addWidget(checkbox)
|
||||
end
|
||||
|
||||
flagRadioGroup:selectWidget(flagCheckbox[1])
|
||||
|
||||
|
||||
cancelButton.onClick = function()
|
||||
flagRadioGroup:destroy()
|
||||
destroyFlagWindow()
|
||||
end
|
||||
okButton.onClick = function()
|
||||
addMapFlag(position, flagRadioGroup:getSelectedWidget().icon, description:getText())
|
||||
flagRadioGroup:destroy()
|
||||
destroyFlagWindow()
|
||||
end
|
||||
end
|
||||
|
||||
function loadMapFlags()
|
||||
mapFlags = {}
|
||||
|
||||
local flagSettings = g_settings.getNode('MapFlags')
|
||||
if flagSettings then
|
||||
for i = 1, #flagSettings do
|
||||
local flag = flagSettings[i]
|
||||
addMapFlag(flag.position, flag.icon, flag.description, flag.id, flag.version)
|
||||
|
||||
if i == #flagSettings then
|
||||
nextFlagId = flag.id + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function saveMapFlags()
|
||||
local flagSettings = {}
|
||||
|
||||
for i = 1, flagsPanel:getChildCount() do
|
||||
local child = flagsPanel:getChildByIndex(i)
|
||||
|
||||
table.insert(flagSettings, { position = child.position,
|
||||
icon = child.icon,
|
||||
description = child.description,
|
||||
id = child.id,
|
||||
version = child.version })
|
||||
end
|
||||
|
||||
g_settings.setNode('MapFlags', flagSettings)
|
||||
end
|
||||
|
||||
function getFlagIconClip(id)
|
||||
return (((id)%10)*11) .. ' ' .. ((math.ceil(id/10+0.1)-1)*11) .. ' 11 11'
|
||||
end
|
||||
|
||||
function addMapFlag(pos, icon, message, flagId, version)
|
||||
if not(icon >= 1 and icon <= 20) or not pos then
|
||||
return
|
||||
end
|
||||
|
||||
version = version or g_game.getClientVersion()
|
||||
-- Check if flag is set for that position
|
||||
for i = 1, flagsPanel:getChildCount() do
|
||||
local flag = flagsPanel:getChildByIndex(i)
|
||||
if flag.position.x == pos.x and flag.position.y == pos.y and flag.position.z == pos.z
|
||||
and version == flag.version then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if not flagId then
|
||||
flagId = nextFlagId
|
||||
nextFlagId = nextFlagId + 1
|
||||
end
|
||||
|
||||
local flagWidget = g_ui.createWidget('FlagWidget', flagsPanel)
|
||||
flagWidget:setIconClip(getFlagIconClip(icon - 1))
|
||||
flagWidget:setId('flag' .. flagId)
|
||||
flagWidget.position = pos
|
||||
flagWidget.icon = icon
|
||||
flagWidget.description = message
|
||||
if message and message:len() > 0 then
|
||||
flagWidget:setTooltip(tr(message))
|
||||
end
|
||||
flagWidget.id = flagId
|
||||
flagWidget.version = version
|
||||
updateMapFlag(flagId)
|
||||
flagWidget.onMousePress = createThingMenu
|
||||
end
|
||||
|
||||
function getMapArea()
|
||||
return minimapWidget:getPosition( { x = 1 + minimapWidget:getX(), y = 1 + minimapWidget:getY() } ),
|
||||
minimapWidget:getPosition( { x = -2 + minimapWidget:getWidth() + minimapWidget:getX(), y = -2 + minimapWidget:getHeight() + minimapWidget:getY() } )
|
||||
end
|
||||
|
||||
function isFlagVisible(flag, firstPosition, lastPosition)
|
||||
return flag.version == g_game.getClientVersion() and (minimapWidget:getZoom() >= 30 and minimapWidget:getZoom() <= 150) and flag.position.x >= firstPosition.x and flag.position.x <= lastPosition.x and flag.position.y >= firstPosition.y and flag.position.y <= lastPosition.y and flag.position.z == firstPosition.z
|
||||
end
|
||||
|
||||
function updateMapFlag(id)
|
||||
local firstPosition, lastPosition = getMapArea()
|
||||
if not firstPosition or not lastPosition then
|
||||
return
|
||||
end
|
||||
|
||||
local flag = flagsPanel:getChildById('flag' .. id)
|
||||
if isFlagVisible(flag, firstPosition, lastPosition) then
|
||||
flag:setVisible(true)
|
||||
flag:setMarginLeft( -5 + (minimapWidget:getWidth() / (lastPosition.x - firstPosition.x)) * (flag.position.x - firstPosition.x))
|
||||
flag:setMarginTop( -5 + (minimapWidget:getHeight() / (lastPosition.y - firstPosition.y)) * (flag.position.y - firstPosition.y))
|
||||
else
|
||||
flag:setVisible(false)
|
||||
end
|
||||
end
|
||||
|
||||
function updateMapFlags()
|
||||
local firstPosition, lastPosition = getMapArea()
|
||||
if not firstPosition or not lastPosition then
|
||||
return
|
||||
end
|
||||
|
||||
for i = 1, flagsPanel:getChildCount() do
|
||||
local flag = flagsPanel:getChildByIndex(i)
|
||||
if isFlagVisible(flag, firstPosition, lastPosition) then
|
||||
flag:setVisible(true)
|
||||
flag:setMarginLeft( -5 + (minimapWidget:getWidth() / (lastPosition.x - firstPosition.x)) * (flag.position.x - firstPosition.x))
|
||||
flag:setMarginTop( -5 + (minimapWidget:getHeight() / (lastPosition.y - firstPosition.y)) * (flag.position.y - firstPosition.y))
|
||||
else
|
||||
flag:setVisible(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function online()
|
||||
reset()
|
||||
loadMap()
|
||||
|
||||
updateMapFlags()
|
||||
end
|
||||
|
||||
function offline()
|
||||
@@ -109,6 +307,8 @@ function center()
|
||||
local player = g_game.getLocalPlayer()
|
||||
if not player then return end
|
||||
minimapWidget:followCreature(player)
|
||||
|
||||
updateMapFlags()
|
||||
end
|
||||
|
||||
function compassClick(self, mousePos, mouseButton, elapsed)
|
||||
@@ -133,6 +333,8 @@ function compassClick(self, mousePos, mouseButton, elapsed)
|
||||
local cameraPos = minimapWidget:getCameraPosition()
|
||||
local pos = {x = cameraPos.x + movex, y = cameraPos.y + movey, z = cameraPos.z}
|
||||
minimapWidget:setCameraPosition(pos)
|
||||
|
||||
updateMapFlags()
|
||||
end
|
||||
|
||||
function onButtonClick(id)
|
||||
@@ -153,6 +355,8 @@ function onButtonClick(id)
|
||||
minimapWidget:setCameraPosition(pos)
|
||||
end
|
||||
end
|
||||
|
||||
updateMapFlags()
|
||||
end
|
||||
|
||||
function onMinimapMouseRelease(self, mousePosition, mouseButton)
|
||||
@@ -179,6 +383,7 @@ function onMinimapMouseWheel(self, mousePos, direction)
|
||||
else
|
||||
self:zoomOut()
|
||||
end
|
||||
updateMapFlags()
|
||||
end
|
||||
|
||||
function onMiniWindowClose()
|
||||
|
@@ -7,6 +7,13 @@ MapControl < Button
|
||||
|
||||
$hover !pressed:
|
||||
icon-clip: 0 16 16 16
|
||||
|
||||
FlagWidget < UIWidget
|
||||
size: 11 11
|
||||
icon-clip: 0 0 11 11
|
||||
icon-source: /game_minimap/images/mapflags.png
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
|
||||
FloorUpControl < MapControl
|
||||
icon-source: /game_minimap/images/floor_up.png
|
||||
@@ -26,6 +33,7 @@ MiniWindow
|
||||
height: 150
|
||||
icon: minimap.png
|
||||
@onClose: modules.game_minimap.onMiniWindowClose()
|
||||
@onGeometryChange: updateMapFlags()
|
||||
&save: true
|
||||
|
||||
Label
|
||||
@@ -43,6 +51,11 @@ MiniWindow
|
||||
id: minimap
|
||||
anchors.fill: parent
|
||||
|
||||
Panel
|
||||
id: flagsPanel
|
||||
anchors.fill: minimap
|
||||
phantom: true
|
||||
|
||||
FloorUpControl
|
||||
id: floorUp
|
||||
anchors.right: parent.right
|
||||
|
BIN
modules/game_spelllist/icons/sample.png
Normal file
After Width: | Height: | Size: 22 KiB |
@@ -1,34 +1,37 @@
|
||||
spelllistWindow = nil
|
||||
spelllistButton = nil
|
||||
spellList = nil
|
||||
nameValueLabel = nil
|
||||
formulaValueLabel = nil
|
||||
vocationValueLabel = nil
|
||||
groupValueLabel = nil
|
||||
typeValueLabel = nil
|
||||
cooldownValueLabel = nil
|
||||
levelValueLabel = nil
|
||||
manaValueLabel = nil
|
||||
premiumValueLabel = nil
|
||||
local SpelllistProfile = 'Default'
|
||||
|
||||
vocationBoxAny = nil
|
||||
vocationBoxSorcerer = nil
|
||||
vocationBoxDruid = nil
|
||||
vocationBoxPaladin = nil
|
||||
vocationBoxKnight = nil
|
||||
spelllistWindow = nil
|
||||
spelllistButton = nil
|
||||
spellList = nil
|
||||
nameValueLabel = nil
|
||||
formulaValueLabel = nil
|
||||
vocationValueLabel = nil
|
||||
groupValueLabel = nil
|
||||
typeValueLabel = nil
|
||||
cooldownValueLabel = nil
|
||||
levelValueLabel = nil
|
||||
manaValueLabel = nil
|
||||
premiumValueLabel = nil
|
||||
descriptionValueLabel = nil
|
||||
|
||||
groupBoxAny = nil
|
||||
groupBoxAttack = nil
|
||||
groupBoxHealing = nil
|
||||
groupBoxSupport = nil
|
||||
vocationBoxAny = nil
|
||||
vocationBoxSorcerer = nil
|
||||
vocationBoxDruid = nil
|
||||
vocationBoxPaladin = nil
|
||||
vocationBoxKnight = nil
|
||||
|
||||
premiumBoxAny = nil
|
||||
premiumBoxNo = nil
|
||||
premiumBoxYes = nil
|
||||
groupBoxAny = nil
|
||||
groupBoxAttack = nil
|
||||
groupBoxHealing = nil
|
||||
groupBoxSupport = nil
|
||||
|
||||
vocationRadioGroup = nil
|
||||
groupRadioGroup = nil
|
||||
premiumRadioGroup = nil
|
||||
premiumBoxAny = nil
|
||||
premiumBoxNo = nil
|
||||
premiumBoxYes = nil
|
||||
|
||||
vocationRadioGroup = nil
|
||||
groupRadioGroup = nil
|
||||
premiumRadioGroup = nil
|
||||
|
||||
-- consts
|
||||
FILTER_PREMIUM_ANY = 0
|
||||
@@ -56,13 +59,27 @@ local filters = {
|
||||
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'
|
||||
function getSpelllistProfile()
|
||||
return SpelllistProfile
|
||||
end
|
||||
|
||||
function setupOptions()
|
||||
function setSpelllistProfile(name)
|
||||
if SpelllistProfile == name then return end
|
||||
|
||||
if SpelllistSettings[name] and SpellInfo[name] then
|
||||
local oldProfile = SpelllistProfile
|
||||
SpelllistProfile = name
|
||||
changeSpelllistProfile(oldProfile)
|
||||
else
|
||||
perror('Spelllist profile \'' .. name .. '\' could not be set.')
|
||||
end
|
||||
end
|
||||
|
||||
function getIconImageClip(id)
|
||||
return (((id-1)%12)*SpelllistSettings[SpelllistProfile].iconSize.width) .. ' ' .. ((math.ceil(id/12)-1)*SpelllistSettings[SpelllistProfile].iconSize.height) .. ' ' .. SpelllistSettings[SpelllistProfile].iconSize.width .. ' ' .. SpelllistSettings[SpelllistProfile].iconSize.height
|
||||
end
|
||||
|
||||
function setOptions()
|
||||
if g_game.getClientVersion() >= 950 then -- Vocation is only send in newer clients
|
||||
spelllistWindow:getChildById('buttonFilterVocation'):setVisible(true)
|
||||
else
|
||||
@@ -71,8 +88,8 @@ function setupOptions()
|
||||
end
|
||||
|
||||
function init()
|
||||
connect(g_game, { onGameStart = setupOptions,
|
||||
onGameEnd = resetWindow })
|
||||
connect(g_game, { onGameStart = setOptions,
|
||||
onGameEnd = resetWindow })
|
||||
|
||||
spelllistWindow = g_ui.displayUI('spelllist.otui', modules.game_interface.getRightPanel())
|
||||
spelllistWindow:hide()
|
||||
@@ -89,6 +106,7 @@ function init()
|
||||
levelValueLabel = spelllistWindow:getChildById('labelLevelValue')
|
||||
manaValueLabel = spelllistWindow:getChildById('labelManaValue')
|
||||
premiumValueLabel = spelllistWindow:getChildById('labelPremiumValue')
|
||||
descriptionValueLabel = spelllistWindow:getChildById('labelDescriptionValue')
|
||||
|
||||
vocationBoxAny = spelllistWindow:getChildById('vocationBoxAny')
|
||||
vocationBoxSorcerer = spelllistWindow:getChildById('vocationBoxSorcerer')
|
||||
@@ -135,35 +153,17 @@ function init()
|
||||
|
||||
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()
|
||||
initialiseSpelllist()
|
||||
setOptions()
|
||||
resizeWindow()
|
||||
end
|
||||
|
||||
function terminate()
|
||||
disconnect(g_game, { onGameStart = setupOptions,
|
||||
onGameEnd = resetWindow })
|
||||
disconnect(g_game, { onGameStart = setOptions,
|
||||
onGameEnd = resetWindow,
|
||||
onSpellGroupCooldown = modules.game_interface.setGroupCooldown,
|
||||
onSpellCooldown = onSpellCooldown })
|
||||
|
||||
disconnect(spellList, { onChildFocusChange = function(self, focusedChild)
|
||||
if focusedChild == nil then return end
|
||||
@@ -171,48 +171,98 @@ function terminate()
|
||||
end })
|
||||
|
||||
spelllistButton:destroy()
|
||||
spelllistButton = nil
|
||||
spelllistButton = nil
|
||||
spelllistWindow:destroy()
|
||||
spelllistWindow = nil
|
||||
spelllistWindow = nil
|
||||
|
||||
vocationRadioGroup:destroy()
|
||||
vocationRadioGroup = nil
|
||||
vocationRadioGroup = nil
|
||||
groupRadioGroup:destroy()
|
||||
groupRadioGroup = nil
|
||||
groupRadioGroup = nil
|
||||
premiumRadioGroup:destroy()
|
||||
premiumRadioGroup = nil
|
||||
premiumRadioGroup = nil
|
||||
|
||||
spellList = nil
|
||||
nameValueLabel = nil
|
||||
formulaValueLabel = nil
|
||||
vocationValueLabel = nil
|
||||
groupValueLabel = nil
|
||||
typeValueLabel = nil
|
||||
cooldownValueLabel = nil
|
||||
levelValueLabel = nil
|
||||
manaValueLabel = nil
|
||||
premiumValueLabel = nil
|
||||
spellList = nil
|
||||
nameValueLabel = nil
|
||||
formulaValueLabel = nil
|
||||
vocationValueLabel = nil
|
||||
groupValueLabel = nil
|
||||
typeValueLabel = nil
|
||||
cooldownValueLabel = nil
|
||||
levelValueLabel = nil
|
||||
manaValueLabel = nil
|
||||
premiumValueLabel = nil
|
||||
descriptionValueLabel = nil
|
||||
|
||||
vocationBoxAny = nil
|
||||
vocationBoxSorcerer = nil
|
||||
vocationBoxDruid = nil
|
||||
vocationBoxPaladin = nil
|
||||
vocationBoxKnight = nil
|
||||
vocationBoxAny = nil
|
||||
vocationBoxSorcerer = nil
|
||||
vocationBoxDruid = nil
|
||||
vocationBoxPaladin = nil
|
||||
vocationBoxKnight = nil
|
||||
|
||||
groupBoxAny = nil
|
||||
groupBoxAttack = nil
|
||||
groupBoxHealing = nil
|
||||
groupBoxSupport = nil
|
||||
groupBoxAny = nil
|
||||
groupBoxAttack = nil
|
||||
groupBoxHealing = nil
|
||||
groupBoxSupport = nil
|
||||
|
||||
premiumBoxAny = nil
|
||||
premiumBoxNo = nil
|
||||
premiumBoxYes = nil
|
||||
premiumBoxAny = nil
|
||||
premiumBoxNo = nil
|
||||
premiumBoxYes = nil
|
||||
end
|
||||
|
||||
function initialiseSpelllist()
|
||||
for i = 1, #SpelllistSettings[SpelllistProfile].spellOrder do
|
||||
local spell = SpelllistSettings[SpelllistProfile].spellOrder[i]
|
||||
local info = SpellInfo[SpelllistProfile][spell]
|
||||
|
||||
local tmpLabel = g_ui.createWidget('SpellListLabel', spellList)
|
||||
tmpLabel:setId(spell)
|
||||
tmpLabel:setText(spell .. '\n\'' .. info.words .. '\'')
|
||||
tmpLabel:setPhantom(false)
|
||||
|
||||
local iconId = tonumber(info.icon)
|
||||
if not iconId and SpellIcons[info.icon] then
|
||||
iconId = SpellIcons[info.icon][1]
|
||||
end
|
||||
|
||||
if not(iconId) then
|
||||
perror('Spell icon \'' .. info.icon .. '\' not found.')
|
||||
end
|
||||
|
||||
tmpLabel:setHeight(SpelllistSettings[SpelllistProfile].iconSize.height + 4)
|
||||
tmpLabel:setTextOffset(topoint((SpelllistSettings[SpelllistProfile].iconSize.width + 10) .. ' ' .. (SpelllistSettings[SpelllistProfile].iconSize.height - 32)/2 + 3))
|
||||
tmpLabel:setImageSource('/game_spelllist/icons/' .. SpelllistSettings[SpelllistProfile].iconFile)
|
||||
tmpLabel:setImageClip(getIconImageClip(iconId))
|
||||
tmpLabel:setImageSize(tosize(SpelllistSettings[SpelllistProfile].iconSize.width .. ' ' .. SpelllistSettings[SpelllistProfile].iconSize.height))
|
||||
tmpLabel.onClick = updateSpellInformation
|
||||
end
|
||||
|
||||
connect(spellList, { onChildFocusChange = function(self, focusedChild)
|
||||
if focusedChild == nil then return end
|
||||
updateSpellInformation(focusedChild)
|
||||
end })
|
||||
end
|
||||
|
||||
function changeSpelllistProfile(oldProfile)
|
||||
-- Delete old labels
|
||||
for i = 1, #SpelllistSettings[oldProfile].spellOrder do
|
||||
local spell = SpelllistSettings[oldProfile].spellOrder[i]
|
||||
local tmpLabel = spellList:getChildById(spell)
|
||||
|
||||
tmpLabel:destroy()
|
||||
end
|
||||
|
||||
-- Create new spelllist and ajust window
|
||||
initialiseSpelllist()
|
||||
setOptions()
|
||||
resizeWindow()
|
||||
resetWindow()
|
||||
end
|
||||
|
||||
function updateSpelllist()
|
||||
for i = 1, #spellDisplayOrder do
|
||||
local spell = spellDisplayOrder[i]
|
||||
local info = SpellInfo[spell]
|
||||
for i = 1, #SpelllistSettings[SpelllistProfile].spellOrder do
|
||||
local spell = SpelllistSettings[SpelllistProfile].spellOrder[i]
|
||||
local info = SpellInfo[SpelllistProfile][spell]
|
||||
local tmpLabel = spellList:getChildById(spell)
|
||||
|
||||
local localPlayer = g_game.getLocalPlayer()
|
||||
@@ -227,18 +277,19 @@ 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 = ''
|
||||
local name = ''
|
||||
local formula = ''
|
||||
local vocation = ''
|
||||
local group = ''
|
||||
local type = ''
|
||||
local cooldown = ''
|
||||
local level = ''
|
||||
local mana = ''
|
||||
local premium = ''
|
||||
local description = ''
|
||||
|
||||
if SpellInfo[spell] then
|
||||
local info = SpellInfo[spell]
|
||||
if SpellInfo[SpelllistProfile][spell] then
|
||||
local info = SpellInfo[SpelllistProfile][spell]
|
||||
|
||||
name = spell
|
||||
formula = info.words
|
||||
@@ -262,6 +313,7 @@ function updateSpellInformation(widget)
|
||||
level = info.level
|
||||
mana = info.mana .. ' / ' .. info.soul
|
||||
premium = (info.premium and 'yes' or 'no')
|
||||
description = info.description or '-'
|
||||
end
|
||||
|
||||
nameValueLabel:setText(name)
|
||||
@@ -273,6 +325,7 @@ function updateSpellInformation(widget)
|
||||
levelValueLabel:setText(level)
|
||||
manaValueLabel:setText(mana)
|
||||
premiumValueLabel:setText(premium)
|
||||
descriptionValueLabel:setText(description)
|
||||
end
|
||||
|
||||
function toggle()
|
||||
@@ -333,6 +386,11 @@ function toggleFilter(widget, selectedWidget)
|
||||
updateSpelllist()
|
||||
end
|
||||
|
||||
function resizeWindow()
|
||||
spelllistWindow:setWidth(SpelllistSettings['Default'].spellWindowWidth + SpelllistSettings[SpelllistProfile].iconSize.width - 32)
|
||||
spellList:setWidth(SpelllistSettings['Default'].spellListWidth + SpelllistSettings[SpelllistProfile].iconSize.width - 32)
|
||||
end
|
||||
|
||||
function resetWindow()
|
||||
spelllistWindow:hide()
|
||||
spelllistButton:setOn(false)
|
||||
|
@@ -29,7 +29,7 @@ SpellInfoValueLabel < Label
|
||||
MainWindow
|
||||
id: spelllistWindow
|
||||
!text: tr('Spell List')
|
||||
size: 500 400
|
||||
size: 550 400
|
||||
@onEscape: toggle()
|
||||
|
||||
TextList
|
||||
@@ -142,6 +142,12 @@ MainWindow
|
||||
anchors.top: labelMana.bottom
|
||||
text: Premium:
|
||||
|
||||
SpellInfoLabel
|
||||
id: labelDescription
|
||||
anchors.left: spellList.right
|
||||
anchors.top: labelPremium.bottom
|
||||
text: Description:
|
||||
|
||||
SpellInfoValueLabel
|
||||
id: labelNameValue
|
||||
anchors.left: labelName.right
|
||||
@@ -187,6 +193,11 @@ MainWindow
|
||||
anchors.left: labelPremium.right
|
||||
anchors.top: labelManaValue.bottom
|
||||
|
||||
SpellInfoValueLabel
|
||||
id: labelDescriptionValue
|
||||
anchors.left: labelDescription.right
|
||||
anchors.top: labelPremiumValue.bottom
|
||||
|
||||
Label
|
||||
id: labelVocationFilter
|
||||
anchors.top: labelPremium.bottom
|
||||
@@ -194,7 +205,7 @@ MainWindow
|
||||
width: 70
|
||||
font: verdana-11px-monochrome
|
||||
text: Vocation
|
||||
margin-top: 25
|
||||
margin-top: 30
|
||||
margin-left: 20
|
||||
|
||||
CheckBox
|
||||
@@ -245,7 +256,7 @@ MainWindow
|
||||
width: 70
|
||||
font: verdana-11px-monochrome
|
||||
text: Group
|
||||
margin-top: 25
|
||||
margin-top: 30
|
||||
margin-left: 20
|
||||
|
||||
CheckBox
|
||||
@@ -288,7 +299,7 @@ MainWindow
|
||||
width: 70
|
||||
font: verdana-11px-monochrome
|
||||
text: Premium
|
||||
margin-top: 25
|
||||
margin-top: 30
|
||||
margin-left: 20
|
||||
|
||||
CheckBox
|
||||
|
@@ -107,6 +107,10 @@ function displayGameMessage(text)
|
||||
displayMessage(MessageModes.Game, text)
|
||||
end
|
||||
|
||||
function displayBroadcastMessage(text)
|
||||
displayMessage(MessageModes.Warning, text)
|
||||
end
|
||||
|
||||
function clearMessages()
|
||||
for _i,child in pairs(messagesPanel:recursiveGetChildren()) do
|
||||
if child:getId():match('Label') then
|
||||
|
@@ -1,133 +1,161 @@
|
||||
-- ['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}}
|
||||
SpelllistSettings = {
|
||||
['Default'] = {
|
||||
iconFile = 'icons.png',
|
||||
iconSize = {width = 32, height = 32},
|
||||
spellListWidth = 210,
|
||||
spellWindowWidth = 550,
|
||||
spellIcons = {[39] = 'Strong Haste', [131] = 'Charge', [91] = 'Poison Bomb', [22] = 'Energy Beam', [142] = 'Envenom', [48] = 'Conjure Poisoned Arrow', [49] = 'Conjure Explosive Arrow', [114] = 'Icicle', [130] = 'Holy Missile', [56] = 'Wrath of Nature', [112] = 'Ice Strike', [87] = 'Death Strike', [10] = 'Light', [24] = 'Hells Core', [75] = 'Ultimate Light', [151] = 'Strong Energy Strike', [42] = 'Food', [117] = 'Thunderstorm', [156] = 'Ultimate Ice Strike', [18] = 'Explosion', [116] = 'Stone Shower', [59] = 'Front Sweep', [11] = 'Great Light', [155] = 'Ultimate Energy Strike', [115] = 'Avalanche', [118] = 'Eternal Winter', [82] = 'Mass Healing', [139] = 'Curser', [54] = 'Paralyze', [15] = 'Fireball', [157] = 'Ultimate Terra Strike', [83] = 'Animate Dead', [9] = 'Summon Creature', [13] = 'Energy Wave', [5] = 'Ultimate Healing Rune', [88] = 'Energy Strike', [86] = 'Magic Wall', [19] = 'Fire Wave', [149] = 'Lightning', [14] = 'Chameleon', [29] = 'Cure Poison', [78] = 'Desintegrate', [105] = 'Fierce Berserk', [108] = 'Conjure Sniper Arrow', [30] = 'Destroy Field', [12] = 'Convince Creature', [4] = 'Intense Healing Rune', [31] = 'Cure Poison Rune', [152] = 'Strong Ice Strike', [21] = 'Sudden Death', [27] = 'Energy Field', [80] = 'Berserk', [55] = 'Energybomb', [28] = 'Fire Wall', [43] = 'Strong Ice Wave', [50] = 'Soulfire', [57] = 'Strong Ethereal Spear', [26] = 'Poison Field', [61] = 'Brutal Strike', [17] = 'Firebomb', [45] = 'Invisibility', [20] = 'Find Person', [146] = 'Cure Electrification', [7] = 'Light Magic Missile', [16] = 'Great Fireball', [92] = 'Enchant Staff', [148] = 'Physical Strike', [132] = 'Protector', [111] = 'Ethereal Spear', [143] = 'Holy Flash', [77] = 'Stalagmite', [33] = 'Energy Wall', [107] = 'Whirlwind Throw', [38] = 'Creature Illusion', [158] = 'Intense Wound Cleansing', [124] = 'Divine Caldera', [84] = 'Heal Friend', [8] = 'Heavy Magic Missile', [25] = 'Fire Field', [125] = 'Divine Healing', [140] = 'Electrify', [95] = 'Conjure Power Bolt', [36] = 'Salvation', [134] = 'Swift Foot', [109] = 'Conjure Piercing Bolt', [79] = 'Conjure Bolt', [141] = 'Inflict Wound', [153] = 'Strong Terra Strike', [1] = 'Light Healing', [51] = 'Conjure Arrow', [123] = 'Wound Cleansing', [129] = 'Enchant Party', [128] = 'Heal Party', [127] = 'Protect Party', [126] = 'Train Party', [23] = 'Great Energy Beam', [2] = 'Intense Healing', [133] = 'Blood Rage', [160] = 'Intense Recovery', [94] = 'Wild Growth', [89] = 'Flame Strike', [147] = 'Cure Curse', [93] = 'Challenge', [90] = 'Cancel Invisibility', [110] = 'Enchant Spear', [6] = 'Haste', [44] = 'Magic Shield', [81] = 'Levitate', [145] = 'Cure Burning', [76] = 'Magic Rope', [3] = 'Ultimate Healing', [159] = 'Recovery', [122] = 'Divine Missile', [120] = 'Terra Wave', [144] = 'Cure Bleeding', [150] = 'Strong Flame Strike', [113] = 'Terra Strike', [62] = 'Annihilation', [121] = 'Ice Wave', [135] = 'Sharpshooter', [138] = 'Ignite', [32] = 'Poison Wall', [119] = 'Rage of the Skies', [154] = 'Ultimate Flame Strike', [106] = 'Groundshaker'},
|
||||
spellOrder = {'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'}
|
||||
},
|
||||
|
||||
['Sample'] = {
|
||||
iconFile = 'sample.png',
|
||||
iconSize = {width = 64, height = 64},
|
||||
spellIcons = {[1] = 'Wind Walk', [2] = 'Fire Breath', [3] = 'Moonglaives', [5] = 'Firefly', [4] = 'Critical Strike'},
|
||||
spellOrder = {'Critical Strike', 'Firefly', 'Fire Breath', 'Moonglaives', 'Wind Walk'}
|
||||
}
|
||||
}
|
||||
|
||||
-- ['const_name'] = {client_id, TFS_id}
|
||||
-- ['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 = {
|
||||
['Default'] = {
|
||||
['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.', level = 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}}
|
||||
},
|
||||
|
||||
['Sample'] = {
|
||||
['Wind Walk'] = {words = 'windwalk', description = 'Run at enormous speed.', exhaustion = 2000, premium = false, type = 'Instant', icon = 1, mana = 50, level = 10, soul = 0, group = {[3] = 2000}, vocations = {1, 2}},
|
||||
['Fire Breath'] = {words = 'firebreath', description = 'A strong firewave.', exhaustion = 2000, premium = false, type = 'Instant', icon = 2, mana = 350, level = 27, soul = 0, group = {[1] = 2000}, vocations = {4, 8}},
|
||||
['Moonglaives'] = {words = 'moonglaives', description = 'Throw moonglaives around you.', exhaustion = 2000, premium = false, type = 'Instant', icon = 3, mana = 90, level = 55, soul = 0, group = {[1] = 2000}, vocations = {3, 7}},
|
||||
['Critical Strike'] = {words = 'criticalstrike', description = 'Land a critical strike.', exhaustion = 2000, premium = false, type = 'Instant', icon = 4, mana = 350, level = 27, soul = 0, group = {[1] = 2000}, vocations = {3, 4, 7, 8}},
|
||||
['Firefly'] = {words = 'firefly', description = 'Summon a angry firefly', exhaustion = 2000, premium = false, type = 'Instant', icon = 5, mana = 350, level = 27, soul = 0, group = {[1] = 2000}, vocations = {1, 2, 5, 6}}
|
||||
}
|
||||
}
|
||||
|
||||
-- ['const_name'] = {client_id, TFS_id}
|
||||
-- Conversion from TFS icon id to the id used by client (icons.png order)
|
||||
SpellIcons = {
|
||||
['intenserecovery'] = {16, 160},
|
||||
@@ -284,5 +312,5 @@ SpellGroups = {
|
||||
[1] = 'Attack',
|
||||
[2] = 'Healing',
|
||||
[3] = 'Support',
|
||||
[4] = 'Powerstrikes'
|
||||
[4] = 'Special'
|
||||
}
|
||||
|
@@ -98,7 +98,7 @@ void Logger::fireOldMessages()
|
||||
|
||||
void Logger::setLogFile(const std::string& file)
|
||||
{
|
||||
m_outFile.open(file.c_str(), std::ios::out | std::ios::app);
|
||||
m_outFile.open(stdext::utf8_to_latin1(file.c_str()).c_str(), std::ios::out | std::ios::app);
|
||||
if(!m_outFile.is_open() || !m_outFile.good()) {
|
||||
g_logger.error(stdext::format("Unable to save log to '%s'", file));
|
||||
return;
|
||||
|
@@ -34,6 +34,7 @@ ResourceManager g_resources;
|
||||
void ResourceManager::init(const char *argv0)
|
||||
{
|
||||
PHYSFS_init(argv0);
|
||||
PHYSFS_permitSymbolicLinks(1);
|
||||
}
|
||||
|
||||
void ResourceManager::terminate()
|
||||
@@ -44,21 +45,23 @@ void ResourceManager::terminate()
|
||||
void ResourceManager::discoverWorkDir(const std::string& appName, const std::string& existentFile)
|
||||
{
|
||||
// search for modules directory
|
||||
std::string sep = PHYSFS_getDirSeparator();
|
||||
std::string possiblePaths[] = { boost::filesystem::current_path().generic_string() + sep,
|
||||
g_resources.getBaseDir() + ".." + sep,
|
||||
g_resources.getBaseDir() + ".." + sep + "share" + sep + appName + sep,
|
||||
g_resources.getBaseDir() + appName + sep };
|
||||
std::string possiblePaths[] = { g_resources.getCurrentDir(),
|
||||
g_resources.getBaseDir() + "../",
|
||||
g_resources.getBaseDir() + "../share/" + appName + "/",
|
||||
g_resources.getBaseDir() + appName + "/" };
|
||||
|
||||
bool found = false;
|
||||
for(const std::string& dir : possiblePaths) {
|
||||
// try to directory to modules path to see if it exists
|
||||
std::ifstream fin(dir + existentFile);
|
||||
if(fin) {
|
||||
if(!PHYSFS_addToSearchPath(dir.c_str(), 0))
|
||||
continue;
|
||||
|
||||
if(PHYSFS_exists(existentFile.c_str())) {
|
||||
g_logger.debug(stdext::format("Found work dir at '%s'", dir.c_str()));
|
||||
m_workDir = dir;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
PHYSFS_removeFromSearchPath(dir.c_str());
|
||||
}
|
||||
|
||||
if(!found)
|
||||
@@ -75,13 +78,18 @@ bool ResourceManager::setupUserWriteDir(const std::string& appWriteDirName)
|
||||
dirName = appWriteDirName;
|
||||
#endif
|
||||
std::string writeDir = userDir + dirName;
|
||||
|
||||
if(!PHYSFS_setWriteDir(writeDir.c_str())) {
|
||||
if(!PHYSFS_setWriteDir(userDir.c_str()) || !PHYSFS_mkdir(dirName.c_str())) {
|
||||
g_logger.error(stdext::format("Unable to create write directory '%s': %s", writeDir, PHYSFS_getLastError()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return setWriteDir(writeDir);
|
||||
}
|
||||
|
||||
bool ResourceManager::setWriteDir(const std::string& writeDir, bool create)
|
||||
{
|
||||
boost::filesystem::create_directory(writeDir);
|
||||
|
||||
if(!PHYSFS_setWriteDir(writeDir.c_str())) {
|
||||
g_logger.error(stdext::format("Unable to set write directory '%s': %s", writeDir, PHYSFS_getLastError()));
|
||||
return false;
|
||||
@@ -113,7 +121,7 @@ bool ResourceManager::addSearchPath(const std::string& path, bool pushFront)
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
g_logger.error(stdext::format("Could not add '%s' to directory search path. Reason %s", path, PHYSFS_getLastError()));
|
||||
//g_logger.error(stdext::format("Could not add '%s' to directory search path. Reason %s", path, PHYSFS_getLastError()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -121,7 +129,6 @@ bool ResourceManager::addSearchPath(const std::string& path, bool pushFront)
|
||||
m_searchPaths.push_front(savePath);
|
||||
else
|
||||
m_searchPaths.push_back(savePath);
|
||||
m_hasSearchPath = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -161,31 +168,21 @@ bool ResourceManager::directoryExists(const std::string& directoryName)
|
||||
void ResourceManager::loadFile(const std::string& fileName, std::iostream& out)
|
||||
{
|
||||
out.clear(std::ios::goodbit);
|
||||
if(m_hasSearchPath) {
|
||||
std::string fullPath = resolvePath(fileName);
|
||||
PHYSFS_file* file = PHYSFS_openRead(fullPath.c_str());
|
||||
if(!file) {
|
||||
out.clear(std::ios::failbit);
|
||||
stdext::throw_exception(stdext::format("unable to load file '%s': %s", fullPath.c_str(), PHYSFS_getLastError()));
|
||||
} else {
|
||||
int fileSize = PHYSFS_fileLength(file);
|
||||
if(fileSize > 0) {
|
||||
std::vector<char> buffer(fileSize);
|
||||
PHYSFS_read(file, (void*)&buffer[0], 1, fileSize);
|
||||
out.write(&buffer[0], fileSize);
|
||||
} else
|
||||
out.clear(std::ios::eofbit);
|
||||
PHYSFS_close(file);
|
||||
out.seekg(0, std::ios::beg);
|
||||
}
|
||||
std::string fullPath = resolvePath(fileName);
|
||||
PHYSFS_file* file = PHYSFS_openRead(fullPath.c_str());
|
||||
if(!file) {
|
||||
out.clear(std::ios::failbit);
|
||||
stdext::throw_exception(stdext::format("unable to load file '%s': %s", fullPath.c_str(), PHYSFS_getLastError()));
|
||||
} else {
|
||||
std::ifstream fin(fileName);
|
||||
if(!fin) {
|
||||
out.clear(std::ios::failbit);
|
||||
stdext::throw_exception(stdext::format("unable to load file '%s': %s", fileName.c_str(), PHYSFS_getLastError()));
|
||||
} else {
|
||||
out << fin.rdbuf();
|
||||
}
|
||||
int fileSize = PHYSFS_fileLength(file);
|
||||
if(fileSize > 0) {
|
||||
std::vector<char> buffer(fileSize);
|
||||
PHYSFS_read(file, (void*)&buffer[0], 1, fileSize);
|
||||
out.write(&buffer[0], fileSize);
|
||||
} else
|
||||
out.clear(std::ios::eofbit);
|
||||
PHYSFS_close(file);
|
||||
out.seekg(0, std::ios::beg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,8 +297,17 @@ std::string ResourceManager::getRealDir(const std::string& path)
|
||||
return dir;
|
||||
}
|
||||
|
||||
std::string ResourceManager::getBaseDir()
|
||||
std::string ResourceManager::getCurrentDir()
|
||||
{
|
||||
return PHYSFS_getBaseDir();
|
||||
char buffer[2048];
|
||||
PHYSFS_utf8FromLatin1((boost::filesystem::current_path().generic_string() + "/").c_str(), buffer, 2048);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string ResourceManager::getBaseDir()
|
||||
{
|
||||
char buffer[2048];
|
||||
PHYSFS_utf8FromLatin1(PHYSFS_getBaseDir(), buffer, 2048);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@@ -64,6 +64,7 @@ public:
|
||||
|
||||
std::string resolvePath(const std::string& path);
|
||||
std::string getRealDir(const std::string& path);
|
||||
std::string getCurrentDir();
|
||||
std::string getBaseDir();
|
||||
std::string getWriteDir() { return m_writeDir; }
|
||||
std::string getWorkDir() { return m_workDir; }
|
||||
@@ -72,7 +73,6 @@ public:
|
||||
private:
|
||||
std::string m_workDir;
|
||||
std::string m_writeDir;
|
||||
stdext::boolean<false> m_hasSearchPath;
|
||||
std::deque<std::string> m_searchPaths;
|
||||
};
|
||||
|
||||
|
@@ -103,6 +103,7 @@ void PlatformWindow::processKeyUp(Fw::Key keyCode)
|
||||
|
||||
if(m_onInputEvent) {
|
||||
m_inputEvent.reset(Fw::KeyUpInputEvent);
|
||||
m_inputEvent.keyCode = keyCode;
|
||||
m_onInputEvent(m_inputEvent);
|
||||
}
|
||||
}
|
||||
|
@@ -847,7 +847,7 @@ void WIN32Window::setFullscreen(bool fullscreen)
|
||||
} else {
|
||||
SetWindowLong(m_window, GWL_STYLE, (dwStyle & ~(WS_POPUP | WS_EX_TOPMOST)) | WS_OVERLAPPEDWINDOW);
|
||||
SetWindowPlacement(m_window, &wpPrev);
|
||||
SetWindowPos(m_window, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
||||
SetWindowPos(m_window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -946,7 +946,7 @@ std::string WIN32Window::getClipboardText()
|
||||
if(hglb) {
|
||||
LPTSTR lptstr = (LPTSTR)GlobalLock(hglb);
|
||||
if(lptstr) {
|
||||
text = stdext::utf8_to_latin1((uchar*)lptstr);
|
||||
text = stdext::utf8_to_latin1(lptstr);
|
||||
GlobalUnlock(hglb);
|
||||
}
|
||||
}
|
||||
|
@@ -1056,7 +1056,7 @@ std::string X11Window::getClipboardText()
|
||||
&bytesLeft,
|
||||
&data);
|
||||
if(len > 0) {
|
||||
clipboardText = stdext::utf8_to_latin1(data);
|
||||
clipboardText = stdext::utf8_to_latin1((char*)data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -67,9 +67,9 @@ uint64_t hex_to_dec(const std::string& str)
|
||||
return num;
|
||||
}
|
||||
|
||||
std::string utf8_to_latin1(uchar *utf8)
|
||||
std::string utf8_to_latin1(const std::string& src)
|
||||
{
|
||||
auto utf8CharToLatin1 = [](uchar *utf8, int *read) -> char {
|
||||
auto utf8CharToLatin1 = [](const uchar *utf8, int *read) -> char {
|
||||
char c = '?';
|
||||
uchar opt1 = utf8[0];
|
||||
*read = 1;
|
||||
@@ -89,10 +89,10 @@ std::string utf8_to_latin1(uchar *utf8)
|
||||
};
|
||||
|
||||
std::string out;
|
||||
int len = strlen((char*)utf8);
|
||||
int len = src.length();
|
||||
for(int i=0; i<len;) {
|
||||
int read = 0;
|
||||
uchar *utf8char = &utf8[i];
|
||||
uchar *utf8char = (uchar*)&src[i];
|
||||
out += utf8CharToLatin1(utf8char, &read);
|
||||
i += read;
|
||||
}
|
||||
|
@@ -42,7 +42,7 @@ std::string date_time_string();
|
||||
|
||||
std::string dec_to_hex(uint64_t num);
|
||||
uint64_t hex_to_dec(const std::string& str);
|
||||
std::string utf8_to_latin1(uchar *utf8);
|
||||
std::string utf8_to_latin1(const std::string& src);
|
||||
void tolower(std::string& str);
|
||||
void toupper(std::string& str);
|
||||
void trim(std::string& str);
|
||||
|
@@ -40,7 +40,7 @@ int main(int argc, const char* argv[])
|
||||
|
||||
// find script init.lua and run it
|
||||
g_resources.discoverWorkDir(g_app.getCompactName(), "init.lua");
|
||||
if(!g_lua.safeRunScript(g_resources.getWorkDir() + "init.lua"))
|
||||
if(!g_lua.safeRunScript("init.lua"))
|
||||
g_logger.fatal("Unable to run script init.lua!");
|
||||
|
||||
// the run application main loop
|
||||
|
@@ -359,6 +359,30 @@ namespace Otc
|
||||
PATHFIND_ALLOW_NONPATHABLE = 4,
|
||||
PATHFIND_ALLOW_NONWALKABLE = 8
|
||||
};
|
||||
|
||||
enum AutomapFlags
|
||||
{
|
||||
MAPMARK_TICK = 0,
|
||||
MAPMARK_QUESTION,
|
||||
MAPMARK_EXCLAMATION,
|
||||
MAPMARK_STAR,
|
||||
MAPMARK_CROSS,
|
||||
MAPMARK_TEMPLE,
|
||||
MAPMARK_KISS,
|
||||
MAPMARK_SHOVEL,
|
||||
MAPMARK_SWORD,
|
||||
MAPMARK_FLAG,
|
||||
MAPMARK_LOCK,
|
||||
MAPMARK_BAG,
|
||||
MAPMARK_SKULL,
|
||||
MAPMARK_DOLLAR,
|
||||
MAPMARK_REDNORTH,
|
||||
MAPMARK_REDSOUTH,
|
||||
MAPMARK_REDEAST,
|
||||
MAPMARK_REDWEST,
|
||||
MAPMARK_GREENNORTH,
|
||||
MAPMARK_GREENSOUTH
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -710,7 +710,7 @@ void Game::useWith(const ItemPtr& item, const ThingPtr& toThing)
|
||||
if(!pos.isValid()) // virtual item
|
||||
pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
|
||||
|
||||
if(toThing->isCreature())
|
||||
if(toThing->isCreature() && g_game.getClientVersion() >= 860)
|
||||
m_protocolGame->sendUseOnCreature(pos, item->getId(), item->getStackpos(), toThing->getId());
|
||||
else
|
||||
m_protocolGame->sendUseItemWith(pos, item->getId(), item->getStackpos(), toThing->getPosition(), toThing->getId(), toThing->getStackpos());
|
||||
|
@@ -28,11 +28,6 @@
|
||||
|
||||
void ProtocolGame::login(const std::string& accountName, const std::string& accountPassword, const std::string& host, uint16 port, const std::string& characterName)
|
||||
{
|
||||
if(accountName.empty() || accountPassword.empty()) {
|
||||
callLuaField("onError", "You must enter an account name and password.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_accountName = accountName;
|
||||
m_accountPassword = accountPassword;
|
||||
m_characterName = characterName;
|
||||
|
@@ -1288,10 +1288,11 @@ void ProtocolGame::parseTutorialHint(const InputMessagePtr& msg)
|
||||
|
||||
void ProtocolGame::parseAutomapFlag(const InputMessagePtr& msg)
|
||||
{
|
||||
// ignored
|
||||
getPosition(msg); // position
|
||||
msg->getU8(); // icon
|
||||
msg->getString(); // message
|
||||
Position pos = getPosition(msg); // position
|
||||
int icon = msg->getU8(); // icon
|
||||
std::string description = msg->getString(); // message
|
||||
|
||||
g_game.processAutomapFlag(pos, icon, description);
|
||||
}
|
||||
|
||||
void ProtocolGame::parseQuestLog(const InputMessagePtr& msg)
|
||||
|
@@ -102,16 +102,11 @@ ImagePtr SpriteManager::getSpriteImage(int id)
|
||||
int read = 0;
|
||||
|
||||
// decompress pixels
|
||||
while(read < pixelDataSize) {
|
||||
while(read < pixelDataSize && writePos < SPRITE_DATA_SIZE) {
|
||||
uint16 transparentPixels = m_spritesFile->getU16();
|
||||
uint16 coloredPixels = m_spritesFile->getU16();
|
||||
|
||||
if(writePos + transparentPixels*4 + coloredPixels*3 >= SPRITE_DATA_SIZE) {
|
||||
g_logger.warning(stdext::format("corrupt sprite id %d", id));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for(int i = 0; i < transparentPixels; i++) {
|
||||
for(int i = 0; i < transparentPixels && writePos < SPRITE_DATA_SIZE; i++) {
|
||||
pixels[writePos + 0] = 0x00;
|
||||
pixels[writePos + 1] = 0x00;
|
||||
pixels[writePos + 2] = 0x00;
|
||||
@@ -119,12 +114,11 @@ ImagePtr SpriteManager::getSpriteImage(int id)
|
||||
writePos += 4;
|
||||
}
|
||||
|
||||
for(int i = 0; i < coloredPixels; i++) {
|
||||
for(int i = 0; i < coloredPixels && writePos < SPRITE_DATA_SIZE; i++) {
|
||||
pixels[writePos + 0] = m_spritesFile->getU8();
|
||||
pixels[writePos + 1] = m_spritesFile->getU8();
|
||||
pixels[writePos + 2] = m_spritesFile->getU8();
|
||||
pixels[writePos + 3] = 0xFF;
|
||||
|
||||
writePos += 4;
|
||||
}
|
||||
|
||||
|
@@ -191,10 +191,9 @@ void ThingTypeManager::parseItemType(uint16 id, TiXmlElement* elem)
|
||||
itemType = ItemTypePtr(new ItemType);
|
||||
itemType->setServerId(serverId);
|
||||
addItemType(itemType);
|
||||
}
|
||||
} else
|
||||
itemType = getItemType(serverId);
|
||||
|
||||
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");
|
||||
|