Browse Source

Support for Protocols up to 10.71, Adventurer Blessing

TheSumm 6 years ago
parent
commit
7f3f18f991

+ 5
- 1
modules/client_entergame/characterlist.otui View File

@@ -45,13 +45,17 @@ CharacterWidget < UIWidget
45 45
 MainWindow
46 46
   id: charactersWindow
47 47
   !text: tr('Character List')
48
-  size: 250 248
49 48
   visible: false
50 49
   @onEnter: CharacterList.doLogin()
51 50
   @onEscape: CharacterList.hide(true)
52 51
   @onSetup: |
53 52
     g_keyboard.bindKeyPress('Up', function() self:getChildById('characters'):focusPreviousChild(KeyboardFocusReason) end, self)
54 53
     g_keyboard.bindKeyPress('Down', function() self:getChildById('characters'):focusNextChild(KeyboardFocusReason) end, self)
54
+    if g_game.getFeature(GamePreviewState) then
55
+      self:setSize({width = 350, height = 400})
56
+    else
57
+      self:setSize({width = 250, height = 248})
58
+    end
55 59
 
56 60
   TextList
57 61
     id: characters

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

@@ -59,6 +59,12 @@ local function onCharacterList(protocol, characters, account, otui)
59 59
   loadBox:destroy()
60 60
   loadBox = nil
61 61
 
62
+  for _, characterInfo in pairs(characters) do
63
+    if characterInfo.previewState and characterInfo.previewState ~= PreviewState.Default then
64
+      characterInfo.worldName = characterInfo.worldName .. ', Preview'
65
+    end
66
+  end
67
+
62 68
   CharacterList.create(characters, account, otui)
63 69
   CharacterList.show()
64 70
 
@@ -105,7 +111,7 @@ function EnterGame.init()
105 111
   local port = g_settings.get('port')
106 112
   local autologin = g_settings.getBoolean('autologin')
107 113
   local clientVersion = g_settings.getInteger('client-version')
108
-  if clientVersion == 0 then clientVersion = 860 end
114
+  if clientVersion == 0 then clientVersion = 1071 end
109 115
 
110 116
   if port == nil or port == 0 then port = 7171 end
111 117
 

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

@@ -17,7 +17,10 @@ inventoryButton = nil
17 17
 purseButton = nil
18 18
 
19 19
 function init()
20
-  connect(LocalPlayer, { onInventoryChange = onInventoryChange })
20
+  connect(LocalPlayer, {
21
+    onInventoryChange = onInventoryChange,
22
+    onBlessingsChange = onBlessingsChange
23
+  })
21 24
   connect(g_game, { onGameStart = refresh })
22 25
 
23 26
   g_keyboard.bindKeyDown('Ctrl+I', toggle)
@@ -43,7 +46,10 @@ function init()
43 46
 end
44 47
 
45 48
 function terminate()
46
-  disconnect(LocalPlayer, { onInventoryChange = onInventoryChange })
49
+  disconnect(LocalPlayer, {
50
+    onInventoryChange = onInventoryChange,
51
+    onBlessingsChange = onBlessingsChange
52
+  })
47 53
   disconnect(g_game, { onGameStart = refresh })
48 54
 
49 55
   g_keyboard.unbindKeyDown('Ctrl+I')
@@ -52,6 +58,21 @@ function terminate()
52 58
   inventoryButton:destroy()
53 59
 end
54 60
 
61
+function toggleAdventurerStyle(hasBlessing)
62
+  for slot = InventorySlotFirst, InventorySlotLast do
63
+    local itemWidget = inventoryPanel:getChildById('slot' .. slot)
64
+    if itemWidget then
65
+      if hasBlessing then
66
+        itemWidget:setBorderWidth(1)
67
+        itemWidget:setBorderColor('#F7C80C')
68
+      else
69
+        itemWidget:setBorderWidth(0)
70
+        itemWidget:setBorderColor('white')
71
+      end
72
+    end
73
+  end
74
+end
75
+
55 76
 function refresh()
56 77
   local player = g_game.getLocalPlayer()
57 78
   for i = InventorySlotFirst, InventorySlotPurse do
@@ -60,6 +81,7 @@ function refresh()
60 81
     else
61 82
       onInventoryChange(player, i, nil)
62 83
     end
84
+    toggleAdventurerStyle(Bit.hasBit(player:getBlessings(), Blessings.Adventurer))
63 85
   end
64 86
 
65 87
   purseButton:setVisible(g_game.getFeature(GamePurseSlot))
@@ -99,3 +121,10 @@ function onInventoryChange(player, slot, item, oldItem)
99 121
     itemWidget:setItem(nil)
100 122
   end
101 123
 end
124
+
125
+function onBlessingsChange(player, blessings, oldBlessings)
126
+  local hasAdventurerBlessing = Bit.hasBit(blessings, Blessings.Adventurer)
127
+  if hasAdventurerBlessing ~= Bit.hasBit(oldBlessings, Blessings.Adventurer) then
128
+    toggleAdventurerStyle(hasAdventurerBlessing)
129
+  end
130
+end

+ 24
- 1
modules/gamelib/const.lua View File

@@ -120,6 +120,13 @@ GameSpritesAlphaChannel = 56
120 120
 GamePremiumExpiration = 57
121 121
 GameBrowseField = 58
122 122
 GameEnhancedAnimations = 59
123
+GameOGLInformation = 60
124
+GameMessageSizeCheck = 61
125
+GamePreviewState = 62
126
+GameLoginPacketEncryption = 63
127
+GameClientVersion = 64
128
+GameContentRevision = 65
129
+GameExperienceBonus = 66
123 130
 
