Browse Source

More multiprotocol support

Eduardo Bart 8 years ago
parent
commit
c795eb91ab
43 changed files with 389 additions and 305 deletions
  1. 1
    1
      modules/client_entergame/characterlist.lua
  2. 2
    1
      modules/client_entergame/entergame.lua
  3. 19
    4
      modules/corelib/util.lua
  4. 2
    2
      modules/game_battle/battle.lua
  5. 0
    4
      modules/game_combatcontrols/combatcontrols.lua
  6. 0
    1
      modules/game_combatcontrols/combatcontrols.otui
  7. 2
    2
      modules/game_containers/containers.lua
  8. 1
    1
      modules/game_healthinfo/healthinfo.lua
  9. 40
    41
      modules/game_interface/gameinterface.lua
  10. 3
    2
      modules/game_inventory/inventory.lua
  11. 5
    3
      modules/game_market/marketprotocol.lua
  12. 1
    0
      modules/game_ruleviolation/ruleviolation.lua
  13. 2
    3
      modules/game_ruleviolation/ruleviolation.otui
  14. 1
    1
      modules/game_textmessage/protocol.lua
  15. 12
    6
      modules/game_tibiafiles/tibiafiles.lua
  16. 3
    0
      modules/gamelib/const.lua
  17. 1
    0
      modules/gamelib/player.lua
  18. 35
    42
      modules/gamelib/protocollogin.lua
  19. 2
    2
      src/framework/graphics/painterogl2_shadersources.h
  20. 1
    0
      src/framework/luafunctions.cpp
  21. 1
    1
      src/framework/sound/soundmanager.h
  22. 1
    1
      src/framework/ui/uianchorlayout.h
  23. 12
    0
      src/framework/ui/uiwidget.cpp
  24. 1
    0
      src/framework/ui/uiwidget.h
  25. 1
    1
      src/otclient/creature.h
  26. 22
    23
      src/otclient/game.cpp
  27. 10
    6
      src/otclient/game.h
  28. 2
    2
      src/otclient/item.cpp
  29. 2
    2
      src/otclient/luafunctions.cpp
  30. 1
    1
      src/otclient/map.cpp
  31. 1
    1
      src/otclient/map.h
  32. 1
    1
      src/otclient/otclient.cpp
  33. 2
    1
      src/otclient/protocolcodes.h
  34. 1
    2
      src/otclient/protocolgame.cpp
  35. 9
    7
      src/otclient/protocolgame.h
  36. 148
    109
      src/otclient/protocolgameparse.cpp
  37. 8
    8
      src/otclient/protocolgamesend.cpp
  38. 4
    4
      src/otclient/spritemanager.cpp
  39. 1
    1
      src/otclient/spritemanager.h
  40. 1
    1
      src/otclient/thing.cpp
  41. 15
    14
      src/otclient/thingtypemanager.cpp
  42. 1
    1
      src/otclient/thingtypemanager.h
  43. 11
    2
      src/otclient/tile.cpp

+ 1
- 1
modules/client_entergame/characterlist.lua View File

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

+ 2
- 1
modules/client_entergame/entergame.lua View File

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

+ 19
- 4
modules/corelib/util.lua View File

@@ -72,7 +72,14 @@ function connect(object, arg1, arg2, arg3)
72 72
   end
73 73
 end
74 74
 
75
-function disconnect(object, signalsAndSlots)
75
+function disconnect(object, arg1, arg2)
76
+  local signalsAndSlots
77
+  if type(arg1) == 'string' then
78
+    signalsAndSlots = { [arg1] = arg2 }
79
+  else
80
+    signalsAndSlots = arg1
81
+  end
82
+
76 83
   for signal,slot in pairs(signalsAndSlots) do
77 84
     if not object[signal] then
78 85
     elseif type(object[signal]) == 'function' then
@@ -231,11 +238,19 @@ end
231 238
 
232 239
 function signalcall(param, ...)
233 240
   if type(param) == 'function' then
234
-    return param(...)
241
+    local status, ret = pcall(param, ...)
242
+    if status then
243
+      return ret
244
+    else
245
+      perror(ret)
246
+    end
235 247
   elseif type(param) == 'table' then
236 248
     for k,v in pairs(param) do
237
-      if v(...) then
238
-        return true
249
+      local status, ret = pcall(v, ...)
250
+      if status then
251
+        if ret then return true end
252
+      else
253
+        perror(ret)
239 254
       end
240 255
     end
241 256
   elseif func ~= nil then

+ 2
- 2
modules/game_battle/battle.lua View File

@@ -91,7 +91,7 @@ end
91 91
 function addAllCreatures()
92 92
   local spectators = {}
93 93
     local player = g_game.getLocalPlayer()
94
-    if player then
94
+    if g_game.isOnline() then
95 95
         creatures = g_map.getSpectators(player:getPosition(), false)
96 96
         for i, creature in ipairs(creatures) do
97 97
             if creature ~= player and doCreatureFitFilters(creature) then
@@ -129,7 +129,7 @@ end
129 129
 
130 130
 function checkCreatures(forceRecheck)
131 131
   local player = g_game.getLocalPlayer()
132
-  if player then
132
+  if g_game.isOnline() then
133 133
     local spectators = {}
134 134
 
135 135
     -- reloading list of spectators

+ 0
- 4
modules/game_combatcontrols/combatcontrols.lua View File

@@ -135,10 +135,6 @@ function toggle()
135 135
   end
136 136
 end
137 137
 
138
-function onMiniWindowClose()
139
-  combatControlsButton:setOn(false)
140
-end
141
-
142 138
 function onSetFightMode(self, selectedFightButton)
143 139
   if selectedFightButton == nil then return end
144 140
   local buttonId = selectedFightButton:getId()

+ 0
- 1
modules/game_combatcontrols/combatcontrols.otui View File

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

+ 2
- 2
modules/game_containers/containers.lua View File

@@ -37,14 +37,14 @@ function clean()
37 37
   end
38 38
 end
39 39
 
40
-local function refreshContainerItems(container)
40
+function refreshContainerItems(container)
41 41
   for slot=0,container:getCapacity()-1 do
42 42
     local itemWidget = container.itemsPanel:getChildById('item' .. slot)
43 43
     itemWidget:setItem(container:getItem(slot))
44 44
   end
45 45
 end
46 46
 
47
-local function onContainerOpen(container, previousContainer)
47
+function onContainerOpen(container, previousContainer)
48 48
   local containerWindow
49 49
   if previousContainer then
50 50
     containerWindow = previousContainer.window

+ 1
- 1
modules/game_healthinfo/healthinfo.lua View File

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

+ 40
- 41
modules/game_interface/gameinterface.lua View File

@@ -238,6 +238,7 @@ function startTradeWith(thing)
238 238
 end
239 239
 
240 240
 function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
241
+  if not g_game.isOnline() then return end
241 242
   local menu = g_ui.createWidget('PopupMenu')
242 243
 
243 244
   if lookThing then
@@ -297,52 +298,50 @@ function createThingMenu(menuPosition, lookThing, useThing, creatureThing)
297 298
 
298 299
     else
299 300
       local localPlayer = g_game.getLocalPlayer()
300
-      if localPlayer then
301
-        if g_game.getAttackingCreature() ~= creatureThing then
302
-          menu:addOption(tr('Attack'), function() g_game.attack(creatureThing) end)
303
-        else
304
-          menu:addOption(tr('Stop Attack'), function() g_game.cancelAttack() end)
305
-        end
301
+      if g_game.getAttackingCreature() ~= creatureThing then
302
+        menu:addOption(tr('Attack'), function() g_game.attack(creatureThing) end)
303
+      else
304
+        menu:addOption(tr('Stop Attack'), function() g_game.cancelAttack() end)
305
+      end
306 306
 
307
-        if g_game.getFollowingCreature() ~= creatureThing then
308
-          menu:addOption(tr('Follow'), function() g_game.follow(creatureThing) end)
309
-        else
310
-          menu:addOption(tr('Stop Follow'), function() g_game.cancelFollow() end)
307
+      if g_game.getFollowingCreature() ~= creatureThing then
308
+        menu:addOption(tr('Follow'), function() g_game.follow(creatureThing) end)
309
+      else
310
+        menu:addOption(tr('Stop Follow'), function() g_game.cancelFollow() end)
311
+      end
312
+
313
+      if creatureThing:asPlayer() then
314
+        menu:addSeparator()
315
+        local creatureName = creatureThing:getName()
316
+        menu:addOption(tr('Message to %s', creatureName), function() g_game.openPrivateChannel(creatureName) end)
317
+        if modules.game_console.getOwnPrivateTab() then
318
+          menu:addOption(tr('Invite to private chat'), function() g_game.inviteToOwnChannel(creatureName) end)
319
+          menu:addOption(tr('Exclude from private chat'), function() g_game.excludeFromOwnChannel(creatureName) end) -- [TODO] must be removed after message's popup labels been implemented
320
+        end
321
+        if (not Player:hasVip(creatureName)) then
322
+          menu:addOption(tr('Add to VIP list'), function() g_game.addVip(creatureName) end)
311 323
         end
312 324
 
313
-        if creatureThing:asPlayer() then
314
-          menu:addSeparator()
315
-          local creatureName = creatureThing:getName()
316
-          menu:addOption(tr('Message to %s', creatureName), function() g_game.openPrivateChannel(creatureName) end)
317
-          if modules.game_console.getOwnPrivateTab() then
318
-            menu:addOption(tr('Invite to private chat'), function() g_game.inviteToOwnChannel(creatureName) end)
319
-            menu:addOption(tr('Exclude from private chat'), function() g_game.excludeFromOwnChannel(creatureName) end) -- [TODO] must be removed after message's popup labels been implemented
325
+        local localPlayerShield = localPlayer:asCreature():getShield()
326
+        local creatureShield = creatureThing:getShield()
327
+
328
+        if localPlayerShield == ShieldNone or localPlayerShield == ShieldWhiteBlue then
329
+          if creatureShield == ShieldWhiteYellow then
330
+            menu:addOption(tr('Join %s\'s Party', creatureThing:getName()), function() g_game.partyJoin(creatureThing:getId()) end)
331
+          else
332
+            menu:addOption(tr('Invite to Party'), function() g_game.partyInvite(creatureThing:getId()) end)
320 333
           end
321
-          if (not Player:hasVip(creatureName)) then
322
-            menu:addOption(tr('Add to VIP list'), function() g_game.addVip(creatureName) end)
334
+        elseif localPlayerShield == ShieldWhiteYellow then
335
+          if creatureShield == ShieldWhiteBlue then
336
+            menu:addOption(tr('Revoke %s\'s Invitation', creatureThing:getName()), function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
323 337
           end
324
-
325
-          local localPlayerShield = localPlayer:asCreature():getShield()
326
-          local creatureShield = creatureThing:getShield()
327
-
328
-          if localPlayerShield == ShieldNone or localPlayerShield == ShieldWhiteBlue then
329
-            if creatureShield == ShieldWhiteYellow then
330
-              menu:addOption(tr('Join %s\'s Party', creatureThing:getName()), function() g_game.partyJoin(creatureThing:getId()) end)
331
-            else
332
-              menu:addOption(tr('Invite to Party'), function() g_game.partyInvite(creatureThing:getId()) end)
333
-            end
334
-          elseif localPlayerShield == ShieldWhiteYellow then
335
-            if creatureShield == ShieldWhiteBlue then
336
-              menu:addOption(tr('Revoke %s\'s Invitation', creatureThing:getName()), function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
337
-            end
338
-          elseif localPlayerShield == ShieldYellow or localPlayerShield == ShieldYellowSharedExp or localPlayerShield == ShieldYellowNoSharedExpBlink or localPlayerShield == ShieldYellowNoSharedExp then
339
-            if creatureShield == ShieldWhiteBlue then
340
-              menu:addOption(tr('Revoke %s\'s Invitation', creatureThing:getName()), function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
341
-            elseif creatureShield == ShieldBlue or creatureShield == ShieldBlueSharedExp or creatureShield == ShieldBlueNoSharedExpBlink or creatureShield == ShieldBlueNoSharedExp then
342
-              menu:addOption(tr('Pass Leadership to %s', creatureThing:getName()), function() g_game.partyPassLeadership(creatureThing:getId()) end)
343
-            else
344
-              menu:addOption(tr('Invite to Party'), function() g_game.partyInvite(creatureThing:getId()) end)
345
-            end
338
+        elseif localPlayerShield == ShieldYellow or localPlayerShield == ShieldYellowSharedExp or localPlayerShield == ShieldYellowNoSharedExpBlink or localPlayerShield == ShieldYellowNoSharedExp then
339
+          if creatureShield == ShieldWhiteBlue then
340
+            menu:addOption(tr('Revoke %s\'s Invitation', creatureThing:getName()), function() g_game.partyRevokeInvitation(creatureThing:getId()) end)
341
+          elseif creatureShield == ShieldBlue or creatureShield == ShieldBlueSharedExp or creatureShield == ShieldBlueNoSharedExpBlink or creatureShield == ShieldBlueNoSharedExp then
342
+            menu:addOption(tr('Pass Leadership to %s', creatureThing:getName()), function() g_game.partyPassLeadership(creatureThing:getId()) end)
343
+          else
344
+            menu:addOption(tr('Invite to Party'), function() g_game.partyInvite(creatureThing:getId()) end)
346 345
           end
347 346
         end
348 347
       end

+ 3
- 2
modules/game_inventory/inventory.lua View File

@@ -43,7 +43,7 @@ end
43 43
 function refresh()
44 44
   local player = g_game.getLocalPlayer()
45 45
   for i=InventorySlotFirst,InventorySlotLast do
46
-    if player then
46
+    if g_game.isOnline() then
47 47
       onInventoryChange(player, i, player:getInventoryItem(i))
48 48
     else
49 49
       onInventoryChange(player, i, nil)
@@ -67,8 +67,9 @@ end
67 67
 
68 68
 -- hooked events
69 69
 function onInventoryChange(player, slot, item, oldItem)
70
+  if slot >= InventorySlotPurse then return end
70 71
   local itemWidget = inventoryPanel:getChildById('slot' .. slot)
71
-  if(item) then
72
+  if item then
72 73
     itemWidget:setStyle('Item')
73 74
     itemWidget:setItem(item)
74 75
   else

+ 5
- 3
modules/game_market/marketprotocol.lua View File

@@ -38,7 +38,7 @@ end
38 38
 local function parseMarketEnter(msg)
39 39
   local balance = msg:getU32()
40 40
   local vocation = -1
41
-  if g_game.getProtocolVersion() < 950 then
41
+  if g_game.getClientVersion() < 950 then
42 42
     vocation = msg:getU8() -- get vocation id
43 43
   end
44 44
   local offers = msg:getU8()
@@ -74,7 +74,8 @@ local function parseMarketDetail(msg)
74 74
   end
75 75
 
76 76
   local purchaseStats = {}
77
-  if msg:getU8() == 0x01 then
77
+  local count = msg:getU8()
78
+  for i=1,count do
78 79
     local transactions = msg:getU32() -- transaction count
79 80
     local totalPrice = msg:getU32() -- total price
80 81
     local highestPrice = msg:getU32() -- highest price
@@ -84,7 +85,8 @@ local function parseMarketDetail(msg)
84 85
   end
85 86
 
86 87
   local saleStats = {}
87
-  if msg:getU8() == 0x01 then
88
+  count = msg:getU8()
89
+  for i=1,count do
88 90
     local transactions = msg:getU32() -- transaction count
89 91
     local totalPrice = msg:getU32() -- total price
90 92
     local highestPrice = msg:getU32() -- highest price

+ 1
- 0
modules/game_ruleviolation/ruleviolation.lua View File

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

+ 2
- 3
modules/game_ruleviolation/ruleviolation.otui View File

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

+ 1
- 1
modules/game_textmessage/protocol.lua View File

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

+ 12
- 6
modules/game_tibiafiles/tibiafiles.lua View File

@@ -1,11 +1,17 @@
1 1
 function init()
2
-  if not g_things.loadDat('/game_tibiafiles/Tibia.dat') then
3
-    fatal(tr("Unable to load dat file, please place a valid Tibia dat in modules/game_tibiafiles/Tibia.dat"))
4
-  end
5
-  if not g_sprites.loadSpr('/game_tibiafiles/Tibia.spr') then
6
-    fatal(tr("Unable to load spr file, please place a valid Tibia spr in modules/game_tibiafiles/Tibia.spr"))
2
+  if g_game.getClientVersion() ~= 0 then
3
+    load()
7 4
   end
8 5
 end
9 6
 
10
-function terminate()
7
+function load()
8
+  local version = g_game.getClientVersion()
9
+  local datPath = resolvepath(version .. '/Tibia.dat')
10
+  local sprPath = resolvepath(version .. '/Tibia.spr')
11
+  if not g_things.loadDat(datPath) then
12
+    fatal(tr("Unable to load dat file, please place a valid dat in '%s'", datPath))
13
+  end
14
+  if not g_sprites.loadSpr(sprPath) then
15
+    fatal(tr("Unable to load spr file, please place a valid spr in '%s'", sprPath))
16
+  end
11 17
 end

+ 3
- 0
modules/gamelib/const.lua View File

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

+ 1
- 0
modules/gamelib/player.lua View File

@@ -11,6 +11,7 @@ InventorySlotLeg = 7
11 11
 InventorySlotFeet = 8
12 12
 InventorySlotFinger = 9
13 13
 InventorySlotAmmo = 10
14
+InventorySlotPurse = 11
14 15
 
15 16
 InventorySlotFirst = 1
16 17
 InventorySlotLast = 10

+ 35
- 42
modules/gamelib/protocollogin.lua View File

@@ -1,21 +1,37 @@
1 1
 -- @docclass
2 2
 ProtocolLogin = extends(Protocol)
3 3
 
4
-local PIC_SIGNATURE = 1337606793
5
-
6 4
 LoginServerError = 10
7 5
 LoginServerMotd = 20
8 6
 LoginServerUpdateNeeded = 30
9 7
 LoginServerCharacterList = 100
10 8
 
9
+function ProtocolLogin:login(host, port, accountName, accountPassword)
10
+  if string.len(accountName) == 0 or string.len(accountPassword) == 0 then
11
+    signalcall(self.onError, self, tr("You must enter an account name and password."))
12
+    return
13
+  end
14
+  if string.len(host) == 0 or port == nil or port == 0 then
15
+    signalcall(self.onError, self, tr("You must enter a valid server address and port."))
16
+    return
17
+  end
18
+
19
+  self.accountName = accountName
20
+  self.accountPassword = accountPassword
21
+  self.connectCallback = sendLoginPacket
22
+
23
+  self:connect(host, port)
24
+end
11 25
 
12
-local function sendLoginPacket(protocol)
26
+function ProtocolLogin:cancelLogin()
27
+  self:disconnect()
28
+end
29
+
30
+function ProtocolLogin:sendLoginPacket()
13 31
   local msg = OutputMessage.create()
14 32
   msg:addU8(ClientOpcodes.ClientEnterAccount)
15 33
   msg:addU16(g_game.getOsType())
16
-  msg:addU16(g_game.getProtocolVersion())
34
+  msg:addU16(g_game.getClientVersion())
17 35
 
18 36
   msg:addU32(g_things.getDatSignature())
19 37
   msg:addU32(g_sprites.getSprSignature())
@@ -26,8 +42,8 @@ local function sendLoginPacket(protocol)
26 42
   paddingBytes = paddingBytes - 1
27 43
 
28 44
   -- xtea key
29
-  protocol:generateXteaKey()
30
-  local xteaKey = protocol:getXteaKey()
45
+  self:generateXteaKey()
46
+  local xteaKey = self:getXteaKey()
31 47
   msg:addU32(xteaKey[1])
32 48
   msg:addU32(xteaKey[2])
33 49
   msg:addU32(xteaKey[3])
@@ -35,30 +51,29 @@ local function sendLoginPacket(protocol)
35 51
   paddingBytes = paddingBytes - 16
36 52
 
37 53
   if g_game.getFeature(GameProtocolChecksum) then
38
-    protocol:enableChecksum()
54
+    self:enableChecksum()
39 55
   end
40 56
 
41 57
   if g_game.getFeature(GameAccountNames) then
42
-    msg:addString(protocol.accountName)
43
-    msg:addString(protocol.accountPassword)
44
-    paddingBytes = paddingBytes - (4 + string.len(protocol.accountName) + string.len(protocol.accountPassword))
58
+    msg:addString(self.accountName)
59
+    msg:addString(self.accountPassword)
60
+    paddingBytes = paddingBytes - (4 + string.len(self.accountName) + string.len(self.accountPassword))
45 61
   else
46
-    msg:addU32(tonumber(protocol.accountName))
47
-    msg:addString(protocol.accountPassword)
48
-    paddingBytes = paddingBytes - (6 + string.len(protocol.accountPassword))
62
+    msg:addU32(tonumber(self.accountName))
63
+    msg:addString(self.accountPassword)
64
+    paddingBytes = paddingBytes - (6 + string.len(self.accountPassword))
49 65
   end
50 66
 
51 67
   msg:addPaddingBytes(paddingBytes, 0)
52 68
   msg:encryptRsa(128, g_game.getRsa())
53 69
 
54
-  protocol:send(msg)
55
-  protocol:enableXteaEncryption()
56
-  protocol:recv()
70
+  self:send(msg)
71
+  self:enableXteaEncryption()
72
+  self:recv()
57 73
 end
58 74
 
59 75
 function ProtocolLogin:onConnect()
60
-  self:connectCallback(self)
76
+  self:sendLoginPacket()
61 77
 end
62 78
 
63 79
 function ProtocolLogin:onRecv(msg)
@@ -79,32 +94,6 @@ function ProtocolLogin:onRecv(msg)
79 94
   self:disconnect()
80 95
 end
81 96
 
82
-function ProtocolLogin.create()
83
-  return ProtocolLogin.internalCreate()
84
-end
85
-
86
-function ProtocolLogin:login(host, port, accountName, accountPassword)
87
-  if string.len(accountName) == 0 or string.len(accountPassword) == 0 then
88
-    signalcall(self.onError, self, tr("You must enter an account name and password."))
89
-    return
90
-  end
91
-  if string.len(host) == 0 or port == nil or port == 0 then
92
-    signalcall(self.onError, self, tr("You must enter a valid server address and port."))
93
-    return
94
-  end
95
-
96
-  self.accountName = accountName
97
-  self.accountPassword = accountPassword
98
-  self.connectCallback = sendLoginPacket
99
-
100
-  self:connect(host, port)
101
-end
102
-
103
-function ProtocolLogin:cancelLogin()
104
-  self:disconnect()
105
-end
106
-
107 97
 function ProtocolLogin:parseError(msg)
108 98
   local errorMessage = msg:getString()
109 99
   signalcall(self.onError, self, errorMessage)

+ 2
- 2
src/framework/graphics/painterogl2_shadersources.h View File

@@ -37,14 +37,14 @@ static const std::string glslMainWithTexCoordsVertexShader = "\n\
37 37
     void main()\n\
38 38
     {\n\
39 39
         gl_Position = calculatePosition();\n\
40
-        v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1)).xy;\n\
40
+        v_TexCoord = (u_TextureMatrix * vec3(a_TexCoord,1.0)).xy;\n\
41 41
     }\n";
42 42
 
43 43
 static std::string glslPositionOnlyVertexShader = "\n\
44 44
     attribute highp vec2 a_Vertex;\n\
45 45
     uniform highp mat3 u_ProjectionMatrix;\n\
46 46
     highp vec4 calculatePosition() {\n\
47
-        return vec4(u_ProjectionMatrix * vec3(a_Vertex.xy, 1), 1);\n\
47
+        return vec4(u_ProjectionMatrix * vec3(a_Vertex.xy, 1.0), 1.0);\n\
48 48
     }\n";
49 49
 
50 50
 static const std::string glslMainFragmentShader = "\n\

+ 1
- 0
src/framework/luafunctions.cpp View File

@@ -336,6 +336,7 @@ void Application::registerLuaFunctions()
336 336
     g_lua.bindClassMemberFunction<UIWidget>("getChildByIndex", &UIWidget::getChildByIndex);
337 337
     g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildById", &UIWidget::recursiveGetChildById);
338 338
     g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildByPos", &UIWidget::recursiveGetChildByPos);
339
+    g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildren", &UIWidget::recursiveGetChildren);
339 340
     g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildrenByPos", &UIWidget::recursiveGetChildrenByPos);
340 341
     g_lua.bindClassMemberFunction<UIWidget>("recursiveGetChildrenByMarginPos", &UIWidget::recursiveGetChildrenByMarginPos);
341 342
     g_lua.bindClassMemberFunction<UIWidget>("backwardsGetWidgetById", &UIWidget::backwardsGetWidgetById);

+ 1
- 1
src/framework/sound/soundmanager.h View File

@@ -56,7 +56,7 @@ private:
56 56
     SoundSourcePtr createSoundSource(const std::string& filename);
57 57
     uint loadFileIntoBuffer(const SoundFilePtr& soundFile);
58 58
 
59
-    std::map<std::string, SoundBufferPtr> m_buffers;
59
+    std::unordered_map<std::string, SoundBufferPtr> m_buffers;
60 60
     std::vector<SoundSourcePtr> m_sources;
61 61
     SoundSourcePtr m_musicSource;
62 62
     ALCdevice *m_device;

+ 1
- 1
src/framework/ui/uianchorlayout.h View File

@@ -81,7 +81,7 @@ protected:
81 81
 
82 82
 private:
83 83
     bool updateWidget(const UIWidgetPtr& widget, UIAnchorGroup& anchorGroup, UIWidgetPtr first = nullptr);
84
-    std::map<UIWidgetPtr, UIAnchorGroup> m_anchorsGroups;
84
+    std::unordered_map<UIWidgetPtr, UIAnchorGroup> m_anchorsGroups;
85 85
 };
