[Scummvm-git-logs] scummvm master -> c97fa9442031fb908911c96809217b675d759d59

mduggan mgithub at guarana.org
Thu Jun 18 05:05:41 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:
c97fa94420 ULTIMA8: Support more Crusader intrinsic. Fix function names while I'm at it.


Commit: c97fa9442031fb908911c96809217b675d759d59
    https://github.com/scummvm/scummvm/commit/c97fa9442031fb908911c96809217b675d759d59
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-06-18T14:05:28+09:00

Commit Message:
ULTIMA8: Support more Crusader intrinsic. Fix function names while I'm at it.

Changed paths:
    engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
    engines/ultima/ultima8/usecode/remorse_intrinsics.h
    engines/ultima/ultima8/usecode/u8_intrinsics.h
    engines/ultima/ultima8/world/actors/actor.cpp
    engines/ultima/ultima8/world/actors/actor.h
    engines/ultima/ultima8/world/actors/actor_anim_process.cpp
    engines/ultima/ultima8/world/camera_process.cpp
    engines/ultima/ultima8/world/camera_process.h
    engines/ultima/ultima8/world/item.cpp
    engines/ultima/ultima8/world/item.h
    engines/ultima/ultima8/world/monster_egg.cpp


diff --git a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
index 427a50d156..dcb495cd2c 100644
--- a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
+++ b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
@@ -91,7 +91,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"int16 Item::I_getY(Item *)",
 	"void AudioProcess::I_playSFXCru(Item *, uint16 sfxnum)",
 	"int16 Item::I_getShape(Item *)", // in STEAMBOX::func0A, is compared to 0x511 (the STEAM2 shape number) to determine direction
-	"void Intrinsic017(8 bytes)",
+	"void Item::I_explode(Item *, exptype, destroy_item)",
 	"int16 UCMachine::I_rndRange(uint16 x, uint16 y)", // // probably.. always called with 2 constants, then result often compared to some number between
 	"byte Item::I_legalCreateAtCoords(Item *, int16 shapeno, int16 frame, int16 x, int16 y, int16 z)", // probably, see usage in DOOR2::ordinal37
 	"void Item::I_andStatus(Item *, uint16 status)", // part of same coff set 01A, 031, 069, 06E, 099, 0B2, 0BF, 0C1, 0C3, 0E9, 0FC, 101, 104, 106, 108, 10A, 10C, 10E, 110, 114, 117, 11A, 128, 132. Always associated with a bitwise-not or bitmask
@@ -108,7 +108,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"void Item::I_setShape(Item *, int16 shapeno)", // probably. See PEPSIEW::gotHit.
 	"void Item::I_touch(Item *)", // same code as U8
 	"int16 Item::I_getQHi(Item *)", // guess, based on variable name in BOUNCBOX::gotHit
-	"int16 I_getClosestDirectionInRange(x1, y1, x2, y2, numdirs, aa, bb)",  // TODO: understand the decompile of this better.. what is it doing with aa and bb?
+	"int16 I_getClosestDirectionInRange(x1, y1, x2, y2, numdirs, mindir, maxdir)",
 	"int16 Item::I_hurl(Item *,8 bytes)", // part of same coff set 028, 08D, 0BD, 0C0, 0C2, 0C8, 0F7, 0F9, 118, 11D
 	"int16 Game::I_getDifficultyLevel(void)",
 	"void AudioProcess::I_playAmbientSFXCru(Item *, sndno)",
@@ -132,10 +132,10 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"void Item::I_setQLo(Item *, int16 qlo)", // probably setQLo, see usage in FREE::ordinal2E where object position is copied.  Disassembly confirms.
 	"int16 Item::I_getItemFamily(Item *)", // based on disasm
 	"void Container::I_destroyContents(Item *)",
-	"void Item::I_fallProbably(Item *)", // similar disasm to U8, but not totally the same.
+	"void Item::I_fallProbably_03E(Item *)", // similar disasm to U8, but not totally the same.
 	"int16 Egg::I_getEggId(Item *)", // from disasm
 	// 0040
-	"void CameraProcess::I_move_to(x, y, z)",
+	"void CameraProcess::I_moveTo(x, y, z)",
 	"void CameraProcess::I_setCenterOn(objid)",
 	"byte Intrinsic042(6 bytes)",
 	"void AudioProcess::I_playSFXCru(Item *, soundno)", // TODO: Work out how this is different from Int015 - to a first approximation they are quite similar.
