[Scummvm-git-logs] scummvm master -> 84d3d95707c7fbaa951b3e202f2bfd3a3e14543d
mduggan
mgithub at guarana.org
Fri Jun 26 04:25:54 UTC 2020
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
84d3d95707 ULTIMA8: More crusader NPC support
Commit: 84d3d95707c7fbaa951b3e202f2bfd3a3e14543d
https://github.com/scummvm/scummvm/commit/84d3d95707c7fbaa951b3e202f2bfd3a3e14543d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-06-26T13:24:59+09:00
Commit Message:
ULTIMA8: More crusader NPC support
Changed paths:
engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
engines/ultima/ultima8/usecode/remorse_intrinsics.h
engines/ultima/ultima8/world/actors/actor.cpp
engines/ultima/ultima8/world/actors/actor.h
engines/ultima/ultima8/world/actors/loiter_process.cpp
engines/ultima/ultima8/world/actors/npc_dat.cpp
engines/ultima/ultima8/world/actors/npc_dat.h
diff --git a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
index 156848bd90..c62fa1ed3a 100644
--- a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
+++ b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
@@ -154,9 +154,9 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
// 0050
"int16 I_GetNPCDataField0x2_050(Actor *)",
"void I_NPCSomething_051(Actor *)", // TODO: check usecode to understand this.
- "void I_SetNPCDataField0x6_052(Actor *, int)", // TODO: check usecode to understand this.
- "void I_SetNPCDataField0x8_053(Actor *, int)", // TODO: check usecode to understand this.
- "void I_SetNPCDataField0xA_054(Actor *, int)", // TODO: check usecode to understand this.
+ "void Actor::I_setDefaultActivity0(Actor *, int)",
+ "void Actor::I_setDefaultActivity1(Actor *, int)",
+ "void Actor::I_setDefaultActivity2(Actor *, int)",
"void Actor::I_setActivity(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
"void Intrinsic056(int itemno)", // Maybe set new target? TODO: check usecode to understand this.
"int16 Item::I_getSOMETHING_57(Item *)",
@@ -306,9 +306,9 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
"int16 Actor::I_getEquip(6 bytes)", // based on disasm
// 00E0
"void Actor::I_setEquip(8 bytes)",
- "int16 Actor::I_GetNPCDataField0x6_0E1(Actor *)",
- "int16 Actor::I_GetNPCDataField0x8_0E2(Actor *)",
- "int16 Actor::I_GetNPCDataField0xa_0E3(Actor *)",
+ "int16 Actor::I_getDefaultActivity0(Actor *)",
+ "int16 Actor::I_getDefaultActivity1(Actor *)",
+ "int16 Actor::I_getDefaultActivity2(Actor *)",
"int16 Actor::I_getLastAnimSet(4 bytes)", // part of same coff set 01D, 05A, 0B9, 0D7, 0E4, 124
"void Actor::I_attackProbably(Actor *, uint16 target)", // TODO: game checks 0x59 flag 3 first.. what is that?
"void Actor::I_SetNPCDataField0x63_0E6(Actor *, int)",
diff --git a/engines/ultima/ultima8/usecode/remorse_intrinsics.h b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
index 4faacc61b1..f87139b50a 100644
--- a/engines/ultima/ultima8/usecode/remorse_intrinsics.h
+++ b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
@@ -122,9 +122,9 @@ Intrinsic RemorseIntrinsics[] = {
// 0x050
0, // void Intrinsic050(4 bytes)
0, // void Intrinsic051(4 bytes)
- 0, // void Intrinsic052(6 bytes)
- 0, // void Intrinsic053(6 bytes)
- 0, // void Intrinsic054(6 bytes)
+ Actor::I_setDefaultActivity0, // void Intrinsic052(6 bytes)
+ Actor::I_setDefaultActivity1, // void Intrinsic053(6 bytes)
+ Actor::I_setDefaultActivity2, // void Intrinsic054(6 bytes)
Actor::I_setActivity, // void Intrinsic055(6 bytes)
0, // void Intrinsic056(2 bytes)
0, // void Intrinsic057(4 bytes)
@@ -138,7 +138,7 @@ Intrinsic RemorseIntrinsics[] = {
0, // void Intrinsic05F(void)
// 0x060
Actor::I_setDead, // void Intrinsic060(4 bytes)
- Actor::I_create, // void Intrinsic061(8 bytes)
+ Actor::I_createActor, // void Intrinsic061(8 bytes)
0, // void Intrinsic062(void)
Actor::I_teleport, // void Intrinsic063(12 bytes)
Item::I_getFootpadData, // void Intrinsic064(16 bytes)
@@ -274,9 +274,9 @@ Intrinsic RemorseIntrinsics[] = {
Actor::I_getEquip, // void Intrinsic0DF(6 bytes)
// 0x0E0
Actor::I_setEquip, // void Intrinsic0E0(8 bytes)
- 0, // void Intrinsic0E1(4 bytes)
- 0, // void Intrinsic0E2(4 bytes)
- 0, // void Intrinsic0E3(4 bytes)
+ Actor::I_getDefaultActivity0, // void Intrinsic0E1(4 bytes)
+ Actor::I_getDefaultActivity1, // void Intrinsic0E2(4 bytes)
+ Actor::I_getDefaultActivity2, // void Intrinsic0E3(4 bytes)
Actor::I_getLastAnimSet, // void Intrinsic0E4(4 bytes)
0, // void Intrinsic0E5(6 bytes)
0, // void Intrinsic0E6(6 bytes)
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 4bbd21c918..e1486e0607 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -67,6 +67,9 @@ Actor::Actor() : _strength(0), _dexterity(0), _intelligence(0),
_hitPoints(0), _mana(0), _alignment(0), _enemyAlignment(0),
_lastAnim(Animation::stand), _animFrame(0), _direction(0),
_fallStart(0), _unk0C(0), _actorFlags(0) {
+ _defaultActivity[0] = 0;
+ _defaultActivity[1] = 0;
+ _defaultActivity[2] = 0;
}
Actor::~Actor() {
@@ -94,6 +97,31 @@ uint16 Actor::getMaxHP() const {
}
bool Actor::loadMonsterStats() {
+ if (GAME_IS_CRUSADER)
+ return loadMonsterStatsCru();
+ else
+ return loadMonsterStatsU8();
+}
+
+bool Actor::loadMonsterStatsCru() {
+ const NPCDat *npcData = GameData::get_instance()->getNPCDataForShape(getShape());
+
+ if (!npcData)
+ return false;
+
+ setStr(npcData->getMaxHp() / 2);
+ setHP(npcData->getMaxHp());
+ _defaultActivity[0] = npcData->getDefaultActivity(0);
+ _defaultActivity[1] = npcData->getDefaultActivity(1);
+ _defaultActivity[2] = npcData->getDefaultActivity(2);
+
+ // TODO: Give them the default weapon for their type here.
+
+ return true;
+}
+
+bool Actor::loadMonsterStatsU8() {
+
ShapeInfo *shapeinfo = getShapeInfo();
MonsterInfo *mi = nullptr;
if (shapeinfo) mi = shapeinfo->_monsterInfo;
@@ -546,9 +574,8 @@ uint16 Actor::setActivityCru(int activity) {
case 1: // stand
return doAnim(Animation::stand, 8);
case 3: // pace
- perr << "Actor::setActivityCru TODO: Implement new PaceProcess(this);";
- // TODO: Implement me as separate from loiter. (fall through for now)
- // fall through
+ perr << "Actor::setActivityCru TODO: Implement new PaceProcess(this);" << Std::endl;
+ return Kernel::get_instance()->addProcess(new LoiterProcess(this));
case 2: // loiter
Kernel::get_instance()->addProcess(new LoiterProcess(this));
return Kernel::get_instance()->addProcess(new DelayProcess(1));
@@ -557,10 +584,12 @@ uint16 Actor::setActivityCru(int activity) {
// Does nothing in game..
break;
case 7:
- perr << "Actor::setActivityCru TODO: Implement new SurrenderProcess(this);";
+ perr << "Actor::setActivityCru TODO: Implement new SurrenderProcess(this);" << Std::endl;
+ return Kernel::get_instance()->addProcess(new LoiterProcess(this));
break;
case 8:
- perr << "Actor::setActivityCru TODO: Implement new GuardProcess(this);";
+ perr << "Actor::setActivityCru TODO: Implement new GuardProcess(this);" << Std::endl;
+ return Kernel::get_instance()->addProcess(new LoiterProcess(this));
break;
case 5:
case 9:
@@ -570,7 +599,12 @@ uint16 Actor::setActivityCru(int activity) {
// attack
setInCombat();
return 0;
-
+ case 0x70:
+ return setActivity(getDefaultActivity(0));
+ case 0x71:
+ return setActivity(getDefaultActivity(1));
+ case 0x72:
+ return setActivity(getDefaultActivity(2));
default:
perr << "Actor::setActivityCru: invalid activity (" << activity << ")"
<< Std::endl;
@@ -629,6 +663,15 @@ int Actor::getDamageAmount() const {
}
}
+void Actor::setDefaultActivity(int no, uint16 activity) {
+ assert(no >= 0 && no < 3);
+ _defaultActivity[no] = activity;
+}
+
+uint16 Actor::getDefaultActivity(int no) const {
+ assert(no >= 0 && no < 3);
+ return _defaultActivity[no];
+}
void Actor::receiveHit(uint16 other, int dir, int damage, uint16 damage_type) {
if (isDead())
@@ -1064,6 +1107,10 @@ int32 Actor::collideMove(int32 x, int32 y, int32 z, bool teleport, bool force,
}
void Actor::notifyNearbyItems() {
+/*
+ TODO: This is not right - maybe we want to trigger each item only when it gets close,
+ then reset the status after it moves away? Need to dig into the assembly more.
+
UCList uclist(2);
LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
CurrentMap *currentmap = World::get_instance()->getCurrentMap();
@@ -1072,7 +1119,7 @@ void Actor::notifyNearbyItems() {
for (unsigned int i = 0; i < uclist.getSize(); ++i) {
Item *item = getItem(uclist.getuint16(i));
item->callUsecodeEvent_npcNearby(_objId);
- }
+ }*/
}
bool Actor::areEnemiesNear() {
@@ -1134,7 +1181,6 @@ Actor *Actor::createActor(uint32 shape, uint32 frame) {
return newactor;
}
-
void Actor::dumpInfo() const {
Container::dumpInfo();
@@ -1664,6 +1710,7 @@ uint32 Actor::I_createActorCru(const uint8 *args, unsigned int /*argsize*/) {
return 0;
uint16 dtableidx = other->getNpcNum();
+
const NPCDat *npcData = GameData::get_instance()->getNPCData(dtableidx);
if (!npcData)
return 0;
@@ -1685,21 +1732,29 @@ uint32 Actor::I_createActorCru(const uint8 *args, unsigned int /*argsize*/) {
return 0;
}
- newactor->setStr(npcData->getMaxHp() / 2);
+ // Most of these will be overwritten below, but this is cleaner..
+ bool loaded = newactor->loadMonsterStats();
+ if (!loaded) {
+ perr << "I_createActorCru failed to load monster stats ("
+ << npcData->getShapeNo() << ")." << Std::endl;
+ return 0;
+ }
+
newactor->setDir(dir);
int32 x, y, z;
item->getLocation(x, y, z);
newactor->move(x, y, z);
+ newactor->setDefaultActivity(0, other->getQuality() >> 8);
+ newactor->setDefaultActivity(1, item->getQuality() >> 8);
+ newactor->setDefaultActivity(2, other->getMapNum());
+
// TODO: once I know what these fields are...
/*
newactor->setField0x5c(0);
newactor->setField0x5e(x, y);
newactor->setField0x12(item->getNpcNum() >> 4);
- newactor->setField0x06(other->getQuality() >> 8);
- newactor->setField0x08(item->getQuality() >> 8);
- newactor->setField0x0A(other->getMapArray());
newactor->setField0x63(item->getQuality() & 0xff);
uint16 wpnType = npcData->getWpnType();
@@ -1778,5 +1833,54 @@ uint32 Actor::I_setEquip(const uint8 *args, unsigned int /*argsize*/) {
return 1;
}
+uint32 Actor::I_setDefaultActivity0(const uint8 *args, unsigned int /*argsize*/) {
+ ARG_ACTOR_FROM_PTR(actor);
+ ARG_UINT16(activity);
+ if (!actor) return 0;
+
+ actor->setDefaultActivity(0, activity);
+ return 0;
+}
+
+uint32 Actor::I_setDefaultActivity1(const uint8 *args, unsigned int /*argsize*/) {
+ ARG_ACTOR_FROM_PTR(actor);
+ ARG_UINT16(activity);
+ if (!actor) return 0;
+
+ actor->setDefaultActivity(1, activity);
+ return 0;
+}
+
+uint32 Actor::I_setDefaultActivity2(const uint8 *args, unsigned int /*argsize*/) {
+ ARG_ACTOR_FROM_PTR(actor);
+ ARG_UINT16(activity);
+ if (!actor) return 0;
+
+ actor->setDefaultActivity(2, activity);
+ return 0;
+}
+
+uint32 Actor::I_getDefaultActivity0(const uint8 *args, unsigned int /*argsize*/) {
+ ARG_ACTOR_FROM_PTR(actor);
+ if (!actor) return 0;
+
+ return actor->getDefaultActivity(0);
+}
+
+uint32 Actor::I_getDefaultActivity1(const uint8 *args, unsigned int /*argsize*/) {
+ ARG_ACTOR_FROM_PTR(actor);
+ if (!actor) return 0;
+
+ return actor->getDefaultActivity(1);
+}
+
+uint32 Actor::I_getDefaultActivity2(const uint8 *args, unsigned int /*argsize*/) {
+ ARG_ACTOR_FROM_PTR(actor);
+ if (!actor) return 0;
+
+ return actor->getDefaultActivity(2);
+}
+
+
} // End of namespace Ultima8
} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/world/actors/actor.h b/engines/ultima/ultima8/world/actors/actor.h
index 337667cb8d..f8a54d6cb5 100644
--- a/engines/ultima/ultima8/world/actors/actor.h
+++ b/engines/ultima/ultima8/world/actors/actor.h
@@ -136,8 +136,9 @@ public:
_actorFlags &= ~mask;
}
- //! set stats from MonsterInfo (hp, dex, _alignment, _enemyAlignment)
- //! \return true if a MonsterInfo struct was found, false otherwise
+ //! set stats from MonsterInfo (hp, dex, alignment, enemyAlignment)
+ //! in Crusader this comes from the NPC Data
+ //! \return true if info was found, false otherwise
bool loadMonsterStats();
//! add treasure according to the TreasureInfo in the MonsterInfo
@@ -162,6 +163,9 @@ public:
uint16 getDamageType() const override;
virtual int getDamageAmount() const;
+ void setDefaultActivity(int no, uint16 activity);
+ uint16 getDefaultActivity(int no) const;
+
//! calculate the damage an attack against this Actor does.
//! \param other the attacker (can be zero)
//! \param damage base damage
@@ -279,6 +283,12 @@ public:
INTRINSIC(I_schedule);
INTRINSIC(I_getEquip);
INTRINSIC(I_setEquip);
+ INTRINSIC(I_setDefaultActivity0);
+ INTRINSIC(I_setDefaultActivity1);
+ INTRINSIC(I_setDefaultActivity2);
+ INTRINSIC(I_getDefaultActivity0);
+ INTRINSIC(I_getDefaultActivity1);
+ INTRINSIC(I_getDefaultActivity2);
enum ActorFlags {
ACT_INVINCIBLE = 0x000001, // flags from npcdata byte 0x1B
@@ -318,6 +328,9 @@ protected:
uint32 _actorFlags;
+ //! the 3 default NPC activities from Crusader
+ uint16 _defaultActivity[3];
+
//! starts an activity (Ultima 8 version)
//! \return processID of process handling the activity or zero
uint16 setActivityU8(int activity);
@@ -326,6 +339,9 @@ protected:
//! \return processID of process handling the activity or zero
uint16 setActivityCru(int activity);
+ bool loadMonsterStatsU8();
+ bool loadMonsterStatsCru();
+
};
} // End of namespace Ultima8
diff --git a/engines/ultima/ultima8/world/actors/loiter_process.cpp b/engines/ultima/ultima8/world/actors/loiter_process.cpp
index 42a3e2f335..e2731f3f59 100644
--- a/engines/ultima/ultima8/world/actors/loiter_process.cpp
+++ b/engines/ultima/ultima8/world/actors/loiter_process.cpp
@@ -26,6 +26,7 @@
#include "ultima/ultima8/world/actors/pathfinder_process.h"
#include "ultima/ultima8/kernel/kernel.h"
#include "ultima/ultima8/kernel/delay_process.h"
+#include "ultima/ultima8/kernel/core_app.h"
#include "ultima/ultima8/world/get_object.h"
namespace Ultima {
@@ -41,7 +42,10 @@ LoiterProcess::LoiterProcess(Actor *actor, int32 c) : _count(c) {
assert(actor);
_itemNum = actor->getObjId();
- _type = 0x205; // CONSTANT!
+ if (GAME_IS_U8)
+ _type = 0x205; // CONSTANT!
+ else
+ _type = 599;
}
void LoiterProcess::run() {
diff --git a/engines/ultima/ultima8/world/actors/npc_dat.cpp b/engines/ultima/ultima8/world/actors/npc_dat.cpp
index 9f99f03c37..b9e206ba42 100644
--- a/engines/ultima/ultima8/world/actors/npc_dat.cpp
+++ b/engines/ultima/ultima8/world/actors/npc_dat.cpp
@@ -39,10 +39,17 @@ NPCDat::NPCDat(Common::SeekableReadStream &rs, Common::SeekableReadStream &namer
rs.skip(22);
// offset 0x1a (26): wpntype
_wpnType = rs.readUint16LE();
+ rs.skip(2);
+ // offset 30: default activity 0x6
+ _defaultActivity[0] = rs.readUint16LE();
// offset 0x3e (62): shape
- rs.skip(62 - 28);
+ rs.skip(62 - 32);
_shapeNo = rs.readUint16LE();
- rs.skip(142 - 64);
+ // offset 64: default activity 0x8
+ _defaultActivity[1] = rs.readUint16LE();
+ // offset 66: default activity 0xA
+ _defaultActivity[2] = rs.readUint16LE();
+ rs.skip(142 - 68);
}
/*static*/
diff --git a/engines/ultima/ultima8/world/actors/npc_dat.h b/engines/ultima/ultima8/world/actors/npc_dat.h
index 9779082e24..d5af113163 100644
--- a/engines/ultima/ultima8/world/actors/npc_dat.h
+++ b/engines/ultima/ultima8/world/actors/npc_dat.h
@@ -54,6 +54,11 @@ public:
return _wpnType;
};
+ uint16 getDefaultActivity(int no) const {
+ assert(no >= 0 && no < 3);
+ return _defaultActivity[no];
+ }
+
private:
NPCDat(Common::SeekableReadStream &datars, Common::SeekableReadStream &namers);
@@ -62,6 +67,7 @@ private:
uint16 _maxHp;
uint16 _shapeNo;
uint16 _wpnType;
+ uint16 _defaultActivity[3]; // activities 0x6, 0x8, and 0xA in game.
};
} // End of namespace Ultima8
More information about the Scummvm-git-logs
mailing list