From 91973db94d335055d656f1daa1e346dbda09c3bf Mon Sep 17 00:00:00 2001 From: FinnHornhoover Date: Sat, 19 Sep 2026 03:53:49 +0300 Subject: [PATCH 1/5] use correct croc pot price for croc potted items --- src/Vendors.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Vendors.cpp b/src/Vendors.cpp index 042f98ee..2fea6b1d 100644 --- a/src/Vendors.cpp +++ b/src/Vendors.cpp @@ -315,11 +315,16 @@ static void vendorCombineItems(CNSocket* sock, CNPacketData* data) { sItemBase* itemStats = &plr->Inven[req->iStatItemSlot]; sItemBase* itemLooks = &plr->Inven[req->iCostumeItemSlot]; + + // if item is already combined, the style item id will be in the higher 16 bits of the iOpt + int16_t itemNonCombinedLooksID = (itemLooks->iOpt >> 16) > 0 ? (itemLooks->iOpt >> 16) : itemLooks->iID; + Items::Item* itemStatsDat = Items::getItemData(itemStats->iID, itemStats->iType); Items::Item* itemLooksDat = Items::getItemData(itemLooks->iID, itemLooks->iType); + Items::Item* itemNonCombinedLooksDat = Items::getItemData(itemNonCombinedLooksID, itemLooks->iType); // sanity check item and combination entry existence - if (itemStatsDat == nullptr || itemLooksDat == nullptr + if (itemStatsDat == nullptr || itemLooksDat == nullptr || itemNonCombinedLooksDat == nullptr || Items::CrocPotTable.find(abs(itemStatsDat->level - itemLooksDat->level)) == Items::CrocPotTable.end()) { std::cout << "[WARN] Either item ids or croc pot value set not found" << std::endl; sock->sendPacket(failResp, P_FE2CL_REP_PC_ITEM_COMBINATION_FAIL); @@ -335,7 +340,8 @@ static void vendorCombineItems(CNSocket* sock, CNPacketData* data) { } CrocPotEntry* recipe = &Items::CrocPotTable[abs(itemStatsDat->level - itemLooksDat->level)]; - int cost = itemStatsDat->buyPrice * recipe->multStats + itemLooksDat->buyPrice * recipe->multLooks; + // buy price of combined items is the uncombined style item's buy price + int cost = itemStatsDat->buyPrice * recipe->multStats + itemNonCombinedLooksDat->buyPrice * recipe->multLooks; float successChance = recipe->base / 100.0f; // base success chance // rarity gap multiplier @@ -360,14 +366,13 @@ static void vendorCombineItems(CNSocket* sock, CNPacketData* data) { //std::cout << rolled << " vs " << successChance << std::endl; plr->subtractCapped(CappedValueType::TAROS, cost); - INITSTRUCT(sP_FE2CL_REP_PC_ITEM_COMBINATION_SUCC, resp); if (rolled < successChance) { // success resp.iSuccessFlag = 1; // modify the looks item with the new stats and set the appearance through iOpt - itemLooks->iOpt = (int32_t)((itemLooks->iOpt) >> 16 > 0 ? (itemLooks->iOpt >> 16) : itemLooks->iID) << 16; + itemLooks->iOpt = (int32_t)((itemLooks->iOpt >> 16) > 0 ? (itemLooks->iOpt >> 16) : itemLooks->iID) << 16; itemLooks->iID = itemStats->iID; // delete stats item From 68d14d766daa870346336fe42b7421b97c4ba27e Mon Sep 17 00:00:00 2001 From: FinnHornhoover Date: Sun, 20 Sep 2026 02:09:30 +0300 Subject: [PATCH 2/5] do iopt calculation once --- src/Vendors.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Vendors.cpp b/src/Vendors.cpp index 2fea6b1d..521f961e 100644 --- a/src/Vendors.cpp +++ b/src/Vendors.cpp @@ -317,11 +317,11 @@ static void vendorCombineItems(CNSocket* sock, CNPacketData* data) { sItemBase* itemLooks = &plr->Inven[req->iCostumeItemSlot]; // if item is already combined, the style item id will be in the higher 16 bits of the iOpt - int16_t itemNonCombinedLooksID = (itemLooks->iOpt >> 16) > 0 ? (itemLooks->iOpt >> 16) : itemLooks->iID; + int16_t itemLooksNonCombinedID = (itemLooks->iOpt >> 16) > 0 ? (itemLooks->iOpt >> 16) : itemLooks->iID; Items::Item* itemStatsDat = Items::getItemData(itemStats->iID, itemStats->iType); Items::Item* itemLooksDat = Items::getItemData(itemLooks->iID, itemLooks->iType); - Items::Item* itemNonCombinedLooksDat = Items::getItemData(itemNonCombinedLooksID, itemLooks->iType); + Items::Item* itemNonCombinedLooksDat = Items::getItemData(itemLooksNonCombinedID, itemLooks->iType); // sanity check item and combination entry existence if (itemStatsDat == nullptr || itemLooksDat == nullptr || itemNonCombinedLooksDat == nullptr @@ -372,7 +372,7 @@ static void vendorCombineItems(CNSocket* sock, CNPacketData* data) { resp.iSuccessFlag = 1; // modify the looks item with the new stats and set the appearance through iOpt - itemLooks->iOpt = (int32_t)((itemLooks->iOpt >> 16) > 0 ? (itemLooks->iOpt >> 16) : itemLooks->iID) << 16; + itemLooks->iOpt = (int32_t)itemLooksNonCombinedID << 16; itemLooks->iID = itemStats->iID; // delete stats item From 6d080a86dcd8b0286941273f46f4beaf3b4bc9fe Mon Sep 17 00:00:00 2001 From: FinnHornhoover Date: Sun, 20 Sep 2026 02:50:03 +0300 Subject: [PATCH 3/5] slightly optimize code --- src/Vendors.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Vendors.cpp b/src/Vendors.cpp index 521f961e..024ecc54 100644 --- a/src/Vendors.cpp +++ b/src/Vendors.cpp @@ -321,12 +321,19 @@ static void vendorCombineItems(CNSocket* sock, CNPacketData* data) { Items::Item* itemStatsDat = Items::getItemData(itemStats->iID, itemStats->iType); Items::Item* itemLooksDat = Items::getItemData(itemLooks->iID, itemLooks->iType); - Items::Item* itemNonCombinedLooksDat = Items::getItemData(itemLooksNonCombinedID, itemLooks->iType); + Items::Item* itemLooksNonCombinedDat = (itemLooksNonCombinedID == itemLooks->iID) ? itemLooksDat : Items::getItemData(itemLooksNonCombinedID, itemLooks->iType); // sanity check item and combination entry existence - if (itemStatsDat == nullptr || itemLooksDat == nullptr || itemNonCombinedLooksDat == nullptr - || Items::CrocPotTable.find(abs(itemStatsDat->level - itemLooksDat->level)) == Items::CrocPotTable.end()) { - std::cout << "[WARN] Either item ids or croc pot value set not found" << std::endl; + if (itemStatsDat == nullptr || itemLooksDat == nullptr || itemLooksNonCombinedDat == nullptr) { + std::cout << "[WARN] Item ids not found for croc pot" << std::endl; + sock->sendPacket(failResp, P_FE2CL_REP_PC_ITEM_COMBINATION_FAIL); + return; + } + + int levelDiff = abs(itemStatsDat->level - itemLooksDat->level); + auto recipeIt = Items::CrocPotTable.find(levelDiff); + if (recipeIt == Items::CrocPotTable.end()) { + std::cout << "[WARN] Croc pot value set not found for level diff " << levelDiff << std::endl; sock->sendPacket(failResp, P_FE2CL_REP_PC_ITEM_COMBINATION_FAIL); return; } @@ -339,9 +346,9 @@ static void vendorCombineItems(CNSocket* sock, CNPacketData* data) { return; } - CrocPotEntry* recipe = &Items::CrocPotTable[abs(itemStatsDat->level - itemLooksDat->level)]; + CrocPotEntry* recipe = &recipeIt->second; // buy price of combined items is the uncombined style item's buy price - int cost = itemStatsDat->buyPrice * recipe->multStats + itemNonCombinedLooksDat->buyPrice * recipe->multLooks; + int cost = itemStatsDat->buyPrice * recipe->multStats + itemLooksNonCombinedDat->buyPrice * recipe->multLooks; float successChance = recipe->base / 100.0f; // base success chance // rarity gap multiplier From f7cd2bce2a8325d9091c4431e2ce44a7ef2bb12e Mon Sep 17 00:00:00 2001 From: FinnHornhoover Date: Sun, 20 Sep 2026 03:24:17 +0300 Subject: [PATCH 4/5] add academy lv0 escape for croc pot --- src/Vendors.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Vendors.cpp b/src/Vendors.cpp index 024ecc54..2c8be72f 100644 --- a/src/Vendors.cpp +++ b/src/Vendors.cpp @@ -369,6 +369,12 @@ static void vendorCombineItems(CNSocket* sock, CNPacketData* data) { break; } +#ifdef ACADEMY + // uncombined academy items in the style slot with level 0 have 100% success chance + if (itemLooksNonCombinedID == itemLooks->iID && itemLooksDat->level == 0) + successChance = 100.0f; +#endif + float rolled = Rand::randFloat(100.0f); // success chance out of 100 //std::cout << rolled << " vs " << successChance << std::endl; plr->subtractCapped(CappedValueType::TAROS, cost); From 67dc14eef2f92aa3f748ebd2bba3ed0b06af238c Mon Sep 17 00:00:00 2001 From: FinnHornhoover Date: Sun, 27 Sep 2026 22:42:35 +0300 Subject: [PATCH 5/5] fix racing gained fm meter --- src/Racing.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Racing.cpp b/src/Racing.cpp index d7ad9547..c5befd6f 100644 --- a/src/Racing.cpp +++ b/src/Racing.cpp @@ -163,13 +163,14 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) { resp.iEPScore = postRanking.Score; resp.iEPRaceTime = postRanking.Time; resp.iEPRaceMode = EPRaces[sock].mode; - resp.iEPRewardFM = fm; - int32_t fmReward = calculateFMReward(plr, resp.iEPRewardFM); + int32_t prevFM = plr->fusionmatter; + int32_t fmReward = calculateFMReward(plr, fm); plr->addCapped(CappedValueType::FUSIONMATTER, fmReward); Missions::updateFusionMatter(sock); resp.iFusionMatter = plr->fusionmatter; + resp.iEPRewardFM = std::max(0, plr->fusionmatter - prevFM); resp.iFatigue = 50; resp.iFatigue_Level = 1;