@@ -157,7 +157,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"void Intrinsic052(6 bytes)",
 	"void I_SetNPCDataField0x8_053(Actor *, int)",
 	"void I_SetNPCDataField0xA_054(Actor *, int)",
-	"void I_NPCSetActivityProbably_055(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
+	"void Actor::I_setActivity(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
 	"void Intrinsic056(2 bytes)",
 	"int16 Item::I_getSOMETHING_57(Item *)",
 	"byte Item::Item::I_isCentreOn(Item *, uint16 other)",
@@ -199,7 +199,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"int16 PaletteFaderProcess::I_fadeFromBlack(void)", // from black, no arg (40 frames)
 	"void Actor::I_clrImmortal(Actor *)", // same coff as 130
 	"int16 I_GetNPCDataField0_07C(Actor *)",
-	"void I_NPCSetActivityProbably_07D(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
+	"void Actor::I_setActivity(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
 	"int16 Item::I_getQuality(Item *)", // based on disassembly
 	"void Item::I_setQuality(Item *, int)", // based on disassembly. same coff as 0BA, 125
 	// 0080
@@ -243,7 +243,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"void Egg::I_setEggXRange(Egg *, int)", // based on disasm
 	"byte Item::I_overlaps(Item *, uint16 unk)", // same disasm as U8
 	"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 I_getAnimationsDiabled(void)", // From disasm. Not implemented, that's ok..
+	"int16 I_getAnimationsDisabled(void)", // From disasm. Not implemented, that's ok..
 	"int16 Egg::I_getEggXRange(Egg *)", // based on disasm
 	"void Actor::I_setDead(Actor *)", // part of same coff set 021, 060, 073, 0A0, 0A8, 0D8, 0E7, 135
 	"void I_playFlic0A9(char *)", // same coff as 092
@@ -284,7 +284,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"byte Actor::I_addHp(Actor *, int)",
 	"void Intrinsic0CB(2 bytes)",
 	"byte I_GetNPCDataField0x59Flag3_0CC(Actor *)",
-	"void I_NPCSetActivityProbably_0CD(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
+	"void Actor::I_setActivity(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
 	"int16 Game::I_isReleaseBuild(void)", // whether the string "GAME COMPILE=1" has the 1.  Might be interesting to see what this does..
 	"void Item::setQAndCallSomething(Item *, int16 q)", // based on disassembly
 	// 00D0
@@ -299,7 +299,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"void Actor::I_setDead(4 bytes)", // part of same coff set 021, 060, 073, 0A0, 0A8, 0D8, 0E7, 135
 	"int16 Item::I_getQLo(Item *)", // same as 02B based on same coff set 010, 02B, 066, 084, 0A1, 0AE, 0D9, 0EA
 	"void Intrinsic0DA_Fade(void)", // something about fades
-	"void I_NPCSetActivityProbably_0DB(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
+	"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 I_GetNPCDataField0x4_0DD(Actor *)",
 	"void I_SetNPCDataField0x5c_0DE(Actor *, int)",
@@ -324,11 +324,11 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	// 00F0
 	"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
 	"byte Item::I_isOn(Item *, itemno)", // part of same coff set 044, 046, 048, 04A, 04C, 04E, 0A5, 0BC, 0C5, 0DC, 0F1, 0FA, 12C
-	"void I_NPCSetActivityProbably_0F2(Actor *, int)(6 bytes)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
+	"void Actor::I_setActivity(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
 	"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
 	"int16 Item::I_getQ(Item *)", // based on disassembly
 	"void Item::I_setQ(Item *, uint16 q)", // based on disassembly
-	"void Intrinsic0F6(void)",
+	"void CruHealer::I_create_0F6(void)",
 	"int16 Item::I_hurl(Item *,8 bytes)", // part of same coff set 028, 08D, 0BD, 0C0, 0C2, 0C8, 0F7, 0F9, 118, 11D
 	"int16 Item::I_getNPCNum(Item *)", // part of same coff set 067, 06D, 089, 08E, 0AD, 0F8, 100, 102, 105, 107, 109, 10B, 10D, 10F, 111, 115, 11C, 123, 129
 	"int16 Item::I_hurl(Item *,8 bytes)", // part of same coff set 028, 08D, 0BD, 0C0, 0C2, 0C8, 0F7, 0F9, 118, 11D