124 131
 TextColors = {
125 132
   red       = '#f55e5e', --'#c83200'
@@ -201,7 +208,7 @@ CIPSOFT_RSA = "1321277432058722840622950990822933849527763264961655079678763618"
201 208
               "88792221429527047321331896351555606801473202394175817"
202 209
 
203 210
 -- set to the latest Tibia.pic signature to make otclient compatible with official tibia
204
-PIC_SIGNATURE = 0x53208400
211
+PIC_SIGNATURE = 0x542100C1
205 212
 
206 213
 OsTypes = {
207 214
   Linux = 1,
@@ -244,4 +251,20 @@ ExtendedIds = {
244 251
   NeedsUpdate = 7
245 252
 }
246 253
 
254
+PreviewState = {
255
+  Default = 0,
256
+  Inactive = 1,
257
+  Active = 2
258
+}
259
+
260
+Blessings = {
261
+  None = 0,
262
+  Adventurer = 1,
263
+  SpiritualShielding = 2,
264
+  EmbraceOfTibia = 4,
265
+  FireOfSuns = 8,
266
+  WisdomOfSolitude = 16,
267
+  SparkOfPhoenix = 32
268
+}
269
+
247 270
 -- @}

+ 18
- 13
modules/gamelib/game.lua View File

@@ -53,38 +53,39 @@ end
53 53
 
54 54
 function g_game.getSupportedClients()
55 55
   return {
56
-    740, 741, 750, 760, 770, 772, 
56
+    740, 741, 750, 760, 770, 772,
57 57
     780, 781, 782, 790, 792,
58 58
 
59
-    800, 810, 811, 820, 821, 822, 
60
-    830, 831, 840, 842, 850, 853, 
61
-    854, 855, 857, 860, 861, 862, 
59
+    800, 810, 811, 820, 821, 822,
60
+    830, 831, 840, 842, 850, 853,
61
+    854, 855, 857, 860, 861, 862,
62 62
     870, 871,
63 63
 
64
-    900, 910, 920, 931, 940, 943, 
65
-    944, 951, 952, 953, 954, 960, 
66
-    961, 963, 970, 971, 972, 973, 
67
-    980, 981, 982, 983, 984, 985, 
64
+    900, 910, 920, 931, 940, 943,
65
+    944, 951, 952, 953, 954, 960,
66
+    961, 963, 970, 971, 972, 973,
67
+    980, 981, 982, 983, 984, 985,
68 68
     986,
69 69
 
70
-    1000, 1001, 1002, 1010, 1011, 
71
-    1012, 1013, 1020, 1021, 1022, 
72
-    1030, 1031, 1032, 1033, 1034, 
73
-    1035, 1036, 1037, 1038, 1039, 
70
+    1000, 1001, 1002, 1010, 1011,
71
+    1012, 1013, 1020, 1021, 1022,
72
+    1030, 1031, 1032, 1033, 1034,
73
+    1035, 1036, 1037, 1038, 1039,
74 74
     1040, 1041, 1050, 1051, 1052,
75 75
     1053, 1054, 1055, 1056, 1057,
76
-    1058, 1059, 1060, 1061
76
+    1058, 1059, 1060, 1061, 1062,
77
+    1063, 1064, 1070, 1071
77 78
   }
78 79
 end
79 80
 
80 81
 -- The client version and protocol version where
82
+-- unsynchronized for some releases, not sure if this
81 83
 -- will be the normal standard.
82 84
 
85
+-- Client Version: Publicly given version when
83 86
 -- downloading Cipsoft client.
84 87
 
88
+-- Protocol Version: Previously was the same as
85 89
 -- the client version, but was unsychronized in some
86 90
 -- releases, now it needs to be verified and added here
87 91
 -- if it does not match the client version.
@@ -92,7 +93,7 @@ end
92 93
 -- Reason for defining both: The server now requires a
93 94
 -- Client version and Protocol version from the client.
94 95
 
96
+-- Important: Use getClientVersion for specific protocol
95 97
 -- features to ensure we are using the proper version.
96 98
 
97 99
 function g_game.getClientProtocolVersion(client)

+ 24
- 11
modules/gamelib/protocollogin.lua View File

@@ -32,23 +32,28 @@ function ProtocolLogin:sendLoginPacket()
32 32
 
33 33
   msg:addU16(g_game.getProtocolVersion())
34 34
 
35
-  if g_game.getClientVersion() >= 980 then
35
+  if g_game.getFeature(GameClientVersion) then
36 36
     msg:addU32(g_game.getClientVersion())
37 37
   end
38 38
 
39
-  msg:addU32(g_things.getDatSignature())
39
+  if g_game.getFeature(GameContentRevision) then
40
+    msg:addU16(g_things.getContentRevision())
41
+    msg:addU16(0)
42
+  else
43
+    msg:addU32(g_things.getDatSignature())
44
+  end
40 45
   msg:addU32(g_sprites.getSprSignature())
41 46
   msg:addU32(PIC_SIGNATURE)
42 47
 
43
-  if g_game.getClientVersion() >= 980 then
44
-    msg:addU8(0) -- clientType
48
+  if g_game.getFeature(GamePreviewState) then
49
+    msg:addU8(0)
45 50
   end
46 51
 
47 52
   local offset = msg:getMessageSize()
48
-
49
-  if g_game.getClientVersion() >= 770 then
53
+  if g_game.getFeature(GameLoginPacketEncryption) then
50 54
     -- first RSA byte must be 0
51 55
     msg:addU8(0)
56
+
52 57
     -- xtea key
53 58
     self:generateXteaKey()
54 59
     local xteaKey = self:getXteaKey()
@@ -74,16 +79,23 @@ function ProtocolLogin:sendLoginPacket()
74 79
   local paddingBytes = g_crypt.rsaGetSize() - (msg:getMessageSize() - offset)
75 80
   assert(paddingBytes >= 0)
76 81
   msg:addPaddingBytes(paddingBytes, 0)
77
-  if g_game.getClientVersion() >= 770 then
82
+  if g_game.getFeature(GameLoginPacketEncryption) then
78 83
     msg:encryptRsa()
79 84
   end
80 85
 
86
+  if g_game.getFeature(GameOGLInformation) then
87
+    msg:addU8(1) --unknown
88
+    msg:addU8(1) --unknown
89
+    msg:addString(g_graphics.getRenderer())
90
+    msg:addString(g_graphics.getVersion())
91
+  end
92
+
81 93
   if g_game.getFeature(GameProtocolChecksum) then
82 94
     self:enableChecksum()
83 95
   end
84 96
 
85 97
   self:send(msg)
86
-  if g_game.getClientVersion() >= 770 then
98
+  if g_game.getFeature(GameLoginPacketEncryption) then
87 99
     self:enableXteaEncryption()
88 100
   end
89 101
   self:recv()
@@ -141,7 +153,7 @@ function ProtocolLogin:parseCharacterList(msg)
141 153
       world.worldName = msg:getString()
142 154
       world.worldIp = msg:getString()
143 155
       world.worldPort = msg:getU16()
144
-      msg:getU8() -- unknow byte?
156
+      world.previewState = msg:getU8()
145 157
       worlds[worldId] = world
146 158
     end
147 159
 
@@ -153,6 +165,7 @@ function ProtocolLogin:parseCharacterList(msg)
153 165
       character.worldName = worlds[worldId].worldName
154 166
       character.worldIp = worlds[worldId].worldIp
155 167
       character.worldPort = worlds[worldId].worldPort
168
+      character.previewState = worlds[worldId].previewState
156 169
       characters[i] = character
157 170
     end
158 171
 
@@ -165,8 +178,8 @@ function ProtocolLogin:parseCharacterList(msg)
165 178
       character.worldIp = iptostring(msg:getU32())
166 179
       character.worldPort = msg:getU16()
167 180
 
168
-      if g_game.getClientVersion() >= 980 then
169
-        character.unknown = msg:getU8()
181
+      if g_game.getFeature(GamePreviewState) then
182
+        character.previewState = msg:getU8()
170 183
       end
171 184
 
172 185
       characters[i] = character

+ 19
- 1
src/client/const.h View File

@@ -328,7 +328,8 @@ namespace Otc
328 328
         MessageRVRChannel              = 46,
329 329
         MessageRVRAnswer               = 47,
330 330
         MessageRVRContinue             = 48,
331
-        LastMessage                    = 49,
331
+        MessageGameHighlight           = 49,
332
+        LastMessage                    = 50,
332 333
         MessageInvalid                 = 255
333 334
     };
