restore some game functionallity

* i'm gradually restoring game functionality with the new modules design, though still a lot to do
* you can reload all scripts and modules using Ctrl+R shortcut while playing (finally! this is the reason of all this rework)
* a bunch of fixes, but new regression too :P
* fix performance issue that could lead freezes in the client in older machines
* completely new game module with new design
* fix crashs in map render
* remove uigame.cpp (now every game input is via lua)
* enable DEBUG macro by default, with it you are able to view any possible lua leak while running
master
Eduardo Bart 12 years ago
parent 26629cf77c
commit c0611bfe2a

@ -1,5 +1,12 @@
Client = {} Client = {}
function Client.reloadScripts()
dofile 'otclientrc.lua'
reloadModules()
TextMessage.displayEventAdvance('All modules and scripts were reloaded.')
print('All modules and scripts were reloaded.')
end
function Client.init() function Client.init()
g_window.setMinimumSize({ width = 600, height = 480 }) g_window.setMinimumSize({ width = 600, height = 480 })

@ -14,6 +14,7 @@ Module
- client_terminal - client_terminal
- client_modulemanager - client_modulemanager
- client_entergame - client_entergame
- game
@onLoad: | @onLoad: |
dofile 'client' dofile 'client'

@ -11,7 +11,10 @@ function Background.init()
local clientVersionLabel = background:getChildById('clientVersionLabel') local clientVersionLabel = background:getChildById('clientVersionLabel')
clientVersionLabel:setText('OTClient ' .. g_app.getVersion() .. '\n' .. clientVersionLabel:setText('OTClient ' .. g_app.getVersion() .. '\n' ..
'Built on ' .. g_app.getBuildDate()) 'Built on ' .. g_app.getBuildDate())
Effects.fadeIn(clientVersionLabel, 1500)
if not g_game.isOnline() then
Effects.fadeIn(clientVersionLabel, 1500)
end
connect(g_game, { onGameStart = Background.hide }) connect(g_game, { onGameStart = Background.hide })
connect(g_game, { onGameEnd = Background.show }) connect(g_game, { onGameEnd = Background.show })

@ -11,12 +11,12 @@ Panel
focusable: false focusable: false
UILabel UILabel
background-color: #00000099
id: clientVersionLabel id: clientVersionLabel
background-color: #00000099
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
text-offset: 4 2 text-offset: 4 2
height: 32 height: 32
width: 120 width: 120
color: #ffffff color: #ffffff
font: verdana-11px-monochrome font: verdana-11px-monochrome

@ -52,7 +52,6 @@ local function tryLogin(charInfo, tries)
Settings.set('lastUsedCharacter', charInfo.characterName) Settings.set('lastUsedCharacter', charInfo.characterName)
end end
function onGameLoginError(message) function onGameLoginError(message)
CharacterList.destroyLoadBox() CharacterList.destroyLoadBox()
local errorBox = displayErrorBox("Login Error", "Login error: " .. message) local errorBox = displayErrorBox("Login Error", "Login error: " .. message)
@ -67,6 +66,10 @@ end
-- public functions -- public functions
function CharacterList.init() function CharacterList.init()
charactersWindow = displayUI('characterlist.otui')
charactersWindow:hide()
characterList = charactersWindow:getChildById('characterList')
charactersWindow.onKeyPress = onCharactersWindowKeyPress
connect(g_game, { onLoginError = onGameLoginError }) connect(g_game, { onLoginError = onGameLoginError })
connect(g_game, { onConnectionError = onGameConnectionError }) connect(g_game, { onConnectionError = onGameConnectionError })
connect(g_game, { onGameStart = CharacterList.destroyLoadBox }) connect(g_game, { onGameStart = CharacterList.destroyLoadBox })
@ -74,11 +77,13 @@ function CharacterList.init()
end end
function CharacterList.terminate() function CharacterList.terminate()
disconnect(g_game, { onLoginError = onGameLoginError })
disconnect(g_game, { onConnectionError = onGameConnectionError })
disconnect(g_game, { onGameStart = CharacterList.destroyLoadBox })
disconnect(g_game, { onGameEnd = CharacterList.show })
characterList = nil characterList = nil
if charactersWindow then charactersWindow:destroy()
charactersWindow:destroy() charactersWindow = nil
charactersWindow = nil
end
if loadBox then if loadBox then
g_game.cancelLogin() g_game.cancelLogin()
loadBox:destroy() loadBox:destroy()
@ -88,14 +93,9 @@ function CharacterList.terminate()
end end
function CharacterList.create(characters, premDays) function CharacterList.create(characters, premDays)
if charactersWindow then CharacterList.show()
charactersWindow:destroy() characterList:destroyChildren()
end
charactersWindow = displayUI('characterlist.otui')
characterList = charactersWindow:getChildById('characterList')
local accountStatusLabel = charactersWindow:getChildById('accountStatusLabel') local accountStatusLabel = charactersWindow:getChildById('accountStatusLabel')
connect(charactersWindow, {onKeyPress = onCharactersWindowKeyPress })
local focusLabel local focusLabel
for i,characterInfo in ipairs(characters) do for i,characterInfo in ipairs(characters) do

@ -184,12 +184,8 @@ function Terminal.executeCommand(command)
-- detect and convert commands with simple syntax -- detect and convert commands with simple syntax
local realCommand local realCommand
if commandEnv[command] then if string.sub(command, 1, 1) == '=' then
if type(commandEnv[command]) == "function" then realCommand = 'print(' .. string.sub(command,2) .. ')'
realCommand = command .. '()'
else
realCommand = 'print(' .. command .. ')'
end
else else
realCommand = command realCommand = command
end end

@ -30,25 +30,27 @@ end
-- public functions -- public functions
function TopMenu.init() function TopMenu.init()
connect(g_game, { onGameStart = TopMenu.showGameButtons,
onGameEnd = TopMenu.hideGameButtons })
topMenu = displayUI('topmenu.otui') topMenu = displayUI('topmenu.otui')
leftButtonsPanel = topMenu:getChildById('leftButtonsPanel') leftButtonsPanel = topMenu:getChildById('leftButtonsPanel')
rightButtonsPanel = topMenu:getChildById('rightButtonsPanel') rightButtonsPanel = topMenu:getChildById('rightButtonsPanel')
gameButtonsPanel = topMenu:getChildById('gameButtonsPanel') gameButtonsPanel = topMenu:getChildById('gameButtonsPanel')
connect(g_game, { onGameStart = TopMenu.showGameButtons,
onGameEnd = TopMenu.hideGameButtons })
end end
function TopMenu.terminate() function TopMenu.terminate()
disconnect(g_game, { onGameStart = TopMenu.showGameButtons,
onGameEnd = TopMenu.hideGameButtons })
leftButtonsPanel = nil leftButtonsPanel = nil
rightButtonsPanel = nil rightButtonsPanel = nil
gameButtonsPanel = nil gameButtonsPanel = nil
topMenu:destroy() topMenu:destroy()
topMenu = nil topMenu = nil
disconnect(g_game, { onGameStart = TopMenu.showGameButtons,
onGameEnd = TopMenu.hideGameButtons })
TopMenu = nil TopMenu = nil
end end

@ -10,10 +10,12 @@ Module
dofile 'ext/table' dofile 'ext/table'
dofile 'ext/string' dofile 'ext/string'
dofile 'ext/os' dofile 'ext/os'
dofile 'math/point' dofile 'math/point'
dofile 'math/size' dofile 'math/size'
dofile 'math/color' dofile 'math/color'
dofile 'math/rect' dofile 'math/rect'
dofile 'const' dofile 'const'
dofile 'util' dofile 'util'
dofile 'globals' dofile 'globals'
@ -35,8 +37,4 @@ Module
dofile 'widgets/uitabbar' dofile 'widgets/uitabbar'
dofile 'widgets/uipopupmenu' dofile 'widgets/uipopupmenu'
dofile 'widgets/uiwindow' dofile 'widgets/uiwindow'
--dofile 'widgets/uiminiwindow'
--dofile 'widgets/uiminiwindowcontainer'
dofile 'widgets/uimessagebox' dofile 'widgets/uimessagebox'

@ -68,5 +68,3 @@ end
function reloadModules() function reloadModules()
g_modules.reloadModules() g_modules.reloadModules()
end end

@ -70,8 +70,8 @@ local function onWidgetKeyDown(widget, keyCode, keyboardModifiers)
end end
local function onWidgetKeyPress(widget, keyCode, keyboardModifiers, autoRepeatTicks) local function onWidgetKeyPress(widget, keyCode, keyboardModifiers, autoRepeatTicks)
local keyComboDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
if keyCode == KeyUnknown then return false end if keyCode == KeyUnknown then return false end
local keyComboDesc = determineKeyComboDesc(keyCode, keyboardModifiers)
local comboConf = widget.boundKeyPressCombos[keyComboDesc] local comboConf = widget.boundKeyPressCombos[keyComboDesc]
if comboConf and (autoRepeatTicks >= comboConf.autoRepeatDelay or autoRepeatTicks == 0) and comboConf.callback then if comboConf and (autoRepeatTicks >= comboConf.autoRepeatDelay or autoRepeatTicks == 0) and comboConf.callback then
comboConf.callback() comboConf.callback()

@ -1,7 +1,7 @@
Mouse = {} Mouse = {}
function Mouse.setTargetCursor() function Mouse.setTargetCursor()
g_window.setMouseCursor('/core_styles/icons/targetcursor.png', {x=9,y=9}) g_window.setMouseCursor('/core_styles/cursors/targetcursor.png', {x=9,y=9})
end end
function Mouse.restoreCursor() function Mouse.restoreCursor()

@ -36,7 +36,8 @@ function UITabBar:addTab(text, panel)
tab.tabBar = self tab.tabBar = self
tab:setText(text) tab:setText(text)
tab:setWidth(tab:getTextSize().width + tab:getPaddingLeft() + tab:getPaddingRight()) tab:setWidth(tab:getTextSize().width + tab:getPaddingLeft() + tab:getPaddingRight())
connect(tab, { onClick = onTabClick }) tab.onClick = onTabClick
tab.onDestroy = function() tab.tabPanel:destroy() end
table.insert(self.tabs, tab) table.insert(self.tabs, tab)
if #self.tabs == 1 then if #self.tabs == 1 then

