@@ -36,6 +36,16 @@ std::map<int32_t, ItemSet> Items::ItemSets;
3636// 1 week
3737#define NANOCOM_BOOSTER_DURATION 604800
3838
39+ // known general item ids
40+ #define GENERALITEM_GUMBALL_ADAPTIUM 119
41+ #define GENERALITEM_GUMBALL_BLASTONS 120
42+ #define GENERALITEM_GUMBALL_COSMIX 121
43+
44+ #define GENERALITEM_FUSION_HUNTER_BOOSTER 153
45+ #define GENERALITEM_IZ_RACER_BOOSTER 154
46+ #define GENERALITEM_QUESTER_BOOSTER 155
47+ #define GENERALITEM_SUPER_BOOSTER_DX 156
48+
3949#ifdef ACADEMY
4050std::map<int32_t , int32_t > Items::NanoCapsules; // crate id -> nano id
4151
@@ -325,14 +335,14 @@ static void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
325335
326336 // if equipping an item, validate that it's of the correct type for the slot
327337 if ((SlotType)itemmove->eTo == SlotType::EQUIP) {
328- if (fromItem->iType == 10 && itemmove->iToSlotNum != 8 )
338+ if (fromItem->iType == 10 && itemmove->iToSlotNum != AEQUIP_VEHICLE_IDX )
329339 return ; // vehicle in wrong slot
330340 else if (fromItem->iType != 10
331341 && !(fromItem->iType == 0 && itemmove->iToSlotNum == 7 )
332342 && fromItem->iType != itemmove->iToSlotNum )
333343 return ; // something other than a vehicle or a weapon in a non-matching slot
334- else if (itemmove->iToSlotNum > 8 )
335- return ; // any slot higher than 8 is for a booster, and they can't be equipped via move packet
344+ else if (itemmove->iToSlotNum >= AEQUIP_COUNT_MINUS_BOOSTERS )
345+ return ; // boosters can't be equipped via move packet
336346 }
337347
338348 // save items to response
@@ -389,7 +399,7 @@ static void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
389399 }
390400
391401 // unequip vehicle if equip slot 8 is 0
392- if (plr->Equip [8 ].iID == 0 && plr->iPCState & 8 ) {
402+ if (plr->Equip [AEQUIP_VEHICLE_IDX ].iID == 0 && plr->iPCState & 8 ) {
393403 INITSTRUCT (sP_FE2CL_PC_VEHICLE_OFF_SUCC , response);
394404 sock->sendPacket (response, P_FE2CL_PC_VEHICLE_OFF_SUCC);
395405
@@ -443,9 +453,9 @@ static void useGumball(CNSocket* sock, CNPacketData* data) {
443453
444454 // sanity check, check if gumball type matches nano style
445455 int nanoStyle = Nanos::nanoStyle (nano.iID );
446- if (!((gumball.iID == 119 && nanoStyle == 0 ) ||
447- ( gumball.iID == 120 && nanoStyle == 1 ) ||
448- ( gumball.iID == 121 && nanoStyle == 2 ))) {
456+ if (!((gumball.iID == GENERALITEM_GUMBALL_ADAPTIUM && nanoStyle == 0 ) ||
457+ ( gumball.iID == GENERALITEM_GUMBALL_BLASTONS && nanoStyle == 1 ) ||
458+ ( gumball.iID == GENERALITEM_GUMBALL_COSMIX && nanoStyle == 2 ))) {
449459 std::cout << " [WARN] Gumball type doesn't match nano type" << std::endl;
450460 INITSTRUCT (sP_FE2CL_REP_PC_ITEM_USE_FAIL , response);
451461 sock->sendPacket (response, P_FE2CL_REP_PC_ITEM_USE_FAIL);
@@ -507,7 +517,7 @@ static void useGumball(CNSocket* sock, CNPacketData* data) {
507517static void useNanocomBooster (CNSocket* sock, CNPacketData* data) {
508518 // Guard against using nanocom boosters in before and including 0104
509519 // either path should be optimized by the compiler, effectively a no-op
510- if (AEQUIP_COUNT < 12 ) {
520+ if (AEQUIP_COUNT < AEQUIP_COUNT_WITH_BOOSTERS ) {
511521 std::cout << " [WARN] Nanocom Booster use not supported in this version" << std::endl;
512522 INITSTRUCT (sP_FE2CL_REP_PC_ITEM_USE_FAIL , respFail);
513523 sock->sendPacket (respFail, P_FE2CL_REP_PC_ITEM_USE_FAIL);
@@ -518,26 +528,26 @@ static void useNanocomBooster(CNSocket* sock, CNPacketData* data) {
518528 Player* player = PlayerManager::getPlayer (sock);
519529 sItemBase item = player->Inven [request->iSlotNum ];
520530
521- // consume item
522- item.iOpt -= 1 ;
523- if (item.iOpt == 0 )
524- item = {};
525-
526531 // decide on the booster to activate
527532 std::vector<int16_t > boosterIDs;
528533 switch (item.iID ) {
529- case 153 :
530- case 154 :
531- case 155 :
534+ case GENERALITEM_FUSION_HUNTER_BOOSTER :
535+ case GENERALITEM_IZ_RACER_BOOSTER :
536+ case GENERALITEM_QUESTER_BOOSTER :
532537 boosterIDs.push_back (item.iID );
533538 break ;
534- case 156 :
535- boosterIDs.push_back (153 );
536- boosterIDs.push_back (154 );
537- boosterIDs.push_back (155 );
539+ case GENERALITEM_SUPER_BOOSTER_DX :
540+ boosterIDs.push_back (GENERALITEM_FUSION_HUNTER_BOOSTER );
541+ boosterIDs.push_back (GENERALITEM_IZ_RACER_BOOSTER );
542+ boosterIDs.push_back (GENERALITEM_QUESTER_BOOSTER );
538543 break ;
539544 }
540545
546+ // consume item
547+ item.iOpt -= 1 ;
548+ if (item.iOpt == 0 )
549+ item = {};
550+
541551 // client wants to subtract server time in seconds from the time limit for display purposes
542552 int32_t timeLimitDisplayed = (getTime () / 1000UL ) + NANOCOM_BOOSTER_DURATION;
543553 // in actuality we will use the timestamp of booster activation to the item time limit similar to vehicles
@@ -548,8 +558,8 @@ static void useNanocomBooster(CNSocket* sock, CNPacketData* data) {
548558 for (int16_t itemID : boosterIDs) {
549559 sItemBase boosterItem = { 7 , itemID, 1 , timeLimitDisplayed };
550560
551- // 155 -> 9, 153 -> 10, 154 -> 11
552- int slot = 9 + ((itemID - 152 ) % 3 );
561+ // quester 155 -> 9, hunter 153 -> 10, racer 154 -> 11
562+ int slot = 9 + ((itemID - GENERALITEM_FUSION_HUNTER_BOOSTER + 1 ) % 3 );
553563
554564 // give item to the equip slot
555565 INITSTRUCT (sP_FE2CL_REP_PC_GIVE_ITEM_SUCC , resp);
@@ -607,15 +617,15 @@ static void itemUseHandler(CNSocket* sock, CNPacketData* data) {
607617 */
608618
609619 switch (item.iID ) {
610- case 119 :
611- case 120 :
612- case 121 :
620+ case GENERALITEM_GUMBALL_ADAPTIUM :
621+ case GENERALITEM_GUMBALL_BLASTONS :
622+ case GENERALITEM_GUMBALL_COSMIX :
613623 useGumball (sock, data);
614624 break ;
615- case 153 :
616- case 154 :
617- case 155 :
618- case 156 :
625+ case GENERALITEM_FUSION_HUNTER_BOOSTER :
626+ case GENERALITEM_IZ_RACER_BOOSTER :
627+ case GENERALITEM_QUESTER_BOOSTER :
628+ case GENERALITEM_SUPER_BOOSTER_DX :
619629 useNanocomBooster (sock, data);
620630 break ;
621631 default :
@@ -709,7 +719,7 @@ static void chestOpenHandler(CNSocket *sock, CNPacketData *data) {
709719 // if we failed to open a crate, at least give the player a gumball (suggested by Jade)
710720 if (failing) {
711721 item->sItem .iType = 7 ;
712- item->sItem .iID = 119 + Rand::rand (3 );
722+ item->sItem .iID = GENERALITEM_GUMBALL_ADAPTIUM + Rand::rand (3 );
713723 item->sItem .iOpt = 1 ;
714724
715725 std::cout << " [WARN] Crate open failed, giving a Gumball..." << std::endl;
@@ -820,7 +830,7 @@ size_t Items::checkAndRemoveExpiredItems(CNSocket* sock, Player* player) {
820830 }
821831
822832 // exit vehicle if player no longer has one equipped (function checks pcstyle)
823- if (player->Equip [8 ].iID == 0 )
833+ if (player->Equip [AEQUIP_VEHICLE_IDX ].iID == 0 )
824834 PlayerManager::exitPlayerVehicle (sock, nullptr );
825835
826836 return itemData.size ();
@@ -881,53 +891,53 @@ static int getFMDrop(Player* plr, int baseAmount, int levelDiff, int groupSize)
881891 double bonus = plr->hasBuff (ECSB_REWARD_BLOB) ? (Nanos::getNanoBoost (plr) ? 1.23 : 1.2 ) : 1.0 ;
882892 double boosterEffect = plr->hasHunterBoost () ? (plr->hasQuestBoost () && plr->hasRacerBoost () ? 1.75 : 1.5 ) : 1.0 ;
883893
894+ // if player is within 1 level of the mob, FM is untouched
884895 double levelEffect = 1.0 ;
885- if (levelDiff >= 6 ) {
896+ // otherwise, follow the table below
897+ switch (std::clamp (levelDiff, -3 , 6 )) {
898+ case 6 :
886899 // if player is 6 or more levels above mob, no FM is dropped
887900 levelEffect = 0.0 ;
888- } else if (levelDiff <= -3 ) {
901+ break ;
902+ case 5 :
903+ levelEffect = 0.25 ;
904+ break ;
905+ case 4 :
906+ levelEffect = 0.5 ;
907+ break ;
908+ case 3 :
909+ levelEffect = 0.75 ;
910+ break ;
911+ case 2 :
912+ levelEffect = 0.899 ;
913+ break ;
914+ case -2 :
915+ levelEffect = 1.1 ;
916+ break ;
917+ case -3 :
889918 // if player is 3 or more levels below mob, FM is 1.2x
890919 levelEffect = 1.2 ;
891- } else {
892- switch (levelDiff) {
893- // if player is within 1 level of the mob, FM is untouched
894- // otherwise, follow the table below
895- case 5 :
896- levelEffect = 0.25 ;
897- break ;
898- case 4 :
899- levelEffect = 0.5 ;
900- break ;
901- case 3 :
902- levelEffect = 0.75 ;
903- break ;
904- case 2 :
905- // this case is more lenient
906- levelEffect = 0.899 ;
907- break ;
908- case -2 :
909- levelEffect = 1.1 ;
910- break ;
911- }
920+ break ;
912921 }
913922
923+ // if no group, FM is untouched
914924 double groupEffect = 1.0 ;
925+ // otherwise, follow the table below
915926 switch (groupSize) {
916- // if no group, FM is untouched
917- // otherwise, follow the table below
918- case 2 :
919- groupEffect = 0.875 ;
920- break ;
921- case 3 :
922- groupEffect = 0.75 ;
923- break ;
924- case 4 :
925- // this case is more lenient
926- groupEffect = 0.688 ;
927- break ;
927+ case 2 :
928+ groupEffect = 0.875 ;
929+ break ;
930+ case 3 :
931+ groupEffect = 0.75 ;
932+ break ;
933+ case 4 :
934+ // this case is more lenient
935+ groupEffect = 0.688 ;
936+ break ;
928937 }
929938
930- int amount = baseAmount * bonus * boosterEffect * levelEffect * groupEffect;
939+ int amount = baseAmount * bonus * levelEffect * groupEffect;
940+ amount *= boosterEffect;
931941 return amount;
932942}
933943
0 commit comments