334 335
 
@@ -390,6 +391,13 @@ namespace Otc
390 391
         GamePremiumExpiration = 57,
391 392
         GameBrowseField = 58,
392 393
         GameEnhancedAnimations = 59,
394
+        GameOGLInformation = 60,
395
+        GameMessageSizeCheck = 61,
396
+        GamePreviewState = 62,
397
+        GameLoginPacketEncryption = 63,
398
+        GameClientVersion = 64,
399
+        GameContentRevision = 65,
400
+        GameExperienceBonus = 66,
393 401
 
394 402
         LastGameFeature = 101
395 403
     };
@@ -450,6 +458,16 @@ namespace Otc
450 458
         PhaseRandom = 254,
451 459
         PhaseAsync = 255
452 460
     };
461
+
462
+    enum Blessings {
463
+        BlessingNone = 0,
464
+        BlessingAdventurer = 1,
465
+        BlessingSpiritualShielding = 1 << 1,
466
+        BlessingEmbraceOfTibia = 1 << 2,
467
+        BlessingFireOfSuns = 1 << 3,
468
+        BlessingWisdomOfSolitude = 1 << 4,
469
+        BlessingSparkOfPhoenix = 1 << 5
470
+    };
453 471
 }
454 472
 
455 473
 #endif

+ 22
- 3
src/client/game.cpp View File

@@ -1425,7 +1425,7 @@ void Game::setProtocolVersion(int version)
1425 1425
     if(isOnline())
1426 1426
         stdext::throw_exception("Unable to change protocol version while online");
1427 1427
 
1428
-    if(version != 0 && (version < 740 || version > 1051))
1428
+    if(version != 0 && (version < 740 || version > 1071))
1429 1429
         stdext::throw_exception(stdext::format("Protocol version %d not supported", version));
1430 1430
 
1431 1431
     m_protocolVersion = version;
@@ -1443,7 +1443,7 @@ void Game::setClientVersion(int version)
1443 1443
     if(isOnline())
1444 1444
         stdext::throw_exception("Unable to change client version while online");
1445 1445
 
1446
-    if(version != 0 && (version < 740 || version > 1051))
1446
+    if(version != 0 && (version < 740 || version > 1071))
1447 1447
         stdext::throw_exception(stdext::format("Client version %d not supported", version));
1448 1448
 
1449 1449
     m_features.reset();
@@ -1452,6 +1452,7 @@ void Game::setClientVersion(int version)
1452 1452
     if(version >= 770) {
1453 1453
         enableFeature(Otc::GameLooktypeU16);
1454 1454
         enableFeature(Otc::GameMessageStatements);
1455
+        enableFeature(Otc::GameLoginPacketEncryption);
1455 1456
     }
1456 1457
 
1457 1458
     if(version >= 780) {
@@ -1475,6 +1476,7 @@ void Game::setClientVersion(int version)
1475 1476
 
1476 1477
     if(version >= 841) {
1477 1478
         enableFeature(Otc::GameChallengeOnLogin);
1479
+        enableFeature(Otc::GameMessageSizeCheck);
1478 1480
     }
1479 1481
 
1480 1482
     if(version >= 854) {
@@ -1523,6 +1525,11 @@ void Game::setClientVersion(int version)
1523 1525
         enableFeature(Otc::GameAdditionalVipInfo);
1524 1526
     }
1525 1527
 
1528
+    if(version >= 980) {
1529
+        enableFeature(Otc::GamePreviewState);
1530
+        enableFeature(Otc::GameClientVersion);
1531
+    }
1532
+
1526 1533
     if(version >= 981) {
1527 1534
         enableFeature(Otc::GameLoginPending);
1528 1535
         enableFeature(Otc::GameNewSpeedLaw);
@@ -1538,7 +1545,7 @@ void Game::setClientVersion(int version)
1538 1545
         enableFeature(Otc::GamePVPMode);
1539 1546
     }
1540 1547
 
1541
-    if (version >= 1035) {
1548
+    if(version >= 1035) {
1542 1549
         enableFeature(Otc::GameDoubleSkills);
1543 1550
         enableFeature(Otc::GameBaseSkillU16);
1544 1551
     }
@@ -1556,6 +1563,18 @@ void Game::setClientVersion(int version)
1556 1563
         enableFeature(Otc::GameEnhancedAnimations);
1557 1564
     }
1558 1565
 
1566
+    if(version >= 1054) {
1567
+        enableFeature(Otc::GameExperienceBonus);
1568
+    }
1569
+
1570
+    if(version >= 1061) {
1571
+        enableFeature(Otc::GameOGLInformation);
1572
+    }
1573
+
1574
+    if(version >= 1071) {
1575
+        enableFeature(Otc::GameContentRevision);
1576
+    }
1577
+
1559 1578
     m_clientVersion = version;
1560 1579
 
1561 1580
     g_lua.callGlobalField("g_game", "onClientVersionChange", version);

+ 11
- 0
src/client/localplayer.cpp View File

@@ -31,6 +31,7 @@ LocalPlayer::LocalPlayer()
31 31
 {
32 32
     m_states = 0;
33 33
     m_vocation = 0;
34
+    m_blessings = Otc::BlessingNone;
34 35
     m_walkLockExpiration = 0;
35 36
 
36 37
     m_skillsLevel.fill(-1);
@@ -546,6 +547,16 @@ void LocalPlayer::setSpells(const std::vector<int>& spells)
546 547
     }
547 548
 }
548 549
 
550
+void LocalPlayer::setBlessings(int blessings)
551
+{
552
+    if(blessings != m_blessings) {
553
+        int oldBlessings = m_blessings;
554
+        m_blessings = blessings;
555
+
556
+        callLuaField("onBlessingsChange", blessings, oldBlessings);
557
+    }
558
+}
559
+
549 560
 bool LocalPlayer::hasSight(const Position& pos)
