Support for client version 7.6
Tell me if there are parts which I should change. - Not everything is tested yet, feel free to report bugs in 7.6 - the data send in between login opcode and account data might not be correct, but I could not find any documents showing the right protocol yet - Hotkeys working
This commit is contained in:
parent
7cf645e715
commit
5843b78e87
|
@ -375,15 +375,41 @@ function doKeyCombo(keyCombo)
|
|||
modules.game_console.setTextEditText(hotKey.value)
|
||||
end
|
||||
elseif hotKey.useType == HOTKEY_MANAGER_USE then
|
||||
if g_game.getProtocolVersion() < 780 then
|
||||
local item = g_game.findItemInContainers(hotKey.itemId, -1)
|
||||
if item then
|
||||
g_game.use(item)
|
||||
end
|
||||
else
|
||||
g_game.useInventoryItem(hotKey.itemId)
|
||||
end
|
||||
elseif hotKey.useType == HOTKEY_MANAGER_USEONSELF then
|
||||
if g_game.getProtocolVersion() < 780 then
|
||||
local item = g_game.findItemInContainers(hotKey.itemId, -1)
|
||||
if item then
|
||||
g_game.useWith(item, g_game.getLocalPlayer())
|
||||
end
|
||||
else
|
||||
g_game.useInventoryItemWith(hotKey.itemId, g_game.getLocalPlayer())
|
||||
end
|
||||
elseif hotKey.useType == HOTKEY_MANAGER_USEONTARGET then
|
||||
local attackingCreature = g_game.getAttackingCreature()
|
||||
if not attackingCreature then return end
|
||||
if g_game.getProtocolVersion() < 780 then
|
||||
local item = g_game.findItemInContainers(hotKey.itemId, -1)
|
||||
if item then
|
||||
g_game.useWith(item, attackingCreature)
|
||||
end
|
||||
else
|
||||
g_game.useInventoryItemWith(hotKey.itemId, attackingCreature)
|
||||
end
|
||||
elseif hotKey.useType == HOTKEY_MANAGER_USEWITH then
|
||||
local item = Item.create(hotKey.itemId)
|
||||
if g_game.getProtocolVersion() < 780 then
|
||||
local tmpItem = g_game.findItemInContainers(hotKey.itemId, -1)
|
||||
if not tmpItem then return true end
|
||||
item = tmpItem
|
||||
end
|
||||
modules.game_interface.startUseWith(item)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,11 +34,11 @@ end
|
|||
|
||||
function g_game.getSupportedClients()
|
||||
return {
|
||||
810, 811, 840, 842, 850, 853, 854,
|
||||
860, 861, 862, 870, 910, 940, 944,
|
||||
953, 954, 960, 961, 963, 970, 980,
|
||||
981, 982, 983, 984, 985, 986, 1001,
|
||||
1002, 1010
|
||||
760, 810, 811, 840, 842, 850, 853,
|
||||
854, 860, 861, 862, 870, 910, 940,
|
||||
944, 953, 954, 960, 961, 963, 970,
|
||||
980, 981, 982, 983, 984, 985, 986,
|
||||
1001, 1002, 1010
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -188,5 +188,9 @@ ClientOpcodes = {
|
|||
ClientMarketCreate = 246, -- 944
|
||||
ClientMarketCancel = 247, -- 944
|
||||
ClientMarketAccept = 248, -- 944
|
||||
ClientAnswerModalDialog = 249 -- 960
|
||||
ClientAnswerModalDialog = 249, -- 960
|
||||
|
||||
-- 760
|
||||
ClientEnterAccount760 = 513,
|
||||
ClientEnterGame760 = 522
|
||||
}
|
||||
|
|
|
@ -27,9 +27,13 @@ end
|
|||
|
||||
function ProtocolLogin:sendLoginPacket()
|
||||
local msg = OutputMessage.create()
|
||||
|
||||
if g_game.getProtocolVersion() == 760 then
|
||||
msg:addU16(ClientOpcodes.ClientEnterAccount760)
|
||||
else
|
||||
msg:addU8(ClientOpcodes.ClientEnterAccount)
|
||||
msg:addU16(g_game.getOs())
|
||||
end
|
||||
|
||||
msg:addU16(g_game.getProtocolVersion())
|
||||
|
||||
if g_game.getProtocolVersion() >= 971 then
|
||||
|
@ -49,6 +53,7 @@ function ProtocolLogin:sendLoginPacket()
|
|||
-- first RSA byte must be 0
|
||||
msg:addU8(0)
|
||||
|
||||
if g_game.getProtocolVersion() >= 800 then
|
||||
-- xtea key
|
||||
self:generateXteaKey()
|
||||
local xteaKey = self:getXteaKey()
|
||||
|
@ -56,6 +61,7 @@ function ProtocolLogin:sendLoginPacket()
|
|||
msg:addU32(xteaKey[2])
|
||||
msg:addU32(xteaKey[3])
|
||||
msg:addU32(xteaKey[4])
|
||||
end
|
||||
|
||||
if g_game.getFeature(GameAccountNames) then
|
||||
msg:addString(self.accountName)
|
||||
|
@ -73,14 +79,18 @@ function ProtocolLogin:sendLoginPacket()
|
|||
local paddingBytes = g_crypt.rsaGetSize() - (msg:getMessageSize() - offset)
|
||||
assert(paddingBytes >= 0)
|
||||
msg:addPaddingBytes(paddingBytes, 0)
|
||||
if g_game.getProtocolVersion() >= 800 then
|
||||
msg:encryptRsa()
|
||||
end
|
||||
|
||||
if g_game.getFeature(GameProtocolChecksum) then
|
||||
self:enableChecksum()
|
||||
end
|
||||
|
||||
self:send(msg)
|
||||
if g_game.getProtocolVersion() >= 800 then
|
||||
self:enableXteaEncryption()
|
||||
end
|
||||
self:recv()
|
||||
end
|
||||
|
||||
|
|
|
@ -355,6 +355,15 @@ namespace Otc
|
|||
GameDoubleShopSellAmount = 39,
|
||||
GameContainerPagination = 40,
|
||||
GameThingMarks = 41,
|
||||
|
||||
GameLooktypeU16 = 42,
|
||||
GamePlayerStamina = 43,
|
||||
GamePlayerAddons = 44,
|
||||
GameMessageStatments = 45,
|
||||
GameMessageLevel = 46,
|
||||
GameNewFluids = 47,
|
||||
GamePlayerStateU16 = 48,
|
||||
|
||||
// 51-100 reserved to be defined in lua
|
||||
LastGameFeature = 101
|
||||
};
|
||||
|
|
|
@ -59,6 +59,14 @@ void Container::onAddItem(const ItemPtr& item)
|
|||
callLuaField("onAddItem", 0, item);
|
||||
}
|
||||
|
||||
ItemPtr Container::findItemById(uint itemId, int subType)
|
||||
{
|
||||
for(const ItemPtr item : m_items)
|
||||
if(item->getId() == itemId && (subType == -1 || item->getSubType() == subType))
|
||||
return item;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Container::onAddItems(const std::vector<ItemPtr>& items)
|
||||
{
|
||||
for(const ItemPtr& item : items)
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
std::string getName() { return m_name; }
|
||||
bool hasParent() { return m_hasParent; }
|
||||
bool isClosed() { return m_closed; }
|
||||
ItemPtr findItemById(uint itemId, int subType);
|
||||
|
||||
protected:
|
||||
void onOpen(const ContainerPtr& previousContainer);
|
||||
|
|
|
@ -884,7 +884,7 @@ void Game::useWith(const ItemPtr& item, const ThingPtr& toThing)
|
|||
if(!pos.isValid()) // virtual item
|
||||
pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
|
||||
|
||||
if(toThing->isCreature())
|
||||
if(toThing->isCreature() && g_game.getProtocolVersion() >= 780)
|
||||
m_protocolGame->sendUseOnCreature(pos, item->getId(), item->getStackPos(), toThing->getId());
|
||||
else
|
||||
m_protocolGame->sendUseItemWith(pos, item->getId(), item->getStackPos(), toThing->getPosition(), toThing->getId(), toThing->getStackPos());
|
||||
|
@ -903,6 +903,20 @@ void Game::useInventoryItemWith(int itemId, const ThingPtr& toThing)
|
|||
m_protocolGame->sendUseItemWith(pos, itemId, 0, toThing->getPosition(), toThing->getId(), toThing->getStackPos());
|
||||
}
|
||||
|
||||
ItemPtr Game::findItemInContainers(uint itemId, int subType)
|
||||
{
|
||||
for(auto& it : m_containers) {
|
||||
const ContainerPtr& container = it.second;
|
||||
|
||||
if(container) {
|
||||
ItemPtr item = container->findItemById(itemId, subType);
|
||||
if(item != nullptr)
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int Game::open(const ItemPtr& item, const ContainerPtr& previousContainer)
|
||||
{
|
||||
if(!canPerformGameAction() || !item)
|
||||
|
@ -1400,19 +1414,31 @@ void Game::setProtocolVersion(int version)
|
|||
if(isOnline())
|
||||
stdext::throw_exception("Unable to change protocol version while online");
|
||||
|
||||
if(version != 0 && (version < 810 || version > 1010))
|
||||
if(version != 0 && version != 760 && (version < 810 || version > 1010))
|
||||
stdext::throw_exception(stdext::format("Protocol version %d not supported", version));
|
||||
|
||||
m_features.reset();
|
||||
enableFeature(Otc::GameFormatCreatureName);
|
||||
|
||||
|
||||
if(version >= 780)
|
||||
{
|
||||
enableFeature(Otc::GamePlayerAddons);
|
||||
enableFeature(Otc::GamePlayerStamina);
|
||||
enableFeature(Otc::GameNewFluids);
|
||||
enableFeature(Otc::GameMessageLevel);
|
||||
enableFeature(Otc::GameMessageStatments);
|
||||
enableFeature(Otc::GamePlayerStateU16);
|
||||
enableFeature(Otc::GameLooktypeU16);
|
||||
}
|
||||
|
||||
if(version >= 840) {
|
||||
enableFeature(Otc::GameProtocolChecksum);
|
||||
enableFeature(Otc::GameChallengeOnLogin);
|
||||
enableFeature(Otc::GameAccountNames);
|
||||
}
|
||||
|
||||
if(version <= 854) {
|
||||
if(version >= 780 && version <= 854) { // 780 might not be accurate
|
||||
enableFeature(Otc::GameChargeableItems);
|
||||
}
|
||||
|
||||
|
@ -1487,7 +1513,7 @@ void Game::setClientVersion(int version)
|
|||
if(isOnline())
|
||||
stdext::throw_exception("Unable to change client version while online");
|
||||
|
||||
if(version != 0 && (version < 810 || version > 1010))
|
||||
if(version != 0 && version != 760 && (version < 810 || version > 1010))
|
||||
stdext::throw_exception(stdext::format("Client version %d not supported", version));
|
||||
|
||||
m_clientVersion = version;
|
||||
|
|
|
@ -158,6 +158,7 @@ public:
|
|||
void useWith(const ItemPtr& fromThing, const ThingPtr& toThing);
|
||||
void useInventoryItem(int itemId);
|
||||
void useInventoryItemWith(int itemId, const ThingPtr& toThing);
|
||||
ItemPtr findItemInContainers(uint itemId, int subType);
|
||||
|
||||
// container related
|
||||
int open(const ItemPtr& item, const ContainerPtr& previousContainer);
|
||||
|
|
|
@ -288,6 +288,7 @@ void Item::calculatePatterns(int& xPattern, int& yPattern, int& zPattern)
|
|||
}
|
||||
} else if(isSplash() || isFluidContainer()) {
|
||||
int color = Otc::FluidTransparent;
|
||||
if(g_game.getFeature(Otc::GameNewFluids)) {
|
||||
switch(m_countOrSubType) {
|
||||
case Otc::FluidNone:
|
||||
color = Otc::FluidTransparent;
|
||||
|
@ -347,6 +348,8 @@ void Item::calculatePatterns(int& xPattern, int& yPattern, int& zPattern)
|
|||
color = Otc::FluidTransparent;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
color = m_countOrSubType;
|
||||
|
||||
xPattern = (color % 4) % getNumPatternX();
|
||||
yPattern = (color / 4) % getNumPatternY();
|
||||
|
|
|
@ -184,6 +184,7 @@ void Client::registerLuaFunctions()
|
|||
g_lua.bindSingletonFunction("g_game", "useWith", &Game::useWith, &g_game);
|
||||
g_lua.bindSingletonFunction("g_game", "useInventoryItem", &Game::useInventoryItem, &g_game);
|
||||
g_lua.bindSingletonFunction("g_game", "useInventoryItemWith", &Game::useInventoryItemWith, &g_game);
|
||||
g_lua.bindSingletonFunction("g_game", "findItemInContainers", &Game::findItemInContainers, &g_game);
|
||||
g_lua.bindSingletonFunction("g_game", "open", &Game::open, &g_game);
|
||||
g_lua.bindSingletonFunction("g_game", "openParent", &Game::openParent, &g_game);
|
||||
g_lua.bindSingletonFunction("g_game", "close", &Game::close, &g_game);
|
||||
|
|
|
@ -87,7 +87,7 @@ void buildMessageModesMap(int version) {
|
|||
messageModesMap[Otc::MessageLook] = 25;
|
||||
messageModesMap[Otc::MessageFailure] = 26;
|
||||
messageModesMap[Otc::MessageBlue] = 27;
|
||||
} else if(version >= 810) {
|
||||
} else if(version >= 760) {
|
||||
messageModesMap[Otc::MessageNone] = 0;
|
||||
messageModesMap[Otc::MessageSay] = 1;
|
||||
messageModesMap[Otc::MessageWhisper] = 2;
|
||||
|
|
|
@ -1038,7 +1038,9 @@ void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
|
|||
|
||||
double magicLevelPercent = msg->getU8();
|
||||
double soul = msg->getU8();
|
||||
double stamina = msg->getU16();
|
||||
double stamina = 0;
|
||||
if(g_game.getFeature(Otc::GamePlayerStamina))
|
||||
stamina = msg->getU16();
|
||||
|
||||
double baseSpeed = 0;
|
||||
if(g_game.getFeature(Otc::GameSkillsBase))
|
||||
|
@ -1092,7 +1094,12 @@ void ProtocolGame::parsePlayerSkills(const InputMessagePtr& msg)
|
|||
|
||||
void ProtocolGame::parsePlayerState(const InputMessagePtr& msg)
|
||||
{
|
||||
int states = msg->getU16();
|
||||
int states;
|
||||
if(g_game.getFeature(Otc::GamePlayerStateU16))
|
||||
states = msg->getU16();
|
||||
else
|
||||
states = msg->getU8();
|
||||
|
||||
m_localPlayer->setStates(states);
|
||||
}
|
||||
|
||||
|
@ -1130,10 +1137,15 @@ void ProtocolGame::parseMultiUseCooldown(const InputMessagePtr& msg)
|
|||
|
||||
void ProtocolGame::parseTalk(const InputMessagePtr& msg)
|
||||
{
|
||||
if(g_game.getFeature(Otc::GameMessageStatments))
|
||||
msg->getU32(); // channel statement guid
|
||||
|
||||
std::string name = g_game.formatCreatureName(msg->getString());
|
||||
int level = msg->getU16();
|
||||
|
||||
int level = 0;
|
||||
if(g_game.getFeature(Otc::GameMessageLevel))
|
||||
level = msg->getU16();
|
||||
|
||||
Otc::MessageMode mode = Proto::translateMessageModeFromServer(msg->getU8());
|
||||
int channelId = 0;
|
||||
Position pos;
|
||||
|
@ -1380,8 +1392,15 @@ void ProtocolGame::parseFloorChangeDown(const InputMessagePtr& msg)
|
|||
void ProtocolGame::parseOpenOutfitWindow(const InputMessagePtr& msg)
|
||||
{
|
||||
Outfit currentOutfit = getOutfit(msg);
|
||||
|
||||
std::vector<std::tuple<int, std::string, int> > outfitList;
|
||||
|
||||
if(g_game.getProtocolVersion() < 780) {
|
||||
int outfitStart = msg->getU8();
|
||||
int outfitEnd = msg->getU8();
|
||||
for(int i = outfitStart; i <= outfitEnd; i++)
|
||||
outfitList.push_back(std::make_tuple(i, "", 0));
|
||||
}
|
||||
else {
|
||||
int outfitCount = msg->getU8();
|
||||
for(int i = 0; i < outfitCount; i++) {
|
||||
int outfitId = msg->getU16();
|
||||
|
@ -1390,6 +1409,7 @@ void ProtocolGame::parseOpenOutfitWindow(const InputMessagePtr& msg)
|
|||
|
||||
outfitList.push_back(std::make_tuple(outfitId, outfitName, outfitAddons));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::tuple<int, std::string> > mountList;
|
||||
if(g_game.getFeature(Otc::GamePlayerMounts)) {
|
||||
|
@ -1665,14 +1685,21 @@ Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg)
|
|||
{
|
||||
Outfit outfit;
|
||||
|
||||
int lookType = msg->getU16();
|
||||
int lookType;
|
||||
if(g_game.getFeature(Otc::GameLooktypeU16))
|
||||
lookType = msg->getU16();
|
||||
else
|
||||
lookType = msg->getU8();
|
||||
|
||||
if(lookType != 0) {
|
||||
outfit.setCategory(ThingCategoryCreature);
|
||||
int head = msg->getU8();
|
||||
int body = msg->getU8();
|
||||
int legs = msg->getU8();
|
||||
int feet = msg->getU8();
|
||||
int addons = msg->getU8();
|
||||
int addons = 0;
|
||||
if(g_game.getFeature(Otc::GamePlayerAddons))
|
||||
addons = msg->getU8();
|
||||
|
||||
if(!g_things.isValidDatId(lookType, ThingCategoryCreature)) {
|
||||
g_logger.traceError(stdext::format("invalid outfit looktype %d", lookType));
|
||||
|
|
|
@ -52,8 +52,16 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
|
|||
{
|
||||
OutputMessagePtr msg(new OutputMessage);
|
||||
|
||||
if(g_game.getProtocolVersion() == 760)
|
||||
{
|
||||
msg->addU16(0x20A);
|
||||
msg->addU8(g_game.getOs());
|
||||
}
|
||||
else
|
||||
{
|
||||
msg->addU8(Proto::ClientPendingGame);
|
||||
msg->addU16(g_game.getOs());
|
||||
}
|
||||
msg->addU16(g_game.getProtocolVersion());
|
||||
|
||||
if(g_game.getProtocolVersion() >= 971) {
|
||||
|
@ -65,6 +73,8 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
|
|||
|
||||
msg->addU8(0); // first RSA byte must be 0
|
||||
|
||||
if(g_game.getProtocolVersion() >= 800)
|
||||
{
|
||||
// xtea key
|
||||
generateXteaKey();
|
||||
msg->addU32(m_xteaKey[0]);
|
||||
|
@ -72,6 +82,7 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
|
|||
msg->addU32(m_xteaKey[2]);
|
||||
msg->addU32(m_xteaKey[3]);
|
||||
msg->addU8(0); // is gm set?
|
||||
}
|
||||
|
||||
if(g_game.getFeature(Otc::GameAccountNames))
|
||||
msg->addString(m_accountName);
|
||||
|
@ -96,6 +107,7 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
|
|||
msg->addPaddingBytes(paddingBytes);
|
||||
|
||||
// encrypt with RSA
|
||||
if(g_game.getProtocolVersion() >= 800)
|
||||
msg->encryptRsa();
|
||||
|
||||
if(g_game.getFeature(Otc::GameProtocolChecksum))
|
||||
|
@ -103,6 +115,7 @@ void ProtocolGame::sendLoginPacket(uint challengeTimestamp, uint8 challengeRando
|
|||
|
||||
send(msg);
|
||||
|
||||
if(g_game.getProtocolVersion() >= 800)
|
||||
enableXteaEncryption();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue