1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifndef ULTIMA4_GAME_CREATURE_H
24 #define ULTIMA4_GAME_CREATURE_H
25 
26 #include "ultima/ultima4/game/object.h"
27 #include "ultima/ultima4/map/movement.h"
28 #include "ultima/ultima4/filesys/savegame.h"
29 #include "ultima/ultima4/core/types.h"
30 
31 namespace Ultima {
32 namespace Ultima4 {
33 
34 class CombatController;
35 class ConfigElement;
36 class Tile;
37 
38 typedef unsigned short CreatureId;
39 typedef Std::map<CreatureId, class Creature *> CreatureMap;
40 typedef Std::vector<class Creature *> CreatureVector;
41 
42 #define MAX_CREATURES 128
43 
44 /* Creatures on world map */
45 
46 #define MAX_CREATURES_ON_MAP 4
47 #define MAX_CREATURE_DISTANCE 16
48 
49 /* Creature ids */
50 
51 typedef enum {
52 	HORSE1_ID       = 0,
53 	HORSE2_ID       = 1,
54 
55 	MAGE_ID         = 2,
56 	BARD_ID         = 3,
57 	FIGHTER_ID      = 4,
58 	DRUID_ID        = 5,
59 	TINKER_ID       = 6,
60 	PALADIN_ID      = 7,
61 	RANGER_ID       = 8,
62 	SHEPHERD_ID     = 9,
63 
64 	GUARD_ID        = 10,
65 	VILLAGER_ID     = 11,
66 	SINGINGBARD_ID  = 12,
67 	JESTER_ID       = 13,
68 	BEGGAR_ID       = 14,
69 	CHILD_ID        = 15,
70 	BULL_ID         = 16,
71 	LORDBRITISH_ID  = 17,
72 
73 	PIRATE_ID       = 18,
74 	NIXIE_ID        = 19,
75 	GIANT_SQUID_ID  = 20,
76 	SEA_SERPENT_ID  = 21,
77 	SEAHORSE_ID     = 22,
78 	WHIRLPOOL_ID    = 23,
79 	STORM_ID        = 24,
80 	RAT_ID          = 25,
81 	BAT_ID          = 26,
82 	GIANT_SPIDER_ID = 27,
83 	GHOST_ID        = 28,
84 	SLIME_ID        = 29,
85 	TROLL_ID        = 30,
86 	GREMLIN_ID      = 31,
87 	MIMIC_ID        = 32,
88 	REAPER_ID       = 33,
89 	INSECT_SWARM_ID = 34,
90 	GAZER_ID        = 35,
91 	PHANTOM_ID      = 36,
92 	ORC_ID          = 37,
93 	SKELETON_ID     = 38,
94 	ROGUE_ID        = 39,
95 	PYTHON_ID       = 40,
96 	ETTIN_ID        = 41,
97 	HEADLESS_ID     = 42,
98 	CYCLOPS_ID      = 43,
99 	WISP_ID         = 44,
100 	EVILMAGE_ID     = 45,
101 	LICH_ID         = 46,
102 	LAVA_LIZARD_ID  = 47,
103 	ZORN_ID         = 48,
104 	DAEMON_ID       = 49,
105 	HYDRA_ID        = 50,
106 	DRAGON_ID       = 51,
107 	BALRON_ID       = 52
108 } CreatureType;
109 
110 typedef enum {
111 	MATTR_STEALFOOD     = 0x1,
112 	MATTR_STEALGOLD     = 0x2,
113 	MATTR_CASTS_SLEEP   = 0x4,
114 	MATTR_UNDEAD        = 0x8,
115 	MATTR_GOOD          = 0x10,
116 	MATTR_WATER         = 0x20,
117 	MATTR_NONATTACKABLE = 0x40,
118 	MATTR_NEGATE        = 0x80,
119 	MATTR_CAMOUFLAGE    = 0x100,
120 	MATTR_NOATTACK      = 0x200,
121 	MATTR_AMBUSHES      = 0x400,
122 	MATTR_RANDOMRANGED  = 0x800,
123 	MATTR_INCORPOREAL   = 0x1000,
124 	MATTR_NOCHEST       = 0x2000,
125 	MATTR_DIVIDES       = 0x4000,
126 	MATTR_SPAWNSONDEATH = 0x8000,
127 	MATTR_FORCE_OF_NATURE = 0x10000
128 } CreatureAttrib;
129 
130 typedef enum {
131 	MATTR_STATIONARY        = 0x1,
132 	MATTR_WANDERS           = 0x2,
133 	MATTR_SWIMS             = 0x4,
134 	MATTR_SAILS             = 0x8,
135 	MATTR_FLIES             = 0x10,
136 	MATTR_TELEPORT          = 0x20,
137 	MATTR_CANMOVECREATURES  = 0x40,
138 	MATTR_CANMOVEAVATAR     = 0x80
139 } CreatureMovementAttrib;
140 
141 typedef enum {
142 	MSTAT_DEAD,
143 	MSTAT_FLEEING,
144 	MSTAT_CRITICAL,
145 	MSTAT_HEAVILYWOUNDED,
146 	MSTAT_LIGHTLYWOUNDED,
147 	MSTAT_BARELYWOUNDED
148 } CreatureStatus;
149 
150 /**
151  * Creature Class Definition
152  * @todo
153  * <ul>
154  *      <li>split into a CreatureType (all the settings for a
155  *      particular creature e.g. orc) and Creature (a specific
156  *      creature instance)</li>
157  *      <li>creatures can be looked up by name, ids can probably go away</li>
158  * </ul>
159  */
160 class Creature : public Object {
161 	typedef Common::List<StatusType> StatusList;
162 
163 public:
164 	/**
165 	 * Creature class implementation
166 	 */
167 	Creature(MapTile tile = MapTile(0));
168 
169 	void load(const ConfigElement &conf);
170 
171 	// Accessor methods
getName()172 	virtual Common::String getName() const {
173 		return _name;
174 	}
getHitTile()175 	virtual const Common::String &getHitTile() const {
176 		return _rangedHitTile;
177 	}
getMissTile()178 	virtual const Common::String &getMissTile() const {
179 		return _rangedMissTile;
180 	}
getId()181 	CreatureId getId() const {
182 		return _id;
183 	}
getLeader()184 	CreatureId getLeader() const {
185 		return _leader;
186 	}
getHp()187 	virtual int getHp() const {
188 		return _hp;
189 	}
getXp()190 	virtual int getXp() const {
191 		return _xp;
192 	}
getWorldrangedtile()193 	virtual const Common::String &getWorldrangedtile() const {
194 		return _worldRangedTile;
195 	}
getSlowedType()196 	SlowedType getSlowedType() const {
197 		return _slowedType;
198 	}
getEncounterSize()199 	int getEncounterSize() const {
200 		return _encounterSize;
201 	}
getResists()202 	byte getResists() const {
203 		return _resists;
204 	}
205 
206 	// Setters
setName(Common::String s)207 	void setName(Common::String s) {
208 		_name = s;
209 	}
setHitTile(const Common::String & t)210 	void setHitTile(const Common::String &t) {
211 		_rangedHitTile = t;
212 	}
setMissTile(const Common::String & t)213 	void setMissTile(const Common::String &t) {
214 		_rangedMissTile = t;
215 	}
setHp(int points)216 	virtual void setHp(int points) {
217 		_hp = points;
218 	}
219 
220 	// Query methods
isGood()221 	bool isGood() const {
222 		return _mAttr & MATTR_GOOD;
223 	}
isEvil()224 	bool isEvil() const {
225 		return !isGood();
226 	}
isUndead()227 	bool isUndead() const {
228 		return _mAttr & MATTR_UNDEAD;
229 	}
leavesChest()230 	bool leavesChest() const {
231 		return !isAquatic() && !(_mAttr & MATTR_NOCHEST);
232 	}
isAquatic()233 	bool isAquatic() const {
234 		return _mAttr & MATTR_WATER;
235 	}
wanders()236 	bool wanders() const {
237 		return _movementAttr & MATTR_WANDERS;
238 	}
isStationary()239 	bool isStationary() const {
240 		return _movementAttr & MATTR_STATIONARY;
241 	}
flies()242 	bool flies() const {
243 		return _movementAttr & MATTR_FLIES;
244 	}
teleports()245 	bool teleports() const {
246 		return _movementAttr & MATTR_TELEPORT;
247 	}
swims()248 	bool swims() const {
249 		return _movementAttr & MATTR_SWIMS;
250 	}
sails()251 	bool sails() const {
252 		return _movementAttr & MATTR_SAILS;
253 	}
walks()254 	bool walks() const {
255 		return !(flies() || swims() || sails());
256 	}
divides()257 	bool divides() const {
258 		return _mAttr & MATTR_DIVIDES;
259 	}
spawnsOnDeath()260 	bool spawnsOnDeath() const {
261 		return _mAttr & MATTR_SPAWNSONDEATH;
262 	}
canMoveOntoCreatures()263 	bool canMoveOntoCreatures() const {
264 		return _movementAttr & MATTR_CANMOVECREATURES;
265 	}
canMoveOntoPlayer()266 	bool canMoveOntoPlayer() const {
267 		return _movementAttr & MATTR_CANMOVEAVATAR;
268 	}
269 	bool isAttackable() const;
willAttack()270 	bool willAttack() const {
271 		return !(_mAttr & MATTR_NOATTACK);
272 	}
stealsGold()273 	bool stealsGold() const {
274 		return _mAttr & MATTR_STEALGOLD;
275 	}
stealsFood()276 	bool stealsFood() const {
277 		return _mAttr & MATTR_STEALFOOD;
278 	}
negates()279 	bool negates() const {
280 		return _mAttr & MATTR_NEGATE;
281 	}
camouflages()282 	bool camouflages() const {
283 		return _mAttr & MATTR_CAMOUFLAGE;
284 	}
ambushes()285 	bool ambushes() const {
286 		return _mAttr & MATTR_AMBUSHES;
287 	}
isIncorporeal()288 	bool isIncorporeal() const {
289 		return _mAttr & MATTR_INCORPOREAL;
290 	}
hasRandomRanged()291 	bool hasRandomRanged() const {
292 		return _mAttr & MATTR_RANDOMRANGED;
293 	}
leavesTile()294 	bool leavesTile() const {
295 		return _leavesTile;
296 	}
castsSleep()297 	bool castsSleep() const {
298 		return _mAttr & MATTR_CASTS_SLEEP;
299 	}
isForceOfNature()300 	bool isForceOfNature() const {
301 		return _mAttr & MATTR_FORCE_OF_NATURE;
302 	}
303 	int getDamage() const;
getCamouflageTile()304 	const Common::String &getCamouflageTile() const {
305 		return _camouflageTile;
306 	}
307 	void setRandomRanged();
308 	int setInitialHp(int hp = -1);
309 
310 	/**
311 	 * Performs a special action for the creature
312 	 * Returns true if the action takes up the creatures
313 	 * whole turn (i.e. it cant move afterwords)
314 	 */
315 	bool specialAction();
316 
317 	/**
318 	 * Performs a special effect for the creature
319 	 * Returns true if something special happened,
320 	 * or false if nothing happened
321 	 */
322 	bool specialEffect();
323 
324 	/* combat methods */
325 	void act(CombatController *controller);
326 
327 	/**
328 	 * Add status effects to the creature, in order of importance
329 	 */
330 	virtual void addStatus(StatusType status);
331 	void applyTileEffect(TileEffect effect);
332 	virtual int getAttackBonus() const;
333 	virtual int getDefense() const;
334 	bool divide();
335 	bool spawnOnDeath();
336 	virtual CreatureStatus getState() const;
337 	StatusType getStatus() const;
338 	bool isAsleep() const;
339 
340 	/**
341 	 * Hides or shows a camouflaged creature, depending on its distance from
342 	 * the nearest opponent
343 	 */
344 	bool hideOrShow();
345 
346 	Creature *nearestOpponent(int *dist, bool ranged);
347 	virtual void putToSleep();
348 	virtual void removeStatus(StatusType status);
349 	virtual void setStatus(StatusType status);
350 	virtual void wakeUp();
351 
352 	/**
353 	 * Applies damage to the creature.
354 	 * Returns true if the creature still exists after the damage has been applied
355 	 * or false, if the creature was destroyed
356 	 *
357 	 * If byplayer is false (when a monster is killed by walking through
358 	 * fire or poison, or as a result of jinx) we don't report experience
359 	 * on death
360 	 */
361 	virtual bool applyDamage(int damage, bool byplayer = true);
362 	virtual bool dealDamage(Creature *m, int damage);
363 
364 	// Properties
365 protected:
366 	Common::String _name;
367 	Common::String _rangedHitTile;
368 	Common::String _rangedMissTile;
369 	CreatureId     _id;
370 	Common::String _camouflageTile;
371 	CreatureId     _leader;
372 	int            _baseHp;
373 	int            _hp;
374 	StatusList     _status;
375 	int            _xp;
376 	byte  _ranged;
377 	Common::String _worldRangedTile;
378 	bool           _leavesTile;
379 	CreatureAttrib _mAttr;
380 	CreatureMovementAttrib _movementAttr;
381 	SlowedType     _slowedType;
382 	int            _encounterSize;
383 	byte  _resists;
384 	CreatureId     _spawn;
385 };
386 
387 /**
388  * CreatureMgr Class Definition
389  */
390 class CreatureMgr {
391 public:
392 	static CreatureMgr *getInstance();
393 
394 	void loadAll();
395 
396 	/**
397 	 * Returns a creature using a tile to find which one to create
398 	 * or nullptr if a creature with that tile cannot be found
399 	 */
400 	Creature *getByTile(MapTile tile);
401 
402 	/**
403 	 * Returns the creature that has the corresponding id
404 	 * or returns nullptr if no creature with that id could
405 	 * be found.
406 	 */
407 	Creature *getById(CreatureId id);
408 
409 	/**
410 	 * Returns the creature that has the corresponding name
411 	 * or returns nullptr if no creature can be found with
412 	 * that name (case insensitive)
413 	 */
414 	Creature *getByName(Common::String name);
415 
416 	/**
417 	 * Creates a random creature based on the tile given
418 	 */
419 	Creature *randomForTile(const Tile *tile);
420 
421 	/**
422 	 * Creates a random creature based on the dungeon level given
423 	 */
424 	Creature *randomForDungeon(int dnglevel);
425 
426 	/**
427 	 * Creates a random ambushing creature
428 	 */
429 	Creature *randomAmbushing();
430 
431 private:
CreatureMgr()432 	CreatureMgr() {}
433 
434 	// disallow assignments, copy contruction
435 	CreatureMgr(const CreatureMgr &);
436 	const CreatureMgr &operator=(const CreatureMgr &);
437 
438 	static CreatureMgr *_instance;
439 
440 	CreatureMap _creatures;
441 };
442 
443 bool isCreature(Object *punknown);
444 
445 #define creatureMgr (CreatureMgr::getInstance())
446 
447 } // End of namespace Ultima4
448 } // End of namespace Ultima
449 
450 #endif
451