@@ -391,7 +391,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"int16 MonsterEgg::I_monsterEggHatch(Item *, uint16 other_itemno)",
 	// 0130
 	"void Actor::I_clrImmortal(Actor *)", // same coff as 07B
-	"void I_NPCSetActivityProbably_131(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
+	"void Actor::I_setActivity(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
 	"void Item::I_andStatus(Item *, int16 status)", // part of same coff set 01A, 031, 069, 06E, 099, 0B2, 0BF, 0C1, 0C3, 0E9, 0FC, 101, 104, 106, 108, 10A, 10C, 10E, 110, 114, 117, 11A, 128, 132
 	"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
 	"void Intrinsic134(2 bytes)",
diff --git a/engines/ultima/ultima8/usecode/remorse_intrinsics.h b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
index 0e17108225..f43b27379c 100644
--- a/engines/ultima/ultima8/usecode/remorse_intrinsics.h
+++ b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
@@ -59,7 +59,7 @@ Intrinsic RemorseIntrinsics[] = {
 	Item::I_getY, //int Intrinsic014(4 bytes) // probably - see FREE::ordinal34
 	AudioProcess::I_playSFXCru, // pretty sure, see SWITCH::ordinal21 which plays various sfx related to access status
 	Item::I_getShape, // in STEAMBOX::func0A, is compared to 0x511 (the STEAM2 shape number) to determine direction
-	0, // void Intrinsic017(8 bytes)
+	Item::I_explode, // void Intrinsic017(8 bytes)
 	UCMachine::I_rndRange, // int16 Intrinsic018(4 bytes) // probably.. always called with 2 constants, then result compared to some number between
 	Item::I_legalCreateAtCoords, // byte Intrinsic019(14 bytes),  probably, see usage in DOOR2::ordinal37
 	Item::I_andStatus, // void Intrinsic01A(6 bytes)
@@ -100,10 +100,10 @@ Intrinsic RemorseIntrinsics[] = {
 	Item::I_setQLo,
 	Item::I_getFamily,
 	Container::I_destroyContents,
-	0, // void Intrinsic03E(4 bytes)
+	Item::I_fall, // FIXME: Not really the same as the U8 version.. does this work?
 	Egg::I_getEggId, // void Intrinsic03F(4 bytes)
 	// 0x040
-	CameraProcess::I_move_to, // void Intrinsic040(8 bytes)
+	CameraProcess::I_moveTo, // void Intrinsic040(8 bytes)
 	CameraProcess::I_setCenterOn, // void Intrinsic041(2 bytes)
 	0, // int Intrinsic042(6 bytes)
 	AudioProcess::I_playSFXCru, // TODO: Work out how this is different from Int015 - to a first approximation they are quite similar.
@@ -125,7 +125,7 @@ Intrinsic RemorseIntrinsics[] = {
 	0, // void Intrinsic052(6 bytes)
 	0, // void Intrinsic053(6 bytes)
 	0, // void Intrinsic054(6 bytes)
-	0, // void Intrinsic055(6 bytes)
+	Actor::I_setActivity, // void Intrinsic055(6 bytes)
 	0, // void Intrinsic056(2 bytes)
 	0, // void Intrinsic057(4 bytes)
 	Item::I_isCentreOn, // int Intrinsic058(6 bytes)
@@ -167,7 +167,7 @@ Intrinsic RemorseIntrinsics[] = {
 	PaletteFaderProcess::I_fadeFromBlack, // void Intrinsic07A(void)
 	Actor::I_clrImmortal, // based on disasm
 	0, // void Intrinsic07C(4 bytes) // I_getQIfSomething, see disassembly
-	0, // void Intrinsic07D(6 bytes)
+	Actor::I_setActivity, // void Intrinsic07D(6 bytes)
 	Item::I_getQuality,
 	Item::I_setQuality,
 	// 0x080
@@ -211,7 +211,7 @@ Intrinsic RemorseIntrinsics[] = {
 	Egg::I_setEggXRange, // void Intrinsic0A3(6 bytes)
 	Item::I_overlaps,
 	Item::I_isOn,
-	0, // TODO: I_getAnimationsDiabled -> default to 0 (fine for now..)
+	0, // TODO: I_getAnimationsDisabled -> default to 0 (fine for now..)
 	Egg::I_getEggXRange, // void Intrinsic0A7(4 bytes)
 	Actor::I_setDead,
 	0, // I_playFlic(char *) Intrinsic0A9(void)
@@ -252,7 +252,7 @@ Intrinsic RemorseIntrinsics[] = {
 	Actor::I_setHp, // int Intrinsic0CA(6 bytes)
 	0, // void Intrinsic0CB(2 bytes)
 	0, // int Intrinsic0CC(4 bytes)
-	0, // void Intrinsic0CD(6 bytes)
+	Actor::I_setActivity, // void Intrinsic0CD(6 bytes)
 	UCMachine::I_true, // whether the string "GAME COMPILE=1" has the 1.  Might be interesting to see how this changes the game.. for now just set to true.
 	0, // void Intrinsic0CF(6 bytes)
 	// 0x0D0
@@ -267,7 +267,7 @@ Intrinsic RemorseIntrinsics[] = {
 	Actor::I_setDead,
 	Item::I_getQLo, // based on same coff set as 02B
 	0, // void Intrinsic0DA(void)
-	0, // void Intrinsic0DB(6 bytes)
+	Actor::I_setActivity, // void Intrinsic0DB(6 bytes)
 	Item::I_isOn,
 	0, // void Intrinsic0DD(4 bytes)
 	0, // void Intrinsic0DE(6 bytes)
@@ -292,11 +292,11 @@ Intrinsic RemorseIntrinsics[] = {
 	// 0x0F0
 	Item::I_getQHi,  // based on same coff set as 026
 	Item::I_isOn,
-	0, // void Intrinsic0F2(6 bytes)
+	Actor::I_setActivity, // void Intrinsic0F2(6 bytes)
 	Item::I_getQHi,  // based on same coff set as 026
 	Item::I_getQ, // void Intrinsic0F4(4 bytes)
 	Item::I_setQ, // void Intrinsic0F5(6 bytes)
-	0, // void Intrinsic0F6(void)
+	0, // TODO: Implement CruHealer::I_create
 	Item::I_hurl, // void Intrinsic0F7(12 bytes)
 	Item::I_getNpcNum, // based on same coff as 102 (-> variable name in TRIGGER::ordinal21)
 	Item::I_hurl, // void Intrinsic0F9(12 bytes)
@@ -359,7 +359,7 @@ Intrinsic RemorseIntrinsics[] = {
 	MonsterEgg::I_monsterEggHatch, // void Intrinsic12F(6 bytes) - FIXME: this is pretty different .. will it work?
 	// 0x130
 	Actor::I_clrImmortal, // void Intrinsic130(4 bytes)
-	0, // void Intrinsic131(6 bytes)
+	Actor::I_setActivity, // void Intrinsic131(6 bytes)
 	Item::I_andStatus, // void Intrinsic132(6 bytes)
 	Item::I_getQHi,  // based on same coff set as 026
     0, // void Intrinsic134(2 bytes)
diff --git a/engines/ultima/ultima8/usecode/u8_intrinsics.h b/engines/ultima/ultima8/usecode/u8_intrinsics.h
index 0d423e295c..a59f86696f 100644
--- a/engines/ultima/ultima8/usecode/u8_intrinsics.h
+++ b/engines/ultima/ultima8/usecode/u8_intrinsics.h
@@ -240,7 +240,7 @@ Intrinsic U8Intrinsics[] = {
 	Actor::I_setHp,
 	Actor::I_setMana,
 	Actor::I_createActor,
-	Actor::I_cSetActivity,
+	Actor::I_setActivity,
 	Actor::I_setAirWalkEnabled,
 	// 0x0B0
 	Actor::I_getAirWalkEnabled,
@@ -258,7 +258,7 @@ Intrinsic U8Intrinsics[] = {
 	UCMachine::I_getName, //temp
 	Item::I_igniteChaos,
 	CameraProcess::I_setCenterOn,
-	CameraProcess::I_move_to,
+	CameraProcess::I_moveTo,
 	// 0x0C0
 	0, //U
 	0, //U
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 3937fa08eb..7067f382a8 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -423,6 +423,8 @@ void Actor::teleport(int newmap, int32 newx, int32 newy, int32 newz) {
 		_y = newy;
 		_z = newz;
 	}
+	if (GAME_IS_CRUSADER)
+		notifyNearbyItems();
 }
 
 uint16 Actor::doAnim(Animation::Sequence anim, int dir, unsigned int steps) {
@@ -507,7 +509,14 @@ Animation::Result Actor::tryAnim(Animation::Sequence anim, int dir,
 	return Animation::END_OFF_LAND;
 }
 
-uint16 Actor::cSetActivity(int activity) {
+uint16 Actor::setActivity(int activity) {
+	if (GAME_IS_CRUSADER)
+		return setActivityCru(activity);
+	else
+		return setActivityU8(activity);
+}
+
+uint16 Actor::setActivityU8(int activity) {
 	switch (activity) {
 	case 0: // loiter
 		Kernel::get_instance()->addProcess(new LoiterProcess(this));
@@ -521,13 +530,54 @@ uint16 Actor::cSetActivity(int activity) {
 		return doAnim(Animation::stand, 8);
 
 	default:
-		perr << "Actor::cSetActivity: invalid activity (" << activity << ")"
+		perr << "Actor::setActivityU8: invalid activity (" << activity << ")"
+		     << Std::endl;
+	}
+
+	return 0;
+}
+
+uint16 Actor::setActivityCru(int activity) {
+	if (isDead())
+		return 0;
+
+	switch (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)
+	case 2: // loiter
+		Kernel::get_instance()->addProcess(new LoiterProcess(this));
+		return Kernel::get_instance()->addProcess(new DelayProcess(1));
+	case 4:
+	case 6:
+	    // Does nothing in game..
+	    break;
+	case 7:
+		perr << "Actor::setActivityCru TODO: Implement new SurrenderProcess(this);";
+	    break;
+	case 8:
+		perr << "Actor::setActivityCru TODO: Implement new GuardProcess(this);";
+	    break;
+	case 5:
+	case 9:
+	case 10:
+	case 0xb:
+	case 0xc:
+		// attack
+	   setInCombat();
+	   return 0;
+
+	default:
+		perr << "Actor::setActivityCru: invalid activity (" << activity << ")"
 		     << Std::endl;
 	}
 
 	return 0;
 }
 
+
 uint32 Actor::getArmourClass() const {
 	const ShapeInfo *si = getShapeInfo();
 	if (si->_monsterInfo)
@@ -1002,6 +1052,26 @@ void Actor::clearInCombat() {
 	clearActorFlag(ACT_INCOMBAT);
 }
 
+int32 Actor::collideMove(int32 x, int32 y, int32 z, bool teleport, bool force,
+						 ObjId *hititem, uint8 *dirs) {
+	int32 result = Item::collideMove(x, y, z, teleport, force, hititem, dirs);
+	if (GAME_IS_CRUSADER)
+		notifyNearbyItems();
+	return result;
+}
+
+void Actor::notifyNearbyItems() {
+	UCList uclist(2);
+	LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
+	CurrentMap *currentmap = World::get_instance()->getCurrentMap();
+	currentmap->areaSearch(&uclist, script, sizeof(script), this, 0x40, false);
+
+	for (unsigned int i = 0; i < uclist.getSize(); ++i) {
+		Item *item = getItem(uclist.getuint16(i));
+		item->callUsecodeEvent_npcNearby(_objId);
+	}
+}
+
 bool Actor::areEnemiesNear() {
 	UCList uclist(2);
 	LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
@@ -1571,12 +1641,12 @@ uint32 Actor::I_createActor(const uint8 *args, unsigned int /*argsize*/) {
 	return objID;
 }
 
-uint32 Actor::I_cSetActivity(const uint8 *args, unsigned int /*argsize*/) {
+uint32 Actor::I_setActivity(const uint8 *args, unsigned int /*argsize*/) {
 	ARG_ACTOR_FROM_PTR(actor);
 	ARG_UINT16(activity);
 	if (!actor) return 0;
 
-	return actor->cSetActivity(activity);
+	return actor->setActivity(activity);
 }
 
 uint32 Actor::I_setAirWalkEnabled(const uint8 *args, unsigned int /*argsize*/) {
diff --git a/engines/ultima/ultima8/world/actors/actor.h b/engines/ultima/ultima8/world/actors/actor.h
index 90b89840d5..9eae47520b 100644
--- a/engines/ultima/ultima8/world/actors/actor.h
+++ b/engines/ultima/ultima8/world/actors/actor.h
@@ -189,9 +189,12 @@ public:
 	//! check if NPCs are near which are in combat mode and hostile
 	bool areEnemiesNear();
 
+	//! check if NPCs are near which are in combat mode and hostile
+	void notifyNearbyItems();
+
 	//! starts an activity
 	//! \return processID of process handling the activity or zero
-	uint16 cSetActivity(int activity);
+	uint16 setActivity(int activity);
 
 	//! run the given animation
 	//! \return the PID of the ActorAnimProcess
@@ -209,6 +212,10 @@ public:
 	//! \param state the state to start from, or 0 to use the current state
 	Animation::Result tryAnim(Animation::Sequence anim, int dir, unsigned int steps = 0, PathfindingState *state = 0);
 
+	//! overrides the standard item collideMove so we  can notify nearby objects.
+	int32 collideMove(int32 x, int32 y, int32 z, bool teleport, bool force,
+	                  ObjId *hititem = 0, uint8 *dirs = 0) override;
+
 	//! create an actor, assign objid, make it ethereal and load monster stats.
 	static Actor *createActor(uint32 shape, uint32 frame);
 
@@ -265,7 +272,7 @@ public:
 	INTRINSIC(I_areEnemiesNear);
 	INTRINSIC(I_isBusy);
 	INTRINSIC(I_createActor);
-	INTRINSIC(I_cSetActivity);
+	INTRINSIC(I_setActivity);
 	INTRINSIC(I_setAirWalkEnabled);
 	INTRINSIC(I_getAirWalkEnabled);
 	INTRINSIC(I_schedule);
@@ -309,6 +316,15 @@ protected:
 	uint8 _unk0C; // unknown byte 0x0C from npcdata.dat
 
 	uint32 _actorFlags;
+
+	//! starts an activity (Ultima 8 version)
+	//! \return processID of process handling the activity or zero
+	uint16 setActivityU8(int activity);
+
+	//! starts an activity (Crusader version)
+	//! \return processID of process handling the activity or zero
+	uint16 setActivityCru(int activity);
+
 };
 
 } // End of namespace Ultima8
diff --git a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
index 40a695caff..fbb28d596c 100644
--- a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
+++ b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
@@ -32,6 +32,7 @@
 #include "ultima/ultima8/world/world.h"
 #include "ultima/ultima8/world/gravity_process.h"
 #include "ultima/ultima8/kernel/kernel.h"
+#include "ultima/ultima8/kernel/core_app.h"
 #include "ultima/ultima8/usecode/uc_list.h"
 #include "ultima/ultima8/world/loop_script.h"
 #include "ultima/ultima8/world/current_map.h"
@@ -416,11 +417,11 @@ void ActorAnimProcess::doSpecial() {
 	}
 
 	// ghost's fireball
-	if (a->getShape() == 0x19d) {
+	if (a->getShape() == 0x19d && GAME_IS_U8) {
 		Actor *av = getMainActor();
 		if (a->getRange(*av) < 96) {
 			a->setActorFlag(Actor::ACT_DEAD);
-			a->explode(); // explode if close to the avatar
+			a->explode(0, true); // explode if close to the avatar
 		}
 		return;
 	}
diff --git a/engines/ultima/ultima8/world/camera_process.cpp b/engines/ultima/ultima8/world/camera_process.cpp
index 02db2facaf..2deb55dc24 100644
--- a/engines/ultima/ultima8/world/camera_process.cpp
+++ b/engines/ultima/ultima8/world/camera_process.cpp
@@ -313,7 +313,7 @@ bool CameraProcess::loadData(Common::ReadStream *rs, uint32 version) {
 }
 
 //	"Camera::move_to(uword, uword, ubyte, word)",
-uint32 CameraProcess::I_move_to(const uint8 *args, unsigned int argsize) {
+uint32 CameraProcess::I_moveTo(const uint8 *args, unsigned int argsize) {
 	ARG_UINT16(x);
 	ARG_UINT16(y);
 	ARG_UINT8(z);
diff --git a/engines/ultima/ultima8/world/camera_process.h b/engines/ultima/ultima8/world/camera_process.h
index 3aa6e5027e..4b0c6a20f4 100644
--- a/engines/ultima/ultima8/world/camera_process.h
+++ b/engines/ultima/ultima8/world/camera_process.h
@@ -62,7 +62,7 @@ public:
 	uint16 FindRoof(int32 factor);
 
 	INTRINSIC(I_setCenterOn);
-	INTRINSIC(I_move_to);
+	INTRINSIC(I_moveTo);
 	INTRINSIC(I_scrollTo);
 	INTRINSIC(I_startQuake);
 	INTRINSIC(I_stopQuake);
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index 0e03456b73..1cbe2e7266 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -1184,6 +1184,12 @@ uint32 Item::callUsecodeEvent_equip() {                           // event A
 	return callUsecodeEvent(0xA); // CONSTANT
 }
 
+uint32 Item::callUsecodeEvent_npcNearby(ObjId npc) {                           // event A
+	DynamicUCStack  arg_stack(2);
+	arg_stack.push2(npc);
+	return callUsecodeEvent(0xA, arg_stack.access(), 2);
+}
+
 uint32 Item::callUsecodeEvent_unequip() {                           // event B
 	return callUsecodeEvent(0xB); // CONSTANT
 }
@@ -1601,20 +1607,54 @@ void Item::hurl(int xs, int ys, int zs, int grav) {
 }
 
 
-void Item::explode() {
-	Process *p = new SpriteProcess(578, 20, 34, 1, 1, //!! constants
+void Item::explode(int explosion_type, bool destroy_item) {
+	Process *p;
+
+	if (GAME_IS_CRUSADER) {
+		// TODO: original game puts them at cx/cy/cz, but that looks wrong..
+		//int32 cx, cy, cz;
+		//getCentre(cx, cy, cz);
+		static const int expshapes[] = {0x31C, 0x31F, 0x326, 0x320, 0x321, 0x324, 0x323, 0x325};
+		int rnd = getRandom();
+		int spriteno;
+		// NOTE: The game does some weird 32-bit struff to decide what
+		// shapenum to use.  Just simplified to a random.
+		switch (explosion_type) {
+		case 0:
+			spriteno = expshapes[rnd % 2];
+			break;
+		case 1:
+			spriteno = expshapes[2 + rnd % 3];
+			break;
+		case 2:
+		default:
+			spriteno = expshapes[5 + rnd % 3];
+			break;
+		}
+		p = new SpriteProcess(spriteno, 0, 39, 1, 1, //!! constants
 	                               _x, _y, _z);
+	} else {
+		p = new SpriteProcess(578, 20, 34, 1, 1, //!! constants
+	                               _x, _y, _z);
+	}
 	Kernel::get_instance()->addProcess(p);
 
-	int sfx = (getRandom() % 2) ? 31 : 158;
+	int sfx;
+	if (GAME_IS_CRUSADER)
+		sfx = (getRandom() % 2) ? 28 : 108;
+	else
+		sfx = (getRandom() % 2) ? 31 : 158;
+
 	AudioProcess *audioproc = AudioProcess::get_instance();
 	if (audioproc) audioproc->playSFX(sfx, 0x60, 0, 0);
 
 	int32 xv, yv, zv;
 	getLocation(xv, yv, zv);
 
-	destroy(); // delete self
-	// WARNING: we are deleted at this point
+	if (destroy_item) {
+		destroy(); // delete self
+		// WARNING: we are deleted at this point
+	}
 
 	UCList itemlist(2);
 	LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
@@ -1650,7 +1690,7 @@ void Item::receiveHit(uint16 other, int dir, int damage, uint16 type) {
 
 	// explosive?
 	if (getShapeInfo()->is_explode()) {
-		explode(); // warning: deletes this
+		explode(0, true); // warning: deletes this
 		return;
 	}
 
@@ -1989,10 +2029,12 @@ uint32 Item::I_getCX(const uint8 *args, unsigned int /*argsize*/) {
 	int32 x, y, z;
 	item->getLocationAbsolute(x, y, z);
 
+	int mul = ((GAME_IS_CRUSADER) ? 8 : 16);
+
 	if (item->_flags & FLG_FLIPPED)
-		return x - item->getShapeInfo()->_y * 16;
+		return x - item->getShapeInfo()->_y * mul;
 	else
-		return x - item->getShapeInfo()->_x * 16;
+		return x - item->getShapeInfo()->_x * mul;
 }
 
 uint32 Item::I_getCY(const uint8 *args, unsigned int /*argsize*/) {
@@ -2002,10 +2044,12 @@ uint32 Item::I_getCY(const uint8 *args, unsigned int /*argsize*/) {
 	int32 x, y, z;
 	item->getLocationAbsolute(x, y, z);
 
+	int mul = ((GAME_IS_CRUSADER) ? 8 : 16);
+
 	if (item->_flags & FLG_FLIPPED)
-		return y - item->getShapeInfo()->_x * 16;
+		return y - item->getShapeInfo()->_x * mul;
 	else
-		return y - item->getShapeInfo()->_y * 16;
+		return y - item->getShapeInfo()->_y * mul;
 }
 
 uint32 Item::I_getCZ(const uint8 *args, unsigned int /*argsize*/) {
@@ -3110,11 +3154,20 @@ uint32 Item::I_receiveHit(const uint8 *args, unsigned int /*argsize*/) {
 	return 0;
 }
 
-uint32 Item::I_explode(const uint8 *args, unsigned int /*argsize*/) {
+uint32 Item::I_explode(const uint8 *args, unsigned int argsize) {
 	ARG_ITEM_FROM_PTR(item);
 	if (!item) return 0;
 
-	item->explode();
+	int exptype = 0;
+	bool destroy_item = true;
+	if (argsize > 4) {
+		ARG_UINT16(etype)
+		ARG_UINT16(destroy)
+		exptype = etype;
+		destroy_item = (destroy != 0);
+	}
+
+	item->explode(exptype, destroy_item);
 	return 0;
 }
 
diff --git a/engines/ultima/ultima8/world/item.h b/engines/ultima/ultima8/world/item.h
index 7ea968d89b..033755e907 100644
--- a/engines/ultima/ultima8/world/item.h
+++ b/engines/ultima/ultima8/world/item.h
@@ -312,7 +312,7 @@ public:
 	//!          0 = didn't move
 	//!          0x4000 = reached destination
 	//! \note This can destroy the object
-	int32 collideMove(int32 x, int32 y, int32 z, bool teleport, bool force,
+	virtual int32 collideMove(int32 x, int32 y, int32 z, bool teleport, bool force,
 	                  ObjId *hititem = 0, uint8 *dirs = 0);
 
 	//! Make the item move up (delta>0) or down (delta<0),
@@ -359,8 +359,8 @@ public:
 	//! Get the volume this item takes up in a container
 	virtual uint32 getVolume() const;
 
-	//! explode
-	void explode();
+	//! explode with explosion type (0,1,2) and flag of whether to destroy the item.
+	void explode(int explosion_type, bool destroy_item);
 
 	//! get the damage type this object does when hitting something
 	virtual uint16 getDamageType() const;
@@ -398,6 +398,7 @@ public:
 	uint32 callUsecodeEvent_schedule(uint32 time);              // event 8
 	uint32 callUsecodeEvent_release();                          // event 9
 	uint32 callUsecodeEvent_equip();                            // event A
+	uint32 callUsecodeEvent_npcNearby(ObjId npc);               // event A
 	uint32 callUsecodeEvent_unequip();                          // event B
 	uint32 callUsecodeEvent_combine();                          // event C
 	uint32 callUsecodeEvent_enterFastArea();                    // event F
diff --git a/engines/ultima/ultima8/world/monster_egg.cpp b/engines/ultima/ultima8/world/monster_egg.cpp
index bf5cb3fec1..77896b9520 100644
--- a/engines/ultima/ultima8/world/monster_egg.cpp
+++ b/engines/ultima/ultima8/world/monster_egg.cpp
@@ -80,8 +80,7 @@ uint16 MonsterEgg::hatch() {
 	newactor->setMapNum(World::get_instance()->getCurrentMap()->getNum());
 	newactor->setNpcNum(objID);
 	newactor->move(_x, _y, _z);
-
-	newactor->cSetActivity(getActivity());
+	newactor->setActivity(getActivity());
 
 	return objID;
 }




More information about the Scummvm-git-logs mailing list