550 561
 {
551 562
     return m_position.isInRange(pos, g_map.getAwareRange().left - 1, g_map.getAwareRange().top - 1);

+ 3
- 0
src/client/localplayer.h View File

@@ -63,6 +63,7 @@ public:
63 63
     void setRegenerationTime(double regenerationTime);
64 64
     void setOfflineTrainingTime(double offlineTrainingTime);
65 65
     void setSpells(const std::vector<int>& spells);
66
+    void setBlessings(int blessings);
66 67
 
67 68
     int getStates() { return m_states; }
68 69
     int getSkillLevel(Otc::Skill skill) { return m_skillsLevel[skill]; }
@@ -88,6 +89,7 @@ public:
88 89
     double getOfflineTrainingTime() { return m_offlineTrainingTime; }
89 90
     std::vector<int> getSpells() { return m_spells; }
90 91
     ItemPtr getInventoryItem(Otc::InventorySlot inventory) { return m_inventoryItems[inventory]; }
92
+    int getBlessings() { return m_blessings; }
91 93
 
92 94
     bool hasSight(const Position& pos);
93 95
     bool isKnown() { return m_known; }
@@ -144,6 +146,7 @@ private:
144 146
 
145 147
     int m_states;
146 148
     int m_vocation;
149
+    int m_blessings;
147 150
 
148 151
     double m_health;
149 152
     double m_maxHealth;

+ 2
- 0
src/client/luafunctions.cpp View File

@@ -63,6 +63,7 @@ void Client::registerLuaFunctions()
63 63
     g_lua.bindSingletonFunction("g_things", "isDatLoaded", &ThingTypeManager::isDatLoaded, &g_things);
64 64
     g_lua.bindSingletonFunction("g_things", "isOtbLoaded", &ThingTypeManager::isOtbLoaded, &g_things);
65 65
     g_lua.bindSingletonFunction("g_things", "getDatSignature", &ThingTypeManager::getDatSignature, &g_things);
66
+    g_lua.bindSingletonFunction("g_things", "getContentRevision", &ThingTypeManager::getContentRevision, &g_things);
66 67
     g_lua.bindSingletonFunction("g_things", "getThingType", &ThingTypeManager::getThingType, &g_things);
67 68
     g_lua.bindSingletonFunction("g_things", "getItemType", &ThingTypeManager::getItemType, &g_things);
68 69
     g_lua.bindSingletonFunction("g_things", "getThingTypes", &ThingTypeManager::getThingTypes, &g_things);
@@ -630,6 +631,7 @@ void Client::registerLuaFunctions()
630 631
     g_lua.bindClassMemberFunction<LocalPlayer>("getTotalCapacity", &LocalPlayer::getTotalCapacity);
631 632
     g_lua.bindClassMemberFunction<LocalPlayer>("getInventoryItem", &LocalPlayer::getInventoryItem);
632 633
     g_lua.bindClassMemberFunction<LocalPlayer>("getVocation", &LocalPlayer::getVocation);
634
+    g_lua.bindClassMemberFunction<LocalPlayer>("getBlessings", &LocalPlayer::getBlessings);
633 635
     g_lua.bindClassMemberFunction<LocalPlayer>("isPremium", &LocalPlayer::isPremium);
634 636
     g_lua.bindClassMemberFunction<LocalPlayer>("isKnown", &LocalPlayer::isKnown);
635 637
     g_lua.bindClassMemberFunction<LocalPlayer>("isPreWalking", &LocalPlayer::isPreWalking);

+ 46
- 1
src/client/protocolcodes.cpp View File

@@ -28,7 +28,52 @@ std::map<uint8, uint8> messageModesMap;
28 28
 
29 29
 void buildMessageModesMap(int version) {
30 30
     messageModesMap.clear();
31
-    if(version >= 1036) {
31
+
32
+    if(version >= 1055) { // might be 1054
33
+        messageModesMap[Otc::MessageNone] = 0;
34
+        messageModesMap[Otc::MessageSay] = 1;
35
+        messageModesMap[Otc::MessageWhisper] = 2;
36
+        messageModesMap[Otc::MessageYell] = 3;
37
+        messageModesMap[Otc::MessagePrivateFrom] = 4;
38
+        messageModesMap[Otc::MessagePrivateTo] = 5;
39
+        messageModesMap[Otc::MessageChannelManagement] = 6;
40
+        messageModesMap[Otc::MessageChannel] = 7;
41
+        messageModesMap[Otc::MessageChannelHighlight] = 8;
42
+        messageModesMap[Otc::MessageSpell] = 9;
43
+        //NpcFromStartBlock = 10
44
+        messageModesMap[Otc::MessageNpcFrom] = 11;
45
+        messageModesMap[Otc::MessageNpcTo] = 12;
46
+        messageModesMap[Otc::MessageGamemasterBroadcast] = 13;
47
+        messageModesMap[Otc::MessageGamemasterChannel] = 14;
48
+        messageModesMap[Otc::MessageGamemasterPrivateFrom] = 15;
49
+        messageModesMap[Otc::MessageGamemasterPrivateTo] = 16;
50
+        messageModesMap[Otc::MessageLogin] = 17;
51
+        messageModesMap[Otc::MessageWarning] = 18; // Admin
52
+        messageModesMap[Otc::MessageGame] = 19;
53
+        messageModesMap[Otc::MessageGameHighlight] = 20;
54
+        messageModesMap[Otc::MessageFailure] = 21;
55
+        messageModesMap[Otc::MessageLook] = 22;
56
+        messageModesMap[Otc::MessageDamageDealed] = 23;
57
+        messageModesMap[Otc::MessageDamageReceived] = 24;
58
+        messageModesMap[Otc::MessageHeal] = 25;
59
+        messageModesMap[Otc::MessageExp] = 26;
60
+        messageModesMap[Otc::MessageDamageOthers] = 27;
61
+        messageModesMap[Otc::MessageHealOthers] = 28;
62
+        messageModesMap[Otc::MessageExpOthers] = 29;
63
+        messageModesMap[Otc::MessageStatus] = 30;
64
+        messageModesMap[Otc::MessageLoot] = 31;
65
+        messageModesMap[Otc::MessageTradeNpc] = 32;
66
+        messageModesMap[Otc::MessageGuild] = 33;
67
+        messageModesMap[Otc::MessagePartyManagement] = 34;
68
+        messageModesMap[Otc::MessageParty] = 35;
69
+        messageModesMap[Otc::MessageBarkLow] = 36;
70
+        messageModesMap[Otc::MessageBarkLoud] = 37;
71
+        messageModesMap[Otc::MessageReport] = 38;
72
+        messageModesMap[Otc::MessageHotkeyUse] = 39;
73
+        messageModesMap[Otc::MessageTutorialHint] = 40;
74
+        messageModesMap[Otc::MessageThankyou] = 41;
75
+        messageModesMap[Otc::MessageMarket] = 42;
76
+    } else if(version >= 1036) {
32 77
             for(int i = Otc::MessageNone; i <= Otc::MessageBeyondLast; ++i) {
33 78
                 if(i >= Otc::MessageNpcTo)
34 79
                     messageModesMap[i] = i + 1;

+ 4
- 0
src/client/protocolcodes.h View File

@@ -107,6 +107,8 @@ namespace Proto {
107 107
         GameServerCreatureType              = 149,
108 108
         GameServerEditText                  = 150,
109 109
         GameServerEditList                  = 151,
110
+        GameServerBlessings                 = 156,
111
+        GameServerPreset                    = 157,
110 112
         GameServerPremiumTrigger            = 158, // 1038
111 113
         GameServerPlayerDataBasic           = 159, // 950
112 114
         GameServerPlayerData                = 160,
@@ -130,6 +132,8 @@ namespace Proto {
130 132
         GameServerTextMessage               = 180,
131 133
         GameServerCancelWalk                = 181,
132 134
         GameServerWalkWait                  = 182,
135
+        GameServerUnjustifiedStats          = 183,
136
+        GameServerPvpSituations             = 184,
133 137
         GameServerFloorChangeUp             = 190,
134 138
         GameServerFloorChangeDown           = 191,
135 139
         GameServerChooseOutfit              = 200,

+ 1
- 1
src/client/protocolgame.cpp View File

@@ -56,7 +56,7 @@ void ProtocolGame::onRecv(const InputMessagePtr& inputMessage)
56 56
     if(m_firstRecv) {
57 57
         m_firstRecv = false;
58 58
 
59
-        if(g_game.getClientVersion() >= 841) { // not sure since which version this is, but it seems to be after 8.40
59
+        if(g_game.getFeature(Otc::GameMessageSizeCheck)) {
60 60
             int size = inputMessage->getU16();
61 61
             if(size != inputMessage->getUnreadSize()) {
62 62
                 g_logger.traceError("invalid message size");

+ 4
- 0
src/client/protocolgame.h View File

@@ -128,6 +128,10 @@ public:
128 128
     void addPosition(const OutputMessagePtr& msg, const Position& position);
129 129
 
130 130
 private:
131
+    void parseBlessings(const InputMessagePtr& msg);
132
+    void parseUnjustifiedStats(const InputMessagePtr& msg);
133
+    void parsePvpSituations(const InputMessagePtr& msg);
134
+    void parsePreset(const InputMessagePtr& msg);
131 135
     void parseCreatureType(const InputMessagePtr& msg);
132 136
     void parsePlayerHelpers(const InputMessagePtr& msg);
133 137
     void parseMessage(const InputMessagePtr& msg);

+ 52
- 3
src/client/protocolgameparse.cpp View File

@@ -340,6 +340,19 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
340 340
             case Proto::GameServerCreatureType:
341 341
                 parseCreatureType(msg);
342 342
                 break;
343
+            // PROTOCOL>=1055
344
+            case Proto::GameServerBlessings:
345
+                parseBlessings(msg);
346
+                break;
347
+            case Proto::GameServerUnjustifiedStats:
348
+                parseUnjustifiedStats(msg);
349
+                break;
350
+            case Proto::GameServerPvpSituations:
351
+                parsePvpSituations(msg);
352
+                break;
353
+            case Proto::GameServerPreset:
354
+                parsePreset(msg);
355
+                break;
343 356
             // otclient ONLY
344 357
             case Proto::GameServerExtendedOpcode:
345 358
                 parseExtendedOpcode(msg);
@@ -372,6 +385,9 @@ void ProtocolGame::parseLogin(const InputMessagePtr& msg)
372 385
     }
373 386
     bool canReportBugs = msg->getU8();
374 387
 
388
+    msg->getU8(); // can change pvp framing option
389
+    msg->getU8(); // expert mode enabled
390
+
375 391
     m_localPlayer->setId(playerId);
376 392
     g_game.setServerBeat(serverBeat);
377 393
     g_game.setCanReportBugs(canReportBugs);
@@ -396,6 +412,34 @@ void ProtocolGame::parseEnterGame(const InputMessagePtr& msg)
396 412
     }
397 413
 }
398 414
 
415
+void ProtocolGame::parseBlessings(const InputMessagePtr& msg)
416
+{
417
+    uint16 blessings = msg->getU16();
418
+    m_localPlayer->setBlessings(blessings);
419
+}
420
+
421
+void ProtocolGame::parsePreset(const InputMessagePtr& msg)
422
+{
423
+    uint16 preset = msg->getU32();
424
+}
425
+
426
+void ProtocolGame::parseUnjustifiedStats(const InputMessagePtr& msg)
427
+{
428
+    // Unjustified Kills display since 10.55
429
+    msg->getU8();
430
+    msg->getU8();
431
+    msg->getU8();
432
+    msg->getU8();
433
+    msg->getU8();
434
+    msg->getU8();
435
+    msg->getU8();
436
+}
437
+
438
+void ProtocolGame::parsePvpSituations(const InputMessagePtr& msg)
439
+{
440
+    msg->getU8(); // amount of open pvp situations
441
+}
442
+
399 443
 void ProtocolGame::parsePlayerHelpers(const InputMessagePtr& msg)
400 444
 {
401 445
     uint id = msg->getU32();
@@ -468,6 +512,7 @@ void ProtocolGame::parseChallenge(const InputMessagePtr& msg)
468 512
 {
469 513
     uint timestamp = msg->getU32();
470 514
     uint8 random = msg->getU8();
515
+
471 516
     sendLoginPacket(timestamp, random);
472 517
 }
473 518
 
@@ -1038,7 +1083,7 @@ void ProtocolGame::parsePlayerInfo(const InputMessagePtr& msg)
1038 1083
     bool premium = msg->getU8(); // premium
1039 1084
     int vocation = msg->getU8(); // vocation
1040 1085
     if(g_game.getFeature(Otc::GamePremiumExpiration))
1041
-        int premiumEx = msg->getU32(); // premium expiration
1086
+        int premiumEx = msg->getU32(); // premium expiration used for premium advertisement
1042 1087
 
1043 1088
     int spellCount = msg->getU16();
1044 1089
     std::vector<int> spells;
@@ -1081,6 +1126,10 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
1081 1126
 
1082 1127
     double level = msg->getU16();
1083 1128
     double levelPercent = msg->getU8();
1129
+
1130
+    if(g_game.getFeature(Otc::GameExperienceBonus))
1131
+        double experienceBonus = msg->getDouble();
1132
+
1084 1133
     double mana;
1085 1134
     double maxMana;
1086 1135
 
@@ -1145,7 +1194,7 @@ void ProtocolGame::parsePlayerSkills(const InputMessagePtr& msg)
1145 1194
 
1146 1195
         int baseLevel;
1147 1196
         if(g_game.getFeature(Otc::GameSkillsBase))
1148
-            if (g_game.getFeature(Otc::GameBaseSkillU16))
1197
+            if(g_game.getFeature(Otc::GameBaseSkillU16))
1149 1198
                 baseLevel = msg->getU16();
1150 1199
             else
1151 1200
                 baseLevel = msg->getU8();
@@ -1699,7 +1748,7 @@ void ProtocolGame::parseChangeMapAwareRange(const InputMessagePtr& msg)
1699 1748
 void ProtocolGame::parseCreaturesMark(const InputMessagePtr& msg)
1700 1749
 {
1701 1750
     int len;
1702
-    if (g_game.getClientVersion() >= 1035) {
1751
+    if(g_game.getClientVersion() >= 1035) {
1703 1752
         len = 1;
1704 1753
     } else {
1705 1754
         len = msg->getU8();

+ 12
- 9
src/client/protocolgamesend.cpp View File

@@ -56,17 +56,20 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
56 56
     msg->addU16(g_game.getOs());
57 57
     msg->addU16(g_game.getProtocolVersion());
58 58
 
59
-    if(g_game.getClientVersion() >= 980) {
59
+    if(g_game.getFeature(Otc::GameClientVersion))
60 60
         msg->addU32(g_game.getClientVersion());
61
-        msg->addU8(0); // preview state
62
-    }
63 61
 
64
-    int offset = msg->getMessageSize();
62
+    if(g_game.getFeature(Otc::GameContentRevision))
63
+        msg->addU16(g_things.getContentRevision());
65 64
 
66
-    msg->addU8(0); // first RSA byte must be 0
65
+    if(g_game.getFeature(Otc::GamePreviewState))
66
+        msg->addU8(0);
67
+
68
+    int offset = msg->getMessageSize();
69
+    // first RSA byte must be 0
70
+    msg->addU8(0);
67 71
 
68
-    if(g_game.getClientVersion() >= 770)
69
-    {
72
+    if(g_game.getFeature(Otc::GameLoginPacketEncryption)) {
70 73
         // xtea key
71 74
         generateXteaKey();
72 75
         msg->addU32(m_xteaKey[0]);
@@ -99,7 +102,7 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
99 102
     msg->addPaddingBytes(paddingBytes);
100 103
 
101 104
     // encrypt with RSA
102
-    if(g_game.getClientVersion() >= 770)
105
+    if(g_game.getFeature(Otc::GameLoginPacketEncryption))
103 106
         msg->encryptRsa();
104 107
 
105 108
     if(g_game.getFeature(Otc::GameProtocolChecksum))
@@ -107,7 +110,7 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
107 110
 
108 111
     send(msg);
109 112
 
110
-    if(g_game.getClientVersion() >= 770)
113
+    if(g_game.getFeature(Otc::GameLoginPacketEncryption))
111 114
         enableXteaEncryption();
112 115
 }
113 116
 

+ 45
- 36
src/client/thingtype.cpp View File

@@ -274,50 +274,59 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS
274 274
         stdext::throw_exception(stdext::format("corrupt data (id: %d, category: %d, count: %d, lastAttr: %d)",
275 275
             m_id, m_category, count, attr));
276 276
 
277
-    uint8 width = fin->getU8();
278
-    uint8 height = fin->getU8();
279
-    m_size = Size(width, height);
280
-    if(width > 1 || height > 1) {
281
-        m_realSize = fin->getU8();
282
-        m_exactSize = std::min<int>(m_realSize, std::max<int>(width * 32, height * 32));
283
-    }
284
-    else
285
-        m_exactSize = 32;
286
-
287
-    m_layers = fin->getU8();
288
-    m_numPatternX = fin->getU8();
289
-    m_numPatternY = fin->getU8();
290
-    if(g_game.getClientVersion() >= 755)
291
-        m_numPatternZ = fin->getU8();
292
-    else
293
-        m_numPatternZ = 1;
294
-    m_animationPhases = fin->getU8();
277
+    uint8 frames = 1;
278
+    if(category == ThingCategoryCreature && g_game.getClientVersion() >= 1057)
279
+        frames = fin->getU8();
280
+
281
+    for(int i = 0; i < frames; ++i) {
282
+        uint8 frameGroup = FrameGroupDefault;
283
+        if(category == ThingCategoryCreature && g_game.getClientVersion() >= 1057) {
284
+            frameGroup = fin->getU8();
285
+        }
295 286
 
296
-    if(g_game.getFeature(Otc::GameEnhancedAnimations)) {
297
-        if(m_animationPhases > 1) {
298
-            m_animation.async = fin->getU8() == 0;
299
-            m_animation.loopCount = fin->get32();
300
-            m_animation.startIndex = fin->getU8();
287
+        uint8 width = fin->getU8();
288
+        uint8 height = fin->getU8();
289
+        m_size = Size(width, height);
290
+        if(width > 1 || height > 1) {
291
+            m_realSize = fin->getU8();
292
+            m_exactSize = std::min<int>(m_realSize, std::max<int>(width * 32, height * 32));
293
+        }
294
+        else
295
+            m_exactSize = 32;
301 296
 
302
-            for(int i = 0; i < m_animationPhases; i++) {
303
-                int minDuration = fin->getU32();
304
-                int maxDuration = fin->getU32();
297
+        m_layers = fin->getU8();
298
+        m_numPatternX = fin->getU8();
299
+        m_numPatternY = fin->getU8();
300
+        if(g_game.getClientVersion() >= 755)
301
+            m_numPatternZ = fin->getU8();
302
+        else
303
+            m_numPatternZ = 1;
304
+        m_animationPhases = fin->getU8();
305
+
306
+        if(g_game.getFeature(Otc::GameEnhancedAnimations)) {
307
+            if(m_animationPhases > 1) {
308
+                m_animation.async = fin->getU8() == 0;
309
+                m_animation.loopCount = fin->get32();
310
+                m_animation.startIndex = fin->getU8();
311
+
312
+                for (int i = 0; i < m_animationPhases; i++) {
313
+                    int minDuration = fin->getU32();
314
+                    int maxDuration = fin->getU32();
305 315
 
306
-                m_animation.frames.push_back(std::make_tuple(minDuration, maxDuration));
316
+                    m_animation.frames.push_back(std::make_tuple(minDuration, maxDuration));
317
+                }
307 318
             }
308 319
         }
309
-    }
310 320
 
311
-    int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
321
+        int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
312 322
 
313
-    // if(totalSprites == 0)
314
-    //     stdext::throw_exception("a thing type has no sprites");
315
-    if(totalSprites > 4096)
316
-        stdext::throw_exception("a thing type has more than 4096 sprites");
323
+        if(totalSprites > 4096)
324
+            stdext::throw_exception("a thing type has more than 4096 sprites");
317 325
 
318
-    m_spritesIndex.resize(totalSprites);
319
-    for(int i = 0; i < totalSprites; i++)
320
-        m_spritesIndex[i] = g_game.getFeature(Otc::GameSpritesU32) ? fin->getU32() : fin->getU16();
326
+        m_spritesIndex.resize(totalSprites);
327
+        for(int i = 0; i < totalSprites; i++)
328
+            m_spritesIndex[i] = g_game.getFeature(Otc::GameSpritesU32) ? fin->getU32() : fin->getU16();
329
+    }
321 330
 
322 331
     m_textures.resize(m_animationPhases);
323 332
     m_texturesFramesRects.resize(m_animationPhases);

+ 6
- 0
src/client/thingtype.h View File

@@ -32,6 +32,12 @@
32 32
 #include <framework/luaengine/luaobject.h>
33 33
 #include <framework/net/server.h>
34 34
 
35
+enum FrameGroup : uint8 {
36
+	FrameGroupIdle = 0,
37
+	FrameGroupMoving,
38
+	FrameGroupDefault = FrameGroupIdle
39
+};
40
+
35 41
 enum ThingCategory : uint8 {
36 42
     ThingCategoryItem = 0,
37 43
     ThingCategoryCreature,

+ 3
- 0
src/client/thingtypemanager.cpp View File

@@ -42,6 +42,7 @@ void ThingTypeManager::init()
42 42
     m_nullThingType = ThingTypePtr(new ThingType);
43 43
     m_nullItemType = ItemTypePtr(new ItemType);
44 44
     m_datSignature = 0;
45
+    m_contentRevision = 0;
45 46
     m_otbMinorVersion = 0;
46 47
     m_otbMajorVersion = 0;
47 48
     m_datLoaded = false;
@@ -100,12 +101,14 @@ bool ThingTypeManager::loadDat(std::string file)
100 101
 {
101 102
     m_datLoaded = false;
102 103
     m_datSignature = 0;
104
+    m_contentRevision = 0;
103 105
     try {
104 106
         file = g_resources.guessFilePath(file, "dat");
105 107
 
106 108
         FileStreamPtr fin = g_resources.openFile(file);
107 109
 
108 110
         m_datSignature = fin->getU32();
111
+        m_contentRevision = static_cast<uint16_t>(m_datSignature);
109 112
 
110 113
         for(int category = 0; category < ThingLastCategory; ++category) {
111 114
             int count = fin->getU16() + 1;

+ 2
- 0
src/client/thingtypemanager.h View File

@@ -66,6 +66,7 @@ public:
66 66
     uint32 getDatSignature() { return m_datSignature; }
67 67
     uint32 getOtbMajorVersion() { return m_otbMajorVersion; }
68 68
     uint32 getOtbMinorVersion() { return m_otbMinorVersion; }
69
+    uint16 getContentRevision() { return m_contentRevision; }
69 70
 
70 71
     bool isDatLoaded() { return m_datLoaded; }
71 72
     bool isXmlLoaded() { return m_xmlLoaded; }
@@ -89,6 +90,7 @@ private:
89 90
     uint32 m_otbMinorVersion;
90 91
     uint32 m_otbMajorVersion;
91 92
     uint32 m_datSignature;
93
+    uint16 m_contentRevision;
92 94
 };
93 95
 
94 96
 extern ThingTypeManager g_things;

Loading…
Cancel
Save