Support for Protocols up to 10.71, Adventurer Blessing

This commit is contained in:
TheSumm 2014-12-29 18:08:13 +01:00
parent 6ab69b499d
commit 7f3f18f991
21 changed files with 342 additions and 88 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}
-- @}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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");

View File

@ -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);

View File

@ -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();

View File

@ -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();
}

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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;