@ -23,9 +23,7 @@ Module
importStyle 'styles/tabbars.otui' importStyle 'styles/tabbars.otui'
importStyle 'styles/windows.otui' importStyle 'styles/windows.otui'
importStyle 'styles/listboxes.otui' importStyle 'styles/listboxes.otui'
importStyle 'styles/items.otui'
importStyle 'styles/creatures.otui'
importStyle 'styles/popupmenus.otui' importStyle 'styles/popupmenus.otui'
importStyle 'styles/comboboxes.otui' importStyle 'styles/comboboxes.otui'
importStyle 'styles/spinboxes.otui' importStyle 'styles/spinboxes.otui'
importStyle 'styles/messagebox.otui' importStyle 'styles/messageboxes.otui'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 932 B

@ -18,7 +18,7 @@ Button < UIButton
color: #f0ad4d88 color: #f0ad4d88
image-color: #ffffff88 image-color: #ffffff88
ConsoleButton < UIButton TabButton < UIButton
size: 20 20 size: 20 20
image-source: /core_styles/styles/images/tabbutton.png image-source: /core_styles/styles/images/tabbutton.png
image-color: white image-color: white

@ -42,4 +42,4 @@ ComboBox < UIComboBox
image-clip: 0 20 89 20 image-clip: 0 20 89 20
$on: $on:
image-clip: 0 40 89 20 image-clip: 0 40 89 20

@ -4,4 +4,3 @@ ProgressBar < UIProgressBar
border: 1 black border: 1 black
image: /core_styles/styles/images/progressbar.png image: /core_styles/styles/images/progressbar.png
image-border: 1 image-border: 1

@ -3,4 +3,4 @@ HorizontalSeparator < UIWidget
image-border-top: 2 image-border-top: 2
height: 2 height: 2
phantom: true phantom: true
focusable: false focusable: false

@ -31,4 +31,4 @@ TabBarButton < UIButton
color: #80c7f8 color: #80c7f8
$on !checked: $on !checked:
color: #F55E5E color: #F55E5E

@ -22,24 +22,3 @@ Window < UIWindow
MainWindow < Window MainWindow < Window
anchors.centerIn: parent anchors.centerIn: parent
MiniWindow < UIMiniWindow
font: verdana-11px-antialised
//icon: /core_styles/icons/login.png
icon-rect: 4 4 16 16
width: 192
height: 200
text-offset: 26 5
text-align: topLeft
margin-top: 2
margin-left: 6
margin-right: 6
move-policy: free updated
image-source: /core_styles/styles/images/mini_window.png
image-border: 4
image-border-top: 23
padding: 25 8 2 8
$on:
height: 24
image-border-bottom: 1

@ -0,0 +1,24 @@
SkullNone = 0
SkullYellow = 1
SkullGreen = 2
SkullWhite = 3
SkullRed = 4
SkullBlack = 5
SkullOrange = 6
ShieldNone = 0
ShieldWhiteYellow = 1
ShieldWhiteBlue = 2
ShieldBlue = 3
ShieldYellow = 4
ShieldBlueSharedExp = 5
ShieldYellowSharedExp = 6
ShieldBlueNoSharedExpBlink = 7
ShieldYellowNoSharedExpBlink = 8
ShieldBlueNoSharedExp = 9
ShieldYellowNoSharedExp = 10
EmblemNone = 0
EmblemGreen = 1
EmblemRed = 2
EmblemBlue = 3

@ -25,51 +25,51 @@ EmblemBlue = 3
function getSkullImagePath(skullId) function getSkullImagePath(skullId)
if skullId == SkullYellow then if skullId == SkullYellow then
return 'images/skull_yellow.png' return 'icons/skull_yellow.png'
elseif skullId == SkullGreen then elseif skullId == SkullGreen then
return 'images/skull_green.png' return 'icons/skull_green.png'
elseif skullId == SkullWhite then elseif skullId == SkullWhite then
return 'images/skull_white.png' return 'icons/skull_white.png'
elseif skullId == SkullRed then elseif skullId == SkullRed then
return 'images/skull_red.png' return 'icons/skull_red.png'
elseif skullId == SkullBlack then elseif skullId == SkullBlack then
return 'images/skull_black.png' return 'icons/skull_black.png'
elseif skullId == SkullOrange then elseif skullId == SkullOrange then
return 'images/skull_orange.png' return 'icons/skull_orange.png'
end end
end end
function getShieldImagePathAndBlink(shieldId) function getShieldImagePathAndBlink(shieldId)
if shieldId == ShieldWhiteYellow then if shieldId == ShieldWhiteYellow then
return 'images/shield_yellow_white.png', false return 'icons/shield_yellow_white.png', false
elseif shieldId == ShieldWhiteBlue then elseif shieldId == ShieldWhiteBlue then
return 'images/shield_blue_white.png', false return 'icons/shield_blue_white.png', false
elseif shieldId == ShieldBlue then elseif shieldId == ShieldBlue then
return 'images/shield_blue.png', false return 'icons/shield_blue.png', false
elseif shieldId == ShieldYellow then elseif shieldId == ShieldYellow then
return 'images/shield_yellow.png', false return 'icons/shield_yellow.png', false
elseif shieldId == ShieldBlueSharedExp then elseif shieldId == ShieldBlueSharedExp then
return 'images/shield_blue_shared.png', false return 'icons/shield_blue_shared.png', false
elseif shieldId == ShieldYellowSharedExp then elseif shieldId == ShieldYellowSharedExp then
return 'images/shield_yellow_shared.png', false return 'icons/shield_yellow_shared.png', false
elseif shieldId == ShieldBlueNoSharedExpBlink then elseif shieldId == ShieldBlueNoSharedExpBlink then
return 'images/shield_blue_not_shared.png', true return 'icons/shield_blue_not_shared.png', true
elseif shieldId == ShieldYellowNoSharedExpBlink then elseif shieldId == ShieldYellowNoSharedExpBlink then
return 'images/shield_yellow_not_shared.png', true return 'icons/shield_yellow_not_shared.png', true
elseif shieldId == ShieldBlueNoSharedExp then elseif shieldId == ShieldBlueNoSharedExp then
return 'images/shield_blue_not_shared.png', false return 'icons/shield_blue_not_shared.png', false
elseif shieldId == ShieldYellowNoSharedExp then elseif shieldId == ShieldYellowNoSharedExp then
return 'images/shield_yellow_not_shared.png', false return 'icons/shield_yellow_not_shared.png', false
end end
end end
function getEmblemImagePath(emblemId) function getEmblemImagePath(emblemId)
if emblemId == EmblemGreen then if emblemId == EmblemGreen then
return 'images/emblem_green.png' return 'icons/emblem_green.png'
elseif emblemId == EmblemRed then elseif emblemId == EmblemRed then
return 'images/emblem_red.png' return 'icons/emblem_red.png'
elseif emblemId == EmblemBlue then elseif emblemId == EmblemBlue then
return 'images/emblem_blue.png' return 'icons/emblem_blue.png'
end end
end end

@ -7,11 +7,26 @@ Module
dependencies: dependencies:
- game_tibiafiles - game_tibiafiles
- client_background
//- game_shaders //- game_shaders
onLoad: | load-later:
dofile 'game' - game_textmessage
dofile 'thing' - game_console
@onLoad: |
importStyle 'styles/items.otui'
importStyle 'styles/creatures.otui'
importStyle 'styles/miniwindow.otui'
importStyle 'styles/countwindow.otui'
dofile 'const'
dofile 'widgets/uigamemap'
dofile 'gameinterface'
dofile 'creature' dofile 'creature'
dofile 'player' GameInterface.init()
dofile 'map'
@onUnload: |
GameInterface.terminate()