86 86
 
87 87
 #endif

+ 12
- 0
src/framework/ui/uiwidget.cpp View File

@@ -1130,6 +1130,18 @@ UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos, bool wantsPh
1130 1130
     return nullptr;
1131 1131
 }
1132 1132
 
1133
+UIWidgetList UIWidget::recursiveGetChildren()
1134
+{
1135
+    UIWidgetList children;
1136
+    for(const UIWidgetPtr& child : m_children) {
1137
+        UIWidgetList subChildren = child->recursiveGetChildren();
1138
+        if(!subChildren.empty())
1139
+            children.insert(children.end(), subChildren.begin(), subChildren.end());
1140
+        children.push_back(child);
1141
+    }
1142
+    return children;
1143
+}
1144
+
1133 1145
 UIWidgetList UIWidget::recursiveGetChildrenByPos(const Point& childPos)
1134 1146
 {
1135 1147
     UIWidgetList children;

+ 1
- 0
src/framework/ui/uiwidget.h View File

@@ -147,6 +147,7 @@ public:
147 147
     UIWidgetPtr getChildByIndex(int index);
148 148
     UIWidgetPtr recursiveGetChildById(const std::string& id);
149 149
     UIWidgetPtr recursiveGetChildByPos(const Point& childPos, bool wantsPhantom);
150
+    UIWidgetList recursiveGetChildren();
150 151
     UIWidgetList recursiveGetChildrenByPos(const Point& childPos);
151 152
     UIWidgetList recursiveGetChildrenByMarginPos(const Point& childPos);
152 153
     UIWidgetPtr backwardsGetWidgetById(const std::string& id);

+ 1
- 1
src/otclient/creature.h View File

@@ -79,7 +79,7 @@ public:
79 79
     uint8 getSkull() { return m_skull; }
80 80
     uint8 getShield() { return m_shield; }
81 81
     uint8 getEmblem() { return m_emblem; }
82
-    bool getPassable() { return m_passable; }
82
+    bool isPassable() { return m_passable; }
83 83
     Point getDrawOffset();
84 84
     Point getWalkOffset() { return m_walkOffset; }
85 85
 

+ 22
- 23
src/otclient/game.cpp View File

@@ -39,15 +39,16 @@ Game::Game()
39 39
 {
40 40
     resetGameStates();
41 41
     m_protocolVersion = 0;
42
-    setProtocolVersion(PROTOCOL);
43 42
 }
44 43
 
45 44
 void Game::resetGameStates()
46 45
 {
46
+    m_online = false;
47 47
     m_denyBotCall = false;
48 48
     m_dead = false;
49 49
     m_mounted = false;
50 50
     m_serverBeat = 50;
51
+    m_seq = 0;
51 52
     m_canReportBugs = false;
52 53
     m_fightMode = Otc::FightBalanced;
53 54
     m_chaseMode = Otc::DontChase;
@@ -104,15 +105,9 @@ void Game::processLoginWait(const std::string& message, int time)
104 105
     g_lua.callGlobalField("g_game", "onLoginWait", message, time);
105 106
 }
106 107
 
107
-void Game::processGameStart(const LocalPlayerPtr& localPlayer, int serverBeat, bool canReportBugs)
108
+void Game::processGameStart()
108 109
 {
109
-    // reset the new game state
110
-    resetGameStates();
111
-
112
-    m_localPlayer = localPlayer;
113
-    m_localPlayer->setName(m_characterName);
114
-    m_serverBeat = serverBeat;
115
-    m_canReportBugs = canReportBugs;
110
+    m_online = true;
116 111
 
117 112
     // synchronize fight modes with the server
118 113
     m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight);
@@ -401,9 +396,9 @@ void Game::processQuestLine(int questId, const std::vector<std::tuple<std::strin
401 396
     g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions);
402 397
 }
