/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef ULTIMA4_GAME_CREATURE_H #define ULTIMA4_GAME_CREATURE_H #include "ultima/ultima4/game/object.h" #include "ultima/ultima4/map/movement.h" #include "ultima/ultima4/filesys/savegame.h" #include "ultima/ultima4/core/types.h" namespace Ultima { namespace Ultima4 { class CombatController; class ConfigElement; class Tile; typedef unsigned short CreatureId; typedef Common::HashMap CreatureMap; typedef Std::vector CreatureVector; #define MAX_CREATURES 128 /* Creatures on world map */ #define MAX_CREATURES_ON_MAP 4 #define MAX_CREATURE_DISTANCE 16 /* Creature ids */ typedef enum { HORSE1_ID = 0, HORSE2_ID = 1, MAGE_ID = 2, BARD_ID = 3, FIGHTER_ID = 4, DRUID_ID = 5, TINKER_ID = 6, PALADIN_ID = 7, RANGER_ID = 8, SHEPHERD_ID = 9, GUARD_ID = 10, VILLAGER_ID = 11, SINGINGBARD_ID = 12, JESTER_ID = 13, BEGGAR_ID = 14, CHILD_ID = 15, BULL_ID = 16, LORDBRITISH_ID = 17, PIRATE_ID = 18, NIXIE_ID = 19, GIANT_SQUID_ID = 20, SEA_SERPENT_ID = 21, SEAHORSE_ID = 22, WHIRLPOOL_ID = 23, STORM_ID = 24, RAT_ID = 25, BAT_ID = 26, GIANT_SPIDER_ID = 27, GHOST_ID = 28, SLIME_ID = 29, TROLL_ID = 30, GREMLIN_ID = 31, MIMIC_ID = 32, REAPER_ID = 33, INSECT_SWARM_ID = 34, GAZER_ID = 35, PHANTOM_ID = 36, ORC_ID = 37, SKELETON_ID = 38, ROGUE_ID = 39, PYTHON_ID = 40, ETTIN_ID = 41, HEADLESS_ID = 42, CYCLOPS_ID = 43, WISP_ID = 44, EVILMAGE_ID = 45, LICH_ID = 46, LAVA_LIZARD_ID = 47, ZORN_ID = 48, DAEMON_ID = 49, HYDRA_ID = 50, DRAGON_ID = 51, BALRON_ID = 52 } CreatureType; typedef enum { MATTR_STEALFOOD = 0x1, MATTR_STEALGOLD = 0x2, MATTR_CASTS_SLEEP = 0x4, MATTR_UNDEAD = 0x8, MATTR_GOOD = 0x10, MATTR_WATER = 0x20, MATTR_NONATTACKABLE = 0x40, MATTR_NEGATE = 0x80, MATTR_CAMOUFLAGE = 0x100, MATTR_NOATTACK = 0x200, MATTR_AMBUSHES = 0x400, MATTR_RANDOMRANGED = 0x800, MATTR_INCORPOREAL = 0x1000, MATTR_NOCHEST = 0x2000, MATTR_DIVIDES = 0x4000, MATTR_SPAWNSONDEATH = 0x8000, MATTR_FORCE_OF_NATURE = 0x10000 } CreatureAttrib; typedef enum { MATTR_STATIONARY = 0x1, MATTR_WANDERS = 0x2, MATTR_SWIMS = 0x4, MATTR_SAILS = 0x8, MATTR_FLIES = 0x10, MATTR_TELEPORT = 0x20, MATTR_CANMOVECREATURES = 0x40, MATTR_CANMOVEAVATAR = 0x80 } CreatureMovementAttrib; typedef enum { MSTAT_DEAD, MSTAT_FLEEING, MSTAT_CRITICAL, MSTAT_HEAVILYWOUNDED, MSTAT_LIGHTLYWOUNDED, MSTAT_BARELYWOUNDED } CreatureStatus; /** * Creature Class Definition * @todo *
    *
  • split into a CreatureType (all the settings for a * particular creature e.g. orc) and Creature (a specific * creature instance)
  • *
  • creatures can be looked up by name, ids can probably go away
  • *
