[Scummvm-git-logs] scummvm master -> 5b7d73240740a48b1d6441a8c54f738236a11c02

mduggan mgithub at guarana.org
Wed Jul 8 08:03:34 UTC 2020


This automated email contains information about 8 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
656c57f4ac ULTIMA8: Put in a small hack for crusader elevators
2751b79c35 ULTIMA8: Add functions to pause/resume palette cycle
a34fb53da6 ULTIMA8: Disable some unneeded debug messages
2a1138407f ULTIMA8: Halve frame repeat on crusader to make it feel better
630c63ae09 ULTIMA8: Add use item hotkeys for crusader
3ecc3ae046 ULTIMA8: Add red crosshairs in Crusader
9704171836 ULTIMA8: Implement Crusader GuardProcess (WIP)
5b7d732407 ULTIMA8: Support a few more crusader intrinsics


Commit: 656c57f4ac4e0d62dd7998bdb544a4b3cf396c80
    https://github.com/scummvm/scummvm/commit/656c57f4ac4e0d62dd7998bdb544a4b3cf396c80
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-08T17:03:02+09:00

Commit Message:
ULTIMA8: Put in a small hack for crusader elevators

Changed paths:
    engines/ultima/ultima8/world/actors/animation_tracker.cpp


diff --git a/engines/ultima/ultima8/world/actors/animation_tracker.cpp b/engines/ultima/ultima8/world/actors/animation_tracker.cpp
index 58be2c4579..d5982078e5 100644
--- a/engines/ultima/ultima8/world/actors/animation_tracker.cpp
+++ b/engines/ultima/ultima8/world/actors/animation_tracker.cpp
@@ -343,6 +343,14 @@ bool AnimationTracker::step() {
 		//       It shouldn't be necessary in that case, and may provide a
 		//       worthwhile speed-up.
 		if ((f._flags & AnimFrame::AFF_ONGROUND) && zd > 8) {
+			if (GAME_IS_CRUSADER && !targetok && support) {
+				// Possibly trying to step onto an elevator platform which stops at a z slightly
+				// above the floor.  Re-scan with a small adjustment.
+				// This is a bit of a temporary hack to make navigation possible.. it "hurls"
+				// the avatar sometimes, so it needs fixing properly.
+				tz += 2;
+			}
+
 			targetok = cm->scanForValidPosition(tx, ty, tz, a, _dir,
 			                                    true, tx, ty, tz);
 


Commit: 2751b79c3579bbb6277aece18a1eedef7aa2a3b8
    https://github.com/scummvm/scummvm/commit/2751b79c3579bbb6277aece18a1eedef7aa2a3b8
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-08T17:03:02+09:00

Commit Message:
ULTIMA8: Add functions to pause/resume palette cycle

Changed paths:
    engines/ultima/ultima8/graphics/cycle_process.h


diff --git a/engines/ultima/ultima8/graphics/cycle_process.h b/engines/ultima/ultima8/graphics/cycle_process.h
index 64e7a05137..7f847a5804 100644
--- a/engines/ultima/ultima8/graphics/cycle_process.h
+++ b/engines/ultima/ultima8/graphics/cycle_process.h
@@ -46,6 +46,14 @@ public:
 
 	static CycleProcess *get_instance();
 
+	void pauseCycle() {
+		_running = 0;
+	}
+
+	void resumeCycle() {
+		_running = 1;
+	}
+
 	bool loadData(Common::ReadStream *rs, uint32 version);
 	void saveData(Common::WriteStream *ws) override;
 };


Commit: a34fb53da671bf3139ff8f804d738035c9792921
    https://github.com/scummvm/scummvm/commit/a34fb53da671bf3139ff8f804d738035c9792921
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-08T17:03:02+09:00

Commit Message:
ULTIMA8: Disable some unneeded debug messages

Changed paths:
    engines/ultima/ultima8/world/item.cpp
    engines/ultima/ultima8/world/map.cpp


diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index 051dfb5300..c9d29dc17c 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -2747,7 +2747,7 @@ uint32 Item::I_push(const uint8 *args, unsigned int /*argsize*/) {
 	if (!item)
 		return 0;
 
-	#if 1
+	#if 0
 		perr << "Pushing item to ethereal void: " << item->getShape() << "," << item->getFrame() << Std::endl;
 	#endif
 
diff --git a/engines/ultima/ultima8/world/map.cpp b/engines/ultima/ultima8/world/map.cpp
index deeb884224..e20651287f 100644
--- a/engines/ultima/ultima8/world/map.cpp
+++ b/engines/ultima/ultima8/world/map.cpp
@@ -263,10 +263,6 @@ void Map::loadFixedFormatObjects(Std::list<Item *> &itemlist,
 			if (info->_family > 10) {
 				//warning("Created fixed item unknown family %d, shape (%d, %d) at (%d, %d, %d)", info->_family, shape, frame, x, y, z);
 			}
-			if (shape == 0x90D) {
-				warning("Created MISS1EGG item unknown family %d, shape (%d, %d) at (%d, %d, %d) q:%d", info->_family, shape, frame, x, y, z, quality);
-
-			}
 		}
 		item->setLocation(x, y, z);
 


Commit: 2a1138407f41bb8c42ac6189e54b2ca334ec4c60
    https://github.com/scummvm/scummvm/commit/2a1138407f41bb8c42ac6189e54b2ca334ec4c60
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-08T17:03:02+09:00

Commit Message:
ULTIMA8: Halve frame repeat on crusader to make it feel better

Changed paths:
    engines/ultima/ultima8/graphics/anim_dat.cpp


diff --git a/engines/ultima/ultima8/graphics/anim_dat.cpp b/engines/ultima/ultima8/graphics/anim_dat.cpp
index 2c97bda6df..2e780647a1 100644
--- a/engines/ultima/ultima8/graphics/anim_dat.cpp
+++ b/engines/ultima/ultima8/graphics/anim_dat.cpp
@@ -117,8 +117,14 @@ void AnimDat::load(Common::SeekableReadStream *rs) {
 	_anims.resize(2048);
 
 	unsigned int actioncount = 64;
-	if (GAME_IS_CRUSADER)
+	unsigned int frame_repeat_factor = 1;
+
+	if (GAME_IS_CRUSADER) {
 		actioncount = 256;
+		// TODO: this is based on making the game "feel" right, not disassembly.
+		// Should confirm if this is the right way to do it.
+		frame_repeat_factor = 2;
+	}
 
 	for (unsigned int shape = 0; shape < _anims.size(); shape++) {
 		rs->seek(4 * shape);
@@ -152,7 +158,7 @@ void AnimDat::load(Common::SeekableReadStream *rs) {
 			uint32 actionsize = rs->readByte();
 			a->_actions[action]->_size = actionsize;
 			a->_actions[action]->_flags = rs->readByte();
-			a->_actions[action]->_frameRepeat = rs->readByte();
+			a->_actions[action]->_frameRepeat = rs->readByte() / frame_repeat_factor;
 			a->_actions[action]->_flags |= rs->readByte() << 8;
 
 			unsigned int dirCount = 8;


Commit: 630c63ae0910f7e41299ef2f2b685b9035638305
    https://github.com/scummvm/scummvm/commit/630c63ae0910f7e41299ef2f2b685b9035638305
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-08T17:03:02+09:00

Commit Message:
ULTIMA8: Add use item hotkeys for crusader

Changed paths:
    engines/ultima/ultima8/meta_engine.cpp
    engines/ultima/ultima8/meta_engine.h
    engines/ultima/ultima8/misc/debugger.cpp
    engines/ultima/ultima8/misc/debugger.h
    engines/ultima/ultima8/world/actors/main_actor.cpp
    engines/ultima/ultima8/world/actors/main_actor.h


diff --git a/engines/ultima/ultima8/meta_engine.cpp b/engines/ultima/ultima8/meta_engine.cpp
index 9b13ccd01c..86bc186388 100644
--- a/engines/ultima/ultima8/meta_engine.cpp
+++ b/engines/ultima/ultima8/meta_engine.cpp
@@ -51,6 +51,9 @@ static const KeybindingRecord KEYS[] = {
 	{ ACTION_RECALL, "RECALL", "Use Recall", "MainActor::useRecall", nullptr, "r", nullptr },
 	{ ACTION_INVENTORY, "INVENTORY", "Inventory", "MainActor::useInventory", nullptr, "z", "JOY_LEFT_SHOULDER" },
 	{ ACTION_NEXT_WEAPON, "NEXT_WEAPON", "Next Crusader Weapon", "MainActor::nextWeapon", nullptr, "w", nullptr },
+	{ ACTION_USE_INVENTORY, "USE_INVENTORY", "Use Cru. Inventroy Item", "MainActor::useInventoryItem", nullptr, "u", nullptr },
+	{ ACTION_SELECT_ITEMS, "SELECT_ITEM", "Selete Cru. Item", "MainActor::startSelection", nullptr, "s", nullptr },
+	{ ACTION_USE_MEDIKIT, "USE_MEDIKIT", "Use Medical Kit", "MainActor::useMedikit", nullptr, "M", nullptr },
 	{ ACTION_MENU, "MENU", "Game Menu", "MenuGump::showMenu", nullptr, "ESCAPE", "JOY_Y" },
 	{ ACTION_CLOSE_GUMPS, "CLOSE_GUMPS", "Close Gumps", "GUIApp::closeItemGumps", nullptr, "BACKSPACE", nullptr },
 	{ ACTION_HIGHLIGHT_ITEMS, "HIGHLIGHT_ITEMS", "Show Highlight Items", "GameMapGump::toggleHighlightItems",
diff --git a/engines/ultima/ultima8/meta_engine.h b/engines/ultima/ultima8/meta_engine.h
index ca00fac08c..b54364ec65 100644
--- a/engines/ultima/ultima8/meta_engine.h
+++ b/engines/ultima/ultima8/meta_engine.h
@@ -31,6 +31,7 @@ namespace Ultima8 {
 enum KeybindingAction {
 	ACTION_QUICKSAVE, ACTION_SAVE, ACTION_LOAD, ACTION_BEDROLL, ACTION_COMBAT, ACTION_BACKPACK,
 	ACTION_KEYRING, ACTION_MINIMAP, ACTION_RECALL, ACTION_INVENTORY, ACTION_NEXT_WEAPON,
+	ACTION_USE_INVENTORY, ACTION_USE_MEDIKIT, ACTION_SELECT_ITEMS,
 	ACTION_MENU, ACTION_CLOSE_GUMPS, ACTION_HIGHLIGHT_ITEMS, ACTION_TOGGLE_TOUCHING,
 	ACTION_JUMP, ACTION_TURN_LEFT, ACTION_TURN_RIGHT, ACTION_MOVE_FORWARD, ACTION_MOVE_BACK,
 	ACTION_MOVE_UP, ACTION_MOVE_DOWN, ACTION_MOVE_LEFT, ACTION_MOVE_RIGHT,
diff --git a/engines/ultima/ultima8/misc/debugger.cpp b/engines/ultima/ultima8/misc/debugger.cpp
index 7665ed7973..954232b9e3 100644
--- a/engines/ultima/ultima8/misc/debugger.cpp
+++ b/engines/ultima/ultima8/misc/debugger.cpp
@@ -141,6 +141,8 @@ Debugger::Debugger() : Shared::Debugger() {
 	registerCmd("MainActor::useBedroll", WRAP_METHOD(Debugger, cmdUseBedroll));
 	registerCmd("MainActor::useKeyring", WRAP_METHOD(Debugger, cmdUseKeyring));
 	registerCmd("MainActor::nextWeapon", WRAP_METHOD(Debugger, cmdNextWeapon));
+	registerCmd("MainActor::useInventoryItem", WRAP_METHOD(Debugger, cmdUseInventoryItem));
+	registerCmd("MainActor::useMedikit", WRAP_METHOD(Debugger, cmdUseMedikit));
 	registerCmd("MainActor::toggleCombat", WRAP_METHOD(Debugger, cmdToggleCombat));
 
 	registerCmd("ObjectManager::objectTypes", WRAP_METHOD(Debugger, cmdObjectTypes));
@@ -1105,6 +1107,32 @@ bool Debugger::cmdNextWeapon(int argc, const char **argv) {
 	return false;
 }
 
+bool Debugger::cmdUseInventoryItem(int argc, const char **argv) {
+	if (Ultima8Engine::get_instance()->isAvatarInStasis()) {
+		debugPrintf("Can't use active inventory item: avatarInStasis\n");
+		return false;
+	}
+	MainActor *av = getMainActor();
+	ObjId activeitemid = av->getActiveInvItem();
+	if (activeitemid) {
+		Item *item = getItem(activeitemid);
+		if (item) {
+			av->useInventoryItem(item);
+		}
+	}
+	return false;
+}
+
+bool Debugger::cmdUseMedikit(int argc, const char **argv) {
+	if (Ultima8Engine::get_instance()->isAvatarInStasis()) {
+		debugPrintf("Can't use medikit: avatarInStasis\n");
+		return false;
+	}
+	MainActor *av = getMainActor();
+	av->useInventoryItem(0x351);
+	return false;
+}
+
 bool Debugger::cmdUseInventory(int argc, const char **argv) {
 	if (Ultima8Engine::get_instance()->isAvatarInStasis()) {
 		debugPrintf("Can't use inventory: avatarInStasis\n");
diff --git a/engines/ultima/ultima8/misc/debugger.h b/engines/ultima/ultima8/misc/debugger.h
index d202bbab5d..b7c4e962e4 100644
--- a/engines/ultima/ultima8/misc/debugger.h
+++ b/engines/ultima/ultima8/misc/debugger.h
@@ -216,6 +216,8 @@ private:
 	bool cmdUseKeyring(int argc, const char **argv);
 	bool cmdNextWeapon(int argc, const char **argv);
 	bool cmdToggleCombat(int argc, const char **argv);
+	bool cmdUseInventoryItem(int argc, const char **argv);
+	bool cmdUseMedikit(int argc, const char **argv);
 
 	// Object Manager
 	bool cmdObjectTypes(int argc, const char **argv);
diff --git a/engines/ultima/ultima8/world/actors/main_actor.cpp b/engines/ultima/ultima8/world/actors/main_actor.cpp
index f170fab4be..e75a2a904b 100644
--- a/engines/ultima/ultima8/world/actors/main_actor.cpp
+++ b/engines/ultima/ultima8/world/actors/main_actor.cpp
@@ -563,7 +563,12 @@ void MainActor::getWeaponOverlay(const WeaponOverlayFrame *&frame_, uint32 &shap
 
 	if (!isInCombat() && _lastAnim != Animation::unreadyWeapon) return;
 
-	ObjId weaponid = getEquip(ShapeInfo::SE_WEAPON);
+	ObjId weaponid;
+	if (GAME_IS_U8)
+		weaponid = getEquip(ShapeInfo::SE_WEAPON);
+	else
+		weaponid = getActiveWeapon();
+
 	Item *weapon = getItem(weaponid);
 	if (!weapon) return;
 
@@ -610,8 +615,10 @@ void MainActor::addKeycard(int bitno) {
 
 static uint16 getIdOfNextItemInList(const Std::vector<Item *> &items, uint16 current) {
 	const int n = items.size();
-	if (n <= 1)
-		return current;
+	if (n == 0)
+		return 0;
+	if (n == 1)
+		return items[0]->getObjId();
 
 	int i;
 	for (i = 0; i < n; i++) {
@@ -797,13 +804,38 @@ uint32 MainActor::I_addItemCru(const uint8 *args,
 }
 
 void MainActor::useInventoryItem(uint32 shapenum) {
+	Item *item = getFirstItemWithShape(shapenum, true);
+	useInventoryItem(item);
+}
+
+void MainActor::useInventoryItem(Item *item) {
+	if (!item)
+		return;
 	if (Ultima8Engine::get_instance()->isAvatarInStasis()) {
 		pout << "Can't use item: avatarInStasis" << Std::endl;
 		return;
 	}
-	Item *item = this->getFirstItemWithShape(shapenum, true);
-	if (item)
-		item->callUsecodeEvent_use();
+	const int32 shapenum = item->getShape();
+	if (shapenum == 0x4ed && GAME_IS_CRUSADER) {
+		// Do nothing for Credits
+		return;
+	}
+	item->callUsecodeEvent_use();
+
+	if (GAME_IS_CRUSADER && (shapenum != 0x4d4 && shapenum != 0x52d &&
+							 shapenum != 0x530 && shapenum != 0x52f &&
+							 shapenum != 0x52e)) {
+		uint16 q = item->getQuality();
+		item->setQuality(q - 1);
+		item->callUsecodeEvent_combine();
+		q = item->getQuality();
+		if (q == 0) {
+			const ObjId id = item->getObjId();
+			item->destroy();
+			if (id == _activeInvItem)
+				nextInvItem();
+		}
+	}
 }
 
 } // End of namespace Ultima8
diff --git a/engines/ultima/ultima8/world/actors/main_actor.h b/engines/ultima/ultima8/world/actors/main_actor.h
index 6a96378065..98bfd99b38 100644
--- a/engines/ultima/ultima8/world/actors/main_actor.h
+++ b/engines/ultima/ultima8/world/actors/main_actor.h
@@ -154,6 +154,7 @@ public:
 
 protected:
 	void useInventoryItem(uint32 shapenum);
+	void useInventoryItem(Item *item);
 
 	bool _justTeleported;
 


Commit: 3ecc3ae04647126bb223e759e1be461930301404
    https://github.com/scummvm/scummvm/commit/3ecc3ae04647126bb223e759e1be461930301404
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-08T17:03:02+09:00

Commit Message:
ULTIMA8: Add red crosshairs in Crusader

Changed paths:
  A engines/ultima/ultima8/world/crosshair_process.cpp
  A engines/ultima/ultima8/world/crosshair_process.h
    engines/ultima/module.mk
    engines/ultima/ultima8/ultima8.cpp


diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index b112de5542..5cb8889aef 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -526,6 +526,7 @@ MODULE_OBJS := \
 	ultima8/world/camera_process.o \
 	ultima8/world/container.o \
 	ultima8/world/create_item_process.o \
+	ultima8/world/crosshair_process.o \
 	ultima8/world/current_map.o \
 	ultima8/world/destroy_item_process.o \
 	ultima8/world/egg.o \
diff --git a/engines/ultima/ultima8/ultima8.cpp b/engines/ultima/ultima8/ultima8.cpp
index acd40725fa..1ec9fb3a88 100644
--- a/engines/ultima/ultima8/ultima8.cpp
+++ b/engines/ultima/ultima8/ultima8.cpp
@@ -93,6 +93,7 @@
 #include "ultima/ultima8/world/item_factory.h"
 #include "ultima/ultima8/world/split_item_process.h"
 #include "ultima/ultima8/world/target_reticle_process.h"
+#include "ultima/ultima8/world/crosshair_process.h"
 #include "ultima/ultima8/world/actors/pathfinder_process.h"
 #include "ultima/ultima8/world/actors/avatar_mover_process.h"
 #include "ultima/ultima8/world/actors/resurrection_process.h"
@@ -422,16 +423,18 @@ void Ultima8Engine::shutdownGame(bool reloading) {
 		_desktopGump->InitGump(0);
 		_desktopGump->MakeFocus();
 
-		debugN(MM_INFO, "Creating _scalerGump...\n");
-		_scalerGump = new ScalerGump(0, 0, dims.w, dims.h);
-		_scalerGump->InitGump(0);
+		if (GAME_IS_U8) {
+			debugN(MM_INFO, "Creating _scalerGump...\n");
+			_scalerGump = new ScalerGump(0, 0, dims.w, dims.h);
+			_scalerGump->InitGump(0);
 
-		Rect scaled_dims;
-		_scalerGump->GetDims(scaled_dims);
+			Rect scaled_dims;
+			_scalerGump->GetDims(scaled_dims);
 
-		debugN(MM_INFO, "Creating Inverter...\n");
-		_inverterGump = new InverterGump(0, 0, scaled_dims.w, scaled_dims.h);
-		_inverterGump->InitGump(0);
+			debugN(MM_INFO, "Creating Inverter...\n");
+			_inverterGump = new InverterGump(0, 0, scaled_dims.w, scaled_dims.h);
+			_inverterGump->InitGump(0);
+		}
 	}
 }
 
@@ -655,14 +658,16 @@ void Ultima8Engine::GraphicSysInit() {
 	_desktopGump->InitGump(0);
 	_desktopGump->MakeFocus();
 
-	_scalerGump = new ScalerGump(0, 0, width, height);
-	_scalerGump->InitGump(0);
+	if (GAME_IS_U8) {
+		_scalerGump = new ScalerGump(0, 0, width, height);
+		_scalerGump->InitGump(0);
 
-	Rect scaled_dims;
-	_scalerGump->GetDims(scaled_dims);
+		Rect scaled_dims;
+		_scalerGump->GetDims(scaled_dims);
 
-	_inverterGump = new InverterGump(0, 0, scaled_dims.w, scaled_dims.h);
-	_inverterGump->InitGump(0);
+		_inverterGump = new InverterGump(0, 0, scaled_dims.w, scaled_dims.h);
+		_inverterGump->InitGump(0);
+	}
 
 	_screen = new_screen;
 
@@ -1047,28 +1052,35 @@ void Ultima8Engine::setupCoreGumps() {
 	_desktopGump->InitGump(0);
 	_desktopGump->MakeFocus();
 
-	debugN(MM_INFO, "Creating _scalerGump...\n");
-	_scalerGump = new ScalerGump(0, 0, dims.w, dims.h);
-	_scalerGump->InitGump(0);
+	if (GAME_IS_U8) {
+		debugN(MM_INFO, "Creating _scalerGump...\n");
+		_scalerGump = new ScalerGump(0, 0, dims.w, dims.h);
+		_scalerGump->InitGump(0);
+
+		Rect scaled_dims;
+		_scalerGump->GetDims(scaled_dims);
 
-	Rect scaled_dims;
-	_scalerGump->GetDims(scaled_dims);
+		debugN(MM_INFO, "Creating Inverter...\n");
+		_inverterGump = new InverterGump(0, 0, scaled_dims.w, scaled_dims.h);
+		_inverterGump->InitGump(0);
 
-	debugN(MM_INFO, "Creating Inverter...\n");
-	_inverterGump = new InverterGump(0, 0, scaled_dims.w, scaled_dims.h);
-	_inverterGump->InitGump(0);
+		debugN(MM_INFO, "Creating GameMapGump...\n");
+		_gameMapGump = new GameMapGump(0, 0, scaled_dims.w, scaled_dims.h);
+		_gameMapGump->InitGump(0);
+	} else {
+		_gameMapGump = new GameMapGump(0, 0, dims.w, dims.h);
+		_gameMapGump->InitGump(0);
+	}
 
-	debugN(MM_INFO, "Creating GameMapGump...\n");
-	_gameMapGump = new GameMapGump(0, 0, scaled_dims.w, scaled_dims.h);
-	_gameMapGump->InitGump(0);
 
 
 	// TODO: clean this up
-	assert(_desktopGump->getObjId() == 256);
-	assert(_scalerGump->getObjId() == 257);
-	assert(_inverterGump->getObjId() == 258);
-	assert(_gameMapGump->getObjId() == 259);
-
+	if (GAME_IS_U8) {
+		assert(_desktopGump->getObjId() == 256);
+		assert(_scalerGump->getObjId() == 257);
+		assert(_inverterGump->getObjId() == 258);
+		assert(_gameMapGump->getObjId() == 259);
+	}
 
 	for (uint16 i = 261; i < 384; ++i)
 		_objectManager->reserveObjId(i);
@@ -1116,6 +1128,7 @@ bool Ultima8Engine::newGame(int saveSlot) {
 
 	if (GAME_IS_CRUSADER) {
 		_kernel->addProcess(new TargetReticleProcess());
+		_kernel->addProcess(new CrosshairProcess());
 		_kernel->addProcess(new CycleProcess());
 	}
 
@@ -1311,18 +1324,20 @@ void Ultima8Engine::addGump(Gump *gump) {
 		//(_ttfOverrides && (dynamic_cast<BarkGump *>(gump) ||
 		//                dynamic_cast<AskGump *>(gump)))
 		) {
-		//		pout << "adding to desktopgump: "; gump->dumpInfo();
 		_desktopGump->AddChild(gump);
 	} else if (dynamic_cast<GameMapGump *>(gump)) {
-		//		pout << "adding to invertergump: "; gump->dumpInfo();
-		_inverterGump->AddChild(gump);
+		if (GAME_IS_U8)
+			_inverterGump->AddChild(gump);
+		else
+			_desktopGump->AddChild(gump);
 	} else if (dynamic_cast<InverterGump *>(gump)) {
-		//		pout << "adding to _scalerGump: "; gump->dumpInfo();
 		_scalerGump->AddChild(gump);
 	} else if (dynamic_cast<DesktopGump *>(gump)) {
 	} else {
-		//		pout << "adding to _scalerGump: "; gump->dumpInfo();
-		_scalerGump->AddChild(gump);
+		if (GAME_IS_U8)
+			_scalerGump->AddChild(gump);
+		else
+			_desktopGump->AddChild(gump);
 	}
 }
 
diff --git a/engines/ultima/ultima8/world/crosshair_process.cpp b/engines/ultima/ultima8/world/crosshair_process.cpp
new file mode 100644
index 0000000000..13c6878ce9
--- /dev/null
+++ b/engines/ultima/ultima8/world/crosshair_process.cpp
@@ -0,0 +1,96 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "ultima/ultima8/misc/pent_include.h"
+
+#include "ultima/ultima8/kernel/kernel.h"
+#include "ultima/ultima8/world/actors/main_actor.h"
+#include "ultima/ultima8/world/crosshair_process.h"
+#include "ultima/ultima8/world/item.h"
+#include "ultima/ultima8/world/world.h"
+#include "ultima/ultima8/world/item_factory.h"
+#include "ultima/ultima8/world/get_object.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+// p_dynamic_cast stuff
+DEFINE_RUNTIME_CLASSTYPE_CODE(CrosshairProcess)
+
+const uint32 CROSSHAIR_SHAPE = 0x4CC;
+const float CROSSHAIR_DIST = 400.0;
+
+CrosshairProcess::CrosshairProcess() : Process() {
+}
+
+void CrosshairProcess::run() {
+	Kernel *kernel = Kernel::get_instance();
+	assert(kernel);
+	MainActor *mainactor = getMainActor();
+	int32 cx, cy, cz, ax, ay, az;
+	mainactor->getCentre(cx, cy, cz);
+	mainactor->getFootpadWorld(ax, ay, az);
+	// TODO: Make a fine adjustment for avatar height (eg, when crouching)
+	// for now just put it at 3/4 avatar height which is about right.
+	cz += az / 4;
+	// TODO: Get the fine angle of the avatar once that is implemented.
+	uint16 dir = (mainactor->getDir() + 2) % 8;
+	// Dir is 0~7, convert to 0~15/8*pi
+	float angle = (3.14 * dir / 4.0);
+	float xoff = CROSSHAIR_DIST * cos(angle);
+	float yoff = CROSSHAIR_DIST * sin(angle);
+	cx -= static_cast<int32>(xoff);
+	cy -= static_cast<int32>(yoff);
+
+	if (mainactor->isInCombat()) {
+		Item *item;
+		if (_itemNum) {
+			item = getItem(_itemNum);
+		} else {
+			// Create a new sprite
+			item = ItemFactory::createItem(CROSSHAIR_SHAPE, 0, 0, Item::FLG_DISPOSABLE,
+										   0, 0, Item::EXT_SPRITE, true);
+			setItemNum(item->getObjId());
+		}
+		assert(item);
+		item->move(cx, cy, cz);
+	} else {
+		if (_itemNum) {
+			Item *item = getItem(_itemNum);
+			assert(item);
+			item->destroy();
+			_itemNum = 0;
+		}
+	}
+
+}
+
+void CrosshairProcess::saveData(Common::WriteStream *ws) {
+	Process::saveData(ws);
+}
+
+bool CrosshairProcess::loadData(Common::ReadStream *rs, uint32 version) {
+	return Process::loadData(rs, version);
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/world/crosshair_process.h b/engines/ultima/ultima8/world/crosshair_process.h
new file mode 100644
index 0000000000..d06ef09b41
--- /dev/null
+++ b/engines/ultima/ultima8/world/crosshair_process.h
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ULTIMA8_WORLD_CROSSHAIRPROCESS_H
+#define ULTIMA8_WORLD_CROSSHAIRPROCESS_H
+
+#include "ultima/ultima8/kernel/process.h"
+#include "ultima/ultima8/misc/p_dynamic_cast.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+/**
+ * A process to update the location of the small red crosshairs in Crusader.
+ * The crosshairs are just based on avatar angle and don't move with the
+ * environment, which makes them simpler than the dynamic target reticle.
+ */
+class CrosshairProcess : public Process {
+public:
+	CrosshairProcess();
+
+	// p_dynamic_cast stuff
+	ENABLE_RUNTIME_CLASSTYPE()
+
+	void run() override;
+
+	bool loadData(Common::ReadStream *rs, uint32 version);
+	void saveData(Common::WriteStream *ws) override;
+};
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif


Commit: 97041718365b273b65c5f99b6685eef5486c9943
    https://github.com/scummvm/scummvm/commit/97041718365b273b65c5f99b6685eef5486c9943
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-08T17:03:02+09:00

Commit Message:
ULTIMA8: Implement Crusader GuardProcess (WIP)

Changed paths:
  A engines/ultima/ultima8/world/actors/guard_process.cpp
  A engines/ultima/ultima8/world/actors/guard_process.h
    engines/ultima/module.mk


diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 5cb8889aef..a262910e97 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -563,6 +563,7 @@ MODULE_OBJS := \
 	ultima8/world/actors/combat_dat.o \
 	ultima8/world/actors/combat_process.o \
 	ultima8/world/actors/grant_peace_process.o \
+	ultima8/world/actors/guard_process.o \
 	ultima8/world/actors/heal_process.o \
 	ultima8/world/actors/loiter_process.o \
 	ultima8/world/actors/main_actor.o \
diff --git a/engines/ultima/ultima8/world/actors/guard_process.cpp b/engines/ultima/ultima8/world/actors/guard_process.cpp
new file mode 100644
index 0000000000..6ab51b2962
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/guard_process.cpp
@@ -0,0 +1,91 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "ultima/ultima8/misc/pent_include.h"
+#include "ultima/ultima8/world/actors/guard_process.h"
+#include "ultima/ultima8/world/actors/actor.h"
+#include "ultima/ultima8/world/actors/main_actor.h"
+#include "ultima/ultima8/world/actors/animation.h"
+#include "ultima/ultima8/world/actors/actor_anim_process.h"
+#include "ultima/ultima8/kernel/kernel.h"
+#include "ultima/ultima8/kernel/delay_process.h"
+#include "ultima/ultima8/kernel/core_app.h"
+#include "ultima/ultima8/world/get_object.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+// p_dynamic_cast stuff
+DEFINE_RUNTIME_CLASSTYPE_CODE(GuardProcess)
+
+GuardProcess::GuardProcess() : Process() {
+}
+
+GuardProcess::GuardProcess(Actor *actor) {
+	assert(actor);
+	_itemNum = actor->getObjId();
+	_type = 0x255;
+}
+
+void GuardProcess::run() {
+	Actor *a = getActor(_itemNum);
+	if (!a || a->isDead()) {
+		// dead?
+		terminate();
+		return;
+	}
+
+	int activeanim = Kernel::get_instance()->getNumProcesses(a->getObjId(), ActorAnimProcess::ACTOR_ANIM_PROC_TYPE);
+	if (activeanim > 0)
+		return;
+
+	Actor *mainactor = getMainActor();
+	if (!mainactor)
+		return;
+
+	int range = a->getRangeIfVisible(*mainactor);
+	if (!range) {
+		if (getRandom() % 2) {
+			DelayProcess *dp = new DelayProcess(30 * (1 + (getRandom() % 3)));
+			Kernel::get_instance()->addProcess(dp);
+			waitFor(dp);
+			return;
+		} else {
+			// TODO: What animation happens in here?
+			//a->tryAnim(0x1e, a->getDir());
+		}
+		return;
+	}
+
+	a->setActivity(5);
+}
+
+void GuardProcess::saveData(Common::WriteStream *ws) {
+	Process::saveData(ws);
+}
+
+bool GuardProcess::loadData(Common::ReadStream *rs, uint32 version) {
+	return Process::loadData(rs, version);
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/world/actors/guard_process.h b/engines/ultima/ultima8/world/actors/guard_process.h
new file mode 100644
index 0000000000..121b375aba
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/guard_process.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WORLD_ACTORS_GUARDPROCESS_H
+#define WORLD_ACTORS_GUARDPROCESS_H
+
+#include "ultima/ultima8/kernel/process.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+class Actor;
+
+class GuardProcess : public Process {
+public:
+	GuardProcess();
+	GuardProcess(Actor *actor);
+
+	// p_dynamic_cast stuff
+	ENABLE_RUNTIME_CLASSTYPE()
+
+	void run() override;
+
+	bool loadData(Common::ReadStream *rs, uint32 version);
+	void saveData(Common::WriteStream *ws) override;
+};
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif


Commit: 5b7d73240740a48b1d6441a8c54f738236a11c02
    https://github.com/scummvm/scummvm/commit/5b7d73240740a48b1d6441a8c54f738236a11c02
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-08T17:03:02+09:00

Commit Message:
ULTIMA8: Support a few more crusader intrinsics

Changed paths:
    engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
    engines/ultima/ultima8/usecode/remorse_intrinsics.h
    engines/ultima/ultima8/world/actors/actor.cpp
    engines/ultima/ultima8/world/actors/actor.h
    engines/ultima/ultima8/world/actors/main_actor.cpp
    engines/ultima/ultima8/world/actors/main_actor.h
    engines/ultima/ultima8/world/world.cpp


diff --git a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
index 7efddb0849..436ce6d5d0 100644
--- a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
+++ b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
@@ -78,7 +78,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"byte Actor::I_isNPC(Item *)", // proably - actually checks is itemno < 256?
 	"byte Item::I_getZ(Item *)",
 	"void Item::I_destroy(Item *)", // probably? often called after creating a replacement object and setting it to the same position (eg, LUGGAGE::gotHit)
-	"int16 Actor::I_GetNPCDataField0x63_00B(Actor *)", // Maybe get HP? Called from ANDROID::calledFromAnim, goes to NPCDEATH
+	"int16 Actor::I_GetNPCDataField0x63_00B(Actor *)", // Some unknown value set for NPCs based on Q of egg.
 	"void Ultima8Engine::I_setAvatarInStasis(int)",
 	"byte Item::I_getDirToItem(Item *, itemno)", // based on disasm
 	"int16 Actor::I_turnToward(Actor *, direction, unk)", // TODO: work out what unk is
@@ -152,13 +152,13 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"byte Item::I_IsOn(Item *, uint16 itemno)", // part of same coff set 044, 046, 048, 04A, 04C, 04E, 0A5, 0BC, 0C5, 0DC, 0F1, 0FA, 12C
 	"int16 Item::I_getQHi(Item *)", // same as 026 based on same coff set 026, 045, 047, 049, 04B, 04D, 04F, 0AF, 0BE, 0C9, 0F0, 0F3, 0FB, 133
 	// 0050
-	"int16 I_GetNPCDataField0x2_050(Actor *)",
+	"int16 Actor::I_getCurrentActivityNo(Actor *)",
 	"void Actor::I_clrInCombat(Actor *)", // probably, based on disasm.
 	"void Actor::I_setDefaultActivity0(Actor *, int)",
 	"void Actor::I_setDefaultActivity1(Actor *, int)",
 	"void Actor::I_setDefaultActivity2(Actor *, int)",
 	"void Actor::I_setActivity(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
-	"void Intrinsic056(int itemno)", // Maybe set new target? TODO: check usecode to understand this.
+	"void I_setControlledNPCTo(int itemno)", // when you take over the Thermatron etc.
 	"int16 Item::I_getSurfaceWeight(Item *)",
 	"byte Item::I_isCentreOn(Item *, uint16 other)",
 	"void Item::I_setFrame(Item *, frame)", // based on same coff as 002
@@ -301,7 +301,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"void PaletteFaderProcess::I_setPalToAllGrey(void)", // sets all colors to 0x3F3F3F
 	"void Actor::I_setActivity(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
 	"byte Item::I_isOn(Item *, itemno)", // part of same coff set 044, 046, 048, 04A, 04C, 04E, 0A5, 0BC, 0C5, 0DC, 0F1, 0FA, 12C
-	"int16 Actor::I_GetNPCDataField0x4_0DD(Actor *)",
+	"int16 Actor::I_getLastActivityNo(Actor *)",
 	"void Actor::I_setCombatTactic(Actor *, int)",
 	"int16 Actor::I_getEquip(6 bytes)", // based on disasm
 	// 00E0
diff --git a/engines/ultima/ultima8/usecode/remorse_intrinsics.h b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
index ec935dd093..ed987f054e 100644
--- a/engines/ultima/ultima8/usecode/remorse_intrinsics.h
+++ b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
@@ -46,7 +46,7 @@ Intrinsic RemorseIntrinsics[] = {
 	Actor::I_isNPC, // byte Intrinsic008(Item *)
 	Item::I_getZ, // byte Intrinsic009(Item *)
 	Item::I_destroy, // void Intrinsic00A(Item *)
-	0, // get something npcdata, maybe HP void Intrinsic00B(4 bytes)
+	Actor::I_getUnkByte, // get something about npcdata - struct byte 0x63 (99)
 	Ultima8Engine::I_setAvatarInStasis, // void Intrinsic00C(2 bytes)
 	Item::I_getDirToItem, // byte Intrinsic00D(6 bytes)
 	0, // TODO: Actor::I_turnToward(Actor *, direction, unk)
@@ -120,7 +120,7 @@ Intrinsic RemorseIntrinsics[] = {
 	Item::I_isOn,
 	Item::I_getQHi,  // based on same coff set as 026
 	// 0x050
-	0, // void Intrinsic050(4 bytes)
+	0, // TODO: int16 Actor::I_getCurrentActivityNo // void Intrinsic050(4 bytes)
 	Actor::I_clrInCombat, // void Intrinsic051(4 bytes)
 	Actor::I_setDefaultActivity0, // void Intrinsic052(6 bytes)
 	Actor::I_setDefaultActivity1, // void Intrinsic053(6 bytes)
@@ -186,7 +186,7 @@ Intrinsic RemorseIntrinsics[] = {
 	Item::I_setBroken, // void Intrinsic08C(4 bytes)
 	Item::I_hurl, // void Intrinsic08D(12 bytes)
 	Item::I_getNpcNum, // based on same coff as 102 (-> variable name in TRIGGER::ordinal21)
-	0, // TODO: PaletteFaderProcess::I_setPalToAllBlack
+	0, // TODO: PaletteFaderProcess::I_setPalToAllBlack - should also resume cycle process.
 	// 0x090
 	MusicProcess::I_musicStop, // void Intrinsic090(void)
 	0, // void Intrinsic091(void)
@@ -198,7 +198,7 @@ Intrinsic RemorseIntrinsics[] = {
 	0, // TODO: PaletteFaderProcess:I_setScreenGreyscale(void) (converts all colors to their Y values on each channel)
 	0, // void Intrinsic098(void) // TODO: reset vargas health to 500.. weird.
 	Item::I_andStatus, // void Intrinsic099(6 bytes)
-	0, // TODO: PaletteFaderProcess::I_stopFadesAndResetToGamePal(void),
+	0, // TODO: PaletteFaderProcess::I_stopFadesAndResetToGamePal(void), - should also stop cycle process.
 	PaletteFaderProcess::I_fadeFromBlack, // fade to game pal with number of steps
 	0, // TODO: PaletteFaderProcess::I_fadeFromBlackWithParam
 	PaletteFaderProcess::I_fadeToBlack, // fade to black with number of steps
@@ -269,7 +269,7 @@ Intrinsic RemorseIntrinsics[] = {
 	0, // TODO: PaletteFaderProcess::I_setPalToAllGrey // sets all colors to 0x3F3F3F
 	Actor::I_setActivity, // void Intrinsic0DB(6 bytes)
 	Item::I_isOn,
-	0, // void Intrinsic0DD(4 bytes)
+	0, // TODO: Actor::I_getLastActivityNo void Intrinsic0DD(4 bytes)
 	Actor::I_setCombatTactic, // void Intrinsic0DE(6 bytes)
 	Actor::I_getEquip, // void Intrinsic0DF(6 bytes)
 	// 0x0E0
@@ -279,12 +279,12 @@ Intrinsic RemorseIntrinsics[] = {
 	Actor::I_getDefaultActivity2, // void Intrinsic0E3(4 bytes)
 	Actor::I_getLastAnimSet, // void Intrinsic0E4(4 bytes)
 	0, // TODO: Actor::I_attack(Actor *, uint16 target) (implement me)
-	0, // void Intrinsic0E6(6 bytes)
+	Actor::I_setUnkByte, // void Intrinsic0E6(6 bytes)
 	Actor::I_setDead,
 	Item::I_cast, // void Intrinsic0E8(6 bytes)
 	Item::I_andStatus, // void Intrinsic0E9(6 bytes)
 	Item::I_getQLo, // based on same coff set as 02B
-	0, // void Intrinsic0EB(void)
+	MainActor::I_getNumberOfCredits, // void Intrinsic0EB(void)
 	Item::I_popToEnd,
 	Item::I_popToContainer,
 	BatteryChargerProcess::I_create,
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index c5e83b43ba..0865328c23 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -66,9 +66,10 @@ static const unsigned int BACKPACK_SHAPE = 529;
 DEFINE_RUNTIME_CLASSTYPE_CODE(Actor)
 
 Actor::Actor() : _strength(0), _dexterity(0), _intelligence(0),
-	  _hitPoints(0), _mana(0), _alignment(0), _enemyAlignment(0),
-	  _lastAnim(Animation::stand), _animFrame(0), _direction(0),
-		_fallStart(0), _unk0C(0), _actorFlags(0), _combatTactic(0) {
+		_hitPoints(0), _mana(0), _alignment(0), _enemyAlignment(0),
+		_lastAnim(Animation::stand), _animFrame(0), _direction(0),
+		_fallStart(0), _unkByte(0), _actorFlags(0), _combatTactic(0),
+		_homeX(0), _homeY(0), _homeZ(0) {
 	_defaultActivity[0] = 0;
 	_defaultActivity[1] = 0;
 	_defaultActivity[2] = 0;
@@ -674,6 +675,18 @@ uint16 Actor::getDefaultActivity(int no) const {
 	return _defaultActivity[no];
 }
 
+void Actor::setHomePosition(int32 x, int32 y, int32 z) {
+	_homeX = x;
+	_homeY = y;
+	_homeZ = z;
+}
+
+void Actor::getHomePosition(int32 &x, int32 &y, int32 &z) const {
+	x = _homeX;
+	y = _homeY;
+	z = _homeZ;
+}
+
 void Actor::receiveHit(uint16 other, int dir, int damage, uint16 damage_type) {
 	if (isDead())
 		return; // already dead, so don't bother
@@ -1110,11 +1123,16 @@ int32 Actor::collideMove(int32 x, int32 y, int32 z, bool teleport, bool force,
 	return result;
 }
 
+static Std::set<uint16> _notifiedItems;
+
 void Actor::notifyNearbyItems() {
-/*
+	/*
 	TODO: This is not right - maybe we want to trigger each item only when it gets close,
 	then reset the status after it moves away?  Need to dig into the assembly more.
- 
+
+	For now this is a temporary hack to trigger some usecode events so we can
+	debug more of the game.
+	 */
 	UCList uclist(2);
 	LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
 	CurrentMap *currentmap = World::get_instance()->getCurrentMap();
@@ -1122,8 +1140,11 @@ void Actor::notifyNearbyItems() {
 
 	for (unsigned int i = 0; i < uclist.getSize(); ++i) {
 		Item *item = getItem(uclist.getuint16(i));
+		if (_notifiedItems.find(item->getObjId()) != _notifiedItems.end())
+			continue;
 		item->callUsecodeEvent_npcNearby(_objId);
-	}*/
+		_notifiedItems.insert(item->getObjId());
+	}
 }
 
 bool Actor::areEnemiesNear() {
@@ -1210,13 +1231,16 @@ void Actor::saveData(Common::WriteStream *ws) {
 	ws->writeUint16LE(_direction);
 	ws->writeUint32LE(_fallStart);
 	ws->writeUint32LE(_actorFlags);
-	ws->writeByte(_unk0C);
+	ws->writeByte(_unkByte);
 
 	if (GAME_IS_CRUSADER) {
 		ws->writeUint16LE(_defaultActivity[0]);
 		ws->writeUint16LE(_defaultActivity[1]);
 		ws->writeUint16LE(_defaultActivity[2]);
 		ws->writeUint16LE(_combatTactic);
+		ws->writeUint32LE(_homeX);
+		ws->writeUint32LE(_homeY);
+		ws->writeUint32LE(_homeZ);
 	}
 }
 
@@ -1235,13 +1259,16 @@ bool Actor::loadData(Common::ReadStream *rs, uint32 version) {
 	_direction = rs->readUint16LE();
 	_fallStart = rs->readUint32LE();
 	_actorFlags = rs->readUint32LE();
-	_unk0C = rs->readByte();
+	_unkByte = rs->readByte();
 
 	if (GAME_IS_CRUSADER) {
 		_defaultActivity[0] = rs->readUint16LE();
 		_defaultActivity[1] = rs->readUint16LE();
 		_defaultActivity[2] = rs->readUint16LE();
 		_combatTactic = rs->readUint16LE();
+		_homeX = rs->readUint32LE();
+		_homeY = rs->readUint32LE();
+		_homeZ = rs->readUint32LE();
 	}
 
 	return true;
@@ -1774,24 +1801,42 @@ uint32 Actor::I_createActorCru(const uint8 *args, unsigned int /*argsize*/) {
 	newactor->setDefaultActivity(1, item->getQuality() >> 8);
 	newactor->setDefaultActivity(2, other->getMapNum());
 
-	// TODO: once I know what these fields are...
-	/*
-	 newactor->setField0x5c(0);
-	 newactor->setField0x5e(x, y);
-	 newactor->setField0x12(item->getNpcNum() >> 4);
-	 newactor->setField0x63(item->getQuality() & 0xff);
+	newactor->setUnkByte(item->getQuality() & 0xff);
 
-	 uint16 wpnType = npcData->getWpnType();
-	 if (gameDifficulty == 4) {
-		wpnType = randomlyGetHigherWeaponType(shape, wpntype);
-	 }
+	uint16 wpntype = npcData->getWpnType();
+	Item *weapon = ItemFactory::createItem(wpntype, 0, 0, 0, 0, newactor->getMapNum(), 0, true);
+	/* TODO:
+	if (gameDifficulty == 4) {
+	   wpntype = randomlyGetHigherWeaponType(shape, wpntype);
+	}*/
+	// TODO: should this be addItemCru? If so need to move it from MainActor.
+	weapon->moveToContainer(newactor, false);
+	newactor->setCombatTactic(0);
+	newactor->setHomePosition(x, y, z);
 
-	 // give weapon to NPC.
+	/*
+	 TODO: once I know what this field is.. seems to never be used in game?
+	 newactor->setField0x12(item->getNpcNum() >> 4);
 	 */
 
 	return newactor->getObjId();
 }
 
+uint32 Actor::I_setUnkByte(const uint8 *args, unsigned int /*argsize*/) {
+	ARG_ACTOR_FROM_PTR(actor);
+	ARG_UINT16(value);
+	if (actor)
+		actor->setUnkByte(static_cast<uint8>(value & 0xff));
+	return 0;
+}
+
+uint32 Actor::I_getUnkByte(const uint8 *args, unsigned int /*argsize*/) {
+	ARG_ACTOR_FROM_PTR(actor);
+	if (!actor) return 0;
+
+	return actor->getUnkByte();
+}
+
 uint32 Actor::I_setActivity(const uint8 *args, unsigned int /*argsize*/) {
 	ARG_ACTOR_FROM_PTR(actor);
 	ARG_UINT16(activity);
diff --git a/engines/ultima/ultima8/world/actors/actor.h b/engines/ultima/ultima8/world/actors/actor.h
index 9f196545fc..1b7a77e7ac 100644
--- a/engines/ultima/ultima8/world/actors/actor.h
+++ b/engines/ultima/ultima8/world/actors/actor.h
@@ -122,8 +122,11 @@ public:
 	void setFallStart(int32 zp) {
 		_fallStart = zp;
 	}
-	void setUnk0C(uint8 b) {
-		_unk0C = b;
+	void setUnkByte(uint8 b) {
+		_unkByte = b;
+	}
+	uint8 getUnkByte() const {
+		return _unkByte;
 	}
 
 	bool hasActorFlags(uint32 flags) const {
@@ -170,6 +173,9 @@ public:
 	void setDefaultActivity(int no, uint16 activity);
 	uint16 getDefaultActivity(int no) const;
 
+	void setHomePosition(int32 x, int32 y, int32 z);
+	void getHomePosition(int32 &x, int32 &y, int32 &z) const;
+
 	//! calculate the damage an attack against this Actor does.
 	//! \param other the attacker (can be zero)
 	//! \param damage base damage
@@ -294,6 +300,8 @@ public:
 	INTRINSIC(I_getDefaultActivity1);
 	INTRINSIC(I_getDefaultActivity2);
 	INTRINSIC(I_setCombatTactic);
+	INTRINSIC(I_setUnkByte);
+	INTRINSIC(I_getUnkByte);
 
 	enum ActorFlags {
 		ACT_INVINCIBLE     = 0x000001, // flags from npcdata byte 0x1B
@@ -329,7 +337,10 @@ protected:
 	uint16 _direction;
 
 	int32 _fallStart;
-	uint8 _unk0C; // unknown byte 0x0C from npcdata.dat
+
+	//! Unknown byte 0x0C from npcdata.dat in U8, or
+	//! Unknown byte 0x99 from NPC struct in Crusader.
+	uint8 _unkByte;
 
 	//! tactic being used in combat (for Crusader), the entry in the combat.dat flex.
 	uint16 _combatTactic;
@@ -339,6 +350,11 @@ protected:
 	//! the 3 default NPC activities from Crusader
 	uint16 _defaultActivity[3];
 
+	//! The "home" position used in some Crusader attack tactics
+	int32 _homeX;
+	int32 _homeY;
+	int32 _homeZ;
+
 	//! starts an activity (Ultima 8 version)
 	//! \return processID of process handling the activity or zero
 	uint16 setActivityU8(int activity);
diff --git a/engines/ultima/ultima8/world/actors/main_actor.cpp b/engines/ultima/ultima8/world/actors/main_actor.cpp
index e75a2a904b..23d0517de3 100644
--- a/engines/ultima/ultima8/world/actors/main_actor.cpp
+++ b/engines/ultima/ultima8/world/actors/main_actor.cpp
@@ -175,7 +175,6 @@ int16 MainActor::addItemCru(Item *item, bool showtoast) {
 			item->moveToContainer(this);
 			if (!_activeWeapon)
 				_activeWeapon = item->getObjId();
-			warning("TODO: Set new weapon as active weapon if there is none");
 			if (showtoast)
 				pickupArea->addPickup(item);
 		}
@@ -803,6 +802,17 @@ uint32 MainActor::I_addItemCru(const uint8 *args,
 	return 0;
 }
 
+uint32 MainActor::I_getNumberOfCredits(const uint8 *args,
+unsigned int /*argsize*/) {
+	MainActor *av = getMainActor();
+	if (av) {
+		Item *item = av->getFirstItemWithShape(0x4ed, true);
+		if (item)
+			return item->getQuality();
+	}
+	return 0;
+}
+
 void MainActor::useInventoryItem(uint32 shapenum) {
 	Item *item = getFirstItemWithShape(shapenum, true);
 	useInventoryItem(item);
diff --git a/engines/ultima/ultima8/world/actors/main_actor.h b/engines/ultima/ultima8/world/actors/main_actor.h
index 98bfd99b38..c4f6ac4070 100644
--- a/engines/ultima/ultima8/world/actors/main_actor.h
+++ b/engines/ultima/ultima8/world/actors/main_actor.h
@@ -148,6 +148,7 @@ public:
 	INTRINSIC(I_hasKeycard);
 	INTRINSIC(I_clrKeycards);
 	INTRINSIC(I_addItemCru);
+	INTRINSIC(I_getNumberOfCredits);
 
 	void getWeaponOverlay(const WeaponOverlayFrame *&frame_, uint32 &shape_);
 
diff --git a/engines/ultima/ultima8/world/world.cpp b/engines/ultima/ultima8/world/world.cpp
index 466d89bf12..e62dcf5efa 100644
--- a/engines/ultima/ultima8/world/world.cpp
+++ b/engines/ultima/ultima8/world/world.cpp
@@ -288,7 +288,7 @@ void World::loadItemCachNPCData(Common::SeekableReadStream *itemcach, Common::Se
 		uint8 align = npcds->readByte(); // 0x0B: alignments
 		actor->setAlignment(align & 0x0F);
 		actor->setEnemyAlignment(align & 0xF0);
-		actor->setUnk0C(npcds->readByte()); // 0x0C: unknown;
+		actor->setUnkByte(npcds->readByte()); // 0x0C: unknown;
 		// 0x0C is almost always zero, except for
 		// the avatar (0xC0) and
 		// Malchir, Vardion, Gorgrond, Beren (0xE0)




More information about the Scummvm-git-logs mailing list