More multiprotocol support
This commit is contained in:
parent
e393bc245d
commit
c795eb91ab
|
@ -92,7 +92,7 @@ end
|
||||||
local function onLoginWait(message, time)
|
local function onLoginWait(message, time)
|
||||||
CharacterList.destroyLoadBox()
|
CharacterList.destroyLoadBox()
|
||||||
|
|
||||||
waitingWindow = g_ui.loadUI('waitinglist.otui')
|
waitingWindow = g_ui.displayUI('waitinglist.otui')
|
||||||
|
|
||||||
local label = waitingWindow:getChildById('infoLabel')
|
local label = waitingWindow:getChildById('infoLabel')
|
||||||
label:setText(message)
|
label:setText(message)
|
||||||
|
|
|
@ -168,7 +168,8 @@ function EnterGame.doLogin()
|
||||||
end })
|
end })
|
||||||
|
|
||||||
g_game.chooseRsa(G.host)
|
g_game.chooseRsa(G.host)
|
||||||
g_game.setProtocolVersion(protocol)
|
g_game.setClientVersion(protocol)
|
||||||
|
modules.game_tibiafiles.load()
|
||||||
protocolLogin:login(G.host, G.port, G.account, G.password)
|
protocolLogin:login(G.host, G.port, G.account, G.password)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,14 @@ function connect(object, arg1, arg2, arg3)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function disconnect(object, signalsAndSlots)
|
function disconnect(object, arg1, arg2)
|
||||||
|
local signalsAndSlots
|
||||||
|
if type(arg1) == 'string' then
|
||||||
|
signalsAndSlots = { [arg1] = arg2 }
|
||||||
|
else
|
||||||
|
signalsAndSlots = arg1
|
||||||
|
end
|
||||||
|
|
||||||
for signal,slot in pairs(signalsAndSlots) do
|
for signal,slot in pairs(signalsAndSlots) do
|
||||||
if not object[signal] then
|
if not object[signal] then
|
||||||
elseif type(object[signal]) == 'function' then
|
elseif type(object[signal]) == 'function' then
|
||||||
|
@ -231,11 +238,19 @@ end
|
||||||
|
|
||||||
function signalcall(param, ...)
|
function signalcall(param, ...)
|
||||||
if type(param) == 'function' then
|
if type(param) == 'function' then
|
||||||
return param(...)
|
local status, ret = pcall(param, ...)
|
||||||
|
if status then
|
||||||
|
return ret
|
||||||
|
else
|
||||||
|
perror(ret)
|
||||||
|
end
|
||||||
elseif type(param) == 'table' then
|
elseif type(param) == 'table' then
|
||||||
for k,v in pairs(param) do
|
for k,v in pairs(param) do
|
||||||
if v(...) then
|
local status, ret = pcall(v, ...)
|
||||||
return true
|
if status then
|
||||||
|
if ret then return true end
|
||||||
|
else
|
||||||
|
perror(ret)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif func ~= nil then
|
elseif func ~= nil then
|
||||||
|
|
|
@ -91,7 +91,7 @@ end
|
||||||
function addAllCreatures()
|
function addAllCreatures()
|
||||||
local spectators = {}
|
local spectators = {}
|
||||||
local player = g_game.getLocalPlayer()
|
local player = g_game.getLocalPlayer()
|
||||||
if player then
|
if g_game.isOnline() then
|
||||||
creatures = g_map.getSpectators(player:getPosition(), false)
|
creatures = g_map.getSpectators(player:getPosition(), false)
|
||||||
for i, creature in ipairs(creatures) do
|
for i, creature in ipairs(creatures) do
|
||||||
if creature ~= player and doCreatureFitFilters(creature) then
|
if creature ~= player and doCreatureFitFilters(creature) then
|
||||||
|
@ -129,7 +129,7 @@ end
|
||||||
|
|
||||||
function checkCreatures(forceRecheck)
|
function checkCreatures(forceRecheck)
|
||||||
local player = g_game.getLocalPlayer()
|
local player = g_game.getLocalPlayer()
|
||||||
if player then
|
if g_game.isOnline() then
|
||||||
local spectators = {}
|
local spectators = {}
|
||||||
|
|
||||||
-- reloading list of spectators
|
-- reloading list of spectators
|
||||||
|
|
|
@ -135,10 +135,6 @@ function toggle()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function onMiniWindowClose()
|
|
||||||
combatControlsButton:setOn(false)
|
|
||||||
end
|
|
||||||
|
|
||||||
function onSetFightMode(self, selectedFightButton)
|
function onSetFightMode(self, selectedFightButton)
|
||||||
if selectedFightButton == nil then return end
|
if selectedFightButton == nil then return end
|
||||||
local buttonId = selectedFightButton:getId()
|
local buttonId = selectedFightButton:getId()
|
||||||
|
|
|
@ -27,7 +27,6 @@ MiniWindow
|
||||||
!text: tr('Combat Controls')
|
!text: tr('Combat Controls')
|
||||||
icon: combatcontrols.png
|
icon: combatcontrols.png
|
||||||
height: 48
|
height: 48
|
||||||
@onClose: CombatControls.onMiniWindowClose()
|
|
||||||
&save: true
|
&save: true
|
||||||
|
|
||||||
MiniWindowContents
|
MiniWindowContents
|
||||||
|
|
|
@ -37,14 +37,14 @@ function clean()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function refreshContainerItems(container)
|
function refreshContainerItems(container)
|
||||||
for slot=0,container:getCapacity()-1 do
|
for slot=0,container:getCapacity()-1 do
|
||||||
local itemWidget = container.itemsPanel:getChildById('item' .. slot)
|
local itemWidget = container.itemsPanel:getChildById('item' .. slot)
|
||||||
itemWidget:setItem(container:getItem(slot))
|
itemWidget:setItem(container:getItem(slot))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function onContainerOpen(container, previousContainer)
|
function onContainerOpen(container, previousContainer)
|
||||||
local containerWindow
|
local containerWindow
|
||||||
if previousContainer then
|
if previousContainer then
|
||||||
containerWindow = previousContainer.window
|
containerWindow = previousContainer.window
|
||||||
|
|
|
@ -2,7 +2,7 @@ Icons = {}
|
||||||
Icons[1] = { tooltip = tr('You are poisoned'), path = '/game_healthinfo/icons/poisoned.png', id = 'condition_poisoned' }
|
Icons[1] = { tooltip = tr('You are poisoned'), path = '/game_healthinfo/icons/poisoned.png', id = 'condition_poisoned' }
|
||||||
Icons[2] = { tooltip = tr('You are burning'), path = '/game_healthinfo/icons/burning.png', id = 'condition_burning' }
|
Icons[2] = { tooltip = tr('You are burning'), path = '/game_healthinfo/icons/burning.png', id = 'condition_burning' }
|
||||||
Icons[4] = { tooltip = tr('You are electrified'), path = '/game_healthinfo/icons/electrified.png', id = 'condition_electrified' }
|
Icons[4] = { tooltip = tr('You are electrified'), path = '/game_healthinfo/icons/electrified.png', id = 'condition_electrified' }
|
||||||
Icons[8] = { tooltip = tr('You are freezing'), path = '/game_healthinfo/icons/drunk.png', id = 'condition_drunk' }
|
Icons[8] = { tooltip = tr('You are drunk'), path = '/game_healthinfo/icons/drunk.png', id = 'condition_drunk' }
|
||||||
Icons[16] = { tooltip = tr('You are protected by a magic shield'), path = '/game_healthinfo/icons/magic_shield.png', id = 'condition_magic_shield' }
|
Icons[16] = { tooltip = tr('You are protected by a magic shield'), path = '/game_healthinfo/icons/magic_shield.png', id = 'condition_magic_shield' }
|
||||||
Icons[32] = { tooltip = tr('You are paralysed'), path = '/game_healthinfo/icons/slowed.png', id = 'condition_slowed' }
|
Icons[32] = { tooltip = tr('You are paralysed'), path = '/game_healthinfo/icons/slowed.png', id = 'condition_slowed' }
|
||||||
Icons[64] = { tooltip = tr('You are hasted'), path = '/game_healthinfo/icons/haste.png', id = 'condition_haste' }
|
Icons[64] = { tooltip = tr('You are hasted'), path = '/game_healthinfo/icons/haste.png', id = 'condition_haste' }
|
||||||
|
|
|
@ -238,6 +238,7 @@ function startTradeWith(thing)
|
||||||
end
|
end
|
||||||
|
|
||||||
function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
|
function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
|
||||||
|
if not g_game.isOnline() then return end
|
||||||
local menu = g_ui.createWidget('PopupMenu')
|
local menu = g_ui.createWidget('PopupMenu')
|
||||||
|
|
||||||
if lookThing then
|
if lookThing then
|
||||||
|
@ -297,7 +298,6 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
|
||||||
|
|
||||||
else
|
else
|
||||||
local localPlayer = g_game.getLocalPlayer()
|
local localPlayer = g_game.getLocalPlayer()
|
||||||
if localPlayer then
|
|
||||||
if g_game.getAttackingCreature() ~= creatureThing then
|
if g_game.getAttackingCreature() ~= creatureThing then
|
||||||
menu:addOption(tr('Attack'), function() g_game.attack(creatureThing) end)
|
menu:addOption(tr('Attack'), function() g_game.attack(creatureThing) end)
|
||||||
else
|
else
|
||||||
|
@ -346,7 +346,6 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if RuleViolation.hasWindowAccess() then
|
if RuleViolation.hasWindowAccess() then
|
||||||
menu:addSeparator()
|
menu:addSeparator()
|
||||||
|
|
|
@ -43,7 +43,7 @@ end
|
||||||
function refresh()
|
function refresh()
|
||||||
local player = g_game.getLocalPlayer()
|
local player = g_game.getLocalPlayer()
|
||||||
for i=InventorySlotFirst,InventorySlotLast do
|
for i=InventorySlotFirst,InventorySlotLast do
|
||||||
if player then
|
if g_game.isOnline() then
|
||||||
onInventoryChange(player, i, player:getInventoryItem(i))
|
onInventoryChange(player, i, player:getInventoryItem(i))
|
||||||
else
|
else
|
||||||
onInventoryChange(player, i, nil)
|
onInventoryChange(player, i, nil)
|
||||||
|
@ -67,8 +67,9 @@ end
|
||||||
|
|
||||||
-- hooked events
|
-- hooked events
|
||||||
function onInventoryChange(player, slot, item, oldItem)
|
function onInventoryChange(player, slot, item, oldItem)
|
||||||
|
if slot >= InventorySlotPurse then return end
|
||||||
local itemWidget = inventoryPanel:getChildById('slot' .. slot)
|
local itemWidget = inventoryPanel:getChildById('slot' .. slot)
|
||||||
if(item) then
|
if item then
|
||||||
itemWidget:setStyle('Item')
|
itemWidget:setStyle('Item')
|
||||||
itemWidget:setItem(item)
|
itemWidget:setItem(item)
|
||||||
else
|
else
|
||||||
|
|
|
@ -38,7 +38,7 @@ end
|
||||||
local function parseMarketEnter(msg)
|
local function parseMarketEnter(msg)
|
||||||
local balance = msg:getU32()
|
local balance = msg:getU32()
|
||||||
local vocation = -1
|
local vocation = -1
|
||||||
if g_game.getProtocolVersion() < 950 then
|
if g_game.getClientVersion() < 950 then
|
||||||
vocation = msg:getU8() -- get vocation id
|
vocation = msg:getU8() -- get vocation id
|
||||||
end
|
end
|
||||||
local offers = msg:getU8()
|
local offers = msg:getU8()
|
||||||
|
@ -74,7 +74,8 @@ local function parseMarketDetail(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
local purchaseStats = {}
|
local purchaseStats = {}
|
||||||
if msg:getU8() == 0x01 then
|
local count = msg:getU8()
|
||||||
|
for i=1,count do
|
||||||
local transactions = msg:getU32() -- transaction count
|
local transactions = msg:getU32() -- transaction count
|
||||||
local totalPrice = msg:getU32() -- total price
|
local totalPrice = msg:getU32() -- total price
|
||||||
local highestPrice = msg:getU32() -- highest price
|
local highestPrice = msg:getU32() -- highest price
|
||||||
|
@ -84,7 +85,8 @@ local function parseMarketDetail(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
local saleStats = {}
|
local saleStats = {}
|
||||||
if msg:getU8() == 0x01 then
|
count = msg:getU8()
|
||||||
|
for i=1,count do
|
||||||
local transactions = msg:getU32() -- transaction count
|
local transactions = msg:getU32() -- transaction count
|
||||||
local totalPrice = msg:getU32() -- total price
|
local totalPrice = msg:getU32() -- total price
|
||||||
local highestPrice = msg:getU32() -- highest price
|
local highestPrice = msg:getU32() -- highest price
|
||||||
|
|
|
@ -67,6 +67,7 @@ function loadReasons()
|
||||||
local actions = g_game.getGMActions()
|
local actions = g_game.getGMActions()
|
||||||
for reason, actionFlags in pairs(actions) do
|
for reason, actionFlags in pairs(actions) do
|
||||||
local label = g_ui.createWidget('RVListLabel', reasonsTextList)
|
local label = g_ui.createWidget('RVListLabel', reasonsTextList)
|
||||||
|
label.onFocusChange = onSelectReason
|
||||||
label:setText(rvreasons[reason])
|
label:setText(rvreasons[reason])
|
||||||
label.reasonId = reason
|
label.reasonId = reason
|
||||||
label.actionFlags = actionFlags
|
label.actionFlags = actionFlags
|
||||||
|
|
|
@ -2,7 +2,6 @@ RVListLabel < Label
|
||||||
background-color: alpha
|
background-color: alpha
|
||||||
text-offset: 2 0
|
text-offset: 2 0
|
||||||
focusable: true
|
focusable: true
|
||||||
@onFocusChange: function (self, focused) RuleViolation.onSelectReason(self, focused) end
|
|
||||||
|
|
||||||
$focus:
|
$focus:
|
||||||
background-color: #ffffff22
|
background-color: #ffffff22
|
||||||
|
@ -109,7 +108,7 @@ MainWindow
|
||||||
width: 64
|
width: 64
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
@onClick: RuleViolation.hide()
|
@onClick: hide()
|
||||||
|
|
||||||
Button
|
Button
|
||||||
!text: tr('Ok')
|
!text: tr('Ok')
|
||||||
|
@ -117,4 +116,4 @@ MainWindow
|
||||||
margin-right: 5
|
margin-right: 5
|
||||||
anchors.right: prev.left
|
anchors.right: prev.left
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
@onClick: RuleViolation.report()
|
@onClick: report()
|
|
@ -47,7 +47,7 @@ end
|
||||||
function parseTextMessage(msg)
|
function parseTextMessage(msg)
|
||||||
local msgtype = msg:getU8()
|
local msgtype = msg:getU8()
|
||||||
local text = msg:getString()
|
local text = msg:getString()
|
||||||
msgtype = getMessageTypes(g_game.getProtocolVersion())[msgtype]
|
msgtype = getMessageTypes(g_game.getClientVersion())[msgtype]
|
||||||
signalcall(g_game.onTextMessage, msgtype, text)
|
signalcall(g_game.onTextMessage, msgtype, text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
function init()
|
function init()
|
||||||
if not g_things.loadDat('/game_tibiafiles/Tibia.dat') then
|
if g_game.getClientVersion() ~= 0 then
|
||||||
fatal(tr("Unable to load dat file, please place a valid Tibia dat in modules/game_tibiafiles/Tibia.dat"))
|
load()
|
||||||
end
|
|
||||||
if not g_sprites.loadSpr('/game_tibiafiles/Tibia.spr') then
|
|
||||||
fatal(tr("Unable to load spr file, please place a valid Tibia spr in modules/game_tibiafiles/Tibia.spr"))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function terminate()
|
function load()
|
||||||
|
local version = g_game.getClientVersion()
|
||||||
|
local datPath = resolvepath(version .. '/Tibia.dat')
|
||||||
|
local sprPath = resolvepath(version .. '/Tibia.spr')
|
||||||
|
if not g_things.loadDat(datPath) then
|
||||||
|
fatal(tr("Unable to load dat file, please place a valid dat in '%s'", datPath))
|
||||||
|
end
|
||||||
|
if not g_sprites.loadSpr(sprPath) then
|
||||||
|
fatal(tr("Unable to load spr file, please place a valid spr in '%s'", sprPath))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -71,6 +71,9 @@ CIPSOFT_RSA = "1321277432058722840622950990822933849527763264961655079678763618"
|
||||||
"2907336840325241747827401343576296990629870233111328210165697754" ..
|
"2907336840325241747827401343576296990629870233111328210165697754" ..
|
||||||
"88792221429527047321331896351555606801473202394175817"
|
"88792221429527047321331896351555606801473202394175817"
|
||||||
|
|
||||||
|
-- set to the latest Tibia.pic signature to make otclient compatible with official tibia
|
||||||
|
PIC_SIGNATURE = 1337606793
|
||||||
|
|
||||||
OsTypes = {
|
OsTypes = {
|
||||||
Linux = 1,
|
Linux = 1,
|
||||||
Windows = 2,
|
Windows = 2,
|
||||||
|
|
|
@ -11,6 +11,7 @@ InventorySlotLeg = 7
|
||||||
InventorySlotFeet = 8
|
InventorySlotFeet = 8
|
||||||
InventorySlotFinger = 9
|
InventorySlotFinger = 9
|
||||||
InventorySlotAmmo = 10
|
InventorySlotAmmo = 10
|
||||||
|
InventorySlotPurse = 11
|
||||||
|
|
||||||
InventorySlotFirst = 1
|
InventorySlotFirst = 1
|
||||||
InventorySlotLast = 10
|
InventorySlotLast = 10
|
||||||
|
|
|
@ -1,89 +1,11 @@
|
||||||
-- @docclass
|
-- @docclass
|
||||||
ProtocolLogin = extends(Protocol)
|
ProtocolLogin = extends(Protocol)
|
||||||
|
|
||||||
-- set to the latest Tibia.pic signature to make otclient compatible with official tibia
|
|
||||||
local PIC_SIGNATURE = 1337606793
|
|
||||||
|
|
||||||
LoginServerError = 10
|
LoginServerError = 10
|
||||||
LoginServerMotd = 20
|
LoginServerMotd = 20
|
||||||
LoginServerUpdateNeeded = 30
|
LoginServerUpdateNeeded = 30
|
||||||
LoginServerCharacterList = 100
|
LoginServerCharacterList = 100
|
||||||
|
|
||||||
|
|
||||||
-- private functions
|
|
||||||
local function sendLoginPacket(protocol)
|
|
||||||
local msg = OutputMessage.create()
|
|
||||||
msg:addU8(ClientOpcodes.ClientEnterAccount)
|
|
||||||
msg:addU16(g_game.getOsType())
|
|
||||||
msg:addU16(g_game.getProtocolVersion())
|
|
||||||
|
|
||||||
msg:addU32(g_things.getDatSignature())
|
|
||||||
msg:addU32(g_sprites.getSprSignature())
|
|
||||||
msg:addU32(PIC_SIGNATURE)
|
|
||||||
|
|
||||||
local paddingBytes = 128
|
|
||||||
msg:addU8(0) -- first RSA byte must be 0
|
|
||||||
paddingBytes = paddingBytes - 1
|
|
||||||
|
|
||||||
-- xtea key
|
|
||||||
protocol:generateXteaKey()
|
|
||||||
local xteaKey = protocol:getXteaKey()
|
|
||||||
msg:addU32(xteaKey[1])
|
|
||||||
msg:addU32(xteaKey[2])
|
|
||||||
msg:addU32(xteaKey[3])
|
|
||||||
msg:addU32(xteaKey[4])
|
|
||||||
paddingBytes = paddingBytes - 16
|
|
||||||
|
|
||||||
if g_game.getFeature(GameProtocolChecksum) then
|
|
||||||
protocol:enableChecksum()
|
|
||||||
end
|
|
||||||
|
|
||||||
if g_game.getFeature(GameAccountNames) then
|
|
||||||
msg:addString(protocol.accountName)
|
|
||||||
msg:addString(protocol.accountPassword)
|
|
||||||
paddingBytes = paddingBytes - (4 + string.len(protocol.accountName) + string.len(protocol.accountPassword))
|
|
||||||
else
|
|
||||||
msg:addU32(tonumber(protocol.accountName))
|
|
||||||
msg:addString(protocol.accountPassword)
|
|
||||||
paddingBytes = paddingBytes - (6 + string.len(protocol.accountPassword))
|
|
||||||
end
|
|
||||||
|
|
||||||
msg:addPaddingBytes(paddingBytes, 0)
|
|
||||||
msg:encryptRsa(128, g_game.getRsa())
|
|
||||||
|
|
||||||
protocol:send(msg)
|
|
||||||
protocol:enableXteaEncryption()
|
|
||||||
protocol:recv()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- events
|
|
||||||
function ProtocolLogin:onConnect()
|
|
||||||
self:connectCallback(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProtocolLogin:onRecv(msg)
|
|
||||||
while not msg:eof() do
|
|
||||||
local opcode = msg:getU8()
|
|
||||||
if opcode == LoginServerError then
|
|
||||||
self:parseError(msg)
|
|
||||||
elseif opcode == LoginServerMotd then
|
|
||||||
self:parseMotd(msg)
|
|
||||||
elseif opcode == LoginServerUpdateNeeded then
|
|
||||||
signalcall(self.onError, self, tr("Client needs update."))
|
|
||||||
elseif opcode == LoginServerCharacterList then
|
|
||||||
self:parseCharacterList(msg)
|
|
||||||
else
|
|
||||||
self:parseOpcode(opcode, msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self:disconnect()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- public functions
|
|
||||||
function ProtocolLogin.create()
|
|
||||||
return ProtocolLogin.internalCreate()
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProtocolLogin:login(host, port, accountName, accountPassword)
|
function ProtocolLogin:login(host, port, accountName, accountPassword)
|
||||||
if string.len(accountName) == 0 or string.len(accountPassword) == 0 then
|
if string.len(accountName) == 0 or string.len(accountPassword) == 0 then
|
||||||
signalcall(self.onError, self, tr("You must enter an account name and password."))
|
signalcall(self.onError, self, tr("You must enter an account name and password."))
|
||||||
|
@ -105,6 +27,73 @@ function ProtocolLogin:cancelLogin()
|
||||||
self:disconnect()
|
self:disconnect()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function ProtocolLogin:sendLoginPacket()
|
||||||
|
local msg = OutputMessage.create()
|
||||||
|
msg:addU8(ClientOpcodes.ClientEnterAccount)
|
||||||
|
msg:addU16(g_game.getOsType())
|
||||||
|
msg:addU16(g_game.getClientVersion())
|
||||||
|
|
||||||
|
msg:addU32(g_things.getDatSignature())
|
||||||
|
msg:addU32(g_sprites.getSprSignature())
|
||||||
|
msg:addU32(PIC_SIGNATURE)
|
||||||
|
|
||||||
|
local paddingBytes = 128
|
||||||
|
msg:addU8(0) -- first RSA byte must be 0
|
||||||
|
paddingBytes = paddingBytes - 1
|
||||||
|
|
||||||
|
-- xtea key
|
||||||
|
self:generateXteaKey()
|
||||||
|
local xteaKey = self:getXteaKey()
|
||||||
|
msg:addU32(xteaKey[1])
|
||||||
|
msg:addU32(xteaKey[2])
|
||||||
|
msg:addU32(xteaKey[3])
|
||||||
|
msg:addU32(xteaKey[4])
|
||||||
|
paddingBytes = paddingBytes - 16
|
||||||
|
|
||||||
|
if g_game.getFeature(GameProtocolChecksum) then
|
||||||
|
self:enableChecksum()
|
||||||
|
end
|
||||||
|
|
||||||
|
if g_game.getFeature(GameAccountNames) then
|
||||||
|
msg:addString(self.accountName)
|
||||||
|
msg:addString(self.accountPassword)
|
||||||
|
paddingBytes = paddingBytes - (4 + string.len(self.accountName) + string.len(self.accountPassword))
|
||||||
|
else
|
||||||
|
msg:addU32(tonumber(self.accountName))
|
||||||
|
msg:addString(self.accountPassword)
|
||||||
|
paddingBytes = paddingBytes - (6 + string.len(self.accountPassword))
|
||||||
|
end
|
||||||
|
|
||||||
|
msg:addPaddingBytes(paddingBytes, 0)
|
||||||
|
msg:encryptRsa(128, g_game.getRsa())
|
||||||
|
|
||||||
|
self:send(msg)
|
||||||
|
self:enableXteaEncryption()
|
||||||
|
self:recv()
|
||||||
|
end
|
||||||
|
|
||||||
|
function ProtocolLogin:onConnect()
|
||||||
|
self:sendLoginPacket()
|
||||||
|
end
|
||||||
|
|
||||||
|
function ProtocolLogin:onRecv(msg)
|
||||||
|
while not msg:eof() do
|
||||||
|
local opcode = msg:getU8()
|
||||||
|
if opcode == LoginServerError then
|
||||||
|
self:parseError(msg)
|
||||||
|
elseif opcode == LoginServerMotd then
|
||||||
|
self:parseMotd(msg)
|
||||||
|
elseif opcode == LoginServerUpdateNeeded then
|
||||||
|
signalcall(self.onError, self, tr("Client needs update."))
|
||||||
|
elseif opcode == LoginServerCharacterList then
|
||||||
|
self:parseCharacterList(msg)
|
||||||
|
else
|
||||||
|
self:parseOpcode(opcode, msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:disconnect()
|
||||||
|
end
|
||||||
|
|
||||||
function ProtocolLogin:parseError(msg)
|
function ProtocolLogin:parseError(msg)
|
||||||
local errorMessage = msg:getString()
|
local errorMessage = msg:getString()
|
||||||
signalcall(self.onError, self, errorMessage)
|
signalcall(self.onError, self, errorMessage)
|
||||||
|
|
|
@ -37,14 +37,14 @@ static const std::string glslMainWithTexCoordsVertexShader = "\n\
|
||||||
void main()\n\
|
void main()\n\
|
||||||
{\n\
|
{\n\
|
||||||
gl_Position = calculatePosition();\n\
|
gl_Position = calculatePosition();\n\
|
||||||
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1)).xy;\n\
|
v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1.0)).xy;\n\
|
||||||
}\n";
|
}\n";
|
||||||
|
|
||||||
static std::string glslPositionOnlyVertexShader = "\n\
|
static std::string glslPositionOnlyVertexShader = "\n\
|
||||||
attribute highp vec2 a_Vertex;\n\
|
attribute highp vec2 a_Vertex;\n\
|
||||||
uniform highp mat3 u_ProjectionMatrix;\n\
|
uniform highp mat3 u_ProjectionMatrix;\n\
|
||||||
highp vec4 calculatePosition() {\n\
|
highp vec4 calculatePosition() {\n\
|
||||||
return vec4(u_ProjectionMatrix * vec3(a_Vertex.xy, 1), 1);\n\
|
return vec4(u_ProjectionMatrix * vec3(a_Vertex.xy, 1.0), 1.0);\n\
|
||||||
}\n";
|
}\n";
|
||||||
|
|
||||||
static const std::string glslMainFragmentShader = "\n\
|
static const std::string glslMainFragmentShader = "\n\
|
||||||
|
|
|
@ -336,6 +336,7 @@ void Application::registerLuaFunctions()
|
||||||
g_lua.bindClassMemberFunction<UIWidget>("getChildByIndex", &UIWidget::getChildByIndex);
|
g_lua.bindClassMemberFunction<UIWidget>("getChildByIndex", &UIWidget::getChildByIndex);
|
||||||
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildById", &UIWidget::recursiveGetChildById);
|
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildById", &UIWidget::recursiveGetChildById);
|
||||||
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildByPos", &UIWidget::recursiveGetChildByPos);
|
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildByPos", &UIWidget::recursiveGetChildByPos);
|
||||||
|
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildren", &UIWidget::recursiveGetChildren);
|
||||||
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildrenByPos", &UIWidget::recursiveGetChildrenByPos);
|
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildrenByPos", &UIWidget::recursiveGetChildrenByPos);
|
||||||
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildrenByMarginPos", &UIWidget::recursiveGetChildrenByMarginPos);
|
g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildrenByMarginPos", &UIWidget::recursiveGetChildrenByMarginPos);
|
||||||
g_lua.bindClassMemberFunction<UIWidget>("backwardsGetWidgetById", &UIWidget::backwardsGetWidgetById);
|
g_lua.bindClassMemberFunction<UIWidget>("backwardsGetWidgetById", &UIWidget::backwardsGetWidgetById);
|
||||||
|
|
|
@ -56,7 +56,7 @@ private:
|
||||||
SoundSourcePtr createSoundSource(const std::string& filename);
|
SoundSourcePtr createSoundSource(const std::string& filename);
|
||||||
uint loadFileIntoBuffer(const SoundFilePtr& soundFile);
|
uint loadFileIntoBuffer(const SoundFilePtr& soundFile);
|
||||||
|
|
||||||
std::map<std::string, SoundBufferPtr> m_buffers;
|
std::unordered_map<std::string, SoundBufferPtr> m_buffers;
|
||||||
std::vector<SoundSourcePtr> m_sources;
|
std::vector<SoundSourcePtr> m_sources;
|
||||||
SoundSourcePtr m_musicSource;
|
SoundSourcePtr m_musicSource;
|
||||||
ALCdevice *m_device;
|
ALCdevice *m_device;
|
||||||
|
|
|
@ -81,7 +81,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool updateWidget(const UIWidgetPtr& widget, UIAnchorGroup& anchorGroup, UIWidgetPtr first = nullptr);
|
bool updateWidget(const UIWidgetPtr& widget, UIAnchorGroup& anchorGroup, UIWidgetPtr first = nullptr);
|
||||||
std::map<UIWidgetPtr, UIAnchorGroup> m_anchorsGroups;
|
std::unordered_map<UIWidgetPtr, UIAnchorGroup> m_anchorsGroups;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1130,6 +1130,18 @@ UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos, bool wantsPh
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UIWidgetList UIWidget::recursiveGetChildren()
|
||||||
|
{
|
||||||
|
UIWidgetList children;
|
||||||
|
for(const UIWidgetPtr& child : m_children) {
|
||||||
|
UIWidgetList subChildren = child->recursiveGetChildren();
|
||||||
|
if(!subChildren.empty())
|
||||||
|
children.insert(children.end(), subChildren.begin(), subChildren.end());
|
||||||
|
children.push_back(child);
|
||||||
|
}
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
UIWidgetList UIWidget::recursiveGetChildrenByPos(const Point& childPos)
|
UIWidgetList UIWidget::recursiveGetChildrenByPos(const Point& childPos)
|
||||||
{
|
{
|
||||||
UIWidgetList children;
|
UIWidgetList children;
|
||||||
|
|
|
@ -147,6 +147,7 @@ public:
|
||||||
UIWidgetPtr getChildByIndex(int index);
|
UIWidgetPtr getChildByIndex(int index);
|
||||||
UIWidgetPtr recursiveGetChildById(const std::string& id);
|
UIWidgetPtr recursiveGetChildById(const std::string& id);
|
||||||
UIWidgetPtr recursiveGetChildByPos(const Point& childPos, bool wantsPhantom);
|
UIWidgetPtr recursiveGetChildByPos(const Point& childPos, bool wantsPhantom);
|
||||||
|
UIWidgetList recursiveGetChildren();
|
||||||
UIWidgetList recursiveGetChildrenByPos(const Point& childPos);
|
UIWidgetList recursiveGetChildrenByPos(const Point& childPos);
|
||||||
UIWidgetList recursiveGetChildrenByMarginPos(const Point& childPos);
|
UIWidgetList recursiveGetChildrenByMarginPos(const Point& childPos);
|
||||||
UIWidgetPtr backwardsGetWidgetById(const std::string& id);
|
UIWidgetPtr backwardsGetWidgetById(const std::string& id);
|
||||||
|
|
|
@ -79,7 +79,7 @@ public:
|
||||||
uint8 getSkull() { return m_skull; }
|
uint8 getSkull() { return m_skull; }
|
||||||
uint8 getShield() { return m_shield; }
|
uint8 getShield() { return m_shield; }
|
||||||
uint8 getEmblem() { return m_emblem; }
|
uint8 getEmblem() { return m_emblem; }
|
||||||
bool getPassable() { return m_passable; }
|
bool isPassable() { return m_passable; }
|
||||||
Point getDrawOffset();
|
Point getDrawOffset();
|
||||||
Point getWalkOffset() { return m_walkOffset; }
|
Point getWalkOffset() { return m_walkOffset; }
|
||||||
|
|
||||||
|
|
|
@ -39,15 +39,16 @@ Game::Game()
|
||||||
{
|
{
|
||||||
resetGameStates();
|
resetGameStates();
|
||||||
m_protocolVersion = 0;
|
m_protocolVersion = 0;
|
||||||
setProtocolVersion(PROTOCOL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::resetGameStates()
|
void Game::resetGameStates()
|
||||||
{
|
{
|
||||||
|
m_online = false;
|
||||||
m_denyBotCall = false;
|
m_denyBotCall = false;
|
||||||
m_dead = false;
|
m_dead = false;
|
||||||
m_mounted = false;
|
m_mounted = false;
|
||||||
m_serverBeat = 50;
|
m_serverBeat = 50;
|
||||||
|
m_seq = 0;
|
||||||
m_canReportBugs = false;
|
m_canReportBugs = false;
|
||||||
m_fightMode = Otc::FightBalanced;
|
m_fightMode = Otc::FightBalanced;
|
||||||
m_chaseMode = Otc::DontChase;
|
m_chaseMode = Otc::DontChase;
|
||||||
|
@ -104,15 +105,9 @@ void Game::processLoginWait(const std::string& message, int time)
|
||||||
g_lua.callGlobalField("g_game", "onLoginWait", message, time);
|
g_lua.callGlobalField("g_game", "onLoginWait", message, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::processGameStart(const LocalPlayerPtr& localPlayer, int serverBeat, bool canReportBugs)
|
void Game::processGameStart()
|
||||||
{
|
{
|
||||||
// reset the new game state
|
m_online = true;
|
||||||
resetGameStates();
|
|
||||||
|
|
||||||
m_localPlayer = localPlayer;
|
|
||||||
m_localPlayer->setName(m_characterName);
|
|
||||||
m_serverBeat = serverBeat;
|
|
||||||
m_canReportBugs = canReportBugs;
|
|
||||||
|
|
||||||
// synchronize fight modes with the server
|
// synchronize fight modes with the server
|
||||||
m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight);
|
m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight);
|
||||||
|
@ -401,9 +396,9 @@ void Game::processQuestLine(int questId, const std::vector<std::tuple<std::strin
|
||||||
g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions);
|
g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::processAttackCancel()
|
void Game::processAttackCancel(uint seq)
|
||||||
{
|
{
|
||||||
if(isAttacking())
|
if(isAttacking() && (seq == 0 || m_seq == seq))
|
||||||
setAttackingCreature(nullptr);
|
setAttackingCreature(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,6 +418,12 @@ void Game::loginWorld(const std::string& account, const std::string& password, c
|
||||||
if(m_protocolVersion == 0)
|
if(m_protocolVersion == 0)
|
||||||
stdext::throw_exception("Must set a valid game protocol version before logging.");
|
stdext::throw_exception("Must set a valid game protocol version before logging.");
|
||||||
|
|
||||||
|
// reset the new game state
|
||||||
|
resetGameStates();
|
||||||
|
|
||||||
|
m_localPlayer = LocalPlayerPtr(new LocalPlayer);
|
||||||
|
m_localPlayer->setName(m_characterName);
|
||||||
|
|
||||||
m_protocolGame = ProtocolGamePtr(new ProtocolGame);
|
m_protocolGame = ProtocolGamePtr(new ProtocolGame);
|
||||||
m_protocolGame->login(account, password, worldHost, (uint16)worldPort, characterName);
|
m_protocolGame->login(account, password, worldHost, (uint16)worldPort, characterName);
|
||||||
m_characterName = characterName;
|
m_characterName = characterName;
|
||||||
|
@ -505,15 +506,10 @@ void Game::autoWalk(const std::vector<Otc::Direction>& dirs)
|
||||||
|
|
||||||
Otc::Direction direction = dirs.front();
|
Otc::Direction direction = dirs.front();
|
||||||
TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
|
TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
|
||||||
if(toTile && toTile->isWalkable())
|
if(toTile && toTile->isWalkable() && !m_localPlayer->isAutoWalking())
|
||||||
m_localPlayer->preWalk(direction);
|
m_localPlayer->preWalk(direction);
|
||||||
|
|
||||||
forceWalk(direction);
|
m_protocolGame->sendAutoWalk(dirs);
|
||||||
|
|
||||||
std::vector<Otc::Direction> nextDirs = dirs;
|
|
||||||
nextDirs.erase(nextDirs.begin());
|
|
||||||
if(nextDirs.size() > 0)
|
|
||||||
m_protocolGame->sendAutoWalk(nextDirs);
|
|
||||||
|
|
||||||
g_lua.callGlobalField("g_game", "onAutoWalk", direction);
|
g_lua.callGlobalField("g_game", "onAutoWalk", direction);
|
||||||
}
|
}
|
||||||
|
@ -737,7 +733,7 @@ void Game::attack(const CreaturePtr& creature)
|
||||||
cancelFollow();
|
cancelFollow();
|
||||||
|
|
||||||
setAttackingCreature(creature);
|
setAttackingCreature(creature);
|
||||||
m_protocolGame->sendAttack(creature ? creature->getId() : 0);
|
m_protocolGame->sendAttack(creature ? creature->getId() : 0, ++m_seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::follow(const CreaturePtr& creature)
|
void Game::follow(const CreaturePtr& creature)
|
||||||
|
@ -751,7 +747,7 @@ void Game::follow(const CreaturePtr& creature)
|
||||||
cancelAttack();
|
cancelAttack();
|
||||||
|
|
||||||
setFollowingCreature(creature);
|
setFollowingCreature(creature);
|
||||||
m_protocolGame->sendFollow(creature ? creature->getId() : 0);
|
m_protocolGame->sendFollow(creature ? creature->getId() : 0, ++m_seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::cancelAttackAndFollow()
|
void Game::cancelAttackAndFollow()
|
||||||
|
@ -885,7 +881,7 @@ void Game::partyShareExperience(bool active)
|
||||||
{
|
{
|
||||||
if(!canPerformGameAction())
|
if(!canPerformGameAction())
|
||||||
return;
|
return;
|
||||||
m_protocolGame->sendShareExperience(active, 0);
|
m_protocolGame->sendShareExperience(active);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::requestOutfit()
|
void Game::requestOutfit()
|
||||||
|
@ -1084,15 +1080,16 @@ bool Game::checkBotProtection()
|
||||||
bool Game::canPerformGameAction()
|
bool Game::canPerformGameAction()
|
||||||
{
|
{
|
||||||
// we can only perform game actions if we meet these conditions:
|
// we can only perform game actions if we meet these conditions:
|
||||||
|
// - the game is online
|
||||||
// - the local player exists
|
// - the local player exists
|
||||||
// - the local player is not dead
|
// - the local player is not dead
|
||||||
// - we have a game protocol
|
// - we have a game protocol
|
||||||
// - the game protocol is connected
|
// - the game protocol is connected
|
||||||
// - its not a bot action
|
// - its not a bot action
|
||||||
return m_localPlayer && !m_dead && m_protocolGame && m_protocolGame->isConnected() && checkBotProtection();
|
return m_online && m_localPlayer && !m_dead && m_protocolGame && m_protocolGame->isConnected() && checkBotProtection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::setProtocolVersion(int version)
|
void Game::setClientVersion(int version)
|
||||||
{
|
{
|
||||||
if(isOnline())
|
if(isOnline())
|
||||||
stdext::throw_exception("Unable to change client version while online");
|
stdext::throw_exception("Unable to change client version while online");
|
||||||
|
@ -1147,6 +1144,8 @@ void Game::setProtocolVersion(int version)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_protocolVersion = version;
|
m_protocolVersion = version;
|
||||||
|
|
||||||
|
g_lua.callGlobalField("g_game", "onClientVersionChange", version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::setAttackingCreature(const CreaturePtr& creature)
|
void Game::setAttackingCreature(const CreaturePtr& creature)
|
||||||
|
|
|
@ -48,7 +48,7 @@ protected:
|
||||||
void processLoginAdvice(const std::string& message);
|
void processLoginAdvice(const std::string& message);
|
||||||
void processLoginWait(const std::string& message, int time);
|
void processLoginWait(const std::string& message, int time);
|
||||||
|
|
||||||
void processGameStart(const LocalPlayerPtr& localPlayer, int serverBeat, bool canReportBugs);
|
void processGameStart();
|
||||||
void processGameEnd();
|
void processGameEnd();
|
||||||
void processDeath(int penality);
|
void processDeath(int penality);
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ protected:
|
||||||
void processInventoryChange(int slot, const ItemPtr& item);
|
void processInventoryChange(int slot, const ItemPtr& item);
|
||||||
void processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos);
|
void processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos);
|
||||||
void processCreatureTeleport(const CreaturePtr& creature);
|
void processCreatureTeleport(const CreaturePtr& creature);
|
||||||
void processAttackCancel();
|
void processAttackCancel(uint seq);
|
||||||
void processWalkCancel(Otc::Direction direction);
|
void processWalkCancel(Otc::Direction direction);
|
||||||
|
|
||||||
// message related
|
// message related
|
||||||
|
@ -232,17 +232,16 @@ public:
|
||||||
void setFeature(Otc::GameFeature feature) { m_features.set(feature, false); }
|
void setFeature(Otc::GameFeature feature) { m_features.set(feature, false); }
|
||||||
bool getFeature(Otc::GameFeature feature) { return m_features.test(feature); }
|
bool getFeature(Otc::GameFeature feature) { return m_features.test(feature); }
|
||||||
|
|
||||||
void setProtocolVersion(int version);
|
void setClientVersion(int version);
|
||||||
int getProtocolVersion() { return m_protocolVersion; }
|
int getClientVersion() { return m_protocolVersion; }
|
||||||
|
|
||||||
void setRSA(const std::string& rsa);
|
void setRSA(const std::string& rsa);
|
||||||
std::string getRSA() { return m_rsa; }
|
std::string getRSA() { return m_rsa; }
|
||||||
|
|
||||||
bool canPerformGameAction();
|
bool canPerformGameAction();
|
||||||
bool canReportBugs() { return m_canReportBugs; }
|
|
||||||
bool checkBotProtection();
|
bool checkBotProtection();
|
||||||
|
|
||||||
bool isOnline() { return !!m_localPlayer; }
|
bool isOnline() { return m_online; }
|
||||||
bool isDead() { return m_dead; }
|
bool isDead() { return m_dead; }
|
||||||
bool isAttacking() { return !!m_attackingCreature; }
|
bool isAttacking() { return !!m_attackingCreature; }
|
||||||
bool isFollowing() { return !!m_followingCreature; }
|
bool isFollowing() { return !!m_followingCreature; }
|
||||||
|
@ -253,7 +252,10 @@ public:
|
||||||
std::map<int, Vip> getVips() { return m_vips; }
|
std::map<int, Vip> getVips() { return m_vips; }
|
||||||
CreaturePtr getAttackingCreature() { return m_attackingCreature; }
|
CreaturePtr getAttackingCreature() { return m_attackingCreature; }
|
||||||
CreaturePtr getFollowingCreature() { return m_followingCreature; }
|
CreaturePtr getFollowingCreature() { return m_followingCreature; }
|
||||||
|
void setServerBeat(int beat) { m_serverBeat = beat; }
|
||||||
int getServerBeat() { return m_serverBeat; }
|
int getServerBeat() { return m_serverBeat; }
|
||||||
|
void setCanReportBugs(bool enable) { m_canReportBugs = enable; }
|
||||||
|
bool canReportBugs() { return m_canReportBugs; }
|
||||||
LocalPlayerPtr getLocalPlayer() { return m_localPlayer; }
|
LocalPlayerPtr getLocalPlayer() { return m_localPlayer; }
|
||||||
ProtocolGamePtr getProtocolGame() { return m_protocolGame; }
|
ProtocolGamePtr getProtocolGame() { return m_protocolGame; }
|
||||||
std::string getCharacterName() { return m_characterName; }
|
std::string getCharacterName() { return m_characterName; }
|
||||||
|
@ -275,10 +277,12 @@ private:
|
||||||
std::map<int, ContainerPtr> m_containers;
|
std::map<int, ContainerPtr> m_containers;
|
||||||
std::map<int, Vip> m_vips;
|
std::map<int, Vip> m_vips;
|
||||||
|
|
||||||
|
bool m_online;
|
||||||
bool m_denyBotCall;
|
bool m_denyBotCall;
|
||||||
bool m_dead;
|
bool m_dead;
|
||||||
bool m_mounted;
|
bool m_mounted;
|
||||||
int m_serverBeat;
|
int m_serverBeat;
|
||||||
|
uint m_seq;
|
||||||
Otc::FightModes m_fightMode;
|
Otc::FightModes m_fightMode;
|
||||||
Otc::ChaseModes m_chaseMode;
|
Otc::ChaseModes m_chaseMode;
|
||||||
bool m_safeFight;
|
bool m_safeFight;
|
||||||
|
|
|
@ -187,8 +187,8 @@ void Item::setOtbId(uint16 id)
|
||||||
{
|
{
|
||||||
if(!g_things.isValidOtbId(id))
|
if(!g_things.isValidOtbId(id))
|
||||||
id = 0;
|
id = 0;
|
||||||
auto otbType = g_things.getItemType(id);
|
auto itemType = g_things.getItemType(id);
|
||||||
m_id = otbType->getClientId();
|
m_id = itemType->getClientId();
|
||||||
m_otbId = id;
|
m_otbId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,8 +194,8 @@ void OTClient::registerLuaFunctions()
|
||||||
g_lua.bindSingletonFunction("g_game", "getServerBeat", &Game::getServerBeat, &g_game);
|
g_lua.bindSingletonFunction("g_game", "getServerBeat", &Game::getServerBeat, &g_game);
|
||||||
g_lua.bindSingletonFunction("g_game", "getLocalPlayer", &Game::getLocalPlayer, &g_game);
|
g_lua.bindSingletonFunction("g_game", "getLocalPlayer", &Game::getLocalPlayer, &g_game);
|
||||||
g_lua.bindSingletonFunction("g_game", "getProtocolGame", &Game::getProtocolGame, &g_game);
|
g_lua.bindSingletonFunction("g_game", "getProtocolGame", &Game::getProtocolGame, &g_game);
|
||||||
g_lua.bindSingletonFunction("g_game", "getProtocolVersion", &Game::getProtocolVersion, &g_game);
|
g_lua.bindSingletonFunction("g_game", "getClientVersion", &Game::getClientVersion, &g_game);
|
||||||
g_lua.bindSingletonFunction("g_game", "setProtocolVersion", &Game::setProtocolVersion, &g_game);
|
g_lua.bindSingletonFunction("g_game", "setClientVersion", &Game::setClientVersion, &g_game);
|
||||||
g_lua.bindSingletonFunction("g_game", "getCharacterName", &Game::getCharacterName, &g_game);
|
g_lua.bindSingletonFunction("g_game", "getCharacterName", &Game::getCharacterName, &g_game);
|
||||||
g_lua.bindSingletonFunction("g_game", "getWorldName", &Game::getWorldName, &g_game);
|
g_lua.bindSingletonFunction("g_game", "getWorldName", &Game::getWorldName, &g_game);
|
||||||
g_lua.bindSingletonFunction("g_game", "getGMActions", &Game::getGMActions, &g_game);
|
g_lua.bindSingletonFunction("g_game", "getGMActions", &Game::getGMActions, &g_game);
|
||||||
|
|
|
@ -518,7 +518,7 @@ void Map::saveOtcm(const std::string& fileName)
|
||||||
// version 1 header
|
// version 1 header
|
||||||
fin->addString("OTCM 1.0"); // map description
|
fin->addString("OTCM 1.0"); // map description
|
||||||
fin->addU32(g_things.getDatSignature());
|
fin->addU32(g_things.getDatSignature());
|
||||||
fin->addU16(g_game.getProtocolVersion());
|
fin->addU16(g_game.getClientVersion());
|
||||||
fin->addString(g_game.getWorldName());
|
fin->addString(g_game.getWorldName());
|
||||||
|
|
||||||
// go back and rewrite where the map data starts
|
// go back and rewrite where the map data starts
|
||||||
|
|
|
@ -175,7 +175,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TileMap m_tiles;
|
TileMap m_tiles;
|
||||||
std::map<uint32, CreaturePtr> m_knownCreatures;
|
std::unordered_map<uint32, CreaturePtr> m_knownCreatures;
|
||||||
std::array<std::vector<MissilePtr>, Otc::MAX_Z+1> m_floorMissiles;
|
std::array<std::vector<MissilePtr>, Otc::MAX_Z+1> m_floorMissiles;
|
||||||
std::vector<AnimatedTextPtr> m_animatedTexts;
|
std::vector<AnimatedTextPtr> m_animatedTexts;
|
||||||
std::vector<StaticTextPtr> m_staticTexts;
|
std::vector<StaticTextPtr> m_staticTexts;
|
||||||
|
|
|
@ -81,6 +81,6 @@ void OTClient::terminate()
|
||||||
{
|
{
|
||||||
g_map.terminate();
|
g_map.terminate();
|
||||||
g_things.terminate();
|
g_things.terminate();
|
||||||
g_sprites.termiante();
|
g_sprites.terminate();
|
||||||
g_shaders.terminate();
|
g_shaders.terminate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,8 @@ namespace Proto {
|
||||||
GameServerMarketEnter = 246, // 944
|
GameServerMarketEnter = 246, // 944
|
||||||
GameServerMarketLeave = 247, // 944
|
GameServerMarketLeave = 247, // 944
|
||||||
GameServerMarketDetail = 248, // 944
|
GameServerMarketDetail = 248, // 944
|
||||||
GameServerMarketBrowse = 249 // 944
|
GameServerMarketBrowse = 249, // 944
|
||||||
|
GameServerShowModalDialog = 250 // 960
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ClientOpcodes {
|
enum ClientOpcodes {
|
||||||
|
|
|
@ -44,8 +44,7 @@ void ProtocolGame::onConnect()
|
||||||
{
|
{
|
||||||
Protocol::onConnect();
|
Protocol::onConnect();
|
||||||
|
|
||||||
// must create local player before parsing anything
|
m_localPlayer = g_game.getLocalPlayer();
|
||||||
m_localPlayer = LocalPlayerPtr(new LocalPlayer);
|
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GameProtocolChecksum))
|
if(g_game.getFeature(Otc::GameProtocolChecksum))
|
||||||
enableChecksum();
|
enableChecksum();
|
||||||
|
|
|
@ -79,14 +79,14 @@ public:
|
||||||
void sendOpenPrivateChannel(const std::string& receiver);
|
void sendOpenPrivateChannel(const std::string& receiver);
|
||||||
void sendCloseNpcChannel();
|
void sendCloseNpcChannel();
|
||||||
void sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight);
|
void sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight);
|
||||||
void sendAttack(uint creatureId);
|
void sendAttack(uint creatureId, uint seq);
|
||||||
void sendFollow(uint creatureId);
|
void sendFollow(uint creatureId, uint seq);
|
||||||
void sendInviteToParty(uint creatureId);
|
void sendInviteToParty(uint creatureId);
|
||||||
void sendJoinParty(uint creatureId);
|
void sendJoinParty(uint creatureId);
|
||||||
void sendRevokeInvitation(uint creatureId);
|
void sendRevokeInvitation(uint creatureId);
|
||||||
void sendPassLeadership(uint creatureId);
|
void sendPassLeadership(uint creatureId);
|
||||||
void sendLeaveParty();
|
void sendLeaveParty();
|
||||||
void sendShareExperience(bool active, int unknown);
|
void sendShareExperience(bool active);
|
||||||
void sendOpenOwnChannel();
|
void sendOpenOwnChannel();
|
||||||
void sendInviteToOwnChannel(const std::string& name);
|
void sendInviteToOwnChannel(const std::string& name);
|
||||||
void sendExcludeFromOwnChannel(const std::string& name);
|
void sendExcludeFromOwnChannel(const std::string& name);
|
||||||
|
@ -166,9 +166,9 @@ private:
|
||||||
void parsePlayerSkills(const InputMessagePtr& msg);
|
void parsePlayerSkills(const InputMessagePtr& msg);
|
||||||
void parsePlayerState(const InputMessagePtr& msg);
|
void parsePlayerState(const InputMessagePtr& msg);
|
||||||
void parsePlayerCancelAttack(const InputMessagePtr& msg);
|
void parsePlayerCancelAttack(const InputMessagePtr& msg);
|
||||||
void parseSpellDelay(const InputMessagePtr& msg);
|
void parseSpellCooldown(const InputMessagePtr& msg);
|
||||||
void parseSpellGroupDelay(const InputMessagePtr& msg);
|
void parseSpellGroupCooldown(const InputMessagePtr& msg);
|
||||||
void parseMultiUseDelay(const InputMessagePtr& msg);
|
void parseMultiUseCooldown(const InputMessagePtr& msg);
|
||||||
void parseCreatureSpeak(const InputMessagePtr& msg);
|
void parseCreatureSpeak(const InputMessagePtr& msg);
|
||||||
void parseChannelList(const InputMessagePtr& msg);
|
void parseChannelList(const InputMessagePtr& msg);
|
||||||
void parseOpenChannel(const InputMessagePtr& msg);
|
void parseOpenChannel(const InputMessagePtr& msg);
|
||||||
|
@ -198,15 +198,17 @@ private:
|
||||||
void parseChannelEvent(const InputMessagePtr& msg);
|
void parseChannelEvent(const InputMessagePtr& msg);
|
||||||
void parseItemInfo(const InputMessagePtr& msg);
|
void parseItemInfo(const InputMessagePtr& msg);
|
||||||
void parsePlayerInventory(const InputMessagePtr& msg);
|
void parsePlayerInventory(const InputMessagePtr& msg);
|
||||||
|
void parseShowModalDialog(const InputMessagePtr& msg);
|
||||||
void parseExtendedOpcode(const InputMessagePtr& msg);
|
void parseExtendedOpcode(const InputMessagePtr& msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setMapDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height);
|
void setMapDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height);
|
||||||
int setFloorDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height, int offset, int skip);
|
int setFloorDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height, int offset, int skip);
|
||||||
void setTileDescription(const InputMessagePtr& msg, Position position);
|
int setTileDescription(const InputMessagePtr& msg, Position position);
|
||||||
|
|
||||||
Outfit getOutfit(const InputMessagePtr& msg);
|
Outfit getOutfit(const InputMessagePtr& msg);
|
||||||
ThingPtr getThing(const InputMessagePtr& msg);
|
ThingPtr getThing(const InputMessagePtr& msg);
|
||||||
|
ThingPtr getMappedThing(const InputMessagePtr& msg);
|
||||||
CreaturePtr getCreature(const InputMessagePtr& msg, int type = 0);
|
CreaturePtr getCreature(const InputMessagePtr& msg, int type = 0);
|
||||||
ItemPtr getItem(const InputMessagePtr& msg, int id = 0);
|
ItemPtr getItem(const InputMessagePtr& msg, int id = 0);
|
||||||
Position getPosition(const InputMessagePtr& msg);
|
Position getPosition(const InputMessagePtr& msg);
|
||||||
|
|
|
@ -35,13 +35,18 @@
|
||||||
|
|
||||||
void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
int opcode = 0;
|
int opcode = -1;
|
||||||
int prevOpcode = 0;
|
int prevOpcode = -1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while(!msg->eof()) {
|
while(!msg->eof()) {
|
||||||
opcode = msg->getU8();
|
opcode = msg->getU8();
|
||||||
|
|
||||||
|
if(!m_gameInitialized && opcode >= Proto::GameServerFirstGameOpcode) {
|
||||||
|
g_game.processGameStart();
|
||||||
|
m_gameInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
// try to parse in lua first
|
// try to parse in lua first
|
||||||
int readPos = msg->getReadPos();
|
int readPos = msg->getReadPos();
|
||||||
if(callLuaField<bool>("onOpcode", opcode, msg))
|
if(callLuaField<bool>("onOpcode", opcode, msg))
|
||||||
|
@ -49,9 +54,6 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
||||||
else
|
else
|
||||||
msg->setReadPos(readPos); // restore read pos
|
msg->setReadPos(readPos); // restore read pos
|
||||||
|
|
||||||
if(!m_gameInitialized && opcode > Proto::GameServerFirstGameOpcode)
|
|
||||||
g_logger.warning("received a game opcode from the server, but the game is not initialized yet, this is a server side bug");
|
|
||||||
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
case Proto::GameServerInitGame:
|
case Proto::GameServerInitGame:
|
||||||
parseInitGame(msg);
|
parseInitGame(msg);
|
||||||
|
@ -70,8 +72,8 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
||||||
break;
|
break;
|
||||||
case Proto::GameServerPing:
|
case Proto::GameServerPing:
|
||||||
case Proto::GameServerPingBack:
|
case Proto::GameServerPingBack:
|
||||||
if((opcode == Proto::GameServerPing && g_game.getProtocolVersion() >= 953) ||
|
if((opcode == Proto::GameServerPing && g_game.getClientVersion() >= 953) ||
|
||||||
(opcode == Proto::GameServerPingBack && g_game.getProtocolVersion() < 953))
|
(opcode == Proto::GameServerPingBack && g_game.getClientVersion() < 953))
|
||||||
parsePingBack(msg);
|
parsePingBack(msg);
|
||||||
else
|
else
|
||||||
parsePing(msg);
|
parsePing(msg);
|
||||||
|
@ -279,13 +281,13 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
||||||
break;
|
break;
|
||||||
// PROTOCOL>=870
|
// PROTOCOL>=870
|
||||||
case Proto::GameServerSpellDelay:
|
case Proto::GameServerSpellDelay:
|
||||||
parseSpellDelay(msg);
|
parseSpellCooldown(msg);
|
||||||
break;
|
break;
|
||||||
case Proto::GameServerSpellGroupDelay:
|
case Proto::GameServerSpellGroupDelay:
|
||||||
parseSpellGroupDelay(msg);
|
parseSpellGroupCooldown(msg);
|
||||||
break;
|
break;
|
||||||
case Proto::GameServerMultiUseDelay:
|
case Proto::GameServerMultiUseDelay:
|
||||||
parseMultiUseDelay(msg);
|
parseMultiUseCooldown(msg);
|
||||||
break;
|
break;
|
||||||
// PROTOCOL>=910
|
// PROTOCOL>=910
|
||||||
case Proto::GameServerChannelEvent:
|
case Proto::GameServerChannelEvent:
|
||||||
|
@ -306,7 +308,7 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
||||||
parseExtendedOpcode(msg);
|
parseExtendedOpcode(msg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
stdext::throw_exception("unknown opcode");
|
stdext::throw_exception(stdext::format("unhandled opcode %d", (int)opcode));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prevOpcode = opcode;
|
prevOpcode = opcode;
|
||||||
|
@ -319,13 +321,13 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
||||||
|
|
||||||
void ProtocolGame::parseInitGame(const InputMessagePtr& msg)
|
void ProtocolGame::parseInitGame(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
m_gameInitialized = true;
|
|
||||||
uint playerId = msg->getU32();
|
uint playerId = msg->getU32();
|
||||||
int serverBeat = msg->getU16();
|
int serverBeat = msg->getU16();
|
||||||
bool canReportBugs = msg->getU8();
|
bool canReportBugs = msg->getU8();
|
||||||
|
|
||||||
m_localPlayer->setId(playerId);
|
m_localPlayer->setId(playerId);
|
||||||
g_game.processGameStart(m_localPlayer, serverBeat, canReportBugs);
|
g_game.setServerBeat(serverBeat);
|
||||||
|
g_game.setCanReportBugs(canReportBugs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseGMActions(const InputMessagePtr& msg)
|
void ProtocolGame::parseGMActions(const InputMessagePtr& msg)
|
||||||
|
@ -334,9 +336,9 @@ void ProtocolGame::parseGMActions(const InputMessagePtr& msg)
|
||||||
|
|
||||||
int numViolationReasons;
|
int numViolationReasons;
|
||||||
|
|
||||||
if(g_game.getProtocolVersion() >= 860)
|
if(g_game.getClientVersion() >= 860)
|
||||||
numViolationReasons = 20;
|
numViolationReasons = 20;
|
||||||
else if(g_game.getProtocolVersion() >= 854)
|
else if(g_game.getClientVersion() >= 854)
|
||||||
numViolationReasons = 19;
|
numViolationReasons = 19;
|
||||||
else
|
else
|
||||||
numViolationReasons = 32;
|
numViolationReasons = 32;
|
||||||
|
@ -454,7 +456,7 @@ void ProtocolGame::parseTileAddThing(const InputMessagePtr& msg)
|
||||||
Position pos = getPosition(msg);
|
Position pos = getPosition(msg);
|
||||||
int stackPos = -1;
|
int stackPos = -1;
|
||||||
|
|
||||||
if(g_game.getProtocolVersion() >= 854)
|
if(g_game.getClientVersion() >= 854)
|
||||||
stackPos = msg->getU8();
|
stackPos = msg->getU8();
|
||||||
|
|
||||||
ThingPtr thing = getThing(msg);
|
ThingPtr thing = getThing(msg);
|
||||||
|
@ -463,54 +465,54 @@ void ProtocolGame::parseTileAddThing(const InputMessagePtr& msg)
|
||||||
|
|
||||||
void ProtocolGame::parseTileTransformThing(const InputMessagePtr& msg)
|
void ProtocolGame::parseTileTransformThing(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
Position pos = getPosition(msg);
|
ThingPtr thing = getMappedThing(msg);
|
||||||
int stackPos = msg->getU8();
|
ThingPtr newThing = getThing(msg);
|
||||||
|
|
||||||
ThingPtr thing = getThing(msg);
|
if(!thing) {
|
||||||
if(thing) {
|
g_logger.traceError("no thing");
|
||||||
if(!g_map.removeThingByPos(pos, stackPos))
|
return;
|
||||||
g_logger.traceError("could not remove thing");
|
|
||||||
g_map.addThing(thing, pos, stackPos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Position pos = thing->getPosition();
|
||||||
|
int stackpos = thing->getStackpos();
|
||||||
|
assert(thing->getStackPriority() == newThing->getStackPriority());
|
||||||
|
|
||||||
|
if(!g_map.removeThing(thing)) {
|
||||||
|
g_logger.traceError("unable to remove thing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_map.addThing(newThing, pos, stackpos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseTileRemoveThing(const InputMessagePtr& msg)
|
void ProtocolGame::parseTileRemoveThing(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
Position pos = getPosition(msg);
|
ThingPtr thing = getMappedThing(msg);
|
||||||
int stackPos = msg->getU8();
|
if(!thing) {
|
||||||
|
g_logger.traceError("no thing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(!g_map.removeThingByPos(pos, stackPos))
|
g_map.removeThing(thing);
|
||||||
g_logger.traceError("could not remove thing");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg)
|
void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
Position oldPos = getPosition(msg);
|
ThingPtr thing = getMappedThing(msg);
|
||||||
int oldStackpos = msg->getU8();
|
|
||||||
Position newPos = getPosition(msg);
|
Position newPos = getPosition(msg);
|
||||||
|
|
||||||
ThingPtr thing = g_map.getThing(oldPos, oldStackpos);
|
if(!thing || !thing->isCreature()) {
|
||||||
if(!thing) {
|
g_logger.traceError("no creature found to move");
|
||||||
g_logger.traceError("could not get thing");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CreaturePtr creature = thing->asCreature();
|
|
||||||
if(!creature) {
|
|
||||||
g_logger.traceError("thing is not a creature");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update map tiles
|
|
||||||
if(!g_map.removeThing(thing))
|
|
||||||
g_logger.traceError("could not remove thing");
|
|
||||||
|
|
||||||
int stackPos = -2;
|
int stackPos = -2;
|
||||||
|
// newer protocols stores creatures in reverse order
|
||||||
// older protocols stores creatures in reverse order
|
if(!g_game.getClientVersion() >= 854)
|
||||||
if(!g_game.getProtocolVersion() >= 854)
|
|
||||||
stackPos = -1;
|
stackPos = -1;
|
||||||
|
|
||||||
|
g_map.removeThing(thing);
|
||||||
g_map.addThing(thing, newPos, stackPos);
|
g_map.addThing(thing, newPos, stackPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -887,7 +889,7 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
|
||||||
m_localPlayer->setStamina(stamina);
|
m_localPlayer->setStamina(stamina);
|
||||||
m_localPlayer->setSoul(soul);
|
m_localPlayer->setSoul(soul);
|
||||||
|
|
||||||
if(g_game.getProtocolVersion() >= 910)
|
if(g_game.getClientVersion() >= 910)
|
||||||
m_localPlayer->setSpeed(msg->getU16());
|
m_localPlayer->setSpeed(msg->getU16());
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GamePlayerRegenerationTime))
|
if(g_game.getFeature(Otc::GamePlayerRegenerationTime))
|
||||||
|
@ -918,29 +920,28 @@ void ProtocolGame::parsePlayerState(const InputMessagePtr& msg)
|
||||||
|
|
||||||
void ProtocolGame::parsePlayerCancelAttack(const InputMessagePtr& msg)
|
void ProtocolGame::parsePlayerCancelAttack(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
if(g_game.getProtocolVersion() >= 860)
|
uint seq = 0;
|
||||||
msg->getU32(); // unknown
|
if(g_game.getClientVersion() >= 860)
|
||||||
|
seq = msg->getU32();
|
||||||
|
|
||||||
g_game.processAttackCancel();
|
g_game.processAttackCancel(seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseSpellDelay(const InputMessagePtr& msg)
|
void ProtocolGame::parseSpellCooldown(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
msg->getU16(); // spell id
|
msg->getU16(); // spell id
|
||||||
msg->getU16(); // cooldown
|
msg->getU32(); // cooldown
|
||||||
msg->getU8(); // unknown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseSpellGroupDelay(const InputMessagePtr& msg)
|
void ProtocolGame::parseSpellGroupCooldown(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
msg->getU16(); // spell id
|
msg->getU8(); // group id
|
||||||
msg->getU16(); // cooldown
|
msg->getU32(); // cooldown
|
||||||
msg->getU8(); // unknown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseMultiUseDelay(const InputMessagePtr& msg)
|
void ProtocolGame::parseMultiUseCooldown(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
//TODO
|
msg->getU32(); // cooldown
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseCreatureSpeak(const InputMessagePtr& msg)
|
void ProtocolGame::parseCreatureSpeak(const InputMessagePtr& msg)
|
||||||
|
@ -1225,18 +1226,36 @@ void ProtocolGame::parseChannelEvent(const InputMessagePtr& msg)
|
||||||
|
|
||||||
void ProtocolGame::parseItemInfo(const InputMessagePtr& msg)
|
void ProtocolGame::parseItemInfo(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
/*int count = msg.getU16() - 1;
|
int size = msg->getU8();
|
||||||
for(int i = 0; i < count; i++)
|
for(int i=0;i<size;++i) {
|
||||||
{
|
msg->getU16(); // id
|
||||||
int unknown1 = msg->getU8();
|
msg->getU8(); // subtype
|
||||||
int unknown2 = msg->getU16();
|
msg->getString(); // description
|
||||||
std::string unknown3 = msg->getString();
|
}
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parsePlayerInventory(const InputMessagePtr& msg)
|
void ProtocolGame::parsePlayerInventory(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
//TODO
|
int size = msg->getU16();
|
||||||
|
for(int i=0;i<size;++i) {
|
||||||
|
msg->getU16(); // id
|
||||||
|
msg->getU8(); // subtype
|
||||||
|
msg->getU16(); // count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseShowModalDialog(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
msg->getU32(); // id
|
||||||
|
msg->getString(); // title
|
||||||
|
msg->getString(); // message
|
||||||
|
int size = msg->getU8();
|
||||||
|
for(int i=0;i<size;++i) {
|
||||||
|
msg->getString(); // button name
|
||||||
|
msg->getU8(); // button value
|
||||||
|
}
|
||||||
|
msg->getU8(); // default escape button
|
||||||
|
msg->getU8(); // default enter button
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg)
|
void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg)
|
||||||
|
@ -1275,51 +1294,41 @@ int ProtocolGame::setFloorDescription(const InputMessagePtr& msg, int x, int y,
|
||||||
for(int nx = 0; nx < width; nx++) {
|
for(int nx = 0; nx < width; nx++) {
|
||||||
for(int ny = 0; ny < height; ny++) {
|
for(int ny = 0; ny < height; ny++) {
|
||||||
Position tilePos(x + nx + offset, y + ny + offset, z);
|
Position tilePos(x + nx + offset, y + ny + offset, z);
|
||||||
|
if(skip == 0)
|
||||||
// clean pre stored tiles
|
skip = setTileDescription(msg, tilePos);
|
||||||
g_map.cleanTile(tilePos);
|
|
||||||
|
|
||||||
if(skip == 0) {
|
|
||||||
int tileOpt = msg->peekU16();
|
|
||||||
if(tileOpt >= 0xFF00)
|
|
||||||
skip = (msg->getU16() & 0xFF);
|
|
||||||
else {
|
else {
|
||||||
setTileDescription(msg, tilePos);
|
g_map.cleanTile(tilePos);
|
||||||
skip = (msg->getU16() & 0xFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
skip--;
|
skip--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return skip;
|
return skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position position)
|
int ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position position)
|
||||||
{
|
{
|
||||||
if(g_game.getFeature(Otc::GameEnvironmentEffect))
|
|
||||||
msg->getU16(); // environment effect
|
|
||||||
|
|
||||||
|
|
||||||
g_map.cleanTile(position);
|
g_map.cleanTile(position);
|
||||||
|
|
||||||
int stackPos = 0;
|
bool gotEffect = 0;
|
||||||
while(true) {
|
for(int stackPos=0;stackPos<256;stackPos++) {
|
||||||
int inspectItemId = msg->peekU16();
|
if(msg->peekU16() >= 0xff00)
|
||||||
if(inspectItemId >= 0xFF00) {
|
return msg->getU16() & 0xff;
|
||||||
return;
|
|
||||||
|
if(g_game.getFeature(Otc::GameEnvironmentEffect) && !gotEffect) {
|
||||||
|
msg->getU16(); // environment effect
|
||||||
|
gotEffect = true;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if(stackPos >= 10)
|
if(stackPos > 10)
|
||||||
g_logger.traceError(stdext::format("too many things, stackpos=%d, pos=%s", stackPos, stdext::to_string(position)));
|
g_logger.traceError(stdext::format("too many things, pos=%s, stackpos=%d", stdext::to_string(position), stackPos));
|
||||||
|
|
||||||
ThingPtr thing = getThing(msg);
|
ThingPtr thing = getThing(msg);
|
||||||
g_map.addThing(thing, position, -2);
|
g_map.addThing(thing, position, -2);
|
||||||
}
|
}
|
||||||
stackPos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg)
|
Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
Outfit outfit;
|
Outfit outfit;
|
||||||
|
@ -1376,6 +1385,31 @@ ThingPtr ProtocolGame::getThing(const InputMessagePtr& msg)
|
||||||
return thing;
|
return thing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThingPtr ProtocolGame::getMappedThing(const InputMessagePtr& msg)
|
||||||
|
{
|
||||||
|
ThingPtr thing;
|
||||||
|
uint16 x = msg->getU16();
|
||||||
|
|
||||||
|
if(x != 0xffff) {
|
||||||
|
Position pos;
|
||||||
|
pos.x = x;
|
||||||
|
pos.y = msg->getU16();
|
||||||
|
pos.z = msg->getU8();
|
||||||
|
uint8 stackpos = msg->getU8();
|
||||||
|
assert(stackpos != 255);
|
||||||
|
thing = g_map.getThing(pos, stackpos);
|
||||||
|
if(!thing)
|
||||||
|
g_logger.traceError(stdext::format("no thing at pos:%s, stackpos:%d", stdext::to_string(pos), stackpos));
|
||||||
|
} else {
|
||||||
|
uint32 id = msg->getU32();
|
||||||
|
thing = g_map.getCreatureById(id);
|
||||||
|
if(!thing)
|
||||||
|
g_logger.traceError(stdext::format("no creature with id %u", id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return thing;
|
||||||
|
}
|
||||||
|
|
||||||
CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
||||||
{
|
{
|
||||||
if(type == 0)
|
if(type == 0)
|
||||||
|
@ -1397,7 +1431,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
||||||
uint id = msg->getU32();
|
uint id = msg->getU32();
|
||||||
|
|
||||||
int creatureType;
|
int creatureType;
|
||||||
if(g_game.getProtocolVersion() >= 910)
|
if(g_game.getClientVersion() >= 910)
|
||||||
creatureType = msg->getU8();
|
creatureType = msg->getU8();
|
||||||
else {
|
else {
|
||||||
if(id >= Proto::PlayerStartId && id < Proto::PlayerEndId)
|
if(id >= Proto::PlayerStartId && id < Proto::PlayerEndId)
|
||||||
|
@ -1416,8 +1450,13 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
||||||
|
|
||||||
if(id == m_localPlayer->getId())
|
if(id == m_localPlayer->getId())
|
||||||
creature = m_localPlayer;
|
creature = m_localPlayer;
|
||||||
else if(creatureType == Proto::CreatureTypePlayer)
|
else if(creatureType == Proto::CreatureTypePlayer) {
|
||||||
|
// fixes a bug server side bug where GameInit is not sent and local player id is unknown
|
||||||
|
if(m_localPlayer->getId() == 0 && name == m_localPlayer->getName())
|
||||||
|
creature = m_localPlayer;
|
||||||
|
else
|
||||||
creature = PlayerPtr(new Player);
|
creature = PlayerPtr(new Player);
|
||||||
|
}
|
||||||
else if(creatureType == Proto::CreatureTypeMonster)
|
else if(creatureType == Proto::CreatureTypeMonster)
|
||||||
creature = MonsterPtr(new Monster);
|
creature = MonsterPtr(new Monster);
|
||||||
else if(creatureType == Proto::CreatureTypeNpc)
|
else if(creatureType == Proto::CreatureTypeNpc)
|
||||||
|
@ -1447,13 +1486,13 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
||||||
|
|
||||||
// emblem is sent only when the creature is not known
|
// emblem is sent only when the creature is not known
|
||||||
int emblem = -1;
|
int emblem = -1;
|
||||||
bool passable = false;
|
bool unpass = true;
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GameCreatureEmblems) && !known)
|
if(g_game.getFeature(Otc::GameCreatureEmblems) && !known)
|
||||||
emblem = msg->getU8();
|
emblem = msg->getU8();
|
||||||
|
|
||||||
if(g_game.getProtocolVersion() >= 854)
|
if(g_game.getClientVersion() >= 854)
|
||||||
passable = (msg->getU8() == 0);
|
unpass = msg->getU8();
|
||||||
|
|
||||||
if(creature) {
|
if(creature) {
|
||||||
creature->setHealthPercent(healthPercent);
|
creature->setHealthPercent(healthPercent);
|
||||||
|
@ -1465,7 +1504,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
||||||
creature->setShield(shield);
|
creature->setShield(shield);
|
||||||
if(emblem != -1)
|
if(emblem != -1)
|
||||||
creature->setEmblem(emblem);
|
creature->setEmblem(emblem);
|
||||||
creature->setPassable(passable);
|
creature->setPassable(!unpass);
|
||||||
|
|
||||||
if(creature == m_localPlayer && !m_localPlayer->isKnown())
|
if(creature == m_localPlayer && !m_localPlayer->isKnown())
|
||||||
m_localPlayer->setKnown(true);
|
m_localPlayer->setKnown(true);
|
||||||
|
@ -1481,11 +1520,11 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
||||||
if(creature)
|
if(creature)
|
||||||
creature->turn(direction);
|
creature->turn(direction);
|
||||||
|
|
||||||
if(g_game.getProtocolVersion() >= 953) {
|
if(g_game.getClientVersion() >= 953) {
|
||||||
bool passable = msg->getU8();
|
bool unpass = msg->getU8();
|
||||||
|
|
||||||
if(creature)
|
if(creature)
|
||||||
creature->setPassable(passable);
|
creature->setPassable(!unpass);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -1502,7 +1541,7 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
|
||||||
|
|
||||||
ItemPtr item = Item::create(id);
|
ItemPtr item = Item::create(id);
|
||||||
if(item->getId() == 0)
|
if(item->getId() == 0)
|
||||||
stdext::throw_exception("unable to create item with invalid id 0");
|
stdext::throw_exception(stdext::format("unable to create item with invalid id %d", id));
|
||||||
|
|
||||||
if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
|
if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
|
||||||
item->setCountOrSubType(msg->getU8());
|
item->setCountOrSubType(msg->getU8());
|
||||||
|
@ -1511,7 +1550,7 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
|
||||||
if(item->getAnimationPhases() > 1) {
|
if(item->getAnimationPhases() > 1) {
|
||||||
// 0xfe => random phase
|
// 0xfe => random phase
|
||||||
// 0xff => async?
|
// 0xff => async?
|
||||||
msg->getU8();
|
msg->getU8(); // phase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ void ProtocolGame::sendLoginPacket(uint challangeTimestamp, uint8 challangeRando
|
||||||
msg->addU8(Proto::ClientEnterGame);
|
msg->addU8(Proto::ClientEnterGame);
|
||||||
|
|
||||||
msg->addU16(g_lua.callGlobalField<int>("g_game", "getOs"));
|
msg->addU16(g_lua.callGlobalField<int>("g_game", "getOs"));
|
||||||
msg->addU16(g_game.getProtocolVersion());
|
msg->addU16(g_game.getClientVersion());
|
||||||
|
|
||||||
int paddingBytes = 128;
|
int paddingBytes = 128;
|
||||||
msg->addU8(0); // first RSA byte must be 0
|
msg->addU8(0); // first RSA byte must be 0
|
||||||
|
@ -509,21 +509,21 @@ void ProtocolGame::sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseMod
|
||||||
send(msg);
|
send(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::sendAttack(uint creatureId)
|
void ProtocolGame::sendAttack(uint creatureId, uint seq)
|
||||||
{
|
{
|
||||||
OutputMessagePtr msg(new OutputMessage);
|
OutputMessagePtr msg(new OutputMessage);
|
||||||
msg->addU8(Proto::ClientAttack);
|
msg->addU8(Proto::ClientAttack);
|
||||||
msg->addU32(creatureId);
|
msg->addU32(creatureId);
|
||||||
msg->addU32(0);
|
msg->addU32(seq);
|
||||||
msg->addU32(0);
|
|
||||||
send(msg);
|
send(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::sendFollow(uint creatureId)
|
void ProtocolGame::sendFollow(uint creatureId, uint seq)
|
||||||
{
|
{
|
||||||
OutputMessagePtr msg(new OutputMessage);
|
OutputMessagePtr msg(new OutputMessage);
|
||||||
msg->addU8(Proto::ClientFollow);
|
msg->addU8(Proto::ClientFollow);
|
||||||
msg->addU32(creatureId);
|
msg->addU32(creatureId);
|
||||||
|
msg->addU32(seq);
|
||||||
send(msg);
|
send(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,14 +566,14 @@ void ProtocolGame::sendLeaveParty()
|
||||||
send(msg);
|
send(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::sendShareExperience(bool active, int unknown)
|
void ProtocolGame::sendShareExperience(bool active)
|
||||||
{
|
{
|
||||||
OutputMessagePtr msg(new OutputMessage);
|
OutputMessagePtr msg(new OutputMessage);
|
||||||
msg->addU8(Proto::ClientShareExperience);
|
msg->addU8(Proto::ClientShareExperience);
|
||||||
msg->addU8(active ? 0x01 : 0x00);
|
msg->addU8(active ? 0x01 : 0x00);
|
||||||
|
|
||||||
if(g_game.getProtocolVersion() < 910)
|
if(g_game.getClientVersion() < 910)
|
||||||
msg->addU8(unknown);
|
msg->addU8(0);
|
||||||
|
|
||||||
send(msg);
|
send(msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,18 +34,18 @@ SpriteManager::SpriteManager()
|
||||||
m_signature = 0;
|
m_signature = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpriteManager::termiante()
|
void SpriteManager::terminate()
|
||||||
{
|
{
|
||||||
unload();
|
unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpriteManager::loadSpr(const std::string& file)
|
bool SpriteManager::loadSpr(const std::string& file)
|
||||||
{
|
{
|
||||||
|
m_spritesCount = 0;
|
||||||
|
m_signature = 0;
|
||||||
|
m_loaded = false;
|
||||||
try {
|
try {
|
||||||
m_spritesFile = g_resources.openFile(file);
|
m_spritesFile = g_resources.openFile(file);
|
||||||
if(!m_spritesFile)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// cache file buffer to avoid lags from hard drive
|
// cache file buffer to avoid lags from hard drive
|
||||||
m_spritesFile->cache();
|
m_spritesFile->cache();
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ class SpriteManager
|
||||||
public:
|
public:
|
||||||
SpriteManager();
|
SpriteManager();
|
||||||
|
|
||||||
void termiante();
|
void terminate();
|
||||||
|
|
||||||
bool loadSpr(const std::string& file);
|
bool loadSpr(const std::string& file);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
|
@ -66,7 +66,7 @@ ContainerPtr Thing::getParentContainer()
|
||||||
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
|
||||||
return 0;
|
return m_position.z;
|
||||||
else if(const TilePtr& tile = getTile())
|
else if(const TilePtr& tile = getTile())
|
||||||
return tile->getThingStackpos(asThing());
|
return tile->getThingStackpos(asThing());
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -59,16 +59,17 @@ void ThingTypeManager::terminate()
|
||||||
|
|
||||||
bool ThingTypeManager::loadDat(const std::string& file)
|
bool ThingTypeManager::loadDat(const std::string& file)
|
||||||
{
|
{
|
||||||
|
m_datLoaded = false;
|
||||||
|
m_datSignature = 0;
|
||||||
try {
|
try {
|
||||||
FileStreamPtr fin = g_resources.openFile(file);
|
FileStreamPtr fin = g_resources.openFile(file);
|
||||||
if(!fin)
|
|
||||||
stdext::throw_exception("unable to open file");
|
|
||||||
|
|
||||||
m_datSignature = fin->getU32();
|
m_datSignature = fin->getU32();
|
||||||
|
|
||||||
int numThings[ThingLastCategory];
|
int numThings[ThingLastCategory];
|
||||||
for(int category = 0; category < ThingLastCategory; ++category) {
|
for(int category = 0; category < ThingLastCategory; ++category) {
|
||||||
int count = fin->getU16() + 1;
|
int count = fin->getU16() + 1;
|
||||||
|
m_thingTypes[category].clear();
|
||||||
m_thingTypes[category].resize(count, m_nullThingType);
|
m_thingTypes[category].resize(count, m_nullThingType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,9 +115,9 @@ void ThingTypeManager::loadOtb(const std::string& file)
|
||||||
|
|
||||||
m_itemTypes.resize(root->getChildren().size(), m_nullItemType);
|
m_itemTypes.resize(root->getChildren().size(), m_nullItemType);
|
||||||
for(const BinaryTreePtr& node : root->getChildren()) {
|
for(const BinaryTreePtr& node : root->getChildren()) {
|
||||||
ItemTypePtr otbType(new ItemType);
|
ItemTypePtr itemType(new ItemType);
|
||||||
otbType->unserialize(node);
|
itemType->unserialize(node);
|
||||||
addItemType(otbType);
|
addItemType(itemType);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_otbLoaded = true;
|
m_otbLoaded = true;
|
||||||
|
@ -171,25 +172,25 @@ void ThingTypeManager::parseItemType(uint16 id, TiXmlElement* elem)
|
||||||
addItemType(newType);
|
addItemType(newType);
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemTypePtr otbType = getItemType(serverId);
|
ItemTypePtr itemType = getItemType(serverId);
|
||||||
otbType->setName(elem->Attribute("name"));
|
itemType->setName(elem->Attribute("name"));
|
||||||
for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
|
for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
|
||||||
if(attrib->ValueStr() != "attribute")
|
if(attrib->ValueStr() != "attribute")
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(attrib->Attribute("key") == "description") {
|
if(attrib->Attribute("key") == "description") {
|
||||||
otbType->setDesc(attrib->Attribute("value"));
|
itemType->setDesc(attrib->Attribute("value"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThingTypeManager::addItemType(const ItemTypePtr& otbType)
|
void ThingTypeManager::addItemType(const ItemTypePtr& itemType)
|
||||||
{
|
{
|
||||||
uint16 id = otbType->getServerId();
|
uint16 id = itemType->getServerId();
|
||||||
if(m_itemTypes.size() <= id)
|
if(m_itemTypes.size() <= id)
|
||||||
m_itemTypes.resize(id+1, m_nullItemType);
|
m_itemTypes.resize(id+1, m_nullItemType);
|
||||||
m_itemTypes[id] = otbType;
|
m_itemTypes[id] = itemType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ItemTypePtr& ThingTypeManager::findOtbForClientId(uint16 id)
|
const ItemTypePtr& ThingTypeManager::findOtbForClientId(uint16 id)
|
||||||
|
@ -197,9 +198,9 @@ const ItemTypePtr& ThingTypeManager::findOtbForClientId(uint16 id)
|
||||||
if(m_itemTypes.empty())
|
if(m_itemTypes.empty())
|
||||||
return m_nullItemType;
|
return m_nullItemType;
|
||||||
|
|
||||||
for(const ItemTypePtr& otbType : m_itemTypes) {
|
for(const ItemTypePtr& itemType : m_itemTypes) {
|
||||||
if(otbType->getClientId() == id)
|
if(itemType->getClientId() == id)
|
||||||
return otbType;
|
return itemType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_nullItemType;
|
return m_nullItemType;
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
void loadXml(const std::string& file);
|
void loadXml(const std::string& file);
|
||||||
void parseItemType(uint16 id, TiXmlElement *elem);
|
void parseItemType(uint16 id, TiXmlElement *elem);
|
||||||
|
|
||||||
void addItemType(const ItemTypePtr& otbType);
|
void addItemType(const ItemTypePtr& itemType);
|
||||||
const ItemTypePtr& findOtbForClientId(uint16 id);
|
const ItemTypePtr& findOtbForClientId(uint16 id);
|
||||||
|
|
||||||
const ThingTypePtr& getNullThingType() { return m_nullThingType; }
|
const ThingTypePtr& getNullThingType() { return m_nullThingType; }
|
||||||
|
|
|
@ -392,7 +392,7 @@ bool Tile::isWalkable()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(CreaturePtr creature = thing->asCreature()) {
|
if(CreaturePtr creature = thing->asCreature()) {
|
||||||
if(!creature->getPassable())
|
if(!creature->isPassable())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,7 +405,7 @@ bool Tile::isPathable()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for(const ThingPtr& thing : m_things) {
|
for(const ThingPtr& thing : m_things) {
|
||||||
if(thing->isNotPathable())
|
if(thing->isNotPathable() || thing->isCreature())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,4 +507,13 @@ void Tile::update()
|
||||||
if(c != 0)
|
if(c != 0)
|
||||||
m_minimapColorByte = c;
|
m_minimapColorByte = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check stack priorities
|
||||||
|
// this code exists to find stackpos bugs faster
|
||||||
|
int lastPriority = 0;
|
||||||
|
for(const ThingPtr& thing : m_things) {
|
||||||
|
int priority = thing->getStackPriority();
|
||||||
|
assert(lastPriority <= priority);
|
||||||
|
lastPriority = priority;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue