[Scummvm-git-logs] scummvm master -> 84d3d95707c7fbaa951b3e202f2bfd3a3e14543d

mduggan mgithub at guarana.org
Fri Jun 26 04:25:54 UTC 2020


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

Summary:
84d3d95707 ULTIMA8: More crusader NPC support


Commit: 84d3d95707c7fbaa951b3e202f2bfd3a3e14543d
    https://github.com/scummvm/scummvm/commit/84d3d95707c7fbaa951b3e202f2bfd3a3e14543d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-06-26T13:24:59+09:00

Commit Message:
ULTIMA8: More crusader NPC support

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/loiter_process.cpp
    engines/ultima/ultima8/world/actors/npc_dat.cpp
    engines/ultima/ultima8/world/actors/npc_dat.h


diff --git a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
index 156848bd90..c62fa1ed3a 100644
--- a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
+++ b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
@@ -154,9 +154,9 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	// 0050
 	"int16 I_GetNPCDataField0x2_050(Actor *)",
 	"void I_NPCSomething_051(Actor *)",  // TODO: check usecode to understand this.
-	"void I_SetNPCDataField0x6_052(Actor *, int)", // TODO: check usecode to understand this.
-	"void I_SetNPCDataField0x8_053(Actor *, int)", // TODO: check usecode to understand this.
-	"void I_SetNPCDataField0xA_054(Actor *, int)", // TODO: check usecode to understand this.
+	"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.
 	"int16 Item::I_getSOMETHING_57(Item *)",
@@ -306,9 +306,9 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"int16 Actor::I_getEquip(6 bytes)", // based on disasm
 	// 00E0
 	"void Actor::I_setEquip(8 bytes)",
-	"int16 Actor::I_GetNPCDataField0x6_0E1(Actor *)",
-	"int16 Actor::I_GetNPCDataField0x8_0E2(Actor *)",
-	"int16 Actor::I_GetNPCDataField0xa_0E3(Actor *)",
+	"int16 Actor::I_getDefaultActivity0(Actor *)",
+	"int16 Actor::I_getDefaultActivity1(Actor *)",
+	"int16 Actor::I_getDefaultActivity2(Actor *)",
 	"int16 Actor::I_getLastAnimSet(4 bytes)", // part of same coff set 01D, 05A, 0B9, 0D7, 0E4, 124
 	"void Actor::I_attackProbably(Actor *, uint16 target)", // TODO: game checks 0x59 flag 3 first.. what is that?
 	"void Actor::I_SetNPCDataField0x63_0E6(Actor *, int)",
diff --git a/engines/ultima/ultima8/usecode/remorse_intrinsics.h b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
index 4faacc61b1..f87139b50a 100644
--- a/engines/ultima/ultima8/usecode/remorse_intrinsics.h
+++ b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
@@ -122,9 +122,9 @@ Intrinsic RemorseIntrinsics[] = {
 	// 0x050
 	0, // void Intrinsic050(4 bytes)
 	0, // void Intrinsic051(4 bytes)
-	0, // void Intrinsic052(6 bytes)
-	0, // void Intrinsic053(6 bytes)
-	0, // void Intrinsic054(6 bytes)
+	Actor::I_setDefaultActivity0, // void Intrinsic052(6 bytes)
+	Actor::I_setDefaultActivity1, // void Intrinsic053(6 bytes)
+	Actor::I_setDefaultActivity2, // void Intrinsic054(6 bytes)
 	Actor::I_setActivity, // void Intrinsic055(6 bytes)
 	0, // void Intrinsic056(2 bytes)
 	0, // void Intrinsic057(4 bytes)
@@ -138,7 +138,7 @@ Intrinsic RemorseIntrinsics[] = {
 	0, // void Intrinsic05F(void)
 	// 0x060
 	Actor::I_setDead, // void Intrinsic060(4 bytes)
-	Actor::I_create, // void Intrinsic061(8 bytes)
+	Actor::I_createActor, // void Intrinsic061(8 bytes)
 	0, // void Intrinsic062(void)
 	Actor::I_teleport, // void Intrinsic063(12 bytes)
 	Item::I_getFootpadData, // void Intrinsic064(16 bytes)
@@ -274,9 +274,9 @@ Intrinsic RemorseIntrinsics[] = {
 	Actor::I_getEquip, // void Intrinsic0DF(6 bytes)
 	// 0x0E0
 	Actor::I_setEquip, // void Intrinsic0E0(8 bytes)
-	0, // void Intrinsic0E1(4 bytes)
-	0, // void Intrinsic0E2(4 bytes)
-	0, // void Intrinsic0E3(4 bytes)
+	Actor::I_getDefaultActivity0, // void Intrinsic0E1(4 bytes)
+	Actor::I_getDefaultActivity1, // void Intrinsic0E2(4 bytes)
+	Actor::I_getDefaultActivity2, // void Intrinsic0E3(4 bytes)
 	Actor::I_getLastAnimSet, // void Intrinsic0E4(4 bytes)
 	0, // void Intrinsic0E5(6 bytes)
 	0, // void Intrinsic0E6(6 bytes)
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 4bbd21c918..e1486e0607 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -67,6 +67,9 @@ 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) {
+	_defaultActivity[0] = 0;
+	_defaultActivity[1] = 0;
+	_defaultActivity[2] = 0;
 }
 
 Actor::~Actor() {
@@ -94,6 +97,31 @@ uint16 Actor::getMaxHP() const {
 }
 
 bool Actor::loadMonsterStats() {
+	if (GAME_IS_CRUSADER)
+		return loadMonsterStatsCru();
+	else
+		return loadMonsterStatsU8();
+}
+
+bool Actor::loadMonsterStatsCru() {
+	const NPCDat *npcData = GameData::get_instance()->getNPCDataForShape(getShape());
+
+	if (!npcData)
+		return false;
+
+	setStr(npcData->getMaxHp() / 2);
+	setHP(npcData->getMaxHp());
+	_defaultActivity[0] = npcData->getDefaultActivity(0);
+	_defaultActivity[1] = npcData->getDefaultActivity(1);
+	_defaultActivity[2] = npcData->getDefaultActivity(2);
+
+	// TODO: Give them the default weapon for their type here.
+
+	return true;
+}
+
+bool Actor::loadMonsterStatsU8() {
+
 	ShapeInfo *shapeinfo = getShapeInfo();
 	MonsterInfo *mi = nullptr;
 	if (shapeinfo) mi = shapeinfo->_monsterInfo;
@@ -546,9 +574,8 @@ uint16 Actor::setActivityCru(int activity) {
 	case 1: // stand
 		return doAnim(Animation::stand, 8);
 	case 3: // pace
-		perr << "Actor::setActivityCru TODO: Implement new PaceProcess(this);";
-		// TODO: Implement me as separate from loiter. (fall through for now)
-		// fall through
+		perr << "Actor::setActivityCru TODO: Implement new PaceProcess(this);" << Std::endl;
+		return Kernel::get_instance()->addProcess(new LoiterProcess(this));
 	case 2: // loiter
 		Kernel::get_instance()->addProcess(new LoiterProcess(this));
 		return Kernel::get_instance()->addProcess(new DelayProcess(1));
@@ -557,10 +584,12 @@ uint16 Actor::setActivityCru(int activity) {
 	    // Does nothing in game..
 	    break;
 	case 7:
-		perr << "Actor::setActivityCru TODO: Implement new SurrenderProcess(this);";
+		perr << "Actor::setActivityCru TODO: Implement new SurrenderProcess(this);" << Std::endl;
+		return Kernel::get_instance()->addProcess(new LoiterProcess(this));
 	    break;
 	case 8:
-		perr << "Actor::setActivityCru TODO: Implement new GuardProcess(this);";
+		perr << "Actor::setActivityCru TODO: Implement new GuardProcess(this);" << Std::endl;
+		return Kernel::get_instance()->addProcess(new LoiterProcess(this));
 	    break;
 	case 5:
 	case 9:
@@ -570,7 +599,12 @@ uint16 Actor::setActivityCru(int activity) {
 		// attack
 	   setInCombat();
 	   return 0;
-
+	case 0x70:
+		return setActivity(getDefaultActivity(0));
+	case 0x71:
+		return setActivity(getDefaultActivity(1));
+	case 0x72:
+		return setActivity(getDefaultActivity(2));
 	default:
 		perr << "Actor::setActivityCru: invalid activity (" << activity << ")"
 		     << Std::endl;
@@ -629,6 +663,15 @@ int Actor::getDamageAmount() const {
 	}
 }
 
+void Actor::setDefaultActivity(int no, uint16 activity) {
+	assert(no >= 0 && no < 3);
+	_defaultActivity[no] = activity;
+}
+
+uint16 Actor::getDefaultActivity(int no) const {
+	assert(no >= 0 && no < 3);
+	return _defaultActivity[no];
+}
 
 void Actor::receiveHit(uint16 other, int dir, int damage, uint16 damage_type) {
 	if (isDead())
@@ -1064,6 +1107,10 @@ int32 Actor::collideMove(int32 x, int32 y, int32 z, bool teleport, bool force,
 }
 
 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.
+ 
 	UCList uclist(2);
 	LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
 	CurrentMap *currentmap = World::get_instance()->getCurrentMap();
@@ -1072,7 +1119,7 @@ void Actor::notifyNearbyItems() {
 	for (unsigned int i = 0; i < uclist.getSize(); ++i) {
 		Item *item = getItem(uclist.getuint16(i));
 		item->callUsecodeEvent_npcNearby(_objId);
-	}
+	}*/
 }
 
 bool Actor::areEnemiesNear() {
@@ -1134,7 +1181,6 @@ Actor *Actor::createActor(uint32 shape, uint32 frame) {
 	return newactor;
 }
 
-
 void Actor::dumpInfo() const {
 	Container::dumpInfo();
 
@@ -1664,6 +1710,7 @@ uint32 Actor::I_createActorCru(const uint8 *args, unsigned int /*argsize*/) {
 		return 0;
 
 	uint16 dtableidx = other->getNpcNum();
+
 	const NPCDat *npcData = GameData::get_instance()->getNPCData(dtableidx);
 	if (!npcData)
 		return 0;
@@ -1685,21 +1732,29 @@ uint32 Actor::I_createActorCru(const uint8 *args, unsigned int /*argsize*/) {
 		return 0;
 	}
 
-	newactor->setStr(npcData->getMaxHp() / 2);
+	// Most of these will be overwritten below, but this is cleaner..
+	bool loaded = newactor->loadMonsterStats();
+	if (!loaded) {
+		perr << "I_createActorCru failed to load monster stats ("
+			 << npcData->getShapeNo() << ")." << Std::endl;
+		return 0;
+	}
+
 	newactor->setDir(dir);
 
 	int32 x, y, z;
 	item->getLocation(x, y, z);
 	newactor->move(x, y, z);
 
+	newactor->setDefaultActivity(0, other->getQuality() >> 8);
+	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->setField0x06(other->getQuality() >> 8);
-	 newactor->setField0x08(item->getQuality() >> 8);
-	 newactor->setField0x0A(other->getMapArray());
 	 newactor->setField0x63(item->getQuality() & 0xff);
 
 	 uint16 wpnType = npcData->getWpnType();
@@ -1778,5 +1833,54 @@ uint32 Actor::I_setEquip(const uint8 *args, unsigned int /*argsize*/) {
 	return 1;
 }
 
+uint32 Actor::I_setDefaultActivity0(const uint8 *args, unsigned int /*argsize*/) {
+	ARG_ACTOR_FROM_PTR(actor);
+	ARG_UINT16(activity);
+	if (!actor) return 0;
+
+	actor->setDefaultActivity(0, activity);
+	return 0;
+}
+
+uint32 Actor::I_setDefaultActivity1(const uint8 *args, unsigned int /*argsize*/) {
+	ARG_ACTOR_FROM_PTR(actor);
+	ARG_UINT16(activity);
+	if (!actor) return 0;
+
+	actor->setDefaultActivity(1, activity);
+	return 0;
+}
+
+uint32 Actor::I_setDefaultActivity2(const uint8 *args, unsigned int /*argsize*/) {
+	ARG_ACTOR_FROM_PTR(actor);
+	ARG_UINT16(activity);
+	if (!actor) return 0;
+
+	actor->setDefaultActivity(2, activity);
+	return 0;
+}
+
+uint32 Actor::I_getDefaultActivity0(const uint8 *args, unsigned int /*argsize*/) {
+	ARG_ACTOR_FROM_PTR(actor);
+	if (!actor) return 0;
+
+	return actor->getDefaultActivity(0);
+}
+
+uint32 Actor::I_getDefaultActivity1(const uint8 *args, unsigned int /*argsize*/) {
+	ARG_ACTOR_FROM_PTR(actor);
+	if (!actor) return 0;
+
+	return actor->getDefaultActivity(1);
+}
+
+uint32 Actor::I_getDefaultActivity2(const uint8 *args, unsigned int /*argsize*/) {
+	ARG_ACTOR_FROM_PTR(actor);
+	if (!actor) return 0;
+
+	return actor->getDefaultActivity(2);
+}
+
+
 } // End of namespace Ultima8
 } // End of namespace Ultima
diff --git a/engines/ultima/ultima8/world/actors/actor.h b/engines/ultima/ultima8/world/actors/actor.h
index 337667cb8d..f8a54d6cb5 100644
--- a/engines/ultima/ultima8/world/actors/actor.h
+++ b/engines/ultima/ultima8/world/actors/actor.h
@@ -136,8 +136,9 @@ public:
 		_actorFlags &= ~mask;
 	}
 
-	//! set stats from MonsterInfo (hp, dex, _alignment, _enemyAlignment)
-	//! \return true if a MonsterInfo struct was found, false otherwise
+	//! set stats from MonsterInfo (hp, dex, alignment, enemyAlignment)
+	//! in Crusader this comes from the NPC Data
+	//! \return true if info was found, false otherwise
 	bool loadMonsterStats();
 
 	//! add treasure according to the TreasureInfo in the MonsterInfo
@@ -162,6 +163,9 @@ public:
 	uint16 getDamageType() const override;
 	virtual int getDamageAmount() const;
 
+	void setDefaultActivity(int no, uint16 activity);
+	uint16 getDefaultActivity(int no) const;
+
 	//! calculate the damage an attack against this Actor does.
 	//! \param other the attacker (can be zero)
 	//! \param damage base damage
@@ -279,6 +283,12 @@ public:
 	INTRINSIC(I_schedule);
 	INTRINSIC(I_getEquip);
 	INTRINSIC(I_setEquip);
+	INTRINSIC(I_setDefaultActivity0);
+	INTRINSIC(I_setDefaultActivity1);
+	INTRINSIC(I_setDefaultActivity2);
+	INTRINSIC(I_getDefaultActivity0);
+	INTRINSIC(I_getDefaultActivity1);
+	INTRINSIC(I_getDefaultActivity2);
 
 	enum ActorFlags {
 		ACT_INVINCIBLE     = 0x000001, // flags from npcdata byte 0x1B
@@ -318,6 +328,9 @@ protected:
 
 	uint32 _actorFlags;
 
+	//! the 3 default NPC activities from Crusader
+	uint16 _defaultActivity[3];
+
 	//! starts an activity (Ultima 8 version)
 	//! \return processID of process handling the activity or zero
 	uint16 setActivityU8(int activity);
@@ -326,6 +339,9 @@ protected:
 	//! \return processID of process handling the activity or zero
 	uint16 setActivityCru(int activity);
 
+	bool loadMonsterStatsU8();
+	bool loadMonsterStatsCru();
+
 };
 
 } // End of namespace Ultima8
diff --git a/engines/ultima/ultima8/world/actors/loiter_process.cpp b/engines/ultima/ultima8/world/actors/loiter_process.cpp
index 42a3e2f335..e2731f3f59 100644
--- a/engines/ultima/ultima8/world/actors/loiter_process.cpp
+++ b/engines/ultima/ultima8/world/actors/loiter_process.cpp
@@ -26,6 +26,7 @@
 #include "ultima/ultima8/world/actors/pathfinder_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 {
@@ -41,7 +42,10 @@ LoiterProcess::LoiterProcess(Actor *actor, int32 c) : _count(c) {
 	assert(actor);
 	_itemNum = actor->getObjId();
 
-	_type = 0x205; // CONSTANT!
+	if (GAME_IS_U8)
+		_type = 0x205; // CONSTANT!
+	else
+		_type = 599;
 }
 
 void LoiterProcess::run() {
diff --git a/engines/ultima/ultima8/world/actors/npc_dat.cpp b/engines/ultima/ultima8/world/actors/npc_dat.cpp
index 9f99f03c37..b9e206ba42 100644
--- a/engines/ultima/ultima8/world/actors/npc_dat.cpp
+++ b/engines/ultima/ultima8/world/actors/npc_dat.cpp
@@ -39,10 +39,17 @@ NPCDat::NPCDat(Common::SeekableReadStream &rs, Common::SeekableReadStream &namer
 	rs.skip(22);
 	// offset 0x1a (26): wpntype
 	_wpnType = rs.readUint16LE();
+	rs.skip(2);
+	// offset 30: default activity 0x6
+	_defaultActivity[0] = rs.readUint16LE();
 	// offset 0x3e (62): shape
-	rs.skip(62 - 28);
+	rs.skip(62 - 32);
 	_shapeNo = rs.readUint16LE();
-	rs.skip(142 - 64);
+	// offset 64: default activity 0x8
+	_defaultActivity[1] = rs.readUint16LE();
+	// offset 66: default activity 0xA
+	_defaultActivity[2] = rs.readUint16LE();
+	rs.skip(142 - 68);
 }
 
 /*static*/
diff --git a/engines/ultima/ultima8/world/actors/npc_dat.h b/engines/ultima/ultima8/world/actors/npc_dat.h
index 9779082e24..d5af113163 100644
--- a/engines/ultima/ultima8/world/actors/npc_dat.h
+++ b/engines/ultima/ultima8/world/actors/npc_dat.h
@@ -54,6 +54,11 @@ public:
 		return _wpnType;
 	};
 
+	uint16 getDefaultActivity(int no) const {
+		assert(no >= 0 && no < 3);
+		return _defaultActivity[no];
+	}
+
 private:
     NPCDat(Common::SeekableReadStream &datars, Common::SeekableReadStream &namers);
 
@@ -62,6 +67,7 @@ private:
 	uint16 _maxHp;
 	uint16 _shapeNo;
 	uint16 _wpnType;
+	uint16 _defaultActivity[3];  // activities 0x6, 0x8, and 0xA in game.
 };
 
 } // End of namespace Ultima8




More information about the Scummvm-git-logs mailing list