[Scummvm-git-logs] scummvm master -> a09add2af9978b6bf7e32cd77e181e611221a09e

mduggan mgithub at guarana.org
Thu Jun 25 04:45:18 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:
a09add2af9 ULTIMA8: Load Crusader NPC data and use it for making NPCs


Commit: a09add2af9978b6bf7e32cd77e181e611221a09e
    https://github.com/scummvm/scummvm/commit/a09add2af9978b6bf7e32cd77e181e611221a09e
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-06-25T13:44:21+09:00

Commit Message:
ULTIMA8: Load Crusader NPC data and use it for making NPCs

Changed paths:
  A engines/ultima/ultima8/world/actors/npc_dat.cpp
  A engines/ultima/ultima8/world/actors/npc_dat.h
    engines/ultima/module.mk
    engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
    engines/ultima/ultima8/games/game_data.cpp
    engines/ultima/ultima8/games/game_data.h
    engines/ultima/ultima8/games/start_crusader_process.cpp
    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/item.cpp
    engines/ultima/ultima8/world/item.h


diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 449858a956..0a9ca13870 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -558,6 +558,7 @@ MODULE_OBJS := \
 	ultima8/world/actors/heal_process.o \
 	ultima8/world/actors/loiter_process.o \
 	ultima8/world/actors/main_actor.o \
+	ultima8/world/actors/npc_dat.o \
 	ultima8/world/actors/pathfinder.o \
 	ultima8/world/actors/pathfinder_process.o \
 	ultima8/world/actors/quick_avatar_mover_process.o \
diff --git a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
index 98eb303015..156848bd90 100644
--- a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
+++ b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
@@ -388,7 +388,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	"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
 	"byte Actor::I_isDead(Item *)", // same coff as 122, 039
-	"int16 MonsterEgg::I_monsterEggHatch(Item *, uint16 other_itemno)",
+	"int16 Actor::I_createActorCru(Item *, uint16 other_itemno)",
 	// 0130
 	"void Actor::I_clrImmortal(Actor *)", // same coff as 07B
 	"void Actor::I_setActivity(Actor *, int)", // part of same coff set 055, 07D, 0CD, 0DB, 0F2, 131
diff --git a/engines/ultima/ultima8/games/game_data.cpp b/engines/ultima/ultima8/games/game_data.cpp
index c16a7fedb0..0ff5a83e6a 100644
--- a/engines/ultima/ultima8/games/game_data.cpp
+++ b/engines/ultima/ultima8/games/game_data.cpp
@@ -31,6 +31,7 @@
 #include "ultima/ultima8/graphics/fonts/font_shape_archive.h"
 #include "ultima/ultima8/graphics/gump_shape_archive.h"
 #include "ultima/ultima8/world/map_glob.h"
+#include "ultima/ultima8/world/actors/npc_dat.h"
 #include "ultima/ultima8/graphics/palette_manager.h"
 #include "ultima/ultima8/graphics/shape.h"
 #include "ultima/ultima8/graphics/wpn_ovlay_dat.h"
