[Scummvm-git-logs] scummvm master -> 1217a1ebefba8ac95610437f41c927b08f5719c2

mduggan mgithub at guarana.org
Sun Mar 7 01:12:55 UTC 2021


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

Summary:
5a8740c714 ULTIMA8: Update Crudader fireWeapon to closer match original
1217a1ebef ULTIMA8: Update SuperSpriteProcess to more closely match original


Commit: 5a8740c71411c9e753e68e5e7c4b0590d87d3053
    https://github.com/scummvm/scummvm/commit/5a8740c71411c9e753e68e5e7c4b0590d87d3053
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-07T10:08:42+09:00

Commit Message:
ULTIMA8: Update Crudader fireWeapon to closer match original

Changed paths:
    engines/ultima/ultima8/world/actors/actor_anim_process.cpp
    engines/ultima/ultima8/world/item.cpp
    engines/ultima/ultima8/world/item.h


diff --git a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
index 70d664a1f5..91b6aca2fe 100644
--- a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
+++ b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
@@ -494,7 +494,6 @@ void ActorAnimProcess::doFireWeaponCru(Actor *a, const AnimFrame *f) {
 	if (!f->is_cruattack())
 		return;
 
-	// TODO: there is some special casing in the game for larger weapons here..
 	const Item *wpn = getItem(a->getActiveWeapon());
 	if (!wpn)
 		return;
@@ -502,8 +501,12 @@ void ActorAnimProcess::doFireWeaponCru(Actor *a, const AnimFrame *f) {
 	if (!wpninfo || !wpninfo->_weaponInfo)
 		return;
 
+	if (a->getObjId() == 1 && wpninfo->_weaponInfo->_damageType == 6) {
+		warning("TODO: implement AutoFirerProcess for Crusader");
+	}
+
 	a->fireWeapon(f->cru_attackx(), f->cru_attacky(), f->cru_attackz(),
-				  a->getDir(), wpninfo->_weaponInfo->_damageType, 1);
+				  a->getDir(), wpninfo->_weaponInfo->_damageType, true);
 
 	AudioProcess *audioproc = AudioProcess::get_instance();
 	if (audioproc)
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index 56bb6fb5e9..9f3a5a7e15 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -1166,7 +1166,7 @@ int32 Item::collideMove(int32 dx, int32 dy, int32 dz, bool teleport, bool force,
 	return 0;
 }
 
-uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype, char findtarget) {
+uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype, bool findtarget) {
 	int32 ix, iy, iz;
 	getLocation(ix, iy, iz);
 
@@ -1192,104 +1192,108 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
 	// CHECKME: the original doesn't exclude the source like this,
 	// but it seems obvious we have to or NPCs shoot themselves?
 	bool isvalid = currentmap->isValidPosition(ix, iy, iz, BULLET_SPLASH_SHAPE, _objId, nullptr, nullptr, &blocker);
+
 	if (!isvalid && blocker) {
 		Item *block = getItem(blocker->getObjId());
 		Point3 blockpt;
 		block->getLocation(blockpt);
 		Direction damagedir = Direction_GetWorldDir(blockpt.y - iy, blockpt.x - ix, dirmode_8dirs);
 		block->receiveHit(getObjId(), damagedir, damage, firetype);
-		int splashdamage = firetypedat->getRandomDamage();
-		firetypedat->applySplashDamageAround(blockpt, splashdamage, block, this);
-
-		firetypedat->makeBulletSplashShapeAndPlaySound(ix, iy, iz);
-		return 0;
-	} else {
-		int spriteframe = 0;
-		switch (firetype) {
-		case 3:
-		case 9:
-		case 10:
-			spriteframe = dir + 0x11;
-			break;
-		case 5:
-			spriteframe = dir + 1;
-			break;
-		case 6:
-			spriteframe = 0x46;
-			break;
-		case 0xe:
-			spriteframe = 0x47 + getRandom() % 5;
-			break;
-		case 0xf:
-			spriteframe = 0x4c;
-			break;
+		if (firetypedat->getRange() != 0) {
+			int splashdamage = firetypedat->getRandomDamage();
+			firetypedat->applySplashDamageAround(blockpt, splashdamage, block, this);
 		}
+		if (firetypedat->getNearSprite())
+			firetypedat->makeBulletSplashShapeAndPlaySound(ix, iy, iz);
+		return 0;
+	}
 
-		// HACK: this should be fixed to use inheritence so the behavior
-		// is clean for both Item and Actor.
-		DirectionMode dirmode = dirmode_8dirs;
-		const Actor *thisactor = dynamic_cast<Actor *>(this);
-		if (thisactor) {
-			// TODO: Get damage for active inventory item
-			dirmode = thisactor->animDirMode(thisactor->getLastAnim());
-		}
+	int spriteframe = 0; // fire types 1, 2, 0xb, 0xd
+	switch (firetype) {
+	case 3:
+	case 9:
+	case 10:
+		spriteframe = dir + 0x11;
+		break;
+	case 5:
+		spriteframe = dir + 1;
+		break;
+	case 6:
+		spriteframe = 0x46;
+		break;
+	case 0xe:
+		spriteframe = 0x47 + getRandom() % 5;
+		break;
+	case 0xf:
+		spriteframe = 0x4c;
+		break;
+	default:
+		break;
+	}
 
-		Item *target = nullptr;
-		if (findtarget) {
-			if (this != getControlledActor()) {
-				target = getControlledActor();
-			} else {
-				target = currentmap->findBestTargetItem(ix, iy, dir, dirmode);
-			}
-		}
+	// HACK: this should be fixed to use inheritence so the behavior
+	// is clean for both Item and Actor.
+	DirectionMode dirmode = dirmode_8dirs;
+	const Actor *thisactor = dynamic_cast<Actor *>(this);
+	if (thisactor) {
+		// TODO: Get damage for active inventory item if not a weapon?
+		dirmode = thisactor->animDirMode(thisactor->getLastAnim());
+	}
 
-		int32 tx = -1;
-		int32 ty = 0;
-		int32 tz = 0;
-		if (target) {
-			target->getCentre(tx, ty, tz);
-			tz = target->getTargetZRelativeToAttackerZ(getZ());
+	Item *target = nullptr;
+	if (findtarget) {
+		if (this != getControlledActor()) {
+			target = getControlledActor();
+		} else {
+			target = currentmap->findBestTargetItem(ix, iy, dir, dirmode);
 		}
+	}
 
-		// TODO: check if we need the equivalent of FUN_1130_0299 here..
-		// maybe not? It seems to reset the target reticle etc which we
-		// handle differently.
-
-		int numshots = firetypedat->getNumShots();
-		uint16 spriteprocpid = 0;
-		for (int i = 0; i < numshots; i++) {
-			SuperSpriteProcess *ssp;
-			CrosshairProcess *chp = CrosshairProcess::get_instance();
-			assert(chp);
-			Item *crosshair = getItem(chp->getItemNum());
-			int32 ssx, ssy, ssz;
-			if (tx != -1) {
-				// Shoot toward the target
-				ssx = tx;
-				ssy = ty;
-				ssz = tz;
-			} else if (this == getControlledActor() && crosshair) {
-				// Shoot toward the crosshair
-				crosshair->getLocation(ssx, ssy, ssz);
-				ssz = iz;
-			} else {
-				// Just send the projectile off into the distance
-				// CHECKME: This is not how the game does it - it has different
-				// tables (at 1478:129b and 1478:12ac). Check the logic here.
-				ssx = ix + Direction_XFactor(dir) * 0x500;
-				ssy = iy + Direction_YFactor(dir) * 0x500;
-				ssz = iz;
-			}
-
-			uint16 targetid = (target ? target->getObjId() : 0);
-			ssp = new SuperSpriteProcess(BULLET_SPLASH_SHAPE, spriteframe,
-										 ix, iy, iz, ssx, ssy, ssz, firetype,
-										 damage, _objId, targetid, findtarget);
-			Kernel::get_instance()->addProcess(ssp);
-			spriteprocpid = ssp->getPid();
+	int32 tx = -1;
+	int32 ty = 0;
+	int32 tz = 0;
+	if (target) {
+		target->getCentre(tx, ty, tz);
+		tz = target->getTargetZRelativeToAttackerZ(getZ());
+	}
+
+	// TODO: check if we need the equivalent of FUN_1130_0299 here..
+	// maybe not? It seems to reset the target reticle etc which we
+	// handle differently.
+
+	int numshots = firetypedat->getNumShots();
+	uint16 spriteprocpid = 0;
+	for (int i = 0; i < numshots; i++) {
+		SuperSpriteProcess *ssp;
+		CrosshairProcess *chp = CrosshairProcess::get_instance();
+		assert(chp);
+		Item *crosshair = getItem(chp->getItemNum());
+		int32 ssx, ssy, ssz;
+		if (tx != -1) {
+			// Shoot toward the target
+			ssx = tx;
+			ssy = ty;
+			ssz = tz;
+			findtarget = true;
+		} else if (this == getControlledActor() && crosshair) {
+			// Shoot toward the crosshair
+			crosshair->getLocation(ssx, ssy, ssz);
+			ssz = iz;
+		} else {
+			// Just send the projectile off into the distance
+			ssx = ix + Direction_XFactor(dir) * 0x500;
+			ssy = iy + Direction_YFactor(dir) * 0x500;
+			ssz = iz;
 		}
-		return spriteprocpid;
+
+		uint16 targetid = (target ? target->getObjId() : 0);
+		ssp = new SuperSpriteProcess(BULLET_SPLASH_SHAPE, spriteframe,
+									 ix, iy, iz, ssx, ssy, ssz, firetype,
+									 damage, _objId, targetid, findtarget);
+		Kernel::get_instance()->addProcess(ssp);
+		spriteprocpid = ssp->getPid();
 	}
+	return spriteprocpid;
 }
 
 uint16 Item::fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff) {
@@ -3836,11 +3840,11 @@ uint32 Item::I_fireWeapon(const uint8 *args, unsigned int /*argsize*/) {
 	ARG_SINT16(z);
 	ARG_UINT16(dir);
 	ARG_UINT16(firetype);
-	ARG_UINT16(unkflag);
+	ARG_UINT16(findtarget);
 
 	if (!item) return 0;
 
-	return item->fireWeapon(x * 2, y * 2, z, Direction_FromUsecodeDir(dir), firetype, unkflag);
+	return item->fireWeapon(x * 2, y * 2, z, Direction_FromUsecodeDir(dir), firetype, findtarget != 0);
 }
 
 uint32 Item::I_fireDistance(const uint8 *args, unsigned int /*argsize*/) {
diff --git a/engines/ultima/ultima8/world/item.h b/engines/ultima/ultima8/world/item.h
index e17097c849..d12152159a 100644
--- a/engines/ultima/ultima8/world/item.h
+++ b/engines/ultima/ultima8/world/item.h
@@ -390,7 +390,7 @@ public:
 	virtual void receiveHit(ObjId other, Direction dir, int damage, uint16 type);
 
 	//! fire the given weapon type in the given direction from location x, y, z.
-	uint16 fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype, char findtarget);
+	uint16 fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype, bool findtarget);
 
 	//! get the distance (in map tiles) if we were to fire in this direction to "other"
 	//! and could hit, otherwise return 0.


Commit: 1217a1ebefba8ac95610437f41c927b08f5719c2
    https://github.com/scummvm/scummvm/commit/1217a1ebefba8ac95610437f41c927b08f5719c2
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-07T10:08:42+09:00

Commit Message:
ULTIMA8: Update SuperSpriteProcess to more closely match original

Changed paths:
    engines/ultima/ultima8/graphics/shape_info.h
    engines/ultima/ultima8/misc/direction_util.h
    engines/ultima/ultima8/world/super_sprite_process.cpp


diff --git a/engines/ultima/ultima8/graphics/shape_info.h b/engines/ultima/ultima8/graphics/shape_info.h
index 32eed9b3a5..dd302a30f0 100644
--- a/engines/ultima/ultima8/graphics/shape_info.h
+++ b/engines/ultima/ultima8/graphics/shape_info.h
@@ -44,7 +44,7 @@ public:
 		SI_NOISY   = 0x0080,
 		SI_DRAW    = 0x0100,
 		SI_IGNORE  = 0x0200,
-		SI_ROOF    = 0x0400,
+		SI_ROOF    = 0x0400, // reflective in Crusader?
 		SI_TRANSL  = 0x0800,
 		SI_EDITOR  = 0x1000,
 		// Note: overlapping names for the rest of the bits depending on U8 or Cru.
diff --git a/engines/ultima/ultima8/misc/direction_util.h b/engines/ultima/ultima8/misc/direction_util.h
index 387079d756..05a150a8dd 100644
--- a/engines/ultima/ultima8/misc/direction_util.h
+++ b/engines/ultima/ultima8/misc/direction_util.h
@@ -40,7 +40,7 @@ inline int Direction_XFactor(Direction dir) {
 	//static const int _x_fact16[] = {  0, +1, +2, +2, +2, +2, +2, +1, 0, -1, -2, -2, -2, -2, -2, -1 };
 	// TODO: AnimPrimitiveProcess uses the below table.. what's the other table for?
 	// (same for y)
-	static const int _x_fact16[] = {  0, +1, +1, +2, +1, +2, +1, +1, 0, -1, -1, -2, -1, -2, -1, -1 };
+	static const int _x_fact16[] = {  0, +1, +1, +2, +1, +2, +1, +1, 0, -1, -1, -2, -1, -2, -1, -1, 0 };
 
 	if (GAME_IS_U8)
 		return _x_fact[(int)dir / 2];
@@ -51,7 +51,7 @@ inline int Direction_XFactor(Direction dir) {
 inline int Direction_YFactor(Direction dir) {
 	static const int _y_fact[] = { -1, -1,  0, +1, +1, +1,  0, -1 };
 	//static const int _y_fact16[] = { -2, -2, -2, -1,  0, +1, +2, +2, +2, +2, +2, +1, 0, -1, -2, -2 };
-	static const int _y_fact16[] = { -1, -2, -1, -1, 0, +1, +1, +2, +1, +2, +1, +1, 0, -1, -1, -2 };
+	static const int _y_fact16[] = { -1, -2, -1, -1, 0, +1, +1, +2, +1, +2, +1, +1, 0, -1, -1, -2, 0 };
 
 	if (GAME_IS_U8)
 		return _y_fact[(int)dir / 2];
diff --git a/engines/ultima/ultima8/world/super_sprite_process.cpp b/engines/ultima/ultima8/world/super_sprite_process.cpp
index 6bff54a33c..95e67994ae 100644
--- a/engines/ultima/ultima8/world/super_sprite_process.cpp
+++ b/engines/ultima/ultima8/world/super_sprite_process.cpp
@@ -135,6 +135,14 @@ void SuperSpriteProcess::move(int x, int y, int z) {
 		item->move(_nowpt);
 }
 
+static inline int _sign(int x) {
+	if (x < 0)
+		return -1;
+	else if (x == 0)
+		return 0;
+	return 1;
+}
+
 void SuperSpriteProcess::run() {
 	CurrentMap *map = World::get_instance()->getCurrentMap();
 	int mapChunkSize = map->getChunkSize();
@@ -154,23 +162,29 @@ void SuperSpriteProcess::run() {
 		newpt.z += _counter * _zstep;
 	} else {
 		int targetz = 0;
-		if (_counter > firetypedat->getRoundDuration()) {
+		if (_counter < firetypedat->getRoundDuration()) {
 			if (!_expired) {
+				Direction dir8 = dir_current;
 				if (_target == 0) {
 					targetz = _nowpt.z;
 				} else {
-					Item *target = getItem(_target);
+					const Item *target = getItem(_target);
 					if (target) {
 						int32 tx, ty, tz;
 						int32 cx, cy, cz;
 						target->getLocation(tx, ty, tz);
 						target->getCentre(cx, cy, cz);
 						targetz = cz + 8;
+						dir8 = Direction_GetWorldDir(ty - _nowpt.y, tx - _nowpt.x, dirmode_8dirs);
 					}
 				}
 
-				// TODO: Apply point adjustments for firetype 9 here
-				// (lines 134~214 of disasm)
+				int xoff = Direction_XFactor(dir8);
+				if (_sign(xoff) != _sign(_xstep))
+					_xstep *= 2;
+				int yoff = Direction_YFactor(dir8);
+				if (_sign(yoff) != _sign(_ystep))
+					_ystep *= 2;
 			}
 		} else {
 			_expired = true;
@@ -209,6 +223,9 @@ void SuperSpriteProcess::run() {
 			}
 		}
 	}
+
+	// TODO: Clamp Z values as original does ~lines 280-290 of
+	// SuperSpriteProcess::run()
 	_pt3 = newpt;
 
 	_counter++;
@@ -221,10 +238,10 @@ void SuperSpriteProcess::run() {
 	}
 
 	if (_pt3.z != 0 && _pt3.z != 0xfa) {
-		int32 duration = firetypedat->getRoundDuration();
+		int32 duration = firetypedat->getRoundDuration() + 25;
 
-		if (_counter >= duration) {
-			// disasm ~line 311
+		if (_counter < duration) {
+			// disasm ~line 305
 			if (!map->isChunkFast(_nowpt.x / mapChunkSize, _nowpt.y / mapChunkSize)) {
 				destroyItemOrTerminate();
 				return;
@@ -275,17 +292,39 @@ void SuperSpriteProcess::makeBulletSplash(const Point3 &pt) {
 	firetypedat->makeBulletSplashShapeAndPlaySound(pt.x, pt.y, pt.z);
 }
 
+static bool _pointOutOfMap(const int pt[3], int maxxy) {
+	return (pt[0] < 0     || pt[1] < 0     || pt[2] < 0 ||
+			pt[0] > maxxy || pt[1] > maxxy || pt[2] > 255);
+}
+
 void SuperSpriteProcess::hitAndFinish() {
 	Point3 pt(_nowpt);
 	//int dist = _nowpt.maxDistXYZ(_pt3);
 
-	CurrentMap *map = World::get_instance()->getCurrentMap();
-	Std::list<CurrentMap::SweepItem> hits;
+	int xstep = _pt3.x - _nowpt.x;
+	int ystep = _pt3.y - _nowpt.y;
+	int zstep = _pt3.z - _nowpt.z;
 	int32 start[3] = {_nowpt.x, _nowpt.y, _nowpt.z};
 	int32 end[3] = {_pt3.x, _pt3.y, _pt3.z};
 	int32 dims[3] = {1, 1, 1};
-	bool collision = map->sweepTest(start, end, dims, ShapeInfo::SI_SOLID,
-									_source, true, &hits);
+	// will never get a collision if not stepping at all..
+	bool collision = !(xstep || ystep || zstep);
+	Std::list<CurrentMap::SweepItem> hits;
+
+	while (!collision) {
+		CurrentMap *map = World::get_instance()->getCurrentMap();
+		collision = map->sweepTest(start, end, dims, ShapeInfo::SI_SOLID,
+								   _source, true, &hits);
+		start[0] += xstep;
+		start[1] += ystep;
+		start[2] += zstep;
+		end[0] += xstep;
+		end[1] += ystep;
+		end[2] += zstep;
+		const int mapmax = map->getChunkSize() * MAP_NUM_CHUNKS;
+		if (_pointOutOfMap(start, mapmax) || _pointOutOfMap(end, mapmax))
+			break;
+	}
 
 	if (collision && hits.size()) {
 		const CurrentMap::SweepItem &firsthit = hits.front();




More information about the Scummvm-git-logs mailing list