2020-09-09 17:06:22 +00:00
|
|
|
#include "TableData.hpp"
|
|
|
|
#include "NPCManager.hpp"
|
2020-09-13 20:26:16 +00:00
|
|
|
#include "TransportManager.hpp"
|
2020-09-13 22:54:47 +00:00
|
|
|
#include "ItemManager.hpp"
|
2020-09-09 17:06:22 +00:00
|
|
|
#include "settings.hpp"
|
2020-09-09 19:09:01 +00:00
|
|
|
#include "MissionManager.hpp"
|
2020-09-16 23:43:48 +00:00
|
|
|
#include "MobManager.hpp"
|
2020-09-17 22:45:43 +00:00
|
|
|
#include "ChunkManager.hpp"
|
2020-09-25 05:35:27 +00:00
|
|
|
#include "NanoManager.hpp"
|
2020-09-09 19:09:01 +00:00
|
|
|
|
2020-09-09 17:06:22 +00:00
|
|
|
#include "contrib/JSON.hpp"
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
|
2020-10-03 15:21:36 +00:00
|
|
|
std::map<int32_t, std::vector<WarpLocation>> TableData::RunningSkywayRoutes;
|
2020-10-06 21:59:12 +00:00
|
|
|
std::map<int32_t, int> TableData::RunningNPCRotations;
|
2020-10-12 01:53:01 +00:00
|
|
|
std::map<int32_t, int> TableData::RunningNPCMapNumbers;
|
2020-10-07 17:29:59 +00:00
|
|
|
std::map<int32_t, BaseNPC*> TableData::RunningMobs;
|
2020-11-08 08:42:49 +00:00
|
|
|
std::map<int32_t, BaseNPC*> TableData::RunningEggs;
|
2020-10-03 02:05:20 +00:00
|
|
|
|
2020-10-16 19:47:43 +00:00
|
|
|
class TableException : public std::exception {
|
|
|
|
public:
|
|
|
|
std::string msg;
|
|
|
|
|
|
|
|
TableException(std::string m) : std::exception() { msg = m; }
|
|
|
|
|
|
|
|
const char *what() const throw() { return msg.c_str(); }
|
|
|
|
};
|
|
|
|
|
2020-09-09 19:09:01 +00:00
|
|
|
void TableData::init() {
|
2020-09-24 22:36:25 +00:00
|
|
|
int32_t nextId = 0;
|
2020-09-09 17:06:22 +00:00
|
|
|
|
|
|
|
// load NPCs from NPC.json
|
|
|
|
try {
|
|
|
|
std::ifstream inFile(settings::NPCJSON);
|
|
|
|
nlohmann::json npcData;
|
|
|
|
|
|
|
|
// read file into json
|
|
|
|
inFile >> npcData;
|
2020-11-23 23:45:28 +00:00
|
|
|
npcData = npcData["NPCs"];
|
2020-09-16 23:43:48 +00:00
|
|
|
for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) {
|
|
|
|
auto npc = _npc.value();
|
2020-10-13 03:42:47 +00:00
|
|
|
int instanceID = npc.find("mapNum") == npc.end() ? INSTANCE_OVERWORLD : (int)npc["mapNum"];
|
2020-10-12 01:53:01 +00:00
|
|
|
BaseNPC *tmp = new BaseNPC(npc["x"], npc["y"], npc["z"], npc["angle"], instanceID, npc["id"], nextId);
|
2020-09-14 13:53:48 +00:00
|
|
|
|
2020-09-24 22:36:25 +00:00
|
|
|
NPCManager::NPCs[nextId] = tmp;
|
2020-11-18 00:07:04 +00:00
|
|
|
NPCManager::updateNPCPosition(nextId, npc["x"], npc["y"], npc["z"], instanceID, npc["angle"]);
|
2020-09-24 22:36:25 +00:00
|
|
|
nextId++;
|
2020-09-09 17:06:22 +00:00
|
|
|
|
2020-09-16 23:43:48 +00:00
|
|
|
if (npc["id"] == 641 || npc["id"] == 642)
|
2020-10-13 03:42:47 +00:00
|
|
|
NPCManager::RespawnPoints.push_back({ npc["x"], npc["y"], ((int)npc["z"]) + RESURRECT_HEIGHT, instanceID });
|
2020-09-09 17:06:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const std::exception& err) {
|
2020-10-18 02:13:33 +00:00
|
|
|
std::cerr << "[FATAL] Malformed NPCs.json file! Reason:" << err.what() << std::endl;
|
|
|
|
terminate(0);
|
2020-09-09 17:06:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// load everything else from xdttable
|
2020-09-09 22:31:09 +00:00
|
|
|
std::cout << "[INFO] Parsing xdt.json..." << std::endl;
|
2020-09-09 19:09:01 +00:00
|
|
|
std::ifstream infile(settings::XDTJSON);
|
|
|
|
nlohmann::json xdtData;
|
2020-09-09 17:06:22 +00:00
|
|
|
|
2020-09-09 19:09:01 +00:00
|
|
|
// read file into json
|
|
|
|
infile >> xdtData;
|
2020-09-09 17:06:22 +00:00
|
|
|
|
2020-09-24 22:36:25 +00:00
|
|
|
// data we'll need for summoned mobs
|
|
|
|
NPCManager::NPCData = xdtData["m_pNpcTable"]["m_pNpcData"];
|
|
|
|
|
2020-09-09 19:09:01 +00:00
|
|
|
try {
|
2020-09-09 22:31:09 +00:00
|
|
|
// load warps
|
2020-09-09 17:06:22 +00:00
|
|
|
nlohmann::json warpData = xdtData["m_pInstanceTable"]["m_pWarpData"];
|
|
|
|
|
2020-09-16 23:43:48 +00:00
|
|
|
for (nlohmann::json::iterator _warp = warpData.begin(); _warp != warpData.end(); _warp++) {
|
|
|
|
auto warp = _warp.value();
|
2020-10-12 01:53:01 +00:00
|
|
|
WarpLocation warpLoc = { warp["m_iToX"], warp["m_iToY"], warp["m_iToZ"], warp["m_iToMapNum"], warp["m_iIsInstance"], warp["m_iLimit_TaskID"], warp["m_iNpcNumber"] };
|
2020-09-16 23:43:48 +00:00
|
|
|
int warpID = warp["m_iWarpNumber"];
|
2020-09-09 17:06:22 +00:00
|
|
|
NPCManager::Warps[warpID] = warpLoc;
|
|
|
|
}
|
|
|
|
|
2020-09-10 16:40:38 +00:00
|
|
|
std::cout << "[INFO] Populated " << NPCManager::Warps.size() << " Warps" << std::endl;
|
2020-09-09 19:09:01 +00:00
|
|
|
|
2020-09-13 20:26:16 +00:00
|
|
|
// load transport routes and locations
|
|
|
|
nlohmann::json transRouteData = xdtData["m_pTransportationTable"]["m_pTransportationData"];
|
|
|
|
nlohmann::json transLocData = xdtData["m_pTransportationTable"]["m_pTransportationWarpLocation"];
|
|
|
|
|
2020-09-16 23:43:48 +00:00
|
|
|
for (nlohmann::json::iterator _tLoc = transLocData.begin(); _tLoc != transLocData.end(); _tLoc++) {
|
|
|
|
auto tLoc = _tLoc.value();
|
|
|
|
TransportLocation transLoc = { tLoc["m_iNPCID"], tLoc["m_iXpos"], tLoc["m_iYpos"], tLoc["m_iZpos"] };
|
|
|
|
TransportManager::Locations[tLoc["m_iLocationID"]] = transLoc;
|
2020-09-13 20:26:16 +00:00
|
|
|
}
|
2020-09-24 22:36:25 +00:00
|
|
|
std::cout << "[INFO] Loaded " << TransportManager::Locations.size() << " S.C.A.M.P.E.R. locations" << std::endl;
|
2020-09-13 20:26:16 +00:00
|
|
|
|
2020-09-16 23:43:48 +00:00
|
|
|
for (nlohmann::json::iterator _tRoute = transRouteData.begin(); _tRoute != transRouteData.end(); _tRoute++) {
|
|
|
|
auto tRoute = _tRoute.value();
|
|
|
|
TransportRoute transRoute = { tRoute["m_iMoveType"], tRoute["m_iStartLocation"], tRoute["m_iEndLocation"],
|
|
|
|
tRoute["m_iCost"] , tRoute["m_iSpeed"], tRoute["m_iRouteNum"] };
|
|
|
|
TransportManager::Routes[tRoute["m_iVehicleID"]] = transRoute;
|
2020-09-13 20:26:16 +00:00
|
|
|
}
|
|
|
|
std::cout << "[INFO] Loaded " << TransportManager::Routes.size() << " transportation routes" << std::endl;
|
|
|
|
|
2020-09-10 13:01:35 +00:00
|
|
|
// load mission-related data
|
2020-09-09 19:09:01 +00:00
|
|
|
nlohmann::json tasks = xdtData["m_pMissionTable"]["m_pMissionData"];
|
|
|
|
|
|
|
|
for (auto _task = tasks.begin(); _task != tasks.end(); _task++) {
|
|
|
|
auto task = _task.value();
|
|
|
|
|
|
|
|
// rewards
|
|
|
|
if (task["m_iSUReward"] != 0) {
|
2020-09-10 16:40:38 +00:00
|
|
|
auto _rew = xdtData["m_pMissionTable"]["m_pRewardData"][(int)task["m_iSUReward"]];
|
|
|
|
Reward *rew = new Reward(_rew["m_iMissionRewardID"], _rew["m_iMissionRewarItemType"],
|
|
|
|
_rew["m_iMissionRewardItemID"], _rew["m_iCash"], _rew["m_iFusionMatter"]);
|
2020-09-09 19:09:01 +00:00
|
|
|
|
|
|
|
MissionManager::Rewards[task["m_iHTaskID"]] = rew;
|
|
|
|
}
|
2020-09-09 22:31:09 +00:00
|
|
|
|
2020-09-10 16:40:38 +00:00
|
|
|
// everything else lol. see TaskData comment.
|
|
|
|
MissionManager::Tasks[task["m_iHTaskID"]] = new TaskData(task);
|
2020-09-09 19:09:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "[INFO] Loaded mission-related data" << std::endl;
|
2020-09-13 22:54:47 +00:00
|
|
|
|
2020-09-14 04:25:14 +00:00
|
|
|
// load all item data. i'm sorry. it has to be done
|
2020-09-14 05:27:20 +00:00
|
|
|
const char* setNames[12] = { "m_pBackItemTable", "m_pFaceItemTable", "m_pGlassItemTable", "m_pHatItemTable",
|
2020-09-14 04:25:14 +00:00
|
|
|
"m_pHeadItemTable", "m_pPantsItemTable", "m_pShirtsItemTable", "m_pShoesItemTable", "m_pWeaponItemTable",
|
2020-09-14 05:27:20 +00:00
|
|
|
"m_pVehicleItemTable", "m_pGeneralItemTable", "m_pChestItemTable" };
|
2020-09-14 04:25:14 +00:00
|
|
|
nlohmann::json itemSet;
|
2020-09-14 05:27:20 +00:00
|
|
|
for (int i = 0; i < 12; i++) {
|
2020-09-14 04:25:14 +00:00
|
|
|
itemSet = xdtData[setNames[i]]["m_pItemData"];
|
2020-09-16 23:43:48 +00:00
|
|
|
for (nlohmann::json::iterator _item = itemSet.begin(); _item != itemSet.end(); _item++) {
|
|
|
|
auto item = _item.value();
|
2020-09-19 20:22:28 +00:00
|
|
|
int typeOverride = getItemType(i); // used for special cases where iEquipLoc doesn't indicate item type
|
2020-09-17 16:59:30 +00:00
|
|
|
ItemManager::ItemData[std::pair<int32_t, int32_t>(item["m_iItemNumber"], typeOverride != -1 ? typeOverride : (int)item["m_iEquipLoc"])]
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
= { item["m_iTradeAble"] == 1, item["m_iSellAble"] == 1, item["m_iItemPrice"], item["m_iItemSellPrice"], item["m_iStackNumber"], i > 9 ? 0 : (int)item["m_iMinReqLev"], i > 9 ? 1 : (int)item["m_iRarity"], i > 9 ? 0 : (int)item["m_iPointRat"], i > 9 ? 0 : (int)item["m_iGroupRat"], i > 9 ? 0 : (int)item["m_iDefenseRat"], i > 9 ? 0 : (int)item["m_iReqSex"] };
|
2020-09-16 23:43:48 +00:00
|
|
|
}
|
2020-09-14 04:25:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "[INFO] Loaded " << ItemManager::ItemData.size() << " items" << std::endl;
|
|
|
|
|
2020-09-23 19:44:27 +00:00
|
|
|
// load player limits from m_pAvatarTable.m_pAvatarGrowData
|
2020-10-05 00:03:13 +00:00
|
|
|
|
2020-09-23 19:44:27 +00:00
|
|
|
nlohmann::json growth = xdtData["m_pAvatarTable"]["m_pAvatarGrowData"];
|
|
|
|
|
2020-09-26 01:48:45 +00:00
|
|
|
for (int i = 0; i < 37; i++) {
|
2020-09-23 19:44:27 +00:00
|
|
|
MissionManager::AvatarGrowth[i] = growth[i];
|
|
|
|
}
|
|
|
|
|
2020-09-13 22:54:47 +00:00
|
|
|
// load vendor listings
|
|
|
|
nlohmann::json listings = xdtData["m_pVendorTable"]["m_pItemData"];
|
|
|
|
|
2020-09-16 23:43:48 +00:00
|
|
|
for (nlohmann::json::iterator _lst = listings.begin(); _lst != listings.end(); _lst++) {
|
|
|
|
auto lst = _lst.value();
|
|
|
|
VendorListing vListing = { lst["m_iSortNumber"], lst["m_iItemType"], lst["m_iitemID"] };
|
|
|
|
ItemManager::VendorTables[lst["m_iNpcNumber"]].push_back(vListing);
|
2020-09-13 22:54:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "[INFO] Loaded " << ItemManager::VendorTables.size() << " vendor tables" << std::endl;
|
2020-09-16 00:30:01 +00:00
|
|
|
|
|
|
|
// load crocpot entries
|
|
|
|
nlohmann::json crocs = xdtData["m_pCombiningTable"]["m_pCombiningData"];
|
|
|
|
|
|
|
|
for (nlohmann::json::iterator croc = crocs.begin(); croc != crocs.end(); croc++) {
|
|
|
|
CrocPotEntry crocEntry = { croc.value()["m_iStatConstant"], croc.value()["m_iLookConstant"], croc.value()["m_fLevelGapStandard"],
|
|
|
|
croc.value()["m_fSameGrade"], croc.value()["m_fOneGrade"], croc.value()["m_fTwoGrade"], croc.value()["m_fThreeGrade"] };
|
|
|
|
ItemManager::CrocPotTable[croc.value()["m_iLevelGap"]] = crocEntry;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "[INFO] Loaded " << ItemManager::CrocPotTable.size() << " croc pot value sets" << std::endl;
|
2020-09-25 05:35:27 +00:00
|
|
|
|
2020-10-19 17:26:14 +00:00
|
|
|
// load nano info
|
2020-09-25 05:35:27 +00:00
|
|
|
nlohmann::json nanoInfo = xdtData["m_pNanoTable"]["m_pNanoData"];
|
|
|
|
for (nlohmann::json::iterator _nano = nanoInfo.begin(); _nano != nanoInfo.end(); _nano++) {
|
|
|
|
auto nano = _nano.value();
|
|
|
|
NanoData nanoData;
|
|
|
|
nanoData.style = nano["m_iStyle"];
|
|
|
|
NanoManager::NanoTable[nano["m_iNanoNumber"]] = nanoData;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "[INFO] Loaded " << NanoManager::NanoTable.size() << " nanos" << std::endl;
|
2020-10-24 20:28:35 +00:00
|
|
|
|
|
|
|
nlohmann::json nanoTuneInfo = xdtData["m_pNanoTable"]["m_pNanoTuneData"];
|
|
|
|
for (nlohmann::json::iterator _nano = nanoTuneInfo.begin(); _nano != nanoTuneInfo.end(); _nano++) {
|
|
|
|
auto nano = _nano.value();
|
|
|
|
NanoTuning nanoData;
|
|
|
|
nanoData.reqItems = nano["m_iReqItemID"];
|
|
|
|
nanoData.reqItemCount = nano["m_iReqItemCount"];
|
|
|
|
NanoManager::NanoTunings[nano["m_iSkillID"]] = nanoData;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "[INFO] Loaded " << NanoManager::NanoTable.size() << " nano tunings" << std::endl;
|
|
|
|
|
2020-09-09 17:06:22 +00:00
|
|
|
}
|
|
|
|
catch (const std::exception& err) {
|
2020-10-18 02:13:33 +00:00
|
|
|
std::cerr << "[FATAL] Malformed xdt.json file! Reason:" << err.what() << std::endl;
|
|
|
|
terminate(0);
|
2020-09-09 17:06:22 +00:00
|
|
|
}
|
2020-09-16 23:43:48 +00:00
|
|
|
|
|
|
|
// load temporary mob dump
|
|
|
|
try {
|
|
|
|
std::ifstream inFile(settings::MOBJSON);
|
2020-11-24 00:28:22 +00:00
|
|
|
nlohmann::json npcData, groupData;
|
2020-09-16 23:43:48 +00:00
|
|
|
|
|
|
|
// read file into json
|
|
|
|
inFile >> npcData;
|
2020-11-24 00:28:22 +00:00
|
|
|
groupData = npcData["groups"];
|
2020-11-23 23:45:28 +00:00
|
|
|
npcData = npcData["mobs"];
|
2020-09-16 23:43:48 +00:00
|
|
|
|
2020-11-24 00:28:22 +00:00
|
|
|
// single mobs
|
2020-09-16 23:43:48 +00:00
|
|
|
for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) {
|
|
|
|
auto npc = _npc.value();
|
2020-09-24 22:36:25 +00:00
|
|
|
auto td = NPCManager::NPCData[(int)npc["iNPCType"]];
|
2020-10-12 16:55:41 +00:00
|
|
|
uint64_t instanceID = npc.find("iMapNum") == npc.end() ? INSTANCE_OVERWORLD : (int)npc["iMapNum"];
|
2020-11-15 07:06:29 +00:00
|
|
|
|
2020-10-12 01:53:01 +00:00
|
|
|
Mob *tmp = new Mob(npc["iX"], npc["iY"], npc["iZ"], npc["iAngle"], instanceID, npc["iNPCType"], npc["iHP"], td, nextId);
|
2020-09-16 23:43:48 +00:00
|
|
|
|
2020-09-24 22:36:25 +00:00
|
|
|
NPCManager::NPCs[nextId] = tmp;
|
|
|
|
MobManager::Mobs[nextId] = (Mob*)NPCManager::NPCs[nextId];
|
2020-11-18 00:07:04 +00:00
|
|
|
NPCManager::updateNPCPosition(nextId, npc["iX"], npc["iY"], npc["iZ"], instanceID, npc["iAngle"]);
|
2020-09-16 23:43:48 +00:00
|
|
|
|
2020-11-24 00:28:22 +00:00
|
|
|
nextId++;
|
|
|
|
}
|
2020-11-15 07:06:29 +00:00
|
|
|
|
2020-11-24 00:28:22 +00:00
|
|
|
// mob groups
|
|
|
|
// single mobs
|
|
|
|
for (nlohmann::json::iterator _group = groupData.begin(); _group != groupData.end(); _group++) {
|
|
|
|
auto leader = _group.value();
|
|
|
|
auto td = NPCManager::NPCData[(int)leader["iNPCType"]];
|
|
|
|
uint64_t instanceID = leader.find("iMapNum") == leader.end() ? INSTANCE_OVERWORLD : (int)leader["iMapNum"];
|
|
|
|
|
|
|
|
Mob* tmp = new Mob(leader["iX"], leader["iY"], leader["iZ"], leader["iAngle"], instanceID, leader["iNPCType"], leader["iHP"], td, nextId);
|
|
|
|
|
|
|
|
NPCManager::NPCs[nextId] = tmp;
|
|
|
|
MobManager::Mobs[nextId] = (Mob*)NPCManager::NPCs[nextId];
|
|
|
|
NPCManager::updateNPCPosition(nextId, leader["iX"], leader["iY"], leader["iZ"], instanceID, leader["iAngle"]);
|
|
|
|
|
|
|
|
tmp->groupLeader = nextId;
|
2020-11-15 07:06:29 +00:00
|
|
|
|
2020-09-24 22:36:25 +00:00
|
|
|
nextId++;
|
2020-11-24 00:28:22 +00:00
|
|
|
|
|
|
|
auto followers = leader["aFollowers"];
|
|
|
|
if (followers.size() < 5) {
|
|
|
|
int followerCount = 0;
|
|
|
|
for (nlohmann::json::iterator _fol = followers.begin(); _fol != followers.end(); _fol++) {
|
|
|
|
auto follower = _fol.value();
|
|
|
|
auto tdFol = NPCManager::NPCData[(int)follower["iNPCType"]];
|
|
|
|
Mob* tmpFol = new Mob((int)leader["iX"] + (int)follower["iOffsetX"], (int)leader["iY"] + (int)follower["iOffsetY"], leader["iZ"], leader["iAngle"], instanceID, follower["iNPCType"], follower["iHP"], tdFol, nextId);
|
|
|
|
|
|
|
|
NPCManager::NPCs[nextId] = tmpFol;
|
|
|
|
MobManager::Mobs[nextId] = (Mob*)NPCManager::NPCs[nextId];
|
|
|
|
NPCManager::updateNPCPosition(nextId, (int)leader["iX"] + (int)follower["iOffsetX"], (int)leader["iY"] + (int)follower["iOffsetY"], leader["iZ"], instanceID, leader["iAngle"]);
|
|
|
|
|
|
|
|
tmpFol->offsetX = follower.find("iOffsetX") == follower.end() ? 0 : (int)follower["iOffsetX"];
|
|
|
|
tmpFol->offsetY = follower.find("iOffsetY") == follower.end() ? 0 : (int)follower["iOffsetY"];
|
|
|
|
tmpFol->groupLeader = tmp->appearanceData.iNPC_ID;
|
|
|
|
tmp->groupMember[followerCount++] = nextId;
|
|
|
|
|
|
|
|
nextId++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::cout << "[WARN] Mob group leader with ID " << nextId << " has too many followers (" << followers.size() << ")\n";
|
|
|
|
}
|
2020-09-16 23:43:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "[INFO] Populated " << NPCManager::NPCs.size() << " NPCs" << std::endl;
|
|
|
|
}
|
|
|
|
catch (const std::exception& err) {
|
2020-10-18 02:13:33 +00:00
|
|
|
std::cerr << "[FATAL] Malformed mobs.json file! Reason:" << err.what() << std::endl;
|
|
|
|
terminate(0);
|
2020-09-16 23:43:48 +00:00
|
|
|
}
|
2020-09-24 22:36:25 +00:00
|
|
|
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
loadDrops();
|
|
|
|
|
2020-11-09 09:34:11 +00:00
|
|
|
loadEggs(&nextId);
|
2020-10-24 19:48:55 +00:00
|
|
|
|
2020-10-13 19:44:43 +00:00
|
|
|
loadPaths(&nextId); // load paths
|
|
|
|
|
2020-10-07 17:29:59 +00:00
|
|
|
loadGruntwork(&nextId);
|
2020-10-06 19:53:21 +00:00
|
|
|
|
2020-09-24 22:36:25 +00:00
|
|
|
NPCManager::nextId = nextId;
|
2020-09-09 19:09:01 +00:00
|
|
|
}
|
|
|
|
|
2020-09-19 20:22:28 +00:00
|
|
|
/*
|
2020-09-25 21:05:36 +00:00
|
|
|
* Some item categories either don't possess iEquipLoc or use a different value for item type.
|
|
|
|
*/
|
2020-09-17 16:59:30 +00:00
|
|
|
int TableData::getItemType(int itemSet) {
|
|
|
|
int overriden;
|
2020-10-19 17:26:14 +00:00
|
|
|
switch (itemSet) {
|
2020-09-19 20:22:28 +00:00
|
|
|
case 11: // Chest items don't have iEquipLoc and are type 9.
|
2020-09-17 16:59:30 +00:00
|
|
|
overriden = 9;
|
|
|
|
break;
|
2020-09-19 20:22:28 +00:00
|
|
|
case 10: // General items don't have iEquipLoc and are type 7.
|
2020-09-17 16:59:30 +00:00
|
|
|
overriden = 7;
|
|
|
|
break;
|
2020-09-19 20:22:28 +00:00
|
|
|
case 9: // Vehicles have iEquipLoc 8, but type 10.
|
2020-09-17 16:59:30 +00:00
|
|
|
overriden = 10;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
overriden = -1;
|
|
|
|
}
|
|
|
|
return overriden;
|
|
|
|
}
|
2020-09-17 09:04:00 +00:00
|
|
|
|
2020-09-22 01:03:48 +00:00
|
|
|
/*
|
|
|
|
* Load paths from paths JSON.
|
|
|
|
*/
|
2020-09-25 18:42:31 +00:00
|
|
|
void TableData::loadPaths(int* nextId) {
|
2020-09-22 01:03:48 +00:00
|
|
|
try {
|
|
|
|
std::ifstream inFile(settings::PATHJSON);
|
|
|
|
nlohmann::json pathData;
|
|
|
|
|
|
|
|
// read file into json
|
|
|
|
inFile >> pathData;
|
|
|
|
|
|
|
|
// skyway paths
|
|
|
|
nlohmann::json pathDataSkyway = pathData["skyway"];
|
|
|
|
for (nlohmann::json::iterator skywayPath = pathDataSkyway.begin(); skywayPath != pathDataSkyway.end(); skywayPath++) {
|
2020-09-24 14:14:37 +00:00
|
|
|
constructPathSkyway(skywayPath);
|
2020-09-22 01:03:48 +00:00
|
|
|
}
|
|
|
|
std::cout << "[INFO] Loaded " << TransportManager::SkywayPaths.size() << " skyway paths" << std::endl;
|
2020-09-24 14:14:37 +00:00
|
|
|
|
2020-09-25 18:42:31 +00:00
|
|
|
// slider circuit
|
2020-10-20 14:40:50 +00:00
|
|
|
int stops = 0;
|
|
|
|
int pos = 0;
|
2020-09-25 18:42:31 +00:00
|
|
|
nlohmann::json pathDataSlider = pathData["slider"];
|
|
|
|
for (nlohmann::json::iterator _sliderPoint = pathDataSlider.begin(); _sliderPoint != pathDataSlider.end(); _sliderPoint++) {
|
|
|
|
auto sliderPoint = _sliderPoint.value();
|
2020-10-20 14:40:50 +00:00
|
|
|
if (sliderPoint["stop"]) { // check if this point in the circuit is a stop
|
2020-09-25 18:42:31 +00:00
|
|
|
// spawn a slider
|
2020-10-20 22:55:58 +00:00
|
|
|
BaseNPC* slider = new BaseNPC(sliderPoint["iX"], sliderPoint["iY"], sliderPoint["iZ"], 0, INSTANCE_OVERWORLD, 1, (*nextId)++, NPC_BUS);
|
|
|
|
NPCManager::NPCs[slider->appearanceData.iNPC_ID] = slider;
|
2020-11-18 00:07:04 +00:00
|
|
|
NPCManager::updateNPCPosition(slider->appearanceData.iNPC_ID, slider->appearanceData.iX, slider->appearanceData.iY, slider->appearanceData.iZ, INSTANCE_OVERWORLD, 0);
|
2020-10-20 22:55:58 +00:00
|
|
|
// set slider path to a rotation of the circuit
|
|
|
|
constructPathSlider(pathDataSlider, pos, slider->appearanceData.iNPC_ID);
|
|
|
|
|
2020-10-20 14:40:50 +00:00
|
|
|
stops++;
|
2020-09-25 18:42:31 +00:00
|
|
|
}
|
2020-10-20 14:40:50 +00:00
|
|
|
pos++;
|
2020-09-25 18:42:31 +00:00
|
|
|
}
|
|
|
|
|
2020-09-24 14:14:37 +00:00
|
|
|
// npc paths
|
|
|
|
nlohmann::json pathDataNPC = pathData["npc"];
|
|
|
|
for (nlohmann::json::iterator npcPath = pathDataNPC.begin(); npcPath != pathDataNPC.end(); npcPath++) {
|
|
|
|
constructPathNPC(npcPath);
|
|
|
|
}
|
2020-10-13 19:44:43 +00:00
|
|
|
|
|
|
|
// mob paths
|
|
|
|
pathDataNPC = pathData["mob"];
|
|
|
|
for (nlohmann::json::iterator npcPath = pathDataNPC.begin(); npcPath != pathDataNPC.end(); npcPath++) {
|
|
|
|
for (auto& pair : MobManager::Mobs) {
|
|
|
|
if (pair.second->appearanceData.iNPCType == npcPath.value()["iNPCType"]) {
|
|
|
|
std::cout << "[INFO] Using static path for mob " << pair.second->appearanceData.iNPCType << " with ID " << pair.first << std::endl;
|
|
|
|
|
|
|
|
auto firstPoint = npcPath.value()["points"][0];
|
|
|
|
if (firstPoint["iX"] != pair.second->spawnX || firstPoint["iY"] != pair.second->spawnY) {
|
|
|
|
std::cout << "[FATAL] The first point of the route for mob " << pair.first <<
|
|
|
|
" (type " << pair.second->appearanceData.iNPCType << ") does not correspond with its spawn point." << std::endl;
|
|
|
|
terminate(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
constructPathNPC(npcPath, pair.first);
|
|
|
|
pair.second->staticPath = true;
|
|
|
|
break; // only one NPC per path
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-24 14:14:37 +00:00
|
|
|
std::cout << "[INFO] Loaded " << TransportManager::NPCQueues.size() << " NPC paths" << std::endl;
|
2020-09-22 01:03:48 +00:00
|
|
|
}
|
|
|
|
catch (const std::exception& err) {
|
2020-10-18 02:13:33 +00:00
|
|
|
std::cerr << "[FATAL] Malformed paths.json file! Reason:" << err.what() << std::endl;
|
|
|
|
terminate(0);
|
2020-09-22 01:03:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
/*
|
|
|
|
* Load drops data from JSON.
|
|
|
|
* This has to be called after reading xdt because it reffers to ItemData!!!
|
|
|
|
*/
|
|
|
|
void TableData::loadDrops() {
|
|
|
|
try {
|
|
|
|
std::ifstream inFile(settings::DROPSJSON);
|
|
|
|
nlohmann::json dropData;
|
|
|
|
|
|
|
|
// read file into json
|
|
|
|
inFile >> dropData;
|
|
|
|
|
|
|
|
// MobDropChances
|
|
|
|
nlohmann::json mobDropChances = dropData["MobDropChances"];
|
|
|
|
for (nlohmann::json::iterator _dropChance = mobDropChances.begin(); _dropChance != mobDropChances.end(); _dropChance++) {
|
|
|
|
auto dropChance = _dropChance.value();
|
|
|
|
MobDropChance toAdd = {};
|
|
|
|
toAdd.dropChance = (int)dropChance["DropChance"];
|
|
|
|
for (nlohmann::json::iterator _cratesRatio = dropChance["CratesRatio"].begin(); _cratesRatio != dropChance["CratesRatio"].end(); _cratesRatio++) {
|
|
|
|
toAdd.cratesRatio.push_back((int)_cratesRatio.value());
|
|
|
|
}
|
|
|
|
MobManager::MobDropChances[(int)dropChance["Type"]] = toAdd;
|
|
|
|
}
|
|
|
|
|
|
|
|
// MobDrops
|
|
|
|
nlohmann::json mobDrops = dropData["MobDrops"];
|
|
|
|
for (nlohmann::json::iterator _drop = mobDrops.begin(); _drop != mobDrops.end(); _drop++) {
|
|
|
|
auto drop = _drop.value();
|
|
|
|
MobDrop toAdd = {};
|
|
|
|
for (nlohmann::json::iterator _crates = drop["CrateIDs"].begin(); _crates != drop["CrateIDs"].end(); _crates++) {
|
|
|
|
toAdd.crateIDs.push_back((int)_crates.value());
|
|
|
|
}
|
2020-10-17 23:19:05 +00:00
|
|
|
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
toAdd.dropChanceType = (int)drop["DropChance"];
|
|
|
|
// Check if DropChance exists
|
2020-10-19 17:26:14 +00:00
|
|
|
if (MobManager::MobDropChances.find(toAdd.dropChanceType) == MobManager::MobDropChances.end()) {
|
2020-10-16 19:47:43 +00:00
|
|
|
throw TableException(" MobDropChance not found: " + std::to_string((toAdd.dropChanceType)));
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
}
|
|
|
|
// Check if number of crates is correct
|
2020-10-19 17:26:14 +00:00
|
|
|
if (!(MobManager::MobDropChances[(int)drop["DropChance"]].cratesRatio.size() == toAdd.crateIDs.size())) {
|
2020-10-16 19:47:43 +00:00
|
|
|
throw TableException(" DropType " + std::to_string((int)drop["DropType"]) + " contains invalid number of crates");
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
toAdd.taros = (int)drop["Taros"];
|
|
|
|
toAdd.fm = (int)drop["FM"];
|
|
|
|
toAdd.boosts = (int)drop["Boosts"];
|
|
|
|
MobManager::MobDrops[(int)drop["DropType"]] = toAdd;
|
|
|
|
}
|
2020-10-17 23:19:05 +00:00
|
|
|
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
std::cout << "[INFO] Loaded " << MobManager::MobDrops.size() << " Mob Drop Types"<< std::endl;
|
2020-10-17 23:19:05 +00:00
|
|
|
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
// Rarity Ratios
|
|
|
|
nlohmann::json rarities = dropData["RarityRatios"];
|
|
|
|
for (nlohmann::json::iterator _rarity = rarities.begin(); _rarity != rarities.end(); _rarity++) {
|
|
|
|
auto rarity = _rarity.value();
|
|
|
|
std::vector<int> toAdd;
|
|
|
|
for (nlohmann::json::iterator _ratio = rarity["Ratio"].begin(); _ratio != rarity["Ratio"].end(); _ratio++){
|
|
|
|
toAdd.push_back((int)_ratio.value());
|
|
|
|
}
|
|
|
|
ItemManager::RarityRatios[(int)rarity["Type"]] = toAdd;
|
|
|
|
}
|
2020-10-17 23:19:05 +00:00
|
|
|
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
// Crates
|
|
|
|
nlohmann::json crates = dropData["Crates"];
|
|
|
|
for (nlohmann::json::iterator _crate = crates.begin(); _crate != crates.end(); _crate++) {
|
|
|
|
auto crate = _crate.value();
|
|
|
|
Crate toAdd;
|
|
|
|
toAdd.rarityRatioId = (int)crate["RarityRatio"];
|
|
|
|
for (nlohmann::json::iterator _itemSet = crate["ItemSets"].begin(); _itemSet != crate["ItemSets"].end(); _itemSet++) {
|
|
|
|
toAdd.itemSets.push_back((int)_itemSet.value());
|
|
|
|
}
|
|
|
|
ItemManager::Crates[(int)crate["Id"]] = toAdd;
|
|
|
|
}
|
2020-10-17 23:19:05 +00:00
|
|
|
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
// Crate Items
|
|
|
|
nlohmann::json items = dropData["Items"];
|
|
|
|
int itemCount = 0;
|
|
|
|
for (nlohmann::json::iterator _item = items.begin(); _item != items.end(); _item++) {
|
|
|
|
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> itemDataKey = std::make_pair((int)item["Id"], (int)item["Type"]);
|
2020-10-17 23:19:05 +00:00
|
|
|
|
2020-10-19 17:26:14 +00:00
|
|
|
if (ItemManager::ItemData.find(itemDataKey) == ItemManager::ItemData.end()) {
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
char buff[255];
|
|
|
|
sprintf(buff, "Unknown item with Id %d and Type %d", (int)item["Id"], (int)item["Type"]);
|
2020-10-16 19:47:43 +00:00
|
|
|
throw TableException(std::string(buff));
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
}
|
2020-10-17 23:19:05 +00:00
|
|
|
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
std::map<std::pair<int32_t, int32_t>, Item>::iterator toAdd = ItemManager::ItemData.find(itemDataKey);
|
2020-10-17 23:19:05 +00:00
|
|
|
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
// if item collection doesn't exist, start a new one
|
|
|
|
if (ItemManager::CrateItems.find(itemSetkey) == ItemManager::CrateItems.end()) {
|
|
|
|
std::vector<std::map<std::pair<int32_t, int32_t>, Item>::iterator> vector;
|
|
|
|
vector.push_back(toAdd);
|
|
|
|
ItemManager::CrateItems[itemSetkey] = vector;
|
2020-10-17 23:19:05 +00:00
|
|
|
} else // else add a new element to existing collection
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
ItemManager::CrateItems[itemSetkey].push_back(toAdd);
|
2020-10-17 23:19:05 +00:00
|
|
|
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
itemCount++;
|
|
|
|
}
|
|
|
|
|
2020-10-17 23:19:05 +00:00
|
|
|
std::cout << "[INFO] Loaded " << ItemManager::Crates.size() << " Crates containing "
|
|
|
|
<< itemCount << " items" << std::endl;
|
|
|
|
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
}
|
|
|
|
catch (const std::exception& err) {
|
2020-10-18 02:13:33 +00:00
|
|
|
std::cerr << "[FATAL] Malformed drops.json file! Reason:" << err.what() << std::endl;
|
|
|
|
terminate(0);
|
2020-10-24 19:48:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-09 09:34:11 +00:00
|
|
|
void TableData::loadEggs(int32_t* nextId) {
|
2020-10-24 19:48:55 +00:00
|
|
|
try {
|
|
|
|
std::ifstream inFile(settings::EGGSJSON);
|
|
|
|
nlohmann::json eggData;
|
|
|
|
|
|
|
|
// read file into json
|
|
|
|
inFile >> eggData;
|
|
|
|
|
|
|
|
// EggTypes
|
|
|
|
nlohmann::json eggTypes = eggData["EggTypes"];
|
|
|
|
for (nlohmann::json::iterator _eggType = eggTypes.begin(); _eggType != eggTypes.end(); _eggType++) {
|
|
|
|
auto eggType = _eggType.value();
|
|
|
|
EggType toAdd = {};
|
|
|
|
toAdd.dropCrateId = (int)eggType["DropCrateId"];
|
|
|
|
toAdd.effectId = (int)eggType["EffectId"];
|
|
|
|
toAdd.duration = (int)eggType["Duration"];
|
|
|
|
toAdd.regen= (int)eggType["Regen"];
|
|
|
|
NPCManager::EggTypes[(int)eggType["Id"]] = toAdd;
|
|
|
|
}
|
|
|
|
|
2020-11-09 09:34:11 +00:00
|
|
|
// Egg instances
|
|
|
|
auto eggs = eggData["Eggs"];
|
|
|
|
for (auto _egg = eggs.begin(); _egg != eggs.end(); _egg++) {
|
|
|
|
auto egg = _egg.value();
|
|
|
|
int id = (*nextId)++;
|
|
|
|
uint64_t instanceID = egg.find("iMapNum") == egg.end() ? INSTANCE_OVERWORLD : (int)egg["iMapNum"];
|
|
|
|
|
|
|
|
Egg* addEgg = new Egg((int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, (int)egg["iType"], id, false);
|
|
|
|
NPCManager::NPCs[id] = addEgg;
|
|
|
|
NPCManager::Eggs[id] = addEgg;
|
2020-11-18 00:07:04 +00:00
|
|
|
NPCManager::updateNPCPosition(id, (int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, 0);
|
2020-11-09 09:34:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "[INFO] Loaded " <<NPCManager::Eggs.size()<<" eggs" <<std::endl;
|
2020-10-24 19:48:55 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
catch (const std::exception& err) {
|
|
|
|
std::cerr << "[FATAL] Malformed eggs.json file! Reason:" << err.what() << std::endl;
|
|
|
|
terminate(0);
|
functional crates (no more plungers) (#133)
* FM, Taros and Boosts awards from killing mobs should be pretty
accurate now. A temporary formula for adjusting player/mob level gap is
implemented, but it will probably need to be adjusted in the future
* Mobs now drop correct crates
* Crates can be opened and give you correct items This includes
regular mob crates, world boss crates, mission crates, IZ race crates,
E.G.G.E.R.s, golden Eggs, and Event Crates. Keep in mind that neither
IZ races or golden Eggs are implemented, but if you spawn such a crate
it can be opened.
* All data is read from a json file, for which I'm going to release a
tool soon so it's easily adjustable
* There is a new setting for enabling events, which enables dropping
extra event crates These are Knishmas, Halloween and Easter
2020-10-10 17:18:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-22 01:03:48 +00:00
|
|
|
/*
|
2020-09-24 14:14:37 +00:00
|
|
|
* Create a full and properly-paced path by interpolating between keyframes.
|
2020-09-22 01:03:48 +00:00
|
|
|
*/
|
2020-09-24 14:14:37 +00:00
|
|
|
void TableData::constructPathSkyway(nlohmann::json::iterator _pathData) {
|
2020-09-22 01:03:48 +00:00
|
|
|
auto pathData = _pathData.value();
|
2020-09-17 09:04:00 +00:00
|
|
|
// Interpolate
|
2020-09-22 01:03:48 +00:00
|
|
|
nlohmann::json pathPoints = pathData["points"];
|
2020-09-17 09:04:00 +00:00
|
|
|
std::queue<WarpLocation> points;
|
2020-09-22 01:03:48 +00:00
|
|
|
nlohmann::json::iterator _point = pathPoints.begin();
|
|
|
|
auto point = _point.value();
|
|
|
|
WarpLocation last = { point["iX"] , point["iY"] , point["iZ"] }; // start pos
|
|
|
|
// use some for loop trickery; start position should not be a point
|
|
|
|
for (_point++; _point != pathPoints.end(); _point++) {
|
|
|
|
point = _point.value();
|
|
|
|
WarpLocation coords = { point["iX"] , point["iY"] , point["iZ"] };
|
2020-09-23 14:53:06 +00:00
|
|
|
TransportManager::lerp(&points, last, coords, pathData["iMonkeySpeed"]);
|
2020-09-22 01:03:48 +00:00
|
|
|
points.push(coords); // add keyframe to the queue
|
2020-09-17 09:04:00 +00:00
|
|
|
last = coords; // update start pos
|
|
|
|
}
|
2020-09-22 01:03:48 +00:00
|
|
|
TransportManager::SkywayPaths[pathData["iRouteID"]] = points;
|
2020-09-17 09:04:00 +00:00
|
|
|
}
|
2020-09-24 14:14:37 +00:00
|
|
|
|
2020-09-25 18:42:31 +00:00
|
|
|
void TableData::constructPathSlider(nlohmann::json points, int rotations, int sliderID) {
|
|
|
|
std::queue<WarpLocation> route;
|
|
|
|
std::rotate(points.begin(), points.begin() + rotations, points.end()); // rotate points
|
|
|
|
nlohmann::json::iterator _point = points.begin(); // iterator
|
|
|
|
auto point = _point.value();
|
|
|
|
WarpLocation from = { point["iX"] , point["iY"] , point["iZ"] }; // point A coords
|
|
|
|
int stopTime = point["stop"] ? SLIDER_STOP_TICKS : 0; // arbitrary stop length
|
|
|
|
for (_point++; _point != points.end(); _point++) { // loop through all point Bs
|
|
|
|
point = _point.value();
|
|
|
|
for (int i = 0; i < stopTime + 1; i++) // repeat point if it's a stop
|
|
|
|
route.push(from); // add point A to the queue
|
|
|
|
WarpLocation to = { point["iX"] , point["iY"] , point["iZ"] }; // point B coords
|
2020-10-20 14:40:50 +00:00
|
|
|
// we may need to change this later; right now, the speed is cut before and after stops (no accel)
|
2020-09-26 22:45:19 +00:00
|
|
|
float curve = 1;
|
|
|
|
if (stopTime > 0) { // point A is a stop
|
2020-10-20 14:40:50 +00:00
|
|
|
curve = 0.375f;//2.0f;
|
2020-09-26 22:45:19 +00:00
|
|
|
} else if (point["stop"]) { // point B is a stop
|
2020-10-20 14:40:50 +00:00
|
|
|
curve = 0.375f;//0.35f;
|
2020-09-26 22:45:19 +00:00
|
|
|
}
|
2020-10-20 14:40:50 +00:00
|
|
|
TransportManager::lerp(&route, from, to, SLIDER_SPEED * curve, 1); // lerp from A to B (arbitrary speed)
|
2020-09-25 18:42:31 +00:00
|
|
|
from = to; // update point A
|
|
|
|
stopTime = point["stop"] ? SLIDER_STOP_TICKS : 0;
|
|
|
|
}
|
|
|
|
std::rotate(points.rbegin(), points.rbegin() + rotations, points.rend()); // undo rotation
|
|
|
|
TransportManager::NPCQueues[sliderID] = route;
|
|
|
|
}
|
|
|
|
|
2020-10-13 19:44:43 +00:00
|
|
|
void TableData::constructPathNPC(nlohmann::json::iterator _pathData, int32_t id) {
|
2020-09-24 14:14:37 +00:00
|
|
|
auto pathData = _pathData.value();
|
|
|
|
// Interpolate
|
|
|
|
nlohmann::json pathPoints = pathData["points"];
|
|
|
|
std::queue<WarpLocation> points;
|
|
|
|
nlohmann::json::iterator _point = pathPoints.begin();
|
|
|
|
auto point = _point.value();
|
|
|
|
WarpLocation from = { point["iX"] , point["iY"] , point["iZ"] }; // point A coords
|
|
|
|
int stopTime = point["stop"];
|
|
|
|
for (_point++; _point != pathPoints.end(); _point++) { // loop through all point Bs
|
|
|
|
point = _point.value();
|
|
|
|
for(int i = 0; i < stopTime + 1; i++) // repeat point if it's a stop
|
|
|
|
points.push(from); // add point A to the queue
|
|
|
|
WarpLocation to = { point["iX"] , point["iY"] , point["iZ"] }; // point B coords
|
|
|
|
TransportManager::lerp(&points, from, to, pathData["iBaseSpeed"]); // lerp from A to B
|
|
|
|
from = to; // update point A
|
|
|
|
stopTime = point["stop"];
|
|
|
|
}
|
2020-10-13 19:44:43 +00:00
|
|
|
|
|
|
|
if (id == 0)
|
|
|
|
id = pathData["iNPCID"];
|
|
|
|
|
|
|
|
TransportManager::NPCQueues[id] = points;
|
2020-09-24 14:14:37 +00:00
|
|
|
}
|
2020-10-06 19:53:21 +00:00
|
|
|
|
|
|
|
// load gruntwork output; if it exists
|
2020-10-07 17:29:59 +00:00
|
|
|
void TableData::loadGruntwork(int32_t *nextId) {
|
2020-10-06 19:53:21 +00:00
|
|
|
try {
|
|
|
|
std::ifstream inFile(settings::GRUNTWORKJSON);
|
|
|
|
nlohmann::json gruntwork;
|
|
|
|
|
|
|
|
// skip if there's no gruntwork to load
|
|
|
|
if (inFile.fail())
|
|
|
|
return;
|
|
|
|
|
|
|
|
inFile >> gruntwork;
|
|
|
|
|
|
|
|
// skyway paths
|
|
|
|
auto skyway = gruntwork["skyway"];
|
|
|
|
for (auto _route = skyway.begin(); _route != skyway.end(); _route++) {
|
|
|
|
auto route = _route.value();
|
|
|
|
std::vector<WarpLocation> points;
|
|
|
|
|
|
|
|
for (auto _point = route["points"].begin(); _point != route["points"].end(); _point++) {
|
|
|
|
auto point = _point.value();
|
|
|
|
points.push_back(WarpLocation{point["x"], point["y"], point["z"]});
|
|
|
|
}
|
|
|
|
|
|
|
|
RunningSkywayRoutes[(int)route["iRouteID"]] = points;
|
|
|
|
}
|
|
|
|
|
2020-10-06 21:59:12 +00:00
|
|
|
// npc rotations
|
|
|
|
auto npcRot = gruntwork["rotations"];
|
|
|
|
for (auto _rot = npcRot.begin(); _rot != npcRot.end(); _rot++) {
|
|
|
|
int32_t npcID = _rot.value()["iNPCID"];
|
|
|
|
int angle = _rot.value()["iAngle"];
|
|
|
|
if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end())
|
|
|
|
continue; // NPC not found
|
|
|
|
BaseNPC* npc = NPCManager::NPCs[npcID];
|
|
|
|
npc->appearanceData.iAngle = angle;
|
2020-10-07 19:13:26 +00:00
|
|
|
|
|
|
|
RunningNPCRotations[npcID] = angle;
|
2020-10-06 21:59:12 +00:00
|
|
|
}
|
|
|
|
|
2020-10-12 01:53:01 +00:00
|
|
|
// npc map numbers
|
|
|
|
auto npcMap = gruntwork["instances"];
|
|
|
|
for (auto _map = npcMap.begin(); _map != npcMap.end(); _map++) {
|
|
|
|
int32_t npcID = _map.value()["iNPCID"];
|
2020-10-12 16:55:41 +00:00
|
|
|
uint64_t instanceID = _map.value()["iMapNum"];
|
2020-10-12 01:53:01 +00:00
|
|
|
if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end())
|
|
|
|
continue; // NPC not found
|
|
|
|
BaseNPC* npc = NPCManager::NPCs[npcID];
|
2020-11-18 00:07:04 +00:00
|
|
|
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->appearanceData.iX, npc->appearanceData.iY,
|
|
|
|
npc->appearanceData.iZ, instanceID, npc->appearanceData.iAngle);
|
2020-10-12 01:53:01 +00:00
|
|
|
|
|
|
|
RunningNPCMapNumbers[npcID] = instanceID;
|
|
|
|
}
|
|
|
|
|
2020-10-07 17:29:59 +00:00
|
|
|
// mobs
|
|
|
|
auto mobs = gruntwork["mobs"];
|
2020-11-15 18:19:34 +00:00
|
|
|
int leaderMob = -1;
|
|
|
|
int leaderMobFollowers = 0;
|
2020-10-07 17:29:59 +00:00
|
|
|
for (auto _mob = mobs.begin(); _mob != mobs.end(); _mob++) {
|
|
|
|
auto mob = _mob.value();
|
2020-10-19 01:45:58 +00:00
|
|
|
BaseNPC *npc;
|
|
|
|
int id = (*nextId)++;
|
2020-10-12 16:55:41 +00:00
|
|
|
uint64_t instanceID = mob.find("iMapNum") == mob.end() ? INSTANCE_OVERWORLD : (int)mob["iMapNum"];
|
2020-10-19 01:45:58 +00:00
|
|
|
|
|
|
|
if (NPCManager::NPCData[(int)mob["iNPCType"]]["m_iTeam"] == 2) {
|
|
|
|
npc = new Mob(mob["iX"], mob["iY"], mob["iZ"], instanceID, mob["iNPCType"],
|
|
|
|
NPCManager::NPCData[(int)mob["iNPCType"]], id);
|
|
|
|
|
|
|
|
// re-enable respawning
|
|
|
|
((Mob*)npc)->summoned = false;
|
|
|
|
|
|
|
|
MobManager::Mobs[npc->appearanceData.iNPC_ID] = (Mob*)npc;
|
2020-11-15 18:19:34 +00:00
|
|
|
|
|
|
|
// handling groups
|
|
|
|
if (mob.find("iOffsetX") != mob.end() && MobManager::Mobs.find(id) != MobManager::Mobs.end()) {
|
|
|
|
Mob* currNpc = MobManager::Mobs[id];
|
|
|
|
|
|
|
|
if (leaderMob == -1) {
|
|
|
|
if (MobManager::Mobs.find(id-1) != MobManager::Mobs.end()) {
|
|
|
|
Mob* leadNpc = MobManager::Mobs[id-1];
|
|
|
|
leaderMob = id-1;
|
|
|
|
leadNpc->groupMember[leaderMobFollowers] = id;
|
|
|
|
leaderMobFollowers++;
|
|
|
|
currNpc->groupLeader = id-1;
|
|
|
|
leadNpc->groupLeader = id-1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (MobManager::Mobs.find(leaderMob) != MobManager::Mobs.end()) {
|
|
|
|
Mob* leadNpc = MobManager::Mobs[leaderMob];
|
|
|
|
leadNpc->groupMember[leaderMobFollowers] = id;
|
|
|
|
leaderMobFollowers++;
|
|
|
|
currNpc->groupLeader = leaderMob;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
currNpc->offsetX = (int)mob["iOffsetX"];
|
|
|
|
currNpc->offsetY = mob.find("iOffsetY") == mob.end() ? 0 : (int)mob["iOffsetY"];
|
|
|
|
} else {
|
|
|
|
leaderMob = -1;
|
|
|
|
leaderMobFollowers = 0;
|
|
|
|
}
|
|
|
|
|
2020-10-19 01:45:58 +00:00
|
|
|
} else {
|
|
|
|
npc = new BaseNPC(mob["iX"], mob["iY"], mob["iZ"], mob["iAngle"], instanceID, mob["iNPCType"], id);
|
|
|
|
}
|
2020-10-07 17:29:59 +00:00
|
|
|
|
|
|
|
NPCManager::NPCs[npc->appearanceData.iNPC_ID] = npc;
|
|
|
|
TableData::RunningMobs[npc->appearanceData.iNPC_ID] = npc;
|
2020-11-18 00:07:04 +00:00
|
|
|
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, mob["iX"], mob["iY"], mob["iZ"], instanceID, mob["iAngle"]);
|
2020-10-07 17:29:59 +00:00
|
|
|
}
|
|
|
|
|
2020-11-08 08:42:49 +00:00
|
|
|
auto eggs = gruntwork["eggs"];
|
|
|
|
for (auto _egg = eggs.begin(); _egg != eggs.end(); _egg++) {
|
|
|
|
auto egg = _egg.value();
|
|
|
|
int id = (*nextId)++;
|
2020-11-09 09:34:11 +00:00
|
|
|
uint64_t instanceID = egg.find("iMapNum") == egg.end() ? INSTANCE_OVERWORLD : (int)egg["iMapNum"];
|
|
|
|
|
|
|
|
Egg* addEgg = new Egg((int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, (int)egg["iType"], id, false);
|
2020-11-08 08:42:49 +00:00
|
|
|
NPCManager::NPCs[id] = addEgg;
|
|
|
|
NPCManager::Eggs[id] = addEgg;
|
2020-11-18 00:07:04 +00:00
|
|
|
NPCManager::updateNPCPosition(id, (int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, 0);
|
2020-11-08 08:42:49 +00:00
|
|
|
TableData::RunningEggs[id] = addEgg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-06 19:53:21 +00:00
|
|
|
std::cout << "[INFO] Loaded gruntwork.json" << std::endl;
|
|
|
|
}
|
|
|
|
catch (const std::exception& err) {
|
2020-10-18 02:13:33 +00:00
|
|
|
std::cerr << "[FATAL] Malformed gruntwork.json file! Reason:" << err.what() << std::endl;
|
|
|
|
terminate(0);
|
2020-10-06 19:53:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// write gruntwork output to file
|
|
|
|
void TableData::flush() {
|
|
|
|
std::ofstream file(settings::GRUNTWORKJSON);
|
|
|
|
nlohmann::json gruntwork;
|
|
|
|
|
|
|
|
for (auto& pair : RunningSkywayRoutes) {
|
|
|
|
nlohmann::json route;
|
|
|
|
|
|
|
|
route["iRouteID"] = (int)pair.first;
|
2020-10-12 01:53:01 +00:00
|
|
|
route["iMonkeySpeed"] = 1500;
|
2020-10-06 19:53:21 +00:00
|
|
|
|
|
|
|
std::cout << "serializing mss route " << (int)pair.first << std::endl;
|
|
|
|
for (WarpLocation& point : pair.second) {
|
|
|
|
nlohmann::json tmp;
|
|
|
|
|
|
|
|
tmp["x"] = point.x;
|
|
|
|
tmp["y"] = point.y;
|
|
|
|
tmp["z"] = point.z;
|
|
|
|
|
|
|
|
route["points"].push_back(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
gruntwork["skyway"].push_back(route);
|
|
|
|
}
|
|
|
|
|
2020-10-06 21:59:12 +00:00
|
|
|
for (auto& pair : RunningNPCRotations) {
|
|
|
|
nlohmann::json rotation;
|
|
|
|
|
|
|
|
rotation["iNPCID"] = (int)pair.first;
|
|
|
|
rotation["iAngle"] = pair.second;
|
|
|
|
|
|
|
|
gruntwork["rotations"].push_back(rotation);
|
|
|
|
}
|
|
|
|
|
2020-10-12 01:53:01 +00:00
|
|
|
for (auto& pair : RunningNPCMapNumbers) {
|
|
|
|
nlohmann::json mapNumber;
|
|
|
|
|
|
|
|
mapNumber["iNPCID"] = (int)pair.first;
|
|
|
|
mapNumber["iMapNum"] = pair.second;
|
|
|
|
|
|
|
|
gruntwork["instances"].push_back(mapNumber);
|
|
|
|
}
|
|
|
|
|
2020-10-07 17:29:59 +00:00
|
|
|
for (auto& pair : RunningMobs) {
|
|
|
|
nlohmann::json mob;
|
2020-10-19 01:45:58 +00:00
|
|
|
BaseNPC *npc = pair.second;
|
2020-10-07 17:29:59 +00:00
|
|
|
|
|
|
|
if (NPCManager::NPCs.find(pair.first) == NPCManager::NPCs.end())
|
|
|
|
continue;
|
|
|
|
|
2020-10-19 01:45:58 +00:00
|
|
|
int x, y, z, hp;
|
2020-11-15 18:19:34 +00:00
|
|
|
int offsetX = 0;
|
|
|
|
int offsetY = 0;
|
2020-10-19 01:45:58 +00:00
|
|
|
if (npc->npcClass == NPC_MOB) {
|
|
|
|
Mob *m = (Mob*)npc;
|
|
|
|
x = m->spawnX;
|
|
|
|
y = m->spawnY;
|
|
|
|
z = m->spawnZ;
|
|
|
|
hp = m->maxHealth;
|
2020-11-15 18:19:34 +00:00
|
|
|
// handling groups
|
|
|
|
if (m->groupLeader != 0 && m->groupLeader != m->appearanceData.iNPC_ID) {
|
|
|
|
offsetX = m->offsetX;
|
|
|
|
offsetY = m->offsetY;
|
|
|
|
}
|
2020-10-19 01:45:58 +00:00
|
|
|
} else {
|
|
|
|
x = npc->appearanceData.iX;
|
|
|
|
y = npc->appearanceData.iY;
|
|
|
|
z = npc->appearanceData.iZ;
|
|
|
|
hp = npc->appearanceData.iHP;
|
|
|
|
}
|
|
|
|
|
2020-10-07 17:29:59 +00:00
|
|
|
// NOTE: this format deviates slightly from the one in mobs.json
|
2020-10-19 01:45:58 +00:00
|
|
|
mob["iNPCType"] = (int)npc->appearanceData.iNPCType;
|
|
|
|
mob["iHP"] = hp;
|
|
|
|
mob["iX"] = x;
|
|
|
|
mob["iY"] = y;
|
|
|
|
mob["iZ"] = z;
|
|
|
|
mob["iMapNum"] = MAPNUM(npc->instanceID);
|
2020-10-07 17:29:59 +00:00
|
|
|
// this is a bit imperfect, since this is a live angle, not a spawn angle so it'll change often, but eh
|
2020-10-19 01:45:58 +00:00
|
|
|
mob["iAngle"] = npc->appearanceData.iAngle;
|
2020-10-07 17:29:59 +00:00
|
|
|
|
2020-11-15 18:19:34 +00:00
|
|
|
// there is an assumption that group mobs will never have an offset of (0,0)
|
|
|
|
if (offsetX != 0 || offsetY != 0) {
|
|
|
|
mob["iOffsetX"] = offsetX;
|
|
|
|
mob["iOffsetY"] = offsetY;
|
|
|
|
}
|
|
|
|
|
2020-10-19 01:45:58 +00:00
|
|
|
// it's called mobs, but really it's everything
|
2020-10-07 17:29:59 +00:00
|
|
|
gruntwork["mobs"].push_back(mob);
|
|
|
|
}
|
|
|
|
|
2020-11-08 08:42:49 +00:00
|
|
|
for (auto& pair : RunningEggs) {
|
|
|
|
nlohmann::json egg;
|
|
|
|
BaseNPC* npc = pair.second;
|
|
|
|
|
|
|
|
if (NPCManager::Eggs.find(pair.first) == NPCManager::Eggs.end())
|
|
|
|
continue;
|
|
|
|
egg["iX"] = npc->appearanceData.iX;
|
|
|
|
egg["iY"] = npc->appearanceData.iY;
|
|
|
|
egg["iZ"] = npc->appearanceData.iZ;
|
2020-11-09 09:34:11 +00:00
|
|
|
int mapnum = MAPNUM(npc->instanceID);
|
|
|
|
if (mapnum != 0)
|
|
|
|
egg["iMapNum"] = mapnum;
|
2020-11-08 08:42:49 +00:00
|
|
|
egg["iType"] = npc->appearanceData.iNPCType;
|
|
|
|
|
|
|
|
gruntwork["eggs"].push_back(egg);
|
|
|
|
}
|
|
|
|
|
2020-10-06 19:53:21 +00:00
|
|
|
file << gruntwork << std::endl;
|
|
|
|
}
|