@@ -93,6 +94,10 @@ GameData::~GameData() {
 	delete _soundFlex;
 	_soundFlex = nullptr;
 
+	for (unsigned int i = 0; i < _npcTable.size(); ++i)
+		delete _npcTable[i];
+	_npcTable.clear();
+
 	_gameData = nullptr;
 
 	for (unsigned int i = 0; i < _speech.size(); ++i) {
@@ -472,6 +477,23 @@ SpeechFlex *GameData::getSpeechFlex(uint32 shapeNum) {
 	return *s;
 }
 
+const NPCDat *GameData::getNPCData(uint16 entry) const {
+	if (entry < _npcTable.size()) {
+		return _npcTable[entry];
+	}
+	return nullptr;
+}
+
+const NPCDat *GameData::getNPCDataForShape(uint16 shapeno) const {
+	for (Std::vector<NPCDat *>::const_iterator it = _npcTable.begin();
+		 it != _npcTable.end();
+		 it++) {
+		const NPCDat *npcdat = *it;
+		if (npcdat->getShapeNo() == shapeno)
+			return npcdat;
+	}
+	return nullptr;
+}
 
 void GameData::loadRemorseData() {
 	FileSystem *filesystem = FileSystem::get_instance();
@@ -595,13 +617,7 @@ void GameData::loadRemorseData() {
 		error("Unable to load static/dtable.flx");
 
 	RawArchive *dtableflex = new RawArchive(dtableds);
-
-	// TODO: What's in this flex file?
-	// Object 1: 35 * 142-byte blocks of .. something. Shapeno at 0x3E (based on disasm)
-	// Object 2: 35 * 32-byte long names of NPCs?
-	//_dtable = new DtableDat();
-	//_dtable->load(dtableflex);
-
+	_npcTable = NPCDat::load(dtableflex);
 	delete dtableflex;
 
 	Common::SeekableReadStream *damageds = filesystem->ReadFile("@game/static/damage.flx");
@@ -645,16 +661,6 @@ void GameData::loadRemorseData() {
 
 	delete stuffds;
 
-	Common::SeekableReadStream *trigds = filesystem->ReadFile("@game/static/trig.dat");
-	if (!trigds)
-		error("Unable to load static/trig.dat");
-
-	// TODO: What's in this dat file?
-	// 12 x 256 bytes. Each block has consistently either 0000 or FFFF in the
-	//vsecond word of each DWORD
-
-	delete trigds;
-
 	Common::SeekableReadStream *xformpalds = filesystem->ReadFile("@game/static/xformpal.dat");
 	if (!xformpalds)
 		error("Unable to load static/xformpal.dat");
diff --git a/engines/ultima/ultima8/games/game_data.h b/engines/ultima/ultima8/games/game_data.h
index 6fc16fd0b7..052170f6e5 100644
--- a/engines/ultima/ultima8/games/game_data.h
+++ b/engines/ultima/ultima8/games/game_data.h
@@ -39,6 +39,7 @@ class MapGlob;
 class Shape;
 class MusicFlex;
 class WpnOvlayDat;
+class NPCDat;
 class ShapeFrame;
 class SoundFlex;
 class SpeechFlex;
@@ -91,6 +92,9 @@ public:
 	Shape *getShape(FrameID frameid) const;
 	const ShapeFrame *getFrame(FrameID frameid) const;
 
+	const NPCDat *getNPCData(uint16 entry) const;
+	const NPCDat *getNPCDataForShape(uint16 shapeno) const;
+
 	Std::string translate(const Std::string &text);
 	FrameID translate(FrameID frame);
 
@@ -113,6 +117,7 @@ private:
 	Shape *_mouse;
 	MusicFlex *_music;
 	WpnOvlayDat *_weaponOverlay;
+	Std::vector<NPCDat *> _npcTable;
 
 	SoundFlex *_soundFlex;
 	Std::vector<SpeechFlex **> _speech;
diff --git a/engines/ultima/ultima8/games/start_crusader_process.cpp b/engines/ultima/ultima8/games/start_crusader_process.cpp
index 55f90a9978..3cdf424deb 100644
--- a/engines/ultima/ultima8/games/start_crusader_process.cpp
+++ b/engines/ultima/ultima8/games/start_crusader_process.cpp
@@ -37,6 +37,7 @@
 #include "ultima/ultima8/gumps/cru_status_gump.h"
 #include "ultima/ultima8/conf/setting_manager.h"
 #include "ultima/ultima8/world/get_object.h"
+#include "ultima/ultima8/world/item_factory.h"
 #include "ultima/ultima8/graphics/palette_fader_process.h"
 #include "ultima/ultima8/audio/music_process.h"
 
@@ -108,6 +109,11 @@ void StartCrusaderProcess::run() {
 		egg->hatch();
 		*/
 
+		// TODO: How is this created in the game??
+		Egg *miss1egg = new Egg();
+		miss1egg->setShape(2317);
+		miss1egg->assignObjId();
+		miss1egg->callUsecodeEvent_hatch();
 	}
 
 	//MusicProcess::get_instance()->playMusic(2);
diff --git a/engines/ultima/ultima8/usecode/remorse_intrinsics.h b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
index b1177233fc..4faacc61b1 100644
--- a/engines/ultima/ultima8/usecode/remorse_intrinsics.h
+++ b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
@@ -356,7 +356,7 @@ Intrinsic RemorseIntrinsics[] = {
 	Item::I_isOn,
 	Item::I_getFootpadData, // void Intrinsic12D(16 bytes)
 	Actor::I_isDead, // int Intrinsic12E(4 bytes)
-	MonsterEgg::I_monsterEggHatch, // void Intrinsic12F(6 bytes) - FIXME: this is pretty different .. will it work?
+	Actor::I_createActorCru, // void Intrinsic12F(6 bytes)
 	// 0x130
 	Actor::I_clrImmortal, // void Intrinsic130(4 bytes)
 	Actor::I_setActivity, // void Intrinsic131(6 bytes)
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index adf2a74a8a..4bbd21c918 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -37,6 +37,7 @@
 #include "ultima/ultima8/graphics/shape_info.h"
 #include "ultima/ultima8/world/actors/pathfinder.h"
 #include "ultima/ultima8/world/actors/animation.h"
+#include "ultima/ultima8/world/actors/npc_dat.h"
 #include "ultima/ultima8/kernel/delay_process.h"
 #include "ultima/ultima8/kernel/core_app.h"
 #include "ultima/ultima8/world/actors/resurrection_process.h"
@@ -573,6 +574,7 @@ uint16 Actor::setActivityCru(int activity) {
 	default:
 		perr << "Actor::setActivityCru: invalid activity (" << activity << ")"
 		     << Std::endl;
+		return doAnim(Animation::stand, 8);
 	}
 
 	return 0;
@@ -1065,7 +1067,7 @@ void Actor::notifyNearbyItems() {
 	UCList uclist(2);
 	LOOPSCRIPT(script, LS_TOKEN_TRUE); // we want all items
 	CurrentMap *currentmap = World::get_instance()->getCurrentMap();
-	currentmap->areaSearch(&uclist, script, sizeof(script), this, 0x40, false);
+	currentmap->areaSearch(&uclist, script, sizeof(script), this, 0x80, false);
 
 	for (unsigned int i = 0; i < uclist.getSize(); ++i) {
 		Item *item = getItem(uclist.getuint16(i));
@@ -1647,6 +1649,70 @@ uint32 Actor::I_createActor(const uint8 *args, unsigned int /*argsize*/) {
 	return objID;
 }
 
+uint32 Actor::I_createActorCru(const uint8 *args, unsigned int /*argsize*/) {
+	ARG_ITEM_FROM_PTR(item);
+	ARG_ITEM_FROM_ID(other);
+
+	if (!item || !other)
+		return 0;
+
+	// TODO: get game difficulty here.
+	static const int gameDifficulty = 1;
+	int npcDifficulty = (item->getMapNum() & 3) + 1;
+
+	if (gameDifficulty < npcDifficulty)
+		return 0;
+
+	uint16 dtableidx = other->getNpcNum();
+	const NPCDat *npcData = GameData::get_instance()->getNPCData(dtableidx);
+	if (!npcData)
+		return 0;
+
+	int dir = item->getNpcNum() & 0xf;
+	int frame = (dir * 2 + 4) & 0xf;
+	uint16 shape = npcData->getShapeNo();
+
+	enum extflags ext = static_cast<extflags>(0);
+	if (shape == 0x597 || shape == 0x3ac)
+		ext = EXT_FEMALE;
+
+	Actor *newactor = ItemFactory::createActor(shape, frame, 0,
+	                  Item::FLG_IN_NPC_LIST | Item::FLG_DISPOSABLE,
+	                  0, 0, ext, true);
+	if (!newactor) {
+		perr << "I_createActorCru failed to create actor ("
+			 << npcData->getShapeNo() << ")." << Std::endl;
+		return 0;
+	}
+
+	newactor->setStr(npcData->getMaxHp() / 2);
+	newactor->setDir(dir);
+
+	int32 x, y, z;
+	item->getLocation(x, y, z);
+	newactor->move(x, y, z);
+
+	// 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();
+	 if (gameDifficulty == 4) {
+		wpnType = randomlyGetHigherWeaponType(shape, wpntype);
+	 }
+
+	 // give weapon to NPC.
+	 */
+
+	return newactor->getObjId();
+}
+
 uint32 Actor::I_setActivity(const uint8 *args, unsigned int /*argsize*/) {
 	ARG_ACTOR_FROM_PTR(actor);
 	ARG_UINT16(activity);
diff --git a/engines/ultima/ultima8/world/actors/actor.h b/engines/ultima/ultima8/world/actors/actor.h
index 9eae47520b..337667cb8d 100644
--- a/engines/ultima/ultima8/world/actors/actor.h
+++ b/engines/ultima/ultima8/world/actors/actor.h
@@ -272,6 +272,7 @@ public:
 	INTRINSIC(I_areEnemiesNear);
 	INTRINSIC(I_isBusy);
 	INTRINSIC(I_createActor);
+	INTRINSIC(I_createActorCru);
 	INTRINSIC(I_setActivity);
 	INTRINSIC(I_setAirWalkEnabled);
 	INTRINSIC(I_getAirWalkEnabled);
diff --git a/engines/ultima/ultima8/world/actors/npc_dat.cpp b/engines/ultima/ultima8/world/actors/npc_dat.cpp
new file mode 100644
index 0000000000..9f99f03c37
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/npc_dat.cpp
@@ -0,0 +1,73 @@
+/* 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/world/actors/npc_dat.h"
+
+#include "common/memstream.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+NPCDat::NPCDat(Common::SeekableReadStream &rs, Common::SeekableReadStream &namers) {
+	char namebuf[33] = {0};
+	namers.read(namebuf, 32);
+	_name.assign(namebuf);
+
+	_minHp = rs.readUint16LE();
+	_maxHp = rs.readUint16LE();
+	// TODO: Read the other data.
+	rs.skip(22);
+	// offset 0x1a (26): wpntype
+	_wpnType = rs.readUint16LE();
+	// offset 0x3e (62): shape
+	rs.skip(62 - 28);
+	_shapeNo = rs.readUint16LE();
+	rs.skip(142 - 64);
+}
+
+/*static*/
+Std::vector<NPCDat *> NPCDat::load(RawArchive *archive) {
+    Std::vector<NPCDat *> result;
+    assert(archive);
+	if (archive->getCount() < 2) {
+		warning("NPCDat: Archive does not include the expected objects.");
+		return result;
+	}
+
+	Common::MemoryReadStream datars(archive->get_object_nodel(0), archive->get_size(0));
+	Common::MemoryReadStream namers(archive->get_object_nodel(2), archive->get_size(2));
+
+	if (!datars.size() || !namers.size()) {
+		warning("NPCDat: Archive appears to be corrupt.");
+		return result;
+	}
+
+	while (!datars.eos() && !namers.eos() && (datars.size() - datars.pos() >= 142)) {
+		result.push_back(new NPCDat(datars, namers));
+	}
+
+	return result;
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/world/actors/npc_dat.h b/engines/ultima/ultima8/world/actors/npc_dat.h
new file mode 100644
index 0000000000..9779082e24
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/npc_dat.h
@@ -0,0 +1,70 @@
+/* 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_NPC_DAT_H
+#define WORLD_ACTORS_NPC_DAT_H
+
+#include "ultima/ultima8/filesys/raw_archive.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+class NPCDat {
+public:
+	NPCDat();
+
+	static Std::vector<NPCDat *> load(RawArchive *archive);
+
+	const Std::string &getName() const {
+		return _name;
+	};
+
+	uint16 getShapeNo() const {
+		return _shapeNo;
+	};
+
+	uint16 getMinHp() const {
+		return _minHp;
+	};
+
+	uint16 getMaxHp() const {
+		return _maxHp;
+	};
+
+	uint16 getWpnType() const {
+		return _wpnType;
+	};
+
+private:
+    NPCDat(Common::SeekableReadStream &datars, Common::SeekableReadStream &namers);
+
+	Std::string _name;
+	uint16 _minHp;
+	uint16 _maxHp;
+	uint16 _shapeNo;
+	uint16 _wpnType;
+};
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index 0b692a59f3..668c5a269b 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -695,7 +695,10 @@ Shape *Item::getShapeObject() const {
 }
 
 uint16 Item::getFamily() const {
-	return static_cast<uint16>(getShapeInfo()->_family);
+	const ShapeInfo *info = getShapeInfo();
+	if (!info)
+		return 0;
+	return static_cast<uint16>(info->_family);
 }
 
 uint32 Item::getWeight() const {
diff --git a/engines/ultima/ultima8/world/item.h b/engines/ultima/ultima8/world/item.h
index 7abeb1fde4..1328a34ee3 100644
--- a/engines/ultima/ultima8/world/item.h
+++ b/engines/ultima/ultima8/world/item.h
@@ -635,7 +635,8 @@ public:
 		EXT_CAMERA       = 0x0020,  //!< Item is being followed by the camera
 		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_PERMANENT_NPC = 0x0100, //!< Item is a permanent NPC
+		EXT_FEMALE       = 0x8000	//!< Crusader Female NPC (controls sfx)
 	};
 };
 




More information about the Scummvm-git-logs mailing list