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 WORLD_ACTORS_ACTOR_H
24 #define WORLD_ACTORS_ACTOR_H
25 
26 #include "ultima/ultima8/world/container.h"
27 #include "ultima/ultima8/usecode/intrinsics.h"
28 #include "ultima/ultima8/world/actors/animation.h"
29 
30 namespace Ultima {
31 namespace Ultima8 {
32 
33 class ActorAnimProcess;
34 struct PathfindingState;
35 class CombatProcess;
36 class AttackProcess;
37 
38 class Actor : public Container {
39 	friend class ActorAnimProcess;
40 	friend class AnimationTracker;
41 public:
42 	Actor();
43 	~Actor() override;
44 
getStr()45 	int16 getStr() const {
46 		return _strength;
47 	}
setStr(int16 str)48 	void setStr(int16 str) {
49 		_strength = str;
50 	}
getDex()51 	int16 getDex() const {
52 		return _dexterity;
53 	}
setDex(int16 dex)54 	void setDex(int16 dex) {
55 		_dexterity = dex;
56 	}
getInt()57 	int16 getInt() const {
58 		return _intelligence;
59 	}
setInt(int16 intl)60 	void setInt(int16 intl) {
61 		_intelligence = intl;
62 	}
getHP()63 	uint16 getHP() const {
64 		return _hitPoints;
65 	}
setHP(uint16 hp)66 	void setHP(uint16 hp) {
67 		_hitPoints = hp;
68 	}
getMana()69 	int16 getMana() const {
70 		return _mana;
71 	}
setMana(int16 mp)72 	void setMana(int16 mp) {
73 		_mana = mp;
74 	}
75 
76 	int16 getMaxMana() const;
77 	uint16 getMaxHP() const;
78 
isDead()79 	bool isDead() const {
80 		return (_actorFlags & ACT_DEAD) != 0;
81 	}
82 
isInCombat()83 	bool isInCombat() const {
84 		return (_actorFlags & ACT_INCOMBAT) != 0;
85 	}
86 
isKneeling()87 	bool isKneeling() const {
88 		return (_actorFlags & ACT_KNEELING) != 0;
89 	}
90 
91 	bool isFalling() const;
92 
93 	CombatProcess *getCombatProcess(); 	// in U8
94 	AttackProcess *getAttackProcess();	// in Crusader
95 	virtual void setInCombat(int activity);
96 	virtual void clearInCombat();
97 
getAlignment()98 	uint16 getAlignment() const {
99 		return _alignment;
100 	}
setAlignment(uint16 a)101 	void setAlignment(uint16 a) {
102 		_alignment = a;
103 	}
getEnemyAlignment()104 	uint16 getEnemyAlignment() const {
105 		return _enemyAlignment;
106 	}
setEnemyAlignment(uint16 a)107 	void setEnemyAlignment(uint16 a) {
108 		_enemyAlignment = a;
109 	}
110 
getLastAnim()111 	Animation::Sequence getLastAnim() const {
112 		return _lastAnim;
113 	}
setLastAnim(Animation::Sequence anim)114 	void setLastAnim(Animation::Sequence anim) {
115 		_lastAnim = anim;
116 	}
getDir()117 	Direction getDir() const {
118 		return _direction;
119 	}
setDir(Direction dir)120 	void setDir(Direction dir) {
121 		_direction = dir;
122 	}
getFallStart()123 	int32 getFallStart() const {
124 		return _fallStart;
125 	}
setFallStart(int32 zp)126 	void setFallStart(int32 zp) {
127 		_fallStart = zp;
128 	}
setUnkByte(uint8 b)129 	void setUnkByte(uint8 b) {
130 		_unkByte = b;
131 	}
getUnkByte()132 	uint8 getUnkByte() const {
133 		return _unkByte;
134 	}
135 
hasActorFlags(uint32 flags)136 	bool hasActorFlags(uint32 flags) const {
137 		return (_actorFlags & flags) != 0;
138 	}
setActorFlag(uint32 mask)139 	void setActorFlag(uint32 mask) {
140 		_actorFlags |= mask;
141 		if (mask & ACT_KNEELING)
142 			_cachedShapeInfo = nullptr;
143 	}
clearActorFlag(uint32 mask)144 	void clearActorFlag(uint32 mask) {
145 		_actorFlags &= ~mask;
146 		if (mask & ACT_KNEELING)
147 			_cachedShapeInfo = nullptr;
148 	}
149 
setCombatTactic(int no)150 	void setCombatTactic(int no) {
151 		_combatTactic = no;
152 	}
153 
154 	//! set stats from MonsterInfo (hp, dex, alignment, enemyAlignment)
155 	//! in Crusader this comes from the NPC Data
156 	//! \return true if info was found, false otherwise
157 	bool loadMonsterStats();
158 
159 	//! add treasure according to the TreasureInfo in the MonsterInfo
160 	//! \return true if a MonsterInfo struct was found, false otherwise
161 	bool giveTreasure();
162 
163 	virtual void teleport(int mapnum, int32 x, int32 y, int32 z);
164 
165 	bool removeItem(Item *item) override;
166 
167 	//! \return the PID of the spawned usecode process if any (otherwise 0)
168 	uint16 schedule(uint32 time);
169 
170 	bool setEquip(Item *item, bool checkwghtvol = false);
171 	uint16 getEquip(uint32 type) const;
172 
173 	virtual uint32 getArmourClass() const;
174 	virtual uint16 getDefenseType() const;
175 	virtual int16 getAttackingDex() const;
176 	virtual int16 getDefendingDex() const;
177 
178 	uint16 getDamageType() const override;
179 	virtual int getDamageAmount() const;
180 
181 	void setDefaultActivity(int no, uint16 activity);
182 	uint16 getDefaultActivity(int no) const;
183 
184 	void setHomePosition(int32 x, int32 y, int32 z);
185 	void getHomePosition(int32 &x, int32 &y, int32 &z) const;
186 
187 	//! calculate the damage an attack against this Actor does.
188 	//! \param other the attacker (can be zero)
189 	//! \param damage base damage
190 	//! \param type damage type
191 	//! \return the amount of damage to be applied. Zero if attack missed.
192 	int calculateAttackDamage(uint16 other, int damage, uint16 type);
193 
194 	//! receive a hit
195 	//! \param damage base damage (or zero to use attacker's default damage)
196 	//! \param type damage type (or zero to use attacker's default type)
197 	void receiveHit(uint16 other, Direction dir, int damage, uint16 type) override;
198 
199 	//! die
200 	//! \param damageType damage type that caused the death
201 	//! \param damagPts damage points that caused the death
202 	//! \param srcDir direction damage came from
203 	//! \return the process ID of the death animation
204 	virtual ProcId die(uint16 damageType, uint16 damagePts, Direction srcDir);
205 
206 	//! kill all processes except those related to combat
207 	void killAllButCombatProcesses();
208 
209 	//! kill all animation processes except those related to dying/falling
210 	//! \return PID of animprocess doing the falling (or getting up)
211 	ProcId killAllButFallAnims(bool death);
212 
213 	//! check if NPCs are near which are in combat mode and hostile
214 	bool areEnemiesNear();
215 
216 	//! starts an activity
217 	//! \return processID of process handling the activity or zero
218 	uint16 setActivity(int activity);
219 
getCurrentActivityNo()220 	uint16 getCurrentActivityNo() const {
221 		return _currentActivityNo;
222 	}
223 
getLastActivityNo()224 	uint16 getLastActivityNo() const {
225 		return _lastActivityNo;
226 	}
227 
clearLastActivityNo()228 	void clearLastActivityNo() {
229 		_lastActivityNo = 0;
230 	}
231 
getLastTickWasHit()232 	int32 getLastTickWasHit() const {
233 		return _lastTickWasHit;
234 	}
235 
236 	//! run the given animation
237 	//! \return the PID of the ActorAnimProcess
238 	uint16 doAnim(Animation::Sequence anim, Direction dir, unsigned int steps = 0);
239 
240 	//! run the given anim after the other animation (waitfor).
241 	//! Safe for either anim to be 0.
242 	//! \return the new anim pid, or 0 if failed
243 	uint16 doAnimAfter(Animation::Sequence anim, Direction dir, ProcId waitfor);
244 
245 	//! check if this actor has a specific animation
246 	bool hasAnim(Animation::Sequence anim);
247 
248 	//! Set the frame to the first frame of an anim (used in resetting NPCs etc)
249 	//! Uses current direction and sets last anim no.
250 	void setToStartOfAnim(Animation::Sequence anim);
251 
252 	//! check if the given animation can be done from the location in state,
253 	//! without walking into things. If state is non-zero, and successful,
254 	//! state will be updated to after the animation. If unsuccessful,
255 	//! the contents of state are undefined.
256 	//! \param anim Action to try
257 	//! \param dir direction to walk in
258 	//! \param state the state to start from, or 0 to use the current state
259 	Animation::Result tryAnim(Animation::Sequence anim, Direction dir, unsigned int steps = 0, PathfindingState *state = 0);
260 
261 	//! Get the number of directions supported by a given animation
262 	DirectionMode animDirMode(Animation::Sequence anim) const;
263 
264 	//! True if the actor is currently doing an animation.
265 	bool isBusy() const;
266 
267 	//! overrides the standard item collideMove so we  can notify nearby objects.
268 	int32 collideMove(int32 x, int32 y, int32 z, bool teleport, bool force,
269 	                  ObjId *hititem = 0, uint8 *dirs = 0) override;
270 
271 	//! Turn one step toward the given direction. If the current direction is already the same,
272 	//! do nothing. Returns an anim process or 0 if no move needed.
273 	//! If a previous pid is specified, wait for that process.
274 	uint16 turnTowardDir(Direction dir, ProcId prevpid = 0);
275 
276 	//! create an actor, assign objid, make it ethereal and load monster stats.
277 	static Actor *createActor(uint32 shape, uint32 frame);
278 
279 	uint16 assignObjId() override; // assign an NPC objid
280 
281 	void dumpInfo() const override;
282 
283 	bool loadData(Common::ReadStream *rs, uint32 version);
284 	void saveData(Common::WriteStream *ws) override;
285 
286 	//! take a hit and optionally adjust it with the shields for this NPC.
receiveShieldHit(int damage,uint16 damage_type)287 	virtual int receiveShieldHit(int damage, uint16 damage_type) {
288 		return damage;
289 	}
290 
getActiveWeapon()291 	uint16 getActiveWeapon() const {
292 		return _activeWeapon;
293 	}
294 
getCombatTactic()295 	uint16 getCombatTactic() const {
296 		return _combatTactic;
297 	}
298 
299 	bool activeWeaponIsSmall() const;
300 
301 	//! A cru-specific behavior - mostly make "ugh" noises, or explode for some robots.
302 	void tookHitCru();
303 
304 	//! Whether this NPC has the controlled actor in their sights (Crusader only)
305 	bool canSeeControlledActor(bool forcombat);
306 
307 	//! Add the x/y/z fire offsets given the current state of the actor
308 	void addFireAnimOffsets(int32 &x, int32 &y, int32 &z);
309 
getAttackMoveTimeoutFinishFrame()310 	uint32 getAttackMoveTimeoutFinishFrame() const {
311 		return _attackMoveStartFrame + _attackMoveTimeout;
312 	}
313 
getAttackMoveDodgeFactor()314 	uint16 getAttackMoveDodgeFactor() const {
315 		return _attackMoveDodgeFactor;
316 	}
317 
getAttackAimFlag()318 	bool getAttackAimFlag() const {
319 		return _attackAimFlag;
320 	}
321 
setAttackAimFlag(bool val)322 	void setAttackAimFlag(bool val) {
323 		_attackAimFlag = val;
324 	}
325 
326 	ENABLE_RUNTIME_CLASSTYPE()
327 
328 	INTRINSIC(I_isNPC);
329 	INTRINSIC(I_getDir);
330 	INTRINSIC(I_getLastAnimSet);
331 	INTRINSIC(I_pathfindToItem);
332 	INTRINSIC(I_pathfindToPoint);
333 	INTRINSIC(I_getStr);
334 	INTRINSIC(I_getDex);
335 	INTRINSIC(I_getInt);
336 	INTRINSIC(I_getHp);
337 	INTRINSIC(I_getMaxHp);
338 	INTRINSIC(I_getMana);
339 	INTRINSIC(I_getAlignment);
340 	INTRINSIC(I_getEnemyAlignment);
341 	INTRINSIC(I_setStr);
342 	INTRINSIC(I_setDex);
343 	INTRINSIC(I_setInt);
344 	INTRINSIC(I_setHp);
345 	INTRINSIC(I_setMana);
346 	INTRINSIC(I_setAlignment);
347 	INTRINSIC(I_setEnemyAlignment);
348 	INTRINSIC(I_getMap);
349 	INTRINSIC(I_addHp);
350 	INTRINSIC(I_teleport);
351 	INTRINSIC(I_doAnim);
352 	INTRINSIC(I_isInCombat);
353 	INTRINSIC(I_setInCombat);
354 	INTRINSIC(I_clrInCombat);
355 	INTRINSIC(I_setTarget);
356 	INTRINSIC(I_getTarget);
357 	INTRINSIC(I_isEnemy);
358 	INTRINSIC(I_isDead);
359 	INTRINSIC(I_setDead);
360 	INTRINSIC(I_clrDead);
361 	INTRINSIC(I_isImmortal);
362 	INTRINSIC(I_setImmortal);
363 	INTRINSIC(I_clrImmortal);
364 	INTRINSIC(I_isWithstandDeath);
365 	INTRINSIC(I_setWithstandDeath);
366 	INTRINSIC(I_clrWithstandDeath);
367 	INTRINSIC(I_isFeignDeath);
368 	INTRINSIC(I_setFeignDeath);
369 	INTRINSIC(I_clrFeignDeath);
370 	INTRINSIC(I_areEnemiesNear);
371 	INTRINSIC(I_isBusy);
372 	INTRINSIC(I_createActor);
373 	INTRINSIC(I_createActorCru);
374 	INTRINSIC(I_setActivity);
375 	INTRINSIC(I_setAirWalkEnabled);
376 	INTRINSIC(I_getAirWalkEnabled);
377 	INTRINSIC(I_schedule);
378 	INTRINSIC(I_getEquip);
379 	INTRINSIC(I_setEquip);
380 	INTRINSIC(I_setDefaultActivity0);
381 	INTRINSIC(I_setDefaultActivity1);
382 	INTRINSIC(I_setDefaultActivity2);
383 	INTRINSIC(I_getDefaultActivity0);
384 	INTRINSIC(I_getDefaultActivity1);
385 	INTRINSIC(I_getDefaultActivity2);
386 	INTRINSIC(I_setCombatTactic);
387 	INTRINSIC(I_setUnkByte);
388 	INTRINSIC(I_getUnkByte);
389 	INTRINSIC(I_getLastActivityNo);
390 	INTRINSIC(I_getCurrentActivityNo);
391 	INTRINSIC(I_turnToward);
392 	INTRINSIC(I_isKneeling);
393 	INTRINSIC(I_isFalling);
394 
395 	enum ActorFlags {
396 		ACT_INVINCIBLE     = 0x000001, // flags from npcdata byte 0x1B
397 		ACT_ASCENDING      = 0x000002,
398 		ACT_DESCENDING     = 0x000004,
399 		ACT_ANIMLOCK       = 0x000008,
400 
401 		ACT_KNEELING	   = 0x000100, // not the same bit used in Crusader, but use this because it's empty.
402 		ACT_FIRSTSTEP      = 0x000400, // flags from npcdata byte 0x2F
403 		ACT_INCOMBAT       = 0x000800,
404 		ACT_DEAD           = 0x001000,
405 		ACT_SURRENDERED    = 0x002000, // not the same bit used in Crusader, but use this because it's empty.
406 		ACT_WEAPONREADY	   = 0x004000, // not the same bit used in Crusader, but use this because it's empty.
407 		ACT_COMBATRUN      = 0x008000,
408 
409 		ACT_AIRWALK        = 0x010000, // flags from npcdata byte 0x30
410 		ACT_IMMORTAL       = 0x040000,
411 		ACT_WITHSTANDDEATH = 0x080000,
412 		ACT_FEIGNDEATH     = 0x100000,
413 		ACT_STUNNED        = 0x200000,
414 		ACT_POISONED       = 0x400000,
415 		ACT_PATHFINDING    = 0x800000
416 	};
417 
418 protected:
419 	int16 _strength;
420 	int16 _dexterity;
421 	int16 _intelligence;
422 	uint16 _hitPoints;
423 	int16 _mana;
424 
425 	uint16 _alignment, _enemyAlignment;
426 
427 	Animation::Sequence _lastAnim;
428 	uint16 _animFrame;
429 	Direction _direction;
430 
431 	int32 _fallStart;
432 
433 	//! Unknown byte 0x0C from npcdata.dat in U8, or
434 	//! Unknown byte 0x99 from NPC struct in Crusader.
435 	uint8 _unkByte;
436 
437 	//! tactic being used in combat (for Crusader), the entry in the combat.dat flex.
438 	uint16 _combatTactic;
439 
440 	uint32 _actorFlags;
441 
442 	//! the 3 default NPC activities from Crusader
443 	uint16 _defaultActivity[3];
444 
445 	//! The "home" position used in some Crusader attack tactics
446 	int32 _homeX;
447 	int32 _homeY;
448 	int32 _homeZ;
449 
450 	//! Current and last activity (only used in Crusader)
451 	uint16 _currentActivityNo;
452 	uint16 _lastActivityNo;
453 
454 	//! Active weapon item (only used in Crusader)
455 	uint16 _activeWeapon;
456 
457 	//! Kernel timer last time NPC was hit (only used in Crusader)
458 	int32 _lastTickWasHit;
459 
460 	//! The frame certain animations last happened (for Crusader).
461 	//! Used in calcualting how hard controlled actor is to hit.
462 	uint32 _attackMoveStartFrame;
463 	//! The number of frames the above effect lasts for.
464 	uint32 _attackMoveTimeout;
465 	//! A spread divisor used by shots targeting the controlled actor when they
466 	//! are within the above timeout.
467 	uint16 _attackMoveDodgeFactor;
468 
469 	//! A flag used in Crusader attack process which adjusts the aim accuracy.
470 	bool _attackAimFlag;
471 
472 	//! starts an activity (Ultima 8 version)
473 	//! \return processID of process handling the activity or zero
474 	uint16 setActivityU8(int activity);
475 
476 	//! starts an activity (Crusader version)
477 	//! \return processID of process handling the activity or zero
478 	uint16 setActivityCru(int activity);
479 
480 	bool loadMonsterStatsU8();
481 	bool loadMonsterStatsCru();
482 
483 	void receiveHitU8(uint16 other, Direction dir, int damage, uint16 type);
484 	void receiveHitCru(uint16 other, Direction dir, int damage, uint16 type);
485 
486 	void setInCombatU8();
487 	void setInCombatCru(int activity);
488 
489 	ProcId dieU8(uint16 damageType);
490 	ProcId dieCru(uint16 damageType, uint16 damagePts, Direction srcDir);
491 };
492 
493 } // End of namespace Ultima8
494 } // End of namespace Ultima
495 
496 #endif
497