2021-03-21 01:42:45 +00:00
|
|
|
#include "core/Core.hpp"
|
|
|
|
#include "Entities.hpp"
|
|
|
|
#include "Chunking.hpp"
|
|
|
|
#include "PlayerManager.hpp"
|
|
|
|
#include "NPCManager.hpp"
|
|
|
|
#include "Eggs.hpp"
|
2021-03-22 16:53:46 +00:00
|
|
|
#include "MobAI.hpp"
|
2021-03-21 01:42:45 +00:00
|
|
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
static_assert(std::is_standard_layout<EntityRef>::value);
|
|
|
|
static_assert(std::is_trivially_copyable<EntityRef>::value);
|
|
|
|
|
|
|
|
EntityRef::EntityRef(CNSocket *s) {
|
2022-04-13 19:56:12 +00:00
|
|
|
kind = EntityKind::PLAYER;
|
2021-03-21 01:42:45 +00:00
|
|
|
sock = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
EntityRef::EntityRef(int32_t i) {
|
|
|
|
id = i;
|
|
|
|
|
|
|
|
assert(NPCManager::NPCs.find(id) != NPCManager::NPCs.end());
|
2022-04-13 19:56:12 +00:00
|
|
|
kind = NPCManager::NPCs[id]->kind;
|
2021-03-21 01:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool EntityRef::isValid() const {
|
2022-04-13 19:56:12 +00:00
|
|
|
if (kind == EntityKind::PLAYER)
|
2021-03-21 01:42:45 +00:00
|
|
|
return PlayerManager::players.find(sock) != PlayerManager::players.end();
|
|
|
|
|
|
|
|
return NPCManager::NPCs.find(id) != NPCManager::NPCs.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
Entity *EntityRef::getEntity() const {
|
|
|
|
assert(isValid());
|
|
|
|
|
2022-04-13 19:56:12 +00:00
|
|
|
if (kind == EntityKind::PLAYER)
|
2021-03-21 01:42:45 +00:00
|
|
|
return PlayerManager::getPlayer(sock);
|
|
|
|
|
|
|
|
return NPCManager::NPCs[id];
|
|
|
|
}
|
|
|
|
|
2021-06-20 18:37:37 +00:00
|
|
|
sNPCAppearanceData BaseNPC::getAppearanceData() {
|
|
|
|
sNPCAppearanceData data = {};
|
|
|
|
data.iAngle = angle;
|
2022-04-13 18:18:54 +00:00
|
|
|
data.iBarkerType = 0; // unused?
|
2021-06-20 18:37:37 +00:00
|
|
|
data.iConditionBitFlag = cbf;
|
|
|
|
data.iHP = hp;
|
|
|
|
data.iNPCType = type;
|
|
|
|
data.iNPC_ID = id;
|
|
|
|
data.iX = x;
|
|
|
|
data.iY = y;
|
|
|
|
data.iZ = z;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2021-03-21 01:42:45 +00:00
|
|
|
/*
|
|
|
|
* Entity coming into view.
|
|
|
|
*/
|
|
|
|
void BaseNPC::enterIntoViewOf(CNSocket *sock) {
|
|
|
|
INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt);
|
2021-06-20 18:37:37 +00:00
|
|
|
pkt.NPCAppearanceData = getAppearanceData();
|
2021-03-21 01:42:45 +00:00
|
|
|
sock->sendPacket(pkt, P_FE2CL_NPC_ENTER);
|
2021-03-22 16:53:46 +00:00
|
|
|
}
|
2021-03-21 01:42:45 +00:00
|
|
|
|
|
|
|
void Bus::enterIntoViewOf(CNSocket *sock) {
|
|
|
|
INITSTRUCT(sP_FE2CL_TRANSPORTATION_ENTER, pkt);
|
|
|
|
|
|
|
|
// TODO: Potentially decouple this from BaseNPC?
|
|
|
|
pkt.AppearanceData = {
|
2021-06-20 18:37:37 +00:00
|
|
|
3, id, type,
|
2021-04-14 00:57:24 +00:00
|
|
|
x, y, z
|
2021-03-21 01:42:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
sock->sendPacket(pkt, P_FE2CL_TRANSPORTATION_ENTER);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Egg::enterIntoViewOf(CNSocket *sock) {
|
|
|
|
INITSTRUCT(sP_FE2CL_SHINY_ENTER, pkt);
|
|
|
|
|
2021-06-20 18:37:37 +00:00
|
|
|
// TODO: Potentially decouple this from BaseNPC?
|
|
|
|
pkt.ShinyAppearanceData = {
|
|
|
|
id, type, 0, // client doesn't care about map num
|
|
|
|
x, y, z
|
|
|
|
};
|
2021-03-21 01:42:45 +00:00
|
|
|
|
|
|
|
sock->sendPacket(pkt, P_FE2CL_SHINY_ENTER);
|
|
|
|
}
|
2021-06-20 18:37:37 +00:00
|
|
|
|
|
|
|
sPCAppearanceData Player::getAppearanceData() {
|
|
|
|
sPCAppearanceData data = {};
|
|
|
|
data.iID = iID;
|
|
|
|
data.iHP = HP;
|
|
|
|
data.iLv = level;
|
|
|
|
data.iX = x;
|
|
|
|
data.iY = y;
|
|
|
|
data.iZ = z;
|
|
|
|
data.iAngle = angle;
|
|
|
|
data.PCStyle = PCStyle;
|
|
|
|
data.Nano = Nanos[activeNano];
|
|
|
|
data.iPCState = iPCState;
|
|
|
|
data.iSpecialState = iSpecialState;
|
|
|
|
memcpy(data.ItemEquip, Equip, sizeof(sItemBase) * AEQUIP_COUNT);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2021-03-21 01:42:45 +00:00
|
|
|
// TODO: this is less effiecient than it was, because of memset()
|
|
|
|
void Player::enterIntoViewOf(CNSocket *sock) {
|
|
|
|
INITSTRUCT(sP_FE2CL_PC_NEW, pkt);
|
2021-06-20 18:37:37 +00:00
|
|
|
pkt.PCAppearanceData = getAppearanceData();
|
2021-03-21 01:42:45 +00:00
|
|
|
sock->sendPacket(pkt, P_FE2CL_PC_NEW);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Entity leaving view.
|
|
|
|
*/
|
|
|
|
void BaseNPC::disappearFromViewOf(CNSocket *sock) {
|
|
|
|
INITSTRUCT(sP_FE2CL_NPC_EXIT, pkt);
|
2021-06-20 18:37:37 +00:00
|
|
|
pkt.iNPC_ID = id;
|
2021-03-21 01:42:45 +00:00
|
|
|
sock->sendPacket(pkt, P_FE2CL_NPC_EXIT);
|
2021-03-22 16:53:46 +00:00
|
|
|
}
|
2021-03-21 01:42:45 +00:00
|
|
|
|
|
|
|
void Bus::disappearFromViewOf(CNSocket *sock) {
|
|
|
|
INITSTRUCT(sP_FE2CL_TRANSPORTATION_EXIT, pkt);
|
|
|
|
pkt.eTT = 3;
|
2021-06-20 18:37:37 +00:00
|
|
|
pkt.iT_ID = id;
|
2021-03-21 01:42:45 +00:00
|
|
|
sock->sendPacket(pkt, P_FE2CL_TRANSPORTATION_EXIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Egg::disappearFromViewOf(CNSocket *sock) {
|
|
|
|
INITSTRUCT(sP_FE2CL_SHINY_EXIT, pkt);
|
2021-06-20 18:37:37 +00:00
|
|
|
pkt.iShinyID = id;
|
2021-03-21 01:42:45 +00:00
|
|
|
sock->sendPacket(pkt, P_FE2CL_SHINY_EXIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::disappearFromViewOf(CNSocket *sock) {
|
|
|
|
INITSTRUCT(sP_FE2CL_PC_EXIT, pkt);
|
|
|
|
pkt.iID = iID;
|
|
|
|
sock->sendPacket(pkt, P_FE2CL_PC_EXIT);
|
|
|
|
}
|