403 398
 
404
-void Game::processAttackCancel()
399
+void Game::processAttackCancel(uint seq)
405 400
 {
406
-    if(isAttacking())
401
+    if(isAttacking() && (seq == 0 || m_seq == seq))
407 402
         setAttackingCreature(nullptr);
408 403
 }
409 404
 
@@ -423,6 +418,12 @@ void Game::loginWorld(const std::string& account, const std::string& password, c
423 418
     if(m_protocolVersion == 0)
424 419
         stdext::throw_exception("Must set a valid game protocol version before logging.");
425 420
 
421
+    // reset the new game state
422
+    resetGameStates();
423
+
424
+    m_localPlayer = LocalPlayerPtr(new LocalPlayer);
425
+    m_localPlayer->setName(m_characterName);
426
+
426 427
     m_protocolGame = ProtocolGamePtr(new ProtocolGame);
427 428
     m_protocolGame->login(account, password, worldHost, (uint16)worldPort, characterName);
428 429
     m_characterName = characterName;
@@ -505,15 +506,10 @@ void Game::autoWalk(const std::vector<Otc::Direction>& dirs)
505 506
 
506 507
     Otc::Direction direction = dirs.front();
507 508
     TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
508
-    if(toTile && toTile->isWalkable())
509
+    if(toTile && toTile->isWalkable() && !m_localPlayer->isAutoWalking())
509 510
         m_localPlayer->preWalk(direction);
510 511
 
511
-    forceWalk(direction);
512
-
513
-    std::vector<Otc::Direction> nextDirs = dirs;
514
-    nextDirs.erase(nextDirs.begin());
515
-    if(nextDirs.size() > 0)
516
-        m_protocolGame->sendAutoWalk(nextDirs);
512
+    m_protocolGame->sendAutoWalk(dirs);
517 513
 
518 514
     g_lua.callGlobalField("g_game", "onAutoWalk", direction);
519 515
 }
@@ -737,7 +733,7 @@ void Game::attack(const CreaturePtr& creature)
737 733
         cancelFollow();
738 734
 
739 735
     setAttackingCreature(creature);
740
-    m_protocolGame->sendAttack(creature ? creature->getId() : 0);
736
+    m_protocolGame->sendAttack(creature ? creature->getId() : 0, ++m_seq);
741 737
 }
742 738
 
743 739
 void Game::follow(const CreaturePtr& creature)
@@ -751,7 +747,7 @@ void Game::follow(const CreaturePtr& creature)
751 747
         cancelAttack();
752 748
 
753 749
     setFollowingCreature(creature);
754
-    m_protocolGame->sendFollow(creature ? creature->getId() : 0);
750
+    m_protocolGame->sendFollow(creature ? creature->getId() : 0, ++m_seq);
755 751
 }
756 752
 
757 753
 void Game::cancelAttackAndFollow()
@@ -885,7 +881,7 @@ void Game::partyShareExperience(bool active)
885 881
 {
886 882
     if(!canPerformGameAction())
887 883
         return;
888
-    m_protocolGame->sendShareExperience(active, 0);
884
+    m_protocolGame->sendShareExperience(active);
889 885
 }
890 886
 
891 887
 void Game::requestOutfit()
@@ -1084,15 +1080,16 @@ bool Game::checkBotProtection()
1084 1080
 bool Game::canPerformGameAction()
1085 1081
 {
1086 1082
     // we can only perform game actions if we meet these conditions:
1083
+    // - the game is online
1087 1084
     // - the local player exists
1088 1085
     // - the local player is not dead
1089 1086
     // - we have a game protocol
1090 1087
     // - the game protocol is connected
1091 1088
     // - its not a bot action
1092
-    return m_localPlayer && !m_dead && m_protocolGame && m_protocolGame->isConnected() && checkBotProtection();
1089
+    return m_online && m_localPlayer && !m_dead && m_protocolGame && m_protocolGame->isConnected() && checkBotProtection();
1093 1090
 }
1094 1091
 
1095
-void Game::setProtocolVersion(int version)
1092
+void Game::setClientVersion(int version)
1096 1093
 {
1097 1094
     if(isOnline())
1098 1095
         stdext::throw_exception("Unable to change client version while online");
@@ -1147,6 +1144,8 @@ void Game::setProtocolVersion(int version)
1147 1144
     }
1148 1145
 
1149 1146
     m_protocolVersion = version;
1147
+
1148
+    g_lua.callGlobalField("g_game", "onClientVersionChange", version);
1150 1149
 }
1151 1150
 
1152 1151
 void Game::setAttackingCreature(const CreaturePtr& creature)

+ 10
- 6
src/otclient/game.h View File

@@ -48,7 +48,7 @@ protected:
48 48
     void processLoginAdvice(const std::string& message);
49 49
     void processLoginWait(const std::string& message, int time);
50 50
 
51
-    void processGameStart(const LocalPlayerPtr& localPlayer, int serverBeat, bool canReportBugs);
51
+    void processGameStart();
52 52
     void processGameEnd();
53 53
     void processDeath(int penality);
54 54
 
@@ -56,7 +56,7 @@ protected:
56 56
     void processInventoryChange(int slot, const ItemPtr& item);
57 57
     void processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos);
58 58
     void processCreatureTeleport(const CreaturePtr& creature);
59
-    void processAttackCancel();
59
+    void processAttackCancel(uint seq);
60 60
     void processWalkCancel(Otc::Direction direction);
61 61
 
62 62
     // message related
@@ -232,17 +232,16 @@ public:
232 232
     void setFeature(Otc::GameFeature feature) { m_features.set(feature, false); }
233 233
     bool getFeature(Otc::GameFeature feature) { return m_features.test(feature); }
234 234
 
235
-    void setProtocolVersion(int version);
236
-    int getProtocolVersion() { return m_protocolVersion; }
235
+    void setClientVersion(int version);
236
+    int getClientVersion() { return m_protocolVersion; }
237 237
 
238 238
     void setRSA(const std::string& rsa);
239 239
     std::string getRSA() { return m_rsa; }
240 240
 
241 241
     bool canPerformGameAction();
242
-    bool canReportBugs() { return m_canReportBugs; }
243 242
     bool checkBotProtection();
244 243
 
245
-    bool isOnline() { return !!m_localPlayer; }
244
+    bool isOnline() { return m_online; }
246 245
     bool isDead() { return m_dead; }
247 246
     bool isAttacking() { return !!m_attackingCreature; }
248 247
     bool isFollowing() { return !!m_followingCreature; }
@@ -253,7 +252,10 @@ public:
253 252
     std::map<int, Vip> getVips() { return m_vips; }
254 253
     CreaturePtr getAttackingCreature() { return m_attackingCreature; }
255 254
     CreaturePtr getFollowingCreature() { return m_followingCreature; }
255
+    void setServerBeat(int beat) { m_serverBeat = beat; }
256 256
     int getServerBeat() { return m_serverBeat; }
257
+    void setCanReportBugs(bool enable) { m_canReportBugs = enable; }
258
+    bool canReportBugs() { return m_canReportBugs; }
257 259
     LocalPlayerPtr getLocalPlayer() { return m_localPlayer; }
258 260
     ProtocolGamePtr getProtocolGame() { return m_protocolGame; }
259 261
     std::string getCharacterName() { return m_characterName; }
@@ -275,10 +277,12 @@ private:
275 277
     std::map<int, ContainerPtr> m_containers;
276 278
     std::map<int, Vip> m_vips;
277 279
 
280
+    bool m_online;
278 281
     bool m_denyBotCall;
279 282
     bool m_dead;
280 283
     bool m_mounted;
281 284
     int m_serverBeat;
285
+    uint m_seq;
282 286
     Otc::FightModes m_fightMode;
283 287
     Otc::ChaseModes m_chaseMode;
284 288
     bool m_safeFight;

+ 2
- 2
src/otclient/item.cpp View File

@@ -187,8 +187,8 @@ void Item::setOtbId(uint16 id)
187 187
 {
188 188
     if(!g_things.isValidOtbId(id))
189 189
         id = 0;
190
-    auto otbType = g_things.getItemType(id);
191
-    m_id = otbType->getClientId();
190
+    auto itemType = g_things.getItemType(id);
191
+    m_id = itemType->getClientId();
192 192
     m_otbId = id;
193 193
 }
194 194
 

+ 2
- 2
src/otclient/luafunctions.cpp View File

@@ -194,8 +194,8 @@ void OTClient::registerLuaFunctions()
194 194
     g_lua.bindSingletonFunction("g_game", "getServerBeat", &Game::getServerBeat, &g_game);
195 195
     g_lua.bindSingletonFunction("g_game", "getLocalPlayer", &Game::getLocalPlayer, &g_game);
196 196
     g_lua.bindSingletonFunction("g_game", "getProtocolGame", &Game::getProtocolGame, &g_game);
197
-    g_lua.bindSingletonFunction("g_game", "getProtocolVersion", &Game::getProtocolVersion, &g_game);
198
-    g_lua.bindSingletonFunction("g_game", "setProtocolVersion", &Game::setProtocolVersion, &g_game);
197
+    g_lua.bindSingletonFunction("g_game", "getClientVersion", &Game::getClientVersion, &g_game);
198
+    g_lua.bindSingletonFunction("g_game", "setClientVersion", &Game::setClientVersion, &g_game);
199 199
     g_lua.bindSingletonFunction("g_game", "getCharacterName", &Game::getCharacterName, &g_game);
200 200
     g_lua.bindSingletonFunction("g_game", "getWorldName", &Game::getWorldName, &g_game);
201 201
     g_lua.bindSingletonFunction("g_game", "getGMActions", &Game::getGMActions, &g_game);

+ 1
- 1
src/otclient/map.cpp View File

@@ -518,7 +518,7 @@ void Map::saveOtcm(const std::string& fileName)
518 518
         // version 1 header
519 519
         fin->addString("OTCM 1.0"); // map description
520 520
         fin->addU32(g_things.getDatSignature());
521
-        fin->addU16(g_game.getProtocolVersion());
521
+        fin->addU16(g_game.getClientVersion());
522 522
         fin->addString(g_game.getWorldName());
523 523
 
524 524
         // go back and rewrite where the map data starts

+ 1
- 1
src/otclient/map.h View File

@@ -175,7 +175,7 @@ public:
175 175
 
176 176
 private:
177 177
     TileMap m_tiles;
178
-    std::map<uint32, CreaturePtr> m_knownCreatures;
178
+    std::unordered_map<uint32, CreaturePtr> m_knownCreatures;
179 179
     std::array<std::vector<MissilePtr>, Otc::MAX_Z+1> m_floorMissiles;
180 180
     std::vector<AnimatedTextPtr> m_animatedTexts;
181 181
     std::vector<StaticTextPtr> m_staticTexts;

+ 1
- 1
src/otclient/otclient.cpp View File

@@ -81,6 +81,6 @@ void OTClient::terminate()
81 81
 {
82 82
     g_map.terminate();
83 83
     g_things.terminate();
84
-    g_sprites.termiante();
84
+    g_sprites.terminate();
85 85
     g_shaders.terminate();
86 86
 }

+ 2
- 1
src/otclient/protocolcodes.h View File

@@ -135,7 +135,8 @@ namespace Proto {
135 135
         GameServerMarketEnter               = 246, // 944
136 136
         GameServerMarketLeave               = 247, // 944
137 137
         GameServerMarketDetail              = 248, // 944
138
-        GameServerMarketBrowse              = 249 // 944
138
+        GameServerMarketBrowse              = 249, // 944
139
+        GameServerShowModalDialog           = 250  // 960
139 140
     };
140 141
 
141 142
     enum ClientOpcodes {

+ 1
- 2
src/otclient/protocolgame.cpp View File

@@ -44,8 +44,7 @@ void ProtocolGame::onConnect()
44 44
 {
45 45
     Protocol::onConnect();
46 46
 
47
-    // must create local player before parsing anything
48
-    m_localPlayer = LocalPlayerPtr(new LocalPlayer);
47
+    m_localPlayer = g_game.getLocalPlayer();
49 48
 
50 49
     if(g_game.getFeature(Otc::GameProtocolChecksum))
51 50
         enableChecksum();

+ 9
- 7
src/otclient/protocolgame.h View File

@@ -79,14 +79,14 @@ public:
79 79
     void sendOpenPrivateChannel(const std::string& receiver);
80 80
     void sendCloseNpcChannel();
81 81
     void sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseModes chaseMode, bool safeFight);
82
-    void sendAttack(uint creatureId);
83
-    void sendFollow(uint creatureId);
82
+    void sendAttack(uint creatureId, uint seq);
83
+    void sendFollow(uint creatureId, uint seq);
84 84
     void sendInviteToParty(uint creatureId);
85 85
     void sendJoinParty(uint creatureId);
86 86
     void sendRevokeInvitation(uint creatureId);
87 87
     void sendPassLeadership(uint creatureId);
88 88
     void sendLeaveParty();
89
-    void sendShareExperience(bool active, int unknown);
89
+    void sendShareExperience(bool active);
90 90
     void sendOpenOwnChannel();
91 91
     void sendInviteToOwnChannel(const std::string& name);
92 92
     void sendExcludeFromOwnChannel(const std::string& name);
@@ -166,9 +166,9 @@ private:
166 166
     void parsePlayerSkills(const InputMessagePtr& msg);
167 167
     void parsePlayerState(const InputMessagePtr& msg);
168 168
     void parsePlayerCancelAttack(const InputMessagePtr& msg);
169
-    void parseSpellDelay(const InputMessagePtr& msg);
170
-    void parseSpellGroupDelay(const InputMessagePtr& msg);
171
-    void parseMultiUseDelay(const InputMessagePtr& msg);
169
+    void parseSpellCooldown(const InputMessagePtr& msg);
170
+    void parseSpellGroupCooldown(const InputMessagePtr& msg);
171
+    void parseMultiUseCooldown(const InputMessagePtr& msg);
172 172
     void parseCreatureSpeak(const InputMessagePtr& msg);
173 173
     void parseChannelList(const InputMessagePtr& msg);
174 174
     void parseOpenChannel(const InputMessagePtr& msg);
@@ -198,15 +198,17 @@ private:
198 198
     void parseChannelEvent(const InputMessagePtr& msg);
199 199
     void parseItemInfo(const InputMessagePtr& msg);
200 200
     void parsePlayerInventory(const InputMessagePtr& msg);
201
+    void parseShowModalDialog(const InputMessagePtr& msg);
201 202
     void parseExtendedOpcode(const InputMessagePtr& msg);
202 203
 
203 204
 public:
204 205
     void setMapDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height);
205 206
     int setFloorDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height, int offset, int skip);
206
-    void setTileDescription(const InputMessagePtr& msg, Position position);
207
+    int setTileDescription(const InputMessagePtr& msg, Position position);
207 208
 
208 209
     Outfit getOutfit(const InputMessagePtr& msg);
209 210
     ThingPtr getThing(const InputMessagePtr& msg);
211
+    ThingPtr getMappedThing(const InputMessagePtr& msg);
210 212
     CreaturePtr getCreature(const InputMessagePtr& msg, int type = 0);
211 213
     ItemPtr getItem(const InputMessagePtr& msg, int id = 0);
212 214
     Position getPosition(const InputMessagePtr& msg);

+ 148
- 109
src/otclient/protocolgameparse.cpp View File

@@ -35,13 +35,18 @@
35 35
 
36 36
 void ProtocolGame::parseMessage(const InputMessagePtr& msg)