*/ class Creature : public Object { typedef Common::List StatusList; public: /** * Creature class implementation */ Creature(MapTile tile = MapTile(0)); void load(const ConfigElement &conf); // Accessor methods virtual Common::String getName() const { return _name; } virtual const Common::String &getHitTile() const { return _rangedHitTile; } virtual const Common::String &getMissTile() const { return _rangedMissTile; } CreatureId getId() const { return _id; } CreatureId getLeader() const { return _leader; } virtual int getHp() const { return _hp; } virtual int getXp() const { return _xp; } virtual const Common::String &getWorldrangedtile() const { return _worldRangedTile; } SlowedType getSlowedType() const { return _slowedType; } int getEncounterSize() const { return _encounterSize; } byte getResists() const { return _resists; } // Setters void setName(Common::String s) { _name = s; } void setHitTile(const Common::String &t) { _rangedHitTile = t; } void setMissTile(const Common::String &t) { _rangedMissTile = t; } virtual void setHp(int points) { _hp = points; } // Query methods bool isGood() const { return _mAttr & MATTR_GOOD; } bool isEvil() const { return !isGood(); } bool isUndead() const { return _mAttr & MATTR_UNDEAD; } bool leavesChest() const { return !isAquatic() && !(_mAttr & MATTR_NOCHEST); } bool isAquatic() const { return _mAttr & MATTR_WATER; } bool wanders() const { return _movementAttr & MATTR_WANDERS; } bool isStationary() const { return _movementAttr & MATTR_STATIONARY; } bool flies() const { return _movementAttr & MATTR_FLIES; } bool teleports() const { return _movementAttr & MATTR_TELEPORT; } bool swims() const { return _movementAttr & MATTR_SWIMS; } bool sails() const { return _movementAttr & MATTR_SAILS; } bool walks() const { return !(flies() || swims() || sails()); } bool divides() const { return _mAttr & MATTR_DIVIDES; } bool spawnsOnDeath() const { return _mAttr & MATTR_SPAWNSONDEATH; } bool canMoveOntoCreatures() const { return _movementAttr & MATTR_CANMOVECREATURES; } bool canMoveOntoPlayer() const { return _movementAttr & MATTR_CANMOVEAVATAR; } bool isAttackable() const; bool willAttack() const { return !(_mAttr & MATTR_NOATTACK); } bool stealsGold() const { return _mAttr & MATTR_STEALGOLD; } bool stealsFood() const { return _mAttr & MATTR_STEALFOOD; } bool negates() const { return _mAttr & MATTR_NEGATE; } bool camouflages() const { return _mAttr & MATTR_CAMOUFLAGE; } bool ambushes() const { return _mAttr & MATTR_AMBUSHES; } bool isIncorporeal() const { return _mAttr & MATTR_INCORPOREAL; } bool hasRandomRanged() const { return _mAttr & MATTR_RANDOMRANGED; } bool leavesTile() const { return _leavesTile; } bool castsSleep() const { return _mAttr & MATTR_CASTS_SLEEP; } bool isForceOfNature() const { return _mAttr & MATTR_FORCE_OF_NATURE; } int getDamage() const; const Common::String &getCamouflageTile() const { return _camouflageTile; } void setRandomRanged(); int setInitialHp(int hp = -1); /** * Performs a special action for the creature * Returns true if the action takes up the creatures * whole turn (i.e. it can't move afterwards) */ bool specialAction(); /** * Performs a special effect for the creature * Returns true if something special happened, * or false if nothing happened */ bool specialEffect(); /* combat methods */ void act(CombatController *controller); /** * Add status effects to the creature, in order of importance */ virtual void addStatus(StatusType status); void applyTileEffect(TileEffect effect); virtual int getAttackBonus() const; virtual int getDefense() const; bool divide(); bool spawnOnDeath(); virtual CreatureStatus getState() const; StatusType getStatus() const; bool isAsleep() const; /** * Hides or shows a camouflaged creature, depending on its distance from * the nearest opponent */ bool hideOrShow(); Creature *nearestOpponent(int *dist, bool ranged); virtual void putToSleep(); virtual void removeStatus(StatusType status); virtual void setStatus(StatusType status); virtual void wakeUp(); /** * Applies damage to the creature. * Returns true if the creature still exists after the damage has been applied * or false, if the creature was destroyed * * If byplayer is false (when a monster is killed by walking through * fire or poison, or as a result of jinx) we don't report experience * on death */ virtual bool applyDamage(int damage, bool byplayer = true); virtual bool dealDamage(Creature *m, int damage); // Properties protected: Common::String _name; Common::String _rangedHitTile; Common::String _rangedMissTile; CreatureId _id; Common::String _camouflageTile; CreatureId _leader; int _baseHp; int _hp; StatusList _status; int _xp; byte _ranged; Common::String _worldRangedTile; bool _leavesTile; CreatureAttrib _mAttr; CreatureMovementAttrib _movementAttr; SlowedType _slowedType; int _encounterSize; byte _resists; CreatureId _spawn; }; /** * CreatureMgr Class Definition */ class CreatureMgr { public: static CreatureMgr *getInstance(); void loadAll(); /** * Returns a creature using a tile to find which one to create * or nullptr if a creature with that tile cannot be found */ Creature *getByTile(MapTile tile); /** * Returns the creature that has the corresponding id * or returns nullptr if no creature with that id could * be found. */ Creature *getById(CreatureId id); /** * Returns the creature that has the corresponding name * or returns nullptr if no creature can be found with * that name (case insensitive) */ Creature *getByName(Common::String name); /** * Creates a random creature based on the tile given */ Creature *randomForTile(const Tile *tile); /** * Creates a random creature based on the dungeon level given */ Creature *randomForDungeon(int dnglevel); /** * Creates a random ambushing creature */ Creature *randomAmbushing(); private: CreatureMgr() {} // disallow assignments, copy construction CreatureMgr(const CreatureMgr &); const CreatureMgr &operator=(const CreatureMgr &); static CreatureMgr *_instance; CreatureMap _creatures; }; bool isCreature(Object *punknown); #define creatureMgr (CreatureMgr::getInstance()) } // End of namespace Ultima4 } // End of namespace Ultima #endif