mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-05 06:50:04 +00:00
Cleaned up item drop logic.
* Replaced bad exception logic with C-style error returns in ItemManager * Removed unnecessary instances of objects being passed by value * Fixed whitespace problems * Added new config options to the default config.ini * Updated tabledata reference
This commit is contained in:
parent
7f716c7278
commit
3ce8cf2129
11
config.ini
11
config.ini
@ -38,6 +38,8 @@ xdtdata=tdata/xdt.json
|
|||||||
mobdata=tdata/mobs.json
|
mobdata=tdata/mobs.json
|
||||||
# path json
|
# path json
|
||||||
pathdata=tdata/paths.json
|
pathdata=tdata/paths.json
|
||||||
|
# drop json
|
||||||
|
dropdata=tdata/drops.json
|
||||||
# gruntwork output (this is what you submit)
|
# gruntwork output (this is what you submit)
|
||||||
gruntwork=tdata/gruntwork.json
|
gruntwork=tdata/gruntwork.json
|
||||||
|
|
||||||
@ -49,6 +51,15 @@ gruntwork=tdata/gruntwork.json
|
|||||||
# any number higher than 50 will disable commands
|
# any number higher than 50 will disable commands
|
||||||
accountlevel=1
|
accountlevel=1
|
||||||
|
|
||||||
|
# should mobs drop event crates?
|
||||||
|
# 0 = no event
|
||||||
|
# 1 = Knishmas
|
||||||
|
# 2 = Halloween
|
||||||
|
# 3 = Easter
|
||||||
|
eventmode=0
|
||||||
|
# percent chance of an event crate dropping each kill
|
||||||
|
eventcratechance=10
|
||||||
|
|
||||||
# spawn coordinates (Z is height)
|
# spawn coordinates (Z is height)
|
||||||
# the supplied defaults are at Sector V (future)
|
# the supplied defaults are at Sector V (future)
|
||||||
spawnx=632032
|
spawnx=632032
|
||||||
|
@ -16,14 +16,11 @@ std::map<int32_t, Crate> ItemManager::Crates;
|
|||||||
/// pair Itemset, Rarity -> vector of pointers (map iterators) to records in ItemData
|
/// pair Itemset, Rarity -> vector of pointers (map iterators) to records in ItemData
|
||||||
std::map<std::pair<int32_t, int32_t>, std::vector<std::map<std::pair<int32_t, int32_t>, Item>::iterator>> ItemManager::CrateItems;
|
std::map<std::pair<int32_t, int32_t>, std::vector<std::map<std::pair<int32_t, int32_t>, Item>::iterator>> ItemManager::CrateItems;
|
||||||
|
|
||||||
// buffer for error messages
|
|
||||||
char buffer[255];
|
|
||||||
|
|
||||||
void ItemManager::init() {
|
void ItemManager::init() {
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_MOVE, itemMoveHandler);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_MOVE, itemMoveHandler);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ITEM_DELETE, itemDeleteHandler);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ITEM_DELETE, itemDeleteHandler);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_ITEM, itemGMGiveHandler);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_ITEM, itemGMGiveHandler);
|
||||||
//this one is for gumballs
|
// this one is for gumballs
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_USE, itemUseHandler);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_USE, itemUseHandler);
|
||||||
// Bank
|
// Bank
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_BANK_OPEN, itemBankOpenHandler);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_BANK_OPEN, itemBankOpenHandler);
|
||||||
@ -809,11 +806,15 @@ void ItemManager::chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
|||||||
return; // ignore the malformed packet
|
return; // ignore the malformed packet
|
||||||
|
|
||||||
sP_CL2FE_REQ_ITEM_CHEST_OPEN *chest = (sP_CL2FE_REQ_ITEM_CHEST_OPEN *)data->buf;
|
sP_CL2FE_REQ_ITEM_CHEST_OPEN *chest = (sP_CL2FE_REQ_ITEM_CHEST_OPEN *)data->buf;
|
||||||
Player *player = PlayerManager::getPlayer(sock);
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
if (player == nullptr)
|
// chest opening acknowledgement packet
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, resp);
|
||||||
|
resp.iSlotNum = chest->iSlotNum;
|
||||||
|
|
||||||
|
if (plr == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// item giving packet
|
// item giving packet
|
||||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
||||||
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
||||||
@ -827,75 +828,82 @@ void ItemManager::chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
|||||||
memset(respbuf, 0, resplen);
|
memset(respbuf, 0, resplen);
|
||||||
|
|
||||||
// maintain stats
|
// maintain stats
|
||||||
reward->m_iCandy = player->money;
|
reward->m_iCandy = plr->money;
|
||||||
reward->m_iFusionMatter = player->fusionmatter;
|
reward->m_iFusionMatter = plr->fusionmatter;
|
||||||
reward->iFatigue = 100; // prevents warning message
|
reward->iFatigue = 100; // prevents warning message
|
||||||
reward->iFatigue_Level = 1;
|
reward->iFatigue_Level = 1;
|
||||||
reward->iItemCnt = 1; // remember to update resplen if you change this
|
reward->iItemCnt = 1; // remember to update resplen if you change this
|
||||||
|
|
||||||
// item reward
|
|
||||||
if (chest->ChestItem.iType != 9)
|
|
||||||
std::cout << "[WARN] Player tried to open a crate with incorrect iType ?!" << std::endl;
|
|
||||||
else
|
|
||||||
item->sItem = openCrate(chest->ChestItem.iID, player->PCStyle.iGender);
|
|
||||||
|
|
||||||
item->iSlotNum = chest->iSlotNum;
|
item->iSlotNum = chest->iSlotNum;
|
||||||
item->eIL = chest->eIL;
|
item->eIL = chest->eIL;
|
||||||
|
|
||||||
|
// item reward
|
||||||
|
if (chest->ChestItem.iType != 9) {
|
||||||
|
std::cout << "[WARN] Player tried to open a crate with incorrect iType ?!" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int itemSetId = -1, rarity = -1, ret = -1;
|
||||||
|
bool failing = false;
|
||||||
|
|
||||||
|
// find the crate
|
||||||
|
if (Crates.find(chest->ChestItem.iID) == Crates.end()) {
|
||||||
|
std::cout << "[WARN] Crate " << chest->ChestItem.iID << " not found!" << std::endl;
|
||||||
|
failing = true;
|
||||||
|
}
|
||||||
|
Crate& crate = Crates[chest->ChestItem.iID];
|
||||||
|
|
||||||
|
if (!failing)
|
||||||
|
itemSetId = getItemSetId(crate, chest->ChestItem.iID);
|
||||||
|
if (itemSetId == -1)
|
||||||
|
failing = true;
|
||||||
|
|
||||||
|
if (!failing)
|
||||||
|
rarity = getRarity(crate, itemSetId);
|
||||||
|
if (rarity == -1)
|
||||||
|
failing = true;
|
||||||
|
|
||||||
|
if (!failing)
|
||||||
|
ret = getCrateItem(item->sItem, itemSetId, rarity, plr->PCStyle.iGender);
|
||||||
|
if (ret == -1)
|
||||||
|
failing = true;
|
||||||
|
|
||||||
|
// if we failed to open a crate, at least give the player a gumball (suggested by Jade)
|
||||||
|
if (failing) {
|
||||||
|
item->sItem.iType = 7;
|
||||||
|
item->sItem.iID = 119 + (rand() % 3);
|
||||||
|
item->sItem.iOpt = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// update player
|
// update player
|
||||||
player->Inven[chest->iSlotNum] = item->sItem;
|
plr->Inven[chest->iSlotNum] = item->sItem;
|
||||||
|
|
||||||
// transmit item
|
// transmit item
|
||||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||||
|
|
||||||
// chest opening acknowledgement packet
|
// transmit chest opening acknowledgement packet
|
||||||
INITSTRUCT(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, resp);
|
|
||||||
|
|
||||||
resp.iSlotNum = chest->iSlotNum;
|
|
||||||
|
|
||||||
std::cout << "opening chest..." << std::endl;
|
std::cout << "opening chest..." << std::endl;
|
||||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, sizeof(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC));
|
sock->sendPacket((void*)&resp, P_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, sizeof(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC));
|
||||||
}
|
}
|
||||||
|
|
||||||
sItemBase ItemManager::openCrate(int crateId, int playerGender) {
|
int ItemManager::getItemSetId(Crate& crate, int crateId) {
|
||||||
sItemBase reward = {};
|
|
||||||
try {
|
|
||||||
Crate crate = getCrate(crateId);
|
|
||||||
int itemSetId = getItemSetId(crate, crateId);
|
|
||||||
int rarity = getRarity(crate, itemSetId);
|
|
||||||
reward = getCrateItem(itemSetId, rarity, playerGender);
|
|
||||||
}
|
|
||||||
catch (const std::exception& err) {
|
|
||||||
std::cerr << "[WARN] An error has occured while trying to open a crate. Error description: \n" << err.what() << std::endl;
|
|
||||||
// if we failed to open a crate, at least give the player a gumball (suggested by Jade)
|
|
||||||
reward.iType = 7;
|
|
||||||
reward.iID = 119 + (rand() % 3);
|
|
||||||
reward.iOpt = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return reward;
|
|
||||||
}
|
|
||||||
|
|
||||||
Crate ItemManager::getCrate(int crateId) {
|
|
||||||
if (Crates.find(crateId) == Crates.end())
|
|
||||||
throwError(sprintf(buffer, "Crate %d was not found!", crateId));
|
|
||||||
return Crates[crateId];
|
|
||||||
}
|
|
||||||
|
|
||||||
int ItemManager::getItemSetId(Crate crate, int crateId) {
|
|
||||||
int itemSetsCount = crate.itemSets.size();
|
int itemSetsCount = crate.itemSets.size();
|
||||||
if (itemSetsCount == 0)
|
if (itemSetsCount == 0) {
|
||||||
throwError(sprintf(buffer, "Crate %d has no item sets assigned?!", crateId));
|
std::cout << "[WARN] Crate " << crateId << " has no item sets assigned?!" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// if crate points to multiple itemSets, choose a random one
|
// if crate points to multiple itemSets, choose a random one
|
||||||
int itemSetIndex = rand() % itemSetsCount;
|
int itemSetIndex = rand() % itemSetsCount;
|
||||||
return crate.itemSets[itemSetIndex];
|
return crate.itemSets[itemSetIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
int ItemManager::getRarity(Crate crate , int itemSetId) {
|
int ItemManager::getRarity(Crate& crate, int itemSetId) {
|
||||||
// find rarity ratio
|
// find rarity ratio
|
||||||
if (RarityRatios.find(crate.rarityRatioId) == RarityRatios.end())
|
if (RarityRatios.find(crate.rarityRatioId) == RarityRatios.end()) {
|
||||||
throwError(sprintf(buffer, "Rarity Ratio %d not found!", crate.rarityRatioId));
|
std::cout << "[WARN] Rarity Ratio " << crate.rarityRatioId << " not found!" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> rarityRatio = RarityRatios[crate.rarityRatioId];
|
std::vector<int> rarityRatio = RarityRatios[crate.rarityRatioId];
|
||||||
|
|
||||||
@ -905,7 +913,7 @@ int ItemManager::getRarity(Crate crate , int itemSetId) {
|
|||||||
* it is simpler to do here than to fix individually in the file
|
* it is simpler to do here than to fix individually in the file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// remember that rarities start from 1 !
|
// remember that rarities start from 1!
|
||||||
for (int i = 0; i < rarityRatio.size(); i++){
|
for (int i = 0; i < rarityRatio.size(); i++){
|
||||||
if (CrateItems.find(std::make_pair(itemSetId, i+1)) == CrateItems.end())
|
if (CrateItems.find(std::make_pair(itemSetId, i+1)) == CrateItems.end())
|
||||||
rarityRatio[i] = 0;
|
rarityRatio[i] = 0;
|
||||||
@ -915,9 +923,10 @@ int ItemManager::getRarity(Crate crate , int itemSetId) {
|
|||||||
for (int value : rarityRatio)
|
for (int value : rarityRatio)
|
||||||
total += value;
|
total += value;
|
||||||
|
|
||||||
// if we didn't find any items, throw exception
|
if (total == 0) {
|
||||||
if (total == 0)
|
std::cout << "Item Set " << itemSetId << " has no items assigned?!" << std::endl;
|
||||||
throwError(sprintf(buffer, "Item Set %d has no items assigned?!", itemSetId));
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// now return a random rarity number
|
// now return a random rarity number
|
||||||
int randomNum = rand() % total;
|
int randomNum = rand() % total;
|
||||||
@ -925,17 +934,19 @@ int ItemManager::getRarity(Crate crate , int itemSetId) {
|
|||||||
int sum = 0;
|
int sum = 0;
|
||||||
do {
|
do {
|
||||||
sum += rarityRatio[rarity];
|
sum += rarityRatio[rarity];
|
||||||
rarity++;
|
rarity++;
|
||||||
} while (sum <= randomNum);
|
} while (sum <= randomNum);
|
||||||
|
|
||||||
return rarity;
|
return rarity;
|
||||||
}
|
}
|
||||||
|
|
||||||
sItemBase ItemManager::getCrateItem(int itemSetId, int rarity, int playerGender) {
|
int ItemManager::getCrateItem(sItemBase& result, int itemSetId, int rarity, int playerGender) {
|
||||||
std::pair key = std::make_pair(itemSetId, rarity);
|
std::pair key = std::make_pair(itemSetId, rarity);
|
||||||
|
|
||||||
if (CrateItems.find(key) == CrateItems.end())
|
if (CrateItems.find(key) == CrateItems.end()) {
|
||||||
throwError(sprintf(buffer, "Item Set ID %d Rarity %d items have not been found", itemSetId, rarity));
|
std::cout << "[WARN] Item Set ID " << itemSetId << " Rarity " << rarity << " items have not been found" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// only take into account items that have correct gender
|
// only take into account items that have correct gender
|
||||||
std::vector<std::map<std::pair<int32_t, int32_t>, Item>::iterator> items;
|
std::vector<std::map<std::pair<int32_t, int32_t>, Item>::iterator> items;
|
||||||
@ -948,20 +959,19 @@ sItemBase ItemManager::getCrateItem(int itemSetId, int rarity, int playerGender)
|
|||||||
items.push_back(crateitem);
|
items.push_back(crateitem);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (items.size() == 0)
|
if (items.size() == 0) {
|
||||||
throwError(sprintf(buffer, "Gender inequality! Set ID %d Rarity %d contains only %s items?!", itemSetId, rarity, playerGender==2 ? "boys" : "girls"));
|
std::cout << "[WARN] Gender inequality! Set ID " << itemSetId << " Rarity " << rarity << " contains only "
|
||||||
|
<< (playerGender == 2 ? "boys" : "girls") << " items?!" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
auto item = items[rand() % items.size()];
|
auto item = items[rand() % items.size()];
|
||||||
sItemBase result = {};
|
|
||||||
result.iID = item->first.first;
|
result.iID = item->first.first;
|
||||||
result.iType = item->first.second;
|
result.iType = item->first.second;
|
||||||
result.iOpt = 1;
|
result.iOpt = 1;
|
||||||
|
|
||||||
return result;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
// argument is here only so we can call sprintf in brackets
|
|
||||||
void ItemManager::throwError(int ignore) {
|
|
||||||
throw buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use this in cleaned up ItemManager
|
// TODO: use this in cleaned up ItemManager
|
||||||
|
@ -29,11 +29,11 @@ namespace ItemManager {
|
|||||||
extern std::map<std::pair<int32_t, int32_t>, Item> ItemData; // <id, type> -> data
|
extern std::map<std::pair<int32_t, int32_t>, Item> ItemData; // <id, type> -> data
|
||||||
extern std::map<int32_t, std::vector<VendorListing>> VendorTables;
|
extern std::map<int32_t, std::vector<VendorListing>> VendorTables;
|
||||||
extern std::map<int32_t, CrocPotEntry> CrocPotTable; // level gap -> entry
|
extern std::map<int32_t, CrocPotEntry> CrocPotTable; // level gap -> entry
|
||||||
extern std::map<int32_t, std::vector<int>> RarityRatios;
|
extern std::map<int32_t, std::vector<int>> RarityRatios;
|
||||||
extern std::map<int32_t, Crate> Crates;
|
extern std::map<int32_t, Crate> Crates;
|
||||||
// pair <Itemset, Rarity> -> vector of pointers (map iterators) to records in ItemData (it looks a lot scarier than it is)
|
// pair <Itemset, Rarity> -> vector of pointers (map iterators) to records in ItemData (it looks a lot scarier than it is)
|
||||||
extern std::map<std::pair<int32_t, int32_t>,
|
extern std::map<std::pair<int32_t, int32_t>,
|
||||||
std::vector<std::map<std::pair<int32_t, int32_t>, Item>::iterator>> CrateItems;
|
std::vector<std::map<std::pair<int32_t, int32_t>, Item>::iterator>> CrateItems;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
@ -56,12 +56,9 @@ namespace ItemManager {
|
|||||||
void chestOpenHandler(CNSocket* sock, CNPacketData* data);
|
void chestOpenHandler(CNSocket* sock, CNPacketData* data);
|
||||||
|
|
||||||
// crate opening logic with all helper functions
|
// crate opening logic with all helper functions
|
||||||
sItemBase openCrate(int crateId, int playerGender);
|
int getItemSetId(Crate& crate, int crateId);
|
||||||
Crate getCrate(int crateId);
|
int getRarity(Crate& crate, int itemSetId);
|
||||||
int getItemSetId(Crate crate, int crateId);
|
int getCrateItem(sItemBase& reward, int itemSetId, int rarity, int playerGender);
|
||||||
int getRarity(Crate crate, int itemSetId);
|
|
||||||
sItemBase getCrateItem(int itemSetId, int rarity, int playerGender);
|
|
||||||
void throwError(int ignore);
|
|
||||||
|
|
||||||
int findFreeSlot(Player *plr);
|
int findFreeSlot(Player *plr);
|
||||||
Item* getItemData(int32_t id, int32_t type);
|
Item* getItemData(int32_t id, int32_t type);
|
||||||
|
@ -11,9 +11,10 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
std::map<int32_t, Mob*> MobManager::Mobs;
|
std::map<int32_t, Mob*> MobManager::Mobs;
|
||||||
|
std::queue<int32_t> MobManager::RemovalQueue;
|
||||||
|
|
||||||
std::map<int32_t, MobDropChance> MobManager::MobDropChances;
|
std::map<int32_t, MobDropChance> MobManager::MobDropChances;
|
||||||
std::map<int32_t, MobDrop> MobManager::MobDrops;
|
std::map<int32_t, MobDrop> MobManager::MobDrops;
|
||||||
std::queue<int32_t> MobManager::RemovalQueue;
|
|
||||||
|
|
||||||
bool MobManager::simulateMobs;
|
bool MobManager::simulateMobs;
|
||||||
|
|
||||||
@ -168,7 +169,7 @@ void MobManager::giveReward(CNSocket *sock, Mob* mob) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// find correct mob drop
|
// find correct mob drop
|
||||||
MobDrop drop = MobDrops[mob->dropType];
|
MobDrop& drop = MobDrops[mob->dropType];
|
||||||
|
|
||||||
plr->money += drop.taros;
|
plr->money += drop.taros;
|
||||||
// formula for scaling FM with player/mob level difference
|
// formula for scaling FM with player/mob level difference
|
||||||
@ -197,29 +198,27 @@ void MobManager::giveReward(CNSocket *sock, Mob* mob) {
|
|||||||
reward->iFatigue_Level = 1;
|
reward->iFatigue_Level = 1;
|
||||||
reward->iItemCnt = 1; // remember to update resplen if you change this
|
reward->iItemCnt = 1; // remember to update resplen if you change this
|
||||||
|
|
||||||
|
|
||||||
int slot = ItemManager::findFreeSlot(plr);
|
int slot = ItemManager::findFreeSlot(plr);
|
||||||
|
|
||||||
bool awardDrop = false;
|
|
||||||
MobDropChance chance;
|
|
||||||
// sanity check
|
|
||||||
if (MobDropChances.find(drop.dropChanceType) == MobDropChances.end())
|
|
||||||
std::cout << "[WARN] Unknown Drop Chance Type: " << drop.dropChanceType << std::endl;
|
|
||||||
else {
|
|
||||||
chance = MobDropChances[drop.dropChanceType];
|
|
||||||
awardDrop = (rand() % 1000 < chance.dropChance);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool awardDrop = false;
|
||||||
|
MobDropChance *chance = nullptr;
|
||||||
|
// sanity check
|
||||||
|
if (MobDropChances.find(drop.dropChanceType) == MobDropChances.end()) {
|
||||||
|
std::cout << "[WARN] Unknown Drop Chance Type: " << drop.dropChanceType << std::endl;
|
||||||
|
return; // this also prevents holiday crate drops, but oh well
|
||||||
|
} else {
|
||||||
|
chance = &MobDropChances[drop.dropChanceType];
|
||||||
|
awardDrop = (rand() % 1000 < chance->dropChance);
|
||||||
|
}
|
||||||
|
|
||||||
// no drop
|
// no drop
|
||||||
if (slot == -1 || !awardDrop) {
|
if (slot == -1 || !awardDrop) {
|
||||||
|
|
||||||
// no room for an item, but you still get FM and taros
|
// no room for an item, but you still get FM and taros
|
||||||
reward->iItemCnt = 0;
|
reward->iItemCnt = 0;
|
||||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
||||||
} else {
|
} else {
|
||||||
// item reward
|
// item reward
|
||||||
item->sItem = getReward(&drop, &chance);
|
getReward(&item->sItem, &drop, chance);
|
||||||
item->iSlotNum = slot;
|
item->iSlotNum = slot;
|
||||||
item->eIL = 1; // Inventory Location. 1 means player inventory.
|
item->eIL = 1; // Inventory Location. 1 means player inventory.
|
||||||
|
|
||||||
@ -227,7 +226,6 @@ void MobManager::giveReward(CNSocket *sock, Mob* mob) {
|
|||||||
plr->Inven[slot] = item->sItem;
|
plr->Inven[slot] = item->sItem;
|
||||||
|
|
||||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// event crates
|
// event crates
|
||||||
@ -235,10 +233,9 @@ void MobManager::giveReward(CNSocket *sock, Mob* mob) {
|
|||||||
giveEventReward(sock, plr);
|
giveEventReward(sock, plr);
|
||||||
}
|
}
|
||||||
|
|
||||||
sItemBase MobManager::getReward(MobDrop* drop, MobDropChance* chance) {
|
void MobManager::getReward(sItemBase *reward, MobDrop* drop, MobDropChance* chance) {
|
||||||
sItemBase reward = {};
|
reward->iType = 9;
|
||||||
reward.iType = 9;
|
reward->iOpt = 1;
|
||||||
reward.iOpt = 1;
|
|
||||||
|
|
||||||
int total = 0;
|
int total = 0;
|
||||||
for (int ratio : chance->cratesRatio)
|
for (int ratio : chance->cratesRatio)
|
||||||
@ -249,29 +246,26 @@ sItemBase MobManager::getReward(MobDrop* drop, MobDropChance* chance) {
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
do {
|
do {
|
||||||
reward.iID = drop->crateIDs[i];
|
reward->iID = drop->crateIDs[i];
|
||||||
sum += chance->cratesRatio[i];
|
sum += chance->cratesRatio[i];
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
while (sum<=randomNum);
|
while (sum<=randomNum);
|
||||||
return reward;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobManager::giveEventReward(CNSocket* sock, Player* player) {
|
void MobManager::giveEventReward(CNSocket* sock, Player* player) {
|
||||||
|
|
||||||
// random drop chance
|
// random drop chance
|
||||||
if (rand() % 100 > settings::EVENTCRATECHANCE)
|
if (rand() % 100 > settings::EVENTCRATECHANCE)
|
||||||
return;
|
return;
|
||||||
// no slot = no award
|
// no slot = no reward
|
||||||
int slot = ItemManager::findFreeSlot(player);
|
int slot = ItemManager::findFreeSlot(player);
|
||||||
if (slot == -1)
|
if (slot == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
||||||
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
||||||
// we know it's only one trailing struct, so we can skip full validation
|
|
||||||
|
|
||||||
uint8_t respbuf[resplen]; // not a variable length array, don't worry
|
uint8_t respbuf[resplen];
|
||||||
sP_FE2CL_REP_REWARD_ITEM* reward = (sP_FE2CL_REP_REWARD_ITEM*)respbuf;
|
sP_FE2CL_REP_REWARD_ITEM* reward = (sP_FE2CL_REP_REWARD_ITEM*)respbuf;
|
||||||
sItemReward* item = (sItemReward*)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
sItemReward* item = (sItemReward*)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
||||||
|
|
||||||
@ -289,20 +283,20 @@ void MobManager::giveEventReward(CNSocket* sock, Player* player) {
|
|||||||
|
|
||||||
// which crate to drop
|
// which crate to drop
|
||||||
int crateId;
|
int crateId;
|
||||||
switch (settings::EVENTMODE)
|
switch (settings::EVENTMODE)
|
||||||
{
|
{
|
||||||
// knishmas
|
// knishmas
|
||||||
case 1: crateId = 1187; break;
|
case 1: crateId = 1187; break;
|
||||||
// halloween
|
// halloween
|
||||||
case 2: crateId = 1181; break;
|
case 2: crateId = 1181; break;
|
||||||
// spring
|
// spring
|
||||||
case 3: crateId = 1126; break;
|
case 3: crateId = 1126; break;
|
||||||
// what
|
// what
|
||||||
default:
|
default:
|
||||||
std::cout << "[WARN] Unknown event Id " << settings::EVENTMODE << std::endl;
|
std::cout << "[WARN] Unknown event Id " << settings::EVENTMODE << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
item->sItem.iType = 9;
|
item->sItem.iType = 9;
|
||||||
item->sItem.iID = crateId;
|
item->sItem.iID = crateId;
|
||||||
item->sItem.iOpt = 1;
|
item->sItem.iOpt = 1;
|
||||||
@ -315,33 +309,33 @@ void MobManager::giveEventReward(CNSocket* sock, Player* player) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int MobManager::hitMob(CNSocket *sock, Mob *mob, int damage) {
|
int MobManager::hitMob(CNSocket *sock, Mob *mob, int damage) {
|
||||||
// cannot kill mobs multiple times; cannot harm retreating mobs
|
// cannot kill mobs multiple times; cannot harm retreating mobs
|
||||||
if (mob->state != MobState::ROAMING && mob->state != MobState::COMBAT) {
|
if (mob->state != MobState::ROAMING && mob->state != MobState::COMBAT) {
|
||||||
return 0; // no damage
|
return 0; // no damage
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mob->state == MobState::ROAMING) {
|
if (mob->state == MobState::ROAMING) {
|
||||||
assert(mob->target == nullptr);
|
assert(mob->target == nullptr);
|
||||||
mob->target = sock;
|
mob->target = sock;
|
||||||
mob->state = MobState::COMBAT;
|
mob->state = MobState::COMBAT;
|
||||||
mob->nextMovement = getTime();
|
mob->nextMovement = getTime();
|
||||||
mob->nextAttack = 0;
|
mob->nextAttack = 0;
|
||||||
|
|
||||||
mob->roamX = mob->appearanceData.iX;
|
mob->roamX = mob->appearanceData.iX;
|
||||||
mob->roamY = mob->appearanceData.iY;
|
mob->roamY = mob->appearanceData.iY;
|
||||||
mob->roamZ = mob->appearanceData.iZ;
|
mob->roamZ = mob->appearanceData.iZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
mob->appearanceData.iHP -= damage;
|
mob->appearanceData.iHP -= damage;
|
||||||
|
|
||||||
// wake up sleeping monster
|
// wake up sleeping monster
|
||||||
// TODO: remove client-side bit somehow
|
// TODO: remove client-side bit somehow
|
||||||
mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ;
|
mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ;
|
||||||
|
|
||||||
if (mob->appearanceData.iHP <= 0)
|
if (mob->appearanceData.iHP <= 0)
|
||||||
killMob(mob->target, mob);
|
killMob(mob->target, mob);
|
||||||
|
|
||||||
return damage;
|
return damage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobManager::killMob(CNSocket *sock, Mob *mob) {
|
void MobManager::killMob(CNSocket *sock, Mob *mob) {
|
||||||
@ -349,14 +343,14 @@ void MobManager::killMob(CNSocket *sock, Mob *mob) {
|
|||||||
mob->target = nullptr;
|
mob->target = nullptr;
|
||||||
mob->appearanceData.iConditionBitFlag = 0;
|
mob->appearanceData.iConditionBitFlag = 0;
|
||||||
mob->killedTime = getTime(); // XXX: maybe introduce a shard-global time for each step?
|
mob->killedTime = getTime(); // XXX: maybe introduce a shard-global time for each step?
|
||||||
|
|
||||||
// check for the edge case where hitting the mob did not aggro it
|
// check for the edge case where hitting the mob did not aggro it
|
||||||
if (sock != nullptr) {
|
if (sock != nullptr) {
|
||||||
Player* plr = PlayerManager::getPlayer(sock);
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
if (plr == nullptr)
|
if (plr == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (plr->groupCnt == 1 && plr->iIDGroup == plr->iID) {
|
if (plr->groupCnt == 1 && plr->iIDGroup == plr->iID) {
|
||||||
giveReward(sock, mob);
|
giveReward(sock, mob);
|
||||||
MissionManager::mobKilled(sock, mob->appearanceData.iNPCType);
|
MissionManager::mobKilled(sock, mob->appearanceData.iNPCType);
|
||||||
|
@ -43,7 +43,7 @@ struct Mob : public BaseNPC {
|
|||||||
time_t nextAttack = 0;
|
time_t nextAttack = 0;
|
||||||
int roamX, roamY, roamZ;
|
int roamX, roamY, roamZ;
|
||||||
|
|
||||||
//drop
|
// drop
|
||||||
int dropType;
|
int dropType;
|
||||||
|
|
||||||
// temporary; until we're sure what's what
|
// temporary; until we're sure what's what
|
||||||
@ -129,7 +129,7 @@ namespace MobManager {
|
|||||||
int hitMob(CNSocket *sock, Mob *mob, int damage);
|
int hitMob(CNSocket *sock, Mob *mob, int damage);
|
||||||
void killMob(CNSocket *sock, Mob *mob);
|
void killMob(CNSocket *sock, Mob *mob);
|
||||||
void giveReward(CNSocket *sock, Mob *mob);
|
void giveReward(CNSocket *sock, Mob *mob);
|
||||||
sItemBase getReward(MobDrop *drop, MobDropChance *chance);
|
void getReward(sItemBase *reward, MobDrop *drop, MobDropChance *chance);
|
||||||
void giveEventReward(CNSocket* sock, Player* player);
|
void giveEventReward(CNSocket* sock, Player* player);
|
||||||
|
|
||||||
std::pair<int,int> lerp(int, int, int, int, int);
|
std::pair<int,int> lerp(int, int, int, int, int);
|
||||||
|
@ -336,7 +336,7 @@ void TableData::loadDrops() {
|
|||||||
for (nlohmann::json::iterator _crates = drop["CrateIDs"].begin(); _crates != drop["CrateIDs"].end(); _crates++) {
|
for (nlohmann::json::iterator _crates = drop["CrateIDs"].begin(); _crates != drop["CrateIDs"].end(); _crates++) {
|
||||||
toAdd.crateIDs.push_back((int)_crates.value());
|
toAdd.crateIDs.push_back((int)_crates.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
toAdd.dropChanceType = (int)drop["DropChance"];
|
toAdd.dropChanceType = (int)drop["DropChance"];
|
||||||
// Check if DropChance exists
|
// Check if DropChance exists
|
||||||
if (MobManager::MobDropChances.find(toAdd.dropChanceType) == MobManager::MobDropChances.end())
|
if (MobManager::MobDropChances.find(toAdd.dropChanceType) == MobManager::MobDropChances.end())
|
||||||
@ -354,7 +354,9 @@ void TableData::loadDrops() {
|
|||||||
toAdd.boosts = (int)drop["Boosts"];
|
toAdd.boosts = (int)drop["Boosts"];
|
||||||
MobManager::MobDrops[(int)drop["DropType"]] = toAdd;
|
MobManager::MobDrops[(int)drop["DropType"]] = toAdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "[INFO] Loaded " << MobManager::MobDrops.size() << " Mob Drop Types"<< std::endl;
|
std::cout << "[INFO] Loaded " << MobManager::MobDrops.size() << " Mob Drop Types"<< std::endl;
|
||||||
|
|
||||||
// Rarity Ratios
|
// Rarity Ratios
|
||||||
nlohmann::json rarities = dropData["RarityRatios"];
|
nlohmann::json rarities = dropData["RarityRatios"];
|
||||||
for (nlohmann::json::iterator _rarity = rarities.begin(); _rarity != rarities.end(); _rarity++) {
|
for (nlohmann::json::iterator _rarity = rarities.begin(); _rarity != rarities.end(); _rarity++) {
|
||||||
@ -365,6 +367,7 @@ void TableData::loadDrops() {
|
|||||||
}
|
}
|
||||||
ItemManager::RarityRatios[(int)rarity["Type"]] = toAdd;
|
ItemManager::RarityRatios[(int)rarity["Type"]] = toAdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crates
|
// Crates
|
||||||
nlohmann::json crates = dropData["Crates"];
|
nlohmann::json crates = dropData["Crates"];
|
||||||
for (nlohmann::json::iterator _crate = crates.begin(); _crate != crates.end(); _crate++) {
|
for (nlohmann::json::iterator _crate = crates.begin(); _crate != crates.end(); _crate++) {
|
||||||
@ -376,6 +379,7 @@ void TableData::loadDrops() {
|
|||||||
}
|
}
|
||||||
ItemManager::Crates[(int)crate["Id"]] = toAdd;
|
ItemManager::Crates[(int)crate["Id"]] = toAdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crate Items
|
// Crate Items
|
||||||
nlohmann::json items = dropData["Items"];
|
nlohmann::json items = dropData["Items"];
|
||||||
int itemCount = 0;
|
int itemCount = 0;
|
||||||
@ -383,28 +387,30 @@ void TableData::loadDrops() {
|
|||||||
auto item = _item.value();
|
auto item = _item.value();
|
||||||
std::pair<int32_t, int32_t> itemSetkey = std::make_pair((int)item["ItemSet"], (int)item["Rarity"]);
|
std::pair<int32_t, int32_t> itemSetkey = std::make_pair((int)item["ItemSet"], (int)item["Rarity"]);
|
||||||
std::pair<int32_t, int32_t> itemDataKey = std::make_pair((int)item["Id"], (int)item["Type"]);
|
std::pair<int32_t, int32_t> itemDataKey = std::make_pair((int)item["Id"], (int)item["Type"]);
|
||||||
|
|
||||||
if (ItemManager::ItemData.find(itemDataKey) == ItemManager::ItemData.end())
|
if (ItemManager::ItemData.find(itemDataKey) == ItemManager::ItemData.end())
|
||||||
{
|
{
|
||||||
char buff[255];
|
char buff[255];
|
||||||
sprintf(buff, "Unknown item with Id %d and Type %d", (int)item["Id"], (int)item["Type"]);
|
sprintf(buff, "Unknown item with Id %d and Type %d", (int)item["Id"], (int)item["Type"]);
|
||||||
throw TableException(std::string(buff));
|
throw TableException(std::string(buff));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::pair<int32_t, int32_t>, Item>::iterator toAdd = ItemManager::ItemData.find(itemDataKey);
|
std::map<std::pair<int32_t, int32_t>, Item>::iterator toAdd = ItemManager::ItemData.find(itemDataKey);
|
||||||
|
|
||||||
// if item collection doesn't exist, start a new one
|
// if item collection doesn't exist, start a new one
|
||||||
if (ItemManager::CrateItems.find(itemSetkey) == ItemManager::CrateItems.end()) {
|
if (ItemManager::CrateItems.find(itemSetkey) == ItemManager::CrateItems.end()) {
|
||||||
std::vector<std::map<std::pair<int32_t, int32_t>, Item>::iterator> vector;
|
std::vector<std::map<std::pair<int32_t, int32_t>, Item>::iterator> vector;
|
||||||
vector.push_back(toAdd);
|
vector.push_back(toAdd);
|
||||||
ItemManager::CrateItems[itemSetkey] = vector;
|
ItemManager::CrateItems[itemSetkey] = vector;
|
||||||
}
|
} else // else add a new element to existing collection
|
||||||
// else add a new element to existing collection
|
|
||||||
else
|
|
||||||
ItemManager::CrateItems[itemSetkey].push_back(toAdd);
|
ItemManager::CrateItems[itemSetkey].push_back(toAdd);
|
||||||
|
|
||||||
itemCount++;
|
itemCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "[INFO] Loaded " << ItemManager::Crates.size() << " Crates containing "
|
std::cout << "[INFO] Loaded " << ItemManager::Crates.size() << " Crates containing "
|
||||||
<<itemCount<<" items" << std::endl;
|
<< itemCount << " items" << std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& err) {
|
catch (const std::exception& err) {
|
||||||
std::cerr << "[WARN] Malformed drops.json file! Reason:" << err.what() << std::endl;
|
std::cerr << "[WARN] Malformed drops.json file! Reason:" << err.what() << std::endl;
|
||||||
|
@ -103,11 +103,15 @@ int main() {
|
|||||||
GroupManager::init();
|
GroupManager::init();
|
||||||
Database::open();
|
Database::open();
|
||||||
|
|
||||||
switch (settings::EVENTMODE)
|
switch (settings::EVENTMODE) {
|
||||||
{
|
case 0: break; // no event
|
||||||
case 1: std::cout << "[INFO] Event active. Hey, Hey It's Knishmas!" << std::endl; break;
|
case 1: std::cout << "[INFO] Event active. Hey, Hey It's Knishmas!" << std::endl; break;
|
||||||
case 2: std::cout << "[INFO] Event active. Wishing you a spook-tacular Halloween!" << std::endl; break;
|
case 2: std::cout << "[INFO] Event active. Wishing you a spook-tacular Halloween!" << std::endl; break;
|
||||||
case 3: std::cout << "[INFO] Event active. Have a very hoppy Easter!" << std::endl; break;
|
case 3: std::cout << "[INFO] Event active. Have a very hoppy Easter!" << std::endl; break;
|
||||||
|
default:
|
||||||
|
std::cout << "[FATAL] Unknown event set in config file." << std::endl;
|
||||||
|
terminate(0);
|
||||||
|
/* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "[INFO] Starting Server Threads..." << std::endl;
|
std::cout << "[INFO] Starting Server Threads..." << std::endl;
|
||||||
|
2
tdata
2
tdata
@ -1 +1 @@
|
|||||||
Subproject commit b9a74bd8145f093b7fa8aef8b74191ac672d3dd2
|
Subproject commit ab1dd0e4398a5b96a9449032aafaaf4e24800283
|
Loading…
Reference in New Issue
Block a user