[Scummvm-git-logs] scummvm master -> 6322e399ec9d97570cba97eeaa50e650fad2a9b5
mduggan
mgithub at guarana.org
Sun Mar 28 04:00:01 UTC 2021
This automated email contains information about 12 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
aaa2d5f5c6 ULTIMA8: Small GravityProcess cleanups (remove dead code) and assertions
e92d4791b1 ULTIMA8: Make gravity behave more like original
743ef873b2 ULTIMA8: Add LAND bit to blocking collision mask.
6a30d603aa ULTIMA8: Fix Crusader pickup gump positioning
dbad8518dc ULTIMA8: Implement Crusader style pathfinder
96f2381926 ULTIMA8: Improve const correctness
19648041c7 ULTIMA8: Remove dead code
36b42f92fe ULTIMA8: Get Crusader inventory shape dyanmically as it can change
52a40f33af ULTIMA8: Also show bombs in cru inventory
3b49490597 ULTIMA8: Refactor isBusy logic to Actor
1de427262f ULTIMA8: Update crusader stance after changing weapons
6322e399ec ULTIMA8: Fix fade on Crusader health/energy gumps
Commit: aaa2d5f5c65ed5e89760412184774b89e1546232
https://github.com/scummvm/scummvm/commit/aaa2d5f5c65ed5e89760412184774b89e1546232
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:49:07+09:00
Commit Message:
ULTIMA8: Small GravityProcess cleanups (remove dead code) and assertions
Changed paths:
engines/ultima/ultima8/world/gravity_process.cpp
diff --git a/engines/ultima/ultima8/world/gravity_process.cpp b/engines/ultima/ultima8/world/gravity_process.cpp
index e7c71053e2..c0df54e6d4 100644
--- a/engines/ultima/ultima8/world/gravity_process.cpp
+++ b/engines/ultima/ultima8/world/gravity_process.cpp
@@ -80,6 +80,9 @@ void GravityProcess::run() {
return;
}
+ // There should never be more than one gravity on an object
+ assert(item->getGravityPID() == _pid);
+
Actor *actor = dynamic_cast<Actor *>(item);
if (actor && actor->getFallStart() < actor->getZ()) {
actor->setFallStart(actor->getZ());
@@ -96,49 +99,27 @@ void GravityProcess::run() {
int32 ix, iy, iz;
item->getLocation(ix, iy, iz);
- int32 ixd, iyd, izd;
- item->getFootpadWorld(ixd, iyd, izd);
+
+ if (iz < -1000) {
+ // Shouldn't happen as item should always hit the floor.
+ warning("Item %d fell too far, stopping GravityProcess", _itemNum);
+ terminate();
+ return;
+ }
int32 tx, ty, tz;
tx = ix + _xSpeed;
ty = iy + _ySpeed;
tz = iz + _zSpeed;
- bool clipped = false;
-
- // Clip to region. This doesn't work
-#if 0
- if (tx < 0 && ix >= 0) {
- int32 scale = (ix - tx) >> 0x8;
- tx = 0;
- ty = iy + ((_ySpeed * scale) >> 0x2000);
- tz = iz + ((_zSpeed * scale) >> 0x2000);
- clipped = true;
- }
- if (ty < 0 && iy >= 0) {
- int32 scale = (iy - ty) >> 0x8;
- tx = ix + ((_xSpeed * scale) >> 0x2000);
- ty = 0;
- tz = iz + ((_zSpeed * scale) >> 0x2000);
- clipped = true;
- }
- if (tz < 0 && iz >= 0) {
- int32 scale = (iz - tz) >> 0x8;
- tx = ix + ((_xSpeed * scale) >> 0x2000);
- ty = iy + ((_ySpeed * scale) >> 0x2000);
- tz = 0;
- clipped = true;
- }
-#endif
-
//#define BOUNCE_DIAG
ObjId hititemid;
uint8 dirs;
int32 dist = item->collideMove(tx, ty, tz, false, false, &hititemid, &dirs);
- if (dist == 0x4000 && !clipped) {
- // normal move
+ if (dist == 0x4000 && !hititemid) {
+ // didn't hit anything.
_zSpeed -= _gravity;
return;
}
@@ -173,7 +154,7 @@ void GravityProcess::run() {
<< "]: hit " << hititem->getObjId() << Std::endl;
#endif
- if (!hititem->getShapeInfo()->is_land() || _zSpeed < -2 * _gravity) {
+ if (GAME_IS_U8 && (!hititem->getShapeInfo()->is_land() || _zSpeed < -2 * _gravity)) {
// Bounce!
termFlag = false;
#ifdef BOUNCE_DIAG
@@ -284,6 +265,7 @@ void GravityProcess::terminate() {
//signal item GravityProcess is gone
Item *item = getItem(_itemNum);
if (item) {
+ assert(item->getGravityPID() == 0 || item->getGravityPID() == _pid);
item->setGravityPID(0);
// no longer bouncing
Commit: e92d4791b16dad30f768fbbe3cb7e2c41f9ef00d
https://github.com/scummvm/scummvm/commit/e92d4791b16dad30f768fbbe3cb7e2c41f9ef00d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:49:07+09:00
Commit Message:
ULTIMA8: Make gravity behave more like original
Tweaks to make it behave more like original games:
* Don't apply gravity to weight == 0 objects
* Add a small hang time in Crusader
Changed paths:
engines/ultima/ultima8/world/item.cpp
engines/ultima/ultima8/world/item.h
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index 6a5f65082f..b52b0369ce 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -27,6 +27,7 @@
#include "ultima/ultima8/usecode/uc_list.h"
#include "ultima/ultima8/world/world.h"
#include "ultima/ultima8/kernel/kernel.h"
+#include "ultima/ultima8/kernel/delay_process.h"
#include "ultima/ultima8/world/get_object.h"
#include "ultima/ultima8/graphics/main_shape_archive.h"
#include "ultima/ultima8/graphics/gump_shape_archive.h"
@@ -1989,16 +1990,16 @@ GravityProcess *Item::ensureGravityProcess() {
void Item::fall() {
const ShapeInfo *info = getShapeInfo();
- if (_flags & FLG_HANGING || info->is_fixed() ||
- (info->_weight == 0 && GAME_IS_CRUSADER)) {
+ bool hanging = GAME_IS_U8 && (_flags & FLG_HANGING);
+
+ if (hanging || info->is_fixed() || info->_weight == 0) {
// can't fall
return;
}
int gravity = GAME_IS_CRUSADER ? 2 : 4; //!! constants
- GravityProcess *p = ensureGravityProcess();
- p->setGravity(gravity);
+ hurl(0, 0, 0, gravity);
}
void Item::grab() {
@@ -2031,9 +2032,16 @@ void Item::grab() {
void Item::hurl(int xs, int ys, int zs, int grav) {
+ // crusader sleeps existing gravity at first
+ bool do_sleep = GAME_IS_CRUSADER && (_gravityPid == 0);
GravityProcess *p = ensureGravityProcess();
p->setGravity(grav);
p->move(xs, ys, zs);
+ if (do_sleep) {
+ Process *delayProc = new DelayProcess(0x14);
+ ProcId pid = Kernel::get_instance()->addProcess(delayProc);
+ p->waitFor(pid);
+ }
}
diff --git a/engines/ultima/ultima8/world/item.h b/engines/ultima/ultima8/world/item.h
index d12152159a..82a9cb010a 100644
--- a/engines/ultima/ultima8/world/item.h
+++ b/engines/ultima/ultima8/world/item.h
@@ -353,8 +353,9 @@ public:
//! Hurl the item in the given direction
void hurl(int xs, int ys, int zs, int grav);
- //! Set the PID of the GravityProcess for this Item
+ //! Set the PID of the GravityProcess for this Item. There should be only one.
void setGravityPID(ProcId pid) {
+ assert(_gravityPid == 0 || pid == 0);
_gravityPid = pid;
}
Commit: 743ef873b2e2e003757075a8e012d1215a2f4220
https://github.com/scummvm/scummvm/commit/743ef873b2e2e003757075a8e012d1215a2f4220
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:49:07+09:00
Commit Message:
ULTIMA8: Add LAND bit to blocking collision mask.
Without this, some temporary items which do not have SI_SOLID can fall through
the floor. In U8, LAND items generally don't move so this shouldn't have any
negative impact
Changed paths:
engines/ultima/ultima8/world/current_map.cpp
diff --git a/engines/ultima/ultima8/world/current_map.cpp b/engines/ultima/ultima8/world/current_map.cpp
index bc2608d4fd..d6a2a2e603 100644
--- a/engines/ultima/ultima8/world/current_map.cpp
+++ b/engines/ultima/ultima8/world/current_map.cpp
@@ -1013,7 +1013,7 @@ bool CurrentMap::sweepTest(const int32 start[3], const int32 end[3],
const int32 dims[3], uint32 shapeflags,
ObjId item, bool blocking_only,
Std::list<SweepItem> *hit) const {
- const uint32 blockflagmask = (ShapeInfo::SI_SOLID | ShapeInfo::SI_DAMAGING);
+ const uint32 blockflagmask = (ShapeInfo::SI_SOLID | ShapeInfo::SI_DAMAGING | ShapeInfo::SI_LAND);
int minx = ((start[0] - dims[0]) / _mapChunkSize) - 1;
int maxx = (start[0] / _mapChunkSize) + 1;
Commit: 6a30d603aaad5b4c0ba3e01c7fd4548bb7de129e
https://github.com/scummvm/scummvm/commit/6a30d603aaad5b4c0ba3e01c7fd4548bb7de129e
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:49:07+09:00
Commit Message:
ULTIMA8: Fix Crusader pickup gump positioning
Changed paths:
engines/ultima/ultima8/gumps/cru_pickup_area_gump.cpp
diff --git a/engines/ultima/ultima8/gumps/cru_pickup_area_gump.cpp b/engines/ultima/ultima8/gumps/cru_pickup_area_gump.cpp
index 365daafcf0..0dfdb337dc 100644
--- a/engines/ultima/ultima8/gumps/cru_pickup_area_gump.cpp
+++ b/engines/ultima/ultima8/gumps/cru_pickup_area_gump.cpp
@@ -56,26 +56,28 @@ void CruPickupAreaGump::addPickup(const Item *item) {
uint32 shapeno = item->getShape();
+ // Find the location to draw the gump for the new item,
+ // or an existing gump to recycle if we have one already
+ // for that shape
+ int32 maxy = PICKUP_GUMP_GAP;
Std::list<Gump *>::iterator it;
-
for (it = _children.begin(); it != _children.end(); it++) {
CruPickupGump *pug = dynamic_cast<CruPickupGump *>(*it);
if (!pug)
- return;
+ continue;
if (pug->getShapeNo() == shapeno) {
// Already a notification for this object, update it
pug->updateForNewItem(item);
- break;
+ return;
}
+ int32 x, y;
+ pug->getLocation(x, y);
+ maxy = MAX(maxy, y + PICKUP_GUMP_GAP + PICKUP_GUMP_HEIGHT);
}
- if (it == _children.end()) {
- int32 yoff = PICKUP_GUMP_GAP;
- if (_children.size() > 0)
- yoff += PICKUP_GUMP_HEIGHT;
- Gump *newgump = new CruPickupGump(item, yoff);
- newgump->InitGump(this, false);
- }
+ // didn't find one, create a new one at the bottom.
+ Gump *newgump = new CruPickupGump(item, maxy);
+ newgump->InitGump(this, false);
}
void CruPickupAreaGump::saveData(Common::WriteStream *ws) {
Commit: dbad8518dcbee6433749fa2c594e0cbf04d28e61
https://github.com/scummvm/scummvm/commit/dbad8518dcbee6433749fa2c594e0cbf04d28e61
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:53+09:00
Commit Message:
ULTIMA8: Implement Crusader style pathfinder
Changed paths:
A engines/ultima/ultima8/world/actors/cru_pathfinder_process.cpp
A engines/ultima/ultima8/world/actors/cru_pathfinder_process.h
engines/ultima/module.mk
engines/ultima/ultima8/world/actors/actor.cpp
engines/ultima/ultima8/world/actors/attack_process.cpp
engines/ultima/ultima8/world/actors/attack_process.h
engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
engines/ultima/ultima8/world/actors/pathfinder_process.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index c336cc0737..120468d620 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -555,6 +555,7 @@ MODULE_OBJS := \
ultima8/world/actors/clear_feign_death_process.o \
ultima8/world/actors/cru_avatar_mover_process.o \
ultima8/world/actors/cru_healer_process.o \
+ ultima8/world/actors/cru_pathfinder_process.o \
ultima8/world/actors/combat_dat.o \
ultima8/world/actors/combat_process.o \
ultima8/world/actors/grant_peace_process.o \
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 3b8985e3f6..42ce0b2236 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -617,6 +617,9 @@ uint16 Actor::turnTowardDir(Direction targetdir) {
}
}
+ if (targetdir == curdir)
+ return 0; // nothing to do.
+
if (combat) {
turnanim = Animation::combatStand;
standanim = Animation::combatStand;
diff --git a/engines/ultima/ultima8/world/actors/attack_process.cpp b/engines/ultima/ultima8/world/actors/attack_process.cpp
index 7241f0833b..aa407ebffa 100644
--- a/engines/ultima/ultima8/world/actors/attack_process.cpp
+++ b/engines/ultima/ultima8/world/actors/attack_process.cpp
@@ -36,7 +36,7 @@
#include "ultima/ultima8/world/loop_script.h"
#include "ultima/ultima8/world/actors/combat_dat.h"
#include "ultima/ultima8/world/actors/loiter_process.h"
-#include "ultima/ultima8/world/actors/pathfinder_process.h"
+#include "ultima/ultima8/world/actors/cru_pathfinder_process.h"
#include "ultima/ultima8/misc/direction_util.h"
namespace Ultima {
@@ -58,6 +58,7 @@ static const int16 ATTACK_SFX_7[] = {0x9B, 0x9C, 0x9D, 0x9E, 0x9F};
// read from the data array.
static const int MAGIC_DATA_OFF = 33000;
+const uint16 AttackProcess::ATTACK_PROCESS_TYPE = 0x259;
static uint16 someSleepGlobal = 0;
@@ -66,7 +67,6 @@ static bool World_FinishedAvatarMoveTimeout() {
return true;
}
-
static inline int32 randomOf(int32 max) {
return (max > 0 ? getRandom() % max : 0);
}
@@ -141,7 +141,7 @@ _soundTimestamp(0), _fireTimestamp(0) {
}
}
- _type = 0x0259; // CONSTANT !
+ _type = ATTACK_PROCESS_TYPE;
setTacticNo(actor->getCombatTactic());
}
@@ -242,7 +242,7 @@ void AttackProcess::run() {
int32 x, y, z;
a->getHomePosition(x, y, z);
ProcId pid = Kernel::get_instance()->addProcess(
- new PathfinderProcess(a, x, y, z));
+ new CruPathfinderProcess(a, x, y, z, 100, 0x40, true));
waitFor(pid);
return;
}
@@ -252,7 +252,7 @@ void AttackProcess::run() {
int32 x, y, z;
target->getLocation(x, y, z);
ProcId pid = Kernel::get_instance()->addProcess(
- new PathfinderProcess(a, x, y, z));
+ new CruPathfinderProcess(a, x, y, z, 12, 0x40, true));
waitFor(pid);
return;
}
@@ -267,7 +267,7 @@ void AttackProcess::run() {
int32 y = (ty + ay) / 2;
int32 z = (tz + az) / 2;
ProcId pid = Kernel::get_instance()->addProcess(
- new PathfinderProcess(a, x, y, z));
+ new CruPathfinderProcess(a, x, y, z, 12, 0x40, true));
waitFor(pid);
return;
}
@@ -395,7 +395,7 @@ void AttackProcess::run() {
if (itemFrame == targetFrame && (targetQ == 0 || itemQlo == targetQ)) {
ProcId pid = Kernel::get_instance()->addProcess(
- new PathfinderProcess(a, founditem->getObjId()));
+ new CruPathfinderProcess(a, founditem, 100, 0x40, true));
waitFor(pid);
break;
}
@@ -551,7 +551,7 @@ void AttackProcess::genericAttack() {
y += -0x1ff + randomOf(0x400);
_field96 = true;
const ProcId pid = Kernel::get_instance()->addProcess(
- new PathfinderProcess(a, x, y, z));
+ new CruPathfinderProcess(a, x, y, z, 12, 0x40, true));
// add a tiny delay to avoid tight loops
Process *delayproc = new DelayProcess(2);
Kernel::get_instance()->addProcess(delayproc);
@@ -831,7 +831,7 @@ void AttackProcess::pathfindToItemInNPCData() {
Actor *a = getActor(_itemNum);
Actor *target = getActor(_target);
- Process *pathproc = new PathfinderProcess(a, target->getObjId());
+ Process *pathproc = new CruPathfinderProcess(a, target, 12, 0x40, false);
// In case pathfinding fails delay for a bit to ensure we don't get
// stuck in a tight loop using all the cpu
Process *delayproc = new DelayProcess(10);
diff --git a/engines/ultima/ultima8/world/actors/attack_process.h b/engines/ultima/ultima8/world/actors/attack_process.h
index 18065acccd..73a8650ce7 100644
--- a/engines/ultima/ultima8/world/actors/attack_process.h
+++ b/engines/ultima/ultima8/world/actors/attack_process.h
@@ -63,12 +63,20 @@ public:
void setField97() {
_field97 = true;
}
+ void setField7F() {
+ _field7f = true;
+ }
void setTimer3();
+ uint16 getTarget() const {
+ return _target;
+ }
+
bool loadData(Common::ReadStream *rs, uint32 version);
void saveData(Common::WriteStream *ws) override;
+ static const uint16 ATTACK_PROCESS_TYPE;
private:
/** Set the current tactic in use from the combat.dat file. If 0,
* will use the genericAttack function. */
diff --git a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
index bf7f0c7422..2d1af824e7 100644
--- a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
@@ -236,11 +236,11 @@ void CruAvatarMoverProcess::handleCombatMode() {
idleanim = Animation::stopRunningAndDrawSmallWeapon;
}
- // not doing anything in particular? stand
- if (lastanim != idleanim) {
- Animation::Sequence nextanim = Animation::checkWeapon(idleanim, lastanim);
- waitFor(avatar->doAnim(nextanim, direction));
- }
+ // not doing anything in particular? stand. Always do the anim here as we
+ // may need to switch from small wpn to large wpn
+ Animation::Sequence nextanim = Animation::checkWeapon(idleanim, lastanim);
+ waitFor(avatar->doAnim(nextanim, direction));
+
}
void CruAvatarMoverProcess::handleNormalMode() {
diff --git a/engines/ultima/ultima8/world/actors/cru_pathfinder_process.cpp b/engines/ultima/ultima8/world/actors/cru_pathfinder_process.cpp
new file mode 100644
index 0000000000..09cab40703
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/cru_pathfinder_process.cpp
@@ -0,0 +1,375 @@
+/* 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/world/actors/cru_pathfinder_process.h"
+#include "ultima/ultima8/world/actors/pathfinder_process.h"
+#include "ultima/ultima8/world/actors/attack_process.h"
+
+#include "ultima/ultima8/world/actors/animation.h"
+#include "ultima/ultima8/world/actors/actor.h"
+#include "ultima/ultima8/world/item.h"
+#include "ultima/ultima8/world/get_object.h"
+#include "ultima/ultima8/world/world.h"
+#include "ultima/ultima8/world/actors/pathfinder.h"
+#include "ultima/ultima8/misc/direction_util.h"
+#include "ultima/ultima8/kernel/kernel.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+static const int8 PATHFIND_DIR_OFFSETS_1[8] = {0, 2, -2, 4, -4, 6, -6, -8};
+static const int8 PATHFIND_DIR_OFFSETS_2[8] = {0, -2, 2, -4, 4, -6, 6, -8};
+
+DEFINE_RUNTIME_CLASSTYPE_CODE(CruPathfinderProcess)
+
+CruPathfinderProcess::CruPathfinderProcess() : Process(),
+ _currentStep(0), _targetItem(0), _currentDistance(0),
+ _targetX(0), _targetY(0), _targetZ(0), _randomFlag(false),
+ _nextTurn(false), _turnAtEnd(false), _lastDir(dir_current),
+ _nextDir(dir_current), _nextDir2(dir_current),
+ _solidObject(true), _directPathBlocked(false), _noShotAvailable(true),
+ _dir16Flag(false), _stopDistance(0)
+{
+}
+
+CruPathfinderProcess::CruPathfinderProcess(Actor *actor, Item *target, int maxsteps, int stopdistance, bool turnatend) :
+ _currentStep(0), _currentDistance(0), _targetX(0), _targetY(0), _targetZ(0),
+ _maxSteps(maxsteps), _stopDistance(stopdistance), _nextTurn(false), _turnAtEnd(turnatend),
+ _lastDir(dir_current), _nextDir(dir_current), _nextDir2(dir_current),
+ _directPathBlocked(false), _noShotAvailable(true), _dir16Flag(false) {
+ assert(actor && target);
+ _itemNum = actor->getObjId();
+ _type = PathfinderProcess::PATHFINDER_PROC_TYPE;
+ _randomFlag = (getRandom() % 2) != 0;
+ _targetItem = target->getObjId();
+ target->getLocation(_targetX, _targetY, _targetZ);
+
+ int32 ax, ay, az;
+ actor->getLocation(ax, ay, az);
+ _currentDistance = MAX(abs(ax - _targetX), abs(ay - _targetY));
+
+ const ShapeInfo *si = actor->getShapeInfo();
+ _solidObject = (si->_flags & ShapeInfo::SI_SOLID) && si->_z > 0;
+
+ // TODO: check if flag already set? kill other pathfinders?
+ assert(!actor->hasActorFlags(Actor::ACT_PATHFINDING));
+ actor->setActorFlag(Actor::ACT_PATHFINDING);
+}
+
+CruPathfinderProcess::CruPathfinderProcess(Actor *actor, int32 x, int32 y, int32 z, int maxsteps, int stopdistance, bool turnatend) :
+ _targetX(x), _targetY(y), _targetZ(z), _targetItem(0), _currentStep(0),
+ _maxSteps(maxsteps), _stopDistance(stopdistance), _nextTurn(false), _turnAtEnd(turnatend),
+ _lastDir(dir_current), _nextDir(dir_current), _nextDir2(dir_current),
+ _directPathBlocked(false), _noShotAvailable(true), _dir16Flag(false) {
+ assert(actor);
+ _itemNum = actor->getObjId();
+ _type = PathfinderProcess::PATHFINDER_PROC_TYPE;
+ _randomFlag = (getRandom() % 2) != 0;
+
+ int32 ax, ay, az;
+ actor->getLocation(ax, ay, az);
+ _currentDistance = MAX(abs(ax - _targetX), abs(ay - _targetY));
+
+ const ShapeInfo *si = actor->getShapeInfo();
+ _solidObject = (si->_flags & ShapeInfo::SI_SOLID) && si->_z > 0;
+
+ // TODO: check if flag already set? kill other pathfinders?
+ assert(!actor->hasActorFlags(Actor::ACT_PATHFINDING));
+ actor->setActorFlag(Actor::ACT_PATHFINDING);
+}
+
+CruPathfinderProcess::~CruPathfinderProcess() {
+}
+
+void CruPathfinderProcess::terminate() {
+ Actor *actor = getActor(_itemNum);
+ if (actor && !actor->isDead()) {
+ // TODO: only clear if it was set by us?
+ // (slightly more complicated if we kill other pathfinders on startup)
+ actor->clearActorFlag(Actor::ACT_PATHFINDING);
+
+ uint16 turnproc = 0;
+ if (_turnAtEnd) {
+ Direction destdir = dir_current;
+ // TODO: this logic can be cleaned up a bit by just updating targetx/y?
+ int32 ix, iy, iz;
+ actor->getLocationAbsolute(ix, iy, iz);
+ if (_targetItem == 0) {
+ destdir = Direction_GetWorldDir(_targetY - iy, _targetX - ix, dirmode_8dirs);
+ } else {
+ Item *target = getItem(_targetItem);
+ if (target) {
+ int32 tx, ty, tz;
+ target->getLocationAbsolute(tx, ty, tz);
+ destdir = Direction_GetWorldDir(ty - iy, tx - ix, dirmode_8dirs);
+ }
+ }
+ turnproc = actor->turnTowardDir(destdir);
+ }
+ if (!turnproc && _noShotAvailable) {
+ Animation::Sequence standanim = (actor->isInCombat() ? Animation::combatStandSmallWeapon : Animation::stand);
+ actor->doAnim(standanim, dir_current);
+ }
+ }
+
+ Process::terminate();
+}
+
+Direction CruPathfinderProcess::nextDirFromPoint(struct Point3 &npcpt) {
+ const Direction dirtotarget = Direction_GetWorldDir(_targetY - npcpt.y, _targetX - npcpt.x, dirmode_8dirs);
+ Actor *npc = getActor(_itemNum);
+
+ //assert(npc);
+
+ const int maxdiffxy = MAX(abs(npcpt.x - _targetX), abs(npcpt.y - _targetY));
+ if (maxdiffxy < _currentDistance) {
+ // each time we get closer, check again if we can walk toward the target.
+ _currentDistance = maxdiffxy;
+ PathfindingState state;
+ state._x = npcpt.x;
+ state._y = npcpt.y;
+ state._z = npcpt.z;
+ state._direction = dirtotarget;
+ state._combat = npc->isInCombat();
+ Animation::Sequence anim = npc->isInCombat() ? Animation::walk : Animation::advanceSmallWeapon;
+ Animation::Result result = npc->tryAnim(anim, dirtotarget, 0, &state);
+ if (result == Animation::SUCCESS) {
+ _directPathBlocked = false;
+ }
+ }
+
+ int startoff = 0;
+ Direction dirtable[8];
+ Direction nextdir_table[8];
+
+ if (!_directPathBlocked) {
+ for (int i = 0; i < 8; i++) {
+ if (_randomFlag) {
+ dirtable[i] = Direction_TurnByDelta(dirtotarget, PATHFIND_DIR_OFFSETS_1[i], dirmode_16dirs);
+ } else {
+ dirtable[i] = Direction_TurnByDelta(dirtotarget, PATHFIND_DIR_OFFSETS_2[i], dirmode_16dirs);
+ }
+ }
+
+ } else {
+
+ int diroffset;
+ if (_randomFlag) {
+ diroffset = (_nextTurn ? 2 : -2);
+ } else {
+ diroffset = (_nextTurn ? -2 : 2);
+ }
+ nextdir_table[0] = Direction_TurnByDelta(_nextDir, diroffset + 8, dirmode_16dirs);
+
+ for (int i = 1; i < 8; i++) {
+ if (_randomFlag) {
+ diroffset = (_nextTurn ? 2 : -2);
+ } else {
+ diroffset = (_nextTurn ? -2 : 2);
+ }
+ nextdir_table[i] = Direction_TurnByDelta(nextdir_table[i - 1], diroffset, dirmode_16dirs);
+ }
+ startoff = 1;
+ }
+
+ PathfindingState state;
+ Animation::Result animresult = Animation::SUCCESS;
+ int i;
+ for (i = startoff; i < 8; i++) {
+ // TODO: double-check these in disasm
+ if (_directPathBlocked && i == 2)
+ continue;
+ if (_directPathBlocked && i == 7)
+ break;
+
+ if (_directPathBlocked)
+ _nextDir2 = nextdir_table[i];
+ else
+ _nextDir2 = dirtable[i];
+
+ // LAB_1110_0c26:
+ Animation::Sequence anim = npc->isInCombat() ? Animation::walk : Animation::advanceSmallWeapon;
+ state._x = npcpt.x;
+ state._y = npcpt.y;
+ state._z = npcpt.z;
+ state._direction = _nextDir2;
+ state._combat = npc->isInCombat();
+ animresult = npc->tryAnim(anim, _nextDir2, 0, &state);
+
+ // Note: this will never trigger in our code -
+ // "tryAnim" code seems to behave differently in original?
+ /*if (_solidObject && ((_result >> 1) & 1)) {
+ _turnAtEnd = true;
+ return dir_invalid;
+ }*/
+
+ if (_stopDistance && (MAX(abs(_targetX - state._x), abs(_targetY - state._y)) <= _stopDistance)) {
+ _turnAtEnd = true;
+ return dir_invalid;
+ }
+
+ if (animresult == Animation::SUCCESS)
+ break;
+ }
+
+ // LAB_1110_0dd5:
+ if (animresult != Animation::SUCCESS)
+ return dir_current;
+
+ if ((_nextDir2 != dirtotarget) && !_directPathBlocked) {
+ _directPathBlocked = true;
+ _nextTurn = (i % 2);
+ }
+
+ npcpt.x = state._x;
+ npcpt.y = state._y;
+ npcpt.z = state._z;
+ bool is_controlled = World::get_instance()->getControlledNPCNum() == _itemNum;
+ if (npc->isInCombat() && !is_controlled) {
+ AttackProcess *attackproc = dynamic_cast<AttackProcess *>
+ (Kernel::get_instance()->findProcess(_itemNum, AttackProcess::ATTACK_PROCESS_TYPE));
+ if (attackproc) {
+ const Actor *target = getActor(attackproc->getTarget());
+ if (target && npc->isOnScreen() && npc->fireDistance(target, dirtotarget, 0, 0, 0)) {
+ npc->doAnim(Animation::stand, dir_current);
+ attackproc->setField7F();
+ _noShotAvailable = false;
+ _turnAtEnd = true;
+ return dir_invalid;
+ }
+ }
+ }
+ return _nextDir2;
+}
+
+
+void CruPathfinderProcess::run() {
+ Actor *npc = getActor(_itemNum);
+ if (!npc || !npc->hasFlags(Item::FLG_FASTAREA))
+ return;
+
+ if (npc->isDead()) {
+ terminate();
+ return;
+ }
+
+ if (_dir16Flag) {
+ terminate(); // terminate 1
+ return;
+ }
+
+ if (_targetItem != 0 && _solidObject) {
+ Item *target = getItem(_targetItem);
+ if (target)
+ target->getLocation(_targetX, _targetY, _targetZ);
+ }
+
+ Point3 npcpt;
+ npc->getLocation(npcpt);
+
+ if (_targetX == npcpt.x && _targetY == npcpt.y) {
+ terminate(); // _destpt.z != npcpt.z
+ return;
+ }
+ const Direction lastdir = _nextDir;
+ _nextDir = nextDirFromPoint(npcpt);
+ _lastDir = lastdir;
+ if (_nextDir == dir_current) {
+ terminate(); //0
+ return;
+ }
+
+ if (_nextDir == dir_invalid) {
+ _dir16Flag = true;
+ } else {
+ if (_currentStep == _maxSteps) {
+ terminate(); //0
+ return;
+ }
+ }
+
+ Direction newdir;
+ if (!_dir16Flag) {
+ newdir = _nextDir;
+ } else {
+ newdir = _nextDir2;
+ }
+
+ uint16 turnpid = npc->turnTowardDir(newdir);
+ Animation::Sequence anim = npc->isInCombat() ? Animation::advanceSmallWeapon : Animation::walk;
+ uint16 animpid = npc->doAnim(anim, newdir);
+ if (turnpid)
+ Kernel::get_instance()->getProcess(animpid)->waitFor(turnpid);
+ waitFor(animpid);
+ _currentStep += 1;
+}
+
+void CruPathfinderProcess::saveData(Common::WriteStream *ws) {
+ Process::saveData(ws);
+
+ ws->writeUint16LE(_targetItem);
+ ws->writeUint16LE(static_cast<uint16>(_targetX));
+ ws->writeUint16LE(static_cast<uint16>(_targetY));
+ ws->writeUint16LE(static_cast<uint16>(_targetZ));
+ ws->writeUint16LE(static_cast<uint16>(_currentDistance));
+ ws->writeByte(_randomFlag ? 1 : 0);
+ ws->writeByte(_nextTurn ? 1 : 0);
+ ws->writeByte(_turnAtEnd ? 1 : 0);
+ ws->writeByte(_lastDir);
+ ws->writeByte(_nextDir);
+ ws->writeByte(_nextDir2);
+ ws->writeByte(_solidObject ? 1 : 0);
+ ws->writeByte(_directPathBlocked ? 1 : 0);
+ ws->writeByte(_noShotAvailable ? 1 : 0);
+ ws->writeByte(_dir16Flag ? 1 : 0);
+ ws->writeUint16LE(static_cast<uint16>(_currentStep));
+ ws->writeUint16LE(static_cast<uint16>(_maxSteps));
+ ws->writeUint16LE(static_cast<uint16>(_stopDistance));
+}
+
+bool CruPathfinderProcess::loadData(Common::ReadStream *rs, uint32 version) {
+ if (!Process::loadData(rs, version)) return false;
+
+ _targetItem = rs->readUint16LE();
+ _targetX = rs->readUint16LE();
+ _targetY = rs->readUint16LE();
+ _targetZ = rs->readUint16LE();
+ _currentDistance = rs->readUint16LE();
+ _randomFlag = rs->readByte();
+ _nextTurn = rs->readByte();
+ _turnAtEnd = rs->readByte();
+ _lastDir = static_cast<Direction>(rs->readByte());
+ _nextDir = static_cast<Direction>(rs->readByte());
+ _nextDir2 = static_cast<Direction>(rs->readByte());
+ _solidObject = rs->readByte();
+ _directPathBlocked = rs->readByte();
+ _noShotAvailable = rs->readByte();
+ _dir16Flag = rs->readByte();
+ _currentStep = rs->readUint16LE();
+ _maxSteps = rs->readUint16LE();
+ _stopDistance = rs->readUint16LE();
+
+ return true;
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/world/actors/cru_pathfinder_process.h b/engines/ultima/ultima8/world/actors/cru_pathfinder_process.h
new file mode 100644
index 0000000000..ea59e6ed1f
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/cru_pathfinder_process.h
@@ -0,0 +1,84 @@
+/* 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_CRU_PATHFINDERPROCESS_H
+#define WORLD_ACTORS_CRU_PATHFINDERPROCESS_H
+
+#include "ultima/ultima8/kernel/process.h"
+#include "ultima/ultima8/misc/direction.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+class Actor;
+class Item;
+
+/**
+ * A simplified pathfinder used in Crusader for the AttackProcess.
+ *
+ * The code and variable names for this are not very well written as
+ * they are are based on the disassembly.
+ */
+class CruPathfinderProcess : public Process {
+public:
+ CruPathfinderProcess();
+ CruPathfinderProcess(Actor *actor, Item *item, int maxsteps, int stopdistance, bool turnatend);
+ CruPathfinderProcess(Actor *actor, int32 x, int32 y, int32 z, int maxsteps, int stopdistance, bool turnatend);
+ ~CruPathfinderProcess() override;
+
+ ENABLE_RUNTIME_CLASSTYPE()
+
+ void run() override;
+ void terminate() override;
+
+ bool loadData(Common::ReadStream *rs, uint32 version);
+ void saveData(Common::WriteStream *ws) override;
+
+private:
+
+ Direction nextDirFromPoint(struct Point3 &npcpt);
+
+ int32 _targetX, _targetY, _targetZ;
+ ObjId _targetItem;
+ int _currentDistance;
+ bool _randomFlag;
+ bool _nextTurn;
+ bool _turnAtEnd;
+
+ Direction _lastDir;
+ Direction _nextDir;
+ Direction _nextDir2;
+
+ bool _solidObject;
+ bool _directPathBlocked;
+ bool _noShotAvailable;
+ bool _dir16Flag;
+
+ unsigned int _currentStep;
+ unsigned int _maxSteps;
+ int _stopDistance;
+};
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima8/world/actors/pathfinder_process.h b/engines/ultima/ultima8/world/actors/pathfinder_process.h
index f42bc7b862..41e0dedea8 100644
--- a/engines/ultima/ultima8/world/actors/pathfinder_process.h
+++ b/engines/ultima/ultima8/world/actors/pathfinder_process.h
@@ -44,8 +44,6 @@ public:
void run() override;
void terminate() override;
-// virtual void terminate();
-
bool loadData(Common::ReadStream *rs, uint32 version);
void saveData(Common::WriteStream *ws) override;
Commit: 96f2381926e442b8cf33ac041e65dabe044b44f5
https://github.com/scummvm/scummvm/commit/96f2381926e442b8cf33ac041e65dabe044b44f5
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:56+09:00
Commit Message:
ULTIMA8: Improve const correctness
Changed paths:
engines/ultima/ultima8/ultima8.cpp
engines/ultima/ultima8/world/item.cpp
engines/ultima/ultima8/world/item.h
diff --git a/engines/ultima/ultima8/ultima8.cpp b/engines/ultima/ultima8/ultima8.cpp
index 7764488879..e52b3000a3 100644
--- a/engines/ultima/ultima8/ultima8.cpp
+++ b/engines/ultima/ultima8/ultima8.cpp
@@ -71,6 +71,7 @@
#include "ultima/ultima8/world/actors/pathfinder_process.h"
#include "ultima/ultima8/world/actors/u8_avatar_mover_process.h"
#include "ultima/ultima8/world/actors/cru_avatar_mover_process.h"
+#include "ultima/ultima8/world/actors/cru_pathfinder_process.h"
#include "ultima/ultima8/world/actors/resurrection_process.h"
#include "ultima/ultima8/world/actors/clear_feign_death_process.h"
#include "ultima/ultima8/world/actors/loiter_process.h"
@@ -224,6 +225,8 @@ bool Ultima8Engine::startup() {
ProcessLoader<QuickAvatarMoverProcess>::load);
_kernel->addProcessLoader("PathfinderProcess",
ProcessLoader<PathfinderProcess>::load);
+ _kernel->addProcessLoader("CruPathfinderProcess",
+ ProcessLoader<CruPathfinderProcess>::load);
_kernel->addProcessLoader("SpriteProcess",
ProcessLoader<SpriteProcess>::load);
_kernel->addProcessLoader("CameraProcess",
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index b52b0369ce..b2c957af68 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -1300,7 +1300,7 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
return spriteprocpid;
}
-uint16 Item::fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff) {
+uint16 Item::fireDistance(const Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff) {
if (!other)
return 0;
@@ -1413,7 +1413,7 @@ uint16 Item::fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, in
return dist / 32;
}
-int32 Item::getTargetZRelativeToAttackerZ(int32 otherz) {
+int32 Item::getTargetZRelativeToAttackerZ(int32 otherz) const {
int32 tsx, tsy, tsz;
getFootpadData(tsx, tsy, tsz);
diff --git a/engines/ultima/ultima8/world/item.h b/engines/ultima/ultima8/world/item.h
index 82a9cb010a..41b0a13087 100644
--- a/engines/ultima/ultima8/world/item.h
+++ b/engines/ultima/ultima8/world/item.h
@@ -395,7 +395,7 @@ public:
//! get the distance (in map tiles) if we were to fire in this direction to "other"
//! and could hit, otherwise return 0.
- uint16 fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff);
+ uint16 fireDistance(const Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff);
//! get damage points, used in Crusader for item damage.
uint8 getDamagePoints() const {
@@ -662,7 +662,7 @@ private:
//! Get the right Z which an attacker should aim for, given the attacker's z.
//! (Crusader only)
- int32 getTargetZRelativeToAttackerZ(int32 attackerz);
+ int32 getTargetZRelativeToAttackerZ(int32 attackerz) const;
public:
enum statusflags {
Commit: 19648041c7c2e83bafea999e1fadd8034b4e291d
https://github.com/scummvm/scummvm/commit/19648041c7c2e83bafea999e1fadd8034b4e291d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:56+09:00
Commit Message:
ULTIMA8: Remove dead code
Changed paths:
engines/ultima/ultima8/games/game_data.cpp
diff --git a/engines/ultima/ultima8/games/game_data.cpp b/engines/ultima/ultima8/games/game_data.cpp
index abcdf15d61..9c1aac50a2 100644
--- a/engines/ultima/ultima8/games/game_data.cpp
+++ b/engines/ultima/ultima8/games/game_data.cpp
@@ -542,10 +542,6 @@ void GameData::loadRemorseData() {
ConfigFileManager *config = ConfigFileManager::get_instance();
// Load weapon, armour info
config->readConfigFile("data/remorseweapons.ini", "weapons");
-#if 0
- config->readConfigFile("data/u8armour.ini", "armour");
- config->readConfigFile("data/u8monsters.ini", "monsters");
-#endif
config->readConfigFile("data/remorse.ini", "game");
// Load typeflags
Commit: 36b42f92fe1c659d8e8b0bb39a0c71edd0063cc3
https://github.com/scummvm/scummvm/commit/36b42f92fe1c659d8e8b0bb39a0c71edd0063cc3
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:56+09:00
Commit Message:
ULTIMA8: Get Crusader inventory shape dyanmically as it can change
Changed paths:
engines/ultima/ultima8/gumps/cru_inventory_gump.cpp
engines/ultima/ultima8/gumps/cru_inventory_gump.h
diff --git a/engines/ultima/ultima8/gumps/cru_inventory_gump.cpp b/engines/ultima/ultima8/gumps/cru_inventory_gump.cpp
index ced54b8744..0c6cd18f5d 100644
--- a/engines/ultima/ultima8/gumps/cru_inventory_gump.cpp
+++ b/engines/ultima/ultima8/gumps/cru_inventory_gump.cpp
@@ -32,18 +32,14 @@
namespace Ultima {
namespace Ultima8 {
-static const int INVENTORY_GUMP_SHAPE = 5;
static const int INVENTORY_TEXT_FONT = 12;
DEFINE_RUNTIME_CLASSTYPE_CODE(CruInventoryGump)
-CruInventoryGump::CruInventoryGump() : CruStatGump(), _inventoryShape(nullptr),
- _inventoryItemGump(nullptr), _inventoryText(nullptr) {
-
+CruInventoryGump::CruInventoryGump() : CruStatGump(), _inventoryItemGump(nullptr), _inventoryText(nullptr) {
}
CruInventoryGump::CruInventoryGump(Shape *shape, int x)
- : CruStatGump(shape, x), _inventoryShape(nullptr), _inventoryItemGump(nullptr),
- _inventoryText(nullptr) {
+ : CruStatGump(shape, x), _inventoryItemGump(nullptr), _inventoryText(nullptr) {
_frameNum = 0;
}
@@ -59,11 +55,6 @@ void CruInventoryGump::InitGump(Gump *newparent, bool take_focus) {
return;
}
- _inventoryShape = gumpshapes->getShape(INVENTORY_GUMP_SHAPE);
- if (!_inventoryShape || !_inventoryShape->getFrame(0)) {
- warning("failed to init stat gump: no inventory shape");
- return;
- }
_inventoryItemGump = new Gump();
_inventoryItemGump->InitGump(this, false);
// we'll set the shape for this gump later.
@@ -119,8 +110,19 @@ void CruInventoryGump::PaintThis(RenderSurface *surf, int32 lerp_factor, bool sc
if (!item) {
_inventoryItemGump->SetShape(0, 0);
} else {
- uint16 frame = getDisplayFrameForShape(item->getShape());
- _inventoryItemGump->SetShape(_inventoryShape, frame);
+ GumpShapeArchive *gumpshapes = GameData::get_instance()->getGumps();
+ if (!gumpshapes) {
+ warning("failed to paint stat gump: no gump shape archive");
+ return;
+ }
+
+ const ShapeInfo *shapeinfo = item->getShapeInfo();
+ if (!shapeinfo->_weaponInfo) {
+ warning("no weapon info for active inventory item %d", item->getShape());
+ return;
+ }
+ Shape *invshape = gumpshapes->getShape(shapeinfo->_weaponInfo->_displayGumpShape);
+ _inventoryItemGump->SetShape(invshape, shapeinfo->_weaponInfo->_displayGumpFrame);
_inventoryItemGump->UpdateDimsFromShape();
_inventoryItemGump->setRelativePosition(CENTER);
diff --git a/engines/ultima/ultima8/gumps/cru_inventory_gump.h b/engines/ultima/ultima8/gumps/cru_inventory_gump.h
index c074085dbb..f69a7941d9 100644
--- a/engines/ultima/ultima8/gumps/cru_inventory_gump.h
+++ b/engines/ultima/ultima8/gumps/cru_inventory_gump.h
@@ -52,7 +52,6 @@ public:
void saveData(Common::WriteStream *ws) override;
private:
- Shape *_inventoryShape;
Gump *_inventoryItemGump;
TextWidget *_inventoryText;
};
Commit: 52a40f33afaaa8a0c0b1dfdc2759c61c4d0d45e6
https://github.com/scummvm/scummvm/commit/52a40f33afaaa8a0c0b1dfdc2759c61c4d0d45e6
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:56+09:00
Commit Message:
ULTIMA8: Also show bombs in cru inventory
Changed paths:
engines/ultima/ultima8/world/actors/main_actor.cpp
diff --git a/engines/ultima/ultima8/world/actors/main_actor.cpp b/engines/ultima/ultima8/world/actors/main_actor.cpp
index b72169f0d5..81c90e9622 100644
--- a/engines/ultima/ultima8/world/actors/main_actor.cpp
+++ b/engines/ultima/ultima8/world/actors/main_actor.cpp
@@ -677,6 +677,7 @@ void MainActor::nextWeapon() {
void MainActor::nextInvItem() {
Std::vector<Item *> items;
getItemsWithShapeFamily(items, ShapeInfo::SF_CRUINVITEM, true);
+ getItemsWithShapeFamily(items, ShapeInfo::SF_CRUBOMB, true);
_activeInvItem = getIdOfNextItemInList(items, _activeInvItem);
}
Commit: 3b49490597eb9ac0023bafab3d961177fd9678fd
https://github.com/scummvm/scummvm/commit/3b49490597eb9ac0023bafab3d961177fd9678fd
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:56+09:00
Commit Message:
ULTIMA8: Refactor isBusy logic to Actor
Changed paths:
engines/ultima/ultima8/world/actors/actor.cpp
engines/ultima/ultima8/world/actors/actor.h
engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp
engines/ultima/ultima8/world/actors/attack_process.cpp
engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
engines/ultima/ultima8/world/actors/guard_process.cpp
engines/ultima/ultima8/world/actors/pace_process.cpp
engines/ultima/ultima8/world/actors/surrender_process.cpp
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 42ce0b2236..1331eb6c72 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -512,6 +512,11 @@ uint16 Actor::doAnim(Animation::Sequence anim, Direction dir, unsigned int steps
return Kernel::get_instance()->addProcess(p);
}
+bool Actor::isBusy() const {
+ uint32 count = Kernel::get_instance()->getNumProcesses(_objId, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE);
+ return count != 0;
+}
+
bool Actor::hasAnim(Animation::Sequence anim) {
AnimationTracker tracker;
@@ -1270,7 +1275,7 @@ ProcId Actor::killAllButFallAnims(bool death) {
if (death) {
// if dead, we want to kill everything but animations
- kernel->killProcessesNotOfType(_objId, 0xF0, true);
+ kernel->killProcessesNotOfType(_objId, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE, true);
} else {
// otherwise, need to focus on combat, so kill everything else
killAllButCombatProcesses();
@@ -2108,11 +2113,9 @@ uint32 Actor::I_areEnemiesNear(const uint8 *args, unsigned int /*argsize*/) {
}
uint32 Actor::I_isBusy(const uint8 *args, unsigned int /*argsize*/) {
- ARG_UC_PTR(ptr);
- uint16 id = UCMachine::ptrToObject(ptr);
+ ARG_ACTOR_FROM_PTR(actor);
- uint32 count = Kernel::get_instance()->getNumProcesses(id, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE);
- if (count > 0)
+ if (actor->isBusy())
return 1;
else
return 0;
diff --git a/engines/ultima/ultima8/world/actors/actor.h b/engines/ultima/ultima8/world/actors/actor.h
index 8da4011f2f..e8cbe9c637 100644
--- a/engines/ultima/ultima8/world/actors/actor.h
+++ b/engines/ultima/ultima8/world/actors/actor.h
@@ -248,6 +248,9 @@ public:
//! Get the number of directions supported by a given animation
DirectionMode animDirMode(Animation::Sequence anim) const;
+ //! True if the actor is currently doing an animation.
+ bool isBusy() const;
+
//! 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;
diff --git a/engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp b/engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp
index 88b14b82e5..3e5598befc 100644
--- a/engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp
+++ b/engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp
@@ -23,7 +23,6 @@
#include "ultima/ultima8/world/actors/actor_bark_notify_process.h"
#include "ultima/ultima8/kernel/delay_process.h"
#include "ultima/ultima8/world/actors/actor.h"
-#include "ultima/ultima8/world/actors/actor_anim_process.h"
#include "ultima/ultima8/kernel/kernel.h"
#include "ultima/ultima8/world/get_object.h"
@@ -57,7 +56,7 @@ void ActorBarkNotifyProcess::run() {
Animation::Sequence lastanim = a->getLastAnim();
if (lastanim != Animation::stand && lastanim != Animation::talk)
doAnim = false;
- else if (Kernel::get_instance()->getNumProcesses(_itemNum, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE) > 0)
+ else if (a->isBusy())
// if busy, don't do talk animation
doAnim = false;
diff --git a/engines/ultima/ultima8/world/actors/attack_process.cpp b/engines/ultima/ultima8/world/actors/attack_process.cpp
index aa407ebffa..6ba2905787 100644
--- a/engines/ultima/ultima8/world/actors/attack_process.cpp
+++ b/engines/ultima/ultima8/world/actors/attack_process.cpp
@@ -29,7 +29,6 @@
#include "ultima/ultima8/kernel/delay_process.h"
#include "ultima/ultima8/usecode/uc_list.h"
#include "ultima/ultima8/world/actors/actor.h"
-#include "ultima/ultima8/world/actors/actor_anim_process.h"
#include "ultima/ultima8/world/current_map.h"
#include "ultima/ultima8/world/get_object.h"
#include "ultima/ultima8/world/world.h"
@@ -516,8 +515,7 @@ void AttackProcess::genericAttack() {
Actor *a = getActor(_itemNum);
assert(a);
- if (Kernel::get_instance()->getNumProcesses(_itemNum, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE)
- || a->hasActorFlags(Actor::ACT_PATHFINDING)) {
+ if (a->isBusy() || a->hasActorFlags(Actor::ACT_PATHFINDING)) {
return;
}
diff --git a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
index fca71f8b2e..83e4d7bb66 100644
--- a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
@@ -40,17 +40,15 @@ AvatarMoverProcess::~AvatarMoverProcess() {
}
void AvatarMoverProcess::run() {
- Kernel *kernel = Kernel::get_instance();
+ MainActor *avatar = getMainActor();
+ assert(avatar);
// busy, so don't move
- if (kernel->getNumProcesses(1, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE) > 0) {
+ if (avatar->isBusy()) {
_idleTime = 0;
return;
}
- MainActor *avatar = getMainActor();
- assert(avatar);
-
if (avatar->getLastAnim() == Animation::hang) {
handleHangingMode();
return;
diff --git a/engines/ultima/ultima8/world/actors/guard_process.cpp b/engines/ultima/ultima8/world/actors/guard_process.cpp
index 676e582288..73de3fb143 100644
--- a/engines/ultima/ultima8/world/actors/guard_process.cpp
+++ b/engines/ultima/ultima8/world/actors/guard_process.cpp
@@ -50,8 +50,7 @@ void GuardProcess::run() {
}
// Do nothing if busy
- int activeanim = Kernel::get_instance()->getNumProcesses(a->getObjId(), ActorAnimProcess::ACTOR_ANIM_PROC_TYPE);
- if (activeanim > 0)
+ if (a->isBusy())
return;
Actor *mainactor = getMainActor();
diff --git a/engines/ultima/ultima8/world/actors/pace_process.cpp b/engines/ultima/ultima8/world/actors/pace_process.cpp
index 675ef4b790..7708d088aa 100644
--- a/engines/ultima/ultima8/world/actors/pace_process.cpp
+++ b/engines/ultima/ultima8/world/actors/pace_process.cpp
@@ -22,7 +22,6 @@
#include "ultima/ultima8/world/actors/pace_process.h"
#include "ultima/ultima8/world/actors/main_actor.h"
-#include "ultima/ultima8/world/actors/actor_anim_process.h"
#include "ultima/ultima8/misc/direction_util.h"
#include "ultima/ultima8/kernel/kernel.h"
#include "ultima/ultima8/kernel/delay_process.h"
@@ -76,7 +75,7 @@ void PaceProcess::run() {
if (maybeStartDefaultActivity1(a))
return;
- if (kernel->getNumProcesses(a->getObjId(), ActorAnimProcess::ACTOR_ANIM_PROC_TYPE)) {
+ if (a->isBusy()) {
return;
}
diff --git a/engines/ultima/ultima8/world/actors/surrender_process.cpp b/engines/ultima/ultima8/world/actors/surrender_process.cpp
index 3229bfcb4d..72363791cf 100644
--- a/engines/ultima/ultima8/world/actors/surrender_process.cpp
+++ b/engines/ultima/ultima8/world/actors/surrender_process.cpp
@@ -23,7 +23,6 @@
#include "ultima/ultima8/audio/audio_process.h"
#include "ultima/ultima8/world/actors/surrender_process.h"
#include "ultima/ultima8/world/actors/main_actor.h"
-#include "ultima/ultima8/world/actors/actor_anim_process.h"
#include "ultima/ultima8/kernel/kernel.h"
#include "ultima/ultima8/world/get_object.h"
@@ -62,16 +61,10 @@ void SurrenderProcess::run() {
return;
}
- // do nothing while we are not in the fast area
- if (!a->hasFlags(Item::FLG_FASTAREA))
+ // do nothing while we are not in the fast area or busy
+ if (!a->hasFlags(Item::FLG_FASTAREA) || a->isBusy())
return;
- int animating = Kernel::get_instance()->getNumProcesses(_itemNum, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE);
- if (animating) {
- // already busy.
- return;
- }
-
a->setActorFlag(Actor::ACT_SURRENDERED);
Direction curdir = a->getDir();
Commit: 1de427262f612baf7e1c2158879613b39f6977bd
https://github.com/scummvm/scummvm/commit/1de427262f612baf7e1c2158879613b39f6977bd
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:59:40+09:00
Commit Message:
ULTIMA8: Update crusader stance after changing weapons
Changed paths:
engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
engines/ultima/ultima8/world/actors/main_actor.cpp
diff --git a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
index 2d1af824e7..a33223ce2a 100644
--- a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
@@ -236,11 +236,11 @@ void CruAvatarMoverProcess::handleCombatMode() {
idleanim = Animation::stopRunningAndDrawSmallWeapon;
}
- // not doing anything in particular? stand. Always do the anim here as we
- // may need to switch from small wpn to large wpn
- Animation::Sequence nextanim = Animation::checkWeapon(idleanim, lastanim);
- waitFor(avatar->doAnim(nextanim, direction));
-
+ // Not doing anything in particular? stand.
+ if (lastanim != idleanim) {
+ Animation::Sequence nextanim = Animation::checkWeapon(idleanim, lastanim);
+ waitFor(avatar->doAnim(nextanim, direction));
+ }
}
void CruAvatarMoverProcess::handleNormalMode() {
@@ -330,7 +330,7 @@ void CruAvatarMoverProcess::handleNormalMode() {
return;
// doing another animation?
- if (Kernel::get_instance()->getNumProcesses(1, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE))
+ if (avatar->isBusy())
return;
// not doing anything in particular? stand
diff --git a/engines/ultima/ultima8/world/actors/main_actor.cpp b/engines/ultima/ultima8/world/actors/main_actor.cpp
index 81c90e9622..ca99520249 100644
--- a/engines/ultima/ultima8/world/actors/main_actor.cpp
+++ b/engines/ultima/ultima8/world/actors/main_actor.cpp
@@ -44,6 +44,7 @@
#include "ultima/ultima8/world/fire_type.h"
#include "ultima/ultima8/world/sprite_process.h"
#include "ultima/ultima8/world/actors/avatar_gravity_process.h"
+#include "ultima/ultima8/world/actors/actor_anim_process.h"
#include "ultima/ultima8/audio/music_process.h"
#include "ultima/ultima8/world/actors/anim_action.h"
@@ -672,6 +673,16 @@ void MainActor::nextWeapon() {
Std::vector<Item *> weapons;
getItemsWithShapeFamily(weapons, ShapeInfo::SF_CRUWEAPON, true);
_activeWeapon = getIdOfNextItemInList(weapons, _activeWeapon);
+
+ // Update combat stance in case we switched big/small weapon.
+ if (_lastAnim == Animation::combatStand) {
+ if (isBusy()) {
+ // Corner case - need to stop active "stand"
+ // animation to correct it.
+ Kernel::get_instance()->killProcesses(_objId, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE, true);
+ }
+ doAnim(Animation::combatStand, dir_current);
+ }
}
void MainActor::nextInvItem() {
Commit: 6322e399ec9d97570cba97eeaa50e650fad2a9b5
https://github.com/scummvm/scummvm/commit/6322e399ec9d97570cba97eeaa50e650fad2a9b5
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:59:43+09:00
Commit Message:
ULTIMA8: Fix fade on Crusader health/energy gumps
Changed paths:
engines/ultima/ultima8/graphics/palette.cpp
engines/ultima/ultima8/graphics/palette.h
engines/ultima/ultima8/gumps/cru_energy_gump.cpp
engines/ultima/ultima8/gumps/cru_health_gump.cpp
diff --git a/engines/ultima/ultima8/graphics/palette.cpp b/engines/ultima/ultima8/graphics/palette.cpp
index 466893e7ef..8593cde8aa 100644
--- a/engines/ultima/ultima8/graphics/palette.cpp
+++ b/engines/ultima/ultima8/graphics/palette.cpp
@@ -63,5 +63,23 @@ void Palette::load(Common::ReadStream &rs) {
_transform = Transform_None;
}
+void Palette::transformRGB(int &r_, int &g_, int &b_) const {
+ const int r = r_;
+ const int g = g_;
+ const int b = b_;
+
+ r_ = (r * _matrix[0] + g * _matrix[1] + b * _matrix[2] + 255 * _matrix[3]) / 2048;
+ if (r_ < 0) r_ = 0;
+ if (r_ > 0xFF) r_ = 0xFF;
+
+ g_ = (r * _matrix[4] + g * _matrix[5] + b * _matrix[6] + 255 * _matrix[7]) / 2048;
+ if (g_ < 0) g_ = 0;
+ if (g_ > 0xFF) g_ = 0xFF;
+
+ b_ = (r * _matrix[8] + g * _matrix[9] + b * _matrix[10] + 255 * _matrix[11]) / 2048;
+ if (b_ < 0) b_ = 0;
+ if (b_ > 0xFF) b_ = 0xFF;
+}
+
} // End of namespace Ultima8
} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/graphics/palette.h b/engines/ultima/ultima8/graphics/palette.h
index f77a0fd3a6..111140825a 100644
--- a/engines/ultima/ultima8/graphics/palette.h
+++ b/engines/ultima/ultima8/graphics/palette.h
@@ -58,6 +58,10 @@ struct Palette {
void load(Common::ReadStream &rs, Common::ReadStream &xformrs);
void load(Common::ReadStream &rs);
+ // Transform a single set of rgb values based on the current matrix.
+ // Not designed for speed - just useful for one-offs.
+ void transformRGB(int &r, int &g, int &b) const;
+
// 256 rgb entries
uint8 _palette[768];
diff --git a/engines/ultima/ultima8/gumps/cru_energy_gump.cpp b/engines/ultima/ultima8/gumps/cru_energy_gump.cpp
index ffb0bf861b..a5ee5388e0 100644
--- a/engines/ultima/ultima8/gumps/cru_energy_gump.cpp
+++ b/engines/ultima/ultima8/gumps/cru_energy_gump.cpp
@@ -23,13 +23,16 @@
#include "ultima/ultima8/gumps/cru_energy_gump.h"
#include "ultima/ultima8/world/actors/main_actor.h"
+#include "ultima/ultima8/graphics/palette_manager.h"
#include "ultima/ultima8/graphics/render_surface.h"
#include "ultima/ultima8/world/get_object.h"
namespace Ultima {
namespace Ultima8 {
-static const uint32 ENERGY_BAR_COLOR = 0xFF9A0404; // RGB: (0, 48, 113)
+static const uint32 ENERGY_BAR_R = 154;
+static const uint32 ENERGY_BAR_G = 4;
+static const uint32 ENERGY_BAR_B = 4;
DEFINE_RUNTIME_CLASSTYPE_CODE(CruEnergyGump)
@@ -61,7 +64,16 @@ void CruEnergyGump::PaintThis(RenderSurface *surf, int32 lerp_factor, bool scale
int16 energy = a->getMana();
int16 max_energy = a->getMaxMana();
int width = max_energy ? ((energy * 67) / max_energy) : 67;
- surf->Fill32(ENERGY_BAR_COLOR, 34, 7, width, 14);
+ const Palette *gamepal = PaletteManager::get_instance()->getPalette(PaletteManager::Pal_Game);
+ if (!gamepal)
+ return;
+
+ int r = ENERGY_BAR_R;
+ int g = ENERGY_BAR_G;
+ int b = ENERGY_BAR_B;
+ gamepal->transformRGB(r, g, b);
+ uint32 fillcolor = (r << 16) | (g << 8) | b;
+ surf->Fill32(fillcolor, 34, 7, width, 14);
}
void CruEnergyGump::saveData(Common::WriteStream *ws) {
diff --git a/engines/ultima/ultima8/gumps/cru_health_gump.cpp b/engines/ultima/ultima8/gumps/cru_health_gump.cpp
index 4b948375cd..81007e6dcd 100644
--- a/engines/ultima/ultima8/gumps/cru_health_gump.cpp
+++ b/engines/ultima/ultima8/gumps/cru_health_gump.cpp
@@ -23,13 +23,16 @@
#include "ultima/ultima8/gumps/cru_health_gump.h"
#include "ultima/ultima8/world/actors/main_actor.h"
+#include "ultima/ultima8/graphics/palette_manager.h"
#include "ultima/ultima8/graphics/render_surface.h"
#include "ultima/ultima8/world/get_object.h"
namespace Ultima {
namespace Ultima8 {
-static const uint32 HEALTH_BAR_COLOR = 0xFF003071; // RGB = (154, 4, 4)
+static const uint32 HEALTH_BAR_R = 0;
+static const uint32 HEALTH_BAR_G = 48;
+static const uint32 HEALTH_BAR_B = 113;
DEFINE_RUNTIME_CLASSTYPE_CODE(CruHealthGump)
@@ -62,7 +65,17 @@ void CruHealthGump::PaintThis(RenderSurface *surf, int32 lerp_factor, bool scale
int max_hp = a->getMaxHP();
// max width = 67
int width = max_hp ? ((current_hp * 67) / max_hp) : 67;
- surf->Fill32(HEALTH_BAR_COLOR, 34, 7, width, 14);
+
+ const Palette *gamepal = PaletteManager::get_instance()->getPalette(PaletteManager::Pal_Game);
+ if (!gamepal)
+ return;
+
+ int r = HEALTH_BAR_R;
+ int g = HEALTH_BAR_G;
+ int b = HEALTH_BAR_B;
+ gamepal->transformRGB(r, g, b);
+ uint32 fillcolor = (r << 16) | (g << 8) | b;
+ surf->Fill32(fillcolor, 34, 7, width, 14);
}
void CruHealthGump::saveData(Common::WriteStream *ws) {
More information about the Scummvm-git-logs
mailing list