mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-05 06:50:04 +00:00
[refactor] E g g s
This commit is contained in:
parent
a55a34e09a
commit
610a683804
2
Makefile
2
Makefile
@ -51,6 +51,7 @@ CXXSRC=\
|
|||||||
src/Chat.cpp\
|
src/Chat.cpp\
|
||||||
src/CustomCommands.cpp\
|
src/CustomCommands.cpp\
|
||||||
src/Email.cpp\
|
src/Email.cpp\
|
||||||
|
src/Eggs.cpp\
|
||||||
src/main.cpp\
|
src/main.cpp\
|
||||||
src/Missions.cpp\
|
src/Missions.cpp\
|
||||||
src/MobAI.cpp\
|
src/MobAI.cpp\
|
||||||
@ -92,6 +93,7 @@ CXXHDR=\
|
|||||||
src/Chat.hpp\
|
src/Chat.hpp\
|
||||||
src/CustomCommands.hpp\
|
src/CustomCommands.hpp\
|
||||||
src/Email.hpp\
|
src/Email.hpp\
|
||||||
|
src/Eggs.hpp\
|
||||||
src/Missions.hpp\
|
src/Missions.hpp\
|
||||||
src/MobAI.hpp\
|
src/MobAI.hpp\
|
||||||
src/Combat.hpp\
|
src/Combat.hpp\
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "NPCManager.hpp"
|
#include "NPCManager.hpp"
|
||||||
#include "Nanos.hpp"
|
#include "Nanos.hpp"
|
||||||
#include "Groups.hpp"
|
#include "Groups.hpp"
|
||||||
|
#include "Eggs.hpp"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: This file is in desperate need of deduplication and rewriting.
|
* TODO: This file is in desperate need of deduplication and rewriting.
|
||||||
@ -521,7 +522,7 @@ bool doDamageNDebuff(Mob *mob, sSkillResult_Damage_N_Debuff *respdata, int i, in
|
|||||||
respdata[i].bProtected = 0;
|
respdata[i].bProtected = 0;
|
||||||
std::pair<CNSocket*, int32_t> key = std::make_pair(sock, bitFlag);
|
std::pair<CNSocket*, int32_t> key = std::make_pair(sock, bitFlag);
|
||||||
time_t until = getTime() + (time_t)duration * 100;
|
time_t until = getTime() + (time_t)duration * 100;
|
||||||
NPCManager::EggBuffs[key] = until;
|
Eggs::EggBuffs[key] = until;
|
||||||
}
|
}
|
||||||
respdata[i].iConditionBitFlag = plr->iConditionBitFlag;
|
respdata[i].iConditionBitFlag = plr->iConditionBitFlag;
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "NPCManager.hpp"
|
#include "NPCManager.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
#include "Combat.hpp"
|
#include "Combat.hpp"
|
||||||
|
#include "Eggs.hpp"
|
||||||
|
|
||||||
using namespace Chunking;
|
using namespace Chunking;
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ void Chunking::addPlayerToChunks(std::set<Chunk*> chnks, CNSocket* sock) {
|
|||||||
break;
|
break;
|
||||||
case NPC_EGG:
|
case NPC_EGG:
|
||||||
INITSTRUCT(sP_FE2CL_SHINY_ENTER, enterEggData);
|
INITSTRUCT(sP_FE2CL_SHINY_ENTER, enterEggData);
|
||||||
NPCManager::npcDataToEggData(&npc->appearanceData, &enterEggData.ShinyAppearanceData);
|
Eggs::npcDataToEggData(&npc->appearanceData, &enterEggData.ShinyAppearanceData);
|
||||||
sock->sendPacket((void*)&enterEggData, P_FE2CL_SHINY_ENTER, sizeof(sP_FE2CL_SHINY_ENTER));
|
sock->sendPacket((void*)&enterEggData, P_FE2CL_SHINY_ENTER, sizeof(sP_FE2CL_SHINY_ENTER));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -183,7 +184,7 @@ void Chunking::addNPCToChunks(std::set<Chunk*> chnks, int32_t id) {
|
|||||||
break;
|
break;
|
||||||
case NPC_EGG:
|
case NPC_EGG:
|
||||||
INITSTRUCT(sP_FE2CL_SHINY_ENTER, enterEggData);
|
INITSTRUCT(sP_FE2CL_SHINY_ENTER, enterEggData);
|
||||||
NPCManager::npcDataToEggData(&npc->appearanceData, &enterEggData.ShinyAppearanceData);
|
Eggs::npcDataToEggData(&npc->appearanceData, &enterEggData.ShinyAppearanceData);
|
||||||
|
|
||||||
for (Chunk* chunk : chnks) {
|
for (Chunk* chunk : chnks) {
|
||||||
for (CNSocket* sock : chunk->players) {
|
for (CNSocket* sock : chunk->players) {
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "PlayerManager.hpp"
|
#include "PlayerManager.hpp"
|
||||||
#include "TableData.hpp"
|
#include "TableData.hpp"
|
||||||
#include "NPCManager.hpp"
|
#include "NPCManager.hpp"
|
||||||
|
#include "Eggs.hpp"
|
||||||
#include "MobAI.hpp"
|
#include "MobAI.hpp"
|
||||||
#include "Items.hpp"
|
#include "Items.hpp"
|
||||||
#include "db/Database.hpp"
|
#include "db/Database.hpp"
|
||||||
@ -485,7 +486,7 @@ static void buffCommand(std::string full, std::vector<std::string>& args, CNSock
|
|||||||
if (*tmp)
|
if (*tmp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (NPCManager::eggBuffPlayer(sock, skillId, 0, duration)<0)
|
if (Eggs::eggBuffPlayer(sock, skillId, 0, duration)<0)
|
||||||
Chat::sendServerMessage(sock, "/buff: unknown skill Id");
|
Chat::sendServerMessage(sock, "/buff: unknown skill Id");
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -501,7 +502,7 @@ static void eggCommand(std::string full, std::vector<std::string>& args, CNSocke
|
|||||||
if (*tmp)
|
if (*tmp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (NPCManager::EggTypes.find(eggType) == NPCManager::EggTypes.end()) {
|
if (Eggs::EggTypes.find(eggType) == Eggs::EggTypes.end()) {
|
||||||
Chat::sendServerMessage(sock, "/egg: Unknown egg type");
|
Chat::sendServerMessage(sock, "/egg: Unknown egg type");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -518,7 +519,7 @@ static void eggCommand(std::string full, std::vector<std::string>& args, CNSocke
|
|||||||
|
|
||||||
Egg* egg = new Egg(plr->x + addX, plr->y + addY, plr->z, plr->instanceID, eggType, id, false); // change last arg to true after gruntwork
|
Egg* egg = new Egg(plr->x + addX, plr->y + addY, plr->z, plr->instanceID, eggType, id, false); // change last arg to true after gruntwork
|
||||||
NPCManager::NPCs[id] = egg;
|
NPCManager::NPCs[id] = egg;
|
||||||
NPCManager::Eggs[id] = egg;
|
Eggs::Eggs[id] = egg;
|
||||||
NPCManager::updateNPCPosition(id, plr->x + addX, plr->y + addY, plr->z, plr->instanceID, plr->angle);
|
NPCManager::updateNPCPosition(id, plr->x + addX, plr->y + addY, plr->z, plr->instanceID, plr->angle);
|
||||||
|
|
||||||
// add to template
|
// add to template
|
||||||
|
263
src/Eggs.cpp
Normal file
263
src/Eggs.cpp
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
#include "core/Core.hpp"
|
||||||
|
#include "Eggs.hpp"
|
||||||
|
#include "PlayerManager.hpp"
|
||||||
|
#include "Items.hpp"
|
||||||
|
#include "Nanos.hpp"
|
||||||
|
#include "Abilities.hpp"
|
||||||
|
#include "Groups.hpp"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
using namespace Eggs;
|
||||||
|
|
||||||
|
/// sock, CBFlag -> until
|
||||||
|
std::map<std::pair<CNSocket*, int32_t>, time_t> Eggs::EggBuffs;
|
||||||
|
std::unordered_map<int, EggType> Eggs::EggTypes;
|
||||||
|
std::unordered_map<int, Egg*> Eggs::Eggs;
|
||||||
|
|
||||||
|
int Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) {
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
||||||
|
|
||||||
|
int bitFlag = Groups::getGroupFlags(otherPlr);
|
||||||
|
int CBFlag = Nanos::applyBuff(sock, skillId, 1, 3, bitFlag);
|
||||||
|
|
||||||
|
size_t resplen;
|
||||||
|
|
||||||
|
if (skillId == 183) {
|
||||||
|
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Damage);
|
||||||
|
} else if (skillId == 150) {
|
||||||
|
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Heal_HP);
|
||||||
|
} else {
|
||||||
|
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Buff);
|
||||||
|
}
|
||||||
|
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
||||||
|
// we know it's only one trailing struct, so we can skip full validation
|
||||||
|
|
||||||
|
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
||||||
|
sP_FE2CL_NPC_SKILL_HIT* skillUse = (sP_FE2CL_NPC_SKILL_HIT*)respbuf;
|
||||||
|
|
||||||
|
if (skillId == 183) { // damage egg
|
||||||
|
sSkillResult_Damage* skill = (sSkillResult_Damage*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
||||||
|
memset(respbuf, 0, resplen);
|
||||||
|
skill->eCT = 1;
|
||||||
|
skill->iID = plr->iID;
|
||||||
|
skill->iDamage = PC_MAXHEALTH(plr->level) * Nanos::SkillTable[skillId].powerIntensity[0] / 1000;
|
||||||
|
plr->HP -= skill->iDamage;
|
||||||
|
if (plr->HP < 0)
|
||||||
|
plr->HP = 0;
|
||||||
|
skill->iHP = plr->HP;
|
||||||
|
} else if (skillId == 150) { // heal egg
|
||||||
|
sSkillResult_Heal_HP* skill = (sSkillResult_Heal_HP*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
||||||
|
memset(respbuf, 0, resplen);
|
||||||
|
skill->eCT = 1;
|
||||||
|
skill->iID = plr->iID;
|
||||||
|
skill->iHealHP = PC_MAXHEALTH(plr->level) * Nanos::SkillTable[skillId].powerIntensity[0] / 1000;
|
||||||
|
plr->HP += skill->iHealHP;
|
||||||
|
if (plr->HP > PC_MAXHEALTH(plr->level))
|
||||||
|
plr->HP = PC_MAXHEALTH(plr->level);
|
||||||
|
skill->iHP = plr->HP;
|
||||||
|
} else { // regular buff egg
|
||||||
|
sSkillResult_Buff* skill = (sSkillResult_Buff*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
||||||
|
memset(respbuf, 0, resplen);
|
||||||
|
skill->eCT = 1;
|
||||||
|
skill->iID = plr->iID;
|
||||||
|
skill->iConditionBitFlag = plr->iConditionBitFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
skillUse->iNPC_ID = eggId;
|
||||||
|
skillUse->iSkillID = skillId;
|
||||||
|
skillUse->eST = Nanos::SkillTable[skillId].skillType;
|
||||||
|
skillUse->iTargetCnt = 1;
|
||||||
|
|
||||||
|
sock->sendPacket((void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen);
|
||||||
|
PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen);
|
||||||
|
|
||||||
|
if (CBFlag == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
std::pair<CNSocket*, int32_t> key = std::make_pair(sock, CBFlag);
|
||||||
|
|
||||||
|
// save the buff serverside;
|
||||||
|
// if you get the same buff again, new duration will override the previous one
|
||||||
|
time_t until = getTime() + (time_t)duration * 1000;
|
||||||
|
EggBuffs[key] = until;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eggStep(CNServer* serv, time_t currTime) {
|
||||||
|
// tick buffs
|
||||||
|
time_t timeStamp = currTime;
|
||||||
|
auto it = EggBuffs.begin();
|
||||||
|
while (it != EggBuffs.end()) {
|
||||||
|
// check remaining time
|
||||||
|
if (it->second > timeStamp)
|
||||||
|
it++;
|
||||||
|
else { // if time reached 0
|
||||||
|
CNSocket* sock = it->first.first;
|
||||||
|
int32_t CBFlag = it->first.second;
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
||||||
|
|
||||||
|
int groupFlags = Groups::getGroupFlags(otherPlr);
|
||||||
|
for (auto& pwr : Nanos::NanoPowers) {
|
||||||
|
if (pwr.bitFlag == CBFlag) { // pick the power with the right flag and unbuff
|
||||||
|
INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, resp);
|
||||||
|
resp.eCSTB = pwr.timeBuffID;
|
||||||
|
resp.eTBU = 2;
|
||||||
|
resp.eTBT = 3; // for egg buffs
|
||||||
|
plr->iConditionBitFlag &= ~CBFlag;
|
||||||
|
resp.iConditionBitFlag = plr->iConditionBitFlag |= groupFlags | plr->iSelfConditionBitFlag;
|
||||||
|
sock->sendPacket((void*)&resp, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE));
|
||||||
|
|
||||||
|
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, resp2); // send a buff timeout to other players
|
||||||
|
resp2.eCT = 1;
|
||||||
|
resp2.iID = plr->iID;
|
||||||
|
resp2.iConditionBitFlag = plr->iConditionBitFlag;
|
||||||
|
PlayerManager::sendToViewable(sock, (void*)&resp2, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove buff from the map
|
||||||
|
it = EggBuffs.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check dead eggs and eggs in inactive chunks
|
||||||
|
for (auto egg : Eggs::Eggs) {
|
||||||
|
if (!egg.second->dead || !Chunking::inPopulatedChunks(egg.second->viewableChunks))
|
||||||
|
continue;
|
||||||
|
if (egg.second->deadUntil <= timeStamp) {
|
||||||
|
// respawn it
|
||||||
|
egg.second->dead = false;
|
||||||
|
egg.second->deadUntil = 0;
|
||||||
|
egg.second->appearanceData.iHP = 400;
|
||||||
|
|
||||||
|
Chunking::addNPCToChunks(Chunking::getViewableChunks(egg.second->chunkPos), egg.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Eggs::npcDataToEggData(sNPCAppearanceData* npc, sShinyAppearanceData* egg) {
|
||||||
|
egg->iX = npc->iX;
|
||||||
|
egg->iY = npc->iY;
|
||||||
|
egg->iZ = npc->iZ;
|
||||||
|
// client doesn't care about egg->iMapNum
|
||||||
|
egg->iShinyType = npc->iNPCType;
|
||||||
|
egg->iShiny_ID = npc->iNPC_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eggPickup(CNSocket* sock, CNPacketData* data) {
|
||||||
|
if (data->size != sizeof(sP_CL2FE_REQ_SHINY_PICKUP))
|
||||||
|
return; // malformed packet
|
||||||
|
|
||||||
|
sP_CL2FE_REQ_SHINY_PICKUP* pickup = (sP_CL2FE_REQ_SHINY_PICKUP*)data->buf;
|
||||||
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
int eggId = pickup->iShinyID;
|
||||||
|
|
||||||
|
if (Eggs::Eggs.find(eggId) == Eggs::Eggs.end()) {
|
||||||
|
std::cout << "[WARN] Player tried to open non existing egg?!" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Egg* egg = Eggs::Eggs[eggId];
|
||||||
|
|
||||||
|
if (egg->dead) {
|
||||||
|
std::cout << "[WARN] Player tried to open a dead egg?!" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this has some issues with position desync, leaving it out for now
|
||||||
|
if (abs(egg->appearanceData.iX - plr->x)>500 || abs(egg->appearanceData.iY - plr->y) > 500) {
|
||||||
|
std::cout << "[WARN] Player tried to open an egg from the other chunk?!" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
int typeId = egg->appearanceData.iNPCType;
|
||||||
|
if (EggTypes.find(typeId) == EggTypes.end()) {
|
||||||
|
std::cout << "[WARN] Egg Type " << typeId << " not found!" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EggType* type = &EggTypes[typeId];
|
||||||
|
|
||||||
|
// buff the player
|
||||||
|
if (type->effectId != 0)
|
||||||
|
eggBuffPlayer(sock, type->effectId, eggId, type->duration);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SHINY_PICKUP_SUCC is only causing a GUI effect in the client
|
||||||
|
* (buff icon pops up in the bottom of the screen)
|
||||||
|
* so we don't send it for non-effect
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (type->effectId != 0)
|
||||||
|
{
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_SHINY_PICKUP_SUCC, resp);
|
||||||
|
resp.iSkillID = type->effectId;
|
||||||
|
|
||||||
|
// in general client finds correct icon on it's own,
|
||||||
|
// but for damage we have to supply correct CSTB
|
||||||
|
if (resp.iSkillID == 183)
|
||||||
|
resp.eCSTB = ECSB_INFECTION;
|
||||||
|
|
||||||
|
sock->sendPacket((void*)&resp, P_FE2CL_REP_SHINY_PICKUP_SUCC, sizeof(sP_FE2CL_REP_SHINY_PICKUP_SUCC));
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop
|
||||||
|
if (type->dropCrateId != 0) {
|
||||||
|
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
||||||
|
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
|
||||||
|
sP_FE2CL_REP_REWARD_ITEM* reward = (sP_FE2CL_REP_REWARD_ITEM*)respbuf;
|
||||||
|
sItemReward* item = (sItemReward*)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
||||||
|
|
||||||
|
// don't forget to zero the buffer!
|
||||||
|
memset(respbuf, 0, resplen);
|
||||||
|
|
||||||
|
// send back player's stats
|
||||||
|
reward->m_iCandy = plr->money;
|
||||||
|
reward->m_iFusionMatter = plr->fusionmatter;
|
||||||
|
reward->m_iBatteryN = plr->batteryN;
|
||||||
|
reward->m_iBatteryW = plr->batteryW;
|
||||||
|
reward->iFatigue = 100; // prevents warning message
|
||||||
|
reward->iFatigue_Level = 1;
|
||||||
|
reward->iItemCnt = 1; // remember to update resplen if you change this
|
||||||
|
|
||||||
|
int slot = Items::findFreeSlot(plr);
|
||||||
|
|
||||||
|
// no space for drop
|
||||||
|
if (slot != -1) {
|
||||||
|
|
||||||
|
// item reward
|
||||||
|
item->sItem.iType = 9;
|
||||||
|
item->sItem.iOpt = 1;
|
||||||
|
item->sItem.iID = type->dropCrateId;
|
||||||
|
item->iSlotNum = slot;
|
||||||
|
item->eIL = 1; // Inventory Location. 1 means player inventory.
|
||||||
|
|
||||||
|
// update player
|
||||||
|
plr->Inven[slot] = item->sItem;
|
||||||
|
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (egg->summoned)
|
||||||
|
NPCManager::destroyNPC(eggId);
|
||||||
|
else {
|
||||||
|
Chunking::removeNPCFromChunks(Chunking::getViewableChunks(egg->chunkPos), eggId);
|
||||||
|
egg->dead = true;
|
||||||
|
egg->deadUntil = getTime() + (time_t)type->regen * 1000;
|
||||||
|
egg->appearanceData.iHP = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Eggs::init() {
|
||||||
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SHINY_PICKUP, eggPickup);
|
||||||
|
|
||||||
|
REGISTER_SHARD_TIMER(eggStep, 1000);
|
||||||
|
}
|
35
src/Eggs.hpp
Normal file
35
src/Eggs.hpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/Core.hpp"
|
||||||
|
#include "NPC.hpp"
|
||||||
|
|
||||||
|
struct Egg : public BaseNPC {
|
||||||
|
bool summoned;
|
||||||
|
bool dead = false;
|
||||||
|
time_t deadUntil;
|
||||||
|
|
||||||
|
Egg(int x, int y, int z, uint64_t iID, int type, int32_t id, bool summon)
|
||||||
|
: BaseNPC(x, y, z, 0, iID, type, id) {
|
||||||
|
summoned = summon;
|
||||||
|
npcClass = NPCClass::NPC_EGG;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EggType {
|
||||||
|
int dropCrateId;
|
||||||
|
int effectId;
|
||||||
|
int duration;
|
||||||
|
int regen;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Eggs {
|
||||||
|
extern std::unordered_map<int, Egg*> Eggs;
|
||||||
|
extern std::map<std::pair<CNSocket*, int32_t>, time_t> EggBuffs;
|
||||||
|
extern std::unordered_map<int, EggType> EggTypes;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
/// returns -1 on fail
|
||||||
|
int eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration);
|
||||||
|
void npcDataToEggData(sNPCAppearanceData* npc, sShinyAppearanceData* egg);
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
#include "Player.hpp"
|
#include "Player.hpp"
|
||||||
#include "Abilities.hpp"
|
#include "Abilities.hpp"
|
||||||
#include "Missions.hpp"
|
#include "Missions.hpp"
|
||||||
|
#include "Eggs.hpp"
|
||||||
|
|
||||||
#include <string.h> // for memset()
|
#include <string.h> // for memset()
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -417,7 +418,7 @@ static void itemUseHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
std::pair<CNSocket*, int32_t> key = std::make_pair(sock, value1);
|
std::pair<CNSocket*, int32_t> key = std::make_pair(sock, value1);
|
||||||
time_t until = getTime() + (time_t)Nanos::SkillTable[144].durationTime[0] * 100;
|
time_t until = getTime() + (time_t)Nanos::SkillTable[144].durationTime[0] * 100;
|
||||||
NPCManager::EggBuffs[key] = until;
|
Eggs::EggBuffs[key] = until;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void itemBankOpenHandler(CNSocket* sock, CNPacketData* data) {
|
static void itemBankOpenHandler(CNSocket* sock, CNPacketData* data) {
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "Racing.hpp"
|
#include "Racing.hpp"
|
||||||
#include "Vendor.hpp"
|
#include "Vendor.hpp"
|
||||||
#include "Abilities.hpp"
|
#include "Abilities.hpp"
|
||||||
|
#include "Eggs.hpp"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -26,10 +27,6 @@ using namespace NPCManager;
|
|||||||
std::map<int32_t, BaseNPC*> NPCManager::NPCs;
|
std::map<int32_t, BaseNPC*> NPCManager::NPCs;
|
||||||
std::map<int32_t, WarpLocation> NPCManager::Warps;
|
std::map<int32_t, WarpLocation> NPCManager::Warps;
|
||||||
std::vector<WarpLocation> NPCManager::RespawnPoints;
|
std::vector<WarpLocation> NPCManager::RespawnPoints;
|
||||||
/// sock, CBFlag -> until
|
|
||||||
std::map<std::pair<CNSocket*, int32_t>, time_t> NPCManager::EggBuffs;
|
|
||||||
std::unordered_map<int, EggType> NPCManager::EggTypes;
|
|
||||||
std::unordered_map<int, Egg*> NPCManager::Eggs;
|
|
||||||
nlohmann::json NPCManager::NPCData;
|
nlohmann::json NPCManager::NPCData;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -65,8 +62,8 @@ void NPCManager::destroyNPC(int32_t id) {
|
|||||||
MobAI::Mobs.erase(id);
|
MobAI::Mobs.erase(id);
|
||||||
|
|
||||||
// remove from eggs
|
// remove from eggs
|
||||||
if (Eggs.find(id) != Eggs.end())
|
if (Eggs::Eggs.find(id) != Eggs::Eggs.end())
|
||||||
Eggs.erase(id);
|
Eggs::Eggs.erase(id);
|
||||||
|
|
||||||
// finally, remove it from the map and free it
|
// finally, remove it from the map and free it
|
||||||
delete entity->viewableChunks;
|
delete entity->viewableChunks;
|
||||||
@ -312,247 +309,6 @@ BaseNPC* NPCManager::getNearestNPC(std::set<Chunk*>* chunks, int X, int Y, int Z
|
|||||||
return npc;
|
return npc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NPCManager::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) {
|
|
||||||
Player* plr = PlayerManager::getPlayer(sock);
|
|
||||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
|
||||||
|
|
||||||
int bitFlag = Groups::getGroupFlags(otherPlr);
|
|
||||||
int CBFlag = Nanos::applyBuff(sock, skillId, 1, 3, bitFlag);
|
|
||||||
|
|
||||||
size_t resplen;
|
|
||||||
|
|
||||||
if (skillId == 183) {
|
|
||||||
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Damage);
|
|
||||||
} else if (skillId == 150) {
|
|
||||||
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Heal_HP);
|
|
||||||
} else {
|
|
||||||
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Buff);
|
|
||||||
}
|
|
||||||
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
|
||||||
// we know it's only one trailing struct, so we can skip full validation
|
|
||||||
|
|
||||||
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
|
||||||
sP_FE2CL_NPC_SKILL_HIT* skillUse = (sP_FE2CL_NPC_SKILL_HIT*)respbuf;
|
|
||||||
|
|
||||||
if (skillId == 183) { // damage egg
|
|
||||||
sSkillResult_Damage* skill = (sSkillResult_Damage*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
|
||||||
memset(respbuf, 0, resplen);
|
|
||||||
skill->eCT = 1;
|
|
||||||
skill->iID = plr->iID;
|
|
||||||
skill->iDamage = PC_MAXHEALTH(plr->level) * Nanos::SkillTable[skillId].powerIntensity[0] / 1000;
|
|
||||||
plr->HP -= skill->iDamage;
|
|
||||||
if (plr->HP < 0)
|
|
||||||
plr->HP = 0;
|
|
||||||
skill->iHP = plr->HP;
|
|
||||||
} else if (skillId == 150) { // heal egg
|
|
||||||
sSkillResult_Heal_HP* skill = (sSkillResult_Heal_HP*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
|
||||||
memset(respbuf, 0, resplen);
|
|
||||||
skill->eCT = 1;
|
|
||||||
skill->iID = plr->iID;
|
|
||||||
skill->iHealHP = PC_MAXHEALTH(plr->level) * Nanos::SkillTable[skillId].powerIntensity[0] / 1000;
|
|
||||||
plr->HP += skill->iHealHP;
|
|
||||||
if (plr->HP > PC_MAXHEALTH(plr->level))
|
|
||||||
plr->HP = PC_MAXHEALTH(plr->level);
|
|
||||||
skill->iHP = plr->HP;
|
|
||||||
} else { // regular buff egg
|
|
||||||
sSkillResult_Buff* skill = (sSkillResult_Buff*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
|
||||||
memset(respbuf, 0, resplen);
|
|
||||||
skill->eCT = 1;
|
|
||||||
skill->iID = plr->iID;
|
|
||||||
skill->iConditionBitFlag = plr->iConditionBitFlag;
|
|
||||||
}
|
|
||||||
|
|
||||||
skillUse->iNPC_ID = eggId;
|
|
||||||
skillUse->iSkillID = skillId;
|
|
||||||
skillUse->eST = Nanos::SkillTable[skillId].skillType;
|
|
||||||
skillUse->iTargetCnt = 1;
|
|
||||||
|
|
||||||
sock->sendPacket((void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen);
|
|
||||||
PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen);
|
|
||||||
|
|
||||||
if (CBFlag == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
std::pair<CNSocket*, int32_t> key = std::make_pair(sock, CBFlag);
|
|
||||||
|
|
||||||
// save the buff serverside;
|
|
||||||
// if you get the same buff again, new duration will override the previous one
|
|
||||||
time_t until = getTime() + (time_t)duration * 1000;
|
|
||||||
EggBuffs[key] = until;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void eggStep(CNServer* serv, time_t currTime) {
|
|
||||||
// tick buffs
|
|
||||||
time_t timeStamp = currTime;
|
|
||||||
auto it = EggBuffs.begin();
|
|
||||||
while (it != EggBuffs.end()) {
|
|
||||||
// check remaining time
|
|
||||||
if (it->second > timeStamp)
|
|
||||||
it++;
|
|
||||||
else { // if time reached 0
|
|
||||||
CNSocket* sock = it->first.first;
|
|
||||||
int32_t CBFlag = it->first.second;
|
|
||||||
Player* plr = PlayerManager::getPlayer(sock);
|
|
||||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
|
||||||
|
|
||||||
int groupFlags = Groups::getGroupFlags(otherPlr);
|
|
||||||
for (auto& pwr : Nanos::NanoPowers) {
|
|
||||||
if (pwr.bitFlag == CBFlag) { // pick the power with the right flag and unbuff
|
|
||||||
INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, resp);
|
|
||||||
resp.eCSTB = pwr.timeBuffID;
|
|
||||||
resp.eTBU = 2;
|
|
||||||
resp.eTBT = 3; // for egg buffs
|
|
||||||
plr->iConditionBitFlag &= ~CBFlag;
|
|
||||||
resp.iConditionBitFlag = plr->iConditionBitFlag |= groupFlags | plr->iSelfConditionBitFlag;
|
|
||||||
sock->sendPacket((void*)&resp, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE));
|
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, resp2); // send a buff timeout to other players
|
|
||||||
resp2.eCT = 1;
|
|
||||||
resp2.iID = plr->iID;
|
|
||||||
resp2.iConditionBitFlag = plr->iConditionBitFlag;
|
|
||||||
PlayerManager::sendToViewable(sock, (void*)&resp2, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// remove buff from the map
|
|
||||||
it = EggBuffs.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check dead eggs and eggs in inactive chunks
|
|
||||||
for (auto egg : Eggs) {
|
|
||||||
if (!egg.second->dead || !Chunking::inPopulatedChunks(egg.second->viewableChunks))
|
|
||||||
continue;
|
|
||||||
if (egg.second->deadUntil <= timeStamp) {
|
|
||||||
// respawn it
|
|
||||||
egg.second->dead = false;
|
|
||||||
egg.second->deadUntil = 0;
|
|
||||||
egg.second->appearanceData.iHP = 400;
|
|
||||||
|
|
||||||
Chunking::addNPCToChunks(Chunking::getViewableChunks(egg.second->chunkPos), egg.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void NPCManager::npcDataToEggData(sNPCAppearanceData* npc, sShinyAppearanceData* egg) {
|
|
||||||
egg->iX = npc->iX;
|
|
||||||
egg->iY = npc->iY;
|
|
||||||
egg->iZ = npc->iZ;
|
|
||||||
// client doesn't care about egg->iMapNum
|
|
||||||
egg->iShinyType = npc->iNPCType;
|
|
||||||
egg->iShiny_ID = npc->iNPC_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void eggPickup(CNSocket* sock, CNPacketData* data) {
|
|
||||||
if (data->size != sizeof(sP_CL2FE_REQ_SHINY_PICKUP))
|
|
||||||
return; // malformed packet
|
|
||||||
|
|
||||||
sP_CL2FE_REQ_SHINY_PICKUP* pickup = (sP_CL2FE_REQ_SHINY_PICKUP*)data->buf;
|
|
||||||
Player* plr = PlayerManager::getPlayer(sock);
|
|
||||||
|
|
||||||
int eggId = pickup->iShinyID;
|
|
||||||
|
|
||||||
if (Eggs.find(eggId) == Eggs.end()) {
|
|
||||||
std::cout << "[WARN] Player tried to open non existing egg?!" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Egg* egg = Eggs[eggId];
|
|
||||||
|
|
||||||
if (egg->dead) {
|
|
||||||
std::cout << "[WARN] Player tried to open a dead egg?!" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this has some issues with position desync, leaving it out for now
|
|
||||||
if (abs(egg->appearanceData.iX - plr->x)>500 || abs(egg->appearanceData.iY - plr->y) > 500) {
|
|
||||||
std::cout << "[WARN] Player tried to open an egg from the other chunk?!" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
int typeId = egg->appearanceData.iNPCType;
|
|
||||||
if (EggTypes.find(typeId) == EggTypes.end()) {
|
|
||||||
std::cout << "[WARN] Egg Type " << typeId << " not found!" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EggType* type = &EggTypes[typeId];
|
|
||||||
|
|
||||||
// buff the player
|
|
||||||
if (type->effectId != 0)
|
|
||||||
eggBuffPlayer(sock, type->effectId, eggId, type->duration);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SHINY_PICKUP_SUCC is only causing a GUI effect in the client
|
|
||||||
* (buff icon pops up in the bottom of the screen)
|
|
||||||
* so we don't send it for non-effect
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (type->effectId != 0)
|
|
||||||
{
|
|
||||||
INITSTRUCT(sP_FE2CL_REP_SHINY_PICKUP_SUCC, resp);
|
|
||||||
resp.iSkillID = type->effectId;
|
|
||||||
|
|
||||||
// in general client finds correct icon on it's own,
|
|
||||||
// but for damage we have to supply correct CSTB
|
|
||||||
if (resp.iSkillID == 183)
|
|
||||||
resp.eCSTB = ECSB_INFECTION;
|
|
||||||
|
|
||||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_SHINY_PICKUP_SUCC, sizeof(sP_FE2CL_REP_SHINY_PICKUP_SUCC));
|
|
||||||
}
|
|
||||||
|
|
||||||
// drop
|
|
||||||
if (type->dropCrateId != 0) {
|
|
||||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
|
||||||
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
|
|
||||||
sP_FE2CL_REP_REWARD_ITEM* reward = (sP_FE2CL_REP_REWARD_ITEM*)respbuf;
|
|
||||||
sItemReward* item = (sItemReward*)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
|
||||||
|
|
||||||
// don't forget to zero the buffer!
|
|
||||||
memset(respbuf, 0, resplen);
|
|
||||||
|
|
||||||
// send back player's stats
|
|
||||||
reward->m_iCandy = plr->money;
|
|
||||||
reward->m_iFusionMatter = plr->fusionmatter;
|
|
||||||
reward->m_iBatteryN = plr->batteryN;
|
|
||||||
reward->m_iBatteryW = plr->batteryW;
|
|
||||||
reward->iFatigue = 100; // prevents warning message
|
|
||||||
reward->iFatigue_Level = 1;
|
|
||||||
reward->iItemCnt = 1; // remember to update resplen if you change this
|
|
||||||
|
|
||||||
int slot = Items::findFreeSlot(plr);
|
|
||||||
|
|
||||||
// no space for drop
|
|
||||||
if (slot != -1) {
|
|
||||||
|
|
||||||
// item reward
|
|
||||||
item->sItem.iType = 9;
|
|
||||||
item->sItem.iOpt = 1;
|
|
||||||
item->sItem.iID = type->dropCrateId;
|
|
||||||
item->iSlotNum = slot;
|
|
||||||
item->eIL = 1; // Inventory Location. 1 means player inventory.
|
|
||||||
|
|
||||||
// update player
|
|
||||||
plr->Inven[slot] = item->sItem;
|
|
||||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (egg->summoned)
|
|
||||||
destroyNPC(eggId);
|
|
||||||
else {
|
|
||||||
Chunking::removeNPCFromChunks(Chunking::getViewableChunks(egg->chunkPos), eggId);
|
|
||||||
egg->dead = true;
|
|
||||||
egg->deadUntil = getTime() + (time_t)type->regen * 1000;
|
|
||||||
egg->appearanceData.iHP = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Move this to MobAI, possibly
|
// TODO: Move this to MobAI, possibly
|
||||||
#pragma region NPCEvents
|
#pragma region NPCEvents
|
||||||
|
|
||||||
@ -614,8 +370,4 @@ void NPCManager::init() {
|
|||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_SUMMON, npcSummonHandler);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_SUMMON, npcSummonHandler);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_UNSUMMON, npcUnsummonHandler);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_UNSUMMON, npcUnsummonHandler);
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_BARKER, npcBarkHandler);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_BARKER, npcBarkHandler);
|
||||||
|
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SHINY_PICKUP, eggPickup);
|
|
||||||
|
|
||||||
REGISTER_SHARD_TIMER(eggStep, 1000);
|
|
||||||
}
|
}
|
||||||
|
@ -33,33 +33,11 @@ struct WarpLocation {
|
|||||||
int x, y, z, instanceID, isInstance, limitTaskID, npcID;
|
int x, y, z, instanceID, isInstance, limitTaskID, npcID;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Egg : public BaseNPC {
|
|
||||||
bool summoned;
|
|
||||||
bool dead = false;
|
|
||||||
time_t deadUntil;
|
|
||||||
|
|
||||||
Egg(int x, int y, int z, uint64_t iID, int type, int32_t id, bool summon)
|
|
||||||
: BaseNPC(x, y, z, 0, iID, type, id) {
|
|
||||||
summoned = summon;
|
|
||||||
npcClass = NPCClass::NPC_EGG;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EggType {
|
|
||||||
int dropCrateId;
|
|
||||||
int effectId;
|
|
||||||
int duration;
|
|
||||||
int regen;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace NPCManager {
|
namespace NPCManager {
|
||||||
extern std::map<int32_t, BaseNPC*> NPCs;
|
extern std::map<int32_t, BaseNPC*> NPCs;
|
||||||
extern std::map<int32_t, WarpLocation> Warps;
|
extern std::map<int32_t, WarpLocation> Warps;
|
||||||
extern std::vector<WarpLocation> RespawnPoints;
|
extern std::vector<WarpLocation> RespawnPoints;
|
||||||
extern std::vector<NPCEvent> NPCEvents;
|
extern std::vector<NPCEvent> NPCEvents;
|
||||||
extern std::unordered_map<int, Egg*> Eggs;
|
|
||||||
extern std::map<std::pair<CNSocket*, int32_t>, time_t> EggBuffs;
|
|
||||||
extern std::unordered_map<int, EggType> EggTypes;
|
|
||||||
extern nlohmann::json NPCData;
|
extern nlohmann::json NPCData;
|
||||||
extern int32_t nextId;
|
extern int32_t nextId;
|
||||||
void init();
|
void init();
|
||||||
@ -72,8 +50,4 @@ namespace NPCManager {
|
|||||||
BaseNPC *summonNPC(int x, int y, int z, uint64_t instance, int type, bool respawn=false, bool baseInstance=false);
|
BaseNPC *summonNPC(int x, int y, int z, uint64_t instance, int type, bool respawn=false, bool baseInstance=false);
|
||||||
|
|
||||||
BaseNPC* getNearestNPC(std::set<Chunk*>* chunks, int X, int Y, int Z);
|
BaseNPC* getNearestNPC(std::set<Chunk*>* chunks, int X, int Y, int Z);
|
||||||
|
|
||||||
/// returns -1 on fail
|
|
||||||
int eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration);
|
|
||||||
void npcDataToEggData(sNPCAppearanceData* npc, sShinyAppearanceData* egg);
|
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "Racing.hpp"
|
#include "Racing.hpp"
|
||||||
#include "BuiltinCommands.hpp"
|
#include "BuiltinCommands.hpp"
|
||||||
#include "Abilities.hpp"
|
#include "Abilities.hpp"
|
||||||
|
#include "Eggs.hpp"
|
||||||
|
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
|
||||||
@ -72,10 +73,10 @@ void PlayerManager::removePlayer(CNSocket* key) {
|
|||||||
Chunking::destroyInstanceIfEmpty(fromInstance);
|
Chunking::destroyInstanceIfEmpty(fromInstance);
|
||||||
|
|
||||||
// remove player's buffs from the server
|
// remove player's buffs from the server
|
||||||
auto it = NPCManager::EggBuffs.begin();
|
auto it = Eggs::EggBuffs.begin();
|
||||||
while (it != NPCManager::EggBuffs.end()) {
|
while (it != Eggs::EggBuffs.end()) {
|
||||||
if (it->first.first == key) {
|
if (it->first.first == key) {
|
||||||
it = NPCManager::EggBuffs.erase(it);
|
it = Eggs::EggBuffs.erase(it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
it++;
|
it++;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "Racing.hpp"
|
#include "Racing.hpp"
|
||||||
#include "Vendor.hpp"
|
#include "Vendor.hpp"
|
||||||
#include "Abilities.hpp"
|
#include "Abilities.hpp"
|
||||||
|
#include "Eggs.hpp"
|
||||||
|
|
||||||
#include "JSON.hpp"
|
#include "JSON.hpp"
|
||||||
|
|
||||||
@ -378,7 +379,7 @@ static void loadEggs(int32_t* nextId) {
|
|||||||
toAdd.effectId = (int)eggType["EffectId"];
|
toAdd.effectId = (int)eggType["EffectId"];
|
||||||
toAdd.duration = (int)eggType["Duration"];
|
toAdd.duration = (int)eggType["Duration"];
|
||||||
toAdd.regen= (int)eggType["Regen"];
|
toAdd.regen= (int)eggType["Regen"];
|
||||||
NPCManager::EggTypes[(int)eggType["Id"]] = toAdd;
|
Eggs::EggTypes[(int)eggType["Id"]] = toAdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Egg instances
|
// Egg instances
|
||||||
@ -390,11 +391,11 @@ static void loadEggs(int32_t* nextId) {
|
|||||||
|
|
||||||
Egg* addEgg = new Egg((int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, (int)egg["iType"], id, false);
|
Egg* addEgg = new Egg((int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, (int)egg["iType"], id, false);
|
||||||
NPCManager::NPCs[id] = addEgg;
|
NPCManager::NPCs[id] = addEgg;
|
||||||
NPCManager::Eggs[id] = addEgg;
|
Eggs::Eggs[id] = addEgg;
|
||||||
NPCManager::updateNPCPosition(id, (int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, 0);
|
NPCManager::updateNPCPosition(id, (int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "[INFO] Loaded " <<NPCManager::Eggs.size()<<" eggs" <<std::endl;
|
std::cout << "[INFO] Loaded " <<Eggs::Eggs.size()<<" eggs" <<std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& err) {
|
catch (const std::exception& err) {
|
||||||
@ -539,7 +540,7 @@ static void loadGruntwork(int32_t *nextId) {
|
|||||||
|
|
||||||
Egg* addEgg = new Egg((int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, (int)egg["iType"], id, false);
|
Egg* addEgg = new Egg((int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, (int)egg["iType"], id, false);
|
||||||
NPCManager::NPCs[id] = addEgg;
|
NPCManager::NPCs[id] = addEgg;
|
||||||
NPCManager::Eggs[id] = addEgg;
|
Eggs::Eggs[id] = addEgg;
|
||||||
NPCManager::updateNPCPosition(id, (int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, 0);
|
NPCManager::updateNPCPosition(id, (int)egg["iX"], (int)egg["iY"], (int)egg["iZ"], instanceID, 0);
|
||||||
RunningEggs[id] = addEgg;
|
RunningEggs[id] = addEgg;
|
||||||
}
|
}
|
||||||
@ -1053,7 +1054,7 @@ void TableData::flush() {
|
|||||||
nlohmann::json egg;
|
nlohmann::json egg;
|
||||||
BaseNPC* npc = pair.second;
|
BaseNPC* npc = pair.second;
|
||||||
|
|
||||||
if (NPCManager::Eggs.find(pair.first) == NPCManager::Eggs.end())
|
if (Eggs::Eggs.find(pair.first) == Eggs::Eggs.end())
|
||||||
continue;
|
continue;
|
||||||
egg["iX"] = npc->appearanceData.iX;
|
egg["iX"] = npc->appearanceData.iX;
|
||||||
egg["iY"] = npc->appearanceData.iY;
|
egg["iY"] = npc->appearanceData.iY;
|
||||||
|
Loading…
Reference in New Issue
Block a user