diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index 9015f198..9b64ddfe 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -35,7 +35,7 @@ end local function onCharacterList(protocol, characters, account, otui) -- Try add server to the server list - ServerList.add(G.host, G.port, g_game.getProtocolVersion()) + ServerList.add(G.host, G.port, g_game.getClientVersion()) if enterGame:getChildById('rememberPasswordBox'):isChecked() then local account = g_crypt.encrypt(G.account) @@ -82,7 +82,7 @@ local function onUpdateNeeded(protocol, signature) local cancelFunc = EnterGame.show EnterGame.updateFunc(signature, continueFunc, cancelFunc) else - local errorBox = displayErrorBox(tr('Update needed'), tr('Your client needs update, try redownloading it.')) + local errorBox = displayErrorBox(tr('Update needed'), tr('Your client needs updating, try redownloading it.')) connect(errorBox, { onOk = EnterGame.show }) end end @@ -242,7 +242,7 @@ function EnterGame.doLogin() g_game.chooseRsa(G.host) g_game.setClientVersion(clientVersion) - g_game.setProtocolVersion(g_game.getProtocolVersionForClient(clientVersion)) + g_game.setProtocolVersion(g_game.getClientProtocolVersion(clientVersion)) if modules.game_things.isLoaded() then protocolLogin:login(G.host, G.port, G.account, G.password) diff --git a/modules/game_console/console.lua b/modules/game_console/console.lua index 924c4bf5..63768b96 100644 --- a/modules/game_console/console.lua +++ b/modules/game_console/console.lua @@ -324,7 +324,7 @@ end function openHelp() local helpChannel = 9 - if g_game.getProtocolVersion() <= 810 then + if g_game.getClientVersion() <= 810 then helpChannel = 8 end g_game.joinChannel(helpChannel) @@ -1236,7 +1236,7 @@ function online() defaultTab = addTab(tr('Default'), true) serverTab = addTab(tr('Server Log'), false) - if g_game.getProtocolVersion() < 862 then + if g_game.getClientVersion() < 862 then g_keyboard.bindKeyDown('Ctrl+R', openPlayerReportRuleViolationWindow) end -- open last channels @@ -1259,7 +1259,7 @@ function online() end function offline() - if g_game.getProtocolVersion() < 862 then + if g_game.getClientVersion() < 862 then g_keyboard.unbindKeyDown('Ctrl+R') end clear() diff --git a/modules/game_hotkeys/hotkeys_manager.lua b/modules/game_hotkeys/hotkeys_manager.lua index e1effdc0..7ffa86a7 100644 --- a/modules/game_hotkeys/hotkeys_manager.lua +++ b/modules/game_hotkeys/hotkeys_manager.lua @@ -382,7 +382,7 @@ function doKeyCombo(keyCombo) modules.game_console.setTextEditText(hotKey.value) end elseif hotKey.useType == HOTKEY_MANAGER_USE then - if g_game.getProtocolVersion() < 780 or hotKey.subType then + if g_game.getClientVersion() < 780 or hotKey.subType then local item = g_game.findPlayerItem(hotKey.itemId, hotKey.subType or -1) if item then g_game.use(item) @@ -391,7 +391,7 @@ function doKeyCombo(keyCombo) g_game.useInventoryItem(hotKey.itemId) end elseif hotKey.useType == HOTKEY_MANAGER_USEONSELF then - if g_game.getProtocolVersion() < 780 or hotKey.subType then + if g_game.getClientVersion() < 780 or hotKey.subType then local item = g_game.findPlayerItem(hotKey.itemId, hotKey.subType or -1) if item then g_game.useWith(item, g_game.getLocalPlayer()) @@ -403,7 +403,7 @@ function doKeyCombo(keyCombo) local attackingCreature = g_game.getAttackingCreature() if not attackingCreature then local item = Item.create(hotKey.itemId) - if g_game.getProtocolVersion() < 780 or hotKey.subType then + if g_game.getClientVersion() < 780 or hotKey.subType then local tmpItem = g_game.findPlayerItem(hotKey.itemId, hotKey.subType or -1) if not tmpItem then return end item = tmpItem @@ -414,7 +414,7 @@ function doKeyCombo(keyCombo) end if not attackingCreature:getTile() then return end - if g_game.getProtocolVersion() < 780 or hotKey.subType then + if g_game.getClientVersion() < 780 or hotKey.subType then local item = g_game.findPlayerItem(hotKey.itemId, hotKey.subType or -1) if item then g_game.useWith(item, attackingCreature) @@ -424,7 +424,7 @@ function doKeyCombo(keyCombo) end elseif hotKey.useType == HOTKEY_MANAGER_USEWITH then local item = Item.create(hotKey.itemId) - if g_game.getProtocolVersion() < 780 or hotKey.subType then + if g_game.getClientVersion() < 780 or hotKey.subType then local tmpItem = g_game.findPlayerItem(hotKey.itemId, hotKey.subType or -1) if not tmpItem then return true end item = tmpItem diff --git a/modules/game_market/marketprotocol.lua b/modules/game_market/marketprotocol.lua index 1caac3c7..5dd28129 100644 --- a/modules/game_market/marketprotocol.lua +++ b/modules/game_market/marketprotocol.lua @@ -39,14 +39,14 @@ end -- parsing protocols local function parseMarketEnter(protocol, msg) local balance - if g_game.getProtocolVersion() >= 973 then + if g_game.getClientVersion() >= 981 then balance = msg:getU64() else balance = msg:getU32() end local vocation = -1 - if g_game.getProtocolVersion() < 950 then + if g_game.getClientVersion() < 950 then vocation = msg:getU8() -- get vocation id end local offers = msg:getU8() diff --git a/modules/game_minimap/minimap.lua b/modules/game_minimap/minimap.lua index ecdd7904..86665903 100644 --- a/modules/game_minimap/minimap.lua +++ b/modules/game_minimap/minimap.lua @@ -8,7 +8,8 @@ oldZoom = nil oldPos = nil function init() - minimapButton = modules.client_topmenu.addRightGameToggleButton('minimapButton', tr('Minimap') .. ' (Ctrl+M)', '/images/topbuttons/minimap', toggle) + minimapButton = modules.client_topmenu.addRightGameToggleButton('minimapButton', + tr('Minimap') .. ' (Ctrl+M)', '/images/topbuttons/minimap', toggle) minimapButton:setOn(true) minimapWindow = g_ui.loadUI('minimap', modules.game_interface.getRightPanel()) @@ -95,7 +96,7 @@ function offline() end function loadMap(clean) - local protocolVersion = g_game.getProtocolVersion() + local clientVersion = g_game.getClientVersion() if clean then g_minimap.clean() @@ -107,7 +108,7 @@ function loadMap(clean) g_minimap.loadOtmm(minimapFile) end else - local minimapFile = '/minimap_' .. protocolVersion .. '.otcm' + local minimapFile = '/minimap_' .. clientVersion .. '.otcm' if g_resources.fileExists(minimapFile) then g_map.loadOtcm(minimapFile) end @@ -116,12 +117,12 @@ function loadMap(clean) end function saveMap() - local protocolVersion = g_game.getProtocolVersion() + local clientVersion = g_game.getClientVersion() if otmm then local minimapFile = '/minimap.otmm' g_minimap.saveOtmm(minimapFile) else - local minimapFile = '/minimap_' .. protocolVersion .. '.otcm' + local minimapFile = '/minimap_' .. clientVersion .. '.otcm' g_map.saveOtcm(minimapFile) end minimapWidget:save() diff --git a/modules/game_spelllist/spelllist.lua b/modules/game_spelllist/spelllist.lua index dd3299fd..1db1ca34 100644 --- a/modules/game_spelllist/spelllist.lua +++ b/modules/game_spelllist/spelllist.lua @@ -83,7 +83,7 @@ function online() end -- Vocation is only send in newer clients - if g_game.getProtocolVersion() >= 950 then + if g_game.getClientVersion() >= 950 then spelllistWindow:getChildById('buttonFilterVocation'):setVisible(true) else spelllistWindow:getChildById('buttonFilterVocation'):setVisible(false) diff --git a/modules/game_things/things.lua b/modules/game_things/things.lua index 3d3e8e7d..35c29903 100644 --- a/modules/game_things/things.lua +++ b/modules/game_things/things.lua @@ -2,11 +2,11 @@ filename = nil loaded = false function init() - connect(g_game, { onProtocolVersionChange = load }) + connect(g_game, { onClientVersionChange = load }) end function terminate() - disconnect(g_game, { onProtocolVersionChange = load }) + disconnect(g_game, { onClientVersionChange = load }) end function setFileName(name) @@ -43,8 +43,9 @@ function load() local messageBox = displayErrorBox(tr('Error'), errorMessage) addEvent(function() messageBox:raise() messageBox:focus() end) - disconnect(g_game, { onProtocolVersionChange = load }) + disconnect(g_game, { onClientVersionChange = load }) + g_game.setClientVersion(0) g_game.setProtocolVersion(0) - connect(g_game, { onProtocolVersionChange = load }) + connect(g_game, { onClientVersionChange = load }) end end diff --git a/modules/gamelib/game.lua b/modules/gamelib/game.lua index eb0188f6..23083f41 100644 --- a/modules/gamelib/game.lua +++ b/modules/gamelib/game.lua @@ -66,21 +66,40 @@ function g_game.getSupportedClients() 1012, 1013, 1020, 1021, 1022, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, - 1040, 1041 + 1040, 1041, 1050, 1051 } end -function g_game.getProtocolVersionForClient(client) - clients = { +-- The client version and protocol version where +-- unsynchronized for some releases, not sure if this +-- will be the normal standard. + +-- Client Version: Publicly given version when +-- downloading Cipsoft client. + +-- Protocol Version: Previously was the same as +-- the client version, but was unsychronized in some +-- releases, now it needs to be verified and added here +-- if it does not match the client version. + +-- Reason for defining both: The server now requires a +-- Client version and Protocol version from the client. + +-- Important: Use getClientVersion for specific protocol +-- features to ensure we are using the proper version. + +function g_game.getClientProtocolVersion(client) + local clients = { [980] = 971, [981] = 973, [982] = 974, - [983] = 975, - [984] = 976, - [985] = 977, - [986] = 978, - [1001] = 979, - [1002] = 980, + [983] = 975, + [984] = 976, + [985] = 977, + [986] = 978, + [1001] = 979, + [1002] = 980, + [1051] = 1000 -- no idea what protocol version is required (1051 doesn't work) } return clients[client] or client end diff --git a/modules/gamelib/protocollogin.lua b/modules/gamelib/protocollogin.lua index 69bc12b4..1aa6665d 100644 --- a/modules/gamelib/protocollogin.lua +++ b/modules/gamelib/protocollogin.lua @@ -32,7 +32,7 @@ function ProtocolLogin:sendLoginPacket() msg:addU16(g_game.getProtocolVersion()) - if g_game.getProtocolVersion() >= 971 then + if g_game.getClientVersion() >= 980 then msg:addU32(g_game.getClientVersion()) end @@ -40,13 +40,13 @@ function ProtocolLogin:sendLoginPacket() msg:addU32(g_sprites.getSprSignature()) msg:addU32(PIC_SIGNATURE) - if g_game.getProtocolVersion() >= 971 then + if g_game.getClientVersion() >= 980 then msg:addU8(0) -- clientType end local offset = msg:getMessageSize() - if g_game.getProtocolVersion() >= 770 then + if g_game.getClientVersion() >= 770 then -- first RSA byte must be 0 msg:addU8(0) -- xtea key @@ -74,7 +74,7 @@ function ProtocolLogin:sendLoginPacket() local paddingBytes = g_crypt.rsaGetSize() - (msg:getMessageSize() - offset) assert(paddingBytes >= 0) msg:addPaddingBytes(paddingBytes, 0) - if g_game.getProtocolVersion() >= 770 then + if g_game.getClientVersion() >= 770 then msg:encryptRsa() end @@ -83,7 +83,7 @@ function ProtocolLogin:sendLoginPacket() end self:send(msg) - if g_game.getProtocolVersion() >= 770 then + if g_game.getClientVersion() >= 770 then self:enableXteaEncryption() end self:recv() @@ -131,7 +131,7 @@ end function ProtocolLogin:parseCharacterList(msg) local characters = {} - if g_game.getProtocolVersion() > 1010 then + if g_game.getClientVersion() > 1010 then local worlds = {} local worldsCount = msg:getU8() @@ -165,7 +165,7 @@ function ProtocolLogin:parseCharacterList(msg) character.worldIp = iptostring(msg:getU32()) character.worldPort = msg:getU16() - if g_game.getProtocolVersion() >= 971 then + if g_game.getClientVersion() >= 980 then character.unknown = msg:getU8() end diff --git a/src/client/const.h b/src/client/const.h index 7a5dcc1f..0e822725 100644 --- a/src/client/const.h +++ b/src/client/const.h @@ -389,6 +389,7 @@ namespace Otc GameSpritesAlphaChannel = 56, GamePremiumExpiration = 57, GameBrowseField = 58, + GameEnhancedAnimations = 59, LastGameFeature = 101 }; diff --git a/src/client/creature.cpp b/src/client/creature.cpp index 5b437722..cd6eac73 100644 --- a/src/client/creature.cpp +++ b/src/client/creature.cpp @@ -846,11 +846,11 @@ int Creature::getStepDuration(bool ignoreDiagonal, Otc::Direction dir) else interval /= speed; - if(g_game.getProtocolVersion() >= 900) + if(g_game.getClientVersion() >= 900) interval = (interval / g_game.getServerBeat()) * g_game.getServerBeat(); float factor = 3; - if(g_game.getProtocolVersion() <= 810) + if(g_game.getClientVersion() <= 810) factor = 2; interval = std::max(interval, g_game.getServerBeat()); diff --git a/src/client/game.cpp b/src/client/game.cpp index 87472043..20ce4aae 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1475,9 +1475,27 @@ void Game::setProtocolVersion(int version) if(isOnline()) stdext::throw_exception("Unable to change protocol version while online"); - if(version != 0 && (version < 740 || version > 1041)) + if(version != 0 && (version < 740 || version > 1051)) stdext::throw_exception(stdext::format("Protocol version %d not supported", version)); + m_protocolVersion = version; + + Proto::buildMessageModesMap(version); + + g_lua.callGlobalField("g_game", "onProtocolVersionChange", version); +} + +void Game::setClientVersion(int version) +{ + if(m_clientVersion == version) + return; + + if(isOnline()) + stdext::throw_exception("Unable to change client version while online"); + + if(version != 0 && (version < 740 || version > 1051)) + stdext::throw_exception(stdext::format("Client version %d not supported", version)); + m_features.reset(); enableFeature(Otc::GameFormatCreatureName); @@ -1585,28 +1603,14 @@ void Game::setProtocolVersion(int version) enableFeature(Otc::GameCreatureIcons); enableFeature(Otc::GameHideNpcNames); } - + if(version >= 1038) { enableFeature(Otc::GamePremiumExpiration); } - m_protocolVersion = version; - - Proto::buildMessageModesMap(version); - - g_lua.callGlobalField("g_game", "onProtocolVersionChange", version); -} - -void Game::setClientVersion(int version) -{ - if(m_clientVersion == version) - return; - - if(isOnline()) - stdext::throw_exception("Unable to change client version while online"); - - if(version != 0 && (version < 740 || version > 1041)) - stdext::throw_exception(stdext::format("Client version %d not supported", version)); + if(version >= 1050) { + enableFeature(Otc::GameEnhancedAnimations); + } m_clientVersion = version; diff --git a/src/client/item.cpp b/src/client/item.cpp index 566d872b..0e4695ed 100644 --- a/src/client/item.cpp +++ b/src/client/item.cpp @@ -241,7 +241,7 @@ int Item::getSubType() { if(isSplash() || isFluidContainer()) return m_countOrSubType; - if(g_game.getProtocolVersion() > 862) + if(g_game.getClientVersion() > 862) return 0; return 1; } diff --git a/src/client/itemtype.cpp b/src/client/itemtype.cpp index d0b9aaeb..30cbe5da 100644 --- a/src/client/itemtype.cpp +++ b/src/client/itemtype.cpp @@ -51,7 +51,7 @@ void ItemType::unserialize(const BinaryTreePtr& node) switch(attr) { case ItemTypeAttrServerId: { uint16 serverId = node->getU16(); - if(g_game.getProtocolVersion() < 960) { + if(g_game.getClientVersion() < 960) { if(serverId > 20000 && serverId < 20100) { serverId -= 20000; } else if(lastId > 99 && lastId != serverId - 1) { diff --git a/src/client/mapio.cpp b/src/client/mapio.cpp index ca6b34da..a1229679 100644 --- a/src/client/mapio.cpp +++ b/src/client/mapio.cpp @@ -491,7 +491,7 @@ void Map::saveOtcm(const std::string& fileName) // version 1 header fin->addString("OTCM 1.0"); // map description fin->addU32(g_things.getDatSignature()); - fin->addU16(g_game.getProtocolVersion()); + fin->addU16(g_game.getClientVersion()); fin->addString(g_game.getWorldName()); // go back and rewrite where the map data starts diff --git a/src/client/protocolgame.cpp b/src/client/protocolgame.cpp index 0e5fd61e..c9d194af 100644 --- a/src/client/protocolgame.cpp +++ b/src/client/protocolgame.cpp @@ -56,7 +56,7 @@ void ProtocolGame::onRecv(const InputMessagePtr& inputMessage) if(m_firstRecv) { m_firstRecv = false; - if(g_game.getProtocolVersion() >= 841) { // not sure since which version this is, but it seems to be after 8.40 + if(g_game.getClientVersion() >= 841) { // not sure since which version this is, but it seems to be after 8.40 int size = inputMessage->getU16(); if(size != inputMessage->getUnreadSize()) { g_logger.traceError("invalid message size"); diff --git a/src/client/protocolgameparse.cpp b/src/client/protocolgameparse.cpp index 51b99735..2ab2a9be 100644 --- a/src/client/protocolgameparse.cpp +++ b/src/client/protocolgameparse.cpp @@ -410,9 +410,9 @@ void ProtocolGame::parseGMActions(const InputMessagePtr& msg) int numViolationReasons; - if(g_game.getProtocolVersion() >= 850) + if(g_game.getClientVersion() >= 850) numViolationReasons = 20; - else if(g_game.getProtocolVersion() >= 840) + else if(g_game.getClientVersion() >= 840) numViolationReasons = 23; else numViolationReasons = 32; @@ -562,7 +562,7 @@ void ProtocolGame::parseTileAddThing(const InputMessagePtr& msg) Position pos = getPosition(msg); int stackPos = -1; - if(g_game.getProtocolVersion() >= 841) + if(g_game.getClientVersion() >= 841) stackPos = msg->getU8(); ThingPtr thing = getThing(msg); @@ -722,7 +722,7 @@ void ProtocolGame::parseOpenNpcTrade(const InputMessagePtr& msg) int listCount; - if(g_game.getProtocolVersion() >= 900) + if(g_game.getClientVersion() >= 900) listCount = msg->getU16(); else listCount = msg->getU8(); @@ -749,7 +749,7 @@ void ProtocolGame::parsePlayerGoods(const InputMessagePtr& msg) std::vector> goods; int money; - if(g_game.getProtocolVersion() >= 973) + if(g_game.getClientVersion() >= 973) money = msg->getU64(); else money = msg->getU32(); @@ -992,7 +992,7 @@ void ProtocolGame::parseEditText(const InputMessagePtr& msg) uint id = msg->getU32(); int itemId; - if(g_game.getProtocolVersion() >= 1010) { + if(g_game.getClientVersion() >= 1010) { // TODO: processEditText with ItemPtr as parameter ItemPtr item = getItem(msg); itemId = item->getId(); @@ -1640,7 +1640,7 @@ void ProtocolGame::parseModalDialog(const InputMessagePtr& msg) } int enterButton, escapeButton; - if(g_game.getProtocolVersion() > 970) { + if(g_game.getClientVersion() > 970) { escapeButton = msg->getU8(); enterButton = msg->getU8(); } @@ -1685,7 +1685,7 @@ void ProtocolGame::parseChangeMapAwareRange(const InputMessagePtr& msg) void ProtocolGame::parseCreaturesMark(const InputMessagePtr& msg) { int len; - if (g_game.getProtocolVersion() >= 1035) { + if (g_game.getClientVersion() >= 1035) { len = 1; } else { len = msg->getU8(); @@ -1895,7 +1895,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type) uint id = msg->getU32(); int creatureType; - if(g_game.getProtocolVersion() >= 910) + if(g_game.getClientVersion() >= 910) creatureType = msg->getU8(); else { if(id >= Proto::PlayerStartId && id < Proto::PlayerEndId) @@ -1973,7 +1973,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type) } } - if(g_game.getProtocolVersion() >= 854) + if(g_game.getClientVersion() >= 854) unpass = msg->getU8(); if(creature) { @@ -2004,7 +2004,7 @@ CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type) if(creature) creature->turn(direction); - if(g_game.getProtocolVersion() >= 953) { + if(g_game.getClientVersion() >= 953) { bool unpass = msg->getU8(); if(creature) diff --git a/src/client/protocolgamesend.cpp b/src/client/protocolgamesend.cpp index 15487b09..03c40602 100644 --- a/src/client/protocolgamesend.cpp +++ b/src/client/protocolgamesend.cpp @@ -65,7 +65,7 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando msg->addU8(0); // first RSA byte must be 0 - if(g_game.getProtocolVersion() >= 770) + if(g_game.getClientVersion() >= 770) { // xtea key generateXteaKey(); @@ -99,7 +99,7 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando msg->addPaddingBytes(paddingBytes); // encrypt with RSA - if(g_game.getProtocolVersion() >= 770) + if(g_game.getClientVersion() >= 770) msg->encryptRsa(); if(g_game.getFeature(Otc::GameProtocolChecksum)) @@ -107,7 +107,7 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando send(msg); - if(g_game.getProtocolVersion() >= 770) + if(g_game.getClientVersion() >= 770) enableXteaEncryption(); } @@ -642,7 +642,7 @@ void ProtocolGame::sendShareExperience(bool active) msg->addU8(Proto::ClientShareExperience); msg->addU8(active ? 0x01 : 0x00); - if(g_game.getProtocolVersion() < 910) + if(g_game.getClientVersion() < 910) msg->addU8(0); send(msg); diff --git a/src/client/thingtype.cpp b/src/client/thingtype.cpp index 236f38b9..7e5f5de3 100644 --- a/src/client/thingtype.cpp +++ b/src/client/thingtype.cpp @@ -53,12 +53,12 @@ void ThingType::serialize(const FileStreamPtr& fin) continue; int attr = i; - if(g_game.getProtocolVersion() >= 780) { + if(g_game.getClientVersion() >= 780) { if(attr == ThingAttrChargeable) attr = ThingAttrWritable; else if(attr >= ThingAttrWritable) attr += 1; - } else if(g_game.getProtocolVersion() >= 1010) { + } else if(g_game.getClientVersion() >= 1010) { if(attr == ThingAttrNoMoveAnimation) attr = 16; else if(attr >= ThingAttrPickupable) @@ -116,6 +116,19 @@ void ThingType::serialize(const FileStreamPtr& fin) fin->addU8(m_numPatternZ); fin->addU8(m_animationPhases); + if(g_game.getFeature(Otc::GameEnhancedAnimations)) { + if(m_animationPhases > 1) { + fin->addU8(m_animation.async ? 0 : 1); + fin->add32(m_animation.loopCount); + fin->addU8(m_animation.startIndex); + + for(std::tuple frame : m_animation.frames) { + fin->addU32(std::get<0>(frame)); + fin->addU32(std::get<1>(frame)); + } + } + } + for(uint i = 0; i < m_spritesIndex.size(); i++) { if(g_game.getFeature(Otc::GameSpritesU32)) fin->addU32(m_spritesIndex[i]); @@ -130,15 +143,17 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS m_id = clientId; m_category = category; + int count = 0, attr = -1; bool done = false; for(int i = 0 ; i < ThingLastAttr;++i) { - int attr = fin->getU8(); + count++; + attr = fin->getU8(); if(attr == ThingLastAttr) { done = true; break; } - if(g_game.getProtocolVersion() >= 1010) { + if(g_game.getClientVersion() >= 1010) { /* In 10.10+ all attributes from 16 and up were * incremented by 1 to make space for 16 as * "No Movement Animation" flag. @@ -147,12 +162,12 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS attr = ThingAttrNoMoveAnimation; else if(attr > 16) attr -= 1; - } else if(g_game.getProtocolVersion() >= 860) { + } else if(g_game.getClientVersion() >= 860) { /* Default attribute values follow * the format of 8.6-9.86. * Therefore no changes here. */ - } else if(g_game.getProtocolVersion() >= 780) { + } else if(g_game.getClientVersion() >= 780) { /* In 7.80-8.54 all attributes from 8 and higher were * incremented by 1 to make space for 8 as * "Item Charges" flag. @@ -162,11 +177,11 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS continue; } else if(attr > 8) attr -= 1; - } else if(g_game.getProtocolVersion() >= 755) { + } else if(g_game.getClientVersion() >= 755) { /* In 7.55-7.72 attributes 23 is "Floor Change". */ if(attr == 23) attr = ThingAttrFloorChange; - } else if(g_game.getProtocolVersion() >= 740) { + } else if(g_game.getClientVersion() >= 740) { /* In 7.4-7.5 attribute "Ground Border" did not exist * attributes 1-15 have to be adjusted. * Several other changes in the format. @@ -207,7 +222,7 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS switch(attr) { case ThingAttrDisplacement: { - if(g_game.getProtocolVersion() >= 755) { + if(g_game.getClientVersion() >= 755) { m_displacement.x = fin->getU16(); m_displacement.y = fin->getU16(); } else { @@ -256,7 +271,8 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS } if(!done) - stdext::throw_exception("corrupt data"); + 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(); @@ -271,12 +287,27 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS m_layers = fin->getU8(); m_numPatternX = fin->getU8(); m_numPatternY = fin->getU8(); - if(g_game.getProtocolVersion() >= 755) + if(g_game.getClientVersion() >= 755) m_numPatternZ = fin->getU8(); else m_numPatternZ = 1; m_animationPhases = 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(); + + 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 == 0) diff --git a/src/client/thingtype.h b/src/client/thingtype.h index 446c9230..e5e0120d 100644 --- a/src/client/thingtype.h +++ b/src/client/thingtype.h @@ -110,6 +110,15 @@ struct Light { uint8 color; }; +struct Animation { + Animation() { startIndex = 0; loopCount = 0; async = false; } + + int startIndex; + int loopCount; + bool async; + std::vector > frames; +}; + class ThingType : public LuaObject { public: @@ -138,6 +147,7 @@ public: int getNumPatternY() { return m_numPatternY; } int getNumPatternZ() { return m_numPatternZ; } int getAnimationPhases() { return m_animationPhases; } + Animation getAnimation() { return m_animation; } Point getDisplacement() { return m_displacement; } int getDisplacementX() { return getDisplacement().x; } int getDisplacementY() { return getDisplacement().y; } @@ -204,10 +214,11 @@ private: Size m_size; Point m_displacement; + Animation m_animation; + int m_animationPhases; int m_exactSize; int m_realSize; int m_numPatternX, m_numPatternY, m_numPatternZ; - int m_animationPhases; int m_layers; int m_elevation; float m_opacity; diff --git a/src/client/thingtypemanager.cpp b/src/client/thingtypemanager.cpp index b00aa0c2..eaec7e82 100644 --- a/src/client/thingtypemanager.cpp +++ b/src/client/thingtypemanager.cpp @@ -276,7 +276,7 @@ void ThingTypeManager::parseItemType(uint16 serverId, TiXmlElement* elem) bool s; int d; - if(g_game.getProtocolVersion() < 960) { + if(g_game.getClientVersion() < 960) { s = serverId > 20000 && serverId < 20100; d = 20000; } else { diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 6e4b8657..548a3335 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -217,7 +217,7 @@ void Tile::addThing(const ThingPtr& thing, int stackPos) append = (priority <= 3); // newer protocols does not store creatures in reverse order - if(g_game.getProtocolVersion() >= 854 && priority == 4) + if(g_game.getClientVersion() >= 854 && priority == 4) append = !append; } diff --git a/src/framework/core/binarytree.cpp b/src/framework/core/binarytree.cpp index 4568c851..14f7a3f0 100644 --- a/src/framework/core/binarytree.cpp +++ b/src/framework/core/binarytree.cpp @@ -132,7 +132,7 @@ uint16 BinaryTree::getU16() unserialize(); if(m_pos+2 > m_buffer.size()) stdext::throw_exception("BinaryTree: getU16 failed"); - uint16 v = stdext::readLE16(&m_buffer[m_pos]); + uint16 v = stdext::readULE16(&m_buffer[m_pos]); m_pos += 2; return v; } @@ -142,7 +142,7 @@ uint32 BinaryTree::getU32() unserialize(); if(m_pos+4 > m_buffer.size()) stdext::throw_exception("BinaryTree: getU32 failed"); - uint32 v = stdext::readLE32(&m_buffer[m_pos]); + uint32 v = stdext::readULE32(&m_buffer[m_pos]); m_pos += 4; return v; } @@ -152,7 +152,7 @@ uint64 BinaryTree::getU64() unserialize(); if(m_pos+8 > m_buffer.size()) stdext::throw_exception("BinaryTree: getU64 failed"); - uint64 v = stdext::readLE64(&m_buffer[m_pos]); + uint64 v = stdext::readULE64(&m_buffer[m_pos]); m_pos += 8; return v; } @@ -193,14 +193,14 @@ void OutputBinaryTree::addU8(uint8 v) void OutputBinaryTree::addU16(uint16 v) { uint8 data[2]; - stdext::writeLE16(data, v); + stdext::writeULE16(data, v); write(data, 2); } void OutputBinaryTree::addU32(uint32 v) { uint8 data[4]; - stdext::writeLE32(data, v); + stdext::writeULE32(data, v); write(data, 4); } diff --git a/src/framework/core/filestream.cpp b/src/framework/core/filestream.cpp index 0de984b1..fc721e92 100644 --- a/src/framework/core/filestream.cpp +++ b/src/framework/core/filestream.cpp @@ -206,7 +206,7 @@ uint16 FileStream::getU16() if(m_pos+2 > m_data.size()) throwError("read failed"); - v = stdext::readLE16(&m_data[m_pos]); + v = stdext::readULE16(&m_data[m_pos]); m_pos += 2; } return v; @@ -222,7 +222,7 @@ uint32 FileStream::getU32() if(m_pos+4 > m_data.size()) throwError("read failed"); - v = stdext::readLE32(&m_data[m_pos]); + v = stdext::readULE32(&m_data[m_pos]); m_pos += 4; } return v; @@ -237,7 +237,70 @@ uint64 FileStream::getU64() } else { if(m_pos+8 > m_data.size()) throwError("read failed"); - v = stdext::readLE64(&m_data[m_pos]); + v = stdext::readULE64(&m_data[m_pos]); + m_pos += 8; + } + return v; +} + +int8 FileStream::get8() +{ + int8 v = 0; + if(!m_caching) { + if(PHYSFS_read(m_fileHandle, &v, 1, 1) != 1) + throwError("read failed", true); + } else { + if(m_pos+1 > m_data.size()) + throwError("read failed"); + + v = m_data[m_pos]; + m_pos += 1; + } + return v; +} + +int16 FileStream::get16() +{ + int16 v = 0; + if(!m_caching) { + if(PHYSFS_readSLE16(m_fileHandle, &v) == 0) + throwError("read failed", true); + } else { + if(m_pos+2 > m_data.size()) + throwError("read failed"); + + v = stdext::readSLE16(&m_data[m_pos]); + m_pos += 2; + } + return v; +} + +int32 FileStream::get32() +{ + int32 v = 0; + if(!m_caching) { + if(PHYSFS_readSLE32(m_fileHandle, &v) == 0) + throwError("read failed", true); + } else { + if(m_pos+4 > m_data.size()) + throwError("read failed"); + + v = stdext::readSLE32(&m_data[m_pos]); + m_pos += 4; + } + return v; +} + +int64 FileStream::get64() +{ + int64 v = 0; + if(!m_caching) { + if(PHYSFS_readSLE64(m_fileHandle, (PHYSFS_sint64*)&v) == 0) + throwError("read failed", true); + } else { + if(m_pos+8 > m_data.size()) + throwError("read failed"); + v = stdext::readSLE64(&m_data[m_pos]); m_pos += 8; } return v; @@ -306,7 +369,7 @@ void FileStream::addU16(uint16 v) throwError("write failed", true); } else { m_data.grow(m_pos + 2); - stdext::writeLE16(&m_data[m_pos], v); + stdext::writeULE16(&m_data[m_pos], v); m_pos += 2; } } @@ -318,7 +381,7 @@ void FileStream::addU32(uint32 v) throwError("write failed", true); } else { m_data.grow(m_pos + 4); - stdext::writeLE32(&m_data[m_pos], v); + stdext::writeULE32(&m_data[m_pos], v); m_pos += 4; } } @@ -330,7 +393,54 @@ void FileStream::addU64(uint64 v) throwError("write failed", true); } else { m_data.grow(m_pos + 8); - stdext::writeLE64(&m_data[m_pos], v); + stdext::writeULE64(&m_data[m_pos], v); + m_pos += 8; + } +} + +void FileStream::add8(int8 v) +{ + if(!m_caching) { + if(PHYSFS_write(m_fileHandle, &v, 1, 1) != 1) + throwError("write failed", true); + } else { + m_data.add(v); + m_pos++; + } +} + +void FileStream::add16(int16 v) +{ + if(!m_caching) { + if(PHYSFS_writeSLE16(m_fileHandle, v) == 0) + throwError("write failed", true); + } else { + m_data.grow(m_pos + 2); + stdext::writeSLE16(&m_data[m_pos], v); + m_pos += 2; + } +} + +void FileStream::add32(int32 v) +{ + if(!m_caching) { + if(PHYSFS_writeSLE32(m_fileHandle, v) == 0) + throwError("write failed", true); + } else { + m_data.grow(m_pos + 4); + stdext::writeSLE32(&m_data[m_pos], v); + m_pos += 4; + } +} + +void FileStream::add64(int64 v) +{ + if(!m_caching) { + if(PHYSFS_writeSLE64(m_fileHandle, v) == 0) + throwError("write failed", true); + } else { + m_data.grow(m_pos + 8); + stdext::writeSLE64(&m_data[m_pos], v); m_pos += 8; } } diff --git a/src/framework/core/filestream.h b/src/framework/core/filestream.h index 69fe7b42..1b6c04d5 100644 --- a/src/framework/core/filestream.h +++ b/src/framework/core/filestream.h @@ -54,6 +54,10 @@ public: uint16 getU16(); uint32 getU32(); uint64 getU64(); + int8 get8(); + int16 get16(); + int32 get32(); + int64 get64(); std::string getString(); BinaryTreePtr getBinaryTree(); @@ -63,6 +67,10 @@ public: void addU16(uint16 v); void addU32(uint32 v); void addU64(uint64 v); + void add8(int8 v); + void add16(int16 v); + void add32(int32 v); + void add64(int64 v); void addString(const std::string& v); void addPos(uint16 x, uint16 y, uint8 z) { addU16(x); addU16(y); addU8(z); } void addPoint(const Point& p) { addU8(p.x); addU8(p.y); } diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index b7122fed..d9defa02 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -195,6 +195,7 @@ void Application::registerLuaFunctions() g_lua.bindSingletonFunction("g_resources", "getFileTime", &ResourceManager::getFileTime, &g_resources); g_lua.bindSingletonFunction("g_resources", "makeDir", &ResourceManager::makeDir, &g_resources); g_lua.bindSingletonFunction("g_resources", "deleteFile", &ResourceManager::deleteFile, &g_resources); + g_lua.bindSingletonFunction("g_resources", "resolvePath", &ResourceManager::resolvePath, &g_resources); // Config g_lua.registerClass(); diff --git a/src/framework/net/inputmessage.cpp b/src/framework/net/inputmessage.cpp index e0fddc79..9389eb87 100644 --- a/src/framework/net/inputmessage.cpp +++ b/src/framework/net/inputmessage.cpp @@ -56,7 +56,7 @@ uint8 InputMessage::getU8() uint16 InputMessage::getU16() { checkRead(2); - uint16 v = stdext::readLE16(m_buffer + m_readPos); + uint16 v = stdext::readULE16(m_buffer + m_readPos); m_readPos += 2; return v; } @@ -64,7 +64,7 @@ uint16 InputMessage::getU16() uint32 InputMessage::getU32() { checkRead(4); - uint32 v = stdext::readLE32(m_buffer + m_readPos); + uint32 v = stdext::readULE32(m_buffer + m_readPos); m_readPos += 4; return v; } @@ -72,7 +72,7 @@ uint32 InputMessage::getU32() uint64 InputMessage::getU64() { checkRead(8); - uint64 v = stdext::readLE64(m_buffer + m_readPos); + uint64 v = stdext::readULE64(m_buffer + m_readPos); m_readPos += 8; return v; } diff --git a/src/framework/net/outputmessage.cpp b/src/framework/net/outputmessage.cpp index 6c930378..dfcef8b9 100644 --- a/src/framework/net/outputmessage.cpp +++ b/src/framework/net/outputmessage.cpp @@ -46,7 +46,7 @@ void OutputMessage::addU8(uint8 value) void OutputMessage::addU16(uint16 value) { checkWrite(2); - stdext::writeLE16(m_buffer + m_writePos, value); + stdext::writeULE16(m_buffer + m_writePos, value); m_writePos += 2; m_messageSize += 2; } @@ -54,7 +54,7 @@ void OutputMessage::addU16(uint16 value) void OutputMessage::addU32(uint32 value) { checkWrite(4); - stdext::writeLE32(m_buffer + m_writePos, value); + stdext::writeULE32(m_buffer + m_writePos, value); m_writePos += 4; m_messageSize += 4; } @@ -62,7 +62,7 @@ void OutputMessage::addU32(uint32 value) void OutputMessage::addU64(uint64 value) { checkWrite(8); - stdext::writeLE64(m_buffer + m_writePos, value); + stdext::writeULE64(m_buffer + m_writePos, value); m_writePos += 8; m_messageSize += 8; } @@ -104,7 +104,7 @@ void OutputMessage::writeChecksum() uint32 checksum = stdext::adler32(m_buffer + m_headerPos, m_messageSize); assert(m_headerPos - 4 >= 0); m_headerPos -= 4; - stdext::writeLE32(m_buffer + m_headerPos, checksum); + stdext::writeULE32(m_buffer + m_headerPos, checksum); m_messageSize += 4; } @@ -112,7 +112,7 @@ void OutputMessage::writeMessageSize() { assert(m_headerPos - 2 >= 0); m_headerPos -= 2; - stdext::writeLE16(m_buffer + m_headerPos, m_messageSize); + stdext::writeULE16(m_buffer + m_headerPos, m_messageSize); m_messageSize += 2; } diff --git a/src/framework/platform/win32window.cpp b/src/framework/platform/win32window.cpp index 5e5deeee..5b73c589 100644 --- a/src/framework/platform/win32window.cpp +++ b/src/framework/platform/win32window.cpp @@ -798,7 +798,7 @@ int WIN32Window::internalLoadMouseCursor(const ImagePtr& image, const Point& hot std::vector xorMask(numbytes, 0); for(int i=0;igetPixelData() + i*4); + uint32 rgba = stdext::readULE32(image->getPixelData() + i*4); if(rgba == 0xffffffff) { //white HSB_BIT_SET(xorMask, i); } else if(rgba == 0x00000000) { //alpha diff --git a/src/framework/stdext/math.h b/src/framework/stdext/math.h index a48205d4..dbc14539 100644 --- a/src/framework/stdext/math.h +++ b/src/framework/stdext/math.h @@ -31,13 +31,21 @@ namespace stdext { inline bool is_power_of_two(size_t v) { return ((v != 0) && !(v & (v - 1))); } inline size_t to_power_of_two(size_t v) { if(v == 0) return 0; size_t r = 1; while(r < v && r != 0xffffffff) r <<= 1; return r; } -inline uint16_t readLE16(const uchar *addr) { return (uint16_t)addr[1] << 8 | addr[0]; } -inline uint32_t readLE32(const uchar *addr) { return (uint32_t)readLE16(addr + 2) << 16 | readLE16(addr); } -inline uint64_t readLE64(const uchar *addr) { return (uint64_t)readLE32(addr + 4) << 32 | readLE32(addr); } +inline uint16_t readULE16(const uchar *addr) { return (uint16_t)addr[1] << 8 | addr[0]; } +inline uint32_t readULE32(const uchar *addr) { return (uint32_t)readULE16(addr + 2) << 16 | readULE16(addr); } +inline uint64_t readULE64(const uchar *addr) { return (uint64_t)readULE32(addr + 4) << 32 | readULE32(addr); } -inline void writeLE16(uchar *addr, uint16_t value) { addr[1] = value >> 8; addr[0] = (uint8_t)value; } -inline void writeLE32(uchar *addr, uint32_t value) { writeLE16(addr + 2, value >> 16); writeLE16(addr, (uint16_t)value); } -inline void writeLE64(uchar *addr, uint64_t value) { writeLE32(addr + 4, value >> 32); writeLE32(addr, (uint32_t)value); } +inline void writeULE16(uchar *addr, uint16_t value) { addr[1] = value >> 8; addr[0] = (uint8_t)value; } +inline void writeULE32(uchar *addr, uint32_t value) { writeULE16(addr + 2, value >> 16); writeULE16(addr, (uint16_t)value); } +inline void writeULE64(uchar *addr, uint64_t value) { writeULE32(addr + 4, value >> 32); writeULE32(addr, (uint32_t)value); } + +inline int16_t readSLE16(const uchar *addr) { return (int16_t)addr[1] << 8 | addr[0]; } +inline int32_t readSLE32(const uchar *addr) { return (int32_t)readSLE16(addr + 2) << 16 | readSLE16(addr); } +inline int64_t readSLE64(const uchar *addr) { return (int64_t)readSLE32(addr + 4) << 32 | readSLE32(addr); } + +inline void writeSLE16(uchar *addr, int16_t value) { addr[1] = value >> 8; addr[0] = (int8_t)value; } +inline void writeSLE32(uchar *addr, int32_t value) { writeSLE16(addr + 2, value >> 16); writeSLE16(addr, (int16_t)value); } +inline void writeSLE64(uchar *addr, int64_t value) { writeSLE32(addr + 4, value >> 32); writeSLE32(addr, (int32_t)value); } uint32_t adler32(const uint8_t *buffer, size_t size); diff --git a/src/framework/util/crypt.cpp b/src/framework/util/crypt.cpp index ce3e0a82..5f9b426f 100644 --- a/src/framework/util/crypt.cpp +++ b/src/framework/util/crypt.cpp @@ -201,7 +201,7 @@ std::string Crypt::_encrypt(const std::string& decrypted_string, bool useMachine { std::string tmp = "0000" + decrypted_string; uint32 sum = stdext::adler32((const uint8*)decrypted_string.c_str(), decrypted_string.size()); - stdext::writeLE32((uint8*)&tmp[0], sum); + stdext::writeULE32((uint8*)&tmp[0], sum); std::string encrypted = base64Encode(xorCrypt(tmp, getCryptKey(useMachineUUID))); return encrypted; } @@ -211,7 +211,7 @@ std::string Crypt::_decrypt(const std::string& encrypted_string, bool useMachine std::string decoded = base64Decode(encrypted_string); std::string tmp = xorCrypt(base64Decode(encrypted_string), getCryptKey(useMachineUUID)); if(tmp.length() >= 4) { - uint32 readsum = stdext::readLE32((const uint8*)tmp.c_str()); + uint32 readsum = stdext::readULE32((const uint8*)tmp.c_str()); std::string decrypted_string = tmp.substr(4); uint32 sum = stdext::adler32((const uint8*)decrypted_string.c_str(), decrypted_string.size()); if(readsum == sum)