[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