Skip to content

Commit 80a30ef

Browse files
add safe taro fm handling, rate command, race and mission booster logic
1 parent 31aac11 commit 80a30ef

18 files changed

Lines changed: 251 additions & 109 deletions

src/Abilities.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,11 @@ static SkillResult handleSkillBatteryDrain(SkillData* skill, int power, ICombata
170170
if(!blocked) {
171171
boostDrain = (int)(skill->values[0][power] * scalingFactor);
172172
if(boostDrain > plr->batteryW) boostDrain = plr->batteryW;
173-
plr->batteryW -= boostDrain;
173+
plr->subtractCapped(CappedValueType::BATTERY_W, boostDrain);
174174

175175
potionDrain = (int)(skill->values[1][power] * scalingFactor);
176176
if(potionDrain > plr->batteryN) potionDrain = plr->batteryN;
177-
plr->batteryN -= potionDrain;
177+
plr->subtractCapped(CappedValueType::BATTERY_N, potionDrain);
178178
}
179179

180180
sSkillResult_BatteryDrain result{};
@@ -364,7 +364,7 @@ void Abilities::useNPCSkill(EntityRef npc, int skillID, std::vector<ICombatant*>
364364
ICombatant* src = nullptr;
365365
if(npc.kind == EntityKind::COMBAT_NPC || npc.kind == EntityKind::MOB)
366366
src = dynamic_cast<ICombatant*>(entity);
367-
367+
368368
SkillData* skill = &SkillTable[skillID];
369369

370370
std::vector<SkillResult> results = handleSkill(skill, 0, src, affected);
@@ -443,7 +443,7 @@ std::vector<ICombatant*> Abilities::matchTargets(ICombatant* src, SkillData* ski
443443
}
444444
}
445445

446-
return targets;
446+
return targets;
447447
}
448448

449449
/* ripped from client (enums emplaced) */

src/BuiltinCommands.cpp

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -75,30 +75,22 @@ static void setValuePlayer(CNSocket* sock, CNPacketData* data) {
7575
case CN_GM_SET_VALUE_TYPE__HP:
7676
response.iSetValue = plr->HP = setData->iSetValue;
7777
break;
78-
case CN_GM_SET_VALUE_TYPE__WEAPON_BATTERY :
79-
plr->batteryW = setData->iSetValue;
80-
81-
// caps
82-
if (plr->batteryW > 9999)
83-
plr->batteryW = 9999;
84-
78+
case CN_GM_SET_VALUE_TYPE__WEAPON_BATTERY:
79+
plr->setCapped(CappedValueType::BATTERY_W, setData->iSetValue);
8580
response.iSetValue = plr->batteryW;
8681
break;
8782
case CN_GM_SET_VALUE_TYPE__NANO_BATTERY:
88-
plr->batteryN = setData->iSetValue;
89-
90-
// caps
91-
if (plr->batteryN > 9999)
92-
plr->batteryN = 9999;
93-
83+
plr->setCapped(CappedValueType::BATTERY_N, setData->iSetValue);
9484
response.iSetValue = plr->batteryN;
9585
break;
9686
case CN_GM_SET_VALUE_TYPE__FUSION_MATTER:
97-
Missions::updateFusionMatter(sock, setData->iSetValue - plr->fusionmatter);
87+
plr->setCapped(CappedValueType::FUSIONMATTER, setData->iSetValue);
88+
Missions::updateFusionMatter(sock);
9889
response.iSetValue = plr->fusionmatter;
9990
break;
10091
case CN_GM_SET_VALUE_TYPE__CANDY:
101-
response.iSetValue = plr->money = setData->iSetValue;
92+
plr->setCapped(CappedValueType::TAROS, setData->iSetValue);
93+
response.iSetValue = plr->money;
10294
break;
10395
case CN_GM_SET_VALUE_TYPE__SPEED:
10496
case CN_GM_SET_VALUE_TYPE__JUMP:
@@ -148,6 +140,47 @@ static void setGMSpecialOnOff(CNSocket *sock, CNPacketData *data) {
148140
// this is only used for muting players, so no need to update the client since that logic is server-side
149141
}
150142

143+
static void setGMRewardRate(CNSocket *sock, CNPacketData *data) {
144+
Player *plr = PlayerManager::getPlayer(sock);
145+
146+
// access check
147+
if (plr->accountLevel > 30)
148+
return;
149+
150+
auto req = (sP_CL2FE_GM_REQ_REWARD_RATE*)data->buf;
151+
152+
if (req->iGetSet != 0) {
153+
double *rate = plr->rateT;
154+
155+
switch (req->iRewardType) {
156+
case REWARD_TYPE_TAROS:
157+
rate = plr->rateT;
158+
break;
159+
case REWARD_TYPE_FUSIONMATTER:
160+
rate = plr->rateF;
161+
break;
162+
}
163+
164+
switch (req->iRewardRateIndex) {
165+
case RATE_SLOT_ALL:
166+
for (int i = 0; i < 5; i++)
167+
rate[i] = req->iSetRateValue;
168+
break;
169+
case RATE_SLOT_COMBAT:
170+
case RATE_SLOT_MISSION:
171+
case RATE_SLOT_EGG:
172+
case RATE_SLOT_RACING:
173+
rate[req->iRewardRateIndex] = req->iSetRateValue;
174+
break;
175+
}
176+
}
177+
178+
INITSTRUCT(sP_FE2CL_GM_REP_REWARD_RATE_SUCC, resp);
179+
memcpy(resp.afRewardRate_Taros, plr->rateT, sizeof(resp.afRewardRate_Taros));
180+
memcpy(resp.afRewardRate_FusionMatter, plr->rateF, sizeof(resp.afRewardRate_FusionMatter));
181+
sock->sendPacket(resp, P_FE2CL_GM_REP_REWARD_RATE_SUCC);
182+
}
183+
151184
static void locatePlayer(CNSocket *sock, CNPacketData *data) {
152185
Player *plr = PlayerManager::getPlayer(sock);
153186

@@ -371,6 +404,7 @@ void BuiltinCommands::init() {
371404

372405
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH, setGMSpecialSwitchPlayer);
373406
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_TARGET_PC_SPECIAL_STATE_ONOFF, setGMSpecialOnOff);
407+
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_REWARD_RATE, setGMRewardRate);
374408

375409
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_LOCATION, locatePlayer);
376410
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_KICK_PLAYER, kickPlayer);

src/Combat.cpp

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ EntityRef CombatNPC::getRef() {
300300
}
301301

302302
void CombatNPC::step(time_t currTime) {
303-
303+
304304
if(stateHandlers.find(state) != stateHandlers.end())
305305
stateHandlers[state](this, currTime);
306306
else {
@@ -441,11 +441,7 @@ static void pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
441441
damage = getDamage(damage.first, (int)mob->data["m_iProtection"], true, (plr->batteryW > 6 + difficulty),
442442
Nanos::nanoStyle(plr->activeNano), (int)mob->data["m_iNpcStyle"], difficulty);
443443

444-
if (plr->batteryW >= 6 + difficulty)
445-
plr->batteryW -= 6 + difficulty;
446-
else
447-
plr->batteryW = 0;
448-
444+
plr->subtractCapped(CappedValueType::BATTERY_W, 6 + difficulty);
449445
damage.first = mob->takeDamage(sock, damage.first);
450446

451447
respdata[i].iID = mob->id;
@@ -690,10 +686,7 @@ static void pcAttackChars(CNSocket *sock, CNPacketData *data) {
690686
Nanos::nanoStyle(plr->activeNano), (int)mob->data["m_iNpcStyle"], difficulty);
691687
}
692688

693-
if (plr->batteryW >= 6 + plr->level)
694-
plr->batteryW -= 6 + plr->level;
695-
else
696-
plr->batteryW = 0;
689+
plr->subtractCapped(CappedValueType::BATTERY_W, 6 + plr->level);
697690

698691
damage.first = target->takeDamage(sock, damage.first);
699692

@@ -742,7 +735,7 @@ static int8_t addBullet(Player* plr, bool isGrenade) {
742735
toAdd.weaponBoost = plr->batteryW > 0;
743736
if (toAdd.weaponBoost) {
744737
int boostCost = Rand::rand(11) + 20;
745-
plr->batteryW = boostCost > plr->batteryW ? 0 : plr->batteryW - boostCost;
738+
plr->subtractCapped(CappedValueType::BATTERY_W, boostCost);
746739
}
747740

748741
Bullets[plr->iID][findId] = toAdd;

src/Email.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ static void emailReceiveTaros(CNSocket* sock, CNPacketData* data) {
7575

7676
Database::EmailData email = Database::getEmail(plr->iID, pkt->iEmailIndex);
7777
// money transfer
78-
plr->money += email.Taros;
78+
plr->addCapped(CappedValueType::TAROS, email.Taros);
7979
email.Taros = 0;
8080
// update Taros in email
8181
Database::updateEmailContent(&email);
@@ -274,7 +274,7 @@ static void emailSend(CNSocket* sock, CNPacketData* data) {
274274
}
275275

276276
int cost = pkt->iCash + 50 + 20 * attachments.size(); // attached taros + postage
277-
plr->money -= cost;
277+
plr->subtractCapped(CappedValueType::TAROS, cost);
278278
Database::EmailData email = {
279279
(int)pkt->iTo_PCUID, // PlayerId
280280
Database::getNextEmailIndex(pkt->iTo_PCUID), // MsgIndex
@@ -291,7 +291,7 @@ static void emailSend(CNSocket* sock, CNPacketData* data) {
291291
};
292292

293293
if (!Database::sendEmail(&email, attachments, plr)) {
294-
plr->money += cost; // give money back
294+
plr->addCapped(CappedValueType::TAROS, cost); // give money back
295295
// give items back
296296
while (!attachments.empty()) {
297297
sItemBase attachment = attachments.back();

src/Entities.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,93 @@ bool Player::hasSuperBoost() const {
136136
return Player::hasQuestBoost() && Player::hasHunterBoost() && Player::hasRacerBoost();
137137
}
138138

139+
static int32_t getCap(CappedValueType type) {
140+
switch (type) {
141+
case CappedValueType::TAROS:
142+
return PC_CANDY_MAX;
143+
case CappedValueType::FUSIONMATTER:
144+
return PC_FUSIONMATTER_MAX;
145+
case CappedValueType::BATTERY_W:
146+
return PC_BATTERY_MAX;
147+
case CappedValueType::BATTERY_N:
148+
return PC_BATTERY_MAX;
149+
case CappedValueType::TAROS_IN_TRADE:
150+
return PC_CANDY_MAX;
151+
default:
152+
return INT32_MAX;
153+
}
154+
}
155+
156+
static int32_t *getCappedValue(Player *player, CappedValueType type) {
157+
switch (type) {
158+
case CappedValueType::TAROS:
159+
return &player->money;
160+
case CappedValueType::FUSIONMATTER:
161+
return &player->fusionmatter;
162+
case CappedValueType::BATTERY_W:
163+
return &player->batteryW;
164+
case CappedValueType::BATTERY_N:
165+
return &player->batteryN;
166+
case CappedValueType::TAROS_IN_TRADE:
167+
return &player->moneyInTrade;
168+
default:
169+
return nullptr;
170+
}
171+
}
172+
173+
void Player::addCapped(CappedValueType type, int32_t diff) {
174+
if (diff <= 0)
175+
return;
176+
177+
int32_t max = getCap(type);
178+
int32_t *value = getCappedValue(this, type);
179+
180+
if (value == nullptr)
181+
return;
182+
183+
if (diff > max)
184+
diff = max;
185+
186+
if (*value + diff > max)
187+
*value = max;
188+
else
189+
*value += diff;
190+
}
191+
192+
void Player::subtractCapped(CappedValueType type, int32_t diff) {
193+
if (diff <= 0)
194+
return;
195+
196+
int32_t max = getCap(type);
197+
int32_t *value = getCappedValue(this, type);
198+
199+
if (value == nullptr)
200+
return;
201+
202+
if (diff > max)
203+
diff = max;
204+
205+
if (*value - diff < 0)
206+
*value = 0;
207+
else
208+
*value -= diff;
209+
}
210+
211+
void Player::setCapped(CappedValueType type, int32_t value) {
212+
int32_t max = getCap(type);
213+
int32_t *valToSet = getCappedValue(this, type);
214+
215+
if (valToSet == nullptr)
216+
return;
217+
218+
if (value < 0)
219+
value = 0;
220+
else if (value > max)
221+
value = max;
222+
223+
*valToSet = value;
224+
}
225+
139226
// TODO: this is less effiecient than it was, because of memset()
140227
void Player::enterIntoViewOf(CNSocket *sock) {
141228
INITSTRUCT(sP_FE2CL_PC_NEW, pkt);

src/Items.cpp

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ static void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
335335

336336
// if equipping an item, validate that it's of the correct type for the slot
337337
if ((SlotType)itemmove->eTo == SlotType::EQUIP) {
338-
if (fromItem->iType == 10 && itemmove->iToSlotNum != AEQUIP_VEHICLE_IDX)
338+
if (fromItem->iType == 10 && itemmove->iToSlotNum != EQUIP_SLOT_VEHICLE)
339339
return; // vehicle in wrong slot
340340
else if (fromItem->iType != 10
341341
&& !(fromItem->iType == 0 && itemmove->iToSlotNum == 7)
@@ -399,7 +399,7 @@ static void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
399399
}
400400

401401
// unequip vehicle if equip slot 8 is 0
402-
if (plr->Equip[AEQUIP_VEHICLE_IDX].iID == 0 && plr->iPCState & 8) {
402+
if (plr->Equip[EQUIP_SLOT_VEHICLE].iID == 0 && plr->iPCState & 8) {
403403
INITSTRUCT(sP_FE2CL_PC_VEHICLE_OFF_SUCC, response);
404404
sock->sendPacket(response, P_FE2CL_PC_VEHICLE_OFF_SUCC);
405405

@@ -830,7 +830,7 @@ size_t Items::checkAndRemoveExpiredItems(CNSocket* sock, Player* player) {
830830
}
831831

832832
// exit vehicle if player no longer has one equipped (function checks pcstyle)
833-
if (player->Equip[AEQUIP_VEHICLE_IDX].iID == 0)
833+
if (player->Equip[EQUIP_SLOT_VEHICLE].iID == 0)
834834
PlayerManager::exitPlayerVehicle(sock, nullptr);
835835

836836
return itemData.size();
@@ -880,14 +880,13 @@ static void getMobDrop(sItemBase* reward, const std::vector<int>& weights, const
880880
reward->iID = crateIds[chosenIndex];
881881
}
882882

883-
static int getTaroDrop(Player* plr, int baseAmount, int groupSize) {
883+
static int32_t calculateTaroReward(Player* plr, int baseAmount, int groupSize) {
884884
double bonus = plr->hasBuff(ECSB_REWARD_CASH) ? (Nanos::getNanoBoost(plr) ? 1.23 : 1.2) : 1.0;
885885
double groupEffect = 1.0 / groupSize;
886-
int amount = baseAmount * bonus * groupEffect;
887-
return amount;
886+
return baseAmount * plr->rateT[RATE_SLOT_COMBAT] * bonus * groupEffect;
888887
}
889888

890-
static int getFMDrop(Player* plr, int baseAmount, int levelDiff, int groupSize) {
889+
static int32_t calculateFMReward(Player* plr, int baseAmount, int levelDiff, int groupSize) {
891890
double bonus = plr->hasBuff(ECSB_REWARD_BLOB) ? (Nanos::getNanoBoost(plr) ? 1.23 : 1.2) : 1.0;
892891
double boosterEffect = plr->hasHunterBoost() ? (plr->hasQuestBoost() && plr->hasRacerBoost() ? 1.75 : 1.5) : 1.0;
893892

@@ -936,7 +935,7 @@ static int getFMDrop(Player* plr, int baseAmount, int levelDiff, int groupSize)
936935
break;
937936
}
938937

939-
int amount = baseAmount * bonus * levelEffect * groupEffect;
938+
int32_t amount = baseAmount * plr->rateF[RATE_SLOT_COMBAT] * bonus * levelEffect * groupEffect;
940939
amount *= boosterEffect;
941940
return amount;
942941
}
@@ -993,24 +992,20 @@ static void giveSingleDrop(CNSocket *sock, Mob* mob, int mobDropId, const DropRo
993992
MiscDropType& miscDropType = Items::MiscDropTypes[drop.miscDropTypeId];
994993

995994
if (rolled.taros % miscDropChance.taroDropChanceTotal < miscDropChance.taroDropChance) {
996-
plr->money += getTaroDrop(plr, miscDropType.taroAmount, groupSize);
995+
int32_t taros = calculateTaroReward(plr, miscDropType.taroAmount, groupSize);
996+
plr->addCapped(CappedValueType::TAROS, taros);
997997
}
998998
if (rolled.fm % miscDropChance.fmDropChanceTotal < miscDropChance.fmDropChance) {
999999
int levelDifference = plr->level - mob->level;
1000-
int fm = getFMDrop(plr, miscDropType.fmAmount, levelDifference, groupSize);
1001-
Missions::updateFusionMatter(sock, fm);
1000+
int32_t fm = calculateFMReward(plr, miscDropType.fmAmount, levelDifference, groupSize);
1001+
plr->addCapped(CappedValueType::FUSIONMATTER, fm);
1002+
Missions::updateFusionMatter(sock);
10021003
}
10031004

10041005
if (rolled.potions % miscDropChance.potionDropChanceTotal < miscDropChance.potionDropChance)
1005-
plr->batteryN += miscDropType.potionAmount;
1006+
plr->addCapped(CappedValueType::BATTERY_N, miscDropType.potionAmount);
10061007
if (rolled.boosts % miscDropChance.boostDropChanceTotal < miscDropChance.boostDropChance)
1007-
plr->batteryW += miscDropType.boostAmount;
1008-
1009-
// caps
1010-
if (plr->batteryW > 9999)
1011-
plr->batteryW = 9999;
1012-
if (plr->batteryN > 9999)
1013-
plr->batteryN = 9999;
1008+
plr->addCapped(CappedValueType::BATTERY_W, miscDropType.boostAmount);
10141009

10151010
// simple rewards
10161011
reward->m_iCandy = plr->money;

0 commit comments

Comments
 (0)