@ -0,0 +1,295 @@
GameInterface = {}
local WALK_AUTO_REPEAT_DELAY = 90
local gameRootPanel
local gameMapPanel
local gameRightPanel
local gameLeftPanel
local gameBottomPanel
local logoutButton
function GameInterface.init()
connect(g_game, { onGameStart = GameInterface.show }, true)
connect(g_game, { onGameEnd = GameInterface.hide }, true)
gameRootPanel = displayUI('gameinterface.otui')
gameRootPanel:hide()
gameRootPanel:lower()
gameMapPanel = gameRootPanel:getChildById('gameMapPanel')
gameRightPanel = gameRootPanel:getChildById('gameRightPanel')
gameLeftPanel = gameRootPanel:getChildById('gameLeftPanel')
gameBottomPanel = gameRootPanel:getChildById('gameBottomPanel')
logoutButton = TopMenu.addRightButton('logoutButton', 'Logout', 'images/logout.png', GameInterface.tryLogout)
logoutButton:hide()
Keyboard.bindKeyPress('Up', function() g_game.walk(North) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Right', function() g_game.walk(East) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Down', function() g_game.walk(South) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Left', function() g_game.walk(West) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Numpad8', function() g_game.walk(North) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Numpad9', function() g_game.walk(NorthEast) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Numpad6', function() g_game.walk(East) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Numpad3', function() g_game.walk(SouthEast) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Numpad2', function() g_game.walk(South) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Numpad1', function() g_game.walk(SouthWest) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Numpad4', function() g_game.walk(West) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Numpad7', function() g_game.walk(NorthWest) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Ctrl+Up', function() g_game.turn(North) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Ctrl+Right', function() g_game.turn(East) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Ctrl+Down', function() g_game.turn(South) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Ctrl+Left', function() g_game.turn(West) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Ctrl+Numpad8', function() g_game.turn(North) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Ctrl+Numpad6', function() g_game.turn(East) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Ctrl+Numpad2', function() g_game.turn(South) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Ctrl+Numpad4', function() g_game.turn(West) end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
Keyboard.bindKeyPress('Escape', function() g_game.cancelAttackAndFollow() end, gameRootPanel, WALK_AUTO_REPEAT_DELAY)
if g_game.isOnline() then
GameInterface.show()
end
end
function GameInterface.terminate()
disconnect(g_game, { onGameStart = GameInterface.show })
disconnect(g_game, { onGameEnd = GameInterface.hide })
logoutButton:destroy()
logoutButton = nil
gameRootPanel:destroy()
gameRootPanel = nil
gameMapPanel = nil
gameRightPanel = nil
gameLeftPanel = nil
gameBottomPanel = nil
GameInterface = nil
end
function GameInterface.show()
g_app.onClose = GameInterface.tryExit
logoutButton:show()
Background.hide()
gameRootPanel:show()
gameRootPanel:focus()
gameMapPanel:followCreature(g_game.getLocalPlayer())
end
function GameInterface.hide()
gameRootPanel:hide()
logoutButton:hide()
Background.show()
g_app.onClose = nil
end
function GameInterface.tryExit()
if g_game.isOnline() then
g_game.forceLogout()
scheduleEvent(exit, 10)
end
end
function GameInterface.tryLogout()
if g_game.isOnline() then
g_game.safeLogout()
return true
end
end
function GameInterface.createThingMenu(menuPosition, lookThing, useThing, creatureThing)
local menu = createWidget('PopupMenu')
if lookThing then
menu:addOption('Look', function() g_game.look(lookThing) end)
end
if useThing then
if useThing:isContainer() then
if useThing:isInsideContainer() then
menu:addOption('Open', function() g_game.open(useThing, useThing:getContainerId()) end)
menu:addOption('Open in new window', function() g_game.open(useThing, Containers.getFreeContainerId()) end)
else
menu:addOption('Open', function() g_game.open(useThing, Containers.getFreeContainerId()) end)
end
else
if useThing:isMultiUse() then
menu:addOption('Use with ...', function() g_game.startUseWith(useThing) end)
else
menu:addOption('Use', function() g_game.use(useThing) end)
end
end
if useThing:isRotateable() then
menu:addOption('Rotate', function() g_game.rotate(useThing) end)
end
end
if lookThing and not lookThing:asCreature() and not lookThing:isNotMoveable() and lookThing:isPickupable() then
menu:addSeparator()
menu:addOption('Trade with ...', function() print('trade with') end)
end
-- check for move up
if creatureThing then
menu:addSeparator()
if creatureThing:asLocalPlayer() then
menu:addOption('Set Outfit', function() g_game.requestOutfit() end)
if creatureThing:isPartyMember() --[[and not fighting]] then
if creatureThing:isPartyLeader() then
if creatureThing:isPartySharedExperienceActive() then
menu:addOption('Disable Shared Experience', function() g_game.partyShareExperience(false) end)
else
menu:addOption('Enable Shared Experience', function() g_game.partyShareExperience(true) end)
end
end
menu:addOption('Leave Party', function() g_game.partyLeave() end)
end
else
local localPlayer = g_game.getLocalPlayer()
if localPlayer then
if g_game.getAttackingCreature() ~= creatureThing then
menu:addOption('Attack', function() g_game.attack(creatureThing) end)
else
menu:addOption('Stop Attack', function() g_game.cancelAttack() end)
end
if g_game.getFollowingCreature() ~= creatureThing then
menu:addOption('Follow', function() g_game.follow(creatureThing) end)
else
menu:addOption('Stop Follow', function() g_game.cancelFollow() end)
end
if creatureThing:asPlayer() then
menu:addSeparator()
menu:addOption('Message to ' .. creatureThing:getName(), function() print('message') end)
menu:addOption('Add to VIP list', function() g_game.addVip(creatureThing:getName()) end)
local localPlayerShield = localPlayer:asCreature():getShield()
local creatureShield = creatureThing:getShield()
if localPlayerShield == ShieldNone or localPlayerShield == ShieldWhiteBlue then
if creatureShield == ShieldWhiteYellow then
menu:addOption('Join ' .. creatureThing:getName() .. '\'s Party', function() g_game.partyJoin(creatureThing:getId()) end)
else
menu:addOption('Invite to Party', function() g_game.partyInvite(creatureThing:getId()) end)
end
elseif localPlayerShield == ShieldWhiteYellow then
if creatureShield == ShieldWhiteBlue then
menu:addOption('Revoke ' .. creatureThing:getName() .. '\'s Invitation', function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
end
elseif localPlayerShield == ShieldYellow or localPlayerShield == ShieldYellowSharedExp or localPlayerShield == ShieldYellowNoSharedExpBlink or localPlayerShield == ShieldYellowNoSharedExp then
if creatureShield == ShieldWhiteBlue then
menu:addOption('Revoke ' .. creatureThing:getName() .. '\'s Invitation', function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
elseif creatureShield == ShieldBlue or creatureShield == ShieldBlueSharedExp or creatureShield == ShieldBlueNoSharedExpBlink or creatureShield == ShieldBlueNoSharedExp then
menu:addOption('Pass Leadership to ' .. creatureThing:getName(), function() g_game.partyPassLeadership(creatureThing:getId()) end)
else
menu:addOption('Invite to Party', function() g_game.partyInvite(creatureThing:getId()) end)
end
end
end
end
end
menu:addSeparator()
menu:addOption('Copy Name', function() g_window.setClipboardText(creatureThing:getName()) end)
end
menu:display(menuPosition)
end
function GameInterface.processMouseAction(menuPosition, mouseButton, autoWalk, lookThing, useThing, creatureThing, multiUseThing)
local keyboardModifiers = g_window.getKeyboardModifiers()
if autoWalk and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseLeftButton then
-- todo auto walk
return true
end
if not Options.classicControl then
if keyboardModifiers == KeyboardNoModifier and mouseButton == MouseRightButton then
GameInterface.createThingMenu(menuPosition, lookThing, useThing, creatureThing)
return true
elseif lookThing and keyboardModifiers == KeyboardShiftModifier and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
g_game.look(lookThing)
return true
elseif useThing and keyboardModifiers == KeyboardCtrlModifier and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
if useThing:isContainer() then
if useThing:isInsideContainer() then
g_game.open(useThing, useThing:getContainerId())
return true
else
g_game.open(useThing, Containers.getFreeContainerId())
return true
end
elseif useThing:isMultiUse() then
g_game.startUseWith(useThing)
return true
else
g_game.use(useThing)
return true
end
return true
elseif creatureThing and keyboardModifiers == KeyboardAltModifier and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
g_game.attack(creatureThing)
return true
end
else
if multiUseThing and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseRightButton then
if multiUseThing:asCreature() then
g_game.attack(multiUseThing:asCreature())
return true
elseif multiUseThing:isContainer() then
if multiUseThing:isInsideContainer() then
g_game.open(multiUseThing, multiUseThing:getContainerId())
return true
else
g_game.open(multiUseThing, Containers.getFreeContainerId())
return true
end
elseif multiUseThing:isMultiUse() then
g_game.startUseWith(multiUseThing)
return true
else
g_game.use(multiUseThing)
end
return true
elseif lookThing and keyboardModifiers == KeyboardShiftModifier and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
g_game.look(lookThing)
return true
elseif useThing and keyboardModifiers == KeyboardCtrlModifier and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
GameInterface.createThingMenu(menuPosition, lookThing, useThing, creatureThing)
return true
elseif creatureThing and keyboardModifiers == KeyboardAltModifier and (mouseButton == MouseLeftButton or mouseButton == MouseRightButton) then
g_game.attack(creatureThing)
return true
end
end
return false
end
function GameInterface.getRootPanel()
return gameRootPanel
end
function GameInterface.getMapPanel()
return gameMapPanel
end
function GameInterface.getRightPanel()
return gameRightPanel
end
function GameInterface.getLeftPanel()
return gameLeftPanel
end
function GameInterface.getBottomPanel()
return gameBottomPanel
end

@ -0,0 +1,53 @@
GameSidePanel < Panel
image-source: images/sidepanel.png
image-border: 4
GameBottomPanel < Panel
image-source: images/bottompanel.png
image-border: 4
GameMapPanel < UIGameMap
padding: 4
image-source: images/mappanel.png
image-border: 4
UIWidget
id: gameRootPanel
anchors.fill: parent
anchors.top: topMenu.bottom
GameSidePanel
id: gameRightPanel
width: 190
layout: verticalBox
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
GameSidePanel
id: gameLeftPanel
width: 190
layout: verticalBox
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
GameBottomPanel
id: gameBottomPanel
height: 170
anchors.left: gameLeftPanel.right
anchors.right: gameRightPanel.left
anchors.bottom: parent.bottom
GameMapPanel
id: gameMapPanel
anchors.left: gameLeftPanel.right
anchors.right: gameRightPanel.left
anchors.top: parent.top
anchors.bottom: gameBottomPanel.top
focusable: false
UIWidget
id: mouseGrabber
focusable: false
visible: false

Before

Width:  |  Height:  |  Size: 385 B

After

Width:  |  Height:  |  Size: 385 B

Before

Width:  |  Height:  |  Size: 381 B

After

Width:  |  Height:  |  Size: 381 B

Before

Width:  |  Height:  |  Size: 386 B

After

Width:  |  Height:  |  Size: 386 B

Before

Width:  |  Height:  |  Size: 352 B

After

Width:  |  Height:  |  Size: 352 B

Before

Width:  |  Height:  |  Size: 522 B

After

Width:  |  Height:  |  Size: 522 B

Before

Width:  |  Height:  |  Size: 516 B

After

Width:  |  Height:  |  Size: 516 B

Before

Width:  |  Height:  |  Size: 404 B

After

Width:  |  Height:  |  Size: 404 B

Before

Width:  |  Height:  |  Size: 377 B

After

Width:  |  Height:  |  Size: 377 B

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 512 B

Before

Width:  |  Height:  |  Size: 494 B

After

Width:  |  Height:  |  Size: 494 B

Before

Width:  |  Height:  |  Size: 407 B

After

Width:  |  Height:  |  Size: 407 B

Before

Width:  |  Height:  |  Size: 482 B

After

Width:  |  Height:  |  Size: 482 B

Before

Width:  |  Height:  |  Size: 438 B

After

Width:  |  Height:  |  Size: 438 B

Before

Width:  |  Height:  |  Size: 445 B

After

Width:  |  Height:  |  Size: 445 B

Before

Width:  |  Height:  |  Size: 421 B

After

Width:  |  Height:  |  Size: 421 B

Before

Width:  |  Height:  |  Size: 437 B

After

Width:  |  Height:  |  Size: 437 B

Before

Width:  |  Height:  |  Size: 437 B

After

Width:  |  Height:  |  Size: 437 B

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Before

Width:  |  Height:  |  Size: 385 B

After

Width:  |  Height:  |  Size: 385 B

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

@ -0,0 +1,41 @@
CountWindow < MainWindow
id: countWindow
text: Move Staackable Item
size: 196 112
@onEscape: self:destroy()
Label
text: Amount:
width: 64
anchors.left: parent.left
anchors.top: parent.top
margin-top: 2
SpinBox
id: spinbox
anchors.left: prev.right
anchors.right: parent.right
anchors.top: parent.top
HorizontalSeparator
id: separator
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: next.top
margin-bottom: 10
Button
id: buttonOk
text: Ok
width: 64
anchors.right: next.left
anchors.bottom: parent.bottom
margin-right: 10
Button
id: buttonCancel
text: Cancel
width: 64
anchors.right: parent.right
anchors.bottom: parent.bottom
@onClick: self:getParent():destroy()

@ -0,0 +1,20 @@
MiniWindow < UIMiniWindow
font: verdana-11px-antialised
//icon: /core_styles/icons/login.png
icon-rect: 4 4 16 16
width: 192
height: 200
text-offset: 26 5
text-align: topLeft
margin-top: 2
margin-left: 6
margin-right: 6
move-policy: free updated
image-source: /core_styles/styles/images/mini_window.png
image-border: 4
image-border-top: 23
padding: 25 8 2 8
$on:
height: 24
image-border-bottom: 1

@ -0,0 +1,64 @@
UIGameMap = extends(UIMap)
function UIGameMap.create()
local gameMap = UIGameMap.internalCreate()
return gameMap
end
function UIGameMap:onDragEnter(mousePos)
local tile = self:getTile(mousePos)
if not tile then return false end
local thing = tile:getTopMoveThing()
if not thing then return false end
self.parsed = false
self.currentDragThing = thing
Mouse.setTargetCursor()
return true
end
function UIGameMap:onDragLeave(droppedWidget, mousePos)
if not self.parsed then
self.currentDragThing = nil
end
Mouse.restoreCursor()
return true
end
function UIGameMap:onDrop(widget, mousePos)
if not widget or not widget.currentDragThing then return false end
local tile = self:getTile(mousePos)
if not tile then return false end
local count = widget.currentDragThing:getCount()
if widget.currentDragThing:isStackable() and count > 1 then
widget.parsed = true
local moveWindow = createWidget('CountWindow', rootWidget)
local spinbox = moveWindow:getChildById('spinbox')
spinbox:setMaximum(count)
spinbox:setMinimum(1)
spinbox:setCurrentIndex(count)
local okButton = moveWindow:getChildById('buttonOk')
okButton.onClick = function()
g_game.move(widget.currentDragThing, tile:getPosition(), spinbox:getCurrentIndex())
okButton:getParent():destroy()
widget.currentDragThing = nil
end
moveWindow.onEnter = okButton.onClick
else
g_game.move(widget.currentDragThing, tile:getPosition(), 1)
end
return true
end
function UIGameMap:onMouseRelease(mousePosition, mouseButton)
local tile = self:getTile(mousePosition)
if tile and GameInterface.processMouseAction(mousePosition, mouseButton, nil, tile:getTopLookThing(), tile:getTopUseThing(), tile:getTopCreature(), tile:getTopMultiUseThing()) then return true end
return false
end

@ -33,14 +33,17 @@ function UIItem:onDrop(widget, mousePos)
local count = widget.currentDragThing:getCount() local count = widget.currentDragThing:getCount()
if widget.currentDragThing:isStackable() and count > 1 then if widget.currentDragThing:isStackable() and count > 1 then
widget.parsed = true widget.parsed = true
local moveWindow = displayUI('/game/movewindow.otui') local countWindow = createWidget('CountWindow', rootWidget)
local spinbox = moveWindow:getChildById('spinbox') local spinbox = moveWindow:getChildById('spinbox')
spinbox:setMaximum(count) spinbox:setMaximum(count)
spinbox:setMinimum(1) spinbox:setMinimum(1)
spinbox:setCurrentIndex(count) spinbox:setCurrentIndex(count)
local okButton = moveWindow:getChildById('buttonOk') local okButton = moveWindow:getChildById('buttonOk')
okButton.onClick = function() g_game.move(widget.currentDragThing, pos, spinbox:getCurrentIndex()) okButton:getParent():destroy() widget.currentDragThing = nil end okButton.onClick = function()
g_game.move(widget.currentDragThing, pos, spinbox:getCurrentIndex()) okButton:getParent():destroy()
widget.currentDragThing = nil
end
moveWindow.onEnter = okButton.onClick moveWindow.onEnter = okButton.onClick
else else
g_game.move(widget.currentDragThing, pos, 1) g_game.move(widget.currentDragThing, pos, 1)

@ -53,4 +53,4 @@ MainWindow
width: 64 width: 64
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
@onClick: self:getParent():destroy() @onClick: self:getParent():destroy()

@ -76,9 +76,83 @@ function applyMessagePrefixies(name, level, message)
return message return message
end end
-- hooked events
local function onCreatureSpeak(name, level, speaktype, message, channelId, creaturePos)
speaktype = SpeakTypes[speaktype]
if speaktype.hideInConsole then return end
message = applyMessagePrefixies(name, level, message)
if speaktype.private then
Console.addPrivateText(message, speaktype, name, false)
else
local channel = channels[channelId]
if channel then
Console.addText(message, speaktype, channel)
else
-- server sent a message on a channel that we are not aware of, must leave it
g_game.leaveChannel(channelId)
end
end
end
local function onOpenChannel(channelId, channelName)
Console.addChannel(channelName, channelId)
end
local function onOpenPrivateChannel(receiver)
local privateTab = Console.getTab(receiver)
if privateTab == nil then
Console.addTab(receiver, true)
end
end
local function doChannelListSubmit(channelsWindow)
local channelListPanel = channelsWindow:getChildById('channelList')
local openPrivateChannelWith = channelsWindow:getChildById('openPrivateChannelWith'):getText()
if openPrivateChannelWith ~= '' then
g_game.openPrivateChannel(openPrivateChannelWith)
else
local selectedChannelLabel = channelListPanel:getFocusedChild()
if not selectedChannelLabel then return end
g_game.joinChannel(selectedChannelLabel.channelId)
end
channelsWindow:destroy()
end
local function onChannelList(channelList)
local channelsWindow = displayUI('channelswindow.otui')
local channelListPanel = channelsWindow:getChildById('channelList')
channelsWindow.onEnter = function() doChannelListSubmit(channelsWindow) end
Keyboard.bindKeyPress('Down', function() channelListPanel:focusNextChild(KeyboardFocusReason) end, channelsWindow)
Keyboard.bindKeyPress('Up', function() channelListPanel:focusPreviousChild(KeyboardFocusReason) end, channelsWindow)
for k,v in pairs(channelList) do
local channelId = v[1]
local channelName = v[2]
if channelId ~= 0 and #channelName > 0 then
local label = createWidget('ChannelListLabel', channelListPanel)
label.channelId = channelId
label:setText(channelName)
label:setPhantom(false)
label.onDoubleClick = function() doChannelListSubmit(channelsWindow) end
end
end
end
-- public functions -- public functions
function Console.create() function Console.init()
consolePanel = displayUI('console.otui', g_game.gameBottomPanel) connect(g_game, { onCreatureSpeak = onCreatureSpeak,
onChannelList = onChannelList,
onOpenChannel = onOpenChannel,
onOpenPrivateChannel = onOpenPrivateChannel})
consolePanel = displayUI('console.otui', GameInterface.getBottomPanel())
consoleLineEdit = consolePanel:getChildById('consoleLineEdit') consoleLineEdit = consolePanel:getChildById('consoleLineEdit')
consoleBuffer = consolePanel:getChildById('consoleBuffer') consoleBuffer = consolePanel:getChildById('consoleBuffer')
consoleTabBar = consolePanel:getChildById('consoleTabBar') consoleTabBar = consolePanel:getChildById('consoleTabBar')
@ -88,25 +162,42 @@ function Console.create()
Console.addChannel('Default', 0) Console.addChannel('Default', 0)
Console.addTab('Server Log', false) Console.addTab('Server Log', false)
Keyboard.bindKeyDown('Shift+Up', function() navigateMessageHistory(1) end, consolePanel) Keyboard.bindKeyPress('Shift+Up', function() navigateMessageHistory(1) end, consolePanel)
Keyboard.bindKeyDown('Shift+Down', function() navigateMessageHistory(-1) end, consolePanel) Keyboard.bindKeyPress('Shift+Down', function() navigateMessageHistory(-1) end, consolePanel)
Keyboard.bindKeyDown('Tab', function() consoleTabBar:selectNextTab() end, consolePanel) Keyboard.bindKeyPress('Tab', function() consoleTabBar:selectNextTab() end, consolePanel)
Keyboard.bindKeyDown('Shift+Tab', function() consoleTabBar:selectPrevTab() end, consolePanel) Keyboard.bindKeyPress('Shift+Tab', function() consoleTabBar:selectPrevTab() end, consolePanel)
Keyboard.bindKeyDown('Enter', Console.sendCurrentMessage, consolePanel) Keyboard.bindKeyDown('Enter', Console.sendCurrentMessage, consolePanel)
-- apply buttom functions after loaded -- apply buttom functions after loaded
connect(consolePanel:getChildById('nextChannelButton'), { onClick = function() consoleTabBar:selectNextTab() end } ) consolePanel:getChildById('nextChannelButton').onClick = function() consoleTabBar:selectNextTab() end
connect(consolePanel:getChildById('prevChannelButton'), { onClick = function() consoleTabBar:selectPrevTab() end } ) consolePanel:getChildById('prevChannelButton').onClick = function() consoleTabBar:selectPrevTab() end
connect(consoleTabBar, { onTabChange = Console.onTabChange }) consoleTabBar.onTabChange = Console.onTabChange
-- tibia like hotkeys -- tibia like hotkeys
Keyboard.bindKeyDown('Ctrl+O', g_game.requestChannels) Keyboard.bindKeyDown('Ctrl+O', g_game.requestChannels)
Keyboard.bindKeyDown('Ctrl+E', Console.removeCurrentTab) Keyboard.bindKeyDown('Ctrl+E', Console.removeCurrentTab)
end end
function Console.destroy() function Console.terminate()
disconnect(g_game, { onCreatureSpeak = onCreatureSpeak,
onChannelList = onChannelList,
onOpenChannel = onOpenChannel,
onOpenPrivateChannel = onOpenPrivateChannel })
for channelid, channelname in ipairs(channels) do
g_game.leaveChannel(channelid)
end
Keyboard.unbindKeyDown('Ctrl+O')
Keyboard.unbindKeyDown('Ctrl+E')
consolePanel:destroy() consolePanel:destroy()
consolePanel = nil consolePanel = nil
consoleLineEdit = nil
consoleBuffer = nil
consoleTabBar = nil
Console = nil
end end
function Console.setLineEditText(text) function Console.setLineEditText(text)
@ -117,7 +208,7 @@ function Console.addTab(name, focus)
local tab = consoleTabBar:addTab(name) local tab = consoleTabBar:addTab(name)
if focus then if focus then
consoleTabBar:selectTab(tab) consoleTabBar:selectTab(tab)
else elseif name ~= 'Server Log' then
consoleTabBar:blinkTab(tab) consoleTabBar:blinkTab(tab)
end end
return tab return tab
@ -299,75 +390,3 @@ function Console.sayModeChange(sayMode)
buttom:setIcon(SayModes[sayMode].icon) buttom:setIcon(SayModes[sayMode].icon)
buttom.sayMode = sayMode buttom.sayMode = sayMode
end end
-- hooked events
local function onCreatureSpeak(name, level, speaktype, message, channelId, creaturePos)
speaktype = SpeakTypes[speaktype]
if speaktype.hideInConsole then return end
message = applyMessagePrefixies(name, level, message)
if speaktype.private then
Console.addPrivateText(message, speaktype, name, false)
else
local channel = channels[channelId]
if channel then
Console.addText(message, speaktype, channel)
else
-- server sent a message on a channel that we are not aware of, must leave it
g_game.leaveChannel(channelId)
end
end
end
local function onOpenChannel(channelId, channelName)
Console.addChannel(channelName, channelId)
end
local function onOpenPrivateChannel(receiver)
local privateTab = Console.getTab(receiver)
if privateTab == nil then
Console.addTab(receiver, true)
end
end
local function doChannelListSubmit(channelsWindow)
local channelListPanel = channelsWindow:getChildById('channelList')
local openPrivateChannelWith = channelsWindow:getChildById('openPrivateChannelWith'):getText()
if openPrivateChannelWith ~= '' then
g_game.openPrivateChannel(openPrivateChannelWith)
else
local selectedChannelLabel = channelListPanel:getFocusedChild()
if not selectedChannelLabel then return end
g_game.joinChannel(selectedChannelLabel.channelId)
end
channelsWindow:destroy()
end
local function onChannelList(channelList)
local channelsWindow = displayUI('channelswindow.otui')
local channelListPanel = channelsWindow:getChildById('channelList')
connect(channelsWindow, { onEnter = function () doChannelListSubmit(channelsWindow) end } )
for k,v in pairs(channelList) do
local channelId = v[1]
local channelName = v[2]
if channelId ~= 0 and #channelName > 0 then
local label = createWidget('ChannelListLabel', channelListPanel)
label.channelId = channelId
label:setText(channelName)
label:setPhantom(false)
connect(label, { onDoubleClick = function () doChannelListSubmit(channelsWindow) end } )
end
end
end
connect(g_game, { onGameStart = Console.create,
onGameEnd = Console.destroy,
onCreatureSpeak = onCreatureSpeak,
onChannelList = onChannelList,
onOpenChannel = onOpenChannel,
onOpenPrivateChannel = onOpenPrivateChannel})

@ -3,5 +3,14 @@ Module
description: Manage chat window description: Manage chat window
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
onLoad: | reloadable: true
dependecies:
- game
@onLoad: |
dofile 'console' dofile 'console'
Console.init()
@onUnload: |
Console.terminate()

@ -14,7 +14,7 @@ Panel
id: consolePanel id: consolePanel
anchors.fill: parent anchors.fill: parent
ConsoleButton TabButton
id: prevChannelButton id: prevChannelButton
icon: /core_styles/icons/leftarrow.png icon: /core_styles/icons/leftarrow.png
anchors.left: parent.left anchors.left: parent.left
@ -30,7 +30,7 @@ Panel
anchors.right: next.left anchors.right: next.left
margin-left: 5 margin-left: 5
ConsoleButton TabButton
id: nextChannelButton id: nextChannelButton
icon: /core_styles/icons/rightarrow.png icon: /core_styles/icons/rightarrow.png
anchors.right: next.left anchors.right: next.left
@ -38,7 +38,7 @@ Panel
margin-right: 5 margin-right: 5
margin-top: 6 margin-top: 6
ConsoleButton TabButton
id: closeChannelButton id: closeChannelButton
tooltip: Close this channel (Ctrl+E) tooltip: Close this channel (Ctrl+E)
icon: /core_styles/icons/closechannel.png icon: /core_styles/icons/closechannel.png
@ -49,7 +49,7 @@ Panel
margin-top: 6 margin-top: 6
@onClick: Console.removeCurrentTab() @onClick: Console.removeCurrentTab()
ConsoleButton TabButton
id: channelsButton id: channelsButton
tooltip: Open new channel (Ctrl+O) tooltip: Open new channel (Ctrl+O)
icon: /core_styles/icons/channels.png icon: /core_styles/icons/channels.png
@ -71,7 +71,7 @@ Panel
margin-top: 4 margin-top: 4
focusable: false focusable: false
ConsoleButton TabButton
id: sayModeButton id: sayModeButton
icon: /core_styles/icons/say.png icon: /core_styles/icons/say.png
tooltip: Adjust volume tooltip: Adjust volume
@ -91,5 +91,4 @@ Panel
margin-right: 6 margin-right: 6
margin-left: 6 margin-left: 6
margin-bottom: 6 margin-bottom: 6
always-active: true shift-navigation: true
focusable: false

@ -17,7 +17,7 @@ local MessageTypes = {
} }
local centerTextMessagePanel local centerTextMessagePanel
local centerLabel local bottomStatusLabel
-- private functions -- private functions
local function displayMessage(msgtype, msg, time) local function displayMessage(msgtype, msg, time)
@ -30,17 +30,17 @@ local function displayMessage(msgtype, msg, time)
end end
if msgtype.labelId then if msgtype.labelId then
local label = g_game.gameMapPanel:recursiveGetChildById(msgtype.labelId) local label = GameInterface.getMapPanel():recursiveGetChildById(msgtype.labelId)
label:setVisible(true)
label:setText(msg) label:setText(msg)
label:setColor(msgtype.color) label:setColor(msgtype.color)
label:resizeToText()
if msgtype.wrap then if msgtype.wrap then
label:setWidth(label:getParent():getWidth()) label:setWidth(label:getParent():getWidth())
label:wrapText() label:wrapText()
label:setHeight(label:getTextSize().height) label:setHeight(label:getTextSize().height)
else
label:resizeToText()
end end
if not time then if not time then
@ -49,6 +49,7 @@ local function displayMessage(msgtype, msg, time)
time = time * 1000 time = time * 1000
end end
removeEvent(label.hideEvent) removeEvent(label.hideEvent)
addEvent(function() label:setVisible(true) end)
label.hideEvent = scheduleEvent(function() label:setVisible(false) end, time) label.hideEvent = scheduleEvent(function() label:setVisible(false) end, time)
end end
end end
@ -64,10 +65,14 @@ local function createTextMessageLabel(id, parent)
end end
-- public functions -- public functions
function TextMessage.init()
connect(g_game, { onDeath = TextMessage.displayDeadMessage,
onTextMessage = TextMessage.display,
onGameStart = TextMessage.clearMessages })
function TextMessage.create() centerTextMessagePanel = createWidget('Panel', GameInterface.getMapPanel())
centerTextMessagePanel = createWidget('Panel', g_game.gameMapPanel)
centerTextMessagePanel:setId('centerTextMessagePanel') centerTextMessagePanel:setId('centerTextMessagePanel')
local layout = UIVerticalLayout.create(centerTextMessagePanel) local layout = UIVerticalLayout.create(centerTextMessagePanel)
layout:setFitChildren(true) layout:setFitChildren(true)
centerTextMessagePanel:setLayout(layout) centerTextMessagePanel:setLayout(layout)
@ -78,13 +83,31 @@ function TextMessage.create()
createTextMessageLabel('centerAdvance', centerTextMessagePanel) createTextMessageLabel('centerAdvance', centerTextMessagePanel)
createTextMessageLabel('centerInfo', centerTextMessagePanel) createTextMessageLabel('centerInfo', centerTextMessagePanel)
bottomStatusLabel = createTextMessageLabel('bottomStatus', g_game.gameMapPanel) bottomStatusLabel = createTextMessageLabel('bottomStatus', GameInterface.getMapPanel())
bottomStatusLabel:setHeight(16) bottomStatusLabel:setHeight(16)
bottomStatusLabel:addAnchor(AnchorBottom, 'parent', AnchorBottom) bottomStatusLabel:addAnchor(AnchorBottom, 'parent', AnchorBottom)
bottomStatusLabel:addAnchor(AnchorLeft, 'parent', AnchorLeft) bottomStatusLabel:addAnchor(AnchorLeft, 'parent', AnchorLeft)
bottomStatusLabel:addAnchor(AnchorRight, 'parent', AnchorRight) bottomStatusLabel:addAnchor(AnchorRight, 'parent', AnchorRight)
end end
function TextMessage.terminate()
disconnect(g_game, { onDeath = TextMessage.displayDeadMessage,
onTextMessage = TextMessage.display,
onGameStart = TextMessage.clearMessages })
centerTextMessagePanel:destroy()
centerTextMessagePanel = nil
bottomStatusLabel:destroy()
bottomStatusLabel = nil
TextMessage = nil
end
function TextMessage.clearMessages()
GameInterface.getMapPanel():recursiveGetChildById('centerWarning'):hide()
GameInterface.getMapPanel():recursiveGetChildById('centerAdvance'):hide()
GameInterface.getMapPanel():recursiveGetChildById('centerInfo'):hide()
GameInterface.getMapPanel():recursiveGetChildById('bottomStatus'):hide()
end
function TextMessage.displayStatus(msg, time) function TextMessage.displayStatus(msg, time)
displayMessage(MessageTypes.warning, msg) displayMessage(MessageTypes.warning, msg)
end end
@ -100,18 +123,8 @@ function TextMessage.display(msgtypedesc, msg)
end end
end end
-- hooked events function TextMessage.displayDeadMessage()
local function onGameDeath() local advanceLabel = GameInterface.getMapPanel():recursiveGetChildById('centerAdvance')
local advanceLabel = g_game.gameMapPanel:recursiveGetChildById('centerAdvance')
if advanceLabel:isVisible() then return end if advanceLabel:isVisible() then return end
TextMessage.displayEventAdvance('You are dead.') TextMessage.displayEventAdvance('You are dead.')
end end
local function onGameTextMessage(msgtypedesc, msg)
TextMessage.display(msgtypedesc, msg)
end
connect(g_game, { onGameStart = TextMessage.create,
onGameEnd = TextMessage.destroy,
onDeath = onGameDeath,
onTextMessage = onGameTextMessage })

@ -3,5 +3,14 @@ Module
description: Manage game text messages description: Manage game text messages
author: OTClient team author: OTClient team
website: https://github.com/edubart/otclient website: https://github.com/edubart/otclient
onLoad: | reloadable: true
dependecies:
- game
@onLoad: |
dofile 'textmessage' dofile 'textmessage'
TextMessage.init()
@onUnload: |
TextMessage.terminate()

@ -0,0 +1,17 @@
Module
name: game
description: Create the game interface, where the ingame stuff starts
author: OTClient team
website: https://github.com/edubart/otclient
reloadable: true
dependencies:
- game_tibiafiles
//- game_shaders
onLoad: |
dofile 'game'
dofile 'thing'
dofile 'creature'
dofile 'player'
dofile 'map'

@ -1,4 +1,4 @@
MainWindow CountWindow < MainWindow
text: Move Item text: Move Item
size: 196 112 size: 196 112
@onEscape: self:destroy() @onEscape: self:destroy()

@ -455,4 +455,4 @@ function HotkeysManager.hotkeyCapture(widget, keyCode, keyboardModifiers)
hotkeysWindow:getChildById('assignWindow'):getChildById('addButton'):enable() hotkeysWindow:getChildById('assignWindow'):getChildById('addButton'):enable()
return true return true
end end

@ -156,4 +156,4 @@ MainWindow
width: 64 width: 64
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
@onClick: HotkeysManager.hide() @onClick: HotkeysManager.hide()

@ -1,14 +1,14 @@
GameSidePanel < UIMiniWindowContainer GameSidePanel < UIMiniWindowContainer
image-source: /core_styles/styles/images/sidepanel.png image-source: images/sidepanel.png
image-border: 4 image-border: 4
GameBottomPanel < Panel GameBottomPanel < Panel
image-source: /core_styles/styles/images/bottompanel.png image-source: images/bottompanel.png
image-border: 4 image-border: 4
GameMapPanel < UIMap GameMapPanel < UIMap
padding: 4 padding: 4
image-source: /core_styles/styles/images/mappanel.png image-source: images/mappanel.png
image-border: 4 image-border: 4
UIGame UIGame
@ -16,7 +16,7 @@ UIGame
anchors.fill: parent anchors.fill: parent
anchors.top: topMenu.bottom anchors.top: topMenu.bottom
InterfacePanel GameSidePanel
id: gameRightPanel id: gameRightPanel
width: 190 width: 190
layout: verticalBox layout: verticalBox

@ -1,5 +1,6 @@
-- this file use loaded after everything is loaded and initialized -- this file is loaded after all modules are loaded and initialized
-- you can place any custom user code here -- you can place any custom user code here
-- you
Keyboard.bindKeyDown('F1', function() g_game.talk('exura gran') end) Keyboard.bindKeyDown('F1', function() g_game.talk('exura gran') end)
Keyboard.bindKeyDown('F2', function() g_game.talk('exori mort') end) Keyboard.bindKeyDown('F2', function() g_game.talk('exori mort') end)
@ -7,12 +8,4 @@ Keyboard.bindKeyDown('F3', function() g_game.talk('exori frigo') end)
Keyboard.bindKeyDown('F4', function() g_game.talk('exevo vis hur') end) Keyboard.bindKeyDown('F4', function() g_game.talk('exevo vis hur') end)
Keyboard.bindKeyDown('F5', function() g_game.talk('utani gran hur') end) Keyboard.bindKeyDown('F5', function() g_game.talk('utani gran hur') end)
Keyboard.bindKeyDown('F6', function() g_game.talk('exani tera') end) Keyboard.bindKeyDown('F6', function() g_game.talk('exani tera') end)
Keyboard.bindKeyDown('Ctrl+R', Client.reloadScripts)
local function reload()
dofile('otclientrc.lua')
TextMessage.displayEventAdvance('Script otclientrc.lua reloaded.')
print('Script otclient.rc lua reloaded')
end
Keyboard.bindKeyDown('Ctrl+R', reload)
rcloaded = true

@ -50,15 +50,6 @@ IF(CMAKE_COMPILER_IS_GNUCXX)
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -static-libgcc -static-libstdc++ -Wl,--as-needed") SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -static-libgcc -static-libstdc++ -Wl,--as-needed")
ENDIF(CMAKE_COMPILER_IS_GNUCXX) ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
ADD_DEFINITIONS(-DDEBUG)
ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug")
IF(CMAKE_BUILD_TYPE STREQUAL "Release")
# NDEBUG disable asserts
ADD_DEFINITIONS(-DNDEBUG)
ENDIF(CMAKE_BUILD_TYPE STREQUAL "Release")
MESSAGE(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) MESSAGE(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
IF(USE_OPENGL_ES2) IF(USE_OPENGL_ES2)
MESSAGE(STATUS "Renderer: OpenGL ES 2.0") MESSAGE(STATUS "Renderer: OpenGL ES 2.0")
@ -66,6 +57,18 @@ ELSE(USE_OPENGL_ES2)
MESSAGE(STATUS "Renderer: OpenGL") MESSAGE(STATUS "Renderer: OpenGL")
ENDIF(USE_OPENGL_ES2) ENDIF(USE_OPENGL_ES2)
IF(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
ADD_DEFINITIONS(-DDEBUG)
MESSAGE(STATUS "Debug information: ON")
ELSE()
MESSAGE(STATUS "Debug information: OFF")
ENDIF()
IF(CMAKE_BUILD_TYPE STREQUAL "Release")
# NDEBUG disable asserts
ADD_DEFINITIONS(-DNDEBUG)
ENDIF(CMAKE_BUILD_TYPE STREQUAL "Release")
IF(CRASH_HANDLER) IF(CRASH_HANDLER)
ADD_DEFINITIONS(-DCRASH_HANDLER) ADD_DEFINITIONS(-DCRASH_HANDLER)
MESSAGE(STATUS "Crash handler: ON") MESSAGE(STATUS "Crash handler: ON")

@ -219,10 +219,7 @@ void Application::poll()
void Application::close() void Application::close()
{ {
g_lua.getGlobalField("g_app", "onClose"); if(!g_lua.callGlobalField<bool>("g_app", "onClose"))
if(!g_lua.isNil())
g_lua.protectedCall();
else
exit(); exit();
} }

@ -362,6 +362,7 @@ void Application::registerLuaFunctions()
g_lua.bindClassMemberFunction<UILineEdit>("setTextHidden", &UILineEdit::setTextHidden); g_lua.bindClassMemberFunction<UILineEdit>("setTextHidden", &UILineEdit::setTextHidden);
g_lua.bindClassMemberFunction<UILineEdit>("setAlwaysActive", &UILineEdit::setAlwaysActive); g_lua.bindClassMemberFunction<UILineEdit>("setAlwaysActive", &UILineEdit::setAlwaysActive);
g_lua.bindClassMemberFunction<UILineEdit>("setValidCharacters", &UILineEdit::setValidCharacters); g_lua.bindClassMemberFunction<UILineEdit>("setValidCharacters", &UILineEdit::setValidCharacters);
g_lua.bindClassMemberFunction<UILineEdit>("setShiftNavigation", &UILineEdit::setShiftNavigation);
g_lua.bindClassMemberFunction<UILineEdit>("moveCursor", &UILineEdit::moveCursor); g_lua.bindClassMemberFunction<UILineEdit>("moveCursor", &UILineEdit::moveCursor);
g_lua.bindClassMemberFunction<UILineEdit>("appendText", &UILineEdit::appendText); g_lua.bindClassMemberFunction<UILineEdit>("appendText", &UILineEdit::appendText);
g_lua.bindClassMemberFunction<UILineEdit>("removeCharacter", &UILineEdit::removeCharacter); g_lua.bindClassMemberFunction<UILineEdit>("removeCharacter", &UILineEdit::removeCharacter);
@ -372,6 +373,7 @@ void Application::registerLuaFunctions()
g_lua.bindClassMemberFunction<UILineEdit>("isCursorEnabled", &UILineEdit::isCursorEnabled); g_lua.bindClassMemberFunction<UILineEdit>("isCursorEnabled", &UILineEdit::isCursorEnabled);
g_lua.bindClassMemberFunction<UILineEdit>("isAlwaysActive", &UILineEdit::isAlwaysActive); g_lua.bindClassMemberFunction<UILineEdit>("isAlwaysActive", &UILineEdit::isAlwaysActive);
g_lua.bindClassMemberFunction<UILineEdit>("isTextHidden", &UILineEdit::isTextHidden); g_lua.bindClassMemberFunction<UILineEdit>("isTextHidden", &UILineEdit::isTextHidden);
g_lua.bindClassMemberFunction<UILineEdit>("isShiftNavigation", &UILineEdit::isShiftNavigation);
// UIFrameCounter // UIFrameCounter
g_lua.registerClass<UIFrameCounter, UIWidget>(); g_lua.registerClass<UIFrameCounter, UIWidget>();

@ -35,6 +35,7 @@ UILineEdit::UILineEdit()
m_textHorizontalMargin = 0; m_textHorizontalMargin = 0;
m_textHidden = false; m_textHidden = false;
m_alwaysActive = false; m_alwaysActive = false;
m_shiftNavigation = false;
blinkCursor(); blinkCursor();
} }
@ -407,8 +408,8 @@ void UILineEdit::onStyleApply(const std::string& styleName, const OTMLNodePtr& s
setTextHorizontalMargin(node->value<int>()); setTextHorizontalMargin(node->value<int>());
else if(node->tag() == "always-active") else if(node->tag() == "always-active")
setAlwaysActive(node->value<bool>()); setAlwaysActive(node->value<bool>());
//else if(node->tag() == "disable-arrow-navitation") else if(node->tag() == "shift-navigation")
// setArrowNavigation(node->value<bool>()); setShiftNavigation(node->value<bool>());
} }
} }
@ -434,28 +435,46 @@ bool UILineEdit::onKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeat
if(UIWidget::onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks)) if(UIWidget::onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks))
return true; return true;
if(keyCode == Fw::KeyDelete) // erase right character if(keyboardModifiers == Fw::KeyboardNoModifier) {
removeCharacter(true); if(keyCode == Fw::KeyDelete) { // erase right character
else if(keyCode == Fw::KeyBackspace) // erase left character { removeCharacter(true);
removeCharacter(false); return true;
else if(keyCode == Fw::KeyRight) // move cursor right } else if(keyCode == Fw::KeyBackspace) { // erase left character {
moveCursor(true); removeCharacter(false);
else if(keyCode == Fw::KeyLeft) // move cursor left return true;
moveCursor(false); } else if(keyCode == Fw::KeyRight && !m_shiftNavigation) { // move cursor right
else if(keyCode == Fw::KeyHome) // move cursor to first character moveCursor(true);
setCursorPos(0); return true;
else if(keyCode == Fw::KeyEnd) // move cursor to last character } else if(keyCode == Fw::KeyLeft && !m_shiftNavigation) { // move cursor left
setCursorPos(m_text.length()); moveCursor(false);
else if(keyCode == Fw::KeyV && keyboardModifiers == Fw::KeyboardCtrlModifier) return true;
appendText(g_window.getClipboardText()); } else if(keyCode == Fw::KeyHome) { // move cursor to first character
else if(keyCode == Fw::KeyTab) { setCursorPos(0);
if(!m_alwaysActive) { return true;
} else if(keyCode == Fw::KeyEnd) { // move cursor to last character
setCursorPos(m_text.length());
return true;
} else if(keyCode == Fw::KeyTab && !m_shiftNavigation) {
if(UIWidgetPtr parent = getParent()) if(UIWidgetPtr parent = getParent())
parent->focusNextChild(Fw::KeyboardFocusReason); parent->focusNextChild(Fw::KeyboardFocusReason);
return true;
} }
} else } else if(keyboardModifiers == Fw::KeyboardCtrlModifier) {
return false; if(keyCode == Fw::KeyV) {
return true; appendText(g_window.getClipboardText());
return true;
}
} else if(keyboardModifiers == Fw::KeyboardShiftModifier) {
if(keyCode == Fw::KeyRight && m_shiftNavigation) { // move cursor right
moveCursor(true);
return true;
} else if(keyCode == Fw::KeyLeft && m_shiftNavigation) { // move cursor left
moveCursor(false);
return true;
}
}
return false;
} }
bool UILineEdit::onKeyText(const std::string& keyText) bool UILineEdit::onKeyText(const std::string& keyText)

@ -42,6 +42,7 @@ public:
void setTextHidden(bool hidden); void setTextHidden(bool hidden);
void setAlwaysActive(bool enable); void setAlwaysActive(bool enable);
void setValidCharacters(const std::string validCharacters) { m_validCharacters = validCharacters; } void setValidCharacters(const std::string validCharacters) { m_validCharacters = validCharacters; }
void setShiftNavigation(bool enable) { m_shiftNavigation = enable; }
void moveCursor(bool right); void moveCursor(bool right);
void appendText(std::string text); void appendText(std::string text);
@ -55,6 +56,7 @@ public:
bool isCursorEnabled() { return m_cursorPos != -1; } bool isCursorEnabled() { return m_cursorPos != -1; }
bool isAlwaysActive() { return m_alwaysActive; } bool isAlwaysActive() { return m_alwaysActive; }
bool isTextHidden() { return m_textHidden; } bool isTextHidden() { return m_textHidden; }
bool isShiftNavigation() { return m_shiftNavigation; }
protected: protected:
virtual void onTextChange(const std::string& text, const std::string& oldText); virtual void onTextChange(const std::string& text, const std::string& oldText);
@ -77,6 +79,7 @@ private:
int m_textHorizontalMargin; int m_textHorizontalMargin;
bool m_textHidden; bool m_textHidden;
bool m_alwaysActive; bool m_alwaysActive;
bool m_shiftNavigation;
std::string m_validCharacters; std::string m_validCharacters;
std::vector<Rect> m_glyphsCoords; std::vector<Rect> m_glyphsCoords;

