#pragma once #include "core/Core.hpp" #include "Chunking.hpp" #include #include enum class EntityType : uint8_t { INVALID, PLAYER, SIMPLE_NPC, COMBAT_NPC, MOB, EGG, BUS }; struct Entity { EntityType kind = EntityType::INVALID; int x = 0, y = 0, z = 0; uint64_t instanceID = 0; ChunkPos chunkPos = {}; std::set viewableChunks = {}; // destructor must be virtual, apparently virtual ~Entity() {} virtual bool isAlive() { return true; } // stubs virtual void enterIntoViewOf(CNSocket *sock) = 0; virtual void disappearFromViewOf(CNSocket *sock) = 0; }; struct EntityRef { EntityType type; union { CNSocket *sock; int32_t id; }; EntityRef(CNSocket *s); EntityRef(int32_t i); bool isValid() const; Entity *getEntity() const; bool operator==(const EntityRef& other) const { if (type != other.type) return false; if (type == EntityType::PLAYER) return sock == other.sock; return id == other.id; } // arbitrary ordering bool operator<(const EntityRef& other) const { if (type == other.type) { if (type == EntityType::PLAYER) return sock < other.sock; else return id < other.id; } return type < other.type; } }; /* * Subclasses */ class BaseNPC : public Entity { public: int id; int type; int hp; int angle; int cbf; int barkerType; bool loopingPath = false; BaseNPC(int _A, uint64_t iID, int t, int _id) { type = t; hp = 400; angle = _A; cbf = 0; barkerType = 0; id = _id; instanceID = iID; }; virtual void enterIntoViewOf(CNSocket *sock) override; virtual void disappearFromViewOf(CNSocket *sock) override; sNPCAppearanceData getAppearanceData(); }; struct CombatNPC : public BaseNPC { int maxHealth = 0; int spawnX = 0; int spawnY = 0; int spawnZ = 0; int level = 0; int speed = 300; void (*_stepAI)(CombatNPC*, time_t) = nullptr; CombatNPC(int x, int y, int z, int angle, uint64_t iID, int t, int id, int maxHP) : BaseNPC(angle, iID, t, id), maxHealth(maxHP) { spawnX = x; spawnY = y; spawnZ = z; } virtual void stepAI(time_t currTime) { if (_stepAI != nullptr) _stepAI(this, currTime); } virtual bool isAlive() override { return hp > 0; } }; // Mob is in MobAI.hpp, Player is in Player.hpp // TODO: decouple from BaseNPC struct Egg : public BaseNPC { bool summoned = false; bool dead = false; time_t deadUntil; Egg(uint64_t iID, int t, int32_t id, bool summon) : BaseNPC(0, iID, t, id) { summoned = summon; kind = EntityType::EGG; } virtual bool isAlive() override { return !dead; } virtual void enterIntoViewOf(CNSocket *sock) override; virtual void disappearFromViewOf(CNSocket *sock) override; }; // TODO: decouple from BaseNPC struct Bus : public BaseNPC { Bus(int angle, uint64_t iID, int t, int id) : BaseNPC(angle, iID, t, id) { kind = EntityType::BUS; loopingPath = true; } virtual void enterIntoViewOf(CNSocket *sock) override; virtual void disappearFromViewOf(CNSocket *sock) override; };