[Scummvm-git-logs] scummvm master -> 7b467a7fd2dfcba4e73d6cb46d1394b138815094
mduggan
mgithub at guarana.org
Thu Jul 2 01:29:48 UTC 2020
This automated email contains information about 5 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
0565afc256 ULTIMA8: Fix searching for alarm panels on alert active
cf3f253d2e ULTIMA8: Play sounds in keypad
d4fab29cab ULTIMA8: Fix potential null deref from coverity
8016bbb426 ULTIMA8: Initial support for Crusader target reticle
7b467a7fd2 ULTIMA8: Fix crusader ambient audio target
Commit: 0565afc256ae344e6f7ed118ffa87f364d9a68b4
https://github.com/scummvm/scummvm/commit/0565afc256ae344e6f7ed118ffa87f364d9a68b4
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-02T10:19:30+09:00
Commit Message:
ULTIMA8: Fix searching for alarm panels on alert active
Changed paths:
engines/ultima/ultima8/world/world.cpp
diff --git a/engines/ultima/ultima8/world/world.cpp b/engines/ultima/ultima8/world/world.cpp
index fb658d960b..466d89bf12 100644
--- a/engines/ultima/ultima8/world/world.cpp
+++ b/engines/ultima/ultima8/world/world.cpp
@@ -417,20 +417,22 @@ void World::setAlertActive(bool active)
UCList itemlist(2);
_world->getCurrentMap()->areaSearch(&itemlist, script, sizeof(script),
- nullptr, 0x7fff, false);
+ nullptr, 0xffff, false);
for (uint32 i = 0; i < itemlist.getSize(); i++) {
uint16 itemid = itemlist.getuint16(i);
Item *item = getItem(itemid);
int frame = item->getFrame();
if (_alertActive) {
- if (item->getShape() == 0x477 && frame < 2) {
- item->setFrame(frame + 2);
+ if (item->getShape() == 0x477) {
+ if (frame < 2)
+ item->setFrame(frame + 2);
} else if (frame == 0) {
item->setFrame(1);
}
} else {
- if (item->getShape() == 0x477 && frame > 1) {
- item->setFrame(frame + 2);
+ if (item->getShape() == 0x477) {
+ if (frame > 1)
+ item->setFrame(frame - 2);
} else if (frame == 1) {
item->setFrame(0);
}
Commit: cf3f253d2e5483385bffedfc24e0868db89cc5ce
https://github.com/scummvm/scummvm/commit/cf3f253d2e5483385bffedfc24e0868db89cc5ce
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-02T10:19:30+09:00
Commit Message:
ULTIMA8: Play sounds in keypad
Changed paths:
engines/ultima/ultima8/gumps/keypad_gump.cpp
diff --git a/engines/ultima/ultima8/gumps/keypad_gump.cpp b/engines/ultima/ultima8/gumps/keypad_gump.cpp
index b212ce6371..ebb3cf96c0 100644
--- a/engines/ultima/ultima8/gumps/keypad_gump.cpp
+++ b/engines/ultima/ultima8/gumps/keypad_gump.cpp
@@ -96,28 +96,33 @@ bool KeypadGump::OnKeyDown(int key, int mod) {
void KeypadGump::ChildNotify(Gump *child, uint32 message) {
//ObjId cid = child->getObjId();
if (message == ButtonWidget::BUTTON_CLICK) {
+ uint16 sfxno = 0;
int buttonNo = child->GetIndex();
if (buttonNo < 9) {
_value *= 10;
_value += buttonNo + 1;
+ sfxno = 0x3b;
} else if (buttonNo == 10) {
_value *= 10;
+ sfxno = 0x3b;
} else if (buttonNo == 9) {
_value /= 10;
+ sfxno = 0x3a;
} else if (buttonNo == 11) {
- AudioProcess *audio = AudioProcess::get_instance();
// TODO: Do something as a result of this other than just play a sound.
if (_value == _targetValue) {
- if (audio)
- audio->playSFX(0x32, 0x10, _objId, 1);
+ sfxno = 0x32;
Close();
+ // Note: careful, this is now deleted.
} else {
// wrong.
- if (audio)
- audio->playSFX(0x31, 0x10, _objId, 1);
+ sfxno = 0x31;
_value = 0;
}
}
+ AudioProcess *audio = AudioProcess::get_instance();
+ if (audio && sfxno)
+ audio->playSFX(sfxno, 0x10, _objId, 1);
}
}
Commit: d4fab29cabab80fdf5fe5e6ac49c0afbefbf98bd
https://github.com/scummvm/scummvm/commit/d4fab29cabab80fdf5fe5e6ac49c0afbefbf98bd
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-02T10:19:30+09:00
Commit Message:
ULTIMA8: Fix potential null deref from coverity
Changed paths:
engines/ultima/ultima8/world/actors/cru_healer_process.cpp
diff --git a/engines/ultima/ultima8/world/actors/cru_healer_process.cpp b/engines/ultima/ultima8/world/actors/cru_healer_process.cpp
index 0649779990..eb6b11ca7e 100644
--- a/engines/ultima/ultima8/world/actors/cru_healer_process.cpp
+++ b/engines/ultima/ultima8/world/actors/cru_healer_process.cpp
@@ -60,7 +60,7 @@ void CruHealerProcess::run() {
AudioProcess *audio = AudioProcess::get_instance();
if (!avatar || avatar->isDead() || avatar->getHP() >= _targetMaxHP) {
- if (avatar->getHP() >= _targetMaxHP) {
+ if (avatar && avatar->getHP() >= _targetMaxHP) {
Ultima8Engine::get_instance()->setAvatarInStasis(false);
}
// dead or finished healing
Commit: 8016bbb4265df8da2f8fa793e1c156c52f075989
https://github.com/scummvm/scummvm/commit/8016bbb4265df8da2f8fa793e1c156c52f075989
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-02T10:28:54+09:00
Commit Message:
ULTIMA8: Initial support for Crusader target reticle
Changed paths:
A engines/ultima/ultima8/world/target_reticle_process.cpp
A engines/ultima/ultima8/world/target_reticle_process.h
engines/ultima/module.mk
engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
engines/ultima/ultima8/graphics/shape_info.h
engines/ultima/ultima8/graphics/type_flags.cpp
engines/ultima/ultima8/ultima8.cpp
engines/ultima/ultima8/usecode/remorse_intrinsics.h
engines/ultima/ultima8/world/actors/actor.cpp
engines/ultima/ultima8/world/current_map.cpp
engines/ultima/ultima8/world/current_map.h
engines/ultima/ultima8/world/item.cpp
engines/ultima/ultima8/world/item.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 60eb24c8ba..f539f12dab 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -539,6 +539,7 @@ MODULE_OBJS := \
ultima8/world/monster_egg.o \
ultima8/world/split_item_process.o \
ultima8/world/sprite_process.o \
+ ultima8/world/target_reticle_process.o \
ultima8/world/teleport_egg.o \
ultima8/world/world.o \
ultima8/world/actors/actor.o \
diff --git a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
index a6494e307c..53f251527c 100644
--- a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
+++ b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
@@ -215,7 +215,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
"int16 Item::I_getNpcNum(Item *)", // part of same coff set 067, 06D, 089, 08E, 0AD, 0F8, 100, 102, 105, 107, 109, 10B, 10D, 10F, 111, 115, 11C, 123, 129
"void Intrinsic08A(12 bytes)", // TODO: No idea here.. something about hurling? look at the usecode.
"int16 Item::I_enterFastArea(Item *)", // based on disasm, v similar to U8
- "void Item::I_doSomethingAndSetStatusFlag0x8000(Item *)", // same coff as 119, 12A
+ "void Item::I_setIsBroken(Item *)", // same coff as 119, 12A
"int16 Item::I_hurl(Item *,8 bytes)", // part of same coff set 028, 08D, 0BD, 0C0, 0C2, 0C8, 0F7, 0F9, 118, 11D
"int16 Item::I_getNPCNum(Item *)", // part of same coff set 067, 06D, 089, 08E, 0AD, 0F8, 100, 102, 105, 107, 109, 10B, 10D, 10F, 111, 115, 11C, 123, 129
"void PaletteFaderProcess::I_setPalToAllBlack(void)",
@@ -365,7 +365,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
"byte Intrinsic116(14 bytes)", // something like distance-to?
"void Item::I_andStatus(Item *, uint16 status)", // part of same coff set 01A, 031, 069, 06E, 099, 0B2, 0BF, 0C1, 0C3, 0E9, 0FC, 101, 104, 106, 108, 10A, 10C, 10E, 110, 114, 117, 11A, 128, 132
"int16 Item::I_hurl(Item *,8 bytes)", // part of same coff set 028, 08D, 0BD, 0C0, 0C2, 0C8, 0F7, 0F9, 118, 11D
- "void Item::I_doSomethingAndSetStatusFlag0x8000(Item *)", // same coff as 08C, 12A
+ "void Item::I_setIsBroken(Item *)", // same coff as 08C, 12A
"void Item::I_andStatus(Item *, uint16 status)", // part of same coff set 01A, 031, 069, 06E, 099, 0B2, 0BF, 0C1, 0C3, 0E9, 0FC, 101, 104, 106, 108, 10A, 10C, 10E, 110, 114, 117, 11A, 128, 132
"byte Item::I_getTypeFlag(Item *, uint16 shift)",
"int16 Item::I_getNPCNum(Item *)", // part of same coff set 067, 06D, 089, 08E, 0AD, 0F8, 100, 102, 105, 107, 109, 10B, 10D, 10F, 111, 115, 11C, 123, 129
@@ -383,7 +383,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
"byte Item::I_getDirToCoords(Item *, uin16 x, uint16 y)", // based on disassembly - FIXME: returns 2* values from U8
"void Item::I_andStatus(Item *, uint16 status)", // part of same coff set 01A, 031, 069, 06E, 099, 0B2, 0BF, 0C1, 0C3, 0E9, 0FC, 101, 104, 106, 108, 10A, 10C, 10E, 110, 114, 117, 11A, 128, 132
"int16 Item::I_getNPCNum(Item *)", // part of same coff set 067, 06D, 089, 08E, 0AD, 0F8, 100, 102, 105, 107, 109, 10B, 10D, 10F, 111, 115, 11C, 123, 129
- "void Item::I_doSomethingAndSetStatusFlag0x8000(Item *)", // same coff as 08C, 119
+ "void Item::I_setIsBroken(Item *)", // same coff as 08C, 119
"int16 IItem::I_getCY(Item *)", // same coff as 11E
"byte Item::I_isOn(Item *, itemno)", // part of same coff set 044, 046, 048, 04A, 04C, 04E, 0A5, 0BC, 0C5, 0DC, 0F1, 0FA, 12C
"void Item::I_getFootpadData(Item *, uint *, uint *, uint *)", // same coff as 064
diff --git a/engines/ultima/ultima8/graphics/shape_info.h b/engines/ultima/ultima8/graphics/shape_info.h
index b03c4b0f2b..825138b74d 100644
--- a/engines/ultima/ultima8/graphics/shape_info.h
+++ b/engines/ultima/ultima8/graphics/shape_info.h
@@ -52,7 +52,7 @@ public:
SI_CRUSUNK61 = 0x2000,
SI_CRUSUNK62 = 0x4000,
SI_CRUSUNK63 = 0x8000,
- SI_CRUSUNK64 = 0x10000,
+ SI_TARGETABLE= 0x10000,
SI_CRUS_NPC = 0x20000,
SI_CRUSUNK66 = 0x40000,
SI_CRUSUNK67 = 0x80000
diff --git a/engines/ultima/ultima8/graphics/type_flags.cpp b/engines/ultima/ultima8/graphics/type_flags.cpp
index 871a0df873..56f0a28030 100644
--- a/engines/ultima/ultima8/graphics/type_flags.cpp
+++ b/engines/ultima/ultima8/graphics/type_flags.cpp
@@ -145,7 +145,7 @@ void TypeFlags::load(Common::SeekableReadStream *rs) {
if (data[6] & 0x02) si._flags |= ShapeInfo::SI_CRUSUNK61;
if (data[6] & 0x04) si._flags |= ShapeInfo::SI_CRUSUNK62;
if (data[6] & 0x08) si._flags |= ShapeInfo::SI_CRUSUNK63;
- if (data[6] & 0x10) si._flags |= ShapeInfo::SI_CRUSUNK64;
+ if (data[6] & 0x10) si._flags |= ShapeInfo::SI_TARGETABLE;
if (data[6] & 0x20) si._flags |= ShapeInfo::SI_CRUS_NPC;
if (data[6] & 0x40) si._flags |= ShapeInfo::SI_CRUSUNK66;
if (data[6] & 0x80) si._flags |= ShapeInfo::SI_CRUSUNK67;
diff --git a/engines/ultima/ultima8/ultima8.cpp b/engines/ultima/ultima8/ultima8.cpp
index 7337b61e45..5f85340efa 100644
--- a/engines/ultima/ultima8/ultima8.cpp
+++ b/engines/ultima/ultima8/ultima8.cpp
@@ -90,14 +90,17 @@
#include "ultima/ultima8/world/actors/avatar_gravity_process.h"
#include "ultima/ultima8/world/actors/teleport_to_egg_process.h"
#include "ultima/ultima8/world/item_factory.h"
+#include "ultima/ultima8/world/split_item_process.h"
+#include "ultima/ultima8/world/target_reticle_process.h"
#include "ultima/ultima8/world/actors/pathfinder_process.h"
#include "ultima/ultima8/world/actors/avatar_mover_process.h"
#include "ultima/ultima8/world/actors/resurrection_process.h"
-#include "ultima/ultima8/world/split_item_process.h"
#include "ultima/ultima8/world/actors/clear_feign_death_process.h"
#include "ultima/ultima8/world/actors/loiter_process.h"
#include "ultima/ultima8/world/actors/avatar_death_process.h"
#include "ultima/ultima8/world/actors/grant_peace_process.h"
+#include "ultima/ultima8/world/actors/cru_healer_process.h"
+#include "ultima/ultima8/world/actors/surrender_process.h"
#include "ultima/ultima8/world/actors/combat_process.h"
#include "ultima/ultima8/world/fireball_process.h"
#include "ultima/ultima8/world/destroy_item_process.h"
@@ -273,6 +276,14 @@ void Ultima8Engine::startup() {
ProcessLoader<ActorBarkNotifyProcess>::load);
_kernel->addProcessLoader("AmbushProcess",
ProcessLoader<AmbushProcess>::load);
+ _kernel->addProcessLoader("TargetReticleProcess",
+ ProcessLoader<TargetReticleProcess>::load);
+ _kernel->addProcessLoader("SurrenderProcess",
+ ProcessLoader<SurrenderProcess>::load);
+ _kernel->addProcessLoader("CruHealerProcess",
+ ProcessLoader<CruHealerProcess>::load);
+ _kernel->addProcessLoader("BatteryChargerProcess",
+ ProcessLoader<BatteryChargerProcess>::load);
_objectManager = new ObjectManager();
_mouse = new Mouse();
@@ -1100,6 +1111,10 @@ bool Ultima8Engine::newGame(int saveSlot) {
_game->startInitialUsecode(saveSlot);
+ if (GAME_IS_CRUSADER) {
+ _kernel->addProcess(new TargetReticleProcess());
+ }
+
if (saveSlot == -1)
_settingMan->set("lastSave", "");
diff --git a/engines/ultima/ultima8/usecode/remorse_intrinsics.h b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
index 40f493d535..64321df270 100644
--- a/engines/ultima/ultima8/usecode/remorse_intrinsics.h
+++ b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
@@ -183,7 +183,7 @@ Intrinsic RemorseIntrinsics[] = {
Item::I_getNpcNum, // based on same coff as 102 (-> variable name in TRIGGER::ordinal21)
0, // void Intrinsic08A(12 bytes)
Item::I_enterFastArea, // void Intrinsic08B(4 bytes)
- Item::I_doSomethingAndSetUnkCruFlag, // void Intrinsic08C(4 bytes)
+ Item::I_setBroken, // void Intrinsic08C(4 bytes)
Item::I_hurl, // void Intrinsic08D(12 bytes)
Item::I_getNpcNum, // based on same coff as 102 (-> variable name in TRIGGER::ordinal21)
0, // TODO: PaletteFaderProcess::I_setPalToAllBlack
@@ -333,7 +333,7 @@ Intrinsic RemorseIntrinsics[] = {
0, // byte Intrinsic116(14 bytes)
Item::I_andStatus, // void Intrinsic117(6 bytes)
Item::I_hurl, // int16 Intrinsic118(12 bytes)
- Item::I_doSomethingAndSetUnkCruFlag, // void Intrinsic119(4 bytes)
+ Item::I_setBroken, // void Intrinsic119(4 bytes)
Item::I_andStatus, // void Intrinsic11A(6 bytes)
Item::I_getTypeFlag, // byte Intrinsic11B(6 bytes)
Item::I_getNpcNum, // based on same coff as 102 (-> variable name in TRIGGER::ordinal21)
@@ -351,7 +351,7 @@ Intrinsic RemorseIntrinsics[] = {
Item::I_getDirToCoords, // int Intrinsic127(8 bytes)
Item::I_andStatus, // void Intrinsic128(6 bytes) // maybe Item::andStatus?? see ITEM::ordinal22
Item::I_getNpcNum, // based on same coff as 102 (-> variable name in TRIGGER::ordinal21)
- Item::I_doSomethingAndSetUnkCruFlag, // void Intrinsic12A(4 bytes)
+ Item::I_setBroken, // void Intrinsic12A(4 bytes)
Item::I_getCY, // void Intrinsic12B(4 bytes)
Item::I_isOn,
Item::I_getFootpadData, // void Intrinsic12D(16 bytes)
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 68ddaa06ec..83f93494b6 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -815,6 +815,7 @@ void Actor::receiveHit(uint16 other, int dir, int damage, uint16 damage_type) {
ProcId Actor::die(uint16 damageType) {
setHP(0);
setActorFlag(ACT_DEAD);
+ setFlag(FLG_BROKEN);
clearActorFlag(ACT_INCOMBAT);
ProcId animprocid = 0;
@@ -1509,9 +1510,11 @@ uint32 Actor::I_setDead(const uint8 *args, unsigned int /*argsize*/) {
ARG_ACTOR_FROM_PTR(actor);
if (!actor) return 0;
- // TODO: In crusader this function also sets flag 0x8000 on
- // the actor. Do we need to do that here?
actor->setActorFlag(ACT_DEAD);
+ if (GAME_IS_CRUSADER) {
+ actor->setFlag(FLG_BROKEN);
+ World::get_instance()->getCurrentMap()->removeTargetItem(actor);
+ }
return 0;
}
@@ -1521,6 +1524,10 @@ uint32 Actor::I_clrDead(const uint8 *args, unsigned int /*argsize*/) {
if (!actor) return 0;
actor->clearActorFlag(ACT_DEAD);
+ if (GAME_IS_CRUSADER) {
+ actor->clearFlag(FLG_BROKEN);
+ World::get_instance()->getCurrentMap()->addTargetItem(actor);
+ }
return 0;
}
diff --git a/engines/ultima/ultima8/world/current_map.cpp b/engines/ultima/ultima8/world/current_map.cpp
index 0e0e1a5a65..c8c47b28dc 100644
--- a/engines/ultima/ultima8/world/current_map.cpp
+++ b/engines/ultima/ultima8/world/current_map.cpp
@@ -62,6 +62,10 @@ CurrentMap::CurrentMap() : _currentMap(0), _eggHatcher(0),
} else {
CANT_HAPPEN_MSG("Unknown game type in CurrentMap constructor.");
}
+
+ for (unsigned int i = 0; i < MAP_NUM_TARGET_ITEMS; i++) {
+ _targets[i] = 0;
+ }
}
@@ -279,6 +283,80 @@ void CurrentMap::removeItem(Item *item) {
removeItemFromList(item, ix, iy);
}
+void CurrentMap::addTargetItem(const Item *item) {
+ assert(item);
+ // The game also maintains a count of non-zero targets, but it
+ // seems to serve little purpose so we just update.
+ ObjId id = item->getObjId();
+ for (int i = 0; i < MAP_NUM_TARGET_ITEMS; i++) {
+ if (_targets[i] == 0) {
+ _targets[i] = id;
+ return;
+ }
+ }
+}
+
+void CurrentMap::removeTargetItem(const Item *item) {
+ assert(item);
+ ObjId id = item->getObjId();
+ for (int i = 0; i < MAP_NUM_TARGET_ITEMS; i++) {
+ if (_targets[i] == id) {
+ _targets[i] = 0;
+ return;
+ }
+ }
+}
+
+
+Item *CurrentMap::findBestTargetItem(int32 x, int32 y, uint8 dir) {
+ // "best" means:
+ // Shape info SI_OCCL
+ // isNPC
+ // Closest
+ // in that order.
+ bool bestisnpc = false;
+ bool bestisoccl = false;
+ Item *bestitem = nullptr;
+ int bestdist = 0xffff;
+
+ for (int i = 0; i < MAP_NUM_TARGET_ITEMS; i++) {
+ if (_targets[i] == 0)
+ continue;
+ Item *item = getItem(_targets[i]);
+ // FIXME: this should probably always be non-null,
+ // but if it's not the item disappeared - remove it from the list.
+ // If we fix this, this function can be const.
+ if (!item) {
+ _targets[i] = 0;
+ continue;
+ }
+ const ShapeInfo *si = item->getShapeInfo();
+ bool isoccl = si->_flags & ShapeInfo::SI_OCCL;
+
+ int ix, iy, iz;
+ item->getLocation(ix, iy, iz);
+ Direction itemdir = Get_WorldDirection(iy - y, ix - x);
+ if (itemdir != dir)
+ continue;
+
+ const Actor *actor = dynamic_cast<const Actor *>(item);
+ if ((bestisoccl && !isoccl) || (bestisnpc && !actor) || !item->isOnScreen())
+ continue;
+
+ int xdiff = abs(x - ix);
+ int ydiff = abs(y - iy);
+ int dist = MAX(xdiff, ydiff);
+
+ if (dist < bestdist) {
+ bestitem = item;
+ bestdist = dist;
+ bestisoccl = isoccl;
+ bestisnpc = (actor != nullptr);
+ }
+ }
+ return bestitem;
+}
+
void CurrentMap::removeItemFromList(Item *item, int32 oldx, int32 oldy) {
//! This might a bit too inefficient
diff --git a/engines/ultima/ultima8/world/current_map.h b/engines/ultima/ultima8/world/current_map.h
index 0f29a0530e..d814006761 100644
--- a/engines/ultima/ultima8/world/current_map.h
+++ b/engines/ultima/ultima8/world/current_map.h
@@ -36,6 +36,7 @@ class TeleportEgg;
class EggHatcherProcess;
#define MAP_NUM_CHUNKS 64
+#define MAP_NUM_TARGET_ITEMS 200
class CurrentMap {
friend class World;
@@ -69,6 +70,13 @@ public:
void removeItemFromList(Item *item, int32 oldx, int32 oldy);
void removeItem(Item *item);
+ //! Add an item to the list of possible targets (in Crusader)
+ void addTargetItem(const Item *item);
+ //! Remove an item from the list of possible targets (in Crusader)
+ void removeTargetItem(const Item *item);
+ //! Find the best target item in the given direction
+ Item *findBestTargetItem(int32 x, int32 y, uint8 dir);
+
//! Update the fast area for the cameras position
void updateFastArea(int32 from_x, int32 from_y, int32 from_z, int32 to_x, int32 to_y, int32 to_z);
@@ -224,6 +232,10 @@ private:
int _mapChunkSize;
+ //! Items that are "targetable" in Crusader. It might be faster to store
+ //! this in a more fancy data structure, but this works fine.
+ ObjId _targets[200];
+
void setChunkFast(int32 cx, int32 cy);
void unsetChunkFast(int32 cx, int32 cy);
};
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index 668c5a269b..2a10668493 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -461,6 +461,8 @@ void Item::setShape(uint32 shape_) {
_shape = shape_;
_cachedShapeInfo = nullptr;
_cachedShape = nullptr;
+ // FIXME: In Crusader, here we should check if the shape
+ // changed from targetable to not-targetable, or vice-versa
}
bool Item::overlaps(const Item &item2) const {
@@ -1438,7 +1440,8 @@ void Item::animateItem() {
// Called when an item has entered the fast area
void Item::enterFastArea() {
//!! HACK to get rid of endless SFX loops
- if (_shape == 0x2c8) return;
+ if (_shape == 0x2c8 && GAME_IS_U8)
+ return;
// Call usecode
if (!(_flags & FLG_FASTAREA)) {
@@ -1451,6 +1454,13 @@ void Item::enterFastArea() {
}
}
+ if (!hasFlags(FLG_BROKEN) && GAME_IS_CRUSADER) {
+ ShapeInfo *si = getShapeInfo();
+ if ((si->_flags & ShapeInfo::SI_TARGETABLE) || (si->_flags & ShapeInfo::SI_OCCL)) {
+ World::get_instance()->getCurrentMap()->addTargetItem(this);
+ }
+ }
+
// We're fast!
_flags |= FLG_FASTAREA;
}
@@ -1471,6 +1481,10 @@ void Item::leaveFastArea() {
// Unset the flag
_flags &= ~FLG_FASTAREA;
+ if (!hasFlags(FLG_BROKEN) && GAME_IS_CRUSADER) {
+ World::get_instance()->getCurrentMap()->removeTargetItem(this);
+ }
+
// CHECKME: what do we need to do exactly?
// currently, destroy object
@@ -1656,13 +1670,14 @@ void Item::explode(int explosion_type, bool destroy_item) {
Process *p;
if (GAME_IS_CRUSADER) {
+ setFlag(FLG_BROKEN);
// TODO: original game puts them at cx/cy/cz, but that looks wrong..
//int32 cx, cy, cz;
//getCentre(cx, cy, cz);
static const int expshapes[] = {0x31C, 0x31F, 0x326, 0x320, 0x321, 0x324, 0x323, 0x325};
int rnd = getRandom();
int spriteno;
- // NOTE: The game does some weird 32-bit struff to decide what
+ // NOTE: The game does some weird 32-bit stuff to decide what
// shapenum to use. Just simplified to a random.
switch (explosion_type) {
case 0:
@@ -3343,12 +3358,13 @@ uint32 Item::I_isCrusTypeNPC(const uint8 *args, unsigned int /*argsize*/) {
return 0;
}
-uint32 Item::I_doSomethingAndSetUnkCruFlag(const uint8 *args, unsigned int /*argsize*/) {
+uint32 Item::I_setBroken(const uint8 *args, unsigned int /*argsize*/) {
ARG_ITEM_FROM_PTR(item);
+ if (!item)
+ return 0;
- // TODO: Do something.. (to match disassembly)
-
- item->setFlag(FLG_UNK_CRU);
+ World::get_instance()->getCurrentMap()->removeTargetItem(item);
+ item->setFlag(FLG_BROKEN);
return 0;
}
diff --git a/engines/ultima/ultima8/world/item.h b/engines/ultima/ultima8/world/item.h
index 1328a34ee3..88280d7044 100644
--- a/engines/ultima/ultima8/world/item.h
+++ b/engines/ultima/ultima8/world/item.h
@@ -557,7 +557,7 @@ public:
INTRINSIC(I_getRange);
INTRINSIC(I_getRangeIfVisible);
INTRINSIC(I_isCrusTypeNPC);
- INTRINSIC(I_doSomethingAndSetUnkCruFlag);
+ INTRINSIC(I_setBroken);
INTRINSIC(I_inFastArea);
INTRINSIC(I_equip);
INTRINSIC(I_unequip);
@@ -624,7 +624,7 @@ public:
FLG_HANGING = 0x1000, //!< Item is suspended in the air
FLG_FASTAREA = 0x2000, //!< Item is in the fast area
FLG_LOW_FRICTION = 0x4000, //!< Item has low friction
- FLG_UNK_CRU = 0x8000 //!< Unknown crusader flag
+ FLG_BROKEN = 0x8000 //!< Item is broken - Crusader only - broken items are not targetable.
};
enum extflags {
@@ -636,7 +636,7 @@ public:
EXT_SPRITE = 0x0040, //!< Item is a sprite
EXT_TRANSPARENT = 0x0080, //!< Item should be painted transparent
EXT_PERMANENT_NPC = 0x0100, //!< Item is a permanent NPC
- EXT_FEMALE = 0x8000 //!< Crusader Female NPC (controls sfx)
+ EXT_FEMALE = 0x8000 //!< Item is Crusader Female NPC (controls sfx)
};
};
diff --git a/engines/ultima/ultima8/world/target_reticle_process.cpp b/engines/ultima/ultima8/world/target_reticle_process.cpp
new file mode 100644
index 0000000000..3210ef8446
--- /dev/null
+++ b/engines/ultima/ultima8/world/target_reticle_process.cpp
@@ -0,0 +1,132 @@
+/* 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/misc/pent_include.h"
+
+#include "ultima/ultima8/kernel/kernel.h"
+#include "ultima/ultima8/world/actors/main_actor.h"
+#include "ultima/ultima8/world/target_reticle_process.h"
+#include "ultima/ultima8/world/sprite_process.h"
+#include "ultima/ultima8/world/item.h"
+#include "ultima/ultima8/world/world.h"
+#include "ultima/ultima8/world/current_map.h"
+#include "ultima/ultima8/world/get_object.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+// p_dynamic_cast stuff
+DEFINE_RUNTIME_CLASSTYPE_CODE(TargetReticleProcess)
+
+TargetReticleProcess::TargetReticleProcess() : Process(), _reticleEnabled(true),
+ _lastUpdate(0), _reticleSpriteProcess(0), _lastTargetDir(0x10), _lastTargetItem(0) {
+}
+
+void TargetReticleProcess::run() {
+ Kernel *kernel = Kernel::get_instance();
+ assert(kernel);
+ uint32 frameno = kernel->getFrameNum();
+ Process *spriteProc = nullptr;
+ if (_reticleSpriteProcess != 0) {
+ spriteProc = kernel->getProcess(_reticleSpriteProcess);
+ }
+
+ if (!_reticleEnabled) {
+ if (spriteProc) {
+ spriteProc->terminate();
+ }
+ _reticleSpriteProcess = 0;
+ return;
+ }
+
+ if (frameno - _lastUpdate < 60) {
+ return;
+ }
+
+ Item *item = findTargetItem();
+ if (item && item->getObjId() != _lastTargetItem) {
+ if (spriteProc)
+ spriteProc->terminate();
+ putTargetReticleOnItem(item);
+ } else if (!item) {
+ debug("New reticle target: NONE");
+ if (spriteProc)
+ spriteProc->terminate();
+ _reticleSpriteProcess = 0;
+ _lastTargetItem = 0;
+ _lastTargetDir = 0x10;
+ }
+ // else, already targeting the right thing. do nothing.
+
+ _lastUpdate = frameno;
+}
+
+Item *TargetReticleProcess::findTargetItem() {
+ MainActor *mainactor = getMainActor();
+ CurrentMap *currentmap = World::get_instance()->getCurrentMap();
+
+ if (!mainactor || !currentmap)
+ return nullptr;
+
+ int dir = mainactor->getDir();
+
+ int32 x, y, z;
+ mainactor->getCentre(x, y, z);
+
+ Item *item = currentmap->findBestTargetItem(x, y, dir);
+ return item;
+}
+
+void TargetReticleProcess::putTargetReticleOnItem(Item *item) {
+ int32 x, y, z;
+
+ // TODO: the game does a bunch of other maths here to pick the right location.
+ // This is an over-simplification.
+ item->getCentre(x, y, z);
+
+ Process *p = new SpriteProcess(0x59a, 0, 5, 1, 10, x, y, z, false);
+
+ _reticleSpriteProcess = Kernel::get_instance()->addProcess(p);
+ _lastTargetItem = item->getObjId();
+ debug("New reticle target: %d (%d, %d, %d)", _lastTargetItem, x, y, z);
+}
+
+void TargetReticleProcess::saveData(Common::WriteStream *ws) {
+ Process::saveData(ws);
+
+ ws->writeUint32LE(_lastUpdate);
+ ws->writeUint16LE(_reticleSpriteProcess);
+ ws->writeUint16LE(_lastTargetItem);
+}
+
+bool TargetReticleProcess::loadData(Common::ReadStream *rs, uint32 version) {
+ if (!Process::loadData(rs, version)) return false;
+
+ _lastUpdate = rs->readUint32LE();
+ _reticleSpriteProcess = rs->readUint16LE();
+ _lastTargetItem = rs->readUint16LE();
+
+ return true;
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/world/target_reticle_process.h b/engines/ultima/ultima8/world/target_reticle_process.h
new file mode 100644
index 0000000000..8a0403f441
--- /dev/null
+++ b/engines/ultima/ultima8/world/target_reticle_process.h
@@ -0,0 +1,64 @@
+/* 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_TARGETRETICLEPROCESS_H
+#define ULTIMA8_WORLD_TARGETRETICLEPROCESS_H
+
+#include "ultima/ultima8/kernel/process.h"
+#include "ultima/ultima8/misc/p_dynamic_cast.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+class Item;
+
+/**
+ * A process to update the targeting reticle location. This is called the
+ * DumbTimer process in the game.
+ */
+class TargetReticleProcess : public Process {
+public:
+ TargetReticleProcess();
+
+ // p_dynamic_cast stuff
+ ENABLE_RUNTIME_CLASSTYPE()
+
+ void run() override;
+
+ bool loadData(Common::ReadStream *rs, uint32 version);
+ void saveData(Common::WriteStream *ws) override;
+
+private:
+ Item *findTargetItem();
+ void putTargetReticleOnItem(Item *);
+
+ bool _reticleEnabled;
+ int32 _lastUpdate;
+ uint16 _reticleSpriteProcess;
+ uint16 _lastTargetDir;
+ uint16 _lastTargetItem;
+};
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif
Commit: 7b467a7fd2dfcba4e73d6cb46d1394b138815094
https://github.com/scummvm/scummvm/commit/7b467a7fd2dfcba4e73d6cb46d1394b138815094
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-02T10:28:56+09:00
Commit Message:
ULTIMA8: Fix crusader ambient audio target
Changed paths:
engines/ultima/ultima8/audio/audio_process.cpp
diff --git a/engines/ultima/ultima8/audio/audio_process.cpp b/engines/ultima/ultima8/audio/audio_process.cpp
index 8e38156a9e..dfc9a7059b 100644
--- a/engines/ultima/ultima8/audio/audio_process.cpp
+++ b/engines/ultima/ultima8/audio/audio_process.cpp
@@ -557,7 +557,7 @@ uint32 AudioProcess::I_playAmbientSFXCru(const uint8 *args, unsigned int argsize
} else {
AudioProcess *ap = AudioProcess::get_instance();
if (ap)
- ap->playSFX(sfxNum, 0x10, 1, -1, true);
+ ap->playSFX(sfxNum, 0x10, item->getObjId(), -1, true);
else
warning("I_playAmbientSFXCru Error: No AudioProcess");
}
More information about the Scummvm-git-logs
mailing list