[Scummvm-git-logs] scummvm master -> a9ae8be3c97f881c08bcc40f7d3fcf0e465be676
mduggan
mgithub at guarana.org
Wed Jul 7 10:34:22 UTC 2021
This automated email contains information about 7 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
0b4878c00e ULTIMA8: Add engine option for high res mode
627932044b ULTIMA8: Fix Crusader paint order corner case
191e7c8180 ULTIMA8: Add simple unit tests for item sorting
a1d7389f10 ULTIMA8: Remove outdated TODO comment
5e97b554d1 ULTIMA8: Fix Crusader firedistance for non-avatar NPCs
e523874936 ULTIMA8: Allow running in No Remorse rebel base.
a9ae8be3c9 ULTIMA: Regenerate ultima.dat and bump U8 data version
Commit: 0b4878c00e934210a578fbf8d673ba757ff4a691
https://github.com/scummvm/scummvm/commit/0b4878c00e934210a578fbf8d673ba757ff4a691
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-07-07T19:34:05+09:00
Commit Message:
ULTIMA8: Add engine option for high res mode
Changed paths:
engines/ultima/metaengine.cpp
engines/ultima/metaengine.h
engines/ultima/shared/engine/ultima.cpp
engines/ultima/ultima8/meta_engine.cpp
engines/ultima/ultima8/ultima8.cpp
engines/ultima/ultima8/ultima8.h
diff --git a/engines/ultima/metaengine.cpp b/engines/ultima/metaengine.cpp
index 93397d4ab9..0f59b22e13 100644
--- a/engines/ultima/metaengine.cpp
+++ b/engines/ultima/metaengine.cpp
@@ -27,6 +27,7 @@
#include "common/savefile.h"
#include "common/str-array.h"
#include "common/memstream.h"
+#include "common/translation.h"
#include "ultima/shared/early/ultima_early.h"
#include "ultima/ultima4/ultima4.h"
#include "ultima/ultima4/meta_engine.h"
diff --git a/engines/ultima/metaengine.h b/engines/ultima/metaengine.h
index ba14111f99..6d7c407dec 100644
--- a/engines/ultima/metaengine.h
+++ b/engines/ultima/metaengine.h
@@ -54,7 +54,6 @@ public:
* Return the extra GUI options used by the target.
*/
const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const override;
-
};
#endif
diff --git a/engines/ultima/shared/engine/ultima.cpp b/engines/ultima/shared/engine/ultima.cpp
index 60fdb729b2..82727d3d4e 100644
--- a/engines/ultima/shared/engine/ultima.cpp
+++ b/engines/ultima/shared/engine/ultima.cpp
@@ -76,6 +76,7 @@ bool UltimaEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsReturnToLauncher) ||
(f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsChangingOptionsDuringRuntime) ||
(f == kSupportsSavingDuringRuntime);
}
diff --git a/engines/ultima/ultima8/meta_engine.cpp b/engines/ultima/ultima8/meta_engine.cpp
index d375b41013..70bc136660 100644
--- a/engines/ultima/ultima8/meta_engine.cpp
+++ b/engines/ultima/ultima8/meta_engine.cpp
@@ -143,6 +143,12 @@ static const ExtraGuiOption COMMON_OPTIONS[] = {
"cheat",
false
},
+ {
+ _s("Enable high resolution"),
+ _s("Enable a higher resolution for the game"),
+ "usehighres",
+ false
+ },
{ nullptr, nullptr, nullptr, false }
};
diff --git a/engines/ultima/ultima8/ultima8.cpp b/engines/ultima/ultima8/ultima8.cpp
index 3e0c1d23de..dc084e7215 100644
--- a/engines/ultima/ultima8/ultima8.cpp
+++ b/engines/ultima/ultima8/ultima8.cpp
@@ -130,7 +130,8 @@ Ultima8Engine::Ultima8Engine(OSystem *syst, const Ultima::UltimaGameDescription
_avatarInStasis(false), _cruStasis(false), _paintEditorItems(false), _inversion(0),
_showTouching(false), _timeOffset(0), _hasCheated(false), _cheatsEnabled(false),
_fontOverride(false), _fontAntialiasing(false), _audioMixer(0), _inverterGump(nullptr),
- _lerpFactor(256), _inBetweenFrame(false), _unkCrusaderFlag(false), _moveKeyFrame(0) {
+ _lerpFactor(256), _inBetweenFrame(false), _unkCrusaderFlag(false), _moveKeyFrame(0),
+ _highRes(false) {
_instance = this;
}
@@ -584,11 +585,14 @@ void Ultima8Engine::paint() {
tpaint -= g_system->getMillis();
-#ifdef DEBUG
- // Fill the screen with an annoying color so we can see fast area bugs
Rect r;
_screen->GetSurfaceDims(r);
- _screen->Fill32(0xFF1010FF, 0, 0, r.width(), r.height());
+ if (_highRes)
+ _screen->Fill32(0, 0, 0, r.width(), r.height());
+
+#ifdef DEBUG
+ // Fill the screen with an annoying color so we can see fast area bugs
+ _screen->Fill32(0xFF10FF10, 0, 0, r.width(), r.height());
#endif
_desktopGump->Paint(_screen, _lerpFactor, false);
@@ -602,12 +606,16 @@ void Ultima8Engine::paint() {
}
void Ultima8Engine::GraphicSysInit() {
+ if (ConfMan.hasKey("usehighres")) {
+ _highRes = ConfMan.getBool("usehighres");
+ }
+
if (GAME_IS_U8) {
- ConfMan.registerDefault("width", U8_DEFAULT_SCREEN_WIDTH);
- ConfMan.registerDefault("height", U8_DEFAULT_SCREEN_HEIGHT);
+ ConfMan.registerDefault("width", _highRes ? U8_HIRES_SCREEN_WIDTH : U8_DEFAULT_SCREEN_WIDTH);
+ ConfMan.registerDefault("height", _highRes ? U8_HIRES_SCREEN_HEIGHT : U8_DEFAULT_SCREEN_HEIGHT);
} else {
- ConfMan.registerDefault("width", CRUSADER_DEFAULT_SCREEN_WIDTH);
- ConfMan.registerDefault("height", CRUSADER_DEFAULT_SCREEN_HEIGHT);
+ ConfMan.registerDefault("width", _highRes ? CRUSADER_HIRES_SCREEN_WIDTH : CRUSADER_DEFAULT_SCREEN_WIDTH);
+ ConfMan.registerDefault("height", _highRes ? CRUSADER_HIRES_SCREEN_HEIGHT : CRUSADER_DEFAULT_SCREEN_HEIGHT);
}
ConfMan.registerDefault("bpp", 16);
@@ -1204,7 +1212,6 @@ void Ultima8Engine::applyGameSettings() {
_frameLimit = ConfMan.getBool("frameLimit");
_interpolate = ConfMan.getBool("interpolate");
_cheatsEnabled = ConfMan.getBool("cheat");
-
}
void Ultima8Engine::openConfigDialog() {
diff --git a/engines/ultima/ultima8/ultima8.h b/engines/ultima/ultima8/ultima8.h
index a35011ec68..b74a526dc1 100644
--- a/engines/ultima/ultima8/ultima8.h
+++ b/engines/ultima/ultima8/ultima8.h
@@ -106,6 +106,7 @@ private:
int32 _lerpFactor; //!< Interpolation factor for this frame (0-256)
bool _inBetweenFrame; //!< Set true if we are doing an inbetween frame
+ bool _highRes; //!< Set to true to enable larger screen size
bool _frameSkip; //!< Set to true to enable frame skipping (default false)
bool _frameLimit; //!< Set to true to enable frame limiting (default true)
bool _interpolate; //!< Set to true to enable interpolation (default true)
@@ -216,6 +217,11 @@ public:
static const int CRUSADER_DEFAULT_SCREEN_WIDTH = 640;
static const int CRUSADER_DEFAULT_SCREEN_HEIGHT = 480;
+ static const int U8_HIRES_SCREEN_WIDTH = 640;
+ static const int U8_HIRES_SCREEN_HEIGHT = 400;
+ static const int CRUSADER_HIRES_SCREEN_WIDTH = 1024;
+ static const int CRUSADER_HIRES_SCREEN_HEIGHT = 768;
+
INTRINSIC(I_getCurrentTimerTick);
INTRINSIC(I_setAvatarInStasis);
INTRINSIC(I_getAvatarInStasis);
Commit: 627932044bac482107ecfa2dca77b8269e114d7d
https://github.com/scummvm/scummvm/commit/627932044bac482107ecfa2dca77b8269e114d7d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-07-07T19:34:05+09:00
Commit Message:
ULTIMA8: Fix Crusader paint order corner case
Changed paths:
engines/ultima/ultima8/graphics/shape_info.h
engines/ultima/ultima8/world/item_sorter.cpp
diff --git a/engines/ultima/ultima8/graphics/shape_info.h b/engines/ultima/ultima8/graphics/shape_info.h
index 4156a55e18..44bf4261ac 100644
--- a/engines/ultima/ultima8/graphics/shape_info.h
+++ b/engines/ultima/ultima8/graphics/shape_info.h
@@ -147,6 +147,9 @@ public:
inline bool is_targetable() const {
return (_flags & (SI_OCCL | SI_CRU_TARGETABLE));
}
+ inline bool is_invitem() const {
+ return (_family == SF_CRUINVITEM);
+ }
bool hasQuantity() const {
return (_family == SF_QUANTITY || _family == SF_REAGENT);
diff --git a/engines/ultima/ultima8/world/item_sorter.cpp b/engines/ultima/ultima8/world/item_sorter.cpp
index 3554a7ec7c..ea1d43a067 100644
--- a/engines/ultima/ultima8/world/item_sorter.cpp
+++ b/engines/ultima/ultima8/world/item_sorter.cpp
@@ -109,6 +109,7 @@ struct SortItem {
bool _fixed : 1;
bool _land : 1;
bool _sprite : 1; // Always-on-top sprite, for Crusader (U8 sprites appear in z order)
+ bool _invitem : 1; // Crusader inventory item, should appear above other things
bool _occluded : 1; // Set true if occluded
bool _clipped : 1; // Clipped to RenderSurface
@@ -309,6 +310,18 @@ inline bool SortItem::below(const SortItem &si2) const {
if (si1._sprite != si2._sprite)
return si1._sprite < si2._sprite;
+ // Clearly in y?
+ if (si1._y <= si2._yFar)
+ return true;
+ if (si1._yFar >= si2._y)
+ return false;
+
+ // Clearly in x?
+ if (si1._x <= si2._xLeft)
+ return true;
+ if (si1._xLeft >= si2._x)
+ return false;
+
// Specialist z flat handling
if (si1._flat && si2._flat) {
// Differing z is easy for flats
@@ -343,25 +356,22 @@ inline bool SortItem::below(const SortItem &si2) const {
}
// Mixed, or non flat
else {
+ // Inv items always drawn first if their z-bottom is equal or higher.
+ // This is a bit of a hack as 2 places in Crusader there are keycards
+ // on tables but their z position is the bottom z of the table.
+ if (si1._invitem) {
+ if (si1._z >= si2._z)
+ return false;
+ }
+
// Clearly in z
if (si1._zTop <= si2._z)
return true;
+
if (si1._z >= si2._zTop)
return false;
}
- // Clearly in y?
- if (si1._y <= si2._yFar)
- return true;
- if (si1._yFar >= si2._y)
- return false;
-
- // Clearly in x?
- if (si1._x <= si2._xLeft)
- return true;
- if (si1._xLeft >= si2._x)
- return false;
-
// Are overlapping in all 3 dimentions if we come here
// Overlapping z-bottom check
@@ -553,7 +563,10 @@ void ItemSorter::AddItem(int32 x, int32 y, int32 z, uint32 shapeNum, uint32 fram
si->_trans = info->is_translucent();
si->_fixed = info->is_fixed();
si->_land = info->is_land();
- si->_sprite = GAME_IS_CRUSADER && (si->_extFlags & Item::EXT_SPRITE);
+ if (GAME_IS_CRUSADER) {
+ si->_sprite = si->_extFlags & Item::EXT_SPRITE;
+ si->_invitem = info->is_invitem();
+ }
si->_occluded = false;
si->_order = -1;
Commit: 191e7c818059bc95f9fca7f123d122b8f9bb3c1a
https://github.com/scummvm/scummvm/commit/191e7c818059bc95f9fca7f123d122b8f9bb3c1a
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-07-07T19:34:05+09:00
Commit Message:
ULTIMA8: Add simple unit tests for item sorting
Changed paths:
A engines/ultima/ultima8/world/sort_item.h
A test/engines/ultima/ultima8/world/sort_item.h
engines/ultima/ultima8/world/item_sorter.cpp
diff --git a/engines/ultima/ultima8/world/item_sorter.cpp b/engines/ultima/ultima8/world/item_sorter.cpp
index ea1d43a067..1e475a40b8 100644
--- a/engines/ultima/ultima8/world/item_sorter.cpp
+++ b/engines/ultima/ultima8/world/item_sorter.cpp
@@ -37,408 +37,11 @@
#include "ultima/ultima8/world/get_object.h"
// --
+#include "ultima/ultima8/world/sort_item.h"
+
namespace Ultima {
namespace Ultima8 {
-// This does NOT need to be in the header
-struct SortItem {
- SortItem(SortItem *n) : _next(n), _prev(nullptr), _itemNum(0),
- _shape(nullptr), _order(-1), _depends(), _shapeNum(0),
- _frame(0), _flags(0), _extFlags(0), _sx(0), _sy(0),
- _sx2(0), _sy2(0), _x(0), _y(0), _z(0), _xLeft(0),
- _yFar(0), _zTop(0), _sxLeft(0), _sxRight(0), _sxTop(0),
- _syTop(0), _sxBot(0), _syBot(0),_f32x32(false), _flat(false),
- _occl(false), _solid(false), _draw(false), _roof(false),
- _noisy(false), _anim(false), _trans(false), _fixed(false),
- _land(false), _occluded(false), _clipped(false), _sprite(false) { }
-
- SortItem *_next;
- SortItem *_prev;
-
- uint16 _itemNum; // Owner item number
-
- const Shape *_shape;
- uint32 _shapeNum;
- uint32 _frame;
- uint32 _flags; // Item flags
- uint32 _extFlags; // Item extended flags
-
- int _sx, _sx2; // Screenspace X coords
- int _sy, _sy2; // Screenspace Y coords
-
- /*
- Bounding Box layout
-
- 1
- / \
- / \ 1 = Left Far Top LFT --+
- 2 3 2 = Left Near Top LNT -++
- | \ / | 3 = Right Far Top RFT +-+
- | \ / | 4 = Right Near Top RNT +++
- | 4 | 5 = Left Near Bot LNB -+-
- | | | 6 = Right Far Bot RFB +--
- 5 | 6 7 = Right Near Bot RNB ++-
- \ | / 8 = Left Far Bot LFB --- (not shown)
- \ | /
- 7
-
- */
-
- int32 _x, _xLeft; // Worldspace bounding box x (xright = x)
- int32 _y, _yFar; // Worldspace bounding box y (ynear = y)
- int32 _z, _zTop; // Worldspace bounding box z (_zTop = z)
-
- int32 _sxLeft; // Screenspace bounding box left extent (LNT x coord)
- int32 _sxRight; // Screenspace bounding box right extent (RFT x coord)
-
- int32 _sxTop; // Screenspace bounding box top x coord (LFT x coord)
- int32 _syTop; // Screenspace bounding box top extent (LFT y coord)
-
- int32 _sxBot; // Screenspace bounding box bottom x coord (RNB x coord) ss origin
- int32 _syBot; // Screenspace bounding box bottom extent (RNB y coord) ss origin
-
- bool _f32x32 : 1; // Needs 1 bit 0
- bool _flat : 1; // Needs 1 bit 1
- bool _occl : 1; // Needs 1 bit 2
- bool _solid : 1; // Needs 1 bit 3
- bool _draw : 1; // Needs 1 bit 4
- bool _roof : 1; // Needs 1 bit 5
- bool _noisy : 1; // Needs 1 bit 6
- bool _anim : 1; // Needs 1 bit 7
- bool _trans : 1; // Needs 1 bit 8
- bool _fixed : 1;
- bool _land : 1;
- bool _sprite : 1; // Always-on-top sprite, for Crusader (U8 sprites appear in z order)
- bool _invitem : 1; // Crusader inventory item, should appear above other things
-
- bool _occluded : 1; // Set true if occluded
- bool _clipped : 1; // Clipped to RenderSurface
-
- int32 _order; // Rendering _order. -1 is not yet drawn
-
- // Note that Std::priority_queue could be used here, BUT there is no guarentee that it's implementation
- // will be friendly to insertions
- // Alternatively i could use Std::list, BUT there is no guarentee that it will keep wont delete
- // the unused nodes after doing a clear
- // So the only reasonable solution is to write my own list
- struct DependsList {
- struct Node {
- Node *_next;
- Node *_prev;
- SortItem *val;
- Node() : _next(nullptr), _prev(nullptr), val(nullptr) { }
- };
-
- Node *list;
- Node *tail;
- Node *unused;
-
- struct iterator {
- Node *n;
- SortItem *&operator *() {
- return n->val;
- }
- iterator(Node *node) : n(node) { }
- iterator &operator++() {
- n = n->_next;
- return *this;
- }
- bool operator != (const iterator &o) const {
- return n != o.n;
- }
- };
-
- iterator begin() const {
- return iterator(list);
- }
- iterator end() const {
- return iterator(nullptr);
- }
-
- void clear() {
- if (tail) {
- tail->_next = unused;
- unused = list;
- tail = nullptr;
- list = nullptr;
- }
- }
-
- void push_back(SortItem *other) {
- if (!unused) unused = new Node();
- Node *nn = unused;
- unused = unused->_next;
- nn->val = other;
-
- // Put it at the end
- if (tail) tail->_next = nn;
- if (!list) list = nn;
- nn->_next = nullptr;
- nn->_prev = tail;
- tail = nn;
- }
-
- void insert_sorted(SortItem *other) {
- if (!unused) unused = new Node();
- Node *nn = unused;
- unused = unused->_next;
- nn->val = other;
-
- for (Node *n = list; n != nullptr; n = n->_next) {
- // Get the insert point... which is before the first item that has higher z than us
- if (other->ListLessThan(n->val)) {
- nn->_next = n;
- nn->_prev = n->_prev;
- n->_prev = nn;
- if (nn->_prev) nn->_prev->_next = nn;
- else list = nn;
- return;
- }
- }
-
- // No suitable, so put at end
- if (tail) tail->_next = nn;
- if (!list) list = nn;
- nn->_next = nullptr;
- nn->_prev = tail;
- tail = nn;
- }
-
- DependsList() : list(nullptr), tail(nullptr), unused(nullptr) { }
-
- ~DependsList() {
- clear();
- while (unused) {
- Node *n = unused->_next;
- delete unused;
- unused = n;
- }
- }
- };
-
- //Std::vector<SortItem *> _depends; // All this Items dependencies (i.e. all objects behind)
- //Std::list<SortItem *> _depends; // All this Items dependencies (i.e. all objects behind)
- DependsList _depends;
-
- // Functions
-
- // Screenspace check to see if this overlaps si2
- inline bool overlap(const SortItem &si2) const;
-
- // Screenspace check to see if this occludes si2. Assumes this is above of si2
- inline bool occludes(const SortItem &si2) const;
-
- // Screenspace check to see if this is below si2. Assumes this overlaps si2
- inline bool below(const SortItem &si2) const;
-
- // Comparison for the sorted lists
- inline bool ListLessThan(const SortItem *other) const {
- return _z < other->_z || (_z == other->_z && _flat && !other->_flat);
- }
-
-};
-
-inline bool SortItem::overlap(const SortItem &si2) const {
- const int point_top_diff[2] = { _sxTop - si2._sxBot, _syTop - si2._syBot };
- const int point_bot_diff[2] = { _sxBot - si2._sxTop, _syBot - si2._syTop };
-
- // This function is a bit of a hack. It uses dot products between
- // points and the lines. Nothing is normalized since that isn't
- // important
-
- // 'normal' of top left line ( 2,-1) of the bounding box
- const int32 dot_top_left = point_top_diff[0] + point_top_diff[1] * 2;
-
- // 'normal' of top right line ( 2, 1) of the bounding box
- const int32 dot_top_right = -point_top_diff[0] + point_top_diff[1] * 2;
-
- // 'normal' of bot left line (-2,-1) of the bounding box
- const int32 dot_bot_left = point_bot_diff[0] - point_bot_diff[1] * 2;
-
- // 'normal' of bot right line (-2, 1) of the bounding box
- const int32 dot_bot_right = -point_bot_diff[0] - point_bot_diff[1] * 2;
-
- const bool right_clear = _sxRight <= si2._sxLeft;
- const bool left_clear = _sxLeft >= si2._sxRight;
- const bool top_left_clear = dot_top_left >= 0;
- const bool top_right_clear = dot_top_right >= 0;
- const bool bot_left_clear = dot_bot_left >= 0;
- const bool bot_right_clear = dot_bot_right >= 0;
-
- const bool clear = right_clear || left_clear ||
- (bot_right_clear || bot_left_clear) ||
- (top_right_clear || top_left_clear);
-
- return !clear;
-}
-
-inline bool SortItem::occludes(const SortItem &si2) const {
- const int point_top_diff[2] = { _sxTop - si2._sxTop, _syTop - si2._syTop };
- const int point_bot_diff[2] = { _sxBot - si2._sxBot, _syBot - si2._syBot };
-
- // This function is a bit of a hack. It uses dot products between
- // points and the lines. Nothing is normalized since that isn't
- // important
-
- // 'normal' of top left line ( 2, -1) of the bounding box
- const int32 dot_top_left = point_top_diff[0] + point_top_diff[1] * 2;
-
- // 'normal' of top right line ( 2, 1) of the bounding box
- const int32 dot_top_right = -point_top_diff[0] + point_top_diff[1] * 2;
-
- // 'normal' of bot left line (-2,-1) of the bounding box
- const int32 dot_bot_left = point_bot_diff[0] - point_bot_diff[1] * 2;
-
- // 'normal' of bot right line (-2, 1) of the bounding box
- const int32 dot_bot_right = -point_bot_diff[0] - point_bot_diff[1] * 2;
-
-
- const bool right_res = _sxRight >= si2._sxRight;
- const bool left_res = _sxLeft <= si2._sxLeft;
- const bool top_left_res = dot_top_left <= 0;
- const bool top_right_res = dot_top_right <= 0;
- const bool bot_left_res = dot_bot_left <= 0;
- const bool bot_right_res = dot_bot_right <= 0;
-
- return right_res && left_res && bot_right_res && bot_left_res &&
- top_right_res && top_left_res;
-}
-
-inline bool SortItem::below(const SortItem &si2) const {
- const SortItem &si1 = *this;
-
- if (si1._sprite != si2._sprite)
- return si1._sprite < si2._sprite;
-
- // Clearly in y?
- if (si1._y <= si2._yFar)
- return true;
- if (si1._yFar >= si2._y)
- return false;
-
- // Clearly in x?
- if (si1._x <= si2._xLeft)
- return true;
- if (si1._xLeft >= si2._x)
- return false;
-
- // Specialist z flat handling
- if (si1._flat && si2._flat) {
- // Differing z is easy for flats
- if (si1._zTop != si2._zTop)
- return si1._zTop < si2._zTop;
-
- // Equal z
-
- // Animated always gets drawn after
- if (si1._anim != si2._anim)
- return si1._anim < si2._anim;
-
- // Trans always gets drawn after
- if (si1._trans != si2._trans)
- return si1._trans < si2._trans;
-
- // Draw always gets drawn first
- if (si1._draw != si2._draw)
- return si1._draw > si2._draw;
-
- // Solid always gets drawn first
- if (si1._solid != si2._solid)
- return si1._solid > si2._solid;
-
- // Occludes always get drawn first
- if (si1._occl != si2._occl)
- return si1._occl > si2._occl;
-
- // 32x32 flats get drawn first
- if (si1._f32x32 != si2._f32x32)
- return si1._f32x32 > si2._f32x32;
- }
- // Mixed, or non flat
- else {
- // Inv items always drawn first if their z-bottom is equal or higher.
- // This is a bit of a hack as 2 places in Crusader there are keycards
- // on tables but their z position is the bottom z of the table.
- if (si1._invitem) {
- if (si1._z >= si2._z)
- return false;
- }
-
- // Clearly in z
- if (si1._zTop <= si2._z)
- return true;
-
- if (si1._z >= si2._zTop)
- return false;
- }
-
- // Are overlapping in all 3 dimentions if we come here
-
- // Overlapping z-bottom check
- // If an object's base (z-bottom) is higher another's, it should be rendered after.
- // This check must be on the z-bottom and not the z-top because two objects with the
- // same z-position may have different heights (think of a mouse sorting vs the Avatar).
- if (si1._z != si2._z)
- return si1._z < si2._z;
-
- // Partial in X + Y front
- if (si1._x + si1._y != si2._x + si2._y)
- return (si1._x + si1._y < si2._x + si2._y);
-
- // Partial in X + Y back
- if (si1._xLeft + si1._yFar != si2._xLeft + si2._yFar)
- return (si1._xLeft + si1._yFar < si2._xLeft + si2._yFar);
-
- // Partial in y?
- if (si1._y != si2._y)
- return si1._y < si2._y;
-
- // Partial in x?
- if (si1._x != si2._x)
- return si1._x < si2._x;
-
- // Just sort by shape number
- if (si1._shapeNum != si2._shapeNum)
- return si1._shapeNum < si2._shapeNum;
-
- // And then by _frame
- return si1._frame < si2._frame;
-}
-
-ConsoleStream &operator<<(ConsoleStream &cs, const SortItem &si) {
- cs << si._shapeNum << ":" << si._frame <<
- " (" << si._xLeft << "," << si._yFar << "," << si._z << ")" <<
- " (" << si._x << "," << si._y << "," << si._zTop << "): ";
- if (si._sprite)
- cs << "sprite ";
- if (si._flat)
- cs << "flat ";
- if (si._anim)
- cs << "anim ";
- if (si._trans)
- cs << "trans ";
- if (si._draw)
- cs << "draw ";
- if (si._solid)
- cs << "solid ";
- if (si._occl)
- cs << "occl ";
- if (si._f32x32)
- cs << "f32x32 ";
- if (si._roof)
- cs << "roof ";
- if (si._land)
- cs << "land ";
- if (si._noisy)
- cs << "noisy ";
-
- return cs;
-}
-
-//
-// ItemSorter
-//
-
ItemSorter::ItemSorter() :
_shapes(nullptr), _surf(nullptr), _items(nullptr), _itemsTail(nullptr),
_itemsUnused(nullptr), _sortLimit(0), _camSx(0), _camSy(0), _orderCounter(0) {
diff --git a/engines/ultima/ultima8/world/sort_item.h b/engines/ultima/ultima8/world/sort_item.h
new file mode 100644
index 0000000000..d867e33171
--- /dev/null
+++ b/engines/ultima/ultima8/world/sort_item.h
@@ -0,0 +1,438 @@
+/* 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 ULTIMA8_WORLD_SORTITEM_H
+#define ULTIMA8_WORLD_SORTITEM_H
+
+#include "ultima/ultima8/misc/common_types.h"
+#include "ultima/ultima8/misc/debugger.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+class Shape;
+
+/**
+ * This class is basically private to ItemSorter, but is in a separate header
+ * to enable unit testing.
+ *
+ * Other code should have no reason to include it.
+ */
+struct SortItem {
+ SortItem(SortItem *n) : _next(n), _prev(nullptr), _itemNum(0),
+ _shape(nullptr), _order(-1), _depends(), _shapeNum(0),
+ _frame(0), _flags(0), _extFlags(0), _sx(0), _sy(0),
+ _sx2(0), _sy2(0), _x(0), _y(0), _z(0), _xLeft(0),
+ _yFar(0), _zTop(0), _sxLeft(0), _sxRight(0), _sxTop(0),
+ _syTop(0), _sxBot(0), _syBot(0),_f32x32(false), _flat(false),
+ _occl(false), _solid(false), _draw(false), _roof(false),
+ _noisy(false), _anim(false), _trans(false), _fixed(false),
+ _land(false), _occluded(false), _clipped(false), _sprite(false),
+ _invitem(false) { }
+
+ SortItem *_next;
+ SortItem *_prev;
+
+ uint16 _itemNum; // Owner item number
+
+ const Shape *_shape;
+ uint32 _shapeNum;
+ uint32 _frame;
+ uint32 _flags; // Item flags
+ uint32 _extFlags; // Item extended flags
+
+ int _sx, _sx2; // Screenspace X coords
+ int _sy, _sy2; // Screenspace Y coords
+
+ /*
+ Bounding Box layout
+
+ 1
+ / \
+ / \ 1 = Left Far Top LFT --+
+ 2 3 2 = Left Near Top LNT -++
+ | \ / | 3 = Right Far Top RFT +-+
+ | \ / | 4 = Right Near Top RNT +++
+ | 4 | 5 = Left Near Bot LNB -+-
+ | | | 6 = Right Far Bot RFB +--
+ 5 | 6 7 = Right Near Bot RNB ++-
+ \ | / 8 = Left Far Bot LFB --- (not shown)
+ \ | /
+ 7
+
+ */
+
+ int32 _x, _xLeft; // Worldspace bounding box x (xright = x)
+ int32 _y, _yFar; // Worldspace bounding box y (ynear = y)
+ int32 _z, _zTop; // Worldspace bounding box z (_zTop = z)
+
+ int32 _sxLeft; // Screenspace bounding box left extent (LNT x coord)
+ int32 _sxRight; // Screenspace bounding box right extent (RFT x coord)
+
+ int32 _sxTop; // Screenspace bounding box top x coord (LFT x coord)
+ int32 _syTop; // Screenspace bounding box top extent (LFT y coord)
+
+ int32 _sxBot; // Screenspace bounding box bottom x coord (RNB x coord) ss origin
+ int32 _syBot; // Screenspace bounding box bottom extent (RNB y coord) ss origin
+
+ bool _f32x32 : 1; // Needs 1 bit 0
+ bool _flat : 1; // Needs 1 bit 1
+ bool _occl : 1; // Needs 1 bit 2
+ bool _solid : 1; // Needs 1 bit 3
+ bool _draw : 1; // Needs 1 bit 4
+ bool _roof : 1; // Needs 1 bit 5
+ bool _noisy : 1; // Needs 1 bit 6
+ bool _anim : 1; // Needs 1 bit 7
+ bool _trans : 1; // Needs 1 bit 8
+ bool _fixed : 1;
+ bool _land : 1;
+ bool _sprite : 1; // Always-on-top sprite, for Crusader (U8 sprites appear in z order)
+ bool _invitem : 1; // Crusader inventory item, should appear above other things
+
+ bool _occluded : 1; // Set true if occluded
+ bool _clipped : 1; // Clipped to RenderSurface
+
+ int32 _order; // Rendering _order. -1 is not yet drawn
+
+ // Note that Std::priority_queue could be used here, BUT there is no guarentee that it's implementation
+ // will be friendly to insertions
+ // Alternatively i could use Std::list, BUT there is no guarentee that it will keep wont delete
+ // the unused nodes after doing a clear
+ // So the only reasonable solution is to write my own list
+ struct DependsList {
+ struct Node {
+ Node *_next;
+ Node *_prev;
+ SortItem *val;
+ Node() : _next(nullptr), _prev(nullptr), val(nullptr) { }
+ };
+
+ Node *list;
+ Node *tail;
+ Node *unused;
+
+ struct iterator {
+ Node *n;
+ SortItem *&operator *() {
+ return n->val;
+ }
+ iterator(Node *node) : n(node) { }
+ iterator &operator++() {
+ n = n->_next;
+ return *this;
+ }
+ bool operator != (const iterator &o) const {
+ return n != o.n;
+ }
+ };
+
+ iterator begin() const {
+ return iterator(list);
+ }
+ iterator end() const {
+ return iterator(nullptr);
+ }
+
+ void clear() {
+ if (tail) {
+ tail->_next = unused;
+ unused = list;
+ tail = nullptr;
+ list = nullptr;
+ }
+ }
+
+ void push_back(SortItem *other) {
+ if (!unused) unused = new Node();
+ Node *nn = unused;
+ unused = unused->_next;
+ nn->val = other;
+
+ // Put it at the end
+ if (tail) tail->_next = nn;
+ if (!list) list = nn;
+ nn->_next = nullptr;
+ nn->_prev = tail;
+ tail = nn;
+ }
+
+ void insert_sorted(SortItem *other) {
+ if (!unused) unused = new Node();
+ Node *nn = unused;
+ unused = unused->_next;
+ nn->val = other;
+
+ for (Node *n = list; n != nullptr; n = n->_next) {
+ // Get the insert point... which is before the first item that has higher z than us
+ if (other->ListLessThan(n->val)) {
+ nn->_next = n;
+ nn->_prev = n->_prev;
+ n->_prev = nn;
+ if (nn->_prev) nn->_prev->_next = nn;
+ else list = nn;
+ return;
+ }
+ }
+
+ // No suitable, so put at end
+ if (tail) tail->_next = nn;
+ if (!list) list = nn;
+ nn->_next = nullptr;
+ nn->_prev = tail;
+ tail = nn;
+ }
+
+ DependsList() : list(nullptr), tail(nullptr), unused(nullptr) { }
+
+ ~DependsList() {
+ clear();
+ while (unused) {
+ Node *n = unused->_next;
+ delete unused;
+ unused = n;
+ }
+ }
+ };
+
+ //Std::vector<SortItem *> _depends; // All this Items dependencies (i.e. all objects behind)
+ //Std::list<SortItem *> _depends; // All this Items dependencies (i.e. all objects behind)
+ DependsList _depends;
+
+ // Functions
+
+ // Screenspace check to see if this overlaps si2
+ inline bool overlap(const SortItem &si2) const;
+
+ // Screenspace check to see if this occludes si2. Assumes this is above of si2
+ inline bool occludes(const SortItem &si2) const;
+
+ // Screenspace check to see if this is below si2. Assumes this overlaps si2
+ inline bool below(const SortItem &si2) const;
+
+ // Comparison for the sorted lists
+ inline bool ListLessThan(const SortItem *other) const {
+ return _z < other->_z || (_z == other->_z && _flat && !other->_flat);
+ }
+
+};
+
+inline bool SortItem::overlap(const SortItem &si2) const {
+ const int point_top_diff[2] = { _sxTop - si2._sxBot, _syTop - si2._syBot };
+ const int point_bot_diff[2] = { _sxBot - si2._sxTop, _syBot - si2._syTop };
+
+ // This function is a bit of a hack. It uses dot products between
+ // points and the lines. Nothing is normalized since that isn't
+ // important
+
+ // 'normal' of top left line ( 2,-1) of the bounding box
+ const int32 dot_top_left = point_top_diff[0] + point_top_diff[1] * 2;
+
+ // 'normal' of top right line ( 2, 1) of the bounding box
+ const int32 dot_top_right = -point_top_diff[0] + point_top_diff[1] * 2;
+
+ // 'normal' of bot left line (-2,-1) of the bounding box
+ const int32 dot_bot_left = point_bot_diff[0] - point_bot_diff[1] * 2;
+
+ // 'normal' of bot right line (-2, 1) of the bounding box
+ const int32 dot_bot_right = -point_bot_diff[0] - point_bot_diff[1] * 2;
+
+ const bool right_clear = _sxRight <= si2._sxLeft;
+ const bool left_clear = _sxLeft >= si2._sxRight;
+ const bool top_left_clear = dot_top_left >= 0;
+ const bool top_right_clear = dot_top_right >= 0;
+ const bool bot_left_clear = dot_bot_left >= 0;
+ const bool bot_right_clear = dot_bot_right >= 0;
+
+ const bool clear = right_clear || left_clear ||
+ (bot_right_clear || bot_left_clear) ||
+ (top_right_clear || top_left_clear);
+
+ return !clear;
+}
+
+inline bool SortItem::occludes(const SortItem &si2) const {
+ const int point_top_diff[2] = { _sxTop - si2._sxTop, _syTop - si2._syTop };
+ const int point_bot_diff[2] = { _sxBot - si2._sxBot, _syBot - si2._syBot };
+
+ // This function is a bit of a hack. It uses dot products between
+ // points and the lines. Nothing is normalized since that isn't
+ // important
+
+ // 'normal' of top left line ( 2, -1) of the bounding box
+ const int32 dot_top_left = point_top_diff[0] + point_top_diff[1] * 2;
+
+ // 'normal' of top right line ( 2, 1) of the bounding box
+ const int32 dot_top_right = -point_top_diff[0] + point_top_diff[1] * 2;
+
+ // 'normal' of bot left line (-2,-1) of the bounding box
+ const int32 dot_bot_left = point_bot_diff[0] - point_bot_diff[1] * 2;
+
+ // 'normal' of bot right line (-2, 1) of the bounding box
+ const int32 dot_bot_right = -point_bot_diff[0] - point_bot_diff[1] * 2;
+
+
+ const bool right_res = _sxRight >= si2._sxRight;
+ const bool left_res = _sxLeft <= si2._sxLeft;
+ const bool top_left_res = dot_top_left <= 0;
+ const bool top_right_res = dot_top_right <= 0;
+ const bool bot_left_res = dot_bot_left <= 0;
+ const bool bot_right_res = dot_bot_right <= 0;
+
+ return right_res && left_res && bot_right_res && bot_left_res &&
+ top_right_res && top_left_res;
+}
+
+inline bool SortItem::below(const SortItem &si2) const {
+ const SortItem &si1 = *this;
+
+ if (si1._sprite != si2._sprite)
+ return si1._sprite < si2._sprite;
+
+ // Clearly in y?
+ if (si1._y <= si2._yFar)
+ return true;
+ if (si1._yFar >= si2._y)
+ return false;
+
+ // Clearly in x?
+ if (si1._x <= si2._xLeft)
+ return true;
+ if (si1._xLeft >= si2._x)
+ return false;
+
+ // Specialist z flat handling
+ if (si1._flat && si2._flat) {
+ // Differing z is easy for flats
+ if (si1._zTop != si2._zTop)
+ return si1._zTop < si2._zTop;
+
+ // Equal z
+
+ // Animated always gets drawn after
+ if (si1._anim != si2._anim)
+ return si1._anim < si2._anim;
+
+ // Trans always gets drawn after
+ if (si1._trans != si2._trans)
+ return si1._trans < si2._trans;
+
+ // Draw always gets drawn first
+ if (si1._draw != si2._draw)
+ return si1._draw > si2._draw;
+
+ // Solid always gets drawn first
+ if (si1._solid != si2._solid)
+ return si1._solid > si2._solid;
+
+ // Occludes always get drawn first
+ if (si1._occl != si2._occl)
+ return si1._occl > si2._occl;
+
+ // 32x32 flats get drawn first
+ if (si1._f32x32 != si2._f32x32)
+ return si1._f32x32 > si2._f32x32;
+ }
+ // Mixed, or non flat
+ else {
+ // Inv items always drawn first if their z-bottom is equal or higher.
+ // This is a bit of a hack as 2 places in Crusader there are keycards
+ // on tables but their z position is the bottom z of the table.
+ if (si1._invitem) {
+ if (si1._z >= si2._z)
+ return false;
+ }
+
+ // Clearly in z
+ if (si1._zTop <= si2._z)
+ return true;
+
+ if (si1._z >= si2._zTop)
+ return false;
+ }
+
+ // Are overlapping in all 3 dimentions if we come here
+
+ // Overlapping z-bottom check
+ // If an object's base (z-bottom) is higher another's, it should be rendered after.
+ // This check must be on the z-bottom and not the z-top because two objects with the
+ // same z-position may have different heights (think of a mouse sorting vs the Avatar).
+ if (si1._z != si2._z)
+ return si1._z < si2._z;
+
+ // Partial in X + Y front
+ if (si1._x + si1._y != si2._x + si2._y)
+ return (si1._x + si1._y < si2._x + si2._y);
+
+ // Partial in X + Y back
+ if (si1._xLeft + si1._yFar != si2._xLeft + si2._yFar)
+ return (si1._xLeft + si1._yFar < si2._xLeft + si2._yFar);
+
+ // Partial in y?
+ if (si1._y != si2._y)
+ return si1._y < si2._y;
+
+ // Partial in x?
+ if (si1._x != si2._x)
+ return si1._x < si2._x;
+
+ // Just sort by shape number
+ if (si1._shapeNum != si2._shapeNum)
+ return si1._shapeNum < si2._shapeNum;
+
+ // And then by _frame
+ return si1._frame < si2._frame;
+}
+
+ConsoleStream &operator<<(ConsoleStream &cs, const SortItem &si) {
+ cs << si._shapeNum << ":" << si._frame <<
+ " (" << si._xLeft << "," << si._yFar << "," << si._z << ")" <<
+ " (" << si._x << "," << si._y << "," << si._zTop << "): ";
+ if (si._sprite)
+ cs << "sprite ";
+ if (si._flat)
+ cs << "flat ";
+ if (si._anim)
+ cs << "anim ";
+ if (si._trans)
+ cs << "trans ";
+ if (si._draw)
+ cs << "draw ";
+ if (si._solid)
+ cs << "solid ";
+ if (si._occl)
+ cs << "occl ";
+ if (si._f32x32)
+ cs << "f32x32 ";
+ if (si._roof)
+ cs << "roof ";
+ if (si._land)
+ cs << "land ";
+ if (si._noisy)
+ cs << "noisy ";
+
+ return cs;
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif
diff --git a/test/engines/ultima/ultima8/world/sort_item.h b/test/engines/ultima/ultima8/world/sort_item.h
new file mode 100644
index 0000000000..f471816b4a
--- /dev/null
+++ b/test/engines/ultima/ultima8/world/sort_item.h
@@ -0,0 +1,77 @@
+#include <cxxtest/TestSuite.h>
+#include "engines/ultima/ultima8/world/sort_item.h"
+
+/**
+ * Test suite for the functions in engines/ultima/ultima8/world/sort_item.h
+ *
+ * Be aware that the x and y coordinates go opposite to what you might expect,
+ * see the notes in sort_item.h
+ *
+ * Still TODO tests:
+ * * overlapping in various dimensions
+ * * flat (z == zTop) items with various flags
+ * * special case for crusader inventory items
+ * * items that are flat in x or y (what should these do?)
+ */
+class U8SortItemTestSuite : public CxxTest::TestSuite {
+ public:
+ U8SortItemTestSuite() {
+ }
+
+ /* Non-overlapping with lower Y position should always be below */
+ void test_basic_y_sort() {
+ Ultima::Ultima8::SortItem si1(nullptr);
+ Ultima::Ultima8::SortItem si2(nullptr);
+
+ si1._yFar = 0;
+ si1._y = 10;
+ si2._yFar = 20;
+ si2._y = 30;
+ si1._x = si2._x = 10;
+ TS_ASSERT(si1.below(si2));
+ TS_ASSERT(!si2.below(si1));
+ }
+
+ /* Non-overlapping with lower X position should always be below */
+ void test_basic_x_sort() {
+ Ultima::Ultima8::SortItem si1(nullptr);
+ Ultima::Ultima8::SortItem si2(nullptr);
+
+ si1._y = si2._y = 10;
+ si1._x = 10;
+ si2._xLeft = 20;
+ si2._x = 30;
+ TS_ASSERT(si1.below(si2));
+ TS_ASSERT(!si2.below(si1));
+ }
+
+ /* Non-overlapping with lower Z position should always be below */
+ void test_basic_z_sort() {
+ Ultima::Ultima8::SortItem si1(nullptr);
+ Ultima::Ultima8::SortItem si2(nullptr);
+
+ si1._x = si2._x = si1._y = si2._y = 10;
+ si1._zTop = 10;
+ si2._z = 20;
+ si2._zTop = 30;
+ TS_ASSERT(si1.below(si2));
+ TS_ASSERT(!si2.below(si1));
+ }
+
+ /* Sprites should always be at the top regardless of x/y/z */
+ void test_sprite_sort() {
+ Ultima::Ultima8::SortItem si1(nullptr);
+ Ultima::Ultima8::SortItem si2(nullptr);
+
+ si2._sprite = true;
+ TS_ASSERT(si1.below(si2));
+ TS_ASSERT(!si2.below(si1));
+
+ si2._x = si2._xLeft = si1._y = si2._yFar = 10;
+ si2._z = 20;
+ si2._zTop = 30;
+ TS_ASSERT(si1.below(si2));
+ TS_ASSERT(!si2.below(si1));
+ }
+
+};
Commit: a1d7389f106eaa50777d6eda485da5504edd1083
https://github.com/scummvm/scummvm/commit/a1d7389f106eaa50777d6eda485da5504edd1083
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-07-07T19:34:05+09:00
Commit Message:
ULTIMA8: Remove outdated TODO comment
Changed paths:
engines/ultima/ultima8/world/item.cpp
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index c616e7e610..908dea3ee4 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -1366,7 +1366,6 @@ uint16 Item::fireDistance(const Item *other, Direction dir, int16 xoff, int16 yo
else
anim = Animation::kneelAndFireLargeWeapon;
} else {
- // TODO: fireLarge seems to be different ID in Regret, check me.
if (ma || smallwpn)
anim = Animation::fireSmallWeapon;
else
Commit: 5e97b554d11d7a21de78c6744628c8f9b229cc5c
https://github.com/scummvm/scummvm/commit/5e97b554d11d7a21de78c6744628c8f9b229cc5c
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-07-07T19:34:05+09:00
Commit Message:
ULTIMA8: Fix Crusader firedistance for non-avatar NPCs
Changed paths:
engines/ultima/ultima8/world/item.cpp
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index 908dea3ee4..6336a19432 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -1366,7 +1366,7 @@ uint16 Item::fireDistance(const Item *other, Direction dir, int16 xoff, int16 yo
else
anim = Animation::kneelAndFireLargeWeapon;
} else {
- if (ma || smallwpn)
+ if (smallwpn || !ma)
anim = Animation::fireSmallWeapon;
else
anim = Animation::fireLargeWeapon;
Commit: e523874936ae9e7dd733f9ea7cb41634ce1ec762
https://github.com/scummvm/scummvm/commit/e523874936ae9e7dd733f9ea7cb41634ce1ec762
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-07-07T19:34:05+09:00
Commit Message:
ULTIMA8: Allow running in No Remorse rebel base.
Changed paths:
engines/ultima/ultima8/world/actors/cru_avatar_mover_process.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 548697626a..3be9ac8af4 100644
--- a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
@@ -310,7 +310,12 @@ void CruAvatarMoverProcess::handleNormalMode() {
if (!hasMovementFlags(MOVE_ANY_DIRECTION) && lastanim == Animation::run) {
// if we were running, slow to a walk before stopping
// (even in stasis)
- waitFor(avatar->doAnim(Animation::stopRunningAndDrawSmallWeapon, direction));
+ Animation::Sequence nextanim;
+ if (rebelBase)
+ nextanim = Animation::stand;
+ else
+ nextanim = Animation::stopRunningAndDrawSmallWeapon;
+ waitFor(avatar->doAnim(nextanim, direction));
avatar->setInCombat(0);
return;
}
@@ -330,7 +335,7 @@ void CruAvatarMoverProcess::handleNormalMode() {
Animation::Sequence nextanim = Animation::walk;
- if (!rebelBase && hasMovementFlags(MOVE_RUN)) {
+ if (hasMovementFlags(MOVE_RUN)) {
if (lastanim == Animation::run
|| lastanim == Animation::startRun
|| lastanim == Animation::startRunSmallWeapon
Commit: a9ae8be3c97f881c08bcc40f7d3fcf0e465be676
https://github.com/scummvm/scummvm/commit/a9ae8be3c97f881c08bcc40f7d3fcf0e465be676
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-07-07T19:34:05+09:00
Commit Message:
ULTIMA: Regenerate ultima.dat and bump U8 data version
* Updates information for Crusader games
* Remove Thumbs.db files from zip
* Bump data version number to 2.0
Changed paths:
devtools/create_ultima/files/ultima8/version.txt
dists/engine-data/ultima.dat
engines/ultima/ultima8/ultima8.cpp
diff --git a/devtools/create_ultima/files/ultima8/version.txt b/devtools/create_ultima/files/ultima8/version.txt
index d3827e75a5..cd5ac039d6 100644
--- a/devtools/create_ultima/files/ultima8/version.txt
+++ b/devtools/create_ultima/files/ultima8/version.txt
@@ -1 +1 @@
-1.0
+2.0
diff --git a/dists/engine-data/ultima.dat b/dists/engine-data/ultima.dat
index 1b18ac3f07..7e861baf46 100644
Binary files a/dists/engine-data/ultima.dat and b/dists/engine-data/ultima.dat differ
diff --git a/engines/ultima/ultima8/ultima8.cpp b/engines/ultima/ultima8/ultima8.cpp
index dc084e7215..42f4d49377 100644
--- a/engines/ultima/ultima8/ultima8.cpp
+++ b/engines/ultima/ultima8/ultima8.cpp
@@ -1624,7 +1624,9 @@ uint32 Ultima8Engine::I_moveKeyDownRecently(const uint8 *args, unsigned int /*ar
bool Ultima8Engine::isDataRequired(Common::String &folder, int &majorVersion, int &minorVersion) {
folder = "ultima8";
- majorVersion = 1;
+ // Version 1: Initial release
+ // Version 2: Add data for Crusader games
+ majorVersion = 2;
minorVersion = 0;
return true;
}
More information about the Scummvm-git-logs
mailing list