Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: parse packets for protocol 13.20 #683

Merged
merged 5 commits into from
Dec 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading