Support for Protocols up to 10.71, Adventurer Blessing
This commit is contained in:
parent
6ab69b499d
commit
7f3f18f991
|
@ -45,13 +45,17 @@ CharacterWidget < UIWidget
|
|||
MainWindow
|
||||
id: charactersWindow
|
||||
!text: tr('Character List')
|
||||
size: 250 248
|
||||
visible: false
|
||||
@onEnter: CharacterList.doLogin()
|
||||
@onEscape: CharacterList.hide(true)
|
||||
@onSetup: |
|
||||
g_keyboard.bindKeyPress('Up', function() self:getChildById('characters'):focusPreviousChild(KeyboardFocusReason) end, self)
|
||||
g_keyboard.bindKeyPress('Down', function() self:getChildById('characters'):focusNextChild(KeyboardFocusReason) end, self)
|
||||
if g_game.getFeature(GamePreviewState) then
|
||||
self:setSize({width = 350, height = 400})
|
||||
else
|
||||
self:setSize({width = 250, height = 248})
|
||||
end
|
||||
|
||||
TextList
|
||||
id: characters
|
||||
|
|
|
@ -59,6 +59,12 @@ local function onCharacterList(protocol, characters, account, otui)
|
|||
loadBox:destroy()
|
||||
loadBox = nil
|
||||
|
||||
for _, characterInfo in pairs(characters) do
|
||||
if characterInfo.previewState and characterInfo.previewState ~= PreviewState.Default then
|
||||
characterInfo.worldName = characterInfo.worldName .. ', Preview'
|
||||
end
|
||||
end
|
||||
|
||||
CharacterList.create(characters, account, otui)
|
||||
CharacterList.show()
|
||||
|
||||
|
@ -105,7 +111,7 @@ function EnterGame.init()
|
|||
local port = g_settings.get('port')
|
||||
local autologin = g_settings.getBoolean('autologin')
|
||||
local clientVersion = g_settings.getInteger('client-version')
|
||||
if clientVersion == 0 then clientVersion = 860 end
|
||||
if clientVersion == 0 then clientVersion = 1071 end
|
||||
|
||||
if port == nil or port == 0 then port = 7171 end
|
||||
|
||||
|
|
|
@ -17,7 +17,10 @@ inventoryButton = nil
|
|||
purseButton = nil
|
||||
|
||||
function init()
|
||||
connect(LocalPlayer, { onInventoryChange = onInventoryChange })
|
||||
connect(LocalPlayer, {
|
||||
onInventoryChange = onInventoryChange,
|
||||
onBlessingsChange = onBlessingsChange
|
||||
})
|
||||
connect(g_game, { onGameStart = refresh })
|
||||
|
||||
g_keyboard.bindKeyDown('Ctrl+I', toggle)
|
||||
|
@ -43,7 +46,10 @@ function init()
|
|||
end
|
||||
|
||||
function terminate()
|
||||
disconnect(LocalPlayer, { onInventoryChange = onInventoryChange })
|
||||
disconnect(LocalPlayer, {
|
||||
onInventoryChange = onInventoryChange,
|
||||
onBlessingsChange = onBlessingsChange
|
||||
})
|
||||
disconnect(g_game, { onGameStart = refresh })
|
||||
|
||||
g_keyboard.unbindKeyDown('Ctrl+I')
|
||||
|
@ -52,6 +58,21 @@ function terminate()
|
|||
inventoryButton:destroy()
|
||||
end
|
||||
|
||||
function toggleAdventurerStyle(hasBlessing)
|
||||
for slot = InventorySlotFirst, InventorySlotLast do
|
||||
local itemWidget = inventoryPanel:getChildById('slot' .. slot)
|
||||
if itemWidget then
|
||||
if hasBlessing then
|
||||
itemWidget:setBorderWidth(1)
|
||||
itemWidget:setBorderColor('#F7C80C')
|
||||
else
|
||||
itemWidget:setBorderWidth(0)
|
||||
itemWidget:setBorderColor('white')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function refresh()
|
||||
local player = g_game.getLocalPlayer()
|
||||
for i = InventorySlotFirst, InventorySlotPurse do
|
||||
|
@ -60,6 +81,7 @@ function refresh()
|
|||
else
|
||||
onInventoryChange(player, i, nil)
|
||||
end
|
||||
toggleAdventurerStyle(Bit.hasBit(player:getBlessings(), Blessings.Adventurer))
|
||||
end
|
||||
|
||||
purseButton:setVisible(g_game.getFeature(GamePurseSlot))
|
||||
|
@ -99,3 +121,10 @@ function onInventoryChange(player, slot, item, oldItem)
|
|||
itemWidget:setItem(nil)
|
||||
end
|
||||
end
|
||||
|
||||
function onBlessingsChange(player, blessings, oldBlessings)
|
||||
local hasAdventurerBlessing = Bit.hasBit(blessings, Blessings.Adventurer)
|
||||
if hasAdventurerBlessing ~= Bit.hasBit(oldBlessings, Blessings.Adventurer) then
|
||||
toggleAdventurerStyle(hasAdventurerBlessing)
|
||||
end
|
||||
end
|
|
@ -120,6 +120,13 @@ GameSpritesAlphaChannel = 56
|
|||
GamePremiumExpiration = 57
|
||||
GameBrowseField = 58
|
||||
GameEnhancedAnimations = 59
|
||||
GameOGLInformation = 60
|
||||
GameMessageSizeCheck = 61
|
||||
GamePreviewState = 62
|
||||
GameLoginPacketEncryption = 63
|
||||
GameClientVersion = 64
|
||||
GameContentRevision = 65
|
||||
GameExperienceBonus = 66
|
||||
|
||||
TextColors = {
|
||||
red = '#f55e5e', --'#c83200'
|
||||
|
@ -201,7 +208,7 @@ CIPSOFT_RSA = "1321277432058722840622950990822933849527763264961655079678763618"
|
|||
"88792221429527047321331896351555606801473202394175817"
|
||||
|
||||
-- set to the latest Tibia.pic signature to make otclient compatible with official tibia
|
||||
PIC_SIGNATURE = 0x53208400
|
||||
PIC_SIGNATURE = 0x542100C1
|
||||
|
||||
OsTypes = {
|
||||
Linux = 1,
|
||||
|
@ -244,4 +251,20 @@ ExtendedIds = {
|
|||
NeedsUpdate = 7
|
||||
}
|
||||
|
||||
PreviewState = {
|
||||
Default = 0,
|
||||
Inactive = 1,
|
||||
Active = 2
|
||||
}
|
||||
|
||||
Blessings = {
|
||||
None = 0,
|
||||
Adventurer = 1,
|
||||
SpiritualShielding = 2,
|
||||
EmbraceOfTibia = 4,
|
||||
FireOfSuns = 8,
|
||||
WisdomOfSolitude = 16,
|
||||
SparkOfPhoenix = 32
|
||||
}
|
||||
|
||||
-- @}
|
||||
|
|
|
@ -73,7 +73,8 @@ function g_game.getSupportedClients()
|
|||
1035, 1036, 1037, 1038, 1039,
|
||||
1040, 1041, 1050, 1051, 1052,
|
||||
1053, 1054, 1055, 1056, 1057,
|
||||
1058, 1059, 1060, 1061
|
||||
1058, 1059, 1060, 1061, 1062,
|
||||
1063, 1064, 1070, 1071
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -32,23 +32,28 @@ function ProtocolLogin:sendLoginPacket()
|
|||
|
||||
msg:addU16(g_game.getProtocolVersion())
|
||||
|
||||
if g_game.getClientVersion() >= 980 then
|
||||
if g_game.getFeature(GameClientVersion) then
|
||||
msg:addU32(g_game.getClientVersion())
|
||||
end
|
||||
|
||||
msg:addU32(g_things.getDatSignature())
|
||||
if g_game.getFeature(GameContentRevision) then
|
||||
msg:addU16(g_things.getContentRevision())
|
||||
msg:addU16(0)
|
||||
else
|
||||
msg:addU32(g_things.getDatSignature())
|
||||
end
|
||||
msg:addU32(g_sprites.getSprSignature())
|
||||
msg:addU32(PIC_SIGNATURE)
|
||||
|
||||
if g_game.getClientVersion() >= 980 then
|
||||
msg:addU8(0) -- clientType
|
||||
if g_game.getFeature(GamePreviewState) then
|
||||
msg:addU8(0)
|
||||
end
|
||||
|
||||
local offset = msg:getMessageSize()
|
||||
|
||||
if g_game.getClientVersion() >= 770 then
|
||||
if g_game.getFeature(GameLoginPacketEncryption) then
|
||||
-- first RSA byte must be 0
|
||||
msg:addU8(0)
|
||||
|
||||
-- xtea key
|
||||
self:generateXteaKey()
|
||||
local xteaKey = self:getXteaKey()
|
||||
|
@ -74,16 +79,23 @@ function ProtocolLogin:sendLoginPacket()
|
|||
local paddingBytes = g_crypt.rsaGetSize() - (msg:getMessageSize() - offset)
|
||||
assert(paddingBytes >= 0)
|
||||
msg:addPaddingBytes(paddingBytes, 0)
|
||||
if g_game.getClientVersion() >= 770 then
|
||||
if g_game.getFeature(GameLoginPacketEncryption) then
|
||||
msg:encryptRsa()
|
||||
end
|
||||
|
||||
if g_game.getFeature(GameOGLInformation) then
|
||||
msg:addU8(1) --unknown
|
||||
msg:addU8(1) --unknown
|
||||
msg:addString(g_graphics.getRenderer())
|
||||
msg:addString(g_graphics.getVersion())
|
||||
end
|
||||
|
||||
if g_game.getFeature(GameProtocolChecksum) then
|
||||
self:enableChecksum()
|
||||
end
|
||||
|
||||
self:send(msg)
|
||||
if g_game.getClientVersion() >= 770 then
|
||||
if g_game.getFeature(GameLoginPacketEncryption) then
|
||||
self:enableXteaEncryption()
|
||||
end
|
||||
self:recv()
|
||||
|
@ -141,7 +153,7 @@ function ProtocolLogin:parseCharacterList(msg)
|
|||
world.worldName = msg:getString()
|
||||
world.worldIp = msg:getString()
|
||||
world.worldPort = msg:getU16()
|
||||
msg:getU8() -- unknow byte?
|
||||
world.previewState = msg:getU8()
|
||||
worlds[worldId] = world
|
||||
end
|
||||
|
||||
|
@ -153,6 +165,7 @@ function ProtocolLogin:parseCharacterList(msg)
|
|||
character.worldName = worlds[worldId].worldName
|
||||
character.worldIp = worlds[worldId].worldIp
|
||||
character.worldPort = worlds[worldId].worldPort
|
||||
character.previewState = worlds[worldId].previewState
|
||||
characters[i] = character
|
||||
end
|
||||
|
||||
|
@ -165,8 +178,8 @@ function ProtocolLogin:parseCharacterList(msg)
|
|||
character.worldIp = iptostring(msg:getU32())
|
||||
character.worldPort = msg:getU16()
|
||||
|
||||
if g_game.getClientVersion() >= 980 then
|
||||
character.unknown = msg:getU8()
|
||||
if g_game.getFeature(GamePreviewState) then
|
||||
character.previewState = msg:getU8()
|
||||
end
|
||||
|
||||
characters[i] = character
|
||||
|
|
|
@ -328,7 +328,8 @@ namespace Otc
|
|||
MessageRVRChannel = 46,
|
||||
MessageRVRAnswer = 47,
|
||||
MessageRVRContinue = 48,
|
||||
LastMessage = 49,
|
||||
MessageGameHighlight = 49,
|
||||
LastMessage = 50,
|
||||
MessageInvalid = 255
|
||||
};
|
||||
|
||||
|
@ -390,6 +391,13 @@ namespace Otc
|
|||
GamePremiumExpiration = 57,
|
||||
GameBrowseField = 58,
|
||||
GameEnhancedAnimations = 59,
|
||||
GameOGLInformation = 60,
|
||||
GameMessageSizeCheck = 61,
|
||||
GamePreviewState = 62,
|
||||
GameLoginPacketEncryption = 63,
|
||||
GameClientVersion = 64,
|
||||
GameContentRevision = 65,
|
||||
GameExperienceBonus = 66,
|
||||
|
||||
LastGameFeature = 101
|
||||
};
|
||||
|
@ -450,6 +458,16 @@ namespace Otc
|
|||
PhaseRandom = 254,
|
||||
PhaseAsync = 255
|
||||
};
|
||||
|
||||
enum Blessings {
|
||||
BlessingNone = 0,
|
||||
BlessingAdventurer = 1,
|
||||
BlessingSpiritualShielding = 1 << 1,
|
||||
BlessingEmbraceOfTibia = 1 << 2,
|
||||
BlessingFireOfSuns = 1 << 3,
|
||||
BlessingWisdomOfSolitude = 1 << 4,
|
||||
BlessingSparkOfPhoenix = 1 << 5
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1425,7 +1425,7 @@ void Game::setProtocolVersion(int version)
|
|||
if(isOnline())
|
||||
stdext::throw_exception("Unable to change protocol version while online");
|
||||
|
||||
if(version != 0 && (version < 740 || version > 1051))
|
||||
if(version != 0 && (version < 740 || version > 1071))
|
||||
stdext::throw_exception(stdext::format("Protocol version %d not supported", version));
|
||||
|
||||
m_protocolVersion = version;
|
||||
|
@ -1443,7 +1443,7 @@ void Game::setClientVersion(int version)
|
|||
if(isOnline())
|
||||
stdext::throw_exception("Unable to change client version while online");
|
||||
|
||||
if(version != 0 && (version < 740 || version > 1051))
|
||||
if(version != 0 && (version < 740 || version > 1071))
|
||||
stdext::throw_exception(stdext::format("Client version %d not supported", version));
|
||||
|
||||
m_features.reset();
|
||||
|
@ -1452,6 +1452,7 @@ void Game::setClientVersion(int version)
|
|||
if(version >= 770) {
|
||||
enableFeature(Otc::GameLooktypeU16);
|
||||
enableFeature(Otc::GameMessageStatements);
|
||||
enableFeature(Otc::GameLoginPacketEncryption);
|
||||
}
|
||||
|
||||
if(version >= 780) {
|
||||
|
@ -1475,6 +1476,7 @@ void Game::setClientVersion(int version)
|
|||
|
||||
if(version >= 841) {
|
||||
enableFeature(Otc::GameChallengeOnLogin);
|
||||
enableFeature(Otc::GameMessageSizeCheck);
|
||||
}
|
||||
|
||||
if(version >= 854) {
|
||||
|
@ -1523,6 +1525,11 @@ void Game::setClientVersion(int version)
|
|||
enableFeature(Otc::GameAdditionalVipInfo);
|
||||
}
|
||||
|
||||
if(version >= 980) {
|
||||
enableFeature(Otc::GamePreviewState);
|
||||
enableFeature(Otc::GameClientVersion);
|
||||
}
|
||||
|
||||
if(version >= 981) {
|
||||
enableFeature(Otc::GameLoginPending);
|
||||
enableFeature(Otc::GameNewSpeedLaw);
|
||||
|
@ -1538,7 +1545,7 @@ void Game::setClientVersion(int version)
|
|||
enableFeature(Otc::GamePVPMode);
|
||||
}
|
||||
|
||||
if (version >= 1035) {
|
||||
if(version >= 1035) {
|
||||
enableFeature(Otc::GameDoubleSkills);
|
||||
enableFeature(Otc::GameBaseSkillU16);
|
||||
}
|
||||
|
@ -1556,6 +1563,18 @@ void Game::setClientVersion(int version)
|
|||
enableFeature(Otc::GameEnhancedAnimations);
|
||||
}
|
||||
|
||||
if(version >= 1054) {
|
||||
enableFeature(Otc::GameExperienceBonus);
|
||||
}
|
||||
|
||||
if(version >= 1061) {
|
||||
enableFeature(Otc::GameOGLInformation);
|
||||
}
|
||||
|
||||
if(version >= 1071) {
|
||||
enableFeature(Otc::GameContentRevision);
|
||||
}
|
||||
|
||||
m_clientVersion = version;
|
||||
|
||||
g_lua.callGlobalField("g_game", "onClientVersionChange", version);
|
||||
|
|
|
@ -31,6 +31,7 @@ LocalPlayer::LocalPlayer()
|
|||
{
|
||||
m_states = 0;
|
||||
m_vocation = 0;
|
||||
m_blessings = Otc::BlessingNone;
|
||||
m_walkLockExpiration = 0;
|
||||
|
||||
m_skillsLevel.fill(-1);
|
||||
|
@ -546,6 +547,16 @@ void LocalPlayer::setSpells(const std::vector<int>& spells)
|
|||
}
|
||||
}
|
||||
|
||||
void LocalPlayer::setBlessings(int blessings)
|
||||
{
|
||||
if(blessings != m_blessings) {
|
||||
int oldBlessings = m_blessings;
|
||||
m_blessings = blessings;
|
||||
|
||||
callLuaField("onBlessingsChange", blessings, oldBlessings);
|
||||
}
|
||||
}
|
||||
|
||||
bool LocalPlayer::hasSight(const Position& pos)
|
||||
{
|
||||
return m_position.isInRange(pos, g_map.getAwareRange().left - 1, g_map.getAwareRange().top - 1);
|
||||
|
|
|
@ -63,6 +63,7 @@ public:
|
|||
void setRegenerationTime(double regenerationTime);
|
||||
void setOfflineTrainingTime(double offlineTrainingTime);
|
||||
void setSpells(const std::vector<int>& spells);
|
||||
void setBlessings(int blessings);
|
||||
|
||||
int getStates() { return m_states; }
|
||||
int getSkillLevel(Otc::Skill skill) { return m_skillsLevel[skill]; }
|
||||
|
@ -88,6 +89,7 @@ public:
|
|||
double getOfflineTrainingTime() { return m_offlineTrainingTime; }
|
||||
std::vector<int> getSpells() { return m_spells; }
|
||||
ItemPtr getInventoryItem(Otc::InventorySlot inventory) { return m_inventoryItems[inventory]; }
|
||||
int getBlessings() { return m_blessings; }
|
||||
|
||||
bool hasSight(const Position& pos);
|
||||
bool isKnown() { return m_known; }
|
||||
|
@ -144,6 +146,7 @@ private:
|
|||
|
||||
int m_states;
|
||||
int m_vocation;
|
||||
int m_blessings;
|
||||
|
||||
double m_health;
|
||||
double m_maxHealth;
|
||||
|
|
|
@ -63,6 +63,7 @@ void Client::registerLuaFunctions()
|
|||
g_lua.bindSingletonFunction("g_things", "isDatLoaded", &ThingTypeManager::isDatLoaded, &g_things);
|
||||
g_lua.bindSingletonFunction("g_things", "isOtbLoaded", &ThingTypeManager::isOtbLoaded, &g_things);
|
||||
g_lua.bindSingletonFunction("g_things", "getDatSignature", &ThingTypeManager::getDatSignature, &g_things);
|
||||
g_lua.bindSingletonFunction("g_things", "getContentRevision", &ThingTypeManager::getContentRevision, &g_things);
|
||||
g_lua.bindSingletonFunction("g_things", "getThingType", &ThingTypeManager::getThingType, &g_things);
|
||||
g_lua.bindSingletonFunction("g_things", "getItemType", &ThingTypeManager::getItemType, &g_things);
|
||||
g_lua.bindSingletonFunction("g_things", "getThingTypes", &ThingTypeManager::getThingTypes, &g_things);
|
||||
|
@ -630,6 +631,7 @@ void Client::registerLuaFunctions()
|
|||
g_lua.bindClassMemberFunction<LocalPlayer>("getTotalCapacity", &LocalPlayer::getTotalCapacity);
|
||||
g_lua.bindClassMemberFunction<LocalPlayer>("getInventoryItem", &LocalPlayer::getInventoryItem);
|
||||
g_lua.bindClassMemberFunction<LocalPlayer>("getVocation", &LocalPlayer::getVocation);
|
||||
g_lua.bindClassMemberFunction<LocalPlayer>("getBlessings", &LocalPlayer::getBlessings);
|
||||
g_lua.bindClassMemberFunction<LocalPlayer>("isPremium", &LocalPlayer::isPremium);
|
||||
g_lua.bindClassMemberFunction<LocalPlayer>("isKnown", &LocalPlayer::isKnown);
|
||||
g_lua.bindClassMemberFunction<LocalPlayer>("isPreWalking", &LocalPlayer::isPreWalking);
|
||||
|
|
|
@ -28,7 +28,52 @@ std::map<uint8, uint8> messageModesMap;
|
|||
|
||||
void buildMessageModesMap(int version) {
|
||||
messageModesMap.clear();
|
||||
if(version >= 1036) {
|
||||
|
||||
if(version >= 1055) { // might be 1054
|
||||
messageModesMap[Otc::MessageNone] = 0;
|
||||
messageModesMap[Otc::MessageSay] = 1;
|
||||
messageModesMap[Otc::MessageWhisper] = 2;
|
||||
messageModesMap[Otc::MessageYell] = 3;
|
||||
messageModesMap[Otc::MessagePrivateFrom] = 4;
|
||||
messageModesMap[Otc::MessagePrivateTo] = 5;
|
||||
messageModesMap[Otc::MessageChannelManagement] = 6;
|
||||
messageModesMap[Otc::MessageChannel] = 7;
|
||||
messageModesMap[Otc::MessageChannelHighlight] = 8;
|
||||
messageModesMap[Otc::MessageSpell] = 9;
|
||||
//NpcFromStartBlock = 10
|
||||
messageModesMap[Otc::MessageNpcFrom] = 11;
|
||||
messageModesMap[Otc::MessageNpcTo] = 12;
|
||||
messageModesMap[Otc::MessageGamemasterBroadcast] = 13;
|
||||
messageModesMap[Otc::MessageGamemasterChannel] = 14;
|
||||
messageModesMap[Otc::MessageGamemasterPrivateFrom] = 15;
|
||||
messageModesMap[Otc::MessageGamemasterPrivateTo] = 16;
|
||||
messageModesMap[Otc::MessageLogin] = 17;
|
||||
messageModesMap[Otc::MessageWarning] = 18; // Admin
|
||||
messageModesMap[Otc::MessageGame] = 19;
|
||||
messageModesMap[Otc::MessageGameHighlight] = 20;
|
||||
messageModesMap[Otc::MessageFailure] = 21;
|
||||
messageModesMap[Otc::MessageLook] = 22;
|
||||
messageModesMap[Otc::MessageDamageDealed] = 23;
|
||||
messageModesMap[Otc::MessageDamageReceived] = 24;
|
||||
messageModesMap[Otc::MessageHeal] = 25;
|
||||
messageModesMap[Otc::MessageExp] = 26;
|
||||
messageModesMap[Otc::MessageDamageOthers] = 27;
|
||||
messageModesMap[Otc::MessageHealOthers] = 28;
|
||||
messageModesMap[Otc::MessageExpOthers] = 29;
|
||||
messageModesMap[Otc::MessageStatus] = 30;
|
||||
messageModesMap[Otc::MessageLoot] = 31;
|
||||
messageModesMap[Otc::MessageTradeNpc] = 32;
|
||||
messageModesMap[Otc::MessageGuild] = 33;
|
||||
messageModesMap[Otc::MessagePartyManagement] = 34;
|
||||
messageModesMap[Otc::MessageParty] = 35;
|
||||
messageModesMap[Otc::MessageBarkLow] = 36;
|
||||
messageModesMap[Otc::MessageBarkLoud] = 37;
|
||||
messageModesMap[Otc::MessageReport] = 38;
|
||||
messageModesMap[Otc::MessageHotkeyUse] = 39;
|
||||
messageModesMap[Otc::MessageTutorialHint] = 40;
|
||||
messageModesMap[Otc::MessageThankyou] = 41;
|
||||
messageModesMap[Otc::MessageMarket] = 42;
|
||||
} else if(version >= 1036) {
|
||||
for(int i = Otc::MessageNone; i <= Otc::MessageBeyondLast; ++i) {
|
||||
if(i >= Otc::MessageNpcTo)
|
||||
messageModesMap[i] = i + 1;
|
||||
|
|
|
@ -107,6 +107,8 @@ namespace Proto {
|
|||
GameServerCreatureType = 149,
|
||||
GameServerEditText = 150,
|
||||
GameServerEditList = 151,
|
||||
GameServerBlessings = 156,
|
||||
GameServerPreset = 157,
|
||||
GameServerPremiumTrigger = 158, // 1038
|
||||
GameServerPlayerDataBasic = 159, // 950
|
||||
GameServerPlayerData = 160,
|
||||
|
@ -130,6 +132,8 @@ namespace Proto {
|
|||
GameServerTextMessage = 180,
|
||||
GameServerCancelWalk = 181,
|
||||
GameServerWalkWait = 182,
|
||||
GameServerUnjustifiedStats = 183,
|
||||
GameServerPvpSituations = 184,
|
||||
GameServerFloorChangeUp = 190,
|
||||
GameServerFloorChangeDown = 191,
|
||||
GameServerChooseOutfit = 200,
|
||||
|
|
|
@ -56,7 +56,7 @@ void ProtocolGame::onRecv(const InputMessagePtr& inputMessage)
|
|||
if(m_firstRecv) {
|
||||
m_firstRecv = false;
|
||||
|
||||
if(g_game.getClientVersion() >= 841) { // not sure since which version this is, but it seems to be after 8.40
|
||||
if(g_game.getFeature(Otc::GameMessageSizeCheck)) {
|
||||
int size = inputMessage->getU16();
|
||||
if(size != inputMessage->getUnreadSize()) {
|
||||
g_logger.traceError("invalid message size");
|
||||
|
|
|
@ -128,6 +128,10 @@ public:
|
|||
void addPosition(const OutputMessagePtr& msg, const Position& position);
|
||||
|
||||
private:
|
||||
void parseBlessings(const InputMessagePtr& msg);
|
||||
void parseUnjustifiedStats(const InputMessagePtr& msg);
|
||||
void parsePvpSituations(const InputMessagePtr& msg);
|
||||
void parsePreset(const InputMessagePtr& msg);
|
||||
void parseCreatureType(const InputMessagePtr& msg);
|
||||
void parsePlayerHelpers(const InputMessagePtr& msg);
|
||||
void parseMessage(const InputMessagePtr& msg);
|
||||
|
|
|
@ -340,6 +340,19 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
|
|||
case Proto::GameServerCreatureType:
|
||||
parseCreatureType(msg);
|
||||
break;
|
||||
// PROTOCOL>=1055
|
||||
case Proto::GameServerBlessings:
|
||||
parseBlessings(msg);
|
||||
break;
|
||||
case Proto::GameServerUnjustifiedStats:
|
||||
parseUnjustifiedStats(msg);
|
||||
break;
|
||||
case Proto::GameServerPvpSituations:
|
||||
parsePvpSituations(msg);
|
||||
break;
|
||||
case Proto::GameServerPreset:
|
||||
parsePreset(msg);
|
||||
break;
|
||||
// otclient ONLY
|
||||
case Proto::GameServerExtendedOpcode:
|
||||
parseExtendedOpcode(msg);
|
||||
|
@ -372,6 +385,9 @@ void ProtocolGame::parseLogin(const InputMessagePtr& msg)
|
|||
}
|
||||
bool canReportBugs = msg->getU8();
|
||||
|
||||
msg->getU8(); // can change pvp framing option
|
||||
msg->getU8(); // expert mode enabled
|
||||
|
||||
m_localPlayer->setId(playerId);
|
||||
g_game.setServerBeat(serverBeat);
|
||||
g_game.setCanReportBugs(canReportBugs);
|
||||
|
@ -396,6 +412,34 @@ void ProtocolGame::parseEnterGame(const InputMessagePtr& msg)
|
|||
}
|
||||
}
|
||||
|
||||
void ProtocolGame::parseBlessings(const InputMessagePtr& msg)
|
||||
{
|
||||
uint16 blessings = msg->getU16();
|
||||
m_localPlayer->setBlessings(blessings);
|
||||
}
|
||||
|
||||
void ProtocolGame::parsePreset(const InputMessagePtr& msg)
|
||||
{
|
||||
uint16 preset = msg->getU32();
|
||||
}
|
||||
|
||||
void ProtocolGame::parseUnjustifiedStats(const InputMessagePtr& msg)
|
||||
{
|
||||
// Unjustified Kills display since 10.55
|
||||
msg->getU8();
|
||||
msg->getU8();
|
||||
msg->getU8();
|
||||
msg->getU8();
|
||||
msg->getU8();
|
||||
msg->getU8();
|
||||
msg->getU8();
|
||||
}
|
||||
|
||||
void ProtocolGame::parsePvpSituations(const InputMessagePtr& msg)
|
||||
{
|
||||
msg->getU8(); // amount of open pvp situations
|
||||
}
|
||||
|
||||
void ProtocolGame::parsePlayerHelpers(const InputMessagePtr& msg)
|
||||
{
|
||||
uint id = msg->getU32();
|
||||
|
@ -468,6 +512,7 @@ void ProtocolGame::parseChallenge(const InputMessagePtr& msg)
|
|||
{
|
||||
uint timestamp = msg->getU32();
|
||||
uint8 random = msg->getU8();
|
||||
|
||||
sendLoginPacket(timestamp, random);
|
||||
}
|
||||
|
||||
|
@ -1038,7 +1083,7 @@ void ProtocolGame::parsePlayerInfo(const InputMessagePtr& msg)
|
|||
bool premium = msg->getU8(); // premium
|
||||
int vocation = msg->getU8(); // vocation
|
||||
if(g_game.getFeature(Otc::GamePremiumExpiration))
|
||||
int premiumEx = msg->getU32(); // premium expiration
|
||||
int premiumEx = msg->getU32(); // premium expiration used for premium advertisement
|
||||
|
||||
int spellCount = msg->getU16();
|
||||
std::vector<int> spells;
|
||||
|
@ -1081,6 +1126,10 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
|
|||
|
||||
double level = msg->getU16();
|
||||
double levelPercent = msg->getU8();
|
||||
|
||||
if(g_game.getFeature(Otc::GameExperienceBonus))
|
||||
double experienceBonus = msg->getDouble();
|
||||
|
||||
double mana;
|
||||
double maxMana;
|
||||
|
||||
|
@ -1145,7 +1194,7 @@ void ProtocolGame::parsePlayerSkills(const InputMessagePtr& msg)
|
|||
|
||||
int baseLevel;
|
||||
if(g_game.getFeature(Otc::GameSkillsBase))
|
||||
if (g_game.getFeature(Otc::GameBaseSkillU16))
|
||||
if(g_game.getFeature(Otc::GameBaseSkillU16))
|
||||
baseLevel = msg->getU16();
|
||||
else
|
||||
baseLevel = msg->getU8();
|
||||
|
@ -1699,7 +1748,7 @@ void ProtocolGame::parseChangeMapAwareRange(const InputMessagePtr& msg)
|
|||
void ProtocolGame::parseCreaturesMark(const InputMessagePtr& msg)
|
||||
{
|
||||
int len;
|
||||
if (g_game.getClientVersion() >= 1035) {
|
||||
if(g_game.getClientVersion() >= 1035) {
|
||||
len = 1;
|
||||
} else {
|
||||
len = msg->getU8();
|
||||
|
|
|
@ -56,17 +56,20 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
|
|||
msg->addU16(g_game.getOs());
|
||||
msg->addU16(g_game.getProtocolVersion());
|
||||
|
||||
if(g_game.getClientVersion() >= 980) {
|
||||
if(g_game.getFeature(Otc::GameClientVersion))
|
||||
msg->addU32(g_game.getClientVersion());
|
||||
msg->addU8(0); // preview state
|
||||
}
|
||||
|
||||
if(g_game.getFeature(Otc::GameContentRevision))
|
||||
msg->addU16(g_things.getContentRevision());
|
||||
|
||||
if(g_game.getFeature(Otc::GamePreviewState))
|
||||
msg->addU8(0);
|
||||
|
||||
int offset = msg->getMessageSize();
|
||||
// first RSA byte must be 0
|
||||
msg->addU8(0);
|
||||
|
||||
msg->addU8(0); // first RSA byte must be 0
|
||||
|
||||
if(g_game.getClientVersion() >= 770)
|
||||
{
|
||||
if(g_game.getFeature(Otc::GameLoginPacketEncryption)) {
|
||||
// xtea key
|
||||
generateXteaKey();
|
||||
msg->addU32(m_xteaKey[0]);
|
||||
|
@ -99,7 +102,7 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
|
|||
msg->addPaddingBytes(paddingBytes);
|
||||
|
||||
// encrypt with RSA
|
||||
if(g_game.getClientVersion() >= 770)
|
||||
if(g_game.getFeature(Otc::GameLoginPacketEncryption))
|
||||
msg->encryptRsa();
|
||||
|
||||
if(g_game.getFeature(Otc::GameProtocolChecksum))
|
||||
|
@ -107,7 +110,7 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
|
|||
|
||||
send(msg);
|
||||
|
||||
if(g_game.getClientVersion() >= 770)
|
||||
if(g_game.getFeature(Otc::GameLoginPacketEncryption))
|
||||
enableXteaEncryption();
|
||||
}
|
||||
|
||||
|
|
|
@ -274,51 +274,60 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS
|
|||
stdext::throw_exception(stdext::format("corrupt data (id: %d, category: %d, count: %d, lastAttr: %d)",
|
||||
m_id, m_category, count, attr));
|
||||
|
||||
uint8 width = fin->getU8();
|
||||
uint8 height = fin->getU8();
|
||||
m_size = Size(width, height);
|
||||
if(width > 1 || height > 1) {
|
||||
m_realSize = fin->getU8();
|
||||
m_exactSize = std::min<int>(m_realSize, std::max<int>(width * 32, height * 32));
|
||||
}
|
||||
else
|
||||
m_exactSize = 32;
|
||||
uint8 frames = 1;
|
||||
if(category == ThingCategoryCreature && g_game.getClientVersion() >= 1057)
|
||||
frames = fin->getU8();
|
||||
|
||||
m_layers = fin->getU8();
|
||||
m_numPatternX = fin->getU8();
|
||||
m_numPatternY = fin->getU8();
|
||||
if(g_game.getClientVersion() >= 755)
|
||||
m_numPatternZ = fin->getU8();
|
||||
else
|
||||
m_numPatternZ = 1;
|
||||
m_animationPhases = fin->getU8();
|
||||
for(int i = 0; i < frames; ++i) {
|
||||
uint8 frameGroup = FrameGroupDefault;
|
||||
if(category == ThingCategoryCreature && g_game.getClientVersion() >= 1057) {
|
||||
frameGroup = fin->getU8();
|
||||
}
|
||||
|
||||
if(g_game.getFeature(Otc::GameEnhancedAnimations)) {
|
||||
if(m_animationPhases > 1) {
|
||||
m_animation.async = fin->getU8() == 0;
|
||||
m_animation.loopCount = fin->get32();
|
||||
m_animation.startIndex = fin->getU8();
|
||||
uint8 width = fin->getU8();
|
||||
uint8 height = fin->getU8();
|
||||
m_size = Size(width, height);
|
||||
if(width > 1 || height > 1) {
|
||||
m_realSize = fin->getU8();
|
||||
m_exactSize = std::min<int>(m_realSize, std::max<int>(width * 32, height * 32));
|
||||
}
|
||||
else
|
||||
m_exactSize = 32;
|
||||
|
||||
for(int i = 0; i < m_animationPhases; i++) {
|
||||
int minDuration = fin->getU32();
|
||||
int maxDuration = fin->getU32();
|
||||
m_layers = fin->getU8();
|
||||
m_numPatternX = fin->getU8();
|
||||
m_numPatternY = fin->getU8();
|
||||
if(g_game.getClientVersion() >= 755)
|
||||
m_numPatternZ = fin->getU8();
|
||||
else
|
||||
m_numPatternZ = 1;
|
||||
m_animationPhases = fin->getU8();
|
||||
|
||||
m_animation.frames.push_back(std::make_tuple(minDuration, maxDuration));
|
||||
if(g_game.getFeature(Otc::GameEnhancedAnimations)) {
|
||||
if(m_animationPhases > 1) {
|
||||
m_animation.async = fin->getU8() == 0;
|
||||
m_animation.loopCount = fin->get32();
|
||||
m_animation.startIndex = fin->getU8();
|
||||
|
||||
for (int i = 0; i < m_animationPhases; i++) {
|
||||
int minDuration = fin->getU32();
|
||||
int maxDuration = fin->getU32();
|
||||
|
||||
m_animation.frames.push_back(std::make_tuple(minDuration, maxDuration));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
|
||||
|
||||
if(totalSprites > 4096)
|
||||
stdext::throw_exception("a thing type has more than 4096 sprites");
|
||||
|
||||
m_spritesIndex.resize(totalSprites);
|
||||
for(int i = 0; i < totalSprites; i++)
|
||||
m_spritesIndex[i] = g_game.getFeature(Otc::GameSpritesU32) ? fin->getU32() : fin->getU16();
|
||||
}
|
||||
|
||||
int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
|
||||
|
||||
// if(totalSprites == 0)
|
||||
// stdext::throw_exception("a thing type has no sprites");
|
||||
if(totalSprites > 4096)
|
||||
stdext::throw_exception("a thing type has more than 4096 sprites");
|
||||
|
||||
m_spritesIndex.resize(totalSprites);
|
||||
for(int i = 0; i < totalSprites; i++)
|
||||
m_spritesIndex[i] = g_game.getFeature(Otc::GameSpritesU32) ? fin->getU32() : fin->getU16();
|
||||
|
||||
m_textures.resize(m_animationPhases);
|
||||
m_texturesFramesRects.resize(m_animationPhases);
|
||||
m_texturesFramesOriginRects.resize(m_animationPhases);
|
||||
|
|
|
@ -32,6 +32,12 @@
|
|||
#include <framework/luaengine/luaobject.h>
|
||||
#include <framework/net/server.h>
|
||||
|
||||
enum FrameGroup : uint8 {
|
||||
FrameGroupIdle = 0,
|
||||
FrameGroupMoving,
|
||||
FrameGroupDefault = FrameGroupIdle
|
||||
};
|
||||
|
||||
enum ThingCategory : uint8 {
|
||||
ThingCategoryItem = 0,
|
||||
ThingCategoryCreature,
|
||||
|
|
|
@ -42,6 +42,7 @@ void ThingTypeManager::init()
|
|||
m_nullThingType = ThingTypePtr(new ThingType);
|
||||
m_nullItemType = ItemTypePtr(new ItemType);
|
||||
m_datSignature = 0;
|
||||
m_contentRevision = 0;
|
||||
m_otbMinorVersion = 0;
|
||||
m_otbMajorVersion = 0;
|
||||
m_datLoaded = false;
|
||||
|
@ -100,12 +101,14 @@ bool ThingTypeManager::loadDat(std::string file)
|
|||
{
|
||||
m_datLoaded = false;
|
||||
m_datSignature = 0;
|
||||
m_contentRevision = 0;
|
||||
try {
|
||||
file = g_resources.guessFilePath(file, "dat");
|
||||
|
||||
FileStreamPtr fin = g_resources.openFile(file);
|
||||
|
||||
m_datSignature = fin->getU32();
|
||||
m_contentRevision = static_cast<uint16_t>(m_datSignature);
|
||||
|
||||
for(int category = 0; category < ThingLastCategory; ++category) {
|
||||
int count = fin->getU16() + 1;
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
uint32 getDatSignature() { return m_datSignature; }
|
||||
uint32 getOtbMajorVersion() { return m_otbMajorVersion; }
|
||||
uint32 getOtbMinorVersion() { return m_otbMinorVersion; }
|
||||
uint16 getContentRevision() { return m_contentRevision; }
|
||||
|
||||
bool isDatLoaded() { return m_datLoaded; }
|
||||
bool isXmlLoaded() { return m_xmlLoaded; }
|
||||
|
@ -89,6 +90,7 @@ private:
|
|||
uint32 m_otbMinorVersion;
|
||||
uint32 m_otbMajorVersion;
|
||||
uint32 m_datSignature;
|
||||
uint16 m_contentRevision;
|
||||
};
|
||||
|
||||
extern ThingTypeManager g_things;
|
||||
|
|
Loading…
Reference in New Issue