@ -319,7 +319,12 @@ UIWidgetPtr UIManager::loadUI(const std::string& file, const UIWidgetPtr& parent
return nullptr; return nullptr;
} }
} }
/*
UIWidgetPtr UIManager::loadWidgetFromStyle()
{
}
*/
UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode, const UIWidgetPtr& parent) UIWidgetPtr UIManager::loadWidgetFromOTML(const OTMLNodePtr& widgetNode, const UIWidgetPtr& parent)
{ {
OTMLNodePtr originalStyleNode = getStyle(widgetNode->tag()); OTMLNodePtr originalStyleNode = getStyle(widgetNode->tag());

@ -206,7 +206,7 @@ void UIWidget::removeChild(UIWidgetPtr child)
g_ui.onWidgetDisappear(child); g_ui.onWidgetDisappear(child);
} else } else
logError("Attempt to remove an unknown child from a UIWidget"); logError("attempt to remove an unknown child from a UIWidget");
} }
@ -637,11 +637,12 @@ void UIWidget::destroy()
// remove itself from parent // remove itself from parent
if(UIWidgetPtr parent = getParent()) { if(UIWidgetPtr parent = getParent()) {
if(parent->hasChild(asUIWidget())) assert(parent->hasChild(asUIWidget()));
parent->removeChild(asUIWidget()); parent->removeChild(asUIWidget());
} }
destroyChildren(); destroyChildren();
m_focusedChild = nullptr;
callLuaField("onDestroy"); callLuaField("onDestroy");
@ -649,12 +650,13 @@ void UIWidget::destroy()
#ifdef DEBUG #ifdef DEBUG
auto self = asUIWidget(); auto self = asUIWidget();
g_lua.collectGarbage();
if(self != g_ui.getRootWidget()) { if(self != g_ui.getRootWidget()) {
g_eventDispatcher.scheduleEvent([self] { g_eventDispatcher.scheduleEvent([self] {
g_lua.collectGarbage(); g_lua.collectGarbage();
if(self->getUseCount() != 1) if(self->getUseCount() != 1)
logWarning("widget '", self->getId(), "' destroyed but still have ", self->getUseCount()-1, " reference(s) left"); logWarning("widget '", self->getId(), "' destroyed but still have ", self->getUseCount()-1, " reference(s) left");
}, 100); }, 500);
} }
#endif #endif
} }

