Skip to content

Commit

Permalink
fix: parse packets for protocol 13.20 (#683)
Browse files Browse the repository at this point in the history
* handle imbu cd panel

* support for meta item colors in loot messages

* more flexible daily reward code

* fix container flags code

* fix typo
  • Loading branch information
Zbizu authored Dec 24, 2023
1 parent bb20da7 commit 01da41c
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 52 deletions.
1 change: 1 addition & 0 deletions src/client/protocolcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ namespace Proto
GameServerFloorDescription = 75,

// original tibia ONLY
GameServerImbuementDurations = 93,
GameServerPassiveCooldown = 94,
GameServerBosstiaryData = 97,
GameServerBosstiarySlots = 98,
Expand Down
1 change: 1 addition & 0 deletions src/client/protocolgame.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ class ProtocolGame : public Protocol
void parseSupplyStash(const InputMessagePtr& msg);
void parseSpecialContainer(const InputMessagePtr& msg);
void parsePartyAnalyzer(const InputMessagePtr& msg);
void parseImbuementDurations(const InputMessagePtr& msg);
void parsePassiveCooldown(const InputMessagePtr& msg);
void parseClientCheck(const InputMessagePtr& msg);
void parseGameNews(const InputMessagePtr& msg);
Expand Down
147 changes: 95 additions & 52 deletions src/client/protocolgameparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,9 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
case Proto::GameServerSendShowDescription:
parseShowDescription(msg);
break;
case Proto::GameServerImbuementDurations:
parseImbuementDurations(msg);
break;
case Proto::GameServerPassiveCooldown:
parsePassiveCooldown(msg);
break;
Expand Down Expand Up @@ -2929,29 +2932,27 @@ ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)

if (item->isContainer()) {
if (g_game.getFeature(Otc::GameContainerTypes)) {
const uint8_t type = msg->getU8();
switch (type) {
case 0: // Empty
break;
case 1: {
if (g_game.getFeature(Otc::GameThingQuickLoot)) {
msg->getU32(); // quick loot flags
}
break;
}
case 2: {
if (g_game.getFeature(Otc::GameThingQuiver)) {
msg->getU32(); // ammoTotal
}
break;
}
case 4: // Empty (Loot highlight boolean)
break;
default: {
throw Exception("unknown container type %d", type);
break;
}
// container flags
// 1: quick loot, 2: quiver, 4: unlooted corpse
const uint8_t containerFlags = msg->getU8();

// quick loot categories
if ((containerFlags & 1) != 0) {
msg->getU32();
}

// quiver ammo count
if ((containerFlags & 2) != 0) {
msg->getU32();
}

// corpse not looted yet
/*
if ((containerFlags & 4) != 0) {
// this flag has no bytes to parse
// draw effect 252 on top of the tile
}
*/
} else {
if (g_game.getFeature(Otc::GameThingQuickLoot)) {
const bool hasQuickLootFlags = msg->getU8() != 0;
Expand Down Expand Up @@ -3201,6 +3202,28 @@ void ProtocolGame::parsePartyAnalyzer(const InputMessagePtr& msg)
}
}

void ProtocolGame::parseImbuementDurations(const InputMessagePtr& msg)
{
uint8_t itemListSize = msg->getU8(); // amount of items to display

for (uint8_t itemIndex = 0; itemIndex < itemListSize; ++itemIndex) {
msg->getU8(); // item slot id
getItem(msg); // imbued item
uint8_t imbuingSlotCount = msg->getU8(); // total amount of imbuing slots on item

for (uint8_t imbuIndex = 0; imbuIndex < imbuingSlotCount; ++imbuIndex) {
bool slotImbued = msg->getU8(); // 0 - empty, 1 - imbued

if (slotImbued) {
msg->getString(); // imbuement name
msg->getU16(); // imbuement icon id
msg->getU32(); // imbuement duration (NOTE: this is a SIGNED 32-bit variable)
msg->getU8(); // decaystate: 0 - paused, 1 - decaying
}
}
}
}

void ProtocolGame::parsePassiveCooldown(const InputMessagePtr& msg)
{
msg->getU8(); // Passive id
Expand Down Expand Up @@ -3289,10 +3312,10 @@ void ProtocolGame::parseItemsPrice(const InputMessagePtr& msg)
const uint16_t itemId = msg->getU16(); // item client id
if (g_game.getClientVersion() >= 1281) {
const auto& item = Item::create(itemId);
if (item->getId() == 0)
throw Exception("unable to create item with invalid id %d", itemId);

if (item->getClassification() > 0) {
// note: vanilla client allows made-up client ids
// their classification is assumed as 0
if (item->getId() != 0 && item->getClassification() > 0) {
msg->getU8();
}
msg->getU64(); // price
Expand Down Expand Up @@ -3355,37 +3378,57 @@ void ProtocolGame::parseOpenRewardWall(const InputMessagePtr& msg)
// TODO: implement open reward wall usage
}

void ProtocolGame::parseDailyReward(const InputMessagePtr& msg)
{
const uint8_t days = msg->getU8(); // Reward count (7 days)
for (uint8_t day = 1; day <= days; day++) {
// Free account
msg->getU8(); // type
msg->getU8(); // Items to pick
uint8_t size = msg->getU8();
if (day == 1 || day == 2 || day == 4 || day == 6) {
for (uint8_t i = 0; i < size; i++) {
msg->getU16(); // Item ID
msg->getString(); // Item name
msg->getU32(); // Item weight
}
} else {
msg->getU16(); // Amount
}
namespace {
void parseRewardDay(const InputMessagePtr& msg) {
uint8_t redeemMode = msg->getU8(); // reward type
if (redeemMode == 1) {
// select x items from the list
msg->getU8(); // items to select

// Premium account
msg->getU8(); // type
msg->getU8(); // Items to pick
size = msg->getU8();
if (day == 1 || day == 2 || day == 4 || day == 6) {
for (uint8_t i = 0; i < size; i++) {
uint8_t itemListSize = msg->getU8();
for (uint8_t listIndex = 0; listIndex < itemListSize; ++listIndex) {
msg->getU16(); // Item ID
msg->getString(); // Item name
msg->getU32(); // Item weight
}
} else {
msg->getU16(); // Amount
}
} else if (redeemMode == 2) {
// no choice, click to redeem all

uint8_t itemListSize = msg->getU8();
for (uint8_t listIndex = 0; listIndex < itemListSize; ++listIndex) {
uint8_t bundleType = msg->getU8(); // type of reward
switch (bundleType) {
case 1: {
// Items
msg->getU16(); // Item ID
msg->getString(); // Item name
msg->getU8(); // Item Count
break;
}
case 2: {
// Prey Wildcards
msg->getU8(); // Prey Wildcards Count
break;
}
case 3: {
// XP Boost
msg->getU16(); // XP Boost Minutes
break;
}
default:
// Invalid type
break;
}
}
}
}
}
void ProtocolGame::parseDailyReward(const InputMessagePtr& msg)
{
const uint8_t days = msg->getU8(); // Reward count (7 days)
for (uint8_t day = 1; day <= days; day++) {
parseRewardDay(msg); // Free account
parseRewardDay(msg); // Premium account
}

const uint8_t bonus = msg->getU8();
Expand All @@ -3394,7 +3437,7 @@ void ProtocolGame::parseDailyReward(const InputMessagePtr& msg)
msg->getU8(); // Bonus ID
}

msg->getU8(); // Unknown
msg->getU8(); // max unlockable "dragons" for free accounts
// TODO: implement daily reward usage
}

Expand Down

0 comments on commit 01da41c

Please sign in to comment.