More multiprotocol support

This commit is contained in:
Eduardo Bart
2012-07-26 03:10:28 -03:00
parent e393bc245d
commit c795eb91ab
43 changed files with 421 additions and 341 deletions

View File

@@ -92,7 +92,7 @@ end
local function onLoginWait(message, time)
CharacterList.destroyLoadBox()
waitingWindow = g_ui.loadUI('waitinglist.otui')
waitingWindow = g_ui.displayUI('waitinglist.otui')
local label = waitingWindow:getChildById('infoLabel')
label:setText(message)

View File

@@ -168,7 +168,8 @@ function EnterGame.doLogin()
end })
g_game.chooseRsa(G.host)
g_game.setProtocolVersion(protocol)
g_game.setClientVersion(protocol)
modules.game_tibiafiles.load()
protocolLogin:login(G.host, G.port, G.account, G.password)
end

View File

@@ -72,7 +72,14 @@ function connect(object, arg1, arg2, arg3)
end
end
function disconnect(object, signalsAndSlots)
function disconnect(object, arg1, arg2)
local signalsAndSlots
if type(arg1) == 'string' then
signalsAndSlots = { [arg1] = arg2 }
else
signalsAndSlots = arg1
end
for signal,slot in pairs(signalsAndSlots) do
if not object[signal] then
elseif type(object[signal]) == 'function' then
@@ -231,11 +238,19 @@ end
function signalcall(param, ...)
if type(param) == 'function' then
return param(...)
local status, ret = pcall(param, ...)
if status then
return ret
else
perror(ret)
end
elseif type(param) == 'table' then
for k,v in pairs(param) do
if v(...) then
return true
local status, ret = pcall(v, ...)
if status then
if ret then return true end
else
perror(ret)
end
end
elseif func ~= nil then

View File

@@ -91,7 +91,7 @@ end
function addAllCreatures()
local spectators = {}
local player = g_game.getLocalPlayer()
if player then
if g_game.isOnline() then
creatures = g_map.getSpectators(player:getPosition(), false)
for i, creature in ipairs(creatures) do
if creature ~= player and doCreatureFitFilters(creature) then
@@ -129,7 +129,7 @@ end
function checkCreatures(forceRecheck)
local player = g_game.getLocalPlayer()
if player then
if g_game.isOnline() then
local spectators = {}
-- reloading list of spectators

View File

@@ -135,10 +135,6 @@ function toggle()
end
end
function onMiniWindowClose()
combatControlsButton:setOn(false)
end
function onSetFightMode(self, selectedFightButton)
if selectedFightButton == nil then return end
local buttonId = selectedFightButton:getId()

View File

@@ -27,7 +27,6 @@ MiniWindow
!text: tr('Combat Controls')
icon: combatcontrols.png
height: 48
@onClose: CombatControls.onMiniWindowClose()
&save: true
MiniWindowContents

View File

@@ -37,14 +37,14 @@ function clean()
end
end
local function refreshContainerItems(container)
function refreshContainerItems(container)
for slot=0,container:getCapacity()-1 do
local itemWidget = container.itemsPanel:getChildById('item' .. slot)
itemWidget:setItem(container:getItem(slot))
end
end
local function onContainerOpen(container, previousContainer)
function onContainerOpen(container, previousContainer)
local containerWindow
if previousContainer then
containerWindow = previousContainer.window

View File

@@ -2,7 +2,7 @@ Icons = {}
Icons[1] = { tooltip = tr('You are poisoned'), path = '/game_healthinfo/icons/poisoned.png', id = 'condition_poisoned' }
Icons[2] = { tooltip = tr('You are burning'), path = '/game_healthinfo/icons/burning.png', id = 'condition_burning' }
Icons[4] = { tooltip = tr('You are electrified'), path = '/game_healthinfo/icons/electrified.png', id = 'condition_electrified' }
Icons[8] = { tooltip = tr('You are freezing'), path = '/game_healthinfo/icons/drunk.png', id = 'condition_drunk' }
Icons[8] = { tooltip = tr('You are drunk'), path = '/game_healthinfo/icons/drunk.png', id = 'condition_drunk' }
Icons[16] = { tooltip = tr('You are protected by a magic shield'), path = '/game_healthinfo/icons/magic_shield.png', id = 'condition_magic_shield' }
Icons[32] = { tooltip = tr('You are paralysed'), path = '/game_healthinfo/icons/slowed.png', id = 'condition_slowed' }
Icons[64] = { tooltip = tr('You are hasted'), path = '/game_healthinfo/icons/haste.png', id = 'condition_haste' }

