Multi-protocol
Lots of chagnes to add multi protocol flexibility, not really completed yet, still have to rework text messages opcodes and other stuff, so this still a working in progress feature * Rework dat reader, the dat reader can now * dinamically detect dat version * Split game into gamelib and game_interface * Lots of other minor changes
9
init.lua
|
@ -29,17 +29,18 @@ g_configs.load("/config.otml")
|
||||||
|
|
||||||
g_modules.discoverModules()
|
g_modules.discoverModules()
|
||||||
|
|
||||||
-- core modules 0-99
|
-- libraries modules 0-99
|
||||||
g_modules.autoLoadModules(99)
|
g_modules.autoLoadModules(99);
|
||||||
g_modules.ensureModuleLoaded("corelib")
|
g_modules.ensureModuleLoaded("corelib")
|
||||||
|
g_modules.ensureModuleLoaded("gamelib")
|
||||||
|
|
||||||
-- client modules 100-499
|
-- client modules 100-499
|
||||||
g_modules.autoLoadModules(499)
|
g_modules.autoLoadModules(499)
|
||||||
g_modules.ensureModuleLoaded("client")
|
g_modules.ensureModuleLoaded("client")
|
||||||
|
|
||||||
-- game modules 500-999
|
-- game modules 500-999
|
||||||
g_modules.autoLoadModules(999)
|
g_modules.autoLoadModules(999);
|
||||||
g_modules.ensureModuleLoaded("game")
|
g_modules.ensureModuleLoaded("game_interface")
|
||||||
|
|
||||||
-- mods 1000-9999
|
-- mods 1000-9999
|
||||||
g_modules.autoLoadModules(9999)
|
g_modules.autoLoadModules(9999)
|
||||||
|
|
|
@ -16,7 +16,6 @@ Module
|
||||||
- client_terminal
|
- client_terminal
|
||||||
- client_modulemanager
|
- client_modulemanager
|
||||||
- client_entergame
|
- client_entergame
|
||||||
- game
|
|
||||||
|
|
||||||
@onLoad: |
|
@onLoad: |
|
||||||
dofile 'client'
|
dofile 'client'
|
||||||
|
|
|
@ -11,7 +11,6 @@ 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' ..
|
||||||
'Rev ' .. g_app.getBuildRevision() .. ' ('.. g_app.getBuildCommit() .. ')\n' ..
|
'Rev ' .. g_app.getBuildRevision() .. ' ('.. g_app.getBuildCommit() .. ')\n' ..
|
||||||
'Protocol ' .. g_game.getProtocolVersion() .. '\n' ..
|
|
||||||
'Built on ' .. g_app.getBuildDate())
|
'Built on ' .. g_app.getBuildDate())
|
||||||
|
|
||||||
if not g_game.isOnline() then
|
if not g_game.isOnline() then
|
||||||
|
|
|
@ -54,7 +54,7 @@ local function updateWait(timeStart, timeEnd)
|
||||||
progressBar:setPercent(percent)
|
progressBar:setPercent(percent)
|
||||||
|
|
||||||
local label = waitingWindow:getChildById('timeLabel')
|
local label = waitingWindow:getChildById('timeLabel')
|
||||||
label:setText('Trying to reconnect in ' .. timeStr .. ' seconds.')
|
label:setText(tr('Trying to reconnect in %s seconds.', timeStr))
|
||||||
|
|
||||||
updateWaitEvent = scheduleEvent(function() updateWait(timeStart, timeEnd) end, 1000 * progressBar:getPercentPixels() / 100 * (timeEnd - timeStart))
|
updateWaitEvent = scheduleEvent(function() updateWait(timeStart, timeEnd) end, 1000 * progressBar:getPercentPixels() / 100 * (timeEnd - timeStart))
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -5,6 +5,7 @@ local loadBox
|
||||||
local enterGame
|
local enterGame
|
||||||
local motdButton
|
local motdButton
|
||||||
local enterGameButton
|
local enterGameButton
|
||||||
|
local protocolBox
|
||||||
|
|
||||||
-- private functions
|
-- private functions
|
||||||
local function onError(protocol, message, errorCode)
|
local function onError(protocol, message, errorCode)
|
||||||
|
@ -66,6 +67,11 @@ function EnterGame.init()
|
||||||
local host = g_settings.get('host')
|
local host = g_settings.get('host')
|
||||||
local port = g_settings.get('port')
|
local port = g_settings.get('port')
|
||||||
local autologin = g_settings.getBoolean('autologin')
|
local autologin = g_settings.getBoolean('autologin')
|
||||||
|
local protocol = g_settings.getInteger('protocol', 860)
|
||||||
|
|
||||||
|
if not protocol or protocol == 0 then
|
||||||
|
protocol = 860
|
||||||
|
end
|
||||||
|
|
||||||
if port == nil or port == 0 then port = 7171 end
|
if port == nil or port == 0 then port = 7171 end
|
||||||
|
|
||||||
|
@ -77,6 +83,12 @@ function EnterGame.init()
|
||||||
enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0)
|
enterGame:getChildById('rememberPasswordBox'):setChecked(#account > 0)
|
||||||
enterGame:getChildById('accountNameTextEdit'):focus()
|
enterGame:getChildById('accountNameTextEdit'):focus()
|
||||||
|
|
||||||
|
protocolBox = enterGame:getChildById('protocolComboBox')
|
||||||
|
for _i,proto in pairs(g_game.getSupportedProtocols()) do
|
||||||
|
protocolBox:addOption(proto)
|
||||||
|
end
|
||||||
|
protocolBox:setCurrentOption(protocol)
|
||||||
|
|
||||||
-- only open entergame when app starts
|
-- only open entergame when app starts
|
||||||
if not g_app.isRunning() then
|
if not g_app.isRunning() then
|
||||||
if #host > 0 and #password > 0 and #account > 0 and autologin then
|
if #host > 0 and #password > 0 and #account > 0 and autologin then
|
||||||
|
@ -95,6 +107,7 @@ function EnterGame.terminate()
|
||||||
enterGameButton = nil
|
enterGameButton = nil
|
||||||
motdButton:destroy()
|
motdButton:destroy()
|
||||||
motdButton = nil
|
motdButton = nil
|
||||||
|
protocolBox = nil
|
||||||
EnterGame = nil
|
EnterGame = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -116,7 +129,6 @@ function EnterGame.openWindow()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function EnterGame.clearAccountFields()
|
function EnterGame.clearAccountFields()
|
||||||
enterGame:getChildById('accountNameTextEdit'):clearText()
|
enterGame:getChildById('accountNameTextEdit'):clearText()
|
||||||
enterGame:getChildById('accountPasswordTextEdit'):clearText()
|
enterGame:getChildById('accountPasswordTextEdit'):clearText()
|
||||||
|
@ -130,16 +142,18 @@ function EnterGame.doLogin()
|
||||||
G.password = enterGame:getChildById('accountPasswordTextEdit'):getText()
|
G.password = enterGame:getChildById('accountPasswordTextEdit'):getText()
|
||||||
G.host = enterGame:getChildById('serverHostTextEdit'):getText()
|
G.host = enterGame:getChildById('serverHostTextEdit'):getText()
|
||||||
G.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText())
|
G.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText())
|
||||||
|
local protocol = tonumber(protocolBox:getText())
|
||||||
EnterGame.hide()
|
EnterGame.hide()
|
||||||
|
|
||||||
if G.host == '' or G.port == nil or G.port == 0 then
|
if g_game.isOnline() then
|
||||||
local errorBox = displayErrorBox(tr('Login Error'), tr('Enter a valid server host and port to login.'))
|
local errorBox = displayErrorBox(tr('Login Error'), tr('Cannot login while already in game.'))
|
||||||
connect(errorBox, { onOk = EnterGame.show })
|
connect(errorBox, { onOk = EnterGame.show })
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
g_settings.set('host', G.host)
|
g_settings.set('host', G.host)
|
||||||
g_settings.set('port', G.port)
|
g_settings.set('port', G.port)
|
||||||
|
g_settings.set('protocol', protocol)
|
||||||
|
|
||||||
local protocolLogin = ProtocolLogin.create()
|
local protocolLogin = ProtocolLogin.create()
|
||||||
protocolLogin.onError = onError
|
protocolLogin.onError = onError
|
||||||
|
@ -153,6 +167,8 @@ function EnterGame.doLogin()
|
||||||
EnterGame.show()
|
EnterGame.show()
|
||||||
end })
|
end })
|
||||||
|
|
||||||
|
g_game.chooseRsa(G.host)
|
||||||
|
g_game.setProtocolVersion(protocol)
|
||||||
protocolLogin:login(G.host, G.port, G.account, G.password)
|
protocolLogin:login(G.host, G.port, G.account, G.password)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
MainWindow
|
MainWindow
|
||||||
id: enterGame
|
id: enterGame
|
||||||
!text: tr('Enter Game')
|
!text: tr('Enter Game')
|
||||||
size: 236 240
|
size: 236 274
|
||||||
@onEnter: EnterGame.doLogin()
|
@onEnter: EnterGame.doLogin()
|
||||||
@onEscape: EnterGame.hide()
|
@onEscape: EnterGame.hide()
|
||||||
|
|
||||||
|
@ -43,26 +43,43 @@ MainWindow
|
||||||
TextEdit
|
TextEdit
|
||||||
id: serverHostTextEdit
|
id: serverHostTextEdit
|
||||||
!tooltip: tr('Make sure that your client uses\nthe correct game protocol version')
|
!tooltip: tr('Make sure that your client uses\nthe correct game protocol version')
|
||||||
anchors.left: serverLabel.left
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
anchors.top: serverLabel.bottom
|
anchors.top: serverLabel.bottom
|
||||||
margin-top: 2
|
margin-top: 2
|
||||||
width: 140
|
|
||||||
|
Label
|
||||||
|
id: protocolLabel
|
||||||
|
!text: tr('Protocol')
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: serverHostTextEdit.bottom
|
||||||
|
anchors.right: portLabel.left
|
||||||
|
margin-right: 10
|
||||||
|
margin-top: 8
|
||||||
|
|
||||||
|
ComboBox
|
||||||
|
id: protocolComboBox
|
||||||
|
anchors.left: protocolLabel.left
|
||||||
|
anchors.right: protocolLabel.right
|
||||||
|
anchors.top: protocolLabel.bottom
|
||||||
|
margin-top: 2
|
||||||
|
width: 90
|
||||||
|
|
||||||
Label
|
Label
|
||||||
id: portLabel
|
id: portLabel
|
||||||
!text: tr('Port')
|
!text: tr('Port')
|
||||||
anchors.left: serverHostTextEdit.right
|
anchors.right: parent.right
|
||||||
anchors.top: serverLabel.top
|
anchors.top: serverHostTextEdit.bottom
|
||||||
margin-left: 10
|
margin-top: 8
|
||||||
text-auto-resize: true
|
width: 70
|
||||||
|
|
||||||
TextEdit
|
TextEdit
|
||||||
id: serverPortTextEdit
|
id: serverPortTextEdit
|
||||||
text: 7171
|
text: 7171
|
||||||
|
anchors.right: parent.right
|
||||||
anchors.left: portLabel.left
|
anchors.left: portLabel.left
|
||||||
anchors.top: portLabel.bottom
|
anchors.top: portLabel.bottom
|
||||||
margin-top: 2
|
margin-top: 2
|
||||||
width: 55
|
|
||||||
|
|
||||||
CheckBox
|
CheckBox
|
||||||
id: rememberPasswordBox
|
id: rememberPasswordBox
|
||||||
|
|
|
@ -55,4 +55,4 @@ function Extended.unregister(opcode)
|
||||||
|
|
||||||
callbacks[opcode] = nil
|
callbacks[opcode] = nil
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
|
@ -132,6 +132,7 @@ function getfsrcpath(depth)
|
||||||
end
|
end
|
||||||
|
|
||||||
function resolvepath(filePath, depth)
|
function resolvepath(filePath, depth)
|
||||||
|
if not filePath then return nil end
|
||||||
depth = depth or 1
|
depth = depth or 1
|
||||||
if filePath then
|
if filePath then
|
||||||
if filePath:sub(0, 1) ~= '/' then
|
if filePath:sub(0, 1) ~= '/' then
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
Module
|
|
||||||
name: game
|
|
||||||
description: Contains game related classes
|
|
||||||
author: OTClient team
|
|
||||||
website: www.otclient.info
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
- client_extended
|
|
||||||
- client_background
|
|
||||||
- game_tibiafiles
|
|
||||||
|
|
||||||
load-later:
|
|
||||||
- game_interface
|
|
||||||
- game_hotkeys
|
|
||||||
- game_questlog
|
|
||||||
- game_textmessage
|
|
||||||
- game_console
|
|
||||||
- game_outfit
|
|
||||||
- game_healthinfo
|
|
||||||
- game_skills
|
|
||||||
- game_inventory
|
|
||||||
- game_combatcontrols
|
|
||||||
- game_containers
|
|
||||||
- game_viplist
|
|
||||||
- game_battle
|
|
||||||
- game_minimap
|
|
||||||
- game_npctrade
|
|
||||||
- game_textwindow
|
|
||||||
- game_playertrade
|
|
||||||
- game_ruleviolation
|
|
||||||
- game_bugreport
|
|
||||||
- game_shaders
|
|
||||||
- game_playerdeath
|
|
||||||
- game_playermount
|
|
||||||
- game_market
|
|
||||||
|
|
||||||
@onLoad: |
|
|
||||||
dofile 'const'
|
|
||||||
|
|
||||||
dofile 'protocollogin'
|
|
||||||
|
|
||||||
dofile 'creature'
|
|
||||||
dofile 'player'
|
|
||||||
dofile 'market'
|
|
|
@ -224,7 +224,7 @@ function Battle.checkCreatureSkull(creature, skullId)
|
||||||
if creature:getSkull() ~= SkullNone then
|
if creature:getSkull() ~= SkullNone then
|
||||||
skullWidget:setWidth(skullWidget:getHeight())
|
skullWidget:setWidth(skullWidget:getHeight())
|
||||||
local imagePath = getSkullImagePath(creature:getSkull())
|
local imagePath = getSkullImagePath(creature:getSkull())
|
||||||
skullWidget:setImageSource('/game/' .. imagePath)
|
skullWidget:setImageSource(imagePath)
|
||||||
labelWidget:setMarginLeft(5)
|
labelWidget:setMarginLeft(5)
|
||||||
else
|
else
|
||||||
skullWidget:setWidth(0)
|
skullWidget:setWidth(0)
|
||||||
|
@ -246,7 +246,7 @@ function Battle.checkCreatureEmblem(creature, emblemId)
|
||||||
if emblemId ~= EmblemNone then
|
if emblemId ~= EmblemNone then
|
||||||
emblemWidget:setWidth(emblemWidget:getHeight())
|
emblemWidget:setWidth(emblemWidget:getHeight())
|
||||||
local imagePath = getEmblemImagePath(emblemId)
|
local imagePath = getEmblemImagePath(emblemId)
|
||||||
emblemWidget:setImageSource('/game/' .. imagePath)
|
emblemWidget:setImageSource(imagePath)
|
||||||
emblemWidget:setMarginLeft(5)
|
emblemWidget:setMarginLeft(5)
|
||||||
labelWidget:setMarginLeft(5)
|
labelWidget:setMarginLeft(5)
|
||||||
else
|
else
|
||||||
|
|
|
@ -4,6 +4,30 @@ Module
|
||||||
author: OTClient team
|
author: OTClient team
|
||||||
website: www.otclient.info
|
website: www.otclient.info
|
||||||
|
|
||||||
|
load-later:
|
||||||
|
- game_hotkeys
|
||||||
|
- game_questlog
|
||||||
|
- game_textmessage
|
||||||
|
- game_console
|
||||||
|
- game_outfit
|
||||||
|
- game_healthinfo
|
||||||
|
- game_skills
|
||||||
|
- game_inventory
|
||||||
|
- game_combatcontrols
|
||||||
|
- game_containers
|
||||||
|
- game_viplist
|
||||||
|
- game_battle
|
||||||
|
- game_minimap
|
||||||
|
- game_npctrade
|
||||||
|
- game_textwindow
|
||||||
|
- game_playertrade
|
||||||
|
- game_ruleviolation
|
||||||
|
- game_bugreport
|
||||||
|
- game_shaders
|
||||||
|
- game_playerdeath
|
||||||
|
- game_playermount
|
||||||
|
- game_market
|
||||||
|
|
||||||
@onLoad: |
|
@onLoad: |
|
||||||
dofile 'widgets/uigamemap'
|
dofile 'widgets/uigamemap'
|
||||||
dofile 'widgets/uiitem'
|
dofile 'widgets/uiitem'
|
||||||
|
|
|
@ -4,9 +4,6 @@ Module
|
||||||
author: BeniS
|
author: BeniS
|
||||||
website: www.otclient.info
|
website: www.otclient.info
|
||||||
|
|
||||||
dependencies:
|
|
||||||
- game
|
|
||||||
|
|
||||||
@onLoad: |
|
@onLoad: |
|
||||||
dofile 'marketoffer'
|
dofile 'marketoffer'
|
||||||
dofile 'marketprotocol'
|
dofile 'marketprotocol'
|
||||||
|
|
|
@ -32,7 +32,7 @@ MarketOffer.new = function(offerId, action, itemId, amount, price, playerName, s
|
||||||
offer.player = playerName
|
offer.player = playerName
|
||||||
|
|
||||||
state = tonumber(state)
|
state = tonumber(state)
|
||||||
if state ~= MarketOfferState.Active and state ~= MarketOfferState.Cancelled
|
if state ~= MarketOfferState.Active and state ~= MarketOfferState.Cancelled
|
||||||
and state ~= MarketOfferState.Expired and state ~= MarketOfferState.Accepted then
|
and state ~= MarketOfferState.Expired and state ~= MarketOfferState.Accepted then
|
||||||
g_logger.error('MarketOffer.new - invalid state provided.')
|
g_logger.error('MarketOffer.new - invalid state provided.')
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,27 +3,6 @@ MarketProtocol = {}
|
||||||
local market
|
local market
|
||||||
|
|
||||||
-- private functions
|
-- private functions
|
||||||
|
|
||||||
local function parseOpcode(protocol, opcode, msg)
|
|
||||||
if not g_game.getFeature(GamePlayerMarket) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- process msg
|
|
||||||
if opcode == GameServerOpcodes.GameServerMarketEnter then
|
|
||||||
parseMarketEnter(msg)
|
|
||||||
elseif opcode == GameServerOpcodes.GameServerMarketLeave then
|
|
||||||
parseMarketLeave(msg)
|
|
||||||
elseif opcode == GameServerOpcodes.GameServerMarketDetail then
|
|
||||||
parseMarketDetail(msg)
|
|
||||||
elseif opcode == GameServerOpcodes.GameServerMarketBrowse then
|
|
||||||
parseMarketBrowse(msg)
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function send(msg)
|
local function send(msg)
|
||||||
print(msg:getMessageSize())
|
print(msg:getMessageSize())
|
||||||
g_game.getProtocolGame():safeSend(msg)
|
g_game.getProtocolGame():safeSend(msg)
|
||||||
|
@ -49,12 +28,11 @@ local function readMarketOffer(msg, action, var)
|
||||||
else
|
else
|
||||||
playerName = msg:getString()
|
playerName = msg:getString()
|
||||||
end
|
end
|
||||||
|
|
||||||
return MarketOffer.new({timestamp, counter}, action, itemId, amount, price, playerName, state)
|
return MarketOffer.new({timestamp, counter}, action, itemId, amount, price, playerName, state)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- parsing protocols
|
-- parsing protocols
|
||||||
|
|
||||||
local function parseMarketEnter(msg)
|
local function parseMarketEnter(msg)
|
||||||
local balance = msg:getU32()
|
local balance = msg:getU32()
|
||||||
local offers = msg:getU8()
|
local offers = msg:getU8()
|
||||||
|
@ -128,14 +106,18 @@ local function parseMarketBrowse(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- public functions
|
-- public functions
|
||||||
|
|
||||||
function MarketProtocol.init()
|
function MarketProtocol.init()
|
||||||
connect(ProtocolGame, { onOpcode = parseOpcode } )
|
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter)
|
||||||
|
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave)
|
||||||
|
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail)
|
||||||
|
ProtocolGame.registerOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse)
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarketProtocol.terminate()
|
function MarketProtocol.terminate()
|
||||||
disconnect(ProtocolGame, { onOpcode = parseOpcode } )
|
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketEnter, parseMarketEnter)
|
||||||
|
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketLeave, parseMarketLeave)
|
||||||
|
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketDetail, parseMarketDetail)
|
||||||
|
ProtocolGame.unregisterOpcode(GameServerOpcodes.GameServerMarketBrowse, parseMarketBrowse)
|
||||||
|
|
||||||
market = nil
|
market = nil
|
||||||
MarketProtocol = nil
|
MarketProtocol = nil
|
||||||
|
|
|
@ -34,11 +34,6 @@ SouthEast = 5
|
||||||
SouthWest = 6
|
SouthWest = 6
|
||||||
NorthWest = 7
|
NorthWest = 7
|
||||||
|
|
||||||
LoginServerError = 10
|
|
||||||
LoginServerMotd = 20
|
|
||||||
LoginServerUpdateNeeded = 30
|
|
||||||
LoginServerCharacterList = 100
|
|
||||||
|
|
||||||
GameExtendedOpcode = 0
|
GameExtendedOpcode = 0
|
||||||
GameProtocolChecksum = 1
|
GameProtocolChecksum = 1
|
||||||
GameAccountNames = 2
|
GameAccountNames = 2
|
||||||
|
@ -56,7 +51,7 @@ GameChannelPlayerList = 13
|
||||||
GamePlayerMounts = 14
|
GamePlayerMounts = 14
|
||||||
GameEnvironmentEffect = 15
|
GameEnvironmentEffect = 15
|
||||||
GameCreatureType = 16
|
GameCreatureType = 16
|
||||||
GameCreatureAdditionalInfo = 17
|
GameCreatureEmblems = 17
|
||||||
GameCreaturePassableInfo = 18
|
GameCreaturePassableInfo = 18
|
||||||
GameItemAnimationPhase = 19
|
GameItemAnimationPhase = 19
|
||||||
GameTrucatedPingOpcode = 20
|
GameTrucatedPingOpcode = 20
|
||||||
|
@ -64,6 +59,25 @@ GameReverseCreatureStack = 21
|
||||||
GameMagicEffectU16 = 22
|
GameMagicEffectU16 = 22
|
||||||
GamePlayerMarket = 23
|
GamePlayerMarket = 23
|
||||||
|
|
||||||
OTSERV_RSA = "109120132967399429278860960508995541528237502902798129123468757937266291492576446330739696001110603907230888610072655818825358503429057592827629436413108566029093628212635953836686562675849720620786279431090218017681061521755056710823876476444260558147179707119674283982419152118103759076030616683978566631413"
|
OTSERV_RSA = "1091201329673994292788609605089955415282375029027981291234687579" ..
|
||||||
|
"3726629149257644633073969600111060390723088861007265581882535850" ..
|
||||||
|
"3429057592827629436413108566029093628212635953836686562675849720" ..
|
||||||
|
"6207862794310902180176810615217550567108238764764442605581471797" ..
|
||||||
|
"07119674283982419152118103759076030616683978566631413"
|
||||||
|
|
||||||
-- @}
|
CIPSOFT_RSA = "1321277432058722840622950990822933849527763264961655079678763618" ..
|
||||||
|
"4334395343554449668205332383339435179772895415509701210392836078" ..
|
||||||
|
"6959821132214473291575712138800495033169914814069637740318278150" ..
|
||||||
|
"2907336840325241747827401343576296990629870233111328210165697754" ..
|
||||||
|
"88792221429527047321331896351555606801473202394175817"
|
||||||
|
|
||||||
|
OsTypes = {
|
||||||
|
Linux = 1,
|
||||||
|
Windows = 2,
|
||||||
|
Flash = 3,
|
||||||
|
OtclientLinux = 10,
|
||||||
|
OtclientWindows = 11,
|
||||||
|
OtclientMac = 12
|
||||||
|
}
|
||||||
|
|
||||||
|
-- @}
|
|
@ -30,73 +30,81 @@ EmblemBlue = 3
|
||||||
-- @}
|
-- @}
|
||||||
|
|
||||||
function getSkullImagePath(skullId)
|
function getSkullImagePath(skullId)
|
||||||
|
local path
|
||||||
if skullId == SkullYellow then
|
if skullId == SkullYellow then
|
||||||
return 'icons/skull_yellow.png'
|
path = 'icons/skull_yellow.png'
|
||||||
elseif skullId == SkullGreen then
|
elseif skullId == SkullGreen then
|
||||||
return 'icons/skull_green.png'
|
path = 'icons/skull_green.png'
|
||||||
elseif skullId == SkullWhite then
|
elseif skullId == SkullWhite then
|
||||||
return 'icons/skull_white.png'
|
path = 'icons/skull_white.png'
|
||||||
elseif skullId == SkullRed then
|
elseif skullId == SkullRed then
|
||||||
return 'icons/skull_red.png'
|
path = 'icons/skull_red.png'
|
||||||
elseif skullId == SkullBlack then
|
elseif skullId == SkullBlack then
|
||||||
return 'icons/skull_black.png'
|
path = 'icons/skull_black.png'
|
||||||
elseif skullId == SkullOrange then
|
elseif skullId == SkullOrange then
|
||||||
return 'icons/skull_orange.png'
|
path = 'icons/skull_orange.png'
|
||||||
end
|
end
|
||||||
|
path = resolvepath(path)
|
||||||
|
return path
|
||||||
end
|
end
|
||||||
|
|
||||||
function getShieldImagePathAndBlink(shieldId)
|
function getShieldImagePathAndBlink(shieldId)
|
||||||
|
local path
|
||||||
if shieldId == ShieldWhiteYellow then
|
if shieldId == ShieldWhiteYellow then
|
||||||
return 'icons/shield_yellow_white.png', false
|
path = 'icons/shield_yellow_white.png', false
|
||||||
elseif shieldId == ShieldWhiteBlue then
|
elseif shieldId == ShieldWhiteBlue then
|
||||||
return 'icons/shield_blue_white.png', false
|
path = 'icons/shield_blue_white.png', false
|
||||||
elseif shieldId == ShieldBlue then
|
elseif shieldId == ShieldBlue then
|
||||||
return 'icons/shield_blue.png', false
|
path = 'icons/shield_blue.png', false
|
||||||
elseif shieldId == ShieldYellow then
|
elseif shieldId == ShieldYellow then
|
||||||
return 'icons/shield_yellow.png', false
|
path = 'icons/shield_yellow.png', false
|
||||||
elseif shieldId == ShieldBlueSharedExp then
|
elseif shieldId == ShieldBlueSharedExp then
|
||||||
return 'icons/shield_blue_shared.png', false
|
path = 'icons/shield_blue_shared.png', false
|
||||||
elseif shieldId == ShieldYellowSharedExp then
|
elseif shieldId == ShieldYellowSharedExp then
|
||||||
return 'icons/shield_yellow_shared.png', false
|
path = 'icons/shield_yellow_shared.png', false
|
||||||
elseif shieldId == ShieldBlueNoSharedExpBlink then
|
elseif shieldId == ShieldBlueNoSharedExpBlink then
|
||||||
return 'icons/shield_blue_not_shared.png', true
|
path = 'icons/shield_blue_not_shared.png', true
|
||||||
elseif shieldId == ShieldYellowNoSharedExpBlink then
|
elseif shieldId == ShieldYellowNoSharedExpBlink then
|
||||||
return 'icons/shield_yellow_not_shared.png', true
|
path = 'icons/shield_yellow_not_shared.png', true
|
||||||
elseif shieldId == ShieldBlueNoSharedExp then
|
elseif shieldId == ShieldBlueNoSharedExp then
|
||||||
return 'icons/shield_blue_not_shared.png', false
|
path = 'icons/shield_blue_not_shared.png', false
|
||||||
elseif shieldId == ShieldYellowNoSharedExp then
|
elseif shieldId == ShieldYellowNoSharedExp then
|
||||||
return 'icons/shield_yellow_not_shared.png', false
|
path = 'icons/shield_yellow_not_shared.png', false
|
||||||
end
|
end
|
||||||
|
path = resolvepath(path)
|
||||||
|
return path
|
||||||
end
|
end
|
||||||
|
|
||||||
function getEmblemImagePath(emblemId)
|
function getEmblemImagePath(emblemId)
|
||||||
|
local path
|
||||||
if emblemId == EmblemGreen then
|
if emblemId == EmblemGreen then
|
||||||
return 'icons/emblem_green.png'
|
path = 'icons/emblem_green.png'
|
||||||
elseif emblemId == EmblemRed then
|
elseif emblemId == EmblemRed then
|
||||||
return 'icons/emblem_red.png'
|
path = 'icons/emblem_red.png'
|
||||||
elseif emblemId == EmblemBlue then
|
elseif emblemId == EmblemBlue then
|
||||||
return 'icons/emblem_blue.png'
|
path = 'icons/emblem_blue.png'
|
||||||
end
|
end
|
||||||
|
path = resolvepath(path)
|
||||||
|
return path
|
||||||
end
|
end
|
||||||
|
|
||||||
function Creature:onSkullChange(skullId)
|
function Creature:onSkullChange(skullId)
|
||||||
local imagePath = getSkullImagePath(skullId)
|
local imagePath = getSkullImagePath(skullId)
|
||||||
if imagePath then
|
if imagePath then
|
||||||
self:setSkullTexture(resolvepath(imagePath))
|
self:setSkullTexture(imagePath)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Creature:onShieldChange(shieldId)
|
function Creature:onShieldChange(shieldId)
|
||||||
local imagePath, blink = getShieldImagePathAndBlink(shieldId)
|
local imagePath, blink = getShieldImagePathAndBlink(shieldId)
|
||||||
if imagePath then
|
if imagePath then
|
||||||
self:setShieldTexture(resolvepath(imagePath), blink)
|
self:setShieldTexture(imagePath, blink)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Creature:onEmblemChange(emblemId)
|
function Creature:onEmblemChange(emblemId)
|
||||||
local imagePath = getEmblemImagePath(emblemId)
|
local imagePath = getEmblemImagePath(emblemId)
|
||||||
if imagePath then
|
if imagePath then
|
||||||
self:setEmblemTexture(resolvepath(imagePath))
|
self:setEmblemTexture(imagePath)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
local currentRsa = OTSERV_RSA
|
||||||
|
|
||||||
|
function g_game.getRsa()
|
||||||
|
return currentRsa
|
||||||
|
end
|
||||||
|
|
||||||
|
function g_game.chooseRsa(host)
|
||||||
|
if host:match('.*\.tibia\.com') or host:match('.*\.cipsoft\.com') then
|
||||||
|
currentRsa = CIPSOFT_RSA
|
||||||
|
else
|
||||||
|
currentRsa = OTSERV_RSA
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function g_game.setRsa(rsa)
|
||||||
|
currentRsa = rsa
|
||||||
|
end
|
||||||
|
|
||||||
|
function g_game.isOfficialTibia()
|
||||||
|
return currentRsa == CIPSOFT_RSA
|
||||||
|
end
|
||||||
|
|
||||||
|
function g_game.getOsType()
|
||||||
|
if g_game.isOfficialTibia() then
|
||||||
|
if g_app.getOs() == 'windows' then
|
||||||
|
return OsTypes.Windows
|
||||||
|
else
|
||||||
|
return OsTypes.Linux
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if g_app.getOs() == 'windows' then
|
||||||
|
return OsTypes.OtclientWindows
|
||||||
|
elseif g_app.getOs() == 'mac' then
|
||||||
|
return OsTypes.OtclientMac
|
||||||
|
else
|
||||||
|
return OsTypes.OtclientLinux
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function g_game.getSupportedProtocols()
|
||||||
|
return {
|
||||||
|
810, 853, 854, 860, 861, 862, 870, 940,
|
||||||
|
953, 954, 960
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
Module
|
||||||
|
name: gamelib
|
||||||
|
description: Contains game related classes
|
||||||
|
author: OTClient team
|
||||||
|
website: www.otclient.info
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- client_extended
|
||||||
|
- game_tibiafiles
|
||||||
|
|
||||||
|
@onLoad: |
|
||||||
|
dofile 'const'
|
||||||
|
|
||||||
|
dofile 'protocollogin'
|
||||||
|
dofile 'protocolgame'
|
||||||
|
dofile 'game'
|
||||||
|
|
||||||
|
dofile 'creature'
|
||||||
|
dofile 'player'
|
||||||
|
dofile 'market'
|
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 |
|
@ -52,4 +52,3 @@ function Player:hasVip(creatureName)
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
local opcodeCallbacks = {}
|
||||||
|
|
||||||
|
function ProtocolGame:onOpcode(opcode, msg)
|
||||||
|
for i, callback in pairs(opcodeCallbacks) do
|
||||||
|
if i == opcode then
|
||||||
|
callback(msg)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function ProtocolGame.registerOpcode(opcode, callback)
|
||||||
|
if opcodeCallbacks[opcode] then
|
||||||
|
error('opcode ' .. opcode .. ' already registered will be overriden')
|
||||||
|
end
|
||||||
|
|
||||||
|
opcodeCallbacks[opcode] = callback
|
||||||
|
end
|
||||||
|
|
||||||
|
function ProtocolGame.unregisterOpcode(opcode)
|
||||||
|
opcodeCallbacks[opcode] = nil
|
||||||
|
end
|
|
@ -1,16 +1,25 @@
|
||||||
-- @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 = 0
|
||||||
|
|
||||||
|
LoginServerError = 10
|
||||||
|
LoginServerMotd = 20
|
||||||
|
LoginServerUpdateNeeded = 30
|
||||||
|
LoginServerCharacterList = 100
|
||||||
|
|
||||||
|
|
||||||
-- private functions
|
-- private functions
|
||||||
local function sendLoginPacket(protocol)
|
local function sendLoginPacket(protocol)
|
||||||
local msg = OutputMessage.create()
|
local msg = OutputMessage.create()
|
||||||
msg:addU8(ClientOpcodes.ClientEnterAccount)
|
msg:addU8(ClientOpcodes.ClientEnterAccount)
|
||||||
msg:addU16(1) -- todo: ClientOs
|
msg:addU16(g_game.getOsType())
|
||||||
msg:addU16(g_game.getClientVersion())
|
msg:addU16(g_game.getProtocolVersion())
|
||||||
|
|
||||||
msg:addU32(g_things.getDatSignature())
|
msg:addU32(g_things.getDatSignature())
|
||||||
msg:addU32(g_sprites.getSprSignature())
|
msg:addU32(g_sprites.getSprSignature())
|
||||||
msg:addU32(0) -- todo: pic signature
|
msg:addU32(PIC_SIGNATURE)
|
||||||
|
|
||||||
local paddingBytes = 128
|
local paddingBytes = 128
|
||||||
msg:addU8(0) -- first RSA byte must be 0
|
msg:addU8(0) -- first RSA byte must be 0
|
||||||
|
@ -40,7 +49,7 @@ local function sendLoginPacket(protocol)
|
||||||
end
|
end
|
||||||
|
|
||||||
msg:addPaddingBytes(paddingBytes, 0)
|
msg:addPaddingBytes(paddingBytes, 0)
|
||||||
msg:encryptRSA(128, OTSERV_RSA) -- todo: check whether to use cip or ot rsa
|
msg:encryptRsa(128, g_game.getRsa())
|
||||||
|
|
||||||
protocol:send(msg)
|
protocol:send(msg)
|
||||||
protocol:enableXteaEncryption()
|
protocol:enableXteaEncryption()
|
||||||
|
@ -60,7 +69,7 @@ function ProtocolLogin:onRecv(msg)
|
||||||
elseif opcode == LoginServerMotd then
|
elseif opcode == LoginServerMotd then
|
||||||
self:parseMotd(msg)
|
self:parseMotd(msg)
|
||||||
elseif opcode == LoginServerUpdateNeeded then
|
elseif opcode == LoginServerUpdateNeeded then
|
||||||
signalcall(self.onError, self, "Client needs update.")
|
signalcall(self.onError, self, tr("Client needs update."))
|
||||||
elseif opcode == LoginServerCharacterList then
|
elseif opcode == LoginServerCharacterList then
|
||||||
self:parseCharacterList(msg)
|
self:parseCharacterList(msg)
|
||||||
else
|
else
|
||||||
|
@ -77,7 +86,11 @@ 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, "You must enter an account name and password.")
|
signalcall(self.onError, self, tr("You must enter an account name and password."))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if string.len(host) == 0 or port == nil or port == 0 then
|
||||||
|
signalcall(self.onError, self, tr("You must enter a valid server address and port."))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
|
@ -141,3 +141,14 @@ void Application::close()
|
||||||
if(!g_lua.callGlobalField<bool>("g_app", "onClose"))
|
if(!g_lua.callGlobalField<bool>("g_app", "onClose"))
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Application::getOs()
|
||||||
|
{
|
||||||
|
#if defined(WIN32)
|
||||||
|
return "windows";
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
return "mac";
|
||||||
|
#else
|
||||||
|
return "linux";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ public:
|
||||||
std::string getBuildCommit() { return BUILD_COMMIT; }
|
std::string getBuildCommit() { return BUILD_COMMIT; }
|
||||||
std::string getBuildType() { return BUILD_TYPE; }
|
std::string getBuildType() { return BUILD_TYPE; }
|
||||||
std::string getBuildArch() { return BUILD_ARCH; }
|
std::string getBuildArch() { return BUILD_ARCH; }
|
||||||
|
std::string getOs();
|
||||||
std::string getStartupOptions() { return m_startupOptions; }
|
std::string getStartupOptions() { return m_startupOptions; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -22,22 +22,25 @@
|
||||||
|
|
||||||
#include <framework/core/application.h>
|
#include <framework/core/application.h>
|
||||||
#include <framework/luaengine/luainterface.h>
|
#include <framework/luaengine/luainterface.h>
|
||||||
#include <framework/graphics/fontmanager.h>
|
|
||||||
#include <framework/ui/ui.h>
|
|
||||||
#include <framework/net/protocol.h>
|
#include <framework/net/protocol.h>
|
||||||
#include <framework/core/eventdispatcher.h>
|
#include <framework/core/eventdispatcher.h>
|
||||||
#include <framework/core/configmanager.h>
|
#include <framework/core/configmanager.h>
|
||||||
#include <framework/otml/otml.h>
|
#include <framework/otml/otml.h>
|
||||||
#include <framework/graphics/graphics.h>
|
|
||||||
#include <framework/platform/platformwindow.h>
|
|
||||||
#include <framework/core/modulemanager.h>
|
#include <framework/core/modulemanager.h>
|
||||||
#include <framework/core/module.h>
|
#include <framework/core/module.h>
|
||||||
#include <framework/sound/soundmanager.h>
|
#include <framework/sound/soundmanager.h>
|
||||||
#include <framework/util/crypt.h>
|
#include <framework/util/crypt.h>
|
||||||
#include <framework/core/resourcemanager.h>
|
#include <framework/core/resourcemanager.h>
|
||||||
#include <framework/graphics/particlemanager.h>
|
|
||||||
#include <framework/graphics/texturemanager.h>
|
#include <framework/graphics/texturemanager.h>
|
||||||
|
|
||||||
|
#ifdef FW_GRAPHICS
|
||||||
|
#include <framework/graphics/graphics.h>
|
||||||
|
#include <framework/platform/platformwindow.h>
|
||||||
|
#include <framework/graphics/particlemanager.h>
|
||||||
|
#include <framework/graphics/fontmanager.h>
|
||||||
|
#include <framework/ui/ui.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
void Application::registerLuaFunctions()
|
void Application::registerLuaFunctions()
|
||||||
{
|
{
|
||||||
// conversion globals
|
// conversion globals
|
||||||
|
@ -67,6 +70,7 @@ void Application::registerLuaFunctions()
|
||||||
g_lua.bindSingletonFunction("g_app", "getBuildCommit", &Application::getBuildCommit, static_cast<Application*>(&g_app));
|
g_lua.bindSingletonFunction("g_app", "getBuildCommit", &Application::getBuildCommit, static_cast<Application*>(&g_app));
|
||||||
g_lua.bindSingletonFunction("g_app", "getBuildType", &Application::getBuildType, static_cast<Application*>(&g_app));
|
g_lua.bindSingletonFunction("g_app", "getBuildType", &Application::getBuildType, static_cast<Application*>(&g_app));
|
||||||
g_lua.bindSingletonFunction("g_app", "getBuildArch", &Application::getBuildArch, static_cast<Application*>(&g_app));
|
g_lua.bindSingletonFunction("g_app", "getBuildArch", &Application::getBuildArch, static_cast<Application*>(&g_app));
|
||||||
|
g_lua.bindSingletonFunction("g_app", "getOs", &Application::getOs, static_cast<Application*>(&g_app));
|
||||||
g_lua.bindSingletonFunction("g_app", "exit", &Application::exit, static_cast<Application*>(&g_app));
|
g_lua.bindSingletonFunction("g_app", "exit", &Application::exit, static_cast<Application*>(&g_app));
|
||||||
|
|
||||||
// Crypt
|
// Crypt
|
||||||
|
@ -644,7 +648,7 @@ void Application::registerLuaFunctions()
|
||||||
g_lua.bindClassMemberFunction<InputMessage>("peekU16", &InputMessage::peekU16);
|
g_lua.bindClassMemberFunction<InputMessage>("peekU16", &InputMessage::peekU16);
|
||||||
g_lua.bindClassMemberFunction<InputMessage>("peekU32", &InputMessage::peekU32);
|
g_lua.bindClassMemberFunction<InputMessage>("peekU32", &InputMessage::peekU32);
|
||||||
g_lua.bindClassMemberFunction<InputMessage>("peekU64", &InputMessage::peekU64);
|
g_lua.bindClassMemberFunction<InputMessage>("peekU64", &InputMessage::peekU64);
|
||||||
g_lua.bindClassMemberFunction<InputMessage>("decryptRSA", &InputMessage::decryptRSA);
|
g_lua.bindClassMemberFunction<InputMessage>("decryptRsa", &InputMessage::decryptRsa);
|
||||||
g_lua.bindClassMemberFunction<InputMessage>("getReadSize", &InputMessage::getReadSize);
|
g_lua.bindClassMemberFunction<InputMessage>("getReadSize", &InputMessage::getReadSize);
|
||||||
g_lua.bindClassMemberFunction<InputMessage>("getUnreadSize", &InputMessage::getUnreadSize);
|
g_lua.bindClassMemberFunction<InputMessage>("getUnreadSize", &InputMessage::getUnreadSize);
|
||||||
g_lua.bindClassMemberFunction<InputMessage>("getMessageSize", &InputMessage::getMessageSize);
|
g_lua.bindClassMemberFunction<InputMessage>("getMessageSize", &InputMessage::getMessageSize);
|
||||||
|
@ -661,7 +665,7 @@ void Application::registerLuaFunctions()
|
||||||
g_lua.bindClassMemberFunction<OutputMessage>("addU64", &OutputMessage::addU64);
|
g_lua.bindClassMemberFunction<OutputMessage>("addU64", &OutputMessage::addU64);
|
||||||
g_lua.bindClassMemberFunction<OutputMessage>("addString", &OutputMessage::addString);
|
g_lua.bindClassMemberFunction<OutputMessage>("addString", &OutputMessage::addString);
|
||||||
g_lua.bindClassMemberFunction<OutputMessage>("addPaddingBytes", &OutputMessage::addPaddingBytes);
|
g_lua.bindClassMemberFunction<OutputMessage>("addPaddingBytes", &OutputMessage::addPaddingBytes);
|
||||||
g_lua.bindClassMemberFunction<OutputMessage>("encryptRSA", &OutputMessage::encryptRSA);
|
g_lua.bindClassMemberFunction<OutputMessage>("encryptRsa", &OutputMessage::encryptRsa);
|
||||||
g_lua.bindClassMemberFunction<OutputMessage>("getMessageSize", &OutputMessage::getMessageSize);
|
g_lua.bindClassMemberFunction<OutputMessage>("getMessageSize", &OutputMessage::getMessageSize);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ std::string InputMessage::getString()
|
||||||
return std::string(v, stringLength);
|
return std::string(v, stringLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputMessage::decryptRSA(int size, const std::string& p, const std::string& q, const std::string& d)
|
void InputMessage::decryptRsa(int size, const std::string& p, const std::string& q, const std::string& d)
|
||||||
{
|
{
|
||||||
checkRead(size);
|
checkRead(size);
|
||||||
RSA::decrypt((char*)m_buffer + m_readPos, size, p.c_str(), q.c_str(), d.c_str());
|
RSA::decrypt((char*)m_buffer + m_readPos, size, p.c_str(), q.c_str(), d.c_str());
|
||||||
|
|
|
@ -40,6 +40,7 @@ public:
|
||||||
void setBuffer(const std::string& buffer);
|
void setBuffer(const std::string& buffer);
|
||||||
|
|
||||||
void skipBytes(uint16 bytes) { m_readPos += bytes; }
|
void skipBytes(uint16 bytes) { m_readPos += bytes; }
|
||||||
|
void setReadPos(uint16 readPos) { m_readPos = readPos; }
|
||||||
uint8 getU8();
|
uint8 getU8();
|
||||||
uint16 getU16();
|
uint16 getU16();
|
||||||
uint32 getU32();
|
uint32 getU32();
|
||||||
|
@ -51,9 +52,10 @@ public:
|
||||||
uint32 peekU32() { uint32 v = getU32(); m_readPos-=4; return v; }
|
uint32 peekU32() { uint32 v = getU32(); m_readPos-=4; return v; }
|
||||||
uint64 peekU64() { uint64 v = getU64(); m_readPos-=8; return v; }
|
uint64 peekU64() { uint64 v = getU64(); m_readPos-=8; return v; }
|
||||||
|
|
||||||
void decryptRSA(int size, const std::string& p, const std::string& q, const std::string& d);
|
void decryptRsa(int size, const std::string& p, const std::string& q, const std::string& d);
|
||||||
|
|
||||||
int getReadSize() { return m_readPos - m_headerPos; }
|
int getReadSize() { return m_readPos - m_headerPos; }
|
||||||
|
int getReadPos() { return m_readPos; }
|
||||||
int getUnreadSize() { return m_messageSize - (m_readPos - m_headerPos); }
|
int getUnreadSize() { return m_messageSize - (m_readPos - m_headerPos); }
|
||||||
uint16 getMessageSize() { return m_messageSize; }
|
uint16 getMessageSize() { return m_messageSize; }
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ void OutputMessage::addPaddingBytes(int bytes, uint8 byte)
|
||||||
m_messageSize += bytes;
|
m_messageSize += bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutputMessage::encryptRSA(int size, const std::string& key)
|
void OutputMessage::encryptRsa(int size, const std::string& key)
|
||||||
{
|
{
|
||||||
if(m_messageSize < size)
|
if(m_messageSize < size)
|
||||||
throw stdext::exception("insufficient bytes in buffer to encrypt");
|
throw stdext::exception("insufficient bytes in buffer to encrypt");
|
||||||
|
|
|
@ -49,7 +49,7 @@ public:
|
||||||
void addString(const std::string& buffer);
|
void addString(const std::string& buffer);
|
||||||
void addPaddingBytes(int bytes, uint8 byte = 0);
|
void addPaddingBytes(int bytes, uint8 byte = 0);
|
||||||
|
|
||||||
void encryptRSA(int size, const std::string& key);
|
void encryptRsa(int size, const std::string& key);
|
||||||
|
|
||||||
uint16 getMessageSize() { return m_messageSize; }
|
uint16 getMessageSize() { return m_messageSize; }
|
||||||
|
|
||||||
|
|
|
@ -286,31 +286,27 @@ namespace Otc
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GameFeature {
|
enum GameFeature {
|
||||||
GameExtendedOpcode = 0,
|
// 1-50 defined in c++
|
||||||
GameProtocolChecksum,
|
GameProtocolChecksum = 1,
|
||||||
GameAccountNames,
|
GameAccountNames = 2,
|
||||||
GameChallangeOnLogin,
|
GameChallangeOnLogin = 3,
|
||||||
GameStackposOnTileAddThing,
|
GamePenalityOnDeath = 5,
|
||||||
GamePenalityOnDeath,
|
GameNameOnNpcTrade = 6,
|
||||||
GameNameOnNpcTrade,
|
GameDoubleFreeCapacity = 7,
|
||||||
GameDoubleFreeCapacity,
|
GameDoubleExperience = 8,
|
||||||
GameDoubleExperience,
|
GameTotalCapacity = 9,
|
||||||
GameTotalCapacity,
|
GameSkillsBase = 10,
|
||||||
GameSkillsBase,
|
GamePlayerRegenerationTime = 11,
|
||||||
GameAdditionalPlayerStats,
|
GameChannelPlayerList = 13,
|
||||||
GameIdOnCancelAttack,
|
GamePlayerMounts = 14,
|
||||||
GameChannelPlayerList,
|
GameEnvironmentEffect = 15,
|
||||||
GamePlayerMounts,
|
GameCreatureEmblems = 17,
|
||||||
GameEnvironmentEffect,
|
GameItemAnimationPhase = 19,
|
||||||
GameCreatureType,
|
GameMagicEffectU16 = 22,
|
||||||
GameCreatureAdditionalInfo,
|
GamePlayerMarket = 23,
|
||||||
GameCreaturePassableInfo,
|
// 23-50 unused yet
|
||||||
GameItemAnimationPhase,
|
// 51-100 reserved to be defined in lua
|
||||||
GameTrucatedPingOpcode,
|
LastGameFeature = 101
|
||||||
GameReverseCreatureStack,
|
|
||||||
GameMagicEffectU16,
|
|
||||||
GamePlayerMarket,
|
|
||||||
LastGameFeature
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PathFindResult {
|
enum PathFindResult {
|
||||||
|
|
|
@ -461,6 +461,8 @@ void Creature::setDirection(Otc::Direction direction)
|
||||||
|
|
||||||
void Creature::setOutfit(const Outfit& outfit)
|
void Creature::setOutfit(const Outfit& outfit)
|
||||||
{
|
{
|
||||||
|
if(!g_things.isValidDatId(outfit.getId(), DatCreatureCategory))
|
||||||
|
return;
|
||||||
m_walkAnimationPhase = 0; // might happen when player is walking and outfit is changed.
|
m_walkAnimationPhase = 0; // might happen when player is walking and outfit is changed.
|
||||||
m_outfit = outfit;
|
m_outfit = outfit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,8 @@ void Effect::startAnimation()
|
||||||
|
|
||||||
void Effect::setId(uint32 id)
|
void Effect::setId(uint32 id)
|
||||||
{
|
{
|
||||||
|
if(!g_things.isValidDatId(id, DatEffectCategory))
|
||||||
|
id = 0;
|
||||||
m_id = id;
|
m_id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ Game g_game;
|
||||||
Game::Game()
|
Game::Game()
|
||||||
{
|
{
|
||||||
resetGameStates();
|
resetGameStates();
|
||||||
setClientVersion(860);
|
m_protocolVersion = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::resetGameStates()
|
void Game::resetGameStates()
|
||||||
|
@ -416,10 +416,11 @@ void Game::processWalkCancel(Otc::Direction direction)
|
||||||
|
|
||||||
void Game::loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName)
|
void Game::loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName)
|
||||||
{
|
{
|
||||||
if(m_protocolGame || isOnline()) {
|
if(m_protocolGame || isOnline())
|
||||||
g_logger.traceError("unable to login into a world while already online or logging");
|
stdext::throw_exception("Unable to login into a world while already online or logging.");
|
||||||
return;
|
|
||||||
}
|
if(m_protocolVersion == 0)
|
||||||
|
stdext::throw_exception("Must set a valid game protocol version before logging.");
|
||||||
|
|
||||||
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);
|
||||||
|
@ -1090,61 +1091,48 @@ bool Game::canPerformGameAction()
|
||||||
return m_localPlayer && !m_dead && m_protocolGame && m_protocolGame->isConnected() && checkBotProtection();
|
return m_localPlayer && !m_dead && m_protocolGame && m_protocolGame->isConnected() && checkBotProtection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::setClientVersion(int clientVersion)
|
void Game::setProtocolVersion(int version)
|
||||||
{
|
{
|
||||||
if(isOnline()) {
|
if(isOnline())
|
||||||
g_logger.error("Unable to change client version while online");
|
stdext::throw_exception("Unable to change client version while online");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: check supported versions
|
if(version < 810 || version > 960)
|
||||||
|
stdext::throw_exception(stdext::format("Protocol version %d not supported", version));
|
||||||
|
|
||||||
m_features.reset();
|
m_features.reset();
|
||||||
|
|
||||||
if(clientVersion >= 854) {
|
if(version >= 854) {
|
||||||
enableFeature(Otc::GameProtocolChecksum);
|
enableFeature(Otc::GameProtocolChecksum);
|
||||||
enableFeature(Otc::GameAccountNames);
|
enableFeature(Otc::GameAccountNames);
|
||||||
enableFeature(Otc::GameChallangeOnLogin);
|
enableFeature(Otc::GameChallangeOnLogin);
|
||||||
enableFeature(Otc::GameStackposOnTileAddThing);
|
|
||||||
enableFeature(Otc::GameDoubleFreeCapacity);
|
enableFeature(Otc::GameDoubleFreeCapacity);
|
||||||
enableFeature(Otc::GameCreatureAdditionalInfo);
|
enableFeature(Otc::GameCreatureEmblems);
|
||||||
enableFeature(Otc::GameReverseCreatureStack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(clientVersion >= 860) {
|
if(version >= 862) {
|
||||||
enableFeature(Otc::GameIdOnCancelAttack);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(clientVersion >= 862) {
|
|
||||||
enableFeature(Otc::GamePenalityOnDeath);
|
enableFeature(Otc::GamePenalityOnDeath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(clientVersion >= 870) {
|
if(version >= 870) {
|
||||||
enableFeature(Otc::GameDoubleExperience);
|
enableFeature(Otc::GameDoubleExperience);
|
||||||
enableFeature(Otc::GamePlayerMounts);
|
enableFeature(Otc::GamePlayerMounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(clientVersion >= 910) {
|
if(version >= 910) {
|
||||||
enableFeature(Otc::GameNameOnNpcTrade);
|
enableFeature(Otc::GameNameOnNpcTrade);
|
||||||
enableFeature(Otc::GameTotalCapacity);
|
enableFeature(Otc::GameTotalCapacity);
|
||||||
enableFeature(Otc::GameSkillsBase);
|
enableFeature(Otc::GameSkillsBase);
|
||||||
enableFeature(Otc::GameAdditionalPlayerStats);
|
enableFeature(Otc::GamePlayerRegenerationTime);
|
||||||
enableFeature(Otc::GameChannelPlayerList);
|
enableFeature(Otc::GameChannelPlayerList);
|
||||||
enableFeature(Otc::GameEnvironmentEffect);
|
enableFeature(Otc::GameEnvironmentEffect);
|
||||||
enableFeature(Otc::GameCreatureType);
|
|
||||||
enableFeature(Otc::GameItemAnimationPhase);
|
enableFeature(Otc::GameItemAnimationPhase);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(clientVersion >= 940) {
|
if(version >= 940) {
|
||||||
enableFeature(Otc::GamePlayerMarket);
|
enableFeature(Otc::GamePlayerMarket);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(clientVersion >= 953) {
|
m_protocolVersion = version;
|
||||||
enableFeature(Otc::GameCreaturePassableInfo);
|
|
||||||
enableFeature(Otc::GameTrucatedPingOpcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_clientVersion = clientVersion;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::setAttackingCreature(const CreaturePtr& creature)
|
void Game::setAttackingCreature(const CreaturePtr& creature)
|
||||||
|
|
|
@ -232,8 +232,8 @@ 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 setClientVersion(int clientVersion);
|
void setProtocolVersion(int version);
|
||||||
int getClientVersion() { return m_clientVersion; }
|
int getProtocolVersion() { 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; }
|
||||||
|
@ -256,7 +256,6 @@ public:
|
||||||
int getServerBeat() { return m_serverBeat; }
|
int getServerBeat() { return m_serverBeat; }
|
||||||
LocalPlayerPtr getLocalPlayer() { return m_localPlayer; }
|
LocalPlayerPtr getLocalPlayer() { return m_localPlayer; }
|
||||||
ProtocolGamePtr getProtocolGame() { return m_protocolGame; }
|
ProtocolGamePtr getProtocolGame() { return m_protocolGame; }
|
||||||
int getProtocolVersion() { return PROTOCOL; }
|
|
||||||
std::string getCharacterName() { return m_characterName; }
|
std::string getCharacterName() { return m_characterName; }
|
||||||
std::string getWorldName() { return m_worldName; }
|
std::string getWorldName() { return m_worldName; }
|
||||||
std::vector<uint8> getGMActions() { return m_gmActions; }
|
std::vector<uint8> getGMActions() { return m_gmActions; }
|
||||||
|
@ -288,7 +287,7 @@ private:
|
||||||
std::string m_characterName;
|
std::string m_characterName;
|
||||||
std::string m_worldName;
|
std::string m_worldName;
|
||||||
std::bitset<Otc::LastGameFeature> m_features;
|
std::bitset<Otc::LastGameFeature> m_features;
|
||||||
int m_clientVersion;
|
int m_protocolVersion;
|
||||||
std::string m_rsa;
|
std::string m_rsa;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ void Item::draw(const Point& dest, float scaleFactor, bool animate)
|
||||||
else if(tile->mustHookEast())
|
else if(tile->mustHookEast())
|
||||||
xPattern = getNumPatternX() >= 3 ? 2 : 0;
|
xPattern = getNumPatternX() >= 3 ? 2 : 0;
|
||||||
}
|
}
|
||||||
} else if(isFluid() || isFluidContainer()) {
|
} else if(isSplash() || isFluidContainer()) {
|
||||||
int color = Otc::FluidTransparent;
|
int color = Otc::FluidTransparent;
|
||||||
switch(m_countOrSubType) {
|
switch(m_countOrSubType) {
|
||||||
case Otc::FluidNone:
|
case Otc::FluidNone:
|
||||||
|
@ -176,15 +176,20 @@ void Item::draw(const Point& dest, float scaleFactor, bool animate)
|
||||||
|
|
||||||
void Item::setId(uint32 id)
|
void Item::setId(uint32 id)
|
||||||
{
|
{
|
||||||
m_otbId = g_things.findOtbForClientId(id)->getServerId();
|
if(!g_things.isValidDatId(id, DatItemCategory))
|
||||||
|
id = 0;
|
||||||
|
//m_otbId = g_things.findOtbForClientId(id)->getServerId();
|
||||||
m_id = id;
|
m_id = id;
|
||||||
|
m_otbId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Item::setOtbId(uint16 id)
|
void Item::setOtbId(uint16 id)
|
||||||
{
|
{
|
||||||
|
if(!g_things.isValidOtbId(id))
|
||||||
|
id = 0;
|
||||||
auto otbType = g_things.getOtbType(id);
|
auto otbType = g_things.getOtbType(id);
|
||||||
m_otbId = id;
|
|
||||||
m_id = otbType->getClientId();
|
m_id = otbType->getClientId();
|
||||||
|
m_otbId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Item::isValid()
|
bool Item::isValid()
|
||||||
|
|
|
@ -190,10 +190,10 @@ void OTClient::registerLuaFunctions()
|
||||||
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", "getProtocolVersion", &Game::getProtocolVersion, &g_game);
|
||||||
|
g_lua.bindSingletonFunction("g_game", "setProtocolVersion", &Game::setProtocolVersion, &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);
|
||||||
g_lua.bindSingletonFunction("g_game", "getClientVersion", &Game::getClientVersion, &g_game);
|
|
||||||
g_lua.bindSingletonFunction("g_game", "getFeature", &Game::getFeature, &g_game);
|
g_lua.bindSingletonFunction("g_game", "getFeature", &Game::getFeature, &g_game);
|
||||||
|
|
||||||
g_lua.registerSingletonClass("g_shaders");
|
g_lua.registerSingletonClass("g_shaders");
|
||||||
|
|
|
@ -467,7 +467,7 @@ bool Map::loadOtcm(const std::string& fileName)
|
||||||
uint8 countOrSubType = fin->getU8();
|
uint8 countOrSubType = fin->getU8();
|
||||||
|
|
||||||
ItemPtr item = Item::create(id);
|
ItemPtr item = Item::create(id);
|
||||||
if(item->isStackable() || item->isFluidContainer() || item->isFluid())
|
if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
|
||||||
item->setCountOrSubType(countOrSubType);
|
item->setCountOrSubType(countOrSubType);
|
||||||
|
|
||||||
if(item->isValid())
|
if(item->isValid())
|
||||||
|
|
|
@ -83,6 +83,8 @@ void Missile::setPath(const Position& fromPosition, const Position& toPosition)
|
||||||
|
|
||||||
void Missile::setId(uint32 id)
|
void Missile::setId(uint32 id)
|
||||||
{
|
{
|
||||||
|
if(!g_things.isValidDatId(id, DatMissileCategory))
|
||||||
|
id = 0;
|
||||||
m_id = id;
|
m_id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
Outfit::Outfit()
|
Outfit::Outfit()
|
||||||
{
|
{
|
||||||
m_category = DatCreatureCategory;
|
m_category = DatCreatureCategory;
|
||||||
m_id = 1;
|
m_id = 0;
|
||||||
resetClothes();
|
resetClothes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,49 +25,7 @@
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
#if !(PROTOCOL == 810) && \
|
|
||||||
!(PROTOCOL == 854) && \
|
|
||||||
!(PROTOCOL >= 860 && PROTOCOL <= 862) && \
|
|
||||||
!(PROTOCOL >= 870 && PROTOCOL <= 871) && \
|
|
||||||
!(PROTOCOL >= 910 && PROTOCOL <= 953)
|
|
||||||
#error "the supplied protocol version is not supported"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Proto {
|
namespace Proto {
|
||||||
#ifdef CIPSOFT_RSA
|
|
||||||
constexpr const char* RSA = "1321277432058722840622950990822933849527763264961655079678763618"
|
|
||||||
"4334395343554449668205332383339435179772895415509701210392836078"
|
|
||||||
"6959821132214473291575712138800495033169914814069637740318278150"
|
|
||||||
"2907336840325241747827401343576296990629870233111328210165697754"
|
|
||||||
"88792221429527047321331896351555606801473202394175817";
|
|
||||||
#else
|
|
||||||
constexpr const char* RSA = "1091201329673994292788609605089955415282375029027981291234687579"
|
|
||||||
"3726629149257644633073969600111060390723088861007265581882535850"
|
|
||||||
"3429057592827629436413108566029093628212635953836686562675849720"
|
|
||||||
"6207862794310902180176810615217550567108238764764442605581471797"
|
|
||||||
"07119674283982419152118103759076030616683978566631413";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
constexpr int PicSignature = 0x4F8C231A; // 953 pic signature
|
|
||||||
constexpr int ClientVersion = PROTOCOL;
|
|
||||||
|
|
||||||
enum OsTypes {
|
|
||||||
OsLinux = 1,
|
|
||||||
OsWindows = 2,
|
|
||||||
OsFlash = 3,
|
|
||||||
OsOtclientLinux = 10,
|
|
||||||
OsOtclientWindows = 11,
|
|
||||||
OsOtclientMac = 12
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef OSTYPE
|
|
||||||
constexpr int ClientOs = OSTYPE;
|
|
||||||
#elif defined WIN32
|
|
||||||
constexpr int ClientOs = OsOtclientWindows;
|
|
||||||
#else
|
|
||||||
constexpr int ClientOs = OsOtclientLinux;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum LoginServerOpts {
|
enum LoginServerOpts {
|
||||||
LoginServerError = 10,
|
LoginServerError = 10,
|
||||||
LoginServerMotd = 20,
|
LoginServerMotd = 20,
|
||||||
|
|
|
@ -43,8 +43,11 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
||||||
opcode = msg->getU8();
|
opcode = msg->getU8();
|
||||||
|
|
||||||
// try to parse in lua first
|
// try to parse in lua first
|
||||||
|
int readPos = msg->getReadPos();
|
||||||
if(callLuaField<bool>("onOpcode", opcode, msg))
|
if(callLuaField<bool>("onOpcode", opcode, msg))
|
||||||
continue;
|
continue;
|
||||||
|
else
|
||||||
|
msg->setReadPos(readPos); // restore read pos
|
||||||
|
|
||||||
if(!m_gameInitialized && opcode > Proto::GameServerFirstGameOpcode)
|
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");
|
g_logger.warning("received a game opcode from the server, but the game is not initialized yet, this is a server side bug");
|
||||||
|
@ -66,16 +69,12 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
||||||
parseLoginWait(msg);
|
parseLoginWait(msg);
|
||||||
break;
|
break;
|
||||||
case Proto::GameServerPing:
|
case Proto::GameServerPing:
|
||||||
if(g_game.getFeature(Otc::GameTrucatedPingOpcode))
|
|
||||||
parsePingBack(msg);
|
|
||||||
else
|
|
||||||
parsePing(msg);
|
|
||||||
break;
|
|
||||||
case Proto::GameServerPingBack:
|
case Proto::GameServerPingBack:
|
||||||
if(g_game.getFeature(Otc::GameTrucatedPingOpcode))
|
if((opcode == Proto::GameServerPing && g_game.getProtocolVersion() >= 953) ||
|
||||||
parsePing(msg);
|
(opcode == Proto::GameServerPingBack && g_game.getProtocolVersion() < 953))
|
||||||
else
|
|
||||||
parsePingBack(msg);
|
parsePingBack(msg);
|
||||||
|
else
|
||||||
|
parsePing(msg);
|
||||||
break;
|
break;
|
||||||
case Proto::GameServerChallange:
|
case Proto::GameServerChallange:
|
||||||
parseChallange(msg);
|
parseChallange(msg);
|
||||||
|
@ -334,9 +333,9 @@ void ProtocolGame::parseGMActions(const InputMessagePtr& msg)
|
||||||
|
|
||||||
int numViolationReasons;
|
int numViolationReasons;
|
||||||
|
|
||||||
if(g_game.getClientVersion() >= 860)
|
if(g_game.getProtocolVersion() >= 860)
|
||||||
numViolationReasons = 20;
|
numViolationReasons = 20;
|
||||||
else if(g_game.getClientVersion() >= 854)
|
else if(g_game.getProtocolVersion() >= 854)
|
||||||
numViolationReasons = 19;
|
numViolationReasons = 19;
|
||||||
else
|
else
|
||||||
numViolationReasons = 32;
|
numViolationReasons = 32;
|
||||||
|
@ -454,7 +453,7 @@ void ProtocolGame::parseTileAddThing(const InputMessagePtr& msg)
|
||||||
Position pos = getPosition(msg);
|
Position pos = getPosition(msg);
|
||||||
int stackPos = -1;
|
int stackPos = -1;
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GameStackposOnTileAddThing))
|
if(g_game.getProtocolVersion() >= 854)
|
||||||
stackPos = msg->getU8();
|
stackPos = msg->getU8();
|
||||||
|
|
||||||
ThingPtr thing = getThing(msg);
|
ThingPtr thing = getThing(msg);
|
||||||
|
@ -508,7 +507,7 @@ void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg)
|
||||||
int stackPos = -2;
|
int stackPos = -2;
|
||||||
|
|
||||||
// older protocols stores creatures in reverse order
|
// older protocols stores creatures in reverse order
|
||||||
if(!g_game.getFeature(Otc::GameReverseCreatureStack))
|
if(!g_game.getProtocolVersion() >= 854)
|
||||||
stackPos = -1;
|
stackPos = -1;
|
||||||
|
|
||||||
g_map.addThing(thing, newPos, stackPos);
|
g_map.addThing(thing, newPos, stackPos);
|
||||||
|
@ -884,12 +883,11 @@ 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.getFeature(Otc::GameAdditionalPlayerStats)) {
|
if(g_game.getProtocolVersion() >= 910)
|
||||||
int speed = msg->getU16();
|
m_localPlayer->setSpeed(msg->getU16());
|
||||||
msg->getU16(); // regeneration time
|
|
||||||
|
|
||||||
m_localPlayer->setSpeed(speed);
|
if(g_game.getFeature(Otc::GamePlayerRegenerationTime))
|
||||||
}
|
msg->getU16(); // regeneration time
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::parsePlayerSkills(const InputMessagePtr& msg)
|
void ProtocolGame::parsePlayerSkills(const InputMessagePtr& msg)
|
||||||
|
@ -913,7 +911,7 @@ void ProtocolGame::parsePlayerState(const InputMessagePtr& msg)
|
||||||
|
|
||||||
void ProtocolGame::parsePlayerCancelAttack(const InputMessagePtr& msg)
|
void ProtocolGame::parsePlayerCancelAttack(const InputMessagePtr& msg)
|
||||||
{
|
{
|
||||||
if(g_game.getFeature(Otc::GameIdOnCancelAttack))
|
if(g_game.getProtocolVersion() >= 860)
|
||||||
msg->getU32(); // unknown
|
msg->getU32(); // unknown
|
||||||
|
|
||||||
g_game.processAttackCancel();
|
g_game.processAttackCancel();
|
||||||
|
@ -1389,7 +1387,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
||||||
uint id = msg->getU32();
|
uint id = msg->getU32();
|
||||||
|
|
||||||
int creatureType;
|
int creatureType;
|
||||||
if(g_game.getFeature(Otc::GameCreatureType))
|
if(g_game.getProtocolVersion() >= 910)
|
||||||
creatureType = msg->getU8();
|
creatureType = msg->getU8();
|
||||||
else {
|
else {
|
||||||
if(id >= Proto::PlayerStartId && id < Proto::PlayerEndId)
|
if(id >= Proto::PlayerStartId && id < Proto::PlayerEndId)
|
||||||
|
@ -1441,12 +1439,11 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
||||||
int emblem = -1;
|
int emblem = -1;
|
||||||
bool passable = false;
|
bool passable = false;
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GameCreatureAdditionalInfo)) {
|
if(g_game.getFeature(Otc::GameCreatureEmblems) && !known)
|
||||||
if(!known)
|
emblem = msg->getU8();
|
||||||
emblem = msg->getU8();
|
|
||||||
|
|
||||||
|
if(g_game.getProtocolVersion() >= 854)
|
||||||
passable = (msg->getU8() == 0);
|
passable = (msg->getU8() == 0);
|
||||||
}
|
|
||||||
|
|
||||||
if(creature) {
|
if(creature) {
|
||||||
creature->setHealthPercent(healthPercent);
|
creature->setHealthPercent(healthPercent);
|
||||||
|
@ -1474,7 +1471,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
|
||||||
if(creature)
|
if(creature)
|
||||||
creature->turn(direction);
|
creature->turn(direction);
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GameCreaturePassableInfo)) {
|
if(g_game.getProtocolVersion() >= 953) {
|
||||||
bool passable = msg->getU8();
|
bool passable = msg->getU8();
|
||||||
|
|
||||||
if(creature)
|
if(creature)
|
||||||
|
@ -1497,7 +1494,7 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
|
||||||
if(item->getId() == 0)
|
if(item->getId() == 0)
|
||||||
stdext::throw_exception("unable to create item with invalid id 0");
|
stdext::throw_exception("unable to create item with invalid id 0");
|
||||||
|
|
||||||
if(item->isStackable() || item->isFluidContainer() || item->isFluid())
|
if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
|
||||||
item->setCountOrSubType(msg->getU8());
|
item->setCountOrSubType(msg->getU8());
|
||||||
|
|
||||||
if(g_game.getFeature(Otc::GameItemAnimationPhase)) {
|
if(g_game.getFeature(Otc::GameItemAnimationPhase)) {
|
||||||
|
|
|
@ -49,8 +49,9 @@ void ProtocolGame::sendLoginPacket(uint challangeTimestamp, uint8 challangeRando
|
||||||
OutputMessagePtr msg(new OutputMessage);
|
OutputMessagePtr msg(new OutputMessage);
|
||||||
|
|
||||||
msg->addU8(Proto::ClientEnterGame);
|
msg->addU8(Proto::ClientEnterGame);
|
||||||
msg->addU16(Proto::ClientOs);
|
|
||||||
msg->addU16(g_game.getClientVersion());
|
msg->addU16(g_lua.callGlobalField<int>("g_game", "getOs"));
|
||||||
|
msg->addU16(g_game.getProtocolVersion());
|
||||||
|
|
||||||
int paddingBytes = 128;
|
int paddingBytes = 128;
|
||||||
msg->addU8(0); // first RSA byte must be 0
|
msg->addU8(0); // first RSA byte must be 0
|
||||||
|
@ -90,7 +91,7 @@ void ProtocolGame::sendLoginPacket(uint challangeTimestamp, uint8 challangeRando
|
||||||
msg->addPaddingBytes(paddingBytes);
|
msg->addPaddingBytes(paddingBytes);
|
||||||
|
|
||||||
// encrypt with RSA
|
// encrypt with RSA
|
||||||
msg->encryptRSA(128, Proto::RSA);
|
msg->encryptRsa(128, g_lua.callGlobalField<std::string>("g_game", "getRsa"));
|
||||||
|
|
||||||
send(msg);
|
send(msg);
|
||||||
|
|
||||||
|
@ -570,9 +571,10 @@ void ProtocolGame::sendShareExperience(bool active, int unknown)
|
||||||
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 PROTOCOL<910
|
|
||||||
msg->addU8(unknown);
|
if(g_game.getProtocolVersion() < 910)
|
||||||
#endif
|
msg->addU8(unknown);
|
||||||
|
|
||||||
send(msg);
|
send(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,12 +28,6 @@
|
||||||
#include "thingtypemanager.h"
|
#include "thingtypemanager.h"
|
||||||
#include <framework/luaengine/luaobject.h>
|
#include <framework/luaengine/luaobject.h>
|
||||||
|
|
||||||
struct Light
|
|
||||||
{
|
|
||||||
uint8 intensity;
|
|
||||||
uint8 color;
|
|
||||||
};
|
|
||||||
|
|
||||||
// @bindclass
|
// @bindclass
|
||||||
#pragma pack(push,1) // disable memory alignment
|
#pragma pack(push,1) // disable memory alignment
|
||||||
class Thing : public LuaObject
|
class Thing : public LuaObject
|
||||||
|
@ -95,8 +89,7 @@ public:
|
||||||
int getAnimationPhases() { return rawGetDatType()->getAnimationPhases(); }
|
int getAnimationPhases() { return rawGetDatType()->getAnimationPhases(); }
|
||||||
int getGroundSpeed() { return rawGetDatType()->getGroundSpeed(); }
|
int getGroundSpeed() { return rawGetDatType()->getGroundSpeed(); }
|
||||||
int getMaxTextLength() { return rawGetDatType()->getMaxTextLength(); }
|
int getMaxTextLength() { return rawGetDatType()->getMaxTextLength(); }
|
||||||
int getLightLevel() { return rawGetDatType()->getLightLevel(); }
|
Light getLight() { return rawGetDatType()->getLight(); }
|
||||||
int getLightColor() { return rawGetDatType()->getLightColor(); }
|
|
||||||
int getMinimapColor() { return rawGetDatType()->getMinimapColor(); }
|
int getMinimapColor() { return rawGetDatType()->getMinimapColor(); }
|
||||||
int getLensHelp() { return rawGetDatType()->getLensHelp(); }
|
int getLensHelp() { return rawGetDatType()->getLensHelp(); }
|
||||||
int getClothSlot() { return rawGetDatType()->getClothSlot(); }
|
int getClothSlot() { return rawGetDatType()->getClothSlot(); }
|
||||||
|
@ -110,9 +103,10 @@ public:
|
||||||
bool isForceUse() { return rawGetDatType()->isForceUse(); }
|
bool isForceUse() { return rawGetDatType()->isForceUse(); }
|
||||||
bool isMultiUse() { return rawGetDatType()->isMultiUse(); }
|
bool isMultiUse() { return rawGetDatType()->isMultiUse(); }
|
||||||
bool isWritable() { return rawGetDatType()->isWritable(); }
|
bool isWritable() { return rawGetDatType()->isWritable(); }
|
||||||
|
bool isChargeable() { return rawGetDatType()->isChargeable(); }
|
||||||
bool isWritableOnce() { return rawGetDatType()->isWritableOnce(); }
|
bool isWritableOnce() { return rawGetDatType()->isWritableOnce(); }
|
||||||
bool isFluidContainer() { return rawGetDatType()->isFluidContainer(); }
|
bool isFluidContainer() { return rawGetDatType()->isFluidContainer(); }
|
||||||
bool isFluid() { return rawGetDatType()->isFluid(); }
|
bool isSplash() { return rawGetDatType()->isSplash(); }
|
||||||
bool isNotWalkable() { return rawGetDatType()->isNotWalkable(); }
|
bool isNotWalkable() { return rawGetDatType()->isNotWalkable(); }
|
||||||
bool isNotMoveable() { return rawGetDatType()->isNotMoveable(); }
|
bool isNotMoveable() { return rawGetDatType()->isNotMoveable(); }
|
||||||
bool blockProjectile() { return rawGetDatType()->blockProjectile(); }
|
bool blockProjectile() { return rawGetDatType()->blockProjectile(); }
|
||||||
|
@ -134,6 +128,7 @@ public:
|
||||||
bool isFullGround() { return rawGetDatType()->isFullGround(); }
|
bool isFullGround() { return rawGetDatType()->isFullGround(); }
|
||||||
bool isIgnoreLook() { return rawGetDatType()->isIgnoreLook(); }
|
bool isIgnoreLook() { return rawGetDatType()->isIgnoreLook(); }
|
||||||
bool isCloth() { return rawGetDatType()->isCloth(); }
|
bool isCloth() { return rawGetDatType()->isCloth(); }
|
||||||
|
MarketData getMarketData() { return rawGetDatType()->getMarketData(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Position m_position;
|
Position m_position;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "thingtypedat.h"
|
#include "thingtypedat.h"
|
||||||
#include "spritemanager.h"
|
#include "spritemanager.h"
|
||||||
|
#include "game.h"
|
||||||
|
|
||||||
#include <framework/graphics/graphics.h>
|
#include <framework/graphics/graphics.h>
|
||||||
#include <framework/graphics/texture.h>
|
#include <framework/graphics/texture.h>
|
||||||
|
@ -33,20 +34,11 @@ ThingTypeDat::ThingTypeDat()
|
||||||
{
|
{
|
||||||
m_category = DatInvalidCategory;
|
m_category = DatInvalidCategory;
|
||||||
m_id = 0;
|
m_id = 0;
|
||||||
|
m_null = true;
|
||||||
m_exactSize = 0;
|
m_exactSize = 0;
|
||||||
m_layers = 0;
|
m_numPatternX = m_numPatternY = m_numPatternZ = 0;
|
||||||
m_numPatternX = 0;
|
|
||||||
m_numPatternY = 0;
|
|
||||||
m_numPatternZ = 0;
|
|
||||||
m_animationPhases = 0;
|
m_animationPhases = 0;
|
||||||
m_groundSpeed = 0;
|
m_layers = 0;
|
||||||
m_maxTextLenght = 0;
|
|
||||||
m_lightLevel = 0;
|
|
||||||
m_lightColor = 0;
|
|
||||||
m_miniMapColor = 0;
|
|
||||||
m_lensHelp = 0;
|
|
||||||
m_clothSlot = 0;
|
|
||||||
m_elevation = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThingTypeDat::unserialize(uint16 clientId, DatCategory category, const FileStreamPtr& fin)
|
void ThingTypeDat::unserialize(uint16 clientId, DatCategory category, const FileStreamPtr& fin)
|
||||||
|
@ -55,136 +47,68 @@ void ThingTypeDat::unserialize(uint16 clientId, DatCategory category, const File
|
||||||
m_id = clientId;
|
m_id = clientId;
|
||||||
m_category = category;
|
m_category = category;
|
||||||
|
|
||||||
|
|
||||||
|
static int datVersion;
|
||||||
|
if(clientId == 100 && category == DatItemCategory)
|
||||||
|
datVersion = 2;
|
||||||
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
for(int i = 0 ; i < DatLastAttrib;++i) {
|
for(int i = 0 ; i < DatLastAttrib;++i) {
|
||||||
int property = fin->getU8();
|
int attrib = fin->getU8();
|
||||||
if(property == DatLastAttrib) {
|
if(attrib == DatLastAttrib) {
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(property) {
|
// hacky way to detect if is older dat version or not
|
||||||
case DatAttribIsGround:
|
if(clientId == 100 && category == DatItemCategory && datVersion != 1 &&
|
||||||
m_isGround = true;
|
(attrib == DatAttribNotPathable || attrib == DatAttribDontHide || attrib == DatAttribIgnoreLook)) {
|
||||||
m_groundSpeed = fin->getU16();
|
datVersion = 1;
|
||||||
if(m_groundSpeed == 0)
|
}
|
||||||
m_groundSpeed = 100;
|
if(datVersion <= 1) {
|
||||||
|
if(attrib == DatAttribWritable) {
|
||||||
|
m_attribs.set(DatAttribChargeable, true);
|
||||||
|
continue;
|
||||||
|
} else if(attrib > DatAttribWritable)
|
||||||
|
attrib -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(attrib) {
|
||||||
|
case DatAttribDisplacement: {
|
||||||
|
m_displacement.x = fin->getU16();
|
||||||
|
m_displacement.y = fin->getU16();
|
||||||
|
m_attribs.set(attrib, true);
|
||||||
break;
|
break;
|
||||||
case DatAttribIsGroundBorder:
|
}
|
||||||
m_isGroundBorder = true;
|
case DatAttribLight: {
|
||||||
|
Light light;
|
||||||
|
light.intensity = fin->getU16();
|
||||||
|
light.color = fin->getU16();
|
||||||
|
m_attribs.set(attrib, light);
|
||||||
break;
|
break;
|
||||||
case DatAttribIsOnBottom:
|
}
|
||||||
m_isOnBottom = true;
|
case DatAttribMarket: {
|
||||||
break;
|
MarketData market;
|
||||||
case DatAttribIsOnTop:
|
market.category = fin->getU16();
|
||||||
m_isOnTop = true;
|
market.showAs = fin->getU16();
|
||||||
break;
|
market.tradeAs = fin->getU16();
|
||||||
case DatAttribIsContainer:
|
market.name = fin->getString();
|
||||||
m_isContainer = true;
|
market.restrictProfession = fin->getU16();
|
||||||
break;
|
market.requiredLevel = fin->getU16();
|
||||||
case DatAttribIsStackable:
|
m_attribs.set(attrib, market);
|
||||||
m_isStackable = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIsForceUse:
|
|
||||||
m_isForceUse = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIsMultiUse:
|
|
||||||
m_isMultiUse = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIsWritable:
|
|
||||||
m_isWritable = true;
|
|
||||||
m_maxTextLenght = fin->getU16();
|
|
||||||
break;
|
|
||||||
case DatAttribIsWritableOnce:
|
|
||||||
m_isWritableOnce = true;
|
|
||||||
m_maxTextLenght = fin->getU16();
|
|
||||||
break;
|
|
||||||
case DatAttribIsFluidContainer:
|
|
||||||
m_isFluidContainer = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIsFluid:
|
|
||||||
m_isFluid = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIsNotWalkable:
|
|
||||||
m_isNotWalkable = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIsNotMoveable:
|
|
||||||
m_isNotMoveable = true;
|
|
||||||
break;
|
|
||||||
case DatAttribBlockProjectile:
|
|
||||||
m_blockProjectile = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIsNotPathable:
|
|
||||||
m_isNotPathable = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIsPickupable:
|
|
||||||
m_isPickupable = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIsHangable:
|
|
||||||
m_isHangable = true;
|
|
||||||
break;
|
|
||||||
case DatAttribHookSouth:
|
|
||||||
m_isHookSouth = true;
|
|
||||||
break;
|
|
||||||
case DatAttribHookEast:
|
|
||||||
m_isHookEast = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIsRotateable:
|
|
||||||
m_isRotateable = true;
|
|
||||||
break;
|
|
||||||
case DatAttribHasLight:
|
|
||||||
m_hasLight = true;
|
|
||||||
m_lightLevel = fin->getU16();
|
|
||||||
m_lightColor = fin->getU16();
|
|
||||||
break;
|
|
||||||
case DatAttribDontHide:
|
|
||||||
m_isDontHide = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIsTranslucent:
|
|
||||||
m_isTranslucent = true;
|
|
||||||
break;
|
|
||||||
case DatAttribHasDisplacement:
|
|
||||||
m_hasDisplacement = true;
|
|
||||||
m_displacement = Point(fin->getU16(), fin->getU16());
|
|
||||||
break;
|
|
||||||
case DatAttribHasElevation:
|
|
||||||
m_hasElevation = true;
|
|
||||||
m_elevation = fin->getU16();
|
|
||||||
break;
|
|
||||||
case DatAttribIsLyingCorpse:
|
|
||||||
m_isLyingCorpse = true;
|
|
||||||
break;
|
|
||||||
case DatAttribAnimateAlways:
|
|
||||||
m_isAnimateAlways = true;
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case DatAttribGround:
|
||||||
|
case DatAttribWritable:
|
||||||
|
case DatAttribWritableOnce:
|
||||||
|
case DatAttribElevation:
|
||||||
case DatAttribMiniMapColor:
|
case DatAttribMiniMapColor:
|
||||||
m_miniMapColor = true;
|
|
||||||
m_miniMapColor = fin->getU16();
|
|
||||||
break;
|
|
||||||
case DatAttribLensHelp:
|
|
||||||
m_lensHelp = true;
|
|
||||||
m_lensHelp = fin->getU16();
|
|
||||||
break;
|
|
||||||
case DatAttribIsFullGround:
|
|
||||||
m_isFullGround = true;
|
|
||||||
break;
|
|
||||||
case DatAttribIgnoreLook:
|
|
||||||
m_isIgnoreLook = true;
|
|
||||||
break;
|
|
||||||
case DatAttribCloth:
|
case DatAttribCloth:
|
||||||
m_isCloth = true;
|
case DatAttribLensHelp:
|
||||||
m_clothSlot = fin->getU16();
|
m_attribs.set(attrib, fin->getU16());
|
||||||
break;
|
|
||||||
case DatAttribMarket:
|
|
||||||
fin->getU16(); // category
|
|
||||||
fin->getU16(); // trade as
|
|
||||||
fin->getU16(); // show as
|
|
||||||
fin->getString(); // name
|
|
||||||
fin->getU16(); // restrict profession
|
|
||||||
fin->getU16(); // level
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
stdext::throw_exception("corrupt data, invalid type attribute");
|
m_attribs.set(attrib, true);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -192,40 +116,18 @@ void ThingTypeDat::unserialize(uint16 clientId, DatCategory category, const File
|
||||||
if(!done)
|
if(!done)
|
||||||
stdext::throw_exception("corrupt data");
|
stdext::throw_exception("corrupt data");
|
||||||
|
|
||||||
int totalSprites = 1;
|
uint8 width = fin->getU8();
|
||||||
for(int i = 0; i < DatLastDimension; ++i) {
|
uint8 height = fin->getU8();
|
||||||
switch(i) {
|
m_size = Size(width, height);
|
||||||
case DatWidth:
|
m_exactSize = (width > 1 || height > 1) ? std::min((int)fin->getU8(), std::max(width * 32, height * 32)) : 32;
|
||||||
m_size.setWidth(fin->getU8());
|
m_layers = fin->getU8();
|
||||||
break;
|
m_numPatternX = fin->getU8();
|
||||||
case DatHeight:
|
m_numPatternY = fin->getU8();
|
||||||
m_size.setHeight(fin->getU8());
|
m_numPatternZ = fin->getU8();
|
||||||
break;
|
m_animationPhases = fin->getU8();
|
||||||
case DatExactSize:
|
|
||||||
if(m_size.width() <= 1 && m_size.height() <= 1)
|
int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
|
||||||
m_exactSize = 32;
|
|
||||||
else
|
|
||||||
m_exactSize = std::min((int)fin->getU8(), std::max(m_size.width() * 32, m_size.height() * 32));
|
|
||||||
break;
|
|
||||||
case DatLayers:
|
|
||||||
m_layers = fin->getU8();
|
|
||||||
break;
|
|
||||||
case DatPatternX:
|
|
||||||
m_numPatternX = fin->getU8();
|
|
||||||
break;
|
|
||||||
case DatPatternY:
|
|
||||||
m_numPatternY = fin->getU8();
|
|
||||||
break;
|
|
||||||
case DatPatternZ:
|
|
||||||
m_numPatternZ = fin->getU8();
|
|
||||||
break;
|
|
||||||
case DatAnimationPhases:
|
|
||||||
m_animationPhases = fin->getU8();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalSprites = m_size.width() * m_size.height() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
|
|
||||||
if(totalSprites == 0)
|
if(totalSprites == 0)
|
||||||
stdext::throw_exception("a thing type has no sprites");
|
stdext::throw_exception("a thing type has no sprites");
|
||||||
if(totalSprites > 4096)
|
if(totalSprites > 4096)
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <framework/graphics/coordsbuffer.h>
|
#include <framework/graphics/coordsbuffer.h>
|
||||||
#include <framework/luaengine/luaobject.h>
|
#include <framework/luaengine/luaobject.h>
|
||||||
#include <framework/net/server.h>
|
#include <framework/net/server.h>
|
||||||
|
#include <framework/util/attribstorage.h>
|
||||||
|
|
||||||
enum DatCategory {
|
enum DatCategory {
|
||||||
DatItemCategory = 0,
|
DatItemCategory = 0,
|
||||||
|
@ -48,53 +49,59 @@ enum DatSpriteMask {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DatAttrib {
|
enum DatAttrib {
|
||||||
DatAttribIsGround = 0,
|
DatAttribGround = 0,
|
||||||
DatAttribIsGroundBorder,
|
DatAttribGroundBorder,
|
||||||
DatAttribIsOnBottom,
|
DatAttribOnBottom,
|
||||||
DatAttribIsOnTop,
|
DatAttribOnTop,
|
||||||
DatAttribIsContainer,
|
DatAttribContainer,
|
||||||
DatAttribIsStackable,
|
DatAttribStackable,
|
||||||
DatAttribIsForceUse,
|
DatAttribForceUse,
|
||||||
DatAttribIsMultiUse,
|
DatAttribMultiUse,
|
||||||
DatAttribIsWritable,
|
//DatAttribRune
|
||||||
DatAttribIsWritableOnce,
|
DatAttribWritable,
|
||||||
DatAttribIsFluidContainer,
|
DatAttribWritableOnce,
|
||||||
DatAttribIsFluid,
|
DatAttribFluidContainer,
|
||||||
DatAttribIsNotWalkable,
|
DatAttribSplash,
|
||||||
DatAttribIsNotMoveable,
|
DatAttribNotWalkable,
|
||||||
|
DatAttribNotMoveable,
|
||||||
DatAttribBlockProjectile,
|
DatAttribBlockProjectile,
|
||||||
DatAttribIsNotPathable,
|
DatAttribNotPathable,
|
||||||
DatAttribIsPickupable,
|
DatAttribPickupable,
|
||||||
DatAttribIsHangable,
|
DatAttribHangable,
|
||||||
DatAttribHookSouth,
|
DatAttribHookSouth,
|
||||||
DatAttribHookEast,
|
DatAttribHookEast,
|
||||||
DatAttribIsRotateable,
|
DatAttribRotateable,
|
||||||
DatAttribHasLight,
|
DatAttribLight,
|
||||||
DatAttribDontHide,
|
DatAttribDontHide,
|
||||||
DatAttribIsTranslucent,
|
DatAttribTranslucent,
|
||||||
DatAttribHasDisplacement,
|
DatAttribDisplacement,
|
||||||
DatAttribHasElevation,
|
DatAttribElevation,
|
||||||
DatAttribIsLyingCorpse,
|
DatAttribLyingCorpse,
|
||||||
DatAttribAnimateAlways,
|
DatAttribAnimateAlways,
|
||||||
DatAttribMiniMapColor,
|
DatAttribMiniMapColor,
|
||||||
DatAttribLensHelp,
|
DatAttribLensHelp,
|
||||||
DatAttribIsFullGround,
|
DatAttribFullGround,
|
||||||
DatAttribIgnoreLook,
|
DatAttribIgnoreLook,
|
||||||
DatAttribCloth,
|
DatAttribCloth,
|
||||||
DatAttribMarket,
|
DatAttribMarket,
|
||||||
DatLastAttrib = 255
|
DatLastAttrib = 255,
|
||||||
|
|
||||||
|
// legacy attribs
|
||||||
|
DatAttribChargeable = 254
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DatDimension {
|
struct MarketData {
|
||||||
DatWidth = 0,
|
std::string name;
|
||||||
DatHeight,
|
int category;
|
||||||
DatExactSize,
|
uint16 requiredLevel;
|
||||||
DatLayers,
|
uint16 restrictProfession;
|
||||||
DatPatternX,
|
uint16 showAs;
|
||||||
DatPatternY,
|
uint16 tradeAs;
|
||||||
DatPatternZ,
|
};
|
||||||
DatAnimationPhases,
|
|
||||||
DatLastDimension
|
struct Light {
|
||||||
|
uint8 intensity;
|
||||||
|
uint8 color;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThingTypeDat : public LuaObject
|
class ThingTypeDat : public LuaObject
|
||||||
|
@ -113,56 +120,58 @@ public:
|
||||||
Size getSize() { return m_size; }
|
Size getSize() { return m_size; }
|
||||||
int getWidth() { return m_size.width(); }
|
int getWidth() { return m_size.width(); }
|
||||||
int getHeight() { return m_size.height(); }
|
int getHeight() { return m_size.height(); }
|
||||||
Point getDisplacement() { return m_displacement; }
|
|
||||||
int getDisplacementX() { return m_displacement.x; }
|
|
||||||
int getDisplacementY() { return m_displacement.y; }
|
|
||||||
int getExactSize() { return m_exactSize; }
|
int getExactSize() { return m_exactSize; }
|
||||||
int getLayers() { return m_layers; }
|
int getLayers() { return m_layers; }
|
||||||
int getNumPatternX() { return m_numPatternX; }
|
int getNumPatternX() { return m_numPatternX; }
|
||||||
int getNumPatternY() { return m_numPatternY; }
|
int getNumPatternY() { return m_numPatternY; }
|
||||||
int getNumPatternZ() { return m_numPatternZ; }
|
int getNumPatternZ() { return m_numPatternZ; }
|
||||||
int getAnimationPhases() { return m_animationPhases; }
|
int getAnimationPhases() { return m_animationPhases; }
|
||||||
int getGroundSpeed() { return m_groundSpeed; }
|
Point getDisplacement() { return m_displacement; }
|
||||||
int getMaxTextLength() { return m_maxTextLenght; }
|
int getDisplacementX() { return getDisplacement().x; }
|
||||||
int getLightLevel() { return m_lightLevel; }
|
int getDisplacementY() { return getDisplacement().y; }
|
||||||
int getLightColor() { return m_lightColor; }
|
|
||||||
int getMinimapColor() { return m_miniMapColor; }
|
int getGroundSpeed() { return m_attribs.get<uint16>(DatAttribGround); }
|
||||||
int getLensHelp() { return m_lensHelp; }
|
int getMaxTextLength() { return m_attribs.has(DatAttribWritableOnce) ? m_attribs.get<uint16>(DatAttribWritableOnce) : m_attribs.get<uint16>(DatAttribWritable); }
|
||||||
int getClothSlot() { return m_clothSlot; }
|
Light getLight() { return m_attribs.get<Light>(DatAttribLight); }
|
||||||
int getElevation() { return m_elevation; }
|
int getMinimapColor() { return m_attribs.get<uint16>(DatAttribMiniMapColor); }
|
||||||
bool isGround() { return m_isGround; }
|
int getLensHelp() { return m_attribs.get<uint16>(DatAttribLensHelp); }
|
||||||
bool isGroundBorder() { return m_isGroundBorder; }
|
int getClothSlot() { return m_attribs.get<uint16>(DatAttribCloth); }
|
||||||
bool isOnBottom() { return m_isOnBottom; }
|
int getElevation() { return m_attribs.get<uint16>(DatAttribElevation); }
|
||||||
bool isOnTop() { return m_isOnTop; }
|
MarketData getMarketData() { return m_attribs.get<MarketData>(DatAttribMarket); }
|
||||||
bool isContainer() { return m_isContainer; }
|
bool isGround() { return m_attribs.has(DatAttribGround); }
|
||||||
bool isStackable() { return m_isStackable; }
|
bool isGroundBorder() { return m_attribs.has(DatAttribGroundBorder); }
|
||||||
bool isForceUse() { return m_isForceUse; }
|
bool isOnBottom() { return m_attribs.has(DatAttribOnBottom); }
|
||||||
bool isMultiUse() { return m_isMultiUse; }
|
bool isOnTop() { return m_attribs.has(DatAttribOnTop); }
|
||||||
bool isWritable() { return m_isWritable; }
|
bool isContainer() { return m_attribs.has(DatAttribContainer); }
|
||||||
bool isWritableOnce() { return m_isWritableOnce; }
|
bool isStackable() { return m_attribs.has(DatAttribStackable); }
|
||||||
bool isFluidContainer() { return m_isFluidContainer; }
|
bool isForceUse() { return m_attribs.has(DatAttribForceUse); }
|
||||||
bool isFluid() { return m_isFluid; }
|
bool isMultiUse() { return m_attribs.has(DatAttribMultiUse); }
|
||||||
bool isNotWalkable() { return m_isNotWalkable; }
|
bool isWritable() { return m_attribs.has(DatAttribWritable); }
|
||||||
bool isNotMoveable() { return m_isNotMoveable; }
|
bool isChargeable() { return m_attribs.has(DatAttribChargeable); }
|
||||||
bool blockProjectile() { return m_blockProjectile; }
|
bool isWritableOnce() { return m_attribs.has(DatAttribWritableOnce); }
|
||||||
bool isNotPathable() { return m_isNotPathable; }
|
bool isFluidContainer() { return m_attribs.has(DatAttribFluidContainer); }
|
||||||
bool isPickupable() { return m_isPickupable; }
|
bool isSplash() { return m_attribs.has(DatAttribSplash); }
|
||||||
bool isHangable() { return m_isHangable; }
|
bool isNotWalkable() { return m_attribs.has(DatAttribNotWalkable); }
|
||||||
bool isHookSouth() { return m_isHookSouth; }
|
bool isNotMoveable() { return m_attribs.has(DatAttribNotMoveable); }
|
||||||
bool isHookEast() { return m_isHookEast; }
|
bool blockProjectile() { return m_attribs.has(DatAttribBlockProjectile); }
|
||||||
bool isRotateable() { return m_isRotateable; }
|
bool isNotPathable() { return m_attribs.has(DatAttribNotPathable); }
|
||||||
bool hasLight() { return m_hasLight; }
|
bool isPickupable() { return m_attribs.has(DatAttribPickupable); }
|
||||||
bool isDontHide() { return m_isDontHide; }
|
bool isHangable() { return m_attribs.has(DatAttribHangable); }
|
||||||
bool isTranslucent() { return m_isTranslucent; }
|
bool isHookSouth() { return m_attribs.has(DatAttribHookSouth); }
|
||||||
bool hasDisplacement() { return m_hasDisplacement; }
|
bool isHookEast() { return m_attribs.has(DatAttribHookEast); }
|
||||||
bool hasElevation() { return m_hasElevation; }
|
bool isRotateable() { return m_attribs.has(DatAttribRotateable); }
|
||||||
bool isLyingCorpse() { return m_isLyingCorpse; }
|
bool hasLight() { return m_attribs.has(DatAttribLight); }
|
||||||
bool isAnimateAlways() { return m_isAnimateAlways; }
|
bool isDontHide() { return m_attribs.has(DatAttribDontHide); }
|
||||||
bool hasMiniMapColor() { return m_hasMiniMapColor; }
|
bool isTranslucent() { return m_attribs.has(DatAttribTranslucent); }
|
||||||
bool hasLensHelp() { return m_hasLensHelp; }
|
bool hasDisplacement() { return m_attribs.has(DatAttribDisplacement); }
|
||||||
bool isFullGround() { return m_isFullGround; }
|
bool hasElevation() { return m_attribs.has(DatAttribElevation); }
|
||||||
bool isIgnoreLook() { return m_isIgnoreLook; }
|
bool isLyingCorpse() { return m_attribs.has(DatAttribLyingCorpse); }
|
||||||
bool isCloth() { return m_isCloth; }
|
bool isAnimateAlways() { return m_attribs.has(DatAttribAnimateAlways); }
|
||||||
|
bool hasMiniMapColor() { return m_attribs.has(DatAttribMiniMapColor); }
|
||||||
|
bool hasLensHelp() { return m_attribs.has(DatAttribLensHelp); }
|
||||||
|
bool isFullGround() { return m_attribs.has(DatAttribFullGround); }
|
||||||
|
bool isIgnoreLook() { return m_attribs.has(DatAttribIgnoreLook); }
|
||||||
|
bool isCloth() { return m_attribs.has(DatAttribCloth); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const TexturePtr& getTexture(int animationPhase);
|
const TexturePtr& getTexture(int animationPhase);
|
||||||
|
@ -172,64 +181,21 @@ private:
|
||||||
|
|
||||||
DatCategory m_category;
|
DatCategory m_category;
|
||||||
uint16 m_id;
|
uint16 m_id;
|
||||||
Boolean<true> m_null;
|
bool m_null;
|
||||||
|
AttribStorage m_attribs;
|
||||||
|
|
||||||
|
Size m_size;
|
||||||
|
Point m_displacement;
|
||||||
|
int m_exactSize;
|
||||||
|
int m_numPatternX, m_numPatternY, m_numPatternZ;
|
||||||
|
int m_animationPhases;
|
||||||
|
int m_layers;
|
||||||
|
|
||||||
std::vector<int> m_spritesIndex;
|
std::vector<int> m_spritesIndex;
|
||||||
std::vector<TexturePtr> m_textures;
|
std::vector<TexturePtr> m_textures;
|
||||||
std::vector<std::vector<Rect>> m_texturesFramesRects;
|
std::vector<std::vector<Rect>> m_texturesFramesRects;
|
||||||
std::vector<std::vector<Rect>> m_texturesFramesOriginRects;
|
std::vector<std::vector<Rect>> m_texturesFramesOriginRects;
|
||||||
std::vector<std::vector<Point>> m_texturesFramesOffsets;
|
std::vector<std::vector<Point>> m_texturesFramesOffsets;
|
||||||
|
|
||||||
// dat stuff
|
|
||||||
Size m_size;
|
|
||||||
Point m_displacement;
|
|
||||||
int m_exactSize;
|
|
||||||
int m_layers;
|
|
||||||
int m_numPatternX;
|
|
||||||
int m_numPatternY;
|
|
||||||
int m_numPatternZ;
|
|
||||||
int m_animationPhases;
|
|
||||||
int m_groundSpeed;
|
|
||||||
int m_maxTextLenght;
|
|
||||||
int m_lightLevel;
|
|
||||||
int m_lightColor;
|
|
||||||
int m_miniMapColor;
|
|
||||||
int m_lensHelp;
|
|
||||||
int m_clothSlot;
|
|
||||||
int m_elevation;
|
|
||||||
Boolean<false> m_isGround;
|
|
||||||
Boolean<false> m_isGroundBorder;
|
|
||||||
Boolean<false> m_isOnBottom;
|
|
||||||
Boolean<false> m_isOnTop;
|
|
||||||
Boolean<false> m_isContainer;
|
|
||||||
Boolean<false> m_isStackable;
|
|
||||||
Boolean<false> m_isForceUse;
|
|
||||||
Boolean<false> m_isMultiUse;
|
|
||||||
Boolean<false> m_isWritable;
|
|
||||||
Boolean<false> m_isWritableOnce;
|
|
||||||
Boolean<false> m_isFluidContainer;
|
|
||||||
Boolean<false> m_isFluid;
|
|
||||||
Boolean<false> m_isNotWalkable;
|
|
||||||
Boolean<false> m_isNotMoveable;
|
|
||||||
Boolean<false> m_blockProjectile;
|
|
||||||
Boolean<false> m_isNotPathable;
|
|
||||||
Boolean<false> m_isPickupable;
|
|
||||||
Boolean<false> m_isHangable;
|
|
||||||
Boolean<false> m_isHookSouth;
|
|
||||||
Boolean<false> m_isHookEast;
|
|
||||||
Boolean<false> m_isRotateable;
|
|
||||||
Boolean<false> m_hasLight;
|
|
||||||
Boolean<false> m_isDontHide;
|
|
||||||
Boolean<false> m_isTranslucent;
|
|
||||||
Boolean<false> m_hasDisplacement;
|
|
||||||
Boolean<false> m_hasElevation;
|
|
||||||
Boolean<false> m_isLyingCorpse;
|
|
||||||
Boolean<false> m_isAnimateAlways;
|
|
||||||
Boolean<false> m_hasMiniMapColor;
|
|
||||||
Boolean<false> m_hasLensHelp;
|
|
||||||
Boolean<false> m_isFullGround;
|
|
||||||
Boolean<false> m_isIgnoreLook;
|
|
||||||
Boolean<false> m_isCloth;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -367,7 +367,7 @@ ThingPtr Tile::getTopMultiUseThing()
|
||||||
for(uint i = 0; i < m_things.size(); ++i) {
|
for(uint i = 0; i < m_things.size(); ++i) {
|
||||||
ThingPtr thing = m_things[i];
|
ThingPtr thing = m_things[i];
|
||||||
if(thing->isForceUse() || (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop())) {
|
if(thing->isForceUse() || (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom() && !thing->isOnTop())) {
|
||||||
if(i > 0 && thing->isFluid())
|
if(i > 0 && thing->isSplash())
|
||||||
return m_things[i-1];
|
return m_things[i-1];
|
||||||
return thing;
|
return thing;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ void UIItem::drawSelf(Fw::DrawPane drawPane)
|
||||||
g_painter->setColor(Color::white);
|
g_painter->setColor(Color::white);
|
||||||
m_item->draw(dest, scaleFactor, true);
|
m_item->draw(dest, scaleFactor, true);
|
||||||
|
|
||||||
if(m_font && m_item->isStackable() && m_item->getCount() > 1) {
|
if(m_font && (m_item->isStackable() || m_item->isChargeable()) && m_item->getCount() > 1) {
|
||||||
std::string count = stdext::to_string(m_item->getCount());
|
std::string count = stdext::to_string(m_item->getCount());
|
||||||
g_painter->setColor(Color(231, 231, 231));
|
g_painter->setColor(Color(231, 231, 231));
|
||||||
m_font->drawText(count, Rect(m_rect.topLeft(), m_rect.bottomRight() - Point(3, 0)), Fw::AlignBottomRight);
|
m_font->drawText(count, Rect(m_rect.topLeft(), m_rect.bottomRight() - Point(3, 0)), Fw::AlignBottomRight);
|
||||||
|
|