Skip to content

Commit 7ccd4ea

Browse files
CakeLancelotFinnHornhoover
authored andcommitted
Groundwork for nanocom boosters
* The item use handler now has a switch for multiple item types (currently gumballs, and a stub for boosters) * All item types are now checked for expiration, not just vehicles
1 parent 51d3cfb commit 7ccd4ea

4 files changed

Lines changed: 81 additions & 46 deletions

File tree

src/Items.cpp

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,8 @@ static void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
328328
&& !(fromItem->iType == 0 && itemmove->iToSlotNum == 7)
329329
&& fromItem->iType != itemmove->iToSlotNum)
330330
return; // something other than a vehicle or a weapon in a non-matching slot
331-
else if (itemmove->iToSlotNum >= AEQUIP_COUNT) // TODO: reject slots >= 9?
332-
return; // invalid slot
331+
else if (itemmove->iToSlotNum > 8)
332+
return; // any slot higher than 8 is for a booster, and they can't be equipped via move packet
333333
}
334334

335335
// save items to response
@@ -430,25 +430,14 @@ static void itemDeleteHandler(CNSocket* sock, CNPacketData* data) {
430430
sock->sendPacket(resp, P_FE2CL_REP_PC_ITEM_DELETE_SUCC);
431431
}
432432

433-
static void itemUseHandler(CNSocket* sock, CNPacketData* data) {
433+
static void useGumball(CNSocket* sock, CNPacketData* data) {
434434
auto request = (sP_CL2FE_REQ_ITEM_USE*)data->buf;
435435
Player* player = PlayerManager::getPlayer(sock);
436436

437-
if (request->iSlotNum < 0 || request->iSlotNum >= AINVEN_COUNT)
438-
return; // sanity check
439-
440437
// gumball can only be used from inventory, so we ignore eIL
441438
sItemBase gumball = player->Inven[request->iSlotNum];
442439
sNano nano = player->Nanos[player->equippedNanos[request->iNanoSlot]];
443440

444-
// sanity check, check if gumball exists
445-
if (!(gumball.iOpt > 0 && gumball.iType == 7 && gumball.iID>=119 && gumball.iID<=121)) {
446-
std::cout << "[WARN] Gumball not found" << std::endl;
447-
INITSTRUCT(sP_FE2CL_REP_PC_ITEM_USE_FAIL, response);
448-
sock->sendPacket(response, P_FE2CL_REP_PC_ITEM_USE_FAIL);
449-
return;
450-
}
451-
452441
// sanity check, check if gumball type matches nano style
453442
int nanoStyle = Nanos::nanoStyle(nano.iID);
454443
if (!((gumball.iID == 119 && nanoStyle == 0) ||
@@ -472,11 +461,8 @@ static void itemUseHandler(CNSocket* sock, CNPacketData* data) {
472461
return;
473462
}
474463

475-
if (gumball.iOpt == 0)
476-
gumball = {};
477-
478-
uint8_t respbuf[CN_PACKET_BODY_SIZE];
479-
memset(respbuf, 0, CN_PACKET_BODY_SIZE);
464+
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
465+
memset(respbuf, 0, resplen);
480466

481467
sP_FE2CL_REP_PC_ITEM_USE_SUCC *resp = (sP_FE2CL_REP_PC_ITEM_USE_SUCC*)respbuf;
482468
sSkillResult_Buff *respdata = (sSkillResult_Buff*)(respbuf+sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC));
@@ -515,6 +501,54 @@ static void itemUseHandler(CNSocket* sock, CNPacketData* data) {
515501
player->Inven[resp->iSlotNum] = resp->RemainItem;
516502
}
517503

504+
static void useNanocomBooster(CNSocket* sock, CNPacketData* data) {
505+
506+
}
507+
508+
static void itemUseHandler(CNSocket* sock, CNPacketData* data) {
509+
auto request = (sP_CL2FE_REQ_ITEM_USE*)data->buf;
510+
Player* player = PlayerManager::getPlayer(sock);
511+
512+
if (request->iSlotNum < 0 || request->iSlotNum >= AINVEN_COUNT)
513+
return; // sanity check
514+
515+
sItemBase item = player->Inven[request->iSlotNum];
516+
517+
// sanity check, check the item exists and has correct iType
518+
if (!(item.iOpt > 0 && item.iType == 7)) {
519+
std::cout << "[WARN] General item not found" << std::endl;
520+
INITSTRUCT(sP_FE2CL_REP_PC_ITEM_USE_FAIL, response);
521+
sock->sendPacket(response, P_FE2CL_REP_PC_ITEM_USE_FAIL);
522+
return;
523+
}
524+
525+
/*
526+
* TODO: In the XDT, there are subtypes for general-use items
527+
* (m_pGeneralItemTable -> m_pItemData-> m_iItemType) that
528+
* determine their behavior. It would be better to load these
529+
* and use them in this switch, rather than hardcoding by IDs.
530+
*/
531+
532+
switch(item.iID) {
533+
case 119:
534+
case 120:
535+
case 121:
536+
useGumball(sock, data);
537+
break;
538+
case 153:
539+
case 154:
540+
case 155:
541+
case 156:
542+
useNanocomBooster(sock, data);
543+
break;
544+
default:
545+
std::cout << "[INFO] General item "<< item.iID << " is unimplemented." << std::endl;
546+
INITSTRUCT(sP_FE2CL_REP_PC_ITEM_USE_FAIL, response);
547+
sock->sendPacket(response, P_FE2CL_REP_PC_ITEM_USE_FAIL);
548+
break;
549+
}
550+
}
551+
518552
static void itemBankOpenHandler(CNSocket* sock, CNPacketData* data) {
519553
Player* plr = PlayerManager::getPlayer(sock);
520554

@@ -633,14 +667,14 @@ Item* Items::getItemData(int32_t id, int32_t type) {
633667
}
634668

635669
void Items::checkItemExpire(CNSocket* sock, Player* player) {
636-
if (player->toRemoveVehicle.eIL == 0 && player->toRemoveVehicle.iSlotNum == 0)
670+
if (player->expiringItem.eIL == 0 && player->expiringItem.iSlotNum == 0)
637671
return;
638672

639673
/* prepare packet
640674
* yes, this is a varadic packet, however analyzing client behavior and code
641675
* it only checks takes the first item sent into account
642676
* yes, this is very stupid
643-
* therefore, we delete all but 1 expired vehicle while loading player
677+
* therefore, we delete all but 1 expired item while loading player
644678
* to delete the last one here so player gets a notification
645679
*/
646680

@@ -653,18 +687,18 @@ void Items::checkItemExpire(CNSocket* sock, Player* player) {
653687
memset(respbuf, 0, resplen);
654688

655689
packet->iItemListCount = 1;
656-
itemData->eIL = player->toRemoveVehicle.eIL;
657-
itemData->iSlotNum = player->toRemoveVehicle.iSlotNum;
690+
itemData->eIL = player->expiringItem.eIL;
691+
itemData->iSlotNum = player->expiringItem.iSlotNum;
658692
sock->sendPacket((void*)&respbuf, P_FE2CL_PC_DELETE_TIME_LIMIT_ITEM, resplen);
659693

660694
// delete serverside
661-
if (player->toRemoveVehicle.eIL == 0)
662-
memset(&player->Equip[8], 0, sizeof(sItemBase));
695+
if (player->expiringItem.eIL == 0)
696+
memset(&player->Equip[player->expiringItem.iSlotNum], 0, sizeof(sItemBase));
663697
else
664-
memset(&player->Inven[player->toRemoveVehicle.iSlotNum], 0, sizeof(sItemBase));
698+
memset(&player->Inven[player->expiringItem.iSlotNum], 0, sizeof(sItemBase));
665699

666-
player->toRemoveVehicle.eIL = 0;
667-
player->toRemoveVehicle.iSlotNum = 0;
700+
player->expiringItem.eIL = 0;
701+
player->expiringItem.iSlotNum = 0;
668702
}
669703

670704
void Items::setItemStats(Player* plr) {
@@ -857,7 +891,6 @@ void Items::giveMobDrop(CNSocket *sock, Mob* mob, const DropRoll& rolled, const
857891
void Items::init() {
858892
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_MOVE, itemMoveHandler);
859893
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ITEM_DELETE, itemDeleteHandler);
860-
// this one is for gumballs
861894
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_USE, itemUseHandler);
862895
// Bank
863896
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_BANK_OPEN, itemBankOpenHandler);

src/Player.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ struct Player : public Entity, public ICombatant {
6565
sItemBase QInven[AQINVEN_COUNT] = {};
6666
int32_t CurrentMissionID = 0;
6767

68-
sTimeLimitItemDeleteInfo2CL toRemoveVehicle = {};
68+
sTimeLimitItemDeleteInfo2CL expiringItem = {};
6969

7070
Group* group = nullptr;
7171

src/PlayerManager.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,8 @@ static void enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
536536

537537
// check if vehicle didn't expire
538538
if (expired) {
539-
plr->toRemoveVehicle.eIL = 0;
540-
plr->toRemoveVehicle.iSlotNum = 8;
539+
plr->expiringItem.eIL = 0;
540+
plr->expiringItem.iSlotNum = 8;
541541
Items::checkItemExpire(sock, plr);
542542
}
543543
}

src/db/player.cpp

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,37 @@
22

33
// Loading and saving players to/from the DB
44

5-
static void removeExpiredVehicles(Player* player) {
5+
static void removeExpiredItems(Player* player) {
66
int32_t currentTime = getTimestamp();
77

8-
// if there are expired vehicles in bank just remove them silently
8+
// if there are expired items in bank just remove them silently
99
for (int i = 0; i < ABANK_COUNT; i++) {
10-
if (player->Bank[i].iType == 10 && player->Bank[i].iTimeLimit < currentTime && player->Bank[i].iTimeLimit != 0) {
10+
if (player->Bank[i].iTimeLimit < currentTime && player->Bank[i].iTimeLimit != 0) {
1111
memset(&player->Bank[i], 0, sizeof(sItemBase));
1212
}
1313
}
1414

15-
// we want to leave only 1 expired vehicle on player to delete it with the client packet
15+
// we want to leave only 1 expired item on player to delete it with the client packet
1616
std::vector<sItemBase*> toRemove;
1717

18-
// equipped vehicle
19-
if (player->Equip[8].iOpt > 0 && player->Equip[8].iTimeLimit < currentTime && player->Equip[8].iTimeLimit != 0) {
20-
toRemove.push_back(&player->Equip[8]);
21-
player->toRemoveVehicle.eIL = 0;
22-
player->toRemoveVehicle.iSlotNum = 8;
18+
// equipped items
19+
for (int i = 0; i < AEQUIP_COUNT; i++) {
20+
if (player->Equip[i].iOpt > 0 && player->Equip[i].iTimeLimit < currentTime && player->Equip[i].iTimeLimit != 0) {
21+
toRemove.push_back(&player->Equip[i]);
22+
player->expiringItem.eIL = 0;
23+
player->expiringItem.iSlotNum = i;
24+
}
2325
}
2426
// inventory
2527
for (int i = 0; i < AINVEN_COUNT; i++) {
26-
if (player->Inven[i].iType == 10 && player->Inven[i].iTimeLimit < currentTime && player->Inven[i].iTimeLimit != 0) {
28+
if (player->Inven[i].iTimeLimit < currentTime && player->Inven[i].iTimeLimit != 0) {
2729
toRemove.push_back(&player->Inven[i]);
28-
player->toRemoveVehicle.eIL = 1;
29-
player->toRemoveVehicle.iSlotNum = i;
30+
player->expiringItem.eIL = 1;
31+
player->expiringItem.iSlotNum = i;
3032
}
3133
}
3234

33-
// delete all but one vehicles, leave last one for ceremonial deletion
35+
// delete all but one item, leave last one for ceremonial deletion
3436
for (int i = 0; i < (int)toRemove.size()-1; i++) {
3537
memset(toRemove[i], 0, sizeof(sItemBase));
3638
}
@@ -160,7 +162,7 @@ void Database::getPlayer(Player* plr, int id) {
160162

161163
sqlite3_finalize(stmt);
162164

163-
removeExpiredVehicles(plr);
165+
removeExpiredItems(plr);
164166

165167
// get quest inventory
166168
sql = R"(

0 commit comments

Comments
 (0)