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 #include "ultima/ultima8/misc/pent_include.h"
24 #include "ultima/ultima8/kernel/object_manager.h"
25 #include "ultima/ultima8/kernel/kernel.h"
26 #include "ultima/ultima8/kernel/delay_process.h"
27 #include "ultima/ultima8/usecode/uc_machine.h"
28 #include "ultima/ultima8/usecode/uc_list.h"
29 #include "ultima/ultima8/misc/direction_util.h"
30 #include "ultima/ultima8/games/game_data.h"
31 #include "ultima/ultima8/world/fire_type.h"
32 #include "ultima/ultima8/graphics/anim_dat.h"
33 #include "ultima/ultima8/graphics/main_shape_archive.h"
34 #include "ultima/ultima8/graphics/shape.h"
35 #include "ultima/ultima8/world/actors/actor_anim_process.h"
36 #include "ultima/ultima8/world/actors/animation_tracker.h"
37 #include "ultima/ultima8/world/actors/anim_action.h"
38 #include "ultima/ultima8/world/actors/npc_dat.h"
39 #include "ultima/ultima8/world/actors/resurrection_process.h"
40 #include "ultima/ultima8/world/actors/clear_feign_death_process.h"
41 #include "ultima/ultima8/world/actors/pathfinder_process.h"
42 #include "ultima/ultima8/world/actors/loiter_process.h"
43 #include "ultima/ultima8/world/actors/guard_process.h"
44 #include "ultima/ultima8/world/actors/combat_process.h"
45 #include "ultima/ultima8/world/actors/attack_process.h"
46 #include "ultima/ultima8/world/actors/pace_process.h"
47 #include "ultima/ultima8/world/actors/surrender_process.h"
48 #include "ultima/ultima8/world/actors/rolling_thunder_process.h"
49 #include "ultima/ultima8/world/bobo_boomer_process.h"
50 #include "ultima/ultima8/world/world.h"
51 #include "ultima/ultima8/world/current_map.h"
52 #include "ultima/ultima8/world/sprite_process.h"
53 #include "ultima/ultima8/world/target_reticle_process.h"
54 #include "ultima/ultima8/world/item_selection_process.h"
55 #include "ultima/ultima8/world/actors/main_actor.h"
56 #include "ultima/ultima8/world/get_object.h"
57 #include "ultima/ultima8/world/item_factory.h"
58 #include "ultima/ultima8/world/loop_script.h"
59 #include "ultima/ultima8/audio/audio_process.h"
60 #include "ultima/ultima8/audio/music_process.h"
61 #include "ultima/ultima8/world/gravity_process.h"
62 
63 namespace Ultima {
64 namespace Ultima8 {
65 
66 static const unsigned int BACKPACK_SHAPE = 529;
67 
DEFINE_RUNTIME_CLASSTYPE_CODE(Actor)68 DEFINE_RUNTIME_CLASSTYPE_CODE(Actor)
69 
70 Actor::Actor() : _strength(0), _dexterity(0), _intelligence(0),
71 		_hitPoints(0), _mana(0), _alignment(0), _enemyAlignment(0),
72 		_lastAnim(Animation::stand), _animFrame(0), _direction(dir_north),
73 		_fallStart(0), _unkByte(0), _actorFlags(0), _combatTactic(0),
74 		_homeX(0), _homeY(0), _homeZ(0), _currentActivityNo(0),
75 		_lastActivityNo(0), _activeWeapon(0), _lastTickWasHit(0),
76 		_attackMoveStartFrame(0), _attackMoveTimeout(0),
77 		_attackMoveDodgeFactor(1), _attackAimFlag(false) {
78 	_defaultActivity[0] = 0;
79 	_defaultActivity[1] = 0;
80 	_defaultActivity[2] = 0;
81 }
82 
~Actor()83 Actor::~Actor() {
84 }
85 
assignObjId()86 uint16 Actor::assignObjId() {
87 	if (_objId == 0xFFFF)
88 		_objId = ObjectManager::get_instance()->assignActorObjId(this);
89 
90 	Std::list<Item *>::iterator iter;
91 	for (iter = _contents.begin(); iter != _contents.end(); ++iter) {
92 		(*iter)->assignObjId();
93 		(*iter)->setParent(_objId);
94 	}
95 
96 	return _objId;
97 }
98 
getMaxMana() const99 int16 Actor::getMaxMana() const {
100 	return static_cast<int16>(2 * getInt());
101 }
102 
getMaxHP() const103 uint16 Actor::getMaxHP() const {
104 	return static_cast<uint16>(2 * getStr());
105 }
106 
loadMonsterStats()107 bool Actor::loadMonsterStats() {
108 	if (GAME_IS_CRUSADER)
109 		return loadMonsterStatsCru();
110 	else
111 		return loadMonsterStatsU8();
112 }
113 
loadMonsterStatsCru()114 bool Actor::loadMonsterStatsCru() {
115 	const NPCDat *npcData = GameData::get_instance()->getNPCDataForShape(getShape());
116 
117 	if (!npcData)
118 		return false;
119 
120 	setStr(npcData->getMaxHp() / 2);
121 	setHP(npcData->getMaxHp());
122 	_defaultActivity[0] = npcData->getDefaultActivity(0);
123 	_defaultActivity[1] = npcData->getDefaultActivity(1);
124 	_defaultActivity[2] = npcData->getDefaultActivity(2);
125 
126 	// TODO: Give them the default weapon for their type here.
127 
128 	return true;
129 }
130 
loadMonsterStatsU8()131 bool Actor::loadMonsterStatsU8() {
132 
133 	const ShapeInfo *shapeinfo = getShapeInfo();
134 	const MonsterInfo *mi = nullptr;
135 	if (shapeinfo) mi = shapeinfo->_monsterInfo;
136 	if (!mi)
137 		return false;
138 
139 	uint16 hp;
140 	if (mi->_maxHp <= mi->_minHp)
141 		hp = mi->_minHp;
142 	else
143 		hp = mi->_minHp + getRandom() % (mi->_maxHp - mi->_minHp);
144 	setHP(hp);
145 
146 	uint16 dex;
147 	if (mi->_maxDex <= mi->_minDex)
148 		dex = mi->_minDex;
149 	else
150 		dex = mi->_minDex + getRandom() % (mi->_maxDex - mi->_minDex);
151 	setDex(dex);
152 
153 	uint8 new_alignment = mi->_alignment;
154 	setAlignment(new_alignment & 0x0F);
155 	setEnemyAlignment((new_alignment & 0xF0) >> 4); // !! CHECKME
156 
157 	return true;
158 }
159 
giveTreasure()160 bool Actor::giveTreasure() {
161 	MainShapeArchive *mainshapes = GameData::get_instance()->getMainShapes();
162 	const ShapeInfo *shapeinfo = getShapeInfo();
163 	const MonsterInfo *mi = nullptr;
164 	if (shapeinfo) mi = shapeinfo->_monsterInfo;
165 	if (!mi)
166 		return false;
167 
168 	const Std::vector<TreasureInfo> &treasure = mi->_treasure;
169 
170 	for (unsigned int i = 0; i < treasure.size(); ++i) {
171 		const TreasureInfo &ti = treasure[i];
172 		Item *item;
173 
174 		// check map
175 		int currentmap = World::get_instance()->getCurrentMap()->getNum();
176 		if (ti._map != 0 && ((ti._map > 0 && ti._map != currentmap) ||
177 		                    (ti._map < 0 && -ti._map == currentmap))) {
178 			continue;
179 		}
180 
181 		// check chance
182 		if (ti._chance < 0.999 &&
183 		        (static_cast<double>(getRandom()) / U8_RAND_MAX) > ti._chance) {
184 			continue;
185 		}
186 
187 		// determine count/quantity
188 		int count;
189 		if (ti._minCount >= ti._maxCount)
190 			count = ti._minCount;
191 		else
192 			count = ti._minCount + (getRandom() % (ti._maxCount - ti._minCount));
193 
194 		if (!ti._special.empty()) {
195 			if (ti._special == "weapon") {
196 
197 				// NB: this is rather biased towards weapons with low _shapes...
198 				for (unsigned int s = 0; s < mainshapes->getCount(); ++s) {
199 					const ShapeInfo *si = mainshapes->getShapeInfo(s);
200 					if (!si->_weaponInfo) continue;
201 
202 					int chance = si->_weaponInfo->_treasureChance;
203 					if (!chance) continue;
204 
205 					int r = getRandom() % 100;
206 #if 0
207 					pout << "weapon (" << s << ") chance: " << r << "/"
208 					     << chance << Std::endl;
209 #endif
210 					if (r >= chance) continue;
211 
212 					// create the weapon
213 					item = ItemFactory::createItem(s,
214 					                               0, // frame
215 					                               count, // quality
216 					                               Item::FLG_DISPOSABLE,//flags
217 					                               0, // npcnum,
218 					                               0, // mapnum
219 					                               0, true); // ext.flags,_objId
220 					item->moveToContainer(this);
221 					item->randomGumpLocation();
222 					break;
223 				}
224 			} else if (ti._special == "sorcfocus") {
225 				// CONSTANTS! (and lots of them...)
226 				int shapeNum = 397;
227 				int frameNum;
228 				uint16 qualityNum;
229 
230 				if (getRandom() % 10 < 8) {
231 					// wand
232 					if (getRandom() % 10 < 4) {
233 						// charged
234 						frameNum = 0;
235 						qualityNum = 3 + (getRandom() % 4) + // charges
236 						          ((1 + (getRandom() % 4)) << 8); // spell
237 					} else {
238 						frameNum = 15;
239 						qualityNum = 0;
240 					}
241 
242 					item = ItemFactory::createItem(shapeNum, frameNum, qualityNum,
243 					                               Item::FLG_DISPOSABLE,
244 					                               0, 0, 0, true);
245 					item->moveToContainer(this);
246 					item->randomGumpLocation();
247 				}
248 
249 				if (getRandom() % 10 < 6) {
250 					// rod
251 					if (getRandom() % 10 < 2) {
252 						// charged
253 						frameNum = 3;
254 						qualityNum = 3 + (getRandom() % 4) + // charges
255 						          ((1 + (getRandom() % 7)) << 8); // spell
256 					} else {
257 						frameNum = 16;
258 						qualityNum = 0;
259 					}
260 
261 					item = ItemFactory::createItem(shapeNum, frameNum, qualityNum,
262 					                               Item::FLG_DISPOSABLE,
263 					                               0, 0, 0, true);
264 					item->moveToContainer(this);
265 					item->randomGumpLocation();
266 				}
267 
268 				if (getRandom() % 10 < 5) {
269 					// symbol
270 					if (getRandom() % 10 < 5) {
271 						// charged
272 						frameNum = 12;
273 						uint8 spell = 1 + (getRandom() % 11);
274 						qualityNum = spell << 8;
275 						if (spell < 4) {
276 							qualityNum += 3 + (getRandom() % 4);
277 						} else {
278 							// symbol can only have one charge of anything
279 							// other than ignite/extinguish
280 							qualityNum += 1;
281 						}
282 					} else {
283 						frameNum = 19;
284 						qualityNum = 0;
285 					}
286 
287 					item = ItemFactory::createItem(shapeNum, frameNum, qualityNum,
288 					                               Item::FLG_DISPOSABLE,
289 					                               0, 0, 0, true);
290 					item->moveToContainer(this);
291 					item->randomGumpLocation();
292 				}
293 
294 				if (getRandom() % 10 < 2) {
295 					// demon talisman
296 					if (getRandom() % 10 < 2) {
297 						// charged
298 						frameNum = 9;
299 						qualityNum = 1 + (getRandom() % 2) +  // charges
300 						          ((10 + (getRandom() % 2)) << 8); // spell
301 					} else {
302 						frameNum = 18;
303 						qualityNum = 0;
304 					}
305 
306 					item = ItemFactory::createItem(shapeNum, frameNum, qualityNum,
307 					                               Item::FLG_DISPOSABLE,
308 					                               0, 0, 0, true);
309 					item->moveToContainer(this);
310 					item->randomGumpLocation();
311 				}
312 
313 			} else {
314 				pout << "Unhandled special treasure: " << ti._special
315 				     << Std::endl;
316 			}
317 			continue;
318 		}
319 
320 		// if _shapes.size() == 1 and the given shape is SF_QUANTITY,
321 		// then produce a stack of that shape (ignoring frame)
322 
323 		if (ti._shapes.size() == 1) {
324 			uint32 shapeNum = ti._shapes[0];
325 			const ShapeInfo *si = mainshapes->getShapeInfo(shapeNum);
326 			if (!si) {
327 				perr << "Trying to create treasure with an invalid shapeNum ("
328 				     << shapeNum << ")" << Std::endl;
329 				continue;
330 			}
331 			if (si->hasQuantity()) {
332 				// CHECKME: which flags?
333 				item = ItemFactory::createItem(shapeNum,
334 				                               0, // frame
335 				                               count, // quality
336 				                               Item::FLG_DISPOSABLE, // flags
337 				                               0, // npcnum,
338 				                               0, // mapnum
339 				                               0, true); // ext. flags, _objId
340 				item->moveToContainer(this);
341 				item->randomGumpLocation();
342 				item->callUsecodeEvent_combine(); // this sets the right frame
343 				continue;
344 			}
345 		}
346 
347 		if (ti._shapes.empty() || ti._frames.empty()) {
348 			perr << "No shape/frame set in treasure" << Std::endl;
349 			continue;
350 		}
351 
352 		// we need to produce a number of items
353 		for (int j = 0; (int)j < count; ++j) {
354 			// pick shape
355 			int n = getRandom() % ti._shapes.size();
356 			uint32 shapeNum = ti._shapes[n];
357 
358 			// pick frame
359 			n = getRandom() % ti._frames.size();
360 			uint32 frameNum = ti._frames[n];
361 
362 			const ShapeInfo *si = GameData::get_instance()->getMainShapes()->
363 			                getShapeInfo(shapeNum);
364 			if (!si) {
365 				perr << "Trying to create treasure with an invalid shapeNum ("
366 				     << shapeNum << ")" << Std::endl;
367 				continue;
368 			}
369 			uint16 qual = 0;
370 			if (si->hasQuantity())
371 				qual = 1;
372 
373 			// CHECKME: flags?
374 			item = ItemFactory::createItem(shapeNum,
375 			                               frameNum, // frameNum
376 			                               qual, // quality
377 			                               Item::FLG_DISPOSABLE, // flags
378 			                               0, // npcnum,
379 			                               0, // mapnum
380 			                               0, true); // ext. flags, _objId
381 			item->moveToContainer(this);
382 			item->randomGumpLocation();
383 		}
384 	}
385 
386 	return true;
387 }
388 
removeItem(Item * item)389 bool Actor::removeItem(Item *item) {
390 	if (!Container::removeItem(item)) return false;
391 
392 	item->clearFlag(FLG_EQUIPPED); // unequip if necessary
393 
394 	return true;
395 }
396 
setEquip(Item * item,bool checkwghtvol)397 bool Actor::setEquip(Item *item, bool checkwghtvol) {
398 	uint32 equiptype = item->getShapeInfo()->_equipType;
399 	bool backpack = (item->getShape() == BACKPACK_SHAPE);
400 
401 	// valid item type?
402 	if (equiptype == ShapeInfo::SE_NONE && !backpack) return false;
403 
404 	// now check 'equipment slots'
405 	// we can have one item of each equipment type, plus one backpack
406 	for (Std::list<Item *>::const_iterator iter = _contents.begin(); iter != _contents.end(); ++iter) {
407 		if ((*iter)->getObjId() == item->getObjId()) continue;
408 
409 		uint32 cet = (*iter)->getShapeInfo()->_equipType;
410 		bool cbackpack = ((*iter)->getShape() == BACKPACK_SHAPE);
411 
412 		// already have an item with the same equiptype
413 		if (cet == equiptype || (cbackpack && backpack)) return false;
414 	}
415 
416 	if (!item->moveToContainer(this, checkwghtvol)) return false;
417 	item->clearFlag(FLG_CONTAINED);
418 	item->setFlag(FLG_EQUIPPED);
419 	item->setZ(equiptype);
420 
421 	return true;
422 }
423 
getEquip(uint32 type) const424 uint16 Actor::getEquip(uint32 type) const {
425 	Std::list<Item *>::const_iterator iter;
426 	for (iter = _contents.begin(); iter != _contents.end(); ++iter) {
427 		uint32 cet = (*iter)->getShapeInfo()->_equipType;
428 		bool cbackpack = ((*iter)->getShape() == BACKPACK_SHAPE);
429 
430 		if ((*iter)->hasFlags(FLG_EQUIPPED) &&
431 		        (cet == type || (cbackpack && type == 7))) { // !! constant
432 			return (*iter)->getObjId();
433 		}
434 	}
435 
436 	return 0;
437 }
438 
teleport(int newmap,int32 newx,int32 newy,int32 newz)439 void Actor::teleport(int newmap, int32 newx, int32 newy, int32 newz) {
440 	uint16 newmapnum = static_cast<uint16>(newmap);
441 
442 	// Set the mapnum
443 	setMapNum(newmapnum);
444 
445 	// Put it in the void
446 	moveToEtherealVoid();
447 
448 	// Move it to this map
449 	if (newmapnum == World::get_instance()->getCurrentMap()->getNum()) {
450 #ifdef DEBUG
451 		perr << "Actor::teleport: " << getObjId() << " to " << newmap << ","
452 		     << newx << "," << newy << "," << newz << Std::endl;
453 #endif
454 		move(newx, newy, newz);
455 	}
456 	// Move it to another map
457 	else {
458 		World::get_instance()->etherealRemove(_objId);
459 		_x = newx;
460 		_y = newy;
461 		_z = newz;
462 	}
463 }
464 
doAnim(Animation::Sequence anim,Direction dir,unsigned int steps)465 uint16 Actor::doAnim(Animation::Sequence anim, Direction dir, unsigned int steps) {
466 	if (dir < 0 || dir > 16) {
467 		perr << "Actor::doAnim: Invalid _direction (" << dir << ")" << Std::endl;
468 		return 0;
469 	}
470 
471 	if (dir == dir_current)
472 		dir = getDir();
473 
474 #if 0
475 	if (tryAnim(anim, dir)) {
476 		perr << "Actor::doAnim: tryAnim = Ok!" << Std::endl;
477 	} else {
478 		perr << "Actor::doAnim: tryAnim = bad!" << Std::endl;
479 	}
480 #endif
481 
482 	if (GAME_IS_CRUSADER) {
483 		// Crusader sets some flags on animation start
484 		// Small hack: When switching from 16-dir to 8-dir, fix the direction
485 		if (animDirMode(anim) == dirmode_8dirs)
486 			dir = static_cast<Direction>(dir - (static_cast<uint32>(dir) % 2));
487 
488 		if (anim == Animation::readyWeapon || anim == Animation::stopRunningAndDrawSmallWeapon ||
489 				anim == Animation::combatStand || anim == Animation::attack || anim == Animation::kneel ||
490 				anim == Animation::kneelAndFire || anim == Animation::reloadSmallWeapon)
491 			setActorFlag(ACT_WEAPONREADY);
492 		else
493 			clearActorFlag(ACT_WEAPONREADY);
494 
495 		if (anim == Animation::kneelStartCru || anim == Animation::kneelAndFire ||
496 				anim == Animation::kneelAndFireSmallWeapon ||
497 				anim == Animation::kneelAndFireLargeWeapon ||
498 				anim == Animation::kneelCombatRollLeft ||
499 				anim == Animation::kneelCombatRollRight ||
500 				anim == Animation::combatRollLeft ||
501 				anim == Animation::combatRollRight ||
502 				anim == Animation::kneelingAdvance ||
503 				anim == Animation::kneelingRetreat) {
504 			setActorFlag(ACT_KNEELING);
505 		} else if (anim != Animation::kneel) {
506 			clearActorFlag(ACT_KNEELING);
507 		}
508 
509 		const uint32 frameno = Kernel::get_instance()->getFrameNum();
510 		switch(anim) {
511 			case Animation::walk:
512 			case Animation::retreat: // SmallWeapon
513 				_attackMoveStartFrame = frameno;
514 				_attackMoveTimeout = 120;
515 				_attackMoveDodgeFactor = 3;
516 				break;
517 			case Animation::run:
518 			case Animation::kneelCombatRollLeft:
519 			case Animation::kneelCombatRollRight:
520 			case Animation::stopRunningAndDrawLargeWeapon:
521 			case Animation::stopRunningAndDrawSmallWeapon:
522 			case Animation::jumpForward:
523 			case Animation::jump:
524 			case Animation::combatRollLeft:
525 			case Animation::combatRollRight:
526 			//case Animation::startRunSmallWeapon:
527 			//case Animation::startRunLargeWeapon:
528 			case Animation::startRun:
529 				_attackMoveStartFrame = frameno;
530 				_attackMoveTimeout = 120;
531 				_attackMoveDodgeFactor = 2;
532 				break;
533 			case Animation::slideLeft:
534 			case Animation::slideRight:
535 				_attackMoveStartFrame = frameno;
536 				_attackMoveTimeout = 60;
537 				_attackMoveDodgeFactor = 3;
538 				break;
539 			case Animation::startKneeling:
540 			case Animation::stopKneeling:
541 				_attackMoveStartFrame = frameno;
542 				_attackMoveTimeout = 75;
543 				_attackMoveDodgeFactor = 3;
544 				break;
545 			default:
546 				break;
547 		}
548 
549 	}
550 
551 #if 0
552 	if (_objId == 1) {
553 		int32 x, y, z;
554 		getLocation(x, y, z);
555 		int32 actionno = AnimDat::getActionNumberForSequence(anim, this);
556 		const AnimAction *action = GameData::get_instance()->getMainShapes()->getAnim(getShape(), actionno);
557 		debug(6, "Actor::doAnim(%d, %d, %d) from (%d, %d, %d) frame repeat %d", anim, dir, steps, x, y, z, action ? action->getFrameRepeat() : -1);
558 	}
559 #endif
560 
561 	Process *p = new ActorAnimProcess(this, anim, dir, steps);
562 
563 	return Kernel::get_instance()->addProcess(p);
564 }
565 
doAnimAfter(Animation::Sequence anim,Direction dir,ProcId waitfor)566 uint16 Actor::doAnimAfter(Animation::Sequence anim, Direction dir, ProcId waitfor) {
567 	ProcId newanim = doAnim(anim, dir);
568 	if (newanim && waitfor) {
569 		Process *newproc = Kernel::get_instance()->getProcess(newanim);
570 		newproc->waitFor(waitfor);
571 	}
572 	return newanim;
573 }
574 
isBusy() const575 bool Actor::isBusy() const {
576 	uint32 count = Kernel::get_instance()->getNumProcesses(_objId, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE);
577 	return count != 0;
578 }
579 
hasAnim(Animation::Sequence anim)580 bool Actor::hasAnim(Animation::Sequence anim) {
581 	AnimationTracker tracker;
582 
583 	return tracker.init(this, anim, dir_north);
584 }
585 
setToStartOfAnim(Animation::Sequence anim)586 void Actor::setToStartOfAnim(Animation::Sequence anim) {
587 	AnimationTracker tracker;
588 	if (tracker.init(this, anim, getDir())) {
589 		const AnimFrame *f = tracker.getAnimFrame();
590 		setFrame(f->_frame);
591 		if ((GAME_IS_U8 && f->is_flipped())
592 			|| (GAME_IS_CRUSADER && f->is_cruflipped())) {
593 			setFlag(Item::FLG_FLIPPED);
594 		} else {
595 			clearFlag(Item::FLG_FLIPPED);
596 		}
597 		setLastAnim(anim);
598 	}
599 }
600 
tryAnim(Animation::Sequence anim,Direction dir,unsigned int steps,PathfindingState * state)601 Animation::Result Actor::tryAnim(Animation::Sequence anim, Direction dir,
602 								 unsigned int steps, PathfindingState *state) {
603 	if (dir < 0 || dir > 16) return Animation::FAILURE;
604 
605 	if (dir == dir_current)
606 		dir = getDir();
607 
608 	AnimationTracker tracker;
609 	if (!tracker.init(this, anim, dir, state))
610 		return Animation::FAILURE;
611 
612 	const AnimAction *animaction = tracker.getAnimAction();
613 
614 	if (!animaction) return Animation::FAILURE;
615 
616 	unsigned int curstep = 0;
617 
618 	while (tracker.step() && (!steps || curstep >= steps)) {
619 		curstep++;
620 	}
621 
622 	if (tracker.isBlocked() &&
623 	        !animaction->hasFlags(AnimAction::AAF_UNSTOPPABLE)) {
624 		return Animation::FAILURE;
625 	}
626 
627 	if (state) {
628 		tracker.updateState(*state);
629 		state->_lastAnim = anim;
630 		state->_direction = dir;
631 	}
632 
633 
634 	if (tracker.isUnsupported()) {
635 		return Animation::END_OFF_LAND;
636 	}
637 
638 	// isUnsupported only checks for AFF_ONGROUND, we need either
639 	int32 end[3], dims[3];
640 	getFootpadWorld(dims[0], dims[1], dims[2]);
641 	tracker.getPosition(end[0], end[1], end[2]);
642 
643 	CurrentMap *cm = World::get_instance()->getCurrentMap();
644 
645 	UCList uclist(2);
646 	LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
647 	cm->surfaceSearch(&uclist, script, sizeof(script),
648 	                  getObjId(), end, dims,
649 	                  false, true, false);
650 	for (uint32 i = 0; i < uclist.getSize(); i++) {
651 		Item *item = getItem(uclist.getuint16(i));
652 		if (item->getShapeInfo()->is_land())
653 			return Animation::SUCCESS;
654 	}
655 
656 	return Animation::END_OFF_LAND;
657 }
658 
animDirMode(Animation::Sequence anim) const659 DirectionMode Actor::animDirMode(Animation::Sequence anim) const {
660 	int32 actionno = AnimDat::getActionNumberForSequence(anim, this);
661 	const AnimAction *action = GameData::get_instance()->getMainShapes()->getAnim(getShape(), actionno);
662 
663 	if (!action)
664 		return dirmode_8dirs;
665 	return action->getDirCount() == 8 ? dirmode_8dirs : dirmode_16dirs;
666 }
667 
turnTowardDir(Direction targetdir,ProcId prevpid)668 uint16 Actor::turnTowardDir(Direction targetdir, ProcId prevpid /* = 0 */) {
669 	bool combatRun = hasActorFlags(Actor::ACT_COMBATRUN);
670 	Direction curdir = getDir();
671 	bool combat = isInCombat() && !combatRun;
672 	Animation::Sequence standanim = Animation::stand;
673 	bool surrendered = hasActorFlags(Actor::ACT_SURRENDERED);
674 
675 	int stepDelta = Direction_GetShorterTurnDelta(curdir, targetdir);
676 	Animation::Sequence turnanim = Animation::stand;
677 	if (GAME_IS_U8) {
678 		if (stepDelta == -1) {
679 			turnanim = Animation::lookLeft;
680 		} else {
681 			turnanim = Animation::lookRight;
682 		}
683 	}
684 
685 	if (targetdir == curdir || targetdir == dir_current)
686 		return 0; // nothing to do.
687 
688 	if (combat) {
689 		turnanim = Animation::combatStand;
690 		standanim = Animation::combatStand;
691 	} else if (surrendered) {
692 		turnanim = Animation::surrenderStand;
693 		standanim = Animation::surrenderStand;
694 	}
695 
696 	ProcId animpid = 0;
697 
698 	// Create a sequence of turn animations from
699 	// our current direction to the new one
700 	DirectionMode mode = animDirMode(turnanim);
701 
702 	// slight hack - avoid making 8-step turns if we need to swap
703 	// to/from a 16-step direction - we'll never get to the right
704 	// direction that way.
705 	if (static_cast<uint32>(targetdir) % 2 !=
706 		static_cast<uint32>(curdir) % 2) {
707 		mode = dirmode_16dirs;
708 	}
709 
710 	bool done = false;
711 	Direction firstanimdir = curdir;
712 
713 	// Skip animating "stand" for the current direction in Crusader.
714 	if (GAME_IS_CRUSADER)
715 		firstanimdir = Direction_TurnByDelta(curdir, stepDelta, mode);
716 
717 	for (Direction dir = firstanimdir; !done; dir = Direction_TurnByDelta(dir, stepDelta, mode)) {
718 		Animation::Sequence nextanim = turnanim;
719 		if (dir == targetdir) {
720 			nextanim = standanim;
721 			done = true;
722 		}
723 
724 		animpid = doAnim(nextanim, dir);
725 		if (prevpid) {
726 			Process *proc = Kernel::get_instance()->getProcess(animpid);
727 			assert(proc);
728 			proc->waitFor(prevpid);
729 		}
730 
731 		prevpid = animpid;
732 	}
733 
734 	return animpid;
735 }
736 
setActivity(int activity)737 uint16 Actor::setActivity(int activity) {
738 	if (GAME_IS_CRUSADER)
739 		return setActivityCru(activity);
740 	else
741 		return setActivityU8(activity);
742 }
743 
setActivityU8(int activity)744 uint16 Actor::setActivityU8(int activity) {
745 	switch (activity) {
746 	case 0: // loiter
747 		Kernel::get_instance()->addProcess(new LoiterProcess(this));
748 		return Kernel::get_instance()->addProcess(new DelayProcess(1));
749 		break;
750 	case 1: // combat
751 		setInCombatU8();
752 		return 0;
753 	case 2: // stand
754 		// NOTE: temporary fall-throughs!
755 		return doAnim(Animation::stand, dir_current);
756 
757 	default:
758 		perr << "Actor::setActivityU8: invalid activity (" << activity << ")"
759 		     << Std::endl;
760 	}
761 
762 	return 0;
763 }
764 
setActivityCru(int activity)765 uint16 Actor::setActivityCru(int activity) {
766 	if (isDead() || World::get_instance()->getControlledNPCNum() == _objId
767 		|| hasActorFlags(ACT_WEAPONREADY) || activity == 0)
768 		return 0;
769 
770 	if ((World::get_instance()->getGameDifficulty() == 4) && (getRandom() % 2 == 0)) {
771 		if (activity == 5)
772 			activity = 0xa;
773 		if (activity == 9)
774 			activity = 0xb;
775 	}
776 
777 	if (_currentActivityNo == activity || (isInCombat() && activity != 0xc))
778 		return 0;
779 
780 	_lastActivityNo = _currentActivityNo;
781 	_currentActivityNo = activity;
782 
783 	if (isInCombat())
784 		clearInCombat();
785 
786 	if (!hasFlags(FLG_FASTAREA))
787 		return 0;
788 
789 	Kernel *kernel = Kernel::get_instance();
790 
791 	static const uint16 PROCSTYPES_TO_KILL[] = {
792 		ActorAnimProcess::ACTOR_ANIM_PROC_TYPE,
793 		PathfinderProcess::PATHFINDER_PROC_TYPE,
794 		0x255, // PaceProcess
795 		0x257, // LoiterProcess
796 		// 0x258, // Stand Process (we don't have a process for this)
797 		AttackProcess::ATTACK_PROCESS_TYPE,
798 		0x25e, // GuardProcess
799 		0x25f  // SurrenderProcess
800 	};
801 	for (int i = 0; i < ARRAYSIZE(PROCSTYPES_TO_KILL); i++) {
802 		kernel->killProcesses(_objId, PROCSTYPES_TO_KILL[i], true);
803 	}
804 
805 	switch (activity) {
806 	case 1: // stand
807 		return doAnim(Animation::stand, dir_current);
808 	case 2: // loiter
809 		return kernel->addProcess(new LoiterProcess(this));
810 	case 3: // pace
811 		return kernel->addProcess(new PaceProcess(this));
812 	case 4:
813 	case 6:
814 	    // Does nothing in game..
815 	    break;
816 	case 7:
817 		if (_lastActivityNo != 7)
818 			return kernel->addProcess(new SurrenderProcess(this));
819 	    break;
820 	case 8:
821 		return kernel->addProcess(new GuardProcess(this));
822 	case 5:
823 	case 9:
824 	case 0xa:
825 	case 0xb:
826 	case 0xc:
827 		// attack
828 		setInCombatCru(activity);
829 		return 0;
830 	case 0xd:
831 		// Only in No Regret
832 		setActorFlag(ACT_INCOMBAT);
833 		return kernel->addProcess(new RollingThunderProcess(this));
834 	case 0x70:
835 		return setActivity(getDefaultActivity(0));
836 	case 0x71:
837 		return setActivity(getDefaultActivity(1));
838 	case 0x72:
839 		return setActivity(getDefaultActivity(2));
840 	default:
841 		perr << "Actor::setActivityCru: invalid activity (" << activity << ")"
842 		     << Std::endl;
843 		return doAnim(Animation::stand, dir_current);
844 	}
845 
846 	return 0;
847 }
848 
849 
getArmourClass() const850 uint32 Actor::getArmourClass() const {
851 	const ShapeInfo *si = getShapeInfo();
852 	if (si->_monsterInfo)
853 		return si->_monsterInfo->_armourClass;
854 	else
855 		return 0;
856 }
857 
getDefenseType() const858 uint16 Actor::getDefenseType() const {
859 	const ShapeInfo *si = getShapeInfo();
860 	if (si->_monsterInfo)
861 		return si->_monsterInfo->_defenseType;
862 	else
863 		return 0;
864 }
865 
getDefendingDex() const866 int16 Actor::getDefendingDex() const {
867 	return getDex();
868 }
869 
getAttackingDex() const870 int16 Actor::getAttackingDex() const {
871 	return getDex();
872 }
873 
getDamageType() const874 uint16 Actor::getDamageType() const {
875 	const ShapeInfo *si = getShapeInfo();
876 	if (si->_monsterInfo)
877 		return si->_monsterInfo->_damageType;
878 	else
879 		return WeaponInfo::DMG_NORMAL;
880 }
881 
882 
getDamageAmount() const883 int Actor::getDamageAmount() const {
884 	const ShapeInfo *si = getShapeInfo();
885 	if (si->_monsterInfo) {
886 
887 		int min = static_cast<int>(si->_monsterInfo->_minDmg);
888 		int max = static_cast<int>(si->_monsterInfo->_maxDmg);
889 
890 		int damage = (getRandom() % (max - min + 1)) + min;
891 
892 		return damage;
893 	} else {
894 		return 1;
895 	}
896 }
897 
setDefaultActivity(int no,uint16 activity)898 void Actor::setDefaultActivity(int no, uint16 activity) {
899 	assert(no >= 0 && no < 3);
900 	_defaultActivity[no] = activity;
901 }
902 
getDefaultActivity(int no) const903 uint16 Actor::getDefaultActivity(int no) const {
904 	assert(no >= 0 && no < 3);
905 	return _defaultActivity[no];
906 }
907 
setHomePosition(int32 x,int32 y,int32 z)908 void Actor::setHomePosition(int32 x, int32 y, int32 z) {
909 	_homeX = x;
910 	_homeY = y;
911 	_homeZ = z;
912 }
913 
getHomePosition(int32 & x,int32 & y,int32 & z) const914 void Actor::getHomePosition(int32 &x, int32 &y, int32 &z) const {
915 	x = _homeX;
916 	y = _homeY;
917 	z = _homeZ;
918 }
919 
920 
receiveHit(uint16 other,Direction dir,int damage,uint16 damage_type)921 void Actor::receiveHit(uint16 other, Direction dir, int damage, uint16 damage_type) {
922 	if (GAME_IS_U8) {
923 		receiveHitU8(other, dir, damage, damage_type);
924 	} else {
925 		receiveHitCru(other, dir, damage, damage_type);
926 	}
927 }
928 
receiveHitCru(uint16 other,Direction dir,int damage,uint16 damage_type)929 void Actor::receiveHitCru(uint16 other, Direction dir, int damage, uint16 damage_type) {
930 	//
931 	// This is a big stack of constants and hard-coded things.
932 	// It's like that in the original game.
933 	//
934 	Actor *attacker = getActor(other);
935 	AudioProcess *audio = AudioProcess::get_instance();
936 	Kernel *kernel = Kernel::get_instance();
937 	uint32 shape = getShape();
938 	World *world = World::get_instance();
939 
940 	// Special case for Vargas, who has a shield.
941 	if (GAME_IS_REMORSE && shape == 0x3ac && world->getVargasShield() > 0) {
942 		uint16 currentanim = 0;
943 		if (isBusy()) {
944 			ActorAnimProcess *proc = dynamic_cast<ActorAnimProcess *>(Kernel::get_instance()->findProcess(_objId, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE));
945 			Animation::Sequence action = proc->getAction();
946 			if (action == Animation::teleportIn || action == Animation::teleportOut || action == Animation::teleportInReplacement || action == Animation::teleportOutReplacement)
947 				return;
948 			currentanim = proc->getPid();
949 		}
950 
951 		ProcId teleout = doAnimAfter(Animation::teleportOutReplacement, dir_current, currentanim);
952 		doAnimAfter(Animation::teleportInReplacement, dir_current, teleout);
953 		int newval = MAX(0, static_cast<int>(world->getVargasShield()) - damage);
954 		world->setVargasShield(static_cast<uint32>(newval));
955 		return;
956 	} else if (GAME_IS_REGRET && shape == 0x5b1) {
957 		warning("TODO: Finish Shape 0x5b1 special case for No Regret.");
958 		/*
959 		_bossHealth = _bossHealth - damage;
960 		if (_bossHealth < 1) {
961 		 _bossHealth = 0;
962 		  Sprite_Int_Create(0x4f1,10,0x13,3,local_8,local_6,local_4);
963 		  Item_PlaySFXCru((uint *)pitemno,0x1eb);
964 		} else {
965 		  Sprite_Int_Create(0x4f1,0,9,3,local_8,local_6,local_4);
966 		}
967 		*/
968 	}
969 
970 	if (isDead() && (getShape() != 0x5d6 || GAME_IS_REMORSE))
971 		return;
972 
973 	_lastTickWasHit = Kernel::get_instance()->getTickNum();
974 
975 	if (shape != 1 && this != getControlledActor()) {
976 		Actor *controlled = getControlledActor();
977 		if (!isInCombat()) {
978 			setActivity(getDefaultActivity(2)); // get activity from field 0xA
979 			if (!isInCombat()) {
980 				setInCombatCru(5);
981 				CombatProcess *combat = getCombatProcess();
982 				if (combat && controlled) {
983 					combat->setTarget(controlled->getObjId());
984 				}
985 			}
986 		} else {
987 			if (getCurrentActivityNo() == 8) {
988 				setActivity(5);
989 			}
990 			setInCombatCru(5);
991 			CombatProcess *combat = getCombatProcess();
992 			if (combat && controlled) {
993 				combat->setTarget(controlled->getObjId());
994 			}
995 		}
996 
997 		// If the attacker is the controlled npc and this actor is not pathfinding
998 		if (attacker && attacker == getControlledActor() &&
999 			kernel->findProcess(_objId, PathfinderProcess::PATHFINDER_PROC_TYPE) != nullptr) {
1000 			int32 x, y, z;
1001 			int32 ox, oy, oz;
1002 			getLocation(x, y, z);
1003 			attacker->getLocation(ox, oy, oz);
1004 			int32 maxdiff = MAX(MAX(abs(x - ox), abs(y - oy)), abs(z - oz));
1005 			if (maxdiff < 641 && isOnScreen()) {
1006 				// TODO: implement the equivalent of this function.  For now, we always
1007 				// cancel pathfinding for the NPC.
1008 				// uint32 direction = static_cast<uint32>(Get_WorldDirection(y - oy, x - ox));
1009 				// int result = FUN_1128_1755(this, attacker, direction, 0, 0, 0);
1010 				// if (result) {
1011 					kernel->killProcesses(_objId, PathfinderProcess::PATHFINDER_PROC_TYPE, true);
1012 				// }
1013 			}
1014 		}
1015 	} else {
1016 		damage = receiveShieldHit(damage, damage_type);
1017 	}
1018 
1019 	if (hasActorFlags(ACT_IMMORTAL | ACT_INVINCIBLE))
1020 		damage = 0;
1021 
1022 	if (damage > _hitPoints)
1023 		damage = _hitPoints;
1024 
1025 	setHP(static_cast<uint16>(_hitPoints - damage));
1026 
1027 	if (_hitPoints == 0) {
1028 		// Die!
1029 		die(damage_type, damage, dir);
1030 	} else if (damage) {
1031 		// Not dead yet.
1032 		if (!isRobotCru()) {
1033 			uint16 sfxno;
1034 			if (hasExtFlags(EXT_FEMALE)) {
1035 				sfxno = 0xd8; // female scream
1036 			} else {
1037 				sfxno = 0x8f; // male scream
1038 			}
1039 			if (audio && !audio->isSFXPlayingForObject(sfxno, other)) {
1040 				audio->playSFX(sfxno, 0x10, other, 1, false);
1041 			}
1042 		}
1043 		if (damage_type == 0xf || damage_type == 7) {
1044 			if (shape == 1) {
1045 				kernel->killProcesses(_objId, PathfinderProcess::PATHFINDER_PROC_TYPE, true);
1046 				doAnim(static_cast<Animation::Sequence>(0x37), dir_current);
1047 			} else if (shape == 0x4e6 || shape == 0x338 || shape == 0x385 || shape == 899) {
1048 				if (!(getRandom() % 3)) {
1049 					// Randomly stun the NPC for these damage types.
1050 					// CHECK ME: is this time accurate?
1051 					Process *attack = kernel->findProcess(_objId, AttackProcess::ATTACK_PROCESS_TYPE);
1052 					uint stun = ((getRandom() % 10) + 8) * 60;
1053 					if (attack && stun) {
1054 						Process *delay = new DelayProcess(stun);
1055 						kernel->addProcess(delay);
1056 						attack->waitFor(delay);
1057 					}
1058 				}
1059 			}
1060 		}
1061 	}
1062 }
1063 
1064 #define RAND_ELEM(array) (array[getRandom() % ARRAYSIZE(array)])
1065 
tookHitCru()1066 void Actor::tookHitCru() {
1067 	AudioProcess *audio = AudioProcess::get_instance();
1068 	Animation::Sequence lastanim = getLastAnim();
1069 	bool isfemale = hasExtFlags(EXT_FEMALE);
1070 	if (!audio)
1071 		return;
1072 
1073 	if (lastanim == Animation::unknownAnim30 || lastanim == Animation::startRunLargeWeapon) {
1074 		if (canSeeControlledActor(true)) {
1075 			if (getRandom() % 4)
1076 				setActivity(5);
1077 			else
1078 				setActivity(10);
1079 		}
1080 	} else if (GAME_IS_REMORSE) {
1081 		uint32 shape = getShape();
1082 		if (shape == 0x385 || shape == 0x4e6) {
1083 			explode(2, 0);
1084 			clearFlag(FLG_IN_NPC_LIST | FLG_GUMP_OPEN);
1085 		} else if (shape == 0x576 || shape == 0x596) {
1086 			bool violence = true; // Game::I_isViolenceEnabled
1087 			if (!violence)
1088 				return;
1089 
1090 			static const uint16 FEMALE_SFX[] = {0xb, 0xa};
1091 			static const uint16 MALE_SFX[] = {0x65, 0x66, 0x67};
1092 			int nsounds = isfemale ? ARRAYSIZE(FEMALE_SFX) : ARRAYSIZE(MALE_SFX);
1093 			const uint16 *sounds = isfemale ? FEMALE_SFX : MALE_SFX;
1094 
1095 			for (int i = 0; i < nsounds; i++) {
1096 				if (audio->isSFXPlayingForObject(sounds[i], _objId))
1097 					return;
1098 			}
1099 
1100 			audio->playSFX(sounds[getRandom() % nsounds], 0x80, _objId, 1);
1101 		}
1102 	} else if (GAME_IS_REGRET) {
1103 		switch (getShape()) {
1104 		case 0x596: {
1105 			static const uint16 FEMALE_SFX[] = {0x212, 0x211};
1106 			static const uint16 MALE_SFX[] = {0x213, 0x214};
1107 			int sfxno = isfemale ? RAND_ELEM(FEMALE_SFX) : RAND_ELEM(MALE_SFX);
1108 			audio->playSFX(sfxno, 0x80, _objId, 1);
1109 			break;
1110 		}
1111 		case 0x576: {
1112 			static const uint16 FEMALE_SFX[] = {0x3D, 0x77, 0x210};
1113 			static const uint16 MALE_SFX[] = {0x24F, 0x250, 0x201, 0x200};
1114 			bool violence = true; // Game::I_isViolenceEnabled
1115 			if (!violence)
1116 				return;
1117 
1118 			int nsounds = isfemale ? ARRAYSIZE(FEMALE_SFX) : ARRAYSIZE(MALE_SFX);
1119 			const uint16 *sounds = isfemale ? FEMALE_SFX : MALE_SFX;
1120 
1121 			for (int i = 0; i < nsounds; i++) {
1122 				if (audio->isSFXPlayingForObject(sounds[i], _objId))
1123 					return;
1124 			}
1125 
1126 			audio->playSFX(sounds[getRandom() % nsounds], 0x80, _objId, 1);
1127 			return;
1128 		}
1129 		case 0x385:
1130 		case 0x4e6: {
1131 			explode(2, false);
1132 			clearFlag(FLG_GUMP_OPEN | FLG_IN_NPC_LIST);
1133 			break;
1134 		}
1135 		case 0x5d6: {
1136 			static const uint16 MALE_SFX[] = {0x21B, 0x21A, 0x21C};
1137 			static const uint16 FEMALE_SFX[] = {0x21D, 0x215};
1138 			int sfxno = isfemale ? RAND_ELEM(FEMALE_SFX) : RAND_ELEM(MALE_SFX);
1139 			audio->playSFX(sfxno, 0x80, _objId, 1);
1140 			break;
1141 		}
1142 		case 0x62d: {
1143 			static const uint16 MALE_SFX[] = {0x217, 0x218};
1144 			static const uint16 FEMALE_SFX[] = {0x219, 0x216};
1145 			int sfxno = isfemale ? RAND_ELEM(FEMALE_SFX) : RAND_ELEM(MALE_SFX);
1146 			audio->playSFX(sfxno, 0x80, _objId, 1);
1147 			break;
1148 		}
1149 		case 0x656:
1150 		case 0x278: {
1151 			static const uint16 MALE_SFX[] = {0x20B, 0x20C, 0x20D};
1152 			static const uint16 FEMALE_SFX[] = {0x20E, 0x20F};
1153 			int sfxno = isfemale ? RAND_ELEM(FEMALE_SFX) : RAND_ELEM(MALE_SFX);
1154 			audio->playSFX(sfxno, 0x80, _objId, 1);
1155 			break;
1156 		}
1157 		case 0x5b1: {
1158 			Process *proc = new BoboBoomerProcess(this);
1159 			Kernel::get_instance()->addProcess(proc);
1160 			break;
1161 		}
1162 		case 0x58f:
1163 		case 0x59c: {
1164 			static const uint16 SOUNDS[] = {0xD9, 0xDA};
1165 			audio->playSFX(RAND_ELEM(SOUNDS), 0x80, _objId, 1);
1166 			break;
1167 		}
1168 		default:
1169 			break;
1170 		}
1171 	}
1172 }
1173 
receiveHitU8(uint16 other,Direction dir,int damage,uint16 damage_type)1174 void Actor::receiveHitU8(uint16 other, Direction dir, int damage, uint16 damage_type) {
1175 	if (isDead())
1176 		return; // already dead, so don't bother
1177 
1178 	Item *hitter = getItem(other);
1179 	Actor *attacker = getActor(other);
1180 
1181 	if (damage == 0 && attacker) {
1182 		damage = attacker->getDamageAmount();
1183 	}
1184 
1185 	if (damage_type == 0 && hitter) {
1186 		damage_type = hitter->getDamageType();
1187 	}
1188 
1189 	if (other == 1 && attacker && attacker->getLastAnim() != Animation::kick) {
1190 		// _strength for kicks is accumulated in AvatarMoverProcess
1191 		MainActor *av = getMainActor();
1192 		av->accumulateStr(damage / 4);
1193 	}
1194 
1195 	pout << "Actor " << getObjId() << " received hit from " << other
1196 	     << " (dmg=" << damage << ",type=" << ConsoleStream::hex << damage_type
1197 	     << ConsoleStream::dec << "). ";
1198 
1199 	damage = calculateAttackDamage(other, damage, damage_type);
1200 
1201 	if (!damage) {
1202 		pout << "No damage." << Std::endl;
1203 	} else {
1204 		pout << "Damage: " << damage << Std::endl;
1205 	}
1206 
1207 	if (damage >= 4 && _objId == 1 && attacker) {
1208 		// play blood sprite
1209 		int start = 0, end = 12;
1210 		if (dir > dir_east) {
1211 			start = 13;
1212 			end = 25;
1213 		}
1214 
1215 		int32 xv, yv, zv;
1216 		getLocation(xv, yv, zv);
1217 		zv += (getRandom() % 24);
1218 		Process *sp = new SpriteProcess(620, start, end, 1, 1, xv, yv, zv);
1219 		Kernel::get_instance()->addProcess(sp);
1220 	}
1221 
1222 	if (damage > 0 && !hasActorFlags(ACT_IMMORTAL | ACT_INVINCIBLE)) {
1223 		if (damage >= _hitPoints) {
1224 			// we're dead
1225 
1226 			if (hasActorFlags(ACT_WITHSTANDDEATH)) {
1227 				// or maybe not...
1228 
1229 				setHP(getMaxHP());
1230 				AudioProcess *audioproc = AudioProcess::get_instance();
1231 				if (audioproc) audioproc->playSFX(59, 0x60, _objId, 0);
1232 				clearActorFlag(ACT_WITHSTANDDEATH);
1233 			} else {
1234 				die(damage_type, damage, dir);
1235 			}
1236 			return;
1237 		}
1238 
1239 		// not dead yet
1240 		setHP(static_cast<uint16>(_hitPoints - damage));
1241 	}
1242 
1243 	ProcId fallingprocid = 0;
1244 	if (_objId == 1 && damage > 0) {
1245 		if ((damage_type & WeaponInfo::DMG_FALLING) && damage >= 6) {
1246 			// high falling damage knocks you down
1247 			doAnim(Animation::fallBackwards, dir_current);
1248 
1249 			// TODO: shake head after getting back up when not in combat
1250 			return;
1251 		}
1252 
1253 		// got hit, so abort current animation
1254 		fallingprocid = killAllButFallAnims(false);
1255 	}
1256 
1257 	// if avatar was blocking; do a quick stopBlock/startBlock and play SFX
1258 	if (_objId == 1 && getLastAnim() == Animation::startBlock) {
1259 		ProcId anim1pid = doAnim(Animation::stopBlock, dir_current);
1260 		ProcId anim2pid = doAnim(Animation::startBlock, dir_current);
1261 
1262 		Process *anim1proc = Kernel::get_instance()->getProcess(anim1pid);
1263 		Process *anim2proc = Kernel::get_instance()->getProcess(anim2pid);
1264 		assert(anim1proc);
1265 		assert(anim2proc);
1266 		anim2proc->waitFor(anim1proc);
1267 
1268 		int sfx;
1269 		if (damage)
1270 			sfx = 50 + (getRandom() % 2); // constants!
1271 		else
1272 			sfx = 20 + (getRandom() % 3); // constants!
1273 		AudioProcess *audioproc = AudioProcess::get_instance();
1274 		if (audioproc) audioproc->playSFX(sfx, 0x60, _objId, 0);
1275 		return;
1276 	}
1277 
1278 	// TODO: target needs to stumble/fall/call for help/...(?)
1279 
1280 	if (_objId != 1) {
1281 		ObjId target = 1;
1282 		if (attacker)
1283 			target = attacker->getObjId();
1284 		if (!isInCombat())
1285 			setInCombatU8();
1286 
1287 		CombatProcess *cp = getCombatProcess();
1288 		assert(cp);
1289 		cp->setTarget(target);
1290 
1291 		if (target == 1) {
1292 			// call for help
1293 		}
1294 	}
1295 
1296 	if (damage && !fallingprocid) {
1297 		ProcId anim1pid = doAnim(Animation::stumbleBackwards, dir);
1298 		ProcId anim2pid;
1299 		if (isInCombat())
1300 			// not doing this would cause you to re-draw your weapon when hit
1301 			anim2pid = doAnim(Animation::combatStand, dir);
1302 		else
1303 			anim2pid = doAnim(Animation::stand, dir);
1304 		Process *anim1proc = Kernel::get_instance()->getProcess(anim1pid);
1305 		Process *anim2proc = Kernel::get_instance()->getProcess(anim2pid);
1306 		assert(anim1proc);
1307 		assert(anim2proc);
1308 		anim2proc->waitFor(anim1proc);
1309 	}
1310 }
1311 
die(uint16 damageType,uint16 damagePts,Direction srcDir)1312 ProcId Actor::die(uint16 damageType, uint16 damagePts, Direction srcDir) {
1313 	setHP(0);
1314 	setActorFlag(ACT_DEAD);
1315 	setFlag(FLG_BROKEN);
1316 	clearActorFlag(ACT_INCOMBAT);
1317 
1318 	if (GAME_IS_U8)
1319 		return dieU8(damageType);
1320 	else
1321 		return dieCru(damageType, damagePts, srcDir);
1322 }
1323 
dieU8(uint16 damageType)1324 ProcId Actor::dieU8(uint16 damageType) {
1325 	ProcId animprocid = 0;
1326 #if 1
1327 	animprocid = killAllButFallAnims(true);
1328 #else
1329 	Kernel::get_instance()->killProcesses(getObjId(), Kernel::PROC_TYPE_ALL, true);
1330 #endif
1331 
1332 	if (!animprocid)
1333 		animprocid = doAnim(Animation::die, dir_current);
1334 
1335 	MainActor *avatar = getMainActor();
1336 	// if hostile to avatar
1337 	if (getEnemyAlignment() & avatar->getAlignment()) {
1338 		if (avatar->isInCombat()) {
1339 			// play victory fanfare
1340 			MusicProcess::get_instance()->playCombatMusic(109);
1341 			// and resume combat music afterwards
1342 			MusicProcess::get_instance()->queueMusic(98);
1343 		}
1344 	}
1345 
1346 	destroyContents();
1347 	giveTreasure();
1348 
1349 	const ShapeInfo *shapeinfo = getShapeInfo();
1350 	const MonsterInfo *mi = nullptr;
1351 	if (shapeinfo) mi = shapeinfo->_monsterInfo;
1352 
1353 	if (mi && mi->_resurrection && !(damageType & WeaponInfo::DMG_FIRE)) {
1354 		// this monster will be resurrected after a while
1355 
1356 		pout << "Actor::die: scheduling resurrection" << Std::endl;
1357 
1358 		int timeout = ((getRandom() % 25) + 5) * 30; // 5-30 seconds
1359 
1360 		Process *resproc = new ResurrectionProcess(this);
1361 		Kernel::get_instance()->addProcess(resproc);
1362 
1363 		Process *delayproc = new DelayProcess(timeout);
1364 		Kernel::get_instance()->addProcess(delayproc);
1365 
1366 		ProcId animpid = doAnim(Animation::standUp, dir_current);
1367 		Process *animproc = Kernel::get_instance()->getProcess(animpid);
1368 		assert(animproc);
1369 
1370 		resproc->waitFor(delayproc);
1371 		animproc->waitFor(resproc);
1372 	}
1373 
1374 	if (mi && mi->_explode) {
1375 		// this monster explodes when it dies
1376 
1377 		pout << "Actor::die: exploding" << Std::endl;
1378 
1379 		int count = 5;
1380 		Shape *explosionshape = GameData::get_instance()->getMainShapes()
1381 								->getShape(mi->_explode);
1382 		assert(explosionshape);
1383 		unsigned int framecount = explosionshape->frameCount();
1384 
1385 		for (int i = 0; i < count; ++i) {
1386 			Item *piece = ItemFactory::createItem(mi->_explode,
1387 												  getRandom() % framecount,
1388 												  0, // qual
1389 												  Item::FLG_FAST_ONLY, //flags,
1390 												  0, // npcnum
1391 												  0, // mapnum
1392 												  0, true // ext. flags, _objId
1393 												 );
1394 			piece->move(_x - 128 + 32 * (getRandom() % 6),
1395 						_y - 128 + 32 * (getRandom() % 6),
1396 						_z + getRandom() % 8); // move to near actor's position
1397 			piece->hurl(-25 + (getRandom() % 50),
1398 						-25 + (getRandom() % 50),
1399 						10 + (getRandom() % 10),
1400 						4); // (wrong?) CONSTANTS!
1401 		}
1402 	}
1403 
1404 	return animprocid;
1405 }
1406 
dieCru(uint16 damageType,uint16 damagePts,Direction srcDir)1407 ProcId Actor::dieCru(uint16 damageType, uint16 damagePts, Direction srcDir) {
1408 	bool is_robot = isRobotCru();
1409 	bool created_koresh = false;
1410 	const uint32 startshape = getShape();
1411 
1412 	World *world = World::get_instance();
1413 
1414 	world->getCurrentMap()->removeTargetItem(this);
1415 
1416     if (world->getControlledNPCNum() == _objId) {
1417 		TargetReticleProcess::get_instance()->avatarMoved();
1418 		if (_objId != 1) {
1419 			world->setControlledNPCNum(0);
1420 		}
1421 	}
1422 
1423 	ProcId lastanim = 0;
1424 	Kernel::get_instance()->killProcesses(_objId, Kernel::PROC_TYPE_ALL, true);
1425 
1426 	destroyContents();
1427 	giveTreasure();
1428 
1429 	if (getShape() == 0x5d6 && GAME_IS_REGRET) {
1430 		// you only die twice.. (frozen person breaking into pieces)
1431 		if (!isBusy()) {
1432 			setShape(0x5ef);
1433 			setToStartOfAnim(Animation::fallBackwardsCru);
1434 		}
1435 	} else if (damageType == 3 || damageType == 4 || damageType == 10 || damageType == 12) {
1436 		if (!is_robot /* && violence enabled */) {
1437 			const FireType *ft = GameData::get_instance()->getFireType(damageType);
1438 			assert(ft);
1439 			uint16 dmg2 = ft->getRandomDamage();
1440 			if (damageType == 3) {
1441 				dmg2 *= 3;
1442 			} else {
1443 				dmg2 *= 2;
1444 			}
1445 			dmg2 /= 5;
1446 			if (dmg2 <= damagePts) {
1447 				moveToEtherealVoid();
1448 				CurrentMap *cm = world->getCurrentMap();
1449 				/* 0x576 - flaming guy running around */
1450 				bool can_create_koresh = cm->isValidPosition(_x, _y, _z, 0x576, _objId);
1451 				returnFromEtherealVoid();
1452 
1453 				if (can_create_koresh) {
1454 					created_koresh = true;
1455 					Direction rundir = _direction;
1456 					setShape(0x576);
1457 					setToStartOfAnim(Animation::walk);
1458 
1459 					int num_random_steps = getRandom() % 9;
1460 					// switch to an 8-dir value
1461 					if (rundir % 2)
1462 						rundir = static_cast<Direction>((rundir + 1) % 16);
1463 
1464 					for (int i = 0; i < num_random_steps; i++) {
1465 						rundir = Direction_TurnByDelta(rundir, (int)(getRandom() % 3) - 1, dirmode_8dirs);
1466 						lastanim = doAnimAfter(Animation::walk, rundir, lastanim);
1467 					}
1468 
1469 					lastanim = doAnimAfter(Animation::fallBackwardsCru, dir_current, lastanim);
1470 
1471 					int num_random_falls = (getRandom() % 3) + 1;
1472 					for (int i = 0; i < num_random_falls; i++) {
1473 						lastanim = doAnimAfter(Animation::fallForwardsCru, dir_current, lastanim);
1474 					}
1475 
1476 					lastanim = doAnimAfter(Animation::kneelCombatRollLeft, dir_current, lastanim);
1477 					tookHitCru();
1478 				}
1479 			}
1480 		}
1481 	} else if (damageType == 6) {
1482 		if (!is_robot) {
1483 			/*  1423 = plasma death */
1484 			setShape(0x58f);
1485 			setToStartOfAnim(Animation::stand);
1486 		}
1487 	} else if (damageType == 14) {
1488 		if (!is_robot) {
1489 			if (true /*isViolenceEnabled()*/) {
1490 				/* 1430 = fire death skeleton */
1491 				setShape(0x596);
1492 				setToStartOfAnim(Animation::fallBackwardsCru);
1493 			}
1494 		}
1495 	} else if (damageType == 15) {
1496 		if (!is_robot) {
1497 			setShape(0x59c);
1498 			setToStartOfAnim(Animation::fallBackwardsCru);
1499 		}
1500 	} else if ((damageType == 0x10) || (damageType == 0x12)) {
1501 		if (!is_robot) {
1502 			setShape(0x5d6);
1503 			setToStartOfAnim(Animation::fallBackwardsCru);
1504 		}
1505 	} else if (damageType == 0x11) {
1506 		if (!is_robot) {
1507 			setShape(0x62d);
1508 			setToStartOfAnim(Animation::fallBackwardsCru);
1509 		}
1510 	} else if (damageType == 0x14) {
1511 		if (!is_robot) {
1512 			if (true /*isViolenceEnabled()*/) {
1513 				setShape(0x278);
1514 				setToStartOfAnim(Animation::fallBackwardsCru);
1515 			}
1516 		}
1517 	} else if (damageType == 7 && _objId == 1) {
1518 		lastanim = doAnimAfter(Animation::electrocuted, dir_current, lastanim);
1519 	}
1520 
1521 	if (!created_koresh) {
1522 		bool fall_backwards = true;
1523 		bool fall_random_dir = false;
1524 
1525 		if (GAME_IS_REGRET) {
1526 			uint32 shape = getShape();
1527 			if (startshape == shape) {
1528 				if (shape == 0x5ff || shape == 0x5d7) {
1529 					setShape(0x606);
1530 					setToStartOfAnim(Animation::fallBackwardsCru);
1531 				} else if (shape == 0x625 || shape == 0x626) {
1532 					setShape(0x62e);
1533 					setToStartOfAnim(Animation::fallBackwardsCru);
1534 				} else if (shape == 0x5f0 || shape == 0x2c3) {
1535 					setShape(0x5d5);
1536 					setToStartOfAnim(Animation::fallBackwardsCru);
1537 				} else if (shape == 0x62f || shape == 0x630) {
1538 					setShape(0x631);
1539 					setToStartOfAnim(Animation::fallBackwardsCru);
1540 				}
1541 			}
1542 		}
1543 
1544 
1545 		Direction dirtest[9];
1546 		/* 0x383 == 899 (robot), 1423 = plasma death, 1430 = fire death skeleton */
1547 		if (getShape() != 899 && getShape() != 0x58f && getShape() != 0x596) {
1548 			dirtest[0] = _direction;
1549 			for (int i = 1; i < 9; i = i + 1) {
1550 				char testdir = (i % 2) ? 1 : -1;
1551 				dirtest[i] = Direction_TurnByDelta(_direction, ((i + 1) / 2) * testdir, dirmode_8dirs);
1552 			}
1553 			for (int i = 0; i < 9; i++) {
1554 				if (dirtest[i] == srcDir) {
1555 					if (i == 8 || i == 9) {
1556 						fall_random_dir = true;
1557 					} else {
1558 						fall_backwards = false;
1559 					}
1560 					break;
1561 				}
1562 			}
1563 		} else {
1564 			fall_random_dir = true;
1565 		}
1566 
1567 		if (!hasAnim(Animation::fallForwardsCru)) {
1568 			lastanim = doAnimAfter(Animation::fallBackwardsCru, dir_current, lastanim);
1569 		} else {
1570 			if (fall_random_dir) {
1571 				fall_backwards = (getRandom() % 2) == 0;
1572 			}
1573 			if (fall_backwards) {
1574 				lastanim = doAnimAfter(Animation::fallBackwardsCru, dir_current, lastanim);
1575 			} else {
1576 				lastanim = doAnimAfter(Animation::fallForwardsCru, dir_current, lastanim);
1577 			}
1578 		}
1579 
1580 		if (!is_robot) {
1581 			uint16 sfxno;
1582 			static const uint16 FADING_SCREAM_SFX[] = { 0xD9, 0xDA };
1583 			static const uint16 MALE_DEATH_SFX[] = { 0x88, 0x8C, 0x8F };
1584 			static const uint16 FEMALE_DEATH_SFX[] = { 0xD8, 0x10 };
1585 			if (damageType == 0xf) {
1586 				sfxno = FADING_SCREAM_SFX[getRandom() % 2];
1587 			} else {
1588 				if (hasExtFlags(EXT_FEMALE)) {
1589 					sfxno = FEMALE_DEATH_SFX[getRandom() % 2];
1590 				} else {
1591 					sfxno = MALE_DEATH_SFX[getRandom() % 3];
1592 				}
1593 			}
1594 			AudioProcess::get_instance()->playSFX(sfxno, 0x10, _objId, 0, true);
1595 		}
1596 	}
1597 
1598 	return lastanim;
1599 }
1600 
killAllButCombatProcesses()1601 void Actor::killAllButCombatProcesses() {
1602 	// loop over all processes, keeping only the relevant ones
1603 	ProcessIter iter = Kernel::get_instance()->getProcessBeginIterator();
1604 	ProcessIter endproc = Kernel::get_instance()->getProcessEndIterator();
1605 	for (; iter != endproc; ++iter) {
1606 		Process *p = *iter;
1607 		if (!p) continue;
1608 		if (p->getItemNum() != _objId) continue;
1609 		if (p->is_terminated()) continue;
1610 
1611 		uint16 type = p->getType();
1612 
1613 		if (type != 0xF0 && type != 0xF2 && type != 0x208 && type != 0x21D &&
1614 		        type != 0x220 && type != 0x238 && type != 0x243) {
1615 			p->fail();
1616 		}
1617 	}
1618 }
1619 
killAllButFallAnims(bool death)1620 ProcId Actor::killAllButFallAnims(bool death) {
1621 	ProcId fallproc = 0;
1622 
1623 	Kernel *kernel = Kernel::get_instance();
1624 
1625 	if (death) {
1626 		// if dead, we want to kill everything but animations
1627 		kernel->killProcessesNotOfType(_objId, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE, true);
1628 	} else {
1629 		// otherwise, need to focus on combat, so kill everything else
1630 		killAllButCombatProcesses();
1631 	}
1632 
1633 	// loop over all animation processes, keeping only the relevant ones
1634 	ProcessIter iter = Kernel::get_instance()->getProcessBeginIterator();
1635 	ProcessIter endproc = Kernel::get_instance()->getProcessEndIterator();
1636 	for (; iter != endproc; ++iter) {
1637 		ActorAnimProcess *p = dynamic_cast<ActorAnimProcess *>(*iter);
1638 		if (!p) continue;
1639 		if (p->getItemNum() != _objId) continue;
1640 		if (p->is_terminated()) continue;
1641 
1642 		Animation::Sequence action = p->getAction();
1643 
1644 		if (action == Animation::die) {
1645 			fallproc = p->getPid();
1646 			continue;
1647 		}
1648 
1649 		if (!death && action == Animation::standUp) {
1650 			fallproc = p->getPid();
1651 		} else {
1652 			p->fail();
1653 		}
1654 	}
1655 
1656 	return fallproc;
1657 }
1658 
calculateAttackDamage(uint16 other,int damage,uint16 damage_type)1659 int Actor::calculateAttackDamage(uint16 other, int damage, uint16 damage_type) {
1660 	Actor *attacker = getActor(other);
1661 
1662 	uint16 defense_type = getDefenseType();
1663 
1664 	// most damage types are blocked straight away by defense types
1665 	damage_type &= ~(defense_type & ~(WeaponInfo::DMG_MAGIC  |
1666 	                                  WeaponInfo::DMG_UNDEAD |
1667 	                                  WeaponInfo::DMG_PIERCE));
1668 
1669 	// immunity to non-magical weapons
1670 	if ((defense_type & WeaponInfo::DMG_MAGIC) &&
1671 	        !(damage_type & WeaponInfo::DMG_MAGIC)) {
1672 		damage = 0;
1673 	}
1674 
1675 	bool slayer = false;
1676 
1677 	// _special attacks
1678 	if (damage && damage_type) {
1679 		if (damage_type & WeaponInfo::DMG_SLAYER) {
1680 			if (getRandom() % 10 == 0) {
1681 				slayer = true;
1682 				damage = 255; // instant kill
1683 			}
1684 		}
1685 
1686 		if ((damage_type & WeaponInfo::DMG_UNDEAD) &&
1687 		        (defense_type & WeaponInfo::DMG_UNDEAD)) {
1688 			damage *= 2; // double damage against undead
1689 		}
1690 
1691 		if ((defense_type & WeaponInfo::DMG_PIERCE) &&
1692 		        !(damage_type & (WeaponInfo::DMG_BLADE |
1693 		                         WeaponInfo::DMG_FIRE  |
1694 		                         WeaponInfo::DMG_PIERCE))) {
1695 			damage /= 2; // resistance to blunt damage
1696 		}
1697 	} else {
1698 		damage = 0;
1699 	}
1700 
1701 	// armour
1702 	if (damage && !(damage_type & WeaponInfo::DMG_PIERCE) && !slayer) {
1703 		// blocking?
1704 		if ((getLastAnim() == Animation::startBlock ||
1705 		        getLastAnim() == Animation::stopBlock) &&
1706 		        !hasActorFlags(ACT_STUNNED)) {
1707 			damage -= getStr() / 5;
1708 		}
1709 
1710 		int ACmod = 3 * getArmourClass();
1711 		if (damage_type & WeaponInfo::DMG_FIRE)
1712 			ACmod /= 2; // armour doesn't protect from fire as well
1713 
1714 		if (hasActorFlags(ACT_STUNNED))
1715 			ACmod /= 2; // stunned?
1716 
1717 		if (ACmod > 100) ACmod = 100;
1718 
1719 		// TODO: replace rounding bias by something random
1720 		damage = ((100 - ACmod) * damage) / 100;
1721 
1722 		if (damage < 0) damage = 0;
1723 	}
1724 
1725 	// to-hit
1726 	if (damage && !(damage_type & WeaponInfo::DMG_PIERCE) && attacker) {
1727 		bool hit = false;
1728 		int16 attackdex = attacker->getAttackingDex();
1729 		int16 defenddex = getDefendingDex();
1730 		if (attackdex < 0) attackdex = 0;
1731 		if (defenddex <= 0) defenddex = 1;
1732 
1733 		if (hasActorFlags(ACT_STUNNED) ||
1734 		        (getRandom() % (attackdex + 3) > getRandom() % defenddex)) {
1735 			hit = true;
1736 		}
1737 
1738 		// TODO: give avatar an extra chance to hit monsters
1739 		//       with defense_type DMG_PIERCE
1740 
1741 		if (hit && other == 1) {
1742 			MainActor *av = getMainActor();
1743 			if (attackdex > defenddex)
1744 				av->accumulateDex(2 * (attackdex - defenddex));
1745 			else
1746 				av->accumulateDex(2);
1747 		}
1748 
1749 		if (!hit) {
1750 			damage = 0;
1751 		}
1752 	}
1753 
1754 	return damage;
1755 }
1756 
isFalling() const1757 bool Actor::isFalling() const {
1758 	ProcId gravitypid = getGravityPID();
1759 	if (!gravitypid)
1760 		return false;
1761 
1762 	// TODO: this is not exactly the same as the Crusader implementation,
1763 	// but pretty close.  Is that ok?
1764 	GravityProcess *proc = dynamic_cast<GravityProcess *>(Kernel::get_instance()->getProcess(gravitypid));
1765 	return (proc && proc->is_active());
1766 }
1767 
getCombatProcess()1768 CombatProcess *Actor::getCombatProcess() {
1769 	Process *p = Kernel::get_instance()->findProcess(_objId, 0xF2); // CONSTANT!
1770 	if (!p)
1771 		return nullptr;
1772 	CombatProcess *cp = dynamic_cast<CombatProcess *>(p);
1773 	assert(cp);
1774 
1775 	return cp;
1776 }
1777 
getAttackProcess()1778 AttackProcess *Actor::getAttackProcess() {
1779 	Process *p = Kernel::get_instance()->findProcess(_objId, AttackProcess::ATTACK_PROCESS_TYPE);
1780 	if (!p)
1781 		return nullptr;
1782 	AttackProcess *ap = dynamic_cast<AttackProcess *>(p);
1783 	assert(ap);
1784 
1785 	return ap;
1786 }
1787 
setInCombat(int activity)1788 void Actor::setInCombat(int activity) {
1789 	if (GAME_IS_U8)
1790 		setInCombatU8();
1791 	else
1792 		setInCombatCru(activity);
1793 }
1794 
setInCombatU8()1795 void Actor::setInCombatU8() {
1796 	if ((_actorFlags & ACT_INCOMBAT) != 0) return;
1797 
1798 	assert(getCombatProcess() == nullptr);
1799 
1800 	// kill any processes belonging to this actor
1801 	Kernel::get_instance()->killProcesses(getObjId(), Kernel::PROC_TYPE_ALL, true);
1802 
1803 	// perform _special actions
1804 	ProcId castproc = callUsecodeEvent_cast(0);
1805 
1806 	CombatProcess *cp = new CombatProcess(this);
1807 	Kernel::get_instance()->addProcess(cp);
1808 
1809 	// wait for any _special actions to finish before starting to fight
1810 	if (castproc)
1811 		cp->waitFor(castproc);
1812 
1813 	setActorFlag(ACT_INCOMBAT);
1814 }
1815 
setInCombatCru(int activity)1816 void Actor::setInCombatCru(int activity) {
1817 	if ((_actorFlags & ACT_INCOMBAT) != 0) return;
1818 
1819 	assert(getAttackProcess() == nullptr);
1820 
1821 	setActorFlag(ACT_INCOMBAT);
1822 
1823 	if (getObjId() == World::get_instance()->getControlledNPCNum())
1824 		return;
1825 
1826 	AttackProcess *ap = new AttackProcess(this);
1827 	Kernel::get_instance()->addProcess(ap);
1828 
1829 	if (getLastActivityNo() == 8) {
1830 		// Coming from guard process.. set some flag in ap
1831 		ap->setField97();
1832 	}
1833 	if (activity == 0xc) {
1834 		// This sets timer 3 of the attack process
1835 		// to some random timer value in the future
1836 		ap->setTimer3();
1837 	}
1838 
1839 	uint16 animproc = 0;
1840 	if (activity == 9 || activity == 0xb) {
1841 		ap->setIsActivity9OrB();
1842 		animproc = doAnim(Animation::readyWeapon, dir_current);
1843 	} else {
1844 		animproc = doAnim(Animation::stand, dir_current);
1845 	}
1846 	if (animproc) {
1847 		// Do the animation first
1848 		ap->waitFor(animproc);
1849 	}
1850 
1851 	if (activity == 0xa || activity == 0xb) {
1852 		ap->setIsActivityAOrB();
1853 	}
1854 }
1855 
clearInCombat()1856 void Actor::clearInCombat() {
1857 	if ((_actorFlags & ACT_INCOMBAT) == 0) return;
1858 
1859 	Process *p;
1860 	if (GAME_IS_U8) {
1861 		p = getCombatProcess();
1862 	} else {
1863 		p = getAttackProcess();
1864 	}
1865 	if (p)
1866 		p->terminate();
1867 
1868 	clearActorFlag(ACT_INCOMBAT);
1869 }
1870 
canSeeControlledActor(bool forcombat)1871 bool Actor::canSeeControlledActor(bool forcombat) {
1872 	const Actor *controlled = getControlledActor();
1873 	if (!controlled)
1874 		return false;
1875 
1876 	if (!isOnScreen())
1877 		return false;
1878 
1879 	Direction dirtocontrolled = getDirToItemCentre(*controlled);
1880 	Direction curdir = getDir();
1881 
1882 	/* TODO: There are extra checks in here in the original
1883 	if (forcombat) {
1884 		 Animation::Sequence lastanim = getLastAnim();
1885 		((lastanim == Animation::unknownAnim30 || lastanim == Animation::startRunLargeWeapon) && currentAnimFrame > 1)) {
1886 		 bool left;
1887 		 if (lastanim == Animation::unknownAnim30) {
1888 			left = false;
1889 			if (((currentdir != 8) && (currentdir != 10)) && (currentdir != 0xc))
1890 				left = true;
1891 		 } else {
1892 			left = true;
1893 			if (((currentdir != 8) && (currentdir != 10)) && (currentdir != 0xc)) {
1894 				left = false;
1895 		 }
1896 		 if (leftflag) {
1897 			currentdir = Direction_TurnByDelta(curdir, -4, dirmode_16dirs);
1898 		 } else {
1899 			currentdir = Direction_TurnByDelta(curdir, 4, dirmode_16dirs);
1900 		 }
1901 	}
1902 	*/
1903 
1904 	if (dirtocontrolled == curdir ||
1905 		dirtocontrolled == Direction_OneLeft(curdir, dirmode_16dirs) ||
1906 		dirtocontrolled == Direction_OneRight(curdir, dirmode_16dirs) ||
1907 		dirtocontrolled == Direction_TurnByDelta(curdir, 2, dirmode_16dirs) ||
1908 		dirtocontrolled == Direction_TurnByDelta(curdir, -2, dirmode_16dirs))
1909 	{
1910 		return getRangeIfVisible(*controlled) > 0;
1911 	}
1912 
1913 	return false;
1914 
1915 }
1916 
collideMove(int32 x,int32 y,int32 z,bool teleports,bool force,ObjId * hititem,uint8 * dirs)1917 int32 Actor::collideMove(int32 x, int32 y, int32 z, bool teleports, bool force,
1918 						 ObjId *hititem, uint8 *dirs) {
1919 	int32 result = Item::collideMove(x, y, z, teleports, force, hititem, dirs);
1920 	if (this == getControlledActor() && GAME_IS_CRUSADER) {
1921 		TargetReticleProcess::get_instance()->avatarMoved();
1922 		ItemSelectionProcess::get_instance()->avatarMoved();
1923 	}
1924 	return result;
1925 }
1926 
activeWeaponIsSmall() const1927 bool Actor::activeWeaponIsSmall() const {
1928 	const Item *wpn = getItem(_activeWeapon);
1929 	if (wpn) {
1930 		const WeaponInfo *wi = wpn->getShapeInfo()->_weaponInfo;
1931 		return wi && (wi->_small != 0);
1932 	}
1933 	return false;
1934 }
1935 
1936 
areEnemiesNear()1937 bool Actor::areEnemiesNear() {
1938 	UCList uclist(2);
1939 	LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
1940 	CurrentMap *currentmap = World::get_instance()->getCurrentMap();
1941 	currentmap->areaSearch(&uclist, script, sizeof(script), this, 0x800, false);
1942 
1943 	for (unsigned int i = 0; i < uclist.getSize(); ++i) {
1944 		Actor *npc = getActor(uclist.getuint16(i));
1945 		if (!npc) continue;
1946 		if (npc == this) continue;
1947 
1948 		if (npc->hasActorFlags(ACT_DEAD | ACT_FEIGNDEATH)) continue;
1949 		if (!npc->hasActorFlags(ACT_INCOMBAT)) continue;
1950 
1951 		// TODO: check if hostile.
1952 		// Might not be strictly necessary, though. This function is only
1953 		// used on the avatar, and any NPCs in combat mode around the avatar
1954 		// are most likely hostile... (and if they're not hostile, they're
1955 		// probably in combat mode because something hostile _is_ nearby)
1956 
1957 		return true;
1958 	}
1959 
1960 	return false;
1961 }
1962 
schedule(uint32 time)1963 uint16 Actor::schedule(uint32 time) {
1964 	if (isDead())
1965 		return 0;
1966 
1967 	uint32 ret = callUsecodeEvent_schedule(time);
1968 
1969 	return static_cast<uint16>(ret);
1970 }
1971 
1972 //static
createActor(uint32 shape,uint32 frame)1973 Actor *Actor::createActor(uint32 shape, uint32 frame) {
1974 	Actor *newactor = ItemFactory::createActor(shape, frame, 0,
1975 	                  Item::FLG_IN_NPC_LIST,
1976 	                  0, 0, 0, true);
1977 	if (!newactor)
1978 		return nullptr;
1979 	uint16 objID = newactor->getObjId();
1980 
1981 	// set stats
1982 	if (!newactor->loadMonsterStats()) {
1983 		perr << "I_createActor failed to set stats for actor (" << shape
1984 		     << ")." << Std::endl;
1985 	}
1986 
1987 	Actor *av = getMainActor();
1988 	newactor->setMapNum(av->getMapNum());
1989 	newactor->setNpcNum(objID);
1990 	newactor->setFlag(FLG_ETHEREAL);
1991 	World::get_instance()->etherealPush(objID);
1992 
1993 	return newactor;
1994 }
1995 
dumpInfo() const1996 void Actor::dumpInfo() const {
1997 	Container::dumpInfo();
1998 
1999 	pout << "hp: " << _hitPoints << ", mp: " << _mana << ", str: " << _strength
2000 	     << ", dex: " << _dexterity << ", int: " << _intelligence
2001 	     << ", ac: " << getArmourClass() << ", defense: " << ConsoleStream::hex
2002 	     << getDefenseType() << " align: " << getAlignment() << " enemy: "
2003 	     << getEnemyAlignment() << ", flags: " << _actorFlags
2004 	     << ConsoleStream::dec << Std::endl;
2005 }
2006 
addFireAnimOffsets(int32 & x,int32 & y,int32 & z)2007 void Actor::addFireAnimOffsets(int32 &x, int32 &y, int32 &z) {
2008 	assert(GAME_IS_CRUSADER);
2009 	Animation::Sequence fireanim = (isKneeling() ? Animation::kneelAndFire : Animation::attack);
2010 	uint32 actionno = AnimDat::getActionNumberForSequence(fireanim, this);
2011 	Direction dir = getDir();
2012 
2013 	const AnimAction *animaction = GameData::get_instance()->getMainShapes()->getAnim(getShape(), actionno);
2014 	if (!animaction)
2015 		return;
2016 
2017 	for (unsigned int i = 0; i < animaction->getSize(); i++) {
2018 		const AnimFrame &frame = animaction->getFrame(dir, i);
2019 		if (frame.is_cruattack()) {
2020 			x += frame.cru_attackx();
2021 			y += frame.cru_attacky();
2022 			z += frame.cru_attackz();
2023 			return;
2024 		}
2025 	}
2026 }
2027 
saveData(Common::WriteStream * ws)2028 void Actor::saveData(Common::WriteStream *ws) {
2029 	Container::saveData(ws);
2030 	ws->writeUint16LE(_strength);
2031 	ws->writeUint16LE(_dexterity);
2032 	ws->writeUint16LE(_intelligence);
2033 	ws->writeUint16LE(_hitPoints);
2034 	ws->writeUint16LE(_mana);
2035 	ws->writeUint16LE(_alignment);
2036 	ws->writeUint16LE(_enemyAlignment);
2037 	ws->writeUint16LE(_lastAnim);
2038 	ws->writeUint16LE(_animFrame);
2039 	ws->writeUint16LE(Direction_ToUsecodeDir(_direction));
2040 	ws->writeUint32LE(_fallStart);
2041 	ws->writeUint32LE(_actorFlags);
2042 	ws->writeByte(_unkByte);
2043 
2044 	if (GAME_IS_CRUSADER) {
2045 		ws->writeUint16LE(_defaultActivity[0]);
2046 		ws->writeUint16LE(_defaultActivity[1]);
2047 		ws->writeUint16LE(_defaultActivity[2]);
2048 		ws->writeUint16LE(_combatTactic);
2049 		ws->writeUint32LE(_homeX);
2050 		ws->writeUint32LE(_homeY);
2051 		ws->writeUint32LE(_homeZ);
2052 		ws->writeUint16LE(_currentActivityNo);
2053 		ws->writeUint16LE(_lastActivityNo);
2054 		ws->writeUint16LE(_activeWeapon);
2055 		ws->writeSint32LE(_lastTickWasHit);
2056 		ws->writeByte(0); // unused, keep for backward compatibility
2057 		ws->writeUint32LE(_attackMoveStartFrame);
2058 		ws->writeUint32LE(_attackMoveTimeout);
2059 		ws->writeUint16LE(_attackMoveDodgeFactor);
2060 		ws->writeByte(_attackAimFlag ? 1 : 0);
2061 	}
2062 }
2063 
loadData(Common::ReadStream * rs,uint32 version)2064 bool Actor::loadData(Common::ReadStream *rs, uint32 version) {
2065 	if (!Container::loadData(rs, version)) return false;
2066 
2067 	_strength = static_cast<int16>(rs->readUint16LE());
2068 	_dexterity = static_cast<int16>(rs->readUint16LE());
2069 	_intelligence = static_cast<int16>(rs->readUint16LE());
2070 	_hitPoints = rs->readUint16LE();
2071 	_mana = static_cast<int16>(rs->readUint16LE());
2072 	_alignment = rs->readUint16LE();
2073 	_enemyAlignment = rs->readUint16LE();
2074 	_lastAnim = static_cast<Animation::Sequence>(rs->readUint16LE());
2075 	_animFrame = rs->readUint16LE();
2076 	_direction = Direction_FromUsecodeDir(rs->readUint16LE());
2077 	_fallStart = rs->readUint32LE();
2078 	_actorFlags = rs->readUint32LE();
2079 	_unkByte = rs->readByte();
2080 
2081 	if (GAME_IS_CRUSADER) {
2082 		_defaultActivity[0] = rs->readUint16LE();
2083 		_defaultActivity[1] = rs->readUint16LE();
2084 		_defaultActivity[2] = rs->readUint16LE();
2085 		_combatTactic = rs->readUint16LE();
2086 		_homeX = rs->readUint32LE();
2087 		_homeY = rs->readUint32LE();
2088 		_homeZ = rs->readUint32LE();
2089 		_currentActivityNo = rs->readUint16LE();
2090 		_lastActivityNo = rs->readUint16LE();
2091 		_activeWeapon = rs->readUint16LE();
2092 		_lastTickWasHit = rs->readSint32LE();
2093 		rs->readByte();  // unused, keep for backward compatibility
2094 		_attackMoveStartFrame = rs->readUint32LE();
2095 		_attackMoveTimeout = rs->readUint32LE();
2096 		_attackMoveDodgeFactor = rs->readUint16LE();
2097 		_attackAimFlag = rs->readByte() != 0;
2098 	}
2099 
2100 	return true;
2101 }
2102 
2103 
I_isNPC(const uint8 * args,unsigned int)2104 uint32 Actor::I_isNPC(const uint8 *args, unsigned int /*argsize*/) {
2105 	ARG_ACTOR_FROM_PTR(actor);
2106 	if (!actor) return 0;
2107 	return 1;
2108 }
2109 
I_getMap(const uint8 * args,unsigned int)2110 uint32 Actor::I_getMap(const uint8 *args, unsigned int /*argsize*/) {
2111 	ARG_ACTOR_FROM_PTR(actor);
2112 	if (!actor) return 0;
2113 
2114 	return actor->getMapNum();
2115 }
2116 
I_teleport(const uint8 * args,unsigned int)2117 uint32 Actor::I_teleport(const uint8 *args, unsigned int /*argsize*/) {
2118 	ARG_ACTOR_FROM_PTR(actor);
2119 	ARG_UINT16(newx);
2120 	ARG_UINT16(newy);
2121 	ARG_UINT16(newz);
2122 	ARG_UINT16(newmap);
2123 	if (!actor) return 0;
2124 
2125 	if (GAME_IS_CRUSADER) {
2126 		newx *= 2;
2127 		newy *= 2;
2128 	}
2129 
2130 	actor->teleport(newmap, newx, newy, newz);
2131 	return 0;
2132 }
2133 
I_doAnim(const uint8 * args,unsigned int)2134 uint32 Actor::I_doAnim(const uint8 *args, unsigned int /*argsize*/) {
2135 	ARG_ACTOR_FROM_PTR(actor);
2136 	ARG_UINT16(anim);
2137 	ARG_UINT16(dir); // seems to be 0-8
2138 	ARG_UINT16(unk1); // this is almost always 10000 in U8.Maybe speed-related?
2139 	ARG_UINT16(unk2); // appears to be 0 or 1. Some flag?
2140 
2141 	if (!actor) return 0;
2142 
2143 	//
2144 	// HACK: In Crusader, we do translation on the animations so we want to remap
2145 	// most of them, but for direct commands from the usecode we add a bitflag for
2146 	// no remapping
2147 	//
2148 	if (GAME_IS_CRUSADER) {
2149 		anim |= Animation::crusaderAbsoluteAnimFlag;
2150 	}
2151 
2152 	return actor->doAnim(static_cast<Animation::Sequence>(anim), Direction_FromUsecodeDir(dir));
2153 }
2154 
I_getDir(const uint8 * args,unsigned int)2155 uint32 Actor::I_getDir(const uint8 *args, unsigned int /*argsize*/) {
2156 	ARG_ACTOR_FROM_PTR(actor);
2157 	if (!actor) return 0;
2158 
2159 	return Direction_ToUsecodeDir(actor->getDir());
2160 }
2161 
I_getLastAnimSet(const uint8 * args,unsigned int)2162 uint32 Actor::I_getLastAnimSet(const uint8 *args, unsigned int /*argsize*/) {
2163 	ARG_ACTOR_FROM_PTR(actor);
2164 	if (!actor) return 0;
2165 
2166 	return AnimDat::getActionNumberForSequence(actor->getLastAnim(), actor);
2167 }
2168 
I_getStr(const uint8 * args,unsigned int)2169 uint32 Actor::I_getStr(const uint8 *args, unsigned int /*argsize*/) {
2170 	ARG_ACTOR_FROM_PTR(actor);
2171 	if (!actor) return 0;
2172 
2173 	return actor->getStr();
2174 }
2175 
I_getDex(const uint8 * args,unsigned int)2176 uint32 Actor::I_getDex(const uint8 *args, unsigned int /*argsize*/) {
2177 	ARG_ACTOR_FROM_PTR(actor);
2178 	if (!actor) return 0;
2179 
2180 	return actor->getDex();
2181 }
2182 
I_getInt(const uint8 * args,unsigned int)2183 uint32 Actor::I_getInt(const uint8 *args, unsigned int /*argsize*/) {
2184 	ARG_ACTOR_FROM_PTR(actor);
2185 	if (!actor) return 0;
2186 
2187 	return actor->getInt();
2188 }
2189 
I_getHp(const uint8 * args,unsigned int)2190 uint32 Actor::I_getHp(const uint8 *args, unsigned int /*argsize*/) {
2191 	ARG_ACTOR_FROM_PTR(actor);
2192 	if (!actor) return 0;
2193 
2194 	return actor->getHP();
2195 }
2196 
I_getMaxHp(const uint8 * args,unsigned int)2197 uint32 Actor::I_getMaxHp(const uint8 *args, unsigned int /*argsize*/) {
2198 	ARG_ACTOR_FROM_PTR(actor);
2199 	if (!actor) return 0;
2200 
2201 	return actor->getMaxHP();
2202 }
2203 
I_getMana(const uint8 * args,unsigned int)2204 uint32 Actor::I_getMana(const uint8 *args, unsigned int /*argsize*/) {
2205 	ARG_ACTOR_FROM_PTR(actor);
2206 	if (!actor) return 0;
2207 
2208 	return actor->getMana();
2209 }
2210 
I_getAlignment(const uint8 * args,unsigned int)2211 uint32 Actor::I_getAlignment(const uint8 *args, unsigned int /*argsize*/) {
2212 	ARG_ACTOR_FROM_PTR(actor);
2213 	if (!actor) return 0;
2214 
2215 	return actor->getAlignment();
2216 }
2217 
I_getEnemyAlignment(const uint8 * args,unsigned int)2218 uint32 Actor::I_getEnemyAlignment(const uint8 *args, unsigned int /*argsize*/) {
2219 	ARG_ACTOR_FROM_PTR(actor);
2220 	if (!actor) return 0;
2221 
2222 	return actor->getEnemyAlignment();
2223 }
2224 
I_setStr(const uint8 * args,unsigned int)2225 uint32 Actor::I_setStr(const uint8 *args, unsigned int /*argsize*/) {
2226 	ARG_ACTOR_FROM_PTR(actor);
2227 	ARG_SINT16(str);
2228 	if (!actor) return 0;
2229 
2230 	actor->setStr(str);
2231 	return 0;
2232 }
2233 
I_setDex(const uint8 * args,unsigned int)2234 uint32 Actor::I_setDex(const uint8 *args, unsigned int /*argsize*/) {
2235 	ARG_ACTOR_FROM_PTR(actor);
2236 	ARG_SINT16(dex);
2237 	if (!actor) return 0;
2238 
2239 	actor->setDex(dex);
2240 	return 0;
2241 }
2242 
I_setInt(const uint8 * args,unsigned int)2243 uint32 Actor::I_setInt(const uint8 *args, unsigned int /*argsize*/) {
2244 	ARG_ACTOR_FROM_PTR(actor);
2245 	ARG_SINT16(int_);
2246 	if (!actor) return 0;
2247 
2248 	actor->setStr(int_);
2249 	return 0;
2250 }
2251 
I_setHp(const uint8 * args,unsigned int)2252 uint32 Actor::I_setHp(const uint8 *args, unsigned int /*argsize*/) {
2253 	ARG_ACTOR_FROM_PTR(actor);
2254 	ARG_UINT16(hp);
2255 	if (!actor) return 0;
2256 
2257 	actor->setHP(hp);
2258 	return 0;
2259 }
2260 
I_addHp(const uint8 * args,unsigned int)2261 uint32 Actor::I_addHp(const uint8 *args, unsigned int /*argsize*/) {
2262 	ARG_ACTOR_FROM_PTR(actor);
2263 	ARG_UINT16(hp);
2264 
2265 	if (actor) {
2266 		int max = actor->getMaxHP();
2267 		int cur = actor->getHP();
2268 		if (cur < max) {
2269 			actor->setHP(MIN(max, cur + hp));
2270 			return 1;
2271 		}
2272 	}
2273 	return 0;
2274 }
2275 
I_setMana(const uint8 * args,unsigned int)2276 uint32 Actor::I_setMana(const uint8 *args, unsigned int /*argsize*/) {
2277 	ARG_ACTOR_FROM_PTR(actor);
2278 	ARG_SINT16(mp);
2279 	if (!actor) return 0;
2280 
2281 	actor->setMana(mp);
2282 	return 0;
2283 }
2284 
I_setAlignment(const uint8 * args,unsigned int)2285 uint32 Actor::I_setAlignment(const uint8 *args, unsigned int /*argsize*/) {
2286 	ARG_ACTOR_FROM_PTR(actor);
2287 	ARG_UINT16(a);
2288 	if (!actor) return 0;
2289 
2290 	actor->setAlignment(a);
2291 	return 0;
2292 }
2293 
I_setEnemyAlignment(const uint8 * args,unsigned int)2294 uint32 Actor::I_setEnemyAlignment(const uint8 *args, unsigned int /*argsize*/) {
2295 	ARG_ACTOR_FROM_PTR(actor);
2296 	ARG_UINT16(a);
2297 	if (!actor) return 0;
2298 
2299 	actor->setEnemyAlignment(a);
2300 	return 0;
2301 }
2302 
I_isInCombat(const uint8 * args,unsigned int)2303 uint32 Actor::I_isInCombat(const uint8 *args, unsigned int /*argsize*/) {
2304 	ARG_ACTOR_FROM_PTR(actor);
2305 	if (!actor) return 0;
2306 
2307 	if (actor->isInCombat())
2308 		return 1;
2309 	else
2310 		return 0;
2311 }
2312 
I_setInCombat(const uint8 * args,unsigned int)2313 uint32 Actor::I_setInCombat(const uint8 *args, unsigned int /*argsize*/) {
2314 	ARG_ACTOR_FROM_PTR(actor);
2315 	if (!actor) return 0;
2316 
2317 	assert(GAME_IS_U8);
2318 	actor->setInCombatU8();
2319 
2320 	return 0;
2321 }
2322 
I_clrInCombat(const uint8 * args,unsigned int)2323 uint32 Actor::I_clrInCombat(const uint8 *args, unsigned int /*argsize*/) {
2324 	ARG_ACTOR_FROM_PTR(actor);
2325 	if (!actor) return 0;
2326 
2327 	actor->clearInCombat();
2328 
2329 	return 0;
2330 }
2331 
I_setTarget(const uint8 * args,unsigned int)2332 uint32 Actor::I_setTarget(const uint8 *args, unsigned int /*argsize*/) {
2333 	ARG_ACTOR_FROM_PTR(actor);
2334 	ARG_UINT16(target);
2335 	if (!actor) return 0;
2336 
2337 	if (GAME_IS_U8) {
2338 		CombatProcess *cp = actor->getCombatProcess();
2339 		if (!cp) {
2340 			actor->setInCombatU8();
2341 			cp = actor->getCombatProcess();
2342 		}
2343 		if (!cp) {
2344 			warning("Actor::I_setTarget: failed to enter combat mode");
2345 			return 0;
2346 		}
2347 
2348 		cp->setTarget(target);
2349 	} else {
2350 		if (actor->isDead() || actor->getObjId() == 1)
2351 			return 0;
2352 
2353 		actor->setActivityCru(5);
2354 		AttackProcess *ap = actor->getAttackProcess();
2355 		if (!ap) {
2356 			warning("Actor::I_setTarget: failed to enter attack mode");
2357 			return 0;
2358 		}
2359 		ap->setTarget(target);
2360 	}
2361 
2362 	return 0;
2363 }
2364 
I_getTarget(const uint8 * args,unsigned int)2365 uint32 Actor::I_getTarget(const uint8 *args, unsigned int /*argsize*/) {
2366 	ARG_ACTOR_FROM_PTR(actor);
2367 	if (!actor) return 0;
2368 
2369 	CombatProcess *cp = actor->getCombatProcess();
2370 
2371 	if (!cp) return 0;
2372 
2373 	return static_cast<uint32>(cp->getTarget());
2374 }
2375 
2376 
I_isEnemy(const uint8 * args,unsigned int)2377 uint32 Actor::I_isEnemy(const uint8 *args, unsigned int /*argsize*/) {
2378 	ARG_ACTOR_FROM_PTR(actor);
2379 	ARG_ACTOR_FROM_ID(other);
2380 	if (!actor) return 0;
2381 	if (!other) return 0;
2382 
2383 	if (actor->getEnemyAlignment() & other->getAlignment())
2384 		return 1;
2385 	else
2386 		return 0;
2387 }
2388 
I_isDead(const uint8 * args,unsigned int)2389 uint32 Actor::I_isDead(const uint8 *args, unsigned int /*argsize*/) {
2390 	ARG_ACTOR_FROM_PTR(actor);
2391 	if (!actor) return 1;
2392 
2393 	if (actor->isDead())
2394 		return 1;
2395 	else
2396 		return 0;
2397 }
2398 
I_setDead(const uint8 * args,unsigned int)2399 uint32 Actor::I_setDead(const uint8 *args, unsigned int /*argsize*/) {
2400 	ARG_ACTOR_FROM_PTR(actor);
2401 	if (!actor) return 0;
2402 
2403 	actor->setActorFlag(ACT_DEAD);
2404 	if (GAME_IS_CRUSADER) {
2405 		actor->setFlag(FLG_BROKEN);
2406 		World::get_instance()->getCurrentMap()->removeTargetItem(actor);
2407 	}
2408 
2409 	return 0;
2410 }
2411 
I_clrDead(const uint8 * args,unsigned int)2412 uint32 Actor::I_clrDead(const uint8 *args, unsigned int /*argsize*/) {
2413 	ARG_ACTOR_FROM_PTR(actor);
2414 	if (!actor) return 0;
2415 
2416 	actor->clearActorFlag(ACT_DEAD);
2417 	if (GAME_IS_CRUSADER) {
2418 		actor->clearFlag(FLG_BROKEN);
2419 		World::get_instance()->getCurrentMap()->addTargetItem(actor);
2420 	}
2421 
2422 	return 0;
2423 }
2424 
I_isImmortal(const uint8 * args,unsigned int)2425 uint32 Actor::I_isImmortal(const uint8 *args, unsigned int /*argsize*/) {
2426 	ARG_ACTOR_FROM_PTR(actor);
2427 	if (!actor) return 0;
2428 
2429 	if (actor->hasActorFlags(ACT_IMMORTAL))
2430 		return 1;
2431 	else
2432 		return 0;
2433 }
2434 
I_setImmortal(const uint8 * args,unsigned int)2435 uint32 Actor::I_setImmortal(const uint8 *args, unsigned int /*argsize*/) {
2436 	ARG_ACTOR_FROM_PTR(actor);
2437 	if (!actor) return 0;
2438 
2439 	actor->setActorFlag(ACT_IMMORTAL);
2440 	actor->clearActorFlag(ACT_INVINCIBLE);
2441 
2442 	return 0;
2443 }
2444 
I_clrImmortal(const uint8 * args,unsigned int)2445 uint32 Actor::I_clrImmortal(const uint8 *args, unsigned int /*argsize*/) {
2446 	ARG_ACTOR_FROM_PTR(actor);
2447 	if (!actor) return 0;
2448 
2449 	actor->clearActorFlag(ACT_IMMORTAL);
2450 
2451 	return 0;
2452 }
2453 
I_isWithstandDeath(const uint8 * args,unsigned int)2454 uint32 Actor::I_isWithstandDeath(const uint8 *args, unsigned int /*argsize*/) {
2455 	ARG_ACTOR_FROM_PTR(actor);
2456 	if (!actor) return 0;
2457 
2458 	if (actor->hasActorFlags(ACT_WITHSTANDDEATH))
2459 		return 1;
2460 	else
2461 		return 0;
2462 }
2463 
I_setWithstandDeath(const uint8 * args,unsigned int)2464 uint32 Actor::I_setWithstandDeath(const uint8 *args, unsigned int /*argsize*/) {
2465 	ARG_ACTOR_FROM_PTR(actor);
2466 	if (!actor) return 0;
2467 
2468 	actor->setActorFlag(ACT_WITHSTANDDEATH);
2469 
2470 	return 0;
2471 }
2472 
I_clrWithstandDeath(const uint8 * args,unsigned int)2473 uint32 Actor::I_clrWithstandDeath(const uint8 *args, unsigned int /*argsize*/) {
2474 	ARG_ACTOR_FROM_PTR(actor);
2475 	if (!actor) return 0;
2476 
2477 	actor->clearActorFlag(ACT_WITHSTANDDEATH);
2478 
2479 	return 0;
2480 }
2481 
I_isFeignDeath(const uint8 * args,unsigned int)2482 uint32 Actor::I_isFeignDeath(const uint8 *args, unsigned int /*argsize*/) {
2483 	ARG_ACTOR_FROM_PTR(actor);
2484 	if (!actor) return 0;
2485 
2486 	if (actor->hasActorFlags(ACT_FEIGNDEATH))
2487 		return 1;
2488 	else
2489 		return 0;
2490 }
2491 
I_setFeignDeath(const uint8 * args,unsigned int)2492 uint32 Actor::I_setFeignDeath(const uint8 *args, unsigned int /*argsize*/) {
2493 	ARG_ACTOR_FROM_PTR(actor);
2494 	if (!actor) return 0;
2495 
2496 	if (actor->hasActorFlags(ACT_FEIGNDEATH))
2497 		return 0;
2498 
2499 	actor->setActorFlag(ACT_FEIGNDEATH);
2500 
2501 	ProcId animfallpid = actor->doAnim(Animation::die, dir_current);
2502 	Process *animfallproc = Kernel::get_instance()->getProcess(animfallpid);
2503 	assert(animfallproc);
2504 
2505 	ProcId animstandpid = actor->doAnim(Animation::standUp, dir_current);
2506 	Process *animstandproc = Kernel::get_instance()->getProcess(animstandpid);
2507 	assert(animstandproc);
2508 
2509 	Process *delayproc = new DelayProcess(900); // 30 seconds
2510 	Kernel::get_instance()->addProcess(delayproc);
2511 
2512 	Process *clearproc = new ClearFeignDeathProcess(actor);
2513 	Kernel::get_instance()->addProcess(clearproc);
2514 
2515 	// do them in order (fall, stand, wait, clear)
2516 
2517 	clearproc->waitFor(delayproc);
2518 	delayproc->waitFor(animstandproc);
2519 	animstandproc->waitFor(animfallproc);
2520 
2521 	return 0;
2522 }
2523 
I_clrFeignDeath(const uint8 * args,unsigned int)2524 uint32 Actor::I_clrFeignDeath(const uint8 *args, unsigned int /*argsize*/) {
2525 	ARG_ACTOR_FROM_PTR(actor);
2526 	if (!actor) return 0;
2527 
2528 	actor->clearActorFlag(ACT_FEIGNDEATH);
2529 
2530 	return 0;
2531 }
2532 
I_pathfindToItem(const uint8 * args,unsigned int)2533 uint32 Actor::I_pathfindToItem(const uint8 *args, unsigned int /*argsize*/) {
2534 	ARG_ACTOR_FROM_PTR(actor);
2535 	ARG_OBJID(id2);
2536 	Item *item = getItem(id2);
2537 	if (!actor) return 0;
2538 	if (!item) return 0;
2539 
2540 	return Kernel::get_instance()->addProcess(
2541 	           new PathfinderProcess(actor, id2));
2542 }
2543 
I_pathfindToPoint(const uint8 * args,unsigned int)2544 uint32 Actor::I_pathfindToPoint(const uint8 *args, unsigned int /*argsize*/) {
2545 	ARG_ACTOR_FROM_PTR(actor);
2546 	ARG_UINT16(x);
2547 	ARG_UINT16(y);
2548 	ARG_UINT8(z);
2549 	ARG_NULL16(); // unknown. Only one instance of this in U8, values are 5,1.
2550 	if (!actor) return 0;
2551 
2552 	if (GAME_IS_CRUSADER) {
2553 		x *= 2;
2554 		y *= 2;
2555 	}
2556 
2557 	return Kernel::get_instance()->addProcess(
2558 	           new PathfinderProcess(actor, x, y, z));
2559 }
2560 
I_areEnemiesNear(const uint8 * args,unsigned int)2561 uint32 Actor::I_areEnemiesNear(const uint8 *args, unsigned int /*argsize*/) {
2562 	ARG_ACTOR_FROM_PTR(actor);
2563 	if (!actor) return 0;
2564 
2565 	if (actor->areEnemiesNear())
2566 		return 1;
2567 	else
2568 		return 0;
2569 }
2570 
I_isBusy(const uint8 * args,unsigned int)2571 uint32 Actor::I_isBusy(const uint8 *args, unsigned int /*argsize*/) {
2572 	ARG_ACTOR_FROM_PTR(actor);
2573 
2574 	if (actor->isBusy())
2575 		return 1;
2576 	else
2577 		return 0;
2578 }
2579 
I_createActor(const uint8 * args,unsigned int)2580 uint32 Actor::I_createActor(const uint8 *args, unsigned int /*argsize*/) {
2581 	ARG_UC_PTR(ptr);
2582 	ARG_UINT16(shape);
2583 	ARG_UINT16(frame);
2584 
2585 	//!! do we need to flag actor as temporary?
2586 
2587 	Actor *newactor = createActor(shape, frame);
2588 	if (!newactor) {
2589 		perr << "I_createActor failed to create actor (" << shape
2590 		     << ")." << Std::endl;
2591 		return 0;
2592 	}
2593 	uint16 objID = newactor->getObjId();
2594 
2595 	uint8 buf[2];
2596 	buf[0] = static_cast<uint8>(objID);
2597 	buf[1] = static_cast<uint8>(objID >> 8);
2598 	UCMachine::get_instance()->assignPointer(ptr, buf, 2);
2599 
2600 #if 0
2601 	perr << "I_createActor: created actor #" << objID << " with shape " << shape << Std::endl;
2602 #endif
2603 
2604 	return objID;
2605 }
2606 
I_createActorCru(const uint8 * args,unsigned int)2607 uint32 Actor::I_createActorCru(const uint8 *args, unsigned int /*argsize*/) {
2608 	ARG_ITEM_FROM_PTR(item);
2609 	ARG_ITEM_FROM_ID(other);
2610 
2611 	if (!item || !other)
2612 		return 0;
2613 
2614 	const int gameDifficulty = World::get_instance()->getGameDifficulty();
2615 	int npcDifficulty = (item->getMapNum() & 3) + 1;
2616 
2617 	if (gameDifficulty < npcDifficulty)
2618 		return 0;
2619 
2620 	uint16 dtableidx = other->getNpcNum();
2621 
2622 	const NPCDat *npcData = GameData::get_instance()->getNPCData(dtableidx);
2623 	if (!npcData)
2624 		return 0;
2625 
2626 	int dir = item->getNpcNum() & 0xf;
2627 	int frame = (dir * 2 + 4) & 0xf;
2628 	uint16 shape = npcData->getShapeNo();
2629 
2630 	enum extflags ext = static_cast<extflags>(0);
2631 	if (shape == 0x597 || shape == 0x3ac)
2632 		ext = EXT_FEMALE;
2633 
2634 	Actor *newactor = ItemFactory::createActor(shape, frame, 0,
2635 	                  Item::FLG_IN_NPC_LIST | Item::FLG_DISPOSABLE,
2636 	                  0, 0, ext, true);
2637 	if (!newactor) {
2638 		perr << "I_createActorCru failed to create actor ("
2639 			 << npcData->getShapeNo() << ")." << Std::endl;
2640 		return 0;
2641 	}
2642 
2643 	// Most of these will be overwritten below, but this is cleaner..
2644 	bool loaded = newactor->loadMonsterStats();
2645 	if (!loaded) {
2646 		perr << "I_createActorCru failed to load monster stats ("
2647 			 << npcData->getShapeNo() << ")." << Std::endl;
2648 		return 0;
2649 	}
2650 
2651 	newactor->setDir(Direction_FromUsecodeDir(dir));
2652 
2653 	int32 x, y, z;
2654 	item->getLocation(x, y, z);
2655 	newactor->move(x, y, z);
2656 
2657 	newactor->setDefaultActivity(0, other->getQuality() >> 8);
2658 	newactor->setDefaultActivity(1, item->getQuality() >> 8);
2659 	newactor->setDefaultActivity(2, other->getMapNum());
2660 
2661 	newactor->setUnkByte(item->getQuality() & 0xff);
2662 
2663 	bool wpnflag = (item->getMapNum() & 4);
2664 	uint16 wpntype = npcData->getWpnType();
2665 	uint16 wpntype2 = npcData->getWpnType2();
2666 
2667 	if (World::get_instance()->getGameDifficulty() == 4) {
2668 		wpntype = NPCDat::randomlyGetStrongerWeaponTypes(shape);
2669 		wpntype2 = wpntype;
2670 	}
2671 
2672 	if ((!wpntype || !wpnflag) && wpntype2) {
2673 		wpntype = wpntype2;
2674 	}
2675 
2676 	// TODO: Nasty hard coded list.. use the ini file for this.
2677 	static const int WPNSHAPES[] = {0, 0x032E, 0x032F, 0x0330, 0x038C, 0x0332, 0x0333,
2678 		0x0334, 0x038E, 0x0388, 0x038A, 0x038D, 0x038B, 0x0386,
2679 		// Regret-specific weapon types
2680 		0x05F6, 0x05F5, 0x0198};
2681 	if (wpntype && wpntype < ARRAYSIZE(WPNSHAPES)) {
2682 		// wpntype is an offset into wpn table
2683 		Item *weapon = ItemFactory::createItem(WPNSHAPES[wpntype], 0, 0, 0, 0, newactor->getMapNum(), 0, true);
2684 		if (weapon) {
2685 			weapon->moveToContainer(newactor, false);
2686 			newactor->_activeWeapon = weapon->getObjId();
2687 		}
2688 	}
2689 
2690 	newactor->setCombatTactic(0);
2691 	newactor->setHomePosition(x, y, z);
2692 
2693 	/*
2694 	 TODO: once I know what this field is.. seems to never be used in game?
2695 	 newactor->setField0x12(item->getNpcNum() >> 4);
2696 	 */
2697 
2698 	return newactor->getObjId();
2699 }
2700 
I_setUnkByte(const uint8 * args,unsigned int)2701 uint32 Actor::I_setUnkByte(const uint8 *args, unsigned int /*argsize*/) {
2702 	ARG_ACTOR_FROM_PTR(actor);
2703 	ARG_UINT16(value);
2704 	if (actor)
2705 		actor->setUnkByte(static_cast<uint8>(value & 0xff));
2706 	return 0;
2707 }
2708 
I_getUnkByte(const uint8 * args,unsigned int)2709 uint32 Actor::I_getUnkByte(const uint8 *args, unsigned int /*argsize*/) {
2710 	ARG_ACTOR_FROM_PTR(actor);
2711 	if (!actor) return 0;
2712 
2713 	return actor->getUnkByte();
2714 }
2715 
I_setActivity(const uint8 * args,unsigned int)2716 uint32 Actor::I_setActivity(const uint8 *args, unsigned int /*argsize*/) {
2717 	ARG_ACTOR_FROM_PTR(actor);
2718 	ARG_UINT16(activity);
2719 	if (!actor) return 0;
2720 
2721 	return actor->setActivity(activity);
2722 }
2723 
I_setAirWalkEnabled(const uint8 * args,unsigned int)2724 uint32 Actor::I_setAirWalkEnabled(const uint8 *args, unsigned int /*argsize*/) {
2725 	ARG_ACTOR_FROM_PTR(actor);
2726 	ARG_UINT16(enabled);
2727 	if (!actor) return 0;
2728 
2729 	if (enabled)
2730 		actor->setActorFlag(ACT_AIRWALK);
2731 	else
2732 		actor->clearActorFlag(ACT_AIRWALK);
2733 
2734 	return 0;
2735 }
2736 
2737 
I_getAirWalkEnabled(const uint8 * args,unsigned int)2738 uint32 Actor::I_getAirWalkEnabled(const uint8 *args, unsigned int /*argsize*/) {
2739 	ARG_ACTOR_FROM_PTR(actor);
2740 	if (!actor) return 0;
2741 
2742 	if (actor->hasActorFlags(ACT_AIRWALK))
2743 		return 1;
2744 	else
2745 		return 0;
2746 }
2747 
I_schedule(const uint8 * args,unsigned int)2748 uint32 Actor::I_schedule(const uint8 *args, unsigned int /*argsize*/) {
2749 	ARG_ACTOR_FROM_PTR(actor);
2750 	ARG_UINT32(time);
2751 	if (!actor) return 0;
2752 
2753 	return actor->schedule(time);
2754 }
2755 
2756 
I_getEquip(const uint8 * args,unsigned int)2757 uint32 Actor::I_getEquip(const uint8 *args, unsigned int /*argsize*/) {
2758 	ARG_ACTOR_FROM_PTR(actor);
2759 	ARG_UINT16(type);
2760 	if (!actor) return 0;
2761 
2762 	return actor->getEquip(type + 1);
2763 }
2764 
I_setEquip(const uint8 * args,unsigned int)2765 uint32 Actor::I_setEquip(const uint8 *args, unsigned int /*argsize*/) {
2766 	ARG_ACTOR_FROM_PTR(actor);
2767 	ARG_UINT16(type);
2768 	ARG_ITEM_FROM_ID(item);
2769 	if (!actor) return 0;
2770 	if (!item) return 0;
2771 
2772 	if (!actor->setEquip(item, false))
2773 		return 0;
2774 
2775 	// check it was added to the right slot
2776 	assert(item->getZ() == type + 1 || (item->getShape() == BACKPACK_SHAPE && type == 6));
2777 
2778 	return 1;
2779 }
2780 
I_setDefaultActivity0(const uint8 * args,unsigned int)2781 uint32 Actor::I_setDefaultActivity0(const uint8 *args, unsigned int /*argsize*/) {
2782 	ARG_ACTOR_FROM_PTR(actor);
2783 	ARG_UINT16(activity);
2784 	if (!actor) return 0;
2785 
2786 	actor->setDefaultActivity(0, activity);
2787 	return 0;
2788 }
2789 
I_setDefaultActivity1(const uint8 * args,unsigned int)2790 uint32 Actor::I_setDefaultActivity1(const uint8 *args, unsigned int /*argsize*/) {
2791 	ARG_ACTOR_FROM_PTR(actor);
2792 	ARG_UINT16(activity);
2793 	if (!actor) return 0;
2794 
2795 	actor->setDefaultActivity(1, activity);
2796 	return 0;
2797 }
2798 
I_setDefaultActivity2(const uint8 * args,unsigned int)2799 uint32 Actor::I_setDefaultActivity2(const uint8 *args, unsigned int /*argsize*/) {
2800 	ARG_ACTOR_FROM_PTR(actor);
2801 	ARG_UINT16(activity);
2802 	if (!actor) return 0;
2803 
2804 	actor->setDefaultActivity(2, activity);
2805 	return 0;
2806 }
2807 
I_getDefaultActivity0(const uint8 * args,unsigned int)2808 uint32 Actor::I_getDefaultActivity0(const uint8 *args, unsigned int /*argsize*/) {
2809 	ARG_ACTOR_FROM_PTR(actor);
2810 	if (!actor) return 0;
2811 
2812 	return actor->getDefaultActivity(0);
2813 }
2814 
I_getDefaultActivity1(const uint8 * args,unsigned int)2815 uint32 Actor::I_getDefaultActivity1(const uint8 *args, unsigned int /*argsize*/) {
2816 	ARG_ACTOR_FROM_PTR(actor);
2817 	if (!actor) return 0;
2818 
2819 	return actor->getDefaultActivity(1);
2820 }
2821 
I_getDefaultActivity2(const uint8 * args,unsigned int)2822 uint32 Actor::I_getDefaultActivity2(const uint8 *args, unsigned int /*argsize*/) {
2823 	ARG_ACTOR_FROM_PTR(actor);
2824 	if (!actor) return 0;
2825 
2826 	return actor->getDefaultActivity(2);
2827 }
2828 
I_setCombatTactic(const uint8 * args,unsigned int)2829 uint32 Actor::I_setCombatTactic(const uint8 *args, unsigned int /*argsize*/) {
2830 	ARG_ACTOR_FROM_PTR(actor);
2831 	if (!actor) return 0;
2832 	ARG_UINT16(tactic);
2833 
2834 	actor->setCombatTactic(tactic);
2835 	return 0;
2836 }
2837 
I_getCurrentActivityNo(const uint8 * args,unsigned int)2838 uint32 Actor::I_getCurrentActivityNo(const uint8 *args, unsigned int /*argsize*/) {
2839 	ARG_ACTOR_FROM_PTR(actor);
2840 	if (!actor) return 0;
2841 
2842 	return actor->getCurrentActivityNo();
2843 }
2844 
I_getLastActivityNo(const uint8 * args,unsigned int)2845 uint32 Actor::I_getLastActivityNo(const uint8 *args, unsigned int /*argsize*/) {
2846 	ARG_ACTOR_FROM_PTR(actor);
2847 	if (!actor) return 0;
2848 
2849 	return actor->getLastActivityNo();
2850 }
2851 
I_turnToward(const uint8 * args,unsigned int)2852 uint32 Actor::I_turnToward(const uint8 *args, unsigned int /*argsize*/) {
2853 	ARG_ACTOR_FROM_PTR(actor);
2854 	if (!actor) return 0;
2855 
2856 	ARG_UINT16(dir);
2857 	ARG_UINT16(dir16);
2858 
2859 	Direction newdir = Direction_FromUsecodeDir(dir);
2860 	Direction curdir = actor->getDir();
2861 	Direction oneleft = Direction_OneLeft(curdir, dirmode_16dirs);
2862 	Direction oneright = Direction_OneRight(curdir, dirmode_16dirs);
2863 
2864 	if (curdir == newdir ||
2865 		(!dir16 && (newdir == oneleft || newdir == oneright)))
2866 		return 0;
2867 
2868 	return actor->turnTowardDir(newdir);
2869 }
2870 
I_isKneeling(const uint8 * args,unsigned int)2871 uint32 Actor::I_isKneeling(const uint8 *args, unsigned int /*argsize*/) {
2872 	ARG_ACTOR_FROM_PTR(actor);
2873 	if (!actor) return 0;
2874 
2875 	return actor->isKneeling() ? 1 : 0;
2876 }
2877 
I_isFalling(const uint8 * args,unsigned int)2878 uint32 Actor::I_isFalling(const uint8 *args, unsigned int /*argsize*/) {
2879 	ARG_ACTOR_FROM_PTR(actor);
2880 	if (!actor) return 0;
2881 
2882 	return actor->isFalling() ? 1 : 0;
2883 }
2884 
2885 } // End of namespace Ultima8
2886 } // End of namespace Ultima
2887