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