View File

@@ -238,6 +238,7 @@ function startTradeWith(thing)
end
function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
if not g_game.isOnline() then return end
local menu = g_ui.createWidget('PopupMenu')
if lookThing then
@@ -297,52 +298,50 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
else
local localPlayer = g_game.getLocalPlayer()
if localPlayer then
if g_game.getAttackingCreature() ~= creatureThing then
menu:addOption(tr('Attack'), function() g_game.attack(creatureThing) end)
else
menu:addOption(tr('Stop Attack'), function() g_game.cancelAttack() end)
if g_game.getAttackingCreature() ~= creatureThing then
menu:addOption(tr('Attack'), function() g_game.attack(creatureThing) end)
else
menu:addOption(tr('Stop Attack'), function() g_game.cancelAttack() end)
end
if g_game.getFollowingCreature() ~= creatureThing then
menu:addOption(tr('Follow'), function() g_game.follow(creatureThing) end)
else
menu:addOption(tr('Stop Follow'), function() g_game.cancelFollow() end)
end
if creatureThing:asPlayer() then
menu:addSeparator()
local creatureName = creatureThing:getName()
menu:addOption(tr('Message to %s', creatureName), function() g_game.openPrivateChannel(creatureName) end)
if modules.game_console.getOwnPrivateTab() then
menu:addOption(tr('Invite to private chat'), function() g_game.inviteToOwnChannel(creatureName) end)
menu:addOption(tr('Exclude from private chat'), function() g_game.excludeFromOwnChannel(creatureName) end) -- [TODO] must be removed after message's popup labels been implemented
end
if (not Player:hasVip(creatureName)) then
menu:addOption(tr('Add to VIP list'), function() g_game.addVip(creatureName) end)
end
if g_game.getFollowingCreature() ~= creatureThing then
menu:addOption(tr('Follow'), function() g_game.follow(creatureThing) end)
else
menu:addOption(tr('Stop Follow'), function() g_game.cancelFollow() end)
end
local localPlayerShield = localPlayer:asCreature():getShield()
local creatureShield = creatureThing:getShield()
if creatureThing:asPlayer() then
menu:addSeparator()
local creatureName = creatureThing:getName()
menu:addOption(tr('Message to %s', creatureName), function() g_game.openPrivateChannel(creatureName) end)
if modules.game_console.getOwnPrivateTab() then
menu:addOption(tr('Invite to private chat'), function() g_game.inviteToOwnChannel(creatureName) end)
menu:addOption(tr('Exclude from private chat'), function() g_game.excludeFromOwnChannel(creatureName) end) -- [TODO] must be removed after message's popup labels been implemented
if localPlayerShield == ShieldNone or localPlayerShield == ShieldWhiteBlue then
if creatureShield == ShieldWhiteYellow then
menu:addOption(tr('Join %s\'s Party', creatureThing:getName()), function() g_game.partyJoin(creatureThing:getId()) end)
else
menu:addOption(tr('Invite to Party'), function() g_game.partyInvite(creatureThing:getId()) end)
end
if (not Player:hasVip(creatureName)) then
menu:addOption(tr('Add to VIP list'), function() g_game.addVip(creatureName) end)
elseif localPlayerShield == ShieldWhiteYellow then
if creatureShield == ShieldWhiteBlue then
menu:addOption(tr('Revoke %s\'s Invitation', creatureThing:getName()), function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
end
local localPlayerShield = localPlayer:asCreature():getShield()
local creatureShield = creatureThing:getShield()
if localPlayerShield == ShieldNone or localPlayerShield == ShieldWhiteBlue then
if creatureShield == ShieldWhiteYellow then
menu:addOption(tr('Join %s\'s Party', creatureThing:getName()), function() g_game.partyJoin(creatureThing:getId()) end)
else
menu:addOption(tr('Invite to Party'), function() g_game.partyInvite(creatureThing:getId()) end)
end
elseif localPlayerShield == ShieldWhiteYellow then
if creatureShield == ShieldWhiteBlue then
menu:addOption(tr('Revoke %s\'s Invitation', creatureThing:getName()), function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
end
elseif localPlayerShield == ShieldYellow or localPlayerShield == ShieldYellowSharedExp or localPlayerShield == ShieldYellowNoSharedExpBlink or localPlayerShield == ShieldYellowNoSharedExp then
if creatureShield == ShieldWhiteBlue then
menu:addOption(tr('Revoke %s\'s Invitation', creatureThing:getName()), function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
elseif creatureShield == ShieldBlue or creatureShield == ShieldBlueSharedExp or creatureShield == ShieldBlueNoSharedExpBlink or creatureShield == ShieldBlueNoSharedExp then
menu:addOption(tr('Pass Leadership to %s', creatureThing:getName()), function() g_game.partyPassLeadership(creatureThing:getId()) end)
else
menu:addOption(tr('Invite to Party'), function() g_game.partyInvite(creatureThing:getId()) end)
end
elseif localPlayerShield == ShieldYellow or localPlayerShield == ShieldYellowSharedExp or localPlayerShield == ShieldYellowNoSharedExpBlink or localPlayerShield == ShieldYellowNoSharedExp then
if creatureShield == ShieldWhiteBlue then
menu:addOption(tr('Revoke %s\'s Invitation', creatureThing:getName()), function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
elseif creatureShield == ShieldBlue or creatureShield == ShieldBlueSharedExp or creatureShield == ShieldBlueNoSharedExpBlink or creatureShield == ShieldBlueNoSharedExp then
menu:addOption(tr('Pass Leadership to %s', creatureThing:getName()), function() g_game.partyPassLeadership(creatureThing:getId()) end)
else
menu:addOption(tr('Invite to Party'), function() g_game.partyInvite(creatureThing:getId()) end)
end
end
end

View File

@@ -43,7 +43,7 @@ end
function refresh()
local player = g_game.getLocalPlayer()
for i=InventorySlotFirst,InventorySlotLast do
if player then
if g_game.isOnline() then
onInventoryChange(player, i, player:getInventoryItem(i))
else
onInventoryChange(player, i, nil)
@@ -67,8 +67,9 @@ end
-- hooked events
function onInventoryChange(player, slot, item, oldItem)
if slot >= InventorySlotPurse then return end
local itemWidget = inventoryPanel:getChildById('slot' .. slot)
if(item) then
if item then
itemWidget:setStyle('Item')
itemWidget:setItem(item)
else

View File

@@ -38,7 +38,7 @@ end
local function parseMarketEnter(msg)
local balance = msg:getU32()
local vocation = -1
if g_game.getProtocolVersion() < 950 then
if g_game.getClientVersion() < 950 then
vocation = msg:getU8() -- get vocation id
end
local offers = msg:getU8()
@@ -74,7 +74,8 @@ local function parseMarketDetail(msg)
end
local purchaseStats = {}
if msg:getU8() == 0x01 then
local count = msg:getU8()
for i=1,count do
local transactions = msg:getU32() -- transaction count
local totalPrice = msg:getU32() -- total price
local highestPrice = msg:getU32() -- highest price
@@ -84,7 +85,8 @@ local function parseMarketDetail(msg)
end
local saleStats = {}
if msg:getU8() == 0x01 then
count = msg:getU8()
for i=1,count do
local transactions = msg:getU32() -- transaction count
local totalPrice = msg:getU32() -- total price
local highestPrice = msg:getU32() -- highest price

View File

@@ -67,6 +67,7 @@ function loadReasons()
local actions = g_game.getGMActions()
for reason, actionFlags in pairs(actions) do
local label = g_ui.createWidget('RVListLabel', reasonsTextList)
label.onFocusChange = onSelectReason
label:setText(rvreasons[reason])
label.reasonId = reason
label.actionFlags = actionFlags

View File

@@ -2,7 +2,6 @@ RVListLabel < Label
background-color: alpha
text-offset: 2 0
focusable: true
@onFocusChange: function (self, focused) RuleViolation.onSelectReason(self, focused) end
$focus:
background-color: #ffffff22
@@ -109,7 +108,7 @@ MainWindow
width: 64
anchors.right: parent.right
anchors.bottom: parent.bottom
@onClick: RuleViolation.hide()
@onClick: hide()
Button
!text: tr('Ok')
@@ -117,4 +116,4 @@ MainWindow
margin-right: 5
anchors.right: prev.left
anchors.bottom: parent.bottom
@onClick: RuleViolation.report()
@onClick: report()

View File

@@ -47,7 +47,7 @@ end
function parseTextMessage(msg)
local msgtype = msg:getU8()
local text = msg:getString()
msgtype = getMessageTypes(g_game.getProtocolVersion())[msgtype]
msgtype = getMessageTypes(g_game.getClientVersion())[msgtype]
signalcall(g_game.onTextMessage, msgtype, text)
end

View File

@@ -1,11 +1,17 @@
function init()
if not g_things.loadDat('/game_tibiafiles/Tibia.dat') then
fatal(tr("Unable to load dat file, please place a valid Tibia dat in modules/game_tibiafiles/Tibia.dat"))
end
if not g_sprites.loadSpr('/game_tibiafiles/Tibia.spr') then
fatal(tr("Unable to load spr file, please place a valid Tibia spr in modules/game_tibiafiles/Tibia.spr"))
if g_game.getClientVersion() ~= 0 then
load()
end
end
function terminate()
function load()
local version = g_game.getClientVersion()
local datPath = resolvepath(version .. '/Tibia.dat')
local sprPath = resolvepath(version .. '/Tibia.spr')
if not g_things.loadDat(datPath) then
fatal(tr("Unable to load dat file, please place a valid dat in '%s'", datPath))
end
if not g_sprites.loadSpr(sprPath) then
fatal(tr("Unable to load spr file, please place a valid spr in '%s'", sprPath))
end
end

View File

@@ -71,6 +71,9 @@ CIPSOFT_RSA = "1321277432058722840622950990822933849527763264961655079678763618"
"2907336840325241747827401343576296990629870233111328210165697754" ..
"88792221429527047321331896351555606801473202394175817"
-- set to the latest Tibia.pic signature to make otclient compatible with official tibia
PIC_SIGNATURE = 1337606793
OsTypes = {
Linux = 1,
Windows = 2,

View File

@@ -11,6 +11,7 @@ InventorySlotLeg = 7
InventorySlotFeet = 8
InventorySlotFinger = 9
InventorySlotAmmo = 10
InventorySlotPurse = 11
InventorySlotFirst = 1
InventorySlotLast = 10

View File

@@ -1,89 +1,11 @@
-- @docclass
ProtocolLogin = extends(Protocol)
-- set to the latest Tibia.pic signature to make otclient compatible with official tibia
local PIC_SIGNATURE = 1337606793
LoginServerError = 10
LoginServerMotd = 20
LoginServerUpdateNeeded = 30
LoginServerCharacterList = 100
-- private functions
local function sendLoginPacket(protocol)
local msg = OutputMessage.create()
msg:addU8(ClientOpcodes.ClientEnterAccount)
msg:addU16(g_game.getOsType())
msg:addU16(g_game.getProtocolVersion())
msg:addU32(g_things.getDatSignature())
msg:addU32(g_sprites.getSprSignature())
msg:addU32(PIC_SIGNATURE)
local paddingBytes = 128
msg:addU8(0) -- first RSA byte must be 0
paddingBytes = paddingBytes - 1
-- xtea key
protocol:generateXteaKey()
local xteaKey = protocol:getXteaKey()
msg:addU32(xteaKey[1])
msg:addU32(xteaKey[2])
msg:addU32(xteaKey[3])
msg:addU32(xteaKey[4])
paddingBytes = paddingBytes - 16
if g_game.getFeature(GameProtocolChecksum) then
protocol:enableChecksum()
end
if g_game.getFeature(GameAccountNames) then
msg:addString(protocol.accountName)
msg:addString(protocol.accountPassword)
paddingBytes = paddingBytes - (4 + string.len(protocol.accountName) + string.len(protocol.accountPassword))
else
msg:addU32(tonumber(protocol.accountName))
msg:addString(protocol.accountPassword)
paddingBytes = paddingBytes - (6 + string.len(protocol.accountPassword))
end
msg:addPaddingBytes(paddingBytes, 0)
msg:encryptRsa(128, g_game.getRsa())
protocol:send(msg)
protocol:enableXteaEncryption()
protocol:recv()
end
-- events
function ProtocolLogin:onConnect()
self:connectCallback(self)
end
function ProtocolLogin:onRecv(msg)
while not msg:eof() do
local opcode = msg:getU8()
if opcode == LoginServerError then
self:parseError(msg)
elseif opcode == LoginServerMotd then
self:parseMotd(msg)
elseif opcode == LoginServerUpdateNeeded then
signalcall(self.onError, self, tr("Client needs update."))
elseif opcode == LoginServerCharacterList then
self:parseCharacterList(msg)
else
self:parseOpcode(opcode, msg)
end
end
self:disconnect()
end
-- public functions
function ProtocolLogin.create()
return ProtocolLogin.internalCreate()
end
function ProtocolLogin:login(host, port, accountName, accountPassword)
if string.len(accountName) == 0 or string.len(accountPassword) == 0 then
signalcall(self.onError, self, tr("You must enter an account name and password."))
@@ -105,6 +27,73 @@ function ProtocolLogin:cancelLogin()
self:disconnect()
end
function ProtocolLogin:sendLoginPacket()
local msg = OutputMessage.create()
msg:addU8(ClientOpcodes.ClientEnterAccount)
msg:addU16(g_game.getOsType())
msg:addU16(g_game.getClientVersion())
msg:addU32(g_things.getDatSignature())
msg:addU32(g_sprites.getSprSignature())
msg:addU32(PIC_SIGNATURE)
local paddingBytes = 128
msg:addU8(0) -- first RSA byte must be 0
paddingBytes = paddingBytes - 1
-- xtea key
self:generateXteaKey()
local xteaKey = self:getXteaKey()
msg:addU32(xteaKey[1])
msg:addU32(xteaKey[2])
msg:addU32(xteaKey[3])
msg:addU32(xteaKey[4])
paddingBytes = paddingBytes - 16
if g_game.getFeature(GameProtocolChecksum) then
self:enableChecksum()
end
if g_game.getFeature(GameAccountNames) then
msg:addString(self.accountName)
msg:addString(self.accountPassword)
paddingBytes = paddingBytes - (4 + string.len(self.accountName) + string.len(self.accountPassword))
else
msg:addU32(tonumber(self.accountName))
msg:addString(self.accountPassword)
paddingBytes = paddingBytes - (6 + string.len(self.accountPassword))
end
msg:addPaddingBytes(paddingBytes, 0)
msg:encryptRsa(128, g_game.getRsa())
self:send(msg)
self:enableXteaEncryption()
self:recv()
end
function ProtocolLogin:onConnect()
self:sendLoginPacket()
end
function ProtocolLogin:onRecv(msg)
while not msg:eof() do
local opcode = msg:getU8()
if opcode == LoginServerError then
self:parseError(msg)
elseif opcode == LoginServerMotd then
self:parseMotd(msg)
elseif opcode == LoginServerUpdateNeeded then
signalcall(self.onError, self, tr("Client needs update."))
elseif opcode == LoginServerCharacterList then
self:parseCharacterList(msg)
else
self:parseOpcode(opcode, msg)
end
end
self:disconnect()
end
function ProtocolLogin:parseError(msg)
local errorMessage = msg:getString()
signalcall(self.onError, self, errorMessage)