37 37
 {
38
-    int opcode = 0;
39
-    int prevOpcode = 0;
38
+    int opcode = -1;
39
+    int prevOpcode = -1;
40 40
 
41 41
     try {
42 42
         while(!msg->eof()) {
43 43
             opcode = msg->getU8();
44 44
 
45
+            if(!m_gameInitialized && opcode >= Proto::GameServerFirstGameOpcode) {
46
+                g_game.processGameStart();
47
+                m_gameInitialized = true;
48
+            }
49
+
45 50
             // try to parse in lua first
46 51
             int readPos = msg->getReadPos();
47 52
             if(callLuaField<bool>("onOpcode", opcode, msg))
@@ -49,9 +54,6 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
49 54
             else
50 55
                 msg->setReadPos(readPos); // restore read pos
51 56
 
52
-            if(!m_gameInitialized && opcode > Proto::GameServerFirstGameOpcode)
53
-                g_logger.warning("received a game opcode from the server, but the game is not initialized yet, this is a server side bug");
54
-
55 57
             switch(opcode) {
56 58
             case Proto::GameServerInitGame:
57 59
                 parseInitGame(msg);
@@ -70,8 +72,8 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
70 72
                 break;
71 73
             case Proto::GameServerPing:
72 74
             case Proto::GameServerPingBack:
73
-                if((opcode == Proto::GameServerPing && g_game.getProtocolVersion() >= 953) ||
74
-                   (opcode == Proto::GameServerPingBack && g_game.getProtocolVersion() < 953))
75
+                if((opcode == Proto::GameServerPing && g_game.getClientVersion() >= 953) ||
76
+                   (opcode == Proto::GameServerPingBack && g_game.getClientVersion() < 953))
75 77
                     parsePingBack(msg);
76 78
                 else
77 79
                     parsePing(msg);
@@ -279,13 +281,13 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
279 281
                 break;
280 282
             // PROTOCOL>=870
281 283
             case Proto::GameServerSpellDelay:
282
-                parseSpellDelay(msg);
284
+                parseSpellCooldown(msg);
283 285
                 break;
284 286
             case Proto::GameServerSpellGroupDelay:
285
-                parseSpellGroupDelay(msg);
287
+                parseSpellGroupCooldown(msg);
286 288
                 break;
287 289
             case Proto::GameServerMultiUseDelay:
288
-                parseMultiUseDelay(msg);
290
+                parseMultiUseCooldown(msg);
289 291
                 break;
290 292
             // PROTOCOL>=910
291 293
             case Proto::GameServerChannelEvent:
@@ -306,7 +308,7 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
306 308
                 parseExtendedOpcode(msg);
307 309
                 break;
308 310
             default:
309
-                stdext::throw_exception("unknown opcode");
311
+                stdext::throw_exception(stdext::format("unhandled opcode %d", (int)opcode));
310 312
                 break;
311 313
             }
312 314
             prevOpcode = opcode;
@@ -319,13 +321,13 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
319 321
 
320 322
 void ProtocolGame::parseInitGame(const InputMessagePtr& msg)
321 323
 {
322
-    m_gameInitialized = true;
323 324
     uint playerId = msg->getU32();
324 325
     int serverBeat = msg->getU16();
325 326
     bool canReportBugs = msg->getU8();
326 327
 
327 328
     m_localPlayer->setId(playerId);
328
-    g_game.processGameStart(m_localPlayer, serverBeat, canReportBugs);
329
+    g_game.setServerBeat(serverBeat);
330
+    g_game.setCanReportBugs(canReportBugs);
329 331
 }
330 332
 
331 333
 void ProtocolGame::parseGMActions(const InputMessagePtr& msg)
@@ -334,9 +336,9 @@ void ProtocolGame::parseGMActions(const InputMessagePtr& msg)
334 336
 
335 337
     int numViolationReasons;
336 338
 
337
-    if(g_game.getProtocolVersion() >= 860)
339
+    if(g_game.getClientVersion() >= 860)
338 340
         numViolationReasons = 20;
339
-    else if(g_game.getProtocolVersion() >= 854)
341
+    else if(g_game.getClientVersion() >= 854)
340 342
         numViolationReasons = 19;
341 343
     else
342 344
         numViolationReasons = 32;
@@ -454,7 +456,7 @@ void ProtocolGame::parseTileAddThing(const InputMessagePtr& msg)
454 456
     Position pos = getPosition(msg);
455 457
     int stackPos = -1;
456 458
 
457
-    if(g_game.getProtocolVersion() >= 854)
459
+    if(g_game.getClientVersion() >= 854)
458 460
         stackPos = msg->getU8();
459 461
 
460 462
     ThingPtr thing = getThing(msg);
@@ -463,54 +465,54 @@ void ProtocolGame::parseTileAddThing(const InputMessagePtr& msg)
463 465
 
464 466
 void ProtocolGame::parseTileTransformThing(const InputMessagePtr& msg)
465 467
 {
466
-    Position pos = getPosition(msg);
467
-    int stackPos = msg->getU8();
468
+    ThingPtr thing = getMappedThing(msg);
469
+    ThingPtr newThing = getThing(msg);
468 470
 
469
-    ThingPtr thing = getThing(msg);
470
-    if(thing) {
471
-        if(!g_map.removeThingByPos(pos, stackPos))
472
-            g_logger.traceError("could not remove thing");
473
-        g_map.addThing(thing, pos, stackPos);
471
+    if(!thing) {
472
+        g_logger.traceError("no thing");
473
+        return;
474 474
     }
475
+
476
+    Position pos = thing->getPosition();
477
+    int stackpos = thing->getStackpos();
478
+    assert(thing->getStackPriority() == newThing->getStackPriority());
479
+
480
+    if(!g_map.removeThing(thing)) {
481
+        g_logger.traceError("unable to remove thing");
482
+        return;
483
+    }
484
+
485
+    g_map.addThing(newThing, pos, stackpos);
475 486
 }
476 487
 
477 488
 void ProtocolGame::parseTileRemoveThing(const InputMessagePtr& msg)
478 489
 {
479
-    Position pos = getPosition(msg);
480
-    int stackPos = msg->getU8();
490
+    ThingPtr thing = getMappedThing(msg);
491
+    if(!thing) {
492
+        g_logger.traceError("no thing");
493
+        return;
494
+    }
481 495
 
482
-    if(!g_map.removeThingByPos(pos, stackPos))
483
-        g_logger.traceError("could not remove thing");
496
+    g_map.removeThing(thing);
484 497
 }
485 498
 
486 499
 void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg)
487 500
 {
488
-    Position oldPos = getPosition(msg);
489
-    int oldStackpos = msg->getU8();
501
+    ThingPtr thing = getMappedThing(msg);
490 502
     Position newPos = getPosition(msg);
491 503
 
492
-    ThingPtr thing = g_map.getThing(oldPos, oldStackpos);
493
-    if(!thing) {
494
-        g_logger.traceError("could not get thing");
504
+    if(!thing || !thing->isCreature()) {
505
+        g_logger.traceError("no creature found to move");
495 506
         return;
496 507
     }
497 508
 
498
-    CreaturePtr creature = thing->asCreature();
499
-    if(!creature) {
500
-        g_logger.traceError("thing is not a creature");
501
-        return;
502
-    }
503
-
504
-    // update map tiles
505
-    if(!g_map.removeThing(thing))
506
-        g_logger.traceError("could not remove thing");
507 509
 
508 510
     int stackPos = -2;
509
-
510
-    // older protocols stores creatures in reverse order
511
-    if(!g_game.getProtocolVersion() >= 854)
511
+    // newer protocols stores creatures in reverse order
512
+    if(!g_game.getClientVersion()  >= 854)
512 513
         stackPos = -1;
513 514
 
515
+    g_map.removeThing(thing);
514 516
     g_map.addThing(thing, newPos, stackPos);
515 517
 }
516 518
 
@@ -887,7 +889,7 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
887 889
     m_localPlayer->setStamina(stamina);
888 890
     m_localPlayer->setSoul(soul);
889 891
 
890
-    if(g_game.getProtocolVersion() >= 910)
892
+    if(g_game.getClientVersion() >= 910)
891 893
         m_localPlayer->setSpeed(msg->getU16());
892 894
 
893 895
     if(g_game.getFeature(Otc::GamePlayerRegenerationTime))
@@ -918,29 +920,28 @@ void ProtocolGame::parsePlayerState(const InputMessagePtr& msg)
918 920
 
919 921
 void ProtocolGame::parsePlayerCancelAttack(const InputMessagePtr& msg)
920 922
 {
921
-    if(g_game.getProtocolVersion() >= 860)
922
-        msg->getU32(); // unknown
923
+    uint seq = 0;
924
+    if(g_game.getClientVersion() >= 860)
925
+        seq = msg->getU32();
923 926
 
924
-    g_game.processAttackCancel();
927
+    g_game.processAttackCancel(seq);
925 928
 }
926 929
 
927
-void ProtocolGame::parseSpellDelay(const InputMessagePtr& msg)
930
+void ProtocolGame::parseSpellCooldown(const InputMessagePtr& msg)
928 931
 {
929 932
     msg->getU16(); // spell id
930
-    msg->getU16(); // cooldown
931
-    msg->getU8(); // unknown
933
+    msg->getU32(); // cooldown
932 934
 }
933 935
 
934
-void ProtocolGame::parseSpellGroupDelay(const InputMessagePtr& msg)
936
+void ProtocolGame::parseSpellGroupCooldown(const InputMessagePtr& msg)
935 937
 {
936
-    msg->getU16(); // spell id
937
-    msg->getU16(); // cooldown
938
-    msg->getU8(); // unknown
938
+    msg->getU8(); // group id
939
+    msg->getU32(); // cooldown
939 940
 }
940 941
 
941
-void ProtocolGame::parseMultiUseDelay(const InputMessagePtr& msg)
942
+void ProtocolGame::parseMultiUseCooldown(const InputMessagePtr& msg)
942 943
 {
943
-    //TODO
944
+    msg->getU32(); // cooldown
944 945
 }
945 946
 
946 947
 void ProtocolGame::parseCreatureSpeak(const InputMessagePtr& msg)
@@ -1225,18 +1226,36 @@ void ProtocolGame::parseChannelEvent(const InputMessagePtr& msg)
1225 1226
 
1226 1227
 void ProtocolGame::parseItemInfo(const InputMessagePtr& msg)
1227 1228
 {
1228
-    /*int count = msg.getU16() - 1;
1229
-    for(int i = 0; i < count; i++)
1230
-    {
1231
-        int unknown1 = msg->getU8();
1232
-        int unknown2 = msg->getU16();
1233
-        std::string unknown3 = msg->getString();
1234
-    }*/
1229
+    int size = msg->getU8();
1230
+    for(int i=0;i<size;++i) {
1231
+        msg->getU16(); // id
1232
+        msg->getU8(); // subtype
1233
+        msg->getString(); // description
1234
+    }
1235 1235
 }
1236 1236
 
1237 1237
 void ProtocolGame::parsePlayerInventory(const InputMessagePtr& msg)
1238 1238
 {
1239
-    //TODO
1239
+    int size = msg->getU16();
1240
+    for(int i=0;i<size;++i) {
1241
+        msg->getU16(); // id
1242
+        msg->getU8(); // subtype
1243
+        msg->getU16(); // count
1244
+    }
1245
+}
1246
+
1247
+void ProtocolGame::parseShowModalDialog(const InputMessagePtr& msg)
1248
+{
1249
+    msg->getU32(); // id
1250
+    msg->getString(); // title
1251
+    msg->getString(); // message
1252
+    int size = msg->getU8();
1253
+    for(int i=0;i<size;++i) {
1254
+        msg->getString(); // button name
1255
+        msg->getU8(); // button value
1256
+    }
1257
+    msg->getU8(); // default escape button
1258
+    msg->getU8(); // default enter button
1240 1259
 }
1241 1260
 
1242 1261
 void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg)
@@ -1275,51 +1294,41 @@ int ProtocolGame::setFloorDescription(const InputMessagePtr& msg, int x, int y,
1275 1294
     for(int nx = 0; nx < width; nx++) {
1276 1295
         for(int ny = 0; ny < height; ny++) {
1277 1296
             Position tilePos(x + nx + offset, y + ny + offset, z);
1278
-
1279
-            // clean pre stored tiles
1280
-            g_map.cleanTile(tilePos);
1281
-
1282
-            if(skip == 0) {
1283
-                int tileOpt = msg->peekU16();
1284
-                if(tileOpt >= 0xFF00)
1285
-                    skip = (msg->getU16() & 0xFF);
1286
-                else {
1287
-                    setTileDescription(msg, tilePos);
1288
-                    skip = (msg->getU16() & 0xFF);
1289
-                }
1290
-            }
1291
-            else
1297
+            if(skip == 0)
1298
+                skip = setTileDescription(msg, tilePos);
1299
+            else {
1300
+                g_map.cleanTile(tilePos);
1292 1301
                 skip--;
1302
+            }
1293 1303
         }
1294 1304
     }
1295 1305
     return skip;
1296 1306
 }
1297 1307
 
1298
-void ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position position)
1308
+int ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position position)
1299 1309
 {
1300
-    if(g_game.getFeature(Otc::GameEnvironmentEffect))
1301
-        msg->getU16(); // environment effect
1302
-
1303
-
1304 1310
     g_map.cleanTile(position);
1305 1311
 
1306
-    int stackPos = 0;
1307
-    while(true) {
1308
-        int inspectItemId = msg->peekU16();
1309
-        if(inspectItemId >= 0xFF00) {
1310
-            return;
1311
-        }
1312
-        else {
1313
-            if(stackPos >= 10)
1314
-                g_logger.traceError(stdext::format("too many things, stackpos=%d, pos=%s", stackPos, stdext::to_string(position)));
1312
+    bool gotEffect = 0;
1313
+    for(int stackPos=0;stackPos<256;stackPos++) {
1314
+        if(msg->peekU16()  >= 0xff00)
1315
+            return msg->getU16() & 0xff;
1315 1316
 
1316
-            ThingPtr thing = getThing(msg);
1317
-            g_map.addThing(thing, position, -2);
1317
+        if(g_game.getFeature(Otc::GameEnvironmentEffect) && !gotEffect) {
1318
+            msg->getU16(); // environment effect
1319
+            gotEffect = true;
1320
+            continue;
1318 1321
         }
1319
-        stackPos++;
1322
+
1323
+        if(stackPos > 10)
1324
+            g_logger.traceError(stdext::format("too many things, pos=%s, stackpos=%d", stdext::to_string(position), stackPos));
1325
+
1326
+        ThingPtr thing = getThing(msg);
1327
+        g_map.addThing(thing, position, -2);
1320 1328
     }
1321
-}
1322 1329
 
1330
+    return 0;
1331
+}
1323 1332
 Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg)
1324 1333
 {
1325 1334
     Outfit outfit;
@@ -1376,6 +1385,31 @@ ThingPtr ProtocolGame::getThing(const InputMessagePtr& msg)
1376 1385
     return thing;
1377 1386
 }
1378 1387
 
1388
+ThingPtr ProtocolGame::getMappedThing(const InputMessagePtr& msg)
1389
+{
1390
+    ThingPtr thing;
1391
+    uint16 x = msg->getU16();
1392
+
1393
+    if(x != 0xffff) {
1394
+        Position pos;
1395
+        pos.x = x;
1396
+        pos.y = msg->getU16();
1397
+        pos.z = msg->getU8();
1398
+        uint8 stackpos = msg->getU8();
1399
+        assert(stackpos != 255);
1400
+        thing = g_map.getThing(pos, stackpos);
1401
+        if(!thing)
1402
+            g_logger.traceError(stdext::format("no thing at pos:%s, stackpos:%d", stdext::to_string(pos), stackpos));
1403
+    } else {
1404
+        uint32 id = msg->getU32();
1405
+        thing = g_map.getCreatureById(id);
1406
+        if(!thing)
1407
+            g_logger.traceError(stdext::format("no creature with id %u", id));
1408
+    }
1409
+
1410
+    return thing;
1411
+}
1412
+
1379 1413
 CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
1380 1414
 {
1381 1415
     if(type == 0)
@@ -1397,7 +1431,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
1397 1431
             uint id = msg->getU32();
1398 1432
 
1399 1433
             int creatureType;
1400
-            if(g_game.getProtocolVersion() >= 910)
1434
+            if(g_game.getClientVersion() >= 910)
1401 1435
                 creatureType = msg->getU8();
1402 1436
             else {
1403 1437
                 if(id >= Proto::PlayerStartId && id < Proto::PlayerEndId)
@@ -1416,8 +1450,13 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
1416 1450
 
1417 1451
             if(id == m_localPlayer->getId())
1418 1452
                 creature = m_localPlayer;
1419
-            else if(creatureType == Proto::CreatureTypePlayer)
1420
-                creature = PlayerPtr(new Player);
1453
+            else if(creatureType == Proto::CreatureTypePlayer) {
1454
+                // fixes a bug server side bug where GameInit is not sent and local player id is unknown
1455
+                if(m_localPlayer->getId() == 0 && name == m_localPlayer->getName())
1456
+                    creature = m_localPlayer;
1457
+                else
1458
+                    creature = PlayerPtr(new Player);
1459
+            }
1421 1460
             else if(creatureType == Proto::CreatureTypeMonster)
1422 1461
                 creature = MonsterPtr(new Monster);
1423 1462
             else if(creatureType == Proto::CreatureTypeNpc)
@@ -1447,13 +1486,13 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
1447 1486
 
1448 1487
         // emblem is sent only when the creature is not known
1449 1488
         int emblem = -1;
1450
-        bool passable = false;
1489
+        bool unpass = true;
1451 1490
 
1452 1491
         if(g_game.getFeature(Otc::GameCreatureEmblems) && !known)
1453 1492
             emblem = msg->getU8();
1454 1493
 
1455
-        if(g_game.getProtocolVersion() >= 854)
1456
-            passable = (msg->getU8() == 0);
1494
+        if(g_game.getClientVersion() >= 854)
1495
+            unpass = msg->getU8();
1457 1496
 
1458 1497
         if(creature) {
1459 1498
             creature->setHealthPercent(healthPercent);
@@ -1465,7 +1504,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
1465 1504
             creature->setShield(shield);
1466 1505
             if(emblem != -1)
1467 1506
                 creature->setEmblem(emblem);
1468
-            creature->setPassable(passable);
1507
+            creature->setPassable(!unpass);
1469 1508
 
1470 1509
             if(creature == m_localPlayer && !m_localPlayer->isKnown())
1471 1510
                 m_localPlayer->setKnown(true);
@@ -1481,11 +1520,11 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
1481 1520
         if(creature)
1482 1521
             creature->turn(direction);
1483 1522
 
1484
-        if(g_game.getProtocolVersion() >= 953) {
1485
-            bool passable = msg->getU8();
1523
+        if(g_game.getClientVersion() >= 953) {
1524
+            bool unpass = msg->getU8();
1486 1525
 
1487 1526
             if(creature)
1488
-                creature->setPassable(passable);
1527
+                creature->setPassable(!unpass);
1489 1528
         }
1490 1529
 
1491 1530
     } else {
@@ -1502,7 +1541,7 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
1502 1541
 
1503 1542
     ItemPtr item = Item::create(id);
1504 1543
     if(item->getId() == 0)
1505
-        stdext::throw_exception("unable to create item with invalid id 0");
1544
+        stdext::throw_exception(stdext::format("unable to create item with invalid id %d", id));
1506 1545
 
1507 1546
     if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
1508 1547
         item->setCountOrSubType(msg->getU8());
@@ -1511,7 +1550,7 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
1511 1550
         if(item->getAnimationPhases() > 1) {
1512 1551
             // 0xfe => random phase
1513 1552
             // 0xff => async?
1514
-            msg->getU8();
1553
+            msg->getU8(); // phase
1515 1554
         }
1516 1555
     }
1517 1556
 

+ 8
- 8
src/otclient/protocolgamesend.cpp View File

@@ -51,7 +51,7 @@ void ProtocolGame::sendLoginPacket(uint challangeTimestamp, uint8 challangeRando
51 51
     msg->addU8(Proto::ClientEnterGame);
52 52
 
53 53
     msg->addU16(g_lua.callGlobalField<int>("g_game", "getOs"));
54
-    msg->addU16(g_game.getProtocolVersion());
54
+    msg->addU16(g_game.getClientVersion());
55 55
 
56 56
     int paddingBytes = 128;
57 57
     msg->addU8(0); // first RSA byte must be 0
@@ -509,21 +509,21 @@ void ProtocolGame::sendChangeFightModes(Otc::FightModes fightMode, Otc::ChaseMod
509 509
     send(msg);
510 510
 }
511 511
 
512
-void ProtocolGame::sendAttack(uint creatureId)
512
+void ProtocolGame::sendAttack(uint creatureId, uint seq)
513 513
 {
514 514
     OutputMessagePtr msg(new OutputMessage);
515 515
     msg->addU8(Proto::ClientAttack);
516 516
     msg->addU32(creatureId);
517
-    msg->addU32(0);
518
-    msg->addU32(0);
517
+    msg->addU32(seq);
519 518
     send(msg);
520 519
 }
521 520
 
522
-void ProtocolGame::sendFollow(uint creatureId)
521
+void ProtocolGame::sendFollow(uint creatureId, uint seq)
523 522
 {
524 523
     OutputMessagePtr msg(new OutputMessage);
525 524
     msg->addU8(Proto::ClientFollow);
526 525
     msg->addU32(creatureId);
526
+    msg->addU32(seq);
527 527
     send(msg);
528 528
 }
529 529
 
@@ -566,14 +566,14 @@ void ProtocolGame::sendLeaveParty()
566 566
     send(msg);
567 567
 }
568 568
 
569
-void ProtocolGame::sendShareExperience(bool active, int unknown)
569
+void ProtocolGame::sendShareExperience(bool active)
570 570
 {
571 571
     OutputMessagePtr msg(new OutputMessage);
572 572
     msg->addU8(Proto::ClientShareExperience);
573 573
     msg->addU8(active ? 0x01 : 0x00);
574 574
 
575
-    if(g_game.getProtocolVersion() < 910)
576
-        msg->addU8(unknown);
575
+    if(g_game.getClientVersion() < 910)
576
+        msg->addU8(0);
577 577
 
578 578
     send(msg);
579 579
 }

+ 4
- 4
src/otclient/spritemanager.cpp View File

@@ -34,18 +34,18 @@ SpriteManager::SpriteManager()
34 34
     m_signature = 0;
35 35
 }
36 36
 
37
-void SpriteManager::termiante()
37
+void SpriteManager::terminate()
38 38
 {
39 39
     unload();
40 40
 }
41 41
 
42 42
 bool SpriteManager::loadSpr(const std::string& file)
43 43
 {
44
+    m_spritesCount = 0;
45
+    m_signature = 0;
46
+    m_loaded = false;
44 47
     try {
45 48
         m_spritesFile = g_resources.openFile(file);
46
-        if(!m_spritesFile)
47
-            return false;
48
-
49 49
         // cache file buffer to avoid lags from hard drive
50 50
         m_spritesFile->cache();
51 51
 

+ 1
- 1
src/otclient/spritemanager.h View File

@@ -32,7 +32,7 @@ class SpriteManager
32 32
 public:
33 33
     SpriteManager();
34 34
 
35
-    void termiante();
35
+    void terminate();
36 36
 
37 37
     bool loadSpr(const std::string& file);
38 38
     void unload();

+ 1
- 1
src/otclient/thing.cpp View File

@@ -66,7 +66,7 @@ ContainerPtr Thing::getParentContainer()
66 66
 int Thing::getStackpos()
67 67
 {
68 68
     if(m_position.x == 65535 && asItem()) // is inside a container
69
-        return 0;
69
+        return m_position.z;
70 70
     else if(const TilePtr& tile = getTile())
71 71
         return tile->getThingStackpos(asThing());
72 72
     else {

+ 15
- 14
src/otclient/thingtypemanager.cpp View File

@@ -59,16 +59,17 @@ void ThingTypeManager::terminate()
59 59
 
60 60
 bool ThingTypeManager::loadDat(const std::string& file)
61 61
 {
62
+    m_datLoaded = false;
63
+    m_datSignature = 0;
62 64
     try {
63 65
         FileStreamPtr fin = g_resources.openFile(file);
64
-        if(!fin)
65
-            stdext::throw_exception("unable to open file");
66 66
 
67 67
         m_datSignature = fin->getU32();
68 68
 
69 69
         int numThings[ThingLastCategory];
70 70
         for(int category = 0; category < ThingLastCategory; ++category) {
71 71
             int count = fin->getU16() + 1;
72
+            m_thingTypes[category].clear();
72 73
             m_thingTypes[category].resize(count, m_nullThingType);
73 74
         }
74 75
 
@@ -114,9 +115,9 @@ void ThingTypeManager::loadOtb(const std::string& file)
114 115
 
115 116
     m_itemTypes.resize(root->getChildren().size(), m_nullItemType);
116 117
     for(const BinaryTreePtr& node : root->getChildren()) {
117
-        ItemTypePtr otbType(new ItemType);
118
-        otbType->unserialize(node);
119
-        addItemType(otbType);
118
+        ItemTypePtr itemType(new ItemType);
119
+        itemType->unserialize(node);
120
+        addItemType(itemType);
120 121
     }
121 122
 
122 123
     m_otbLoaded = true;
@@ -171,25 +172,25 @@ void ThingTypeManager::parseItemType(uint16 id, TiXmlElement* elem)
171 172
         addItemType(newType);
172 173
     }
173 174
 
174
-    ItemTypePtr otbType = getItemType(serverId);
175
-    otbType->setName(elem->Attribute("name"));
175
+    ItemTypePtr itemType = getItemType(serverId);
176
+    itemType->setName(elem->Attribute("name"));
176 177
     for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
177 178
         if(attrib->ValueStr() != "attribute")
178 179
             break;
179 180
 
180 181
         if(attrib->Attribute("key") == "description") {
181
-            otbType->setDesc(attrib->Attribute("value"));
182
+            itemType->setDesc(attrib->Attribute("value"));
182 183
             break;
183 184
         }
184 185
     }
185 186
 }
186 187
 
187
-void ThingTypeManager::addItemType(const ItemTypePtr& otbType)
188
+void ThingTypeManager::addItemType(const ItemTypePtr& itemType)
188 189
 {
189
-    uint16 id = otbType->getServerId();
190
+    uint16 id = itemType->getServerId();
190 191
     if(m_itemTypes.size() <= id)
191 192
         m_itemTypes.resize(id+1, m_nullItemType);
192
-    m_itemTypes[id] = otbType;
193
+    m_itemTypes[id] = itemType;
193 194
 }
194 195
 
195 196
 const ItemTypePtr& ThingTypeManager::findOtbForClientId(uint16 id)
@@ -197,9 +198,9 @@ const ItemTypePtr& ThingTypeManager::findOtbForClientId(uint16 id)
197 198
     if(m_itemTypes.empty())
198 199
         return m_nullItemType;
199 200
 
200
-    for(const ItemTypePtr& otbType : m_itemTypes) {
201
-        if(otbType->getClientId() == id)
202
-            return otbType;
201
+    for(const ItemTypePtr& itemType : m_itemTypes) {
202
+        if(itemType->getClientId() == id)
203
+            return itemType;
203 204
     }
204 205
 
205 206
     return m_nullItemType;

+ 1
- 1
src/otclient/thingtypemanager.h View File

@@ -40,7 +40,7 @@ public:
40 40
     void loadXml(const std::string& file);
41 41
     void parseItemType(uint16 id, TiXmlElement *elem);
42 42
 
43
-    void addItemType(const ItemTypePtr& otbType);
43
+    void addItemType(const ItemTypePtr& itemType);
44 44
     const ItemTypePtr& findOtbForClientId(uint16 id);
45 45
 
46 46
     const ThingTypePtr& getNullThingType() { return m_nullThingType; }

+ 11
- 2
src/otclient/tile.cpp View File

@@ -392,7 +392,7 @@ bool Tile::isWalkable()
392 392
             return false;
393 393
 
394 394
         if(CreaturePtr creature = thing->asCreature()) {
395
-            if(!creature->getPassable())
395
+            if(!creature->isPassable())
396 396
                 return false;
397 397
         }
398 398
     }
@@ -405,7 +405,7 @@ bool Tile::isPathable()
405 405
         return false;
406 406
 
407 407
     for(const ThingPtr& thing : m_things) {
408
-        if(thing->isNotPathable())
408
+        if(thing->isNotPathable() || thing->isCreature())
409 409
             return false;
410 410
     }
411 411
 
@@ -507,4 +507,13 @@ void Tile::update()
507 507
         if(c != 0)
508 508
             m_minimapColorByte = c;
509 509
     }
510
+
511
+    // check stack priorities
512
+    // this code exists to find stackpos bugs faster
513
+    int lastPriority = 0;
514
+    for(const ThingPtr& thing : m_things) {
515
+        int priority = thing->getStackPriority();
516
+        assert(lastPriority <= priority);
517
+        lastPriority = priority;
518
+    }
510 519
 }

Loading…
Cancel
Save