@ -51,6 +51,9 @@ void UIWidget::drawText(const Rect& screenCoords)
if(m_text.length() == 0 || m_color.a() == 0) if(m_text.length() == 0 || m_color.a() == 0)
return; return;
#if 0
//TODO: creating framebuffers on the fly was slowing down the render
// we should use vertex arrys instead of this method
Size boxSize = screenCoords.size(); Size boxSize = screenCoords.size();
if(boxSize != m_textCachedBoxSize || m_textMustRecache) { if(boxSize != m_textCachedBoxSize || m_textMustRecache) {
if(!m_textFramebuffer) if(!m_textFramebuffer)
@ -73,6 +76,11 @@ void UIWidget::drawText(const Rect& screenCoords)
g_painter.setColor(m_color); g_painter.setColor(m_color);
m_textFramebuffer->draw(screenCoords); m_textFramebuffer->draw(screenCoords);
#else
Rect textRect = screenCoords;
textRect.translate(m_textOffset);
m_font->renderText(m_text, textRect, m_textAlign, m_color);
#endif
} }
void UIWidget::onTextChange(const std::string& text, const std::string& oldText) void UIWidget::onTextChange(const std::string& text, const std::string& oldText)

@ -31,6 +31,7 @@ SET(otclient_SOURCES ${otclient_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/core/thingstype.cpp ${CMAKE_CURRENT_LIST_DIR}/core/thingstype.cpp
${CMAKE_CURRENT_LIST_DIR}/core/spritemanager.cpp ${CMAKE_CURRENT_LIST_DIR}/core/spritemanager.cpp
${CMAKE_CURRENT_LIST_DIR}/core/item.cpp ${CMAKE_CURRENT_LIST_DIR}/core/item.cpp
${CMAKE_CURRENT_LIST_DIR}/core/container.cpp
${CMAKE_CURRENT_LIST_DIR}/core/tile.cpp ${CMAKE_CURRENT_LIST_DIR}/core/tile.cpp
${CMAKE_CURRENT_LIST_DIR}/core/thing.cpp ${CMAKE_CURRENT_LIST_DIR}/core/thing.cpp
${CMAKE_CURRENT_LIST_DIR}/core/creature.cpp ${CMAKE_CURRENT_LIST_DIR}/core/creature.cpp

@ -0,0 +1,23 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "container.h"

@ -20,17 +20,16 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#ifndef UIGAME_H #ifndef CONTAINER_H
#define UIGAME_H #define CONTAINER_H
#include "declarations.h" #include "declarations.h"
#include <framework/ui/uiwidget.h>
class UIGame : public UIWidget class Container
{ {
protected: public:
bool onKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeatTicks); Container();
bool onKeyText(const std::string& keyText);
}; };
#endif #endif

@ -31,6 +31,7 @@ class MapView;
class Tile; class Tile;
class Thing; class Thing;
class Item; class Item;
class Container;
class Creature; class Creature;
class Monster; class Monster;
class Npc; class Npc;
@ -45,6 +46,7 @@ typedef std::shared_ptr<MapView> MapViewPtr;
typedef std::shared_ptr<Tile> TilePtr; typedef std::shared_ptr<Tile> TilePtr;
typedef std::shared_ptr<Thing> ThingPtr; typedef std::shared_ptr<Thing> ThingPtr;
typedef std::shared_ptr<Item> ItemPtr; typedef std::shared_ptr<Item> ItemPtr;
typedef std::shared_ptr<Container> ContainerPtr;
typedef std::shared_ptr<Creature> CreaturePtr; typedef std::shared_ptr<Creature> CreaturePtr;
typedef std::shared_ptr<Monster> MonsterPtr; typedef std::shared_ptr<Monster> MonsterPtr;
typedef std::shared_ptr<Npc> NpcPtr; typedef std::shared_ptr<Npc> NpcPtr;

@ -764,7 +764,6 @@ void Game::setSafeFight(bool on)
m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight); m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight);
} }
void Game::inspectNpcTrade(const ItemPtr& item) void Game::inspectNpcTrade(const ItemPtr& item)
{ {
if(!canPerformGameAction() || !item) if(!canPerformGameAction() || !item)

@ -216,6 +216,7 @@ public:
bool isAttacking() { return !!m_attackingCreature; } bool isAttacking() { return !!m_attackingCreature; }
bool isFollowing() { return !!m_followingCreature; } bool isFollowing() { return !!m_followingCreature; }
ContainerPtr getContainer(int index) { return m_containers[index]; }
CreaturePtr getAttackingCreature() { return m_attackingCreature; } CreaturePtr getAttackingCreature() { return m_attackingCreature; }
CreaturePtr getFollowingCreature() { return m_followingCreature; } CreaturePtr getFollowingCreature() { return m_followingCreature; }
int getServerBeat() { return m_serverBeat; } int getServerBeat() { return m_serverBeat; }
@ -231,6 +232,7 @@ private:
CreaturePtr m_attackingCreature; CreaturePtr m_attackingCreature;
CreaturePtr m_followingCreature; CreaturePtr m_followingCreature;
ProtocolGamePtr m_protocolGame; ProtocolGamePtr m_protocolGame;
std::map<int, ContainerPtr> m_containers;
bool m_dead; bool m_dead;
int m_serverBeat; int m_serverBeat;
Otc::FightModes m_fightMode; Otc::FightModes m_fightMode;

@ -36,12 +36,17 @@
MapView::MapView() MapView::MapView()
{ {
m_viewRange = NEAR_VIEW;
m_lockedFirstVisibleFloor = -1;
m_cachedFirstVisibleFloor = 0;
m_cachedLastVisibleFloor = 7;
m_customCameraPosition.z = 7;
Size frameBufferSize(std::min(g_graphics.getMaxTextureSize(), (int)DEFAULT_FRAMBUFFER_WIDTH), Size frameBufferSize(std::min(g_graphics.getMaxTextureSize(), (int)DEFAULT_FRAMBUFFER_WIDTH),
std::min(g_graphics.getMaxTextureSize(), (int)DEFAULT_FRAMBUFFER_HEIGHT)); std::min(g_graphics.getMaxTextureSize(), (int)DEFAULT_FRAMBUFFER_HEIGHT));
m_framebuffer = FrameBufferPtr(new FrameBuffer(frameBufferSize)); m_framebuffer = FrameBufferPtr(new FrameBuffer(frameBufferSize));
m_framebuffer->setClearColor(Fw::black); m_framebuffer->setClearColor(Fw::black);
m_lockedFirstVisibleFloor = -1;
setVisibleDimension(Size(15, 11)); setVisibleDimension(Size(15, 11));
m_shaderProgram = PainterShaderProgramPtr(new PainterShaderProgram); m_shaderProgram = PainterShaderProgramPtr(new PainterShaderProgram);
@ -374,7 +379,6 @@ void MapView::unlockFirstVisibleFloor()
void MapView::followCreature(const CreaturePtr& creature) void MapView::followCreature(const CreaturePtr& creature)
{ {
m_followingCreature = creature; m_followingCreature = creature;
m_customCameraPosition = Position();
requestVisibleTilesCacheUpdate(); requestVisibleTilesCacheUpdate();
} }

@ -93,7 +93,6 @@ public:
MapViewPtr asMapView() { return std::static_pointer_cast<MapView>(shared_from_this()); } MapViewPtr asMapView() { return std::static_pointer_cast<MapView>(shared_from_this()); }
private: private:
int m_drawFlags;
int m_lockedFirstVisibleFloor; int m_lockedFirstVisibleFloor;
int m_cachedFirstVisibleFloor; int m_cachedFirstVisibleFloor;
int m_cachedLastVisibleFloor; int m_cachedLastVisibleFloor;
@ -102,7 +101,6 @@ private:
Size m_visibleDimension; Size m_visibleDimension;
Point m_virtualCenterOffset; Point m_virtualCenterOffset;
Position m_customCameraPosition; Position m_customCameraPosition;
Position m_framebufferCenterPosition;
Boolean<true> m_mustUpdateVisibleTilesCache; Boolean<true> m_mustUpdateVisibleTilesCache;
Boolean<true> m_mustDrawVisibleTilesCache; Boolean<true> m_mustDrawVisibleTilesCache;
Boolean<true> m_mustCleanFramebuffer; Boolean<true> m_mustCleanFramebuffer;

@ -0,0 +1,23 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "player.h"

@ -31,6 +31,10 @@ public:
Player() { } Player() { }
virtual ~Player() { } virtual ~Player() { }
bool isPartyMember() { return (m_shield != 0); }
bool isPartyLeader() { return (m_shield & Otc::ShieldYellow); }
bool isPartySharedExperienceActive() { return false; }
PlayerPtr asPlayer() { return std::static_pointer_cast<Player>(shared_from_this()); } PlayerPtr asPlayer() { return std::static_pointer_cast<Player>(shared_from_this()); }
}; };

@ -26,6 +26,7 @@
#include <framework/graphics/graphics.h> #include <framework/graphics/graphics.h>
#include "map.h" #include "map.h"
#include "tile.h" #include "tile.h"
#include "game.h"
Thing::Thing() Thing::Thing()
{ {
@ -53,6 +54,13 @@ const TilePtr& Thing::getTile()
return g_map.getTile(m_position); return g_map.getTile(m_position);
} }
ContainerPtr Thing::getParentContainer()
{
if(m_position.x == 0xFFFF && m_position.y & 0x40)
return g_game.getContainer(m_position.z);
return nullptr;
}
int Thing::getStackpos() int Thing::getStackpos()
{ {
if(m_position.x == 65535 && asItem()) // is inside a container if(m_position.x == 65535 && asItem()) // is inside a container

@ -49,6 +49,7 @@ public:
Position getPosition() { return m_position; } Position getPosition() { return m_position; }
int getStackPriority(); int getStackPriority();
const TilePtr& getTile(); const TilePtr& getTile();
ContainerPtr getParentContainer();
int getStackpos(); int getStackpos();
ThingPtr asThing() { return std::static_pointer_cast<Thing>(shared_from_this()); } ThingPtr asThing() { return std::static_pointer_cast<Thing>(shared_from_this()); }

@ -305,6 +305,7 @@ void OTClient::registerLuaFunctions()
g_lua.registerClass<UIMap, UIWidget>(); g_lua.registerClass<UIMap, UIWidget>();
g_lua.bindClassStaticFunction<UIMap>("create", []{ return UIMapPtr(new UIMap); } ); g_lua.bindClassStaticFunction<UIMap>("create", []{ return UIMapPtr(new UIMap); } );
g_lua.bindClassMemberFunction<UIMap>("followCreature", &UIMap::followCreature);
g_lua.bindClassMemberFunction<UIMap>("getTile", &UIMap::getTile); g_lua.bindClassMemberFunction<UIMap>("getTile", &UIMap::getTile);
g_lua.bindClassMemberFunction<UIMap>("zoomIn", &UIMap::zoomIn); g_lua.bindClassMemberFunction<UIMap>("zoomIn", &UIMap::zoomIn);
g_lua.bindClassMemberFunction<UIMap>("zoomOut", &UIMap::zoomOut); g_lua.bindClassMemberFunction<UIMap>("zoomOut", &UIMap::zoomOut);

@ -1,117 +0,0 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "uigame.h"
#include <otclient/core/game.h>
#include <framework/ui/uilineedit.h>
#include <framework/platform/platformwindow.h>
bool UIGame::onKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeatTicks)
{
if(UIWidget::onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks))
return true;
UILineEditPtr chatLineEdit = std::dynamic_pointer_cast<UILineEdit>(getParent()->recursiveGetChildById("consoleLineEdit"));
//TODO: move this whole shit to lua
if(keyboardModifiers == Fw::KeyboardNoModifier) {
if(keyCode == Fw::KeyUp || keyCode == Fw::KeyNumpad8) {
g_game.walk(Otc::North);
return true;
} else if(keyCode == Fw::KeyRight || keyCode == Fw::KeyNumpad6) {
g_game.walk(Otc::East);
return true;
} else if(keyCode == Fw::KeyDown || keyCode == Fw::KeyNumpad2) {
g_game.walk(Otc::South);
return true;
} else if(keyCode == Fw::KeyLeft || keyCode == Fw::KeyNumpad4) {
g_game.walk(Otc::West);
return true;
} else if(keyCode == Fw::KeyNumpad9) {
g_game.walk(Otc::NorthEast);
return true;
} else if(keyCode == Fw::KeyNumpad3) {
g_game.walk(Otc::SouthEast);
return true;
} else if(keyCode == Fw::KeyNumpad1) {
g_game.walk(Otc::SouthWest);
return true;
} else if(keyCode == Fw::KeyNumpad7) {
g_game.walk(Otc::NorthWest);
return true;
} else if(keyCode == Fw::KeyDelete) {
chatLineEdit->removeCharacter(true);
return true;
} else if(keyCode == Fw::KeyBackspace) {
chatLineEdit->removeCharacter(false);
return true;
} else if(keyCode == Fw::KeyRight) {
chatLineEdit->moveCursor(true);
return true;
} else if(keyCode == Fw::KeyLeft) {
chatLineEdit->moveCursor(false);
return true;
} else if(keyCode == Fw::KeyHome) {
chatLineEdit->setCursorPos(0);
return true;
} else if(keyCode == Fw::KeyEnd) {
chatLineEdit->setCursorPos(chatLineEdit->getText().length());
return true;
}
} else if(keyboardModifiers == Fw::KeyboardCtrlModifier) {
if(keyCode == Fw::KeyUp || keyCode == Fw::KeyNumpad8) {
g_game.turn(Otc::North);
return true;
} else if(keyCode == Fw::KeyRight || keyCode == Fw::KeyNumpad6) {
g_game.turn(Otc::East);
return true;
} else if(keyCode == Fw::KeyDown || keyCode == Fw::KeyNumpad2) {
g_game.turn(Otc::South);
return true;
} else if(keyCode == Fw::KeyLeft || keyCode == Fw::KeyNumpad4) {
g_game.turn(Otc::West);
return true;
} else if(keyCode == Fw::KeyV) {
chatLineEdit->appendText(g_window.getClipboardText());
}
} else if(keyboardModifiers == Fw::KeyboardShiftModifier) {
if(keyCode == Fw::KeyRight || keyCode == Fw::KeyNumpad6) {
chatLineEdit->moveCursor(true);
return true;
} else if(keyCode == Fw::KeyLeft || keyCode == Fw::KeyNumpad4) {
chatLineEdit->moveCursor(false);
return true;
}
}
return false;
}
bool UIGame::onKeyText(const std::string& keyText)
{
if(UIWidget::onKeyText(keyText))
return true;
UILineEditPtr chatLineEdit = std::dynamic_pointer_cast<UILineEdit>(getParent()->recursiveGetChildById("consoleLineEdit"));
chatLineEdit->appendText(keyText);
return true;
}

@ -33,7 +33,6 @@ UIMap::UIMap()
m_dragable = true; m_dragable = true;
m_mapView = MapViewPtr(new MapView); m_mapView = MapViewPtr(new MapView);
g_map.addMapView(m_mapView); g_map.addMapView(m_mapView);
m_mapView->followCreature(g_game.getLocalPlayer());
} }
UIMap::~UIMap() UIMap::~UIMap()
@ -96,6 +95,11 @@ void UIMap::zoomOut()
m_mapRect.moveCenter(m_rect.center()); m_mapRect.moveCenter(m_rect.center());
} }
void UIMap::followCreature(const CreaturePtr& creature)
{
m_mapView->followCreature(creature);
}
void UIMap::setCameraPosition(const Position& pos) void UIMap::setCameraPosition(const Position& pos)
{ {
m_mapView->setCameraPosition(pos); m_mapView->setCameraPosition(pos);

@ -37,6 +37,7 @@ public:
void zoomIn(); void zoomIn();
void zoomOut(); void zoomOut();
void followCreature(const CreaturePtr& creature);
void setCameraPosition(const Position& pos); void setCameraPosition(const Position& pos);
TilePtr getTile(const Point& mousePos); TilePtr getTile(const Point& mousePos);

Loading…
Cancel
Save