[Scummvm-git-logs] scummvm master -> e358d02685fe8bb820e6de49b3752c6b3bbc9ea2
sev-
noreply at scummvm.org
Sat Aug 9 19:03:48 UTC 2025
This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
7f51b61906 TEENAGENT: Unify string resources into one segment
4768231b0e TEENAGENT: Add support for Polish voice acting
2faa0d7f03 TEENAGENT: Remove unused variables in Resources class
e358d02685 TEENAGENT: Fix description being not shown for inventory items
Commit: 7f51b61906715fe4adfc70837c5224682a63df37
https://github.com/scummvm/scummvm/commit/7f51b61906715fe4adfc70837c5224682a63df37
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-08-09T21:03:44+02:00
Commit Message:
TEENAGENT: Unify string resources into one segment
Store every string resource (message, dialog, credits, etc.) into one
big segment - eseg. This change is a building block for adding
voiceovers in the next commits. In addition in certain methods "addr"
parameter is now 32-bit unsigned integer instead 16-bit. This is needed
as 16-bit address space is not enough store polish and czech strings.
Changed paths:
devtools/create_teenagent/create_teenagent.cpp
devtools/create_teenagent/create_teenagent.h
dists/engine-data/teenagent.dat
engines/teenagent/callbacks.cpp
engines/teenagent/dialog.cpp
engines/teenagent/dialog.h
engines/teenagent/inventory.cpp
engines/teenagent/resources.cpp
engines/teenagent/resources.h
engines/teenagent/scene.cpp
engines/teenagent/teenagent.cpp
engines/teenagent/teenagent.h
diff --git a/devtools/create_teenagent/create_teenagent.cpp b/devtools/create_teenagent/create_teenagent.cpp
index c9d1fd54292..e71a8fedb50 100644
--- a/devtools/create_teenagent/create_teenagent.cpp
+++ b/devtools/create_teenagent/create_teenagent.cpp
@@ -311,11 +311,8 @@ void writeSceneObjects(FILE *fd, Common::Language language) {
fseek(fd, pos, SEEK_SET);
}
-void writeResource(FILE *fd, ResourceType resType, Common::Language language) {
- uint currentFilePos = ftell(fd);
- uint prevFilePos = currentFilePos;
- uint32 resourceSize = 0;
- writeUint32LE(fd, resourceSize);
+uint32 writeResource(FILE *fd, ResourceType resType, Common::Language language) {
+ uint prevFilePos = ftell(fd);
switch (resType) {
case kResCredits: {
@@ -358,11 +355,9 @@ void writeResource(FILE *fd, ResourceType resType, Common::Language language) {
break;
};
- currentFilePos = ftell(fd);
- resourceSize = currentFilePos - prevFilePos - sizeof(uint32);
- fseek(fd, prevFilePos, SEEK_SET);
- writeUint32LE(fd, resourceSize);
- fseek(fd, currentFilePos, SEEK_SET);
+ uint currentFilePos = ftell(fd);
+ uint32 resourceSize = currentFilePos - prevFilePos;
+ return resourceSize;
}
int main(int argc, char *argv[]) {
@@ -416,9 +411,32 @@ int main(int argc, char *argv[]) {
fseek(fout, dataOffset, SEEK_SET);
+ ResourceInfo resourceInfos[NUM_RESOURCES];
+ uint32 resInfoPos = ftell(fout);
+ fseek(fout, (2 * sizeof(uint32) + sizeof(byte)) * NUM_RESOURCES, SEEK_CUR);
+
+ for (uint i = 0; i < NUM_RESOURCES; i++) {
+ resourceInfos[i]._id = i;
+ resourceInfos[i]._offset = ftell(fout);
+
+ uint32 size = writeResource(fout, ResourceType(i), supportedLanguages[lang]);
+ resourceInfos[i]._size = size;
+ }
+
+ fseek(fout, resInfoPos, SEEK_SET);
for (uint i = 0; i < NUM_RESOURCES; i++) {
- writeResource(fout, ResourceType(i), supportedLanguages[lang]);
+ writeByte(fout, resourceInfos[i]._id);
+ if (resourceInfos[i]._id != 0) {
+ // Offsets are stored relative to first resource's offset
+ // NOTE: First resource is kResDialogs(1), not kResDialogStacks(0)
+ // because kResDialogStacks is not stored with the rest of resources.
+ writeUint32LE(fout, resourceInfos[i]._offset - resourceInfos[1]._offset);
+ } else
+ writeUint32LE(fout, resourceInfos[i]._offset);
+ writeUint32LE(fout, resourceInfos[i]._size);
}
+ // Go back to current file pos
+ fseek(fout, resourceInfos[NUM_RESOURCES - 1]._offset + resourceInfos[NUM_RESOURCES - 1]._size, SEEK_SET);
}
fclose(fout);
diff --git a/devtools/create_teenagent/create_teenagent.h b/devtools/create_teenagent/create_teenagent.h
index 97274201f50..3118a4af413 100644
--- a/devtools/create_teenagent/create_teenagent.h
+++ b/devtools/create_teenagent/create_teenagent.h
@@ -25,11 +25,11 @@
#include "common/language.h"
#include "util.h"
-#define TEENAGENT_DAT_VERSION 5
+#define TEENAGENT_DAT_VERSION 6
enum ResourceType {
- kResDialogs = 0,
- kResDialogStacks,
+ kResDialogStacks = 0,
+ kResDialogs,
kResItems,
kResCredits,
kResSceneObjects,
@@ -37,6 +37,12 @@ enum ResourceType {
kResCombinations,
};
+struct ResourceInfo {
+ byte _id;
+ uint32 _offset;
+ uint32 _size;
+};
+
#define NUM_RESOURCES 7
#define NUM_LANGS 4
diff --git a/dists/engine-data/teenagent.dat b/dists/engine-data/teenagent.dat
index 41be7c9a348..8926c93863e 100644
Binary files a/dists/engine-data/teenagent.dat and b/dists/engine-data/teenagent.dat differ
diff --git a/engines/teenagent/callbacks.cpp b/engines/teenagent/callbacks.cpp
index b2a104a461b..b7c5045a1f4 100644
--- a/engines/teenagent/callbacks.cpp
+++ b/engines/teenagent/callbacks.cpp
@@ -484,7 +484,7 @@ void TeenAgentEngine::fnGiveAnotherFlowerToAnne() {
void TeenAgentEngine::bookColorMessage() {
uint bookIndex = GET_FLAG(dsAddr_drawerPuzzleBookValue) - 1;
- uint16 addr = res->getMessageAddr(MessageType((int)kBookColorMsg0 + bookIndex));
+ uint32 addr = res->getMessageAddr(MessageType((int)kBookColorMsg0 + bookIndex));
displayMessage(addr);
}
diff --git a/engines/teenagent/dialog.cpp b/engines/teenagent/dialog.cpp
index d6e53cf7e16..2e43d6b53c9 100644
--- a/engines/teenagent/dialog.cpp
+++ b/engines/teenagent/dialog.cpp
@@ -27,7 +27,7 @@
namespace TeenAgent {
void Dialog::show(uint16 dialogNum, Scene *scene, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2) {
- uint16 addr = _vm->res->getDialogAddr(dialogNum);
+ uint32 addr = _vm->res->getDialogAddr(dialogNum);
// WORKAROUND: For Dialog 163, The usage of this in the engine overlaps the previous dialog i.e. the
// starting offset used is two bytes early, thus implicitly changing the first command of this dialog
// from NEW_LINE to CHANGE_CHARACTER.
@@ -39,7 +39,7 @@ void Dialog::show(uint16 dialogNum, Scene *scene, uint16 animation1, uint16 anim
show(scene, addr, animation1, animation2, character1ID, character2ID, slot1, slot2);
}
-void Dialog::show(Scene *scene, uint16 addr, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2) {
+void Dialog::show(Scene *scene, uint32 addr, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2) {
debugC(0, kDebugDialog, "Dialog::show(%04x, %u:%u, %u:%u)", addr, slot1, animation1, slot2, animation2);
int n = 0;
Common::String message;
@@ -151,7 +151,11 @@ uint16 Dialog::pop(Scene *scene, uint16 addr, uint16 animation1, uint16 animatio
uint16 next2 = _vm->res->dseg.get_word(addr);
if (next2 != 0xffff)
_vm->res->dseg.set_word(addr - 2, 0);
- show(scene, next, animation1, animation2, character1ID, character2ID, slot1, slot2);
+
+ // Dialog addresses popped from stack are relative
+ // to dialog start offset. So we add that offset first
+ uint32 dialogAddr = _vm->res->getDialogStartPos() + next;
+ show(scene, dialogAddr, animation1, animation2, character1ID, character2ID, slot1, slot2);
return next;
}
diff --git a/engines/teenagent/dialog.h b/engines/teenagent/dialog.h
index eef6f542cd3..ebdbd448732 100644
--- a/engines/teenagent/dialog.h
+++ b/engines/teenagent/dialog.h
@@ -135,7 +135,7 @@ public:
private:
TeenAgentEngine *_vm;
- void show(Scene *scene, uint16 addr, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2);
+ void show(Scene *scene, uint32 addr, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2);
};
} // End of namespace TeenAgent
diff --git a/engines/teenagent/inventory.cpp b/engines/teenagent/inventory.cpp
index 56fd486c9cf..bfab6558697 100644
--- a/engines/teenagent/inventory.cpp
+++ b/engines/teenagent/inventory.cpp
@@ -62,8 +62,8 @@ Inventory::Inventory(TeenAgentEngine *vm) : _vm(vm) {
_objects.push_back(ioBlank);
for (byte i = 0; i < kNumInventoryItems; ++i) {
InventoryObject io;
- uint16 objAddr = vm->res->getItemAddr(i);
- io.load(vm->res->itemsSeg.ptr(objAddr));
+ uint32 objAddr = vm->res->getItemAddr(i);
+ io.load(vm->res->eseg.ptr(objAddr));
_objects.push_back(io);
}
@@ -213,7 +213,7 @@ bool Inventory::processEvent(const Common::Event &event) {
debugC(0, kDebugInventory, "combine(%u, %u)!", id1, id2);
for (uint i = 0; i < kNumCombinations; i++) {
- byte *table = _vm->res->combinationsSeg.ptr(_vm->res->getCombinationAddr(i));
+ byte *table = _vm->res->eseg.ptr(_vm->res->getCombinationAddr(i));
if ((id1 == table[0] && id2 == table[1]) || (id2 == table[0] && id1 == table[1])) {
byte newObj = table[2];
diff --git a/engines/teenagent/resources.cpp b/engines/teenagent/resources.cpp
index 7c24cef5de1..836093a38aa 100644
--- a/engines/teenagent/resources.cpp
+++ b/engines/teenagent/resources.cpp
@@ -31,6 +31,13 @@
namespace TeenAgent {
Resources::Resources() {
+ _combinationsStartOffset = 0;
+ _creditsStartOffset = 0;
+ _dialogsStartOffset = 0;
+ _messagesStartOffset = 0;
+ _sceneObjectsStartOffset = 0;
+ _sceneObjectsBlockSize = 0;
+ _itemsStartOffset = 0;
}
Resources::~Resources() {
@@ -64,12 +71,12 @@ quick note on varia resources:
#define DSEG_SIZE 59280 // 0xe790
#define ESEG_SIZE 35810 // 0x8be2
-void Resources::precomputeResourceOffsets(Segment &seg, Common::Array<uint16> &offsets, uint numTerminators) {
- offsets.push_back(0);
+void Resources::precomputeResourceOffsets(const ResourceInfo &resInfo, Common::Array<uint32> &offsets, uint numTerminators) {
+ offsets.push_back(resInfo._offset);
uint n = 0;
uint8 current, last = 0xff;
- for (uint i = 0; i < seg.size(); i++) {
- current = seg.get_byte(i);
+ for (uint32 i = resInfo._offset; i < resInfo._offset + resInfo._size; i++) {
+ current = eseg.get_byte(i);
if (n == numTerminators) {
offsets.push_back(i);
@@ -86,36 +93,36 @@ void Resources::precomputeResourceOffsets(Segment &seg, Common::Array<uint16> &o
}
}
-void Resources::precomputeDialogOffsets() {
- precomputeResourceOffsets(eseg, dialogOffsets, 4);
+void Resources::precomputeDialogOffsets(const ResourceInfo &resInfo) {
+ precomputeResourceOffsets(resInfo, dialogOffsets, 4);
debug(1, "Resources::precomputeDialogOffsets() - Found %d dialogs", dialogOffsets.size());
for (uint i = 0; i < dialogOffsets.size(); i++)
debug(1, "\tDialog #%d: Offset 0x%04x", i, dialogOffsets[i]);
}
-void Resources::precomputeCreditsOffsets() {
- precomputeResourceOffsets(creditsSeg, creditsOffsets);
+void Resources::precomputeCreditsOffsets(const ResourceInfo &resInfo) {
+ precomputeResourceOffsets(resInfo, creditsOffsets);
debug(1, "Resources::precomputeCreditsOffsets() - Found %d credits", creditsOffsets.size());
for (uint i = 0; i < creditsOffsets.size(); i++)
debug(1, "\tCredit #%d: Offset 0x%04x", i, creditsOffsets[i]);
}
-void Resources::precomputeItemOffsets() {
- precomputeResourceOffsets(itemsSeg, itemOffsets);
+void Resources::precomputeItemOffsets(const ResourceInfo &resInfo) {
+ precomputeResourceOffsets(resInfo, itemOffsets);
debug(1, "Resources::precomputeItemOffsets() - Found %d items", itemOffsets.size());
for (uint i = 0; i < itemOffsets.size(); i++)
debug(1, "\tItem #%d: Offset 0x%04x", i, itemOffsets[i]);
}
-void Resources::precomputeMessageOffsets() {
- precomputeResourceOffsets(messagesSeg, messageOffsets);
+void Resources::precomputeMessageOffsets(const ResourceInfo &resInfo) {
+ precomputeResourceOffsets(resInfo, messageOffsets);
}
-void Resources::precomputeCombinationOffsets() {
- precomputeResourceOffsets(combinationsSeg, combinationOffsets);
+void Resources::precomputeCombinationOffsets(const ResourceInfo &resInfo) {
+ precomputeResourceOffsets(resInfo, combinationOffsets);
debug(1, "Resources::precomputeCombinationOffsets() - Found %d combination items", combinationOffsets.size());
for (uint i = 0; i < combinationOffsets.size(); i++)
@@ -137,6 +144,41 @@ void Resources::readDialogStacks(byte *src) {
}
}
+void Resources::precomputeAllOffsets(const Common::Array<ResourceInfo> &resourceInfos) {
+ for (const auto &resInfo : resourceInfos) {
+ switch ((ResourceType)resInfo._id) {
+ case kResCombinations:
+ _combinationsStartOffset = resInfo._offset;
+ precomputeCombinationOffsets(resInfo);
+ break;
+ case kResCredits:
+ _creditsStartOffset = resInfo._offset;
+ precomputeCreditsOffsets(resInfo);
+ break;
+ case kResDialogs:
+ _dialogsStartOffset = resInfo._offset;
+ precomputeDialogOffsets(resInfo);
+ break;
+ case kResItems:
+ _itemsStartOffset = resInfo._offset;
+ precomputeItemOffsets(resInfo);
+ break;
+ case kResMessages:
+ _messagesStartOffset = resInfo._offset;
+ precomputeMessageOffsets(resInfo);
+ break;
+ case kResSceneObjects:
+ _sceneObjectsStartOffset = resInfo._offset;
+ _sceneObjectsBlockSize = resInfo._size;
+ break;
+ case kResDialogStacks:
+ // fall through
+ default:
+ break;
+ }
+ }
+}
+
bool Resources::loadArchives(const ADGameDescription *gd) {
Common::File *dat_file = new Common::File();
Common::String filename = "teenagent.dat";
@@ -195,36 +237,30 @@ bool Resources::loadArchives(const ADGameDescription *gd) {
}
}
- uint resourceSize = dat->readUint32LE();
- eseg.read(dat, resourceSize);
+ Common::Array<ResourceInfo> resourceInfos(kNumResources);
+ uint32 allResourcesSize = 0;
- // Dialog stack data
- resourceSize = dat->readUint32LE();
- dat->read(tempBuffer, resourceSize);
- readDialogStacks((byte *)tempBuffer);
+ for (auto &resInfo : resourceInfos) {
+ resInfo._id = dat->readByte();
+ resInfo._offset = dat->readUint32LE();
+ resInfo._size = dat->readUint32LE();
- resourceSize = dat->readUint32LE();
- itemsSeg.read(dat, resourceSize);
-
- resourceSize = dat->readUint32LE();
- creditsSeg.read(dat, resourceSize);
-
- resourceSize = dat->readUint32LE();
- sceneObjectsSeg.read(dat, resourceSize);
+ // Don't count Dialog stack's size
+ // since it will be stored in dseg, not eseg
+ if ((ResourceType)resInfo._id != kResDialogStacks)
+ allResourcesSize += resInfo._size;
+ }
- resourceSize = dat->readUint32LE();
- messagesSeg.read(dat, resourceSize);
+ // Dialog stack data
+ dat->read(tempBuffer, resourceInfos[(uint)kResDialogStacks]._size);
+ readDialogStacks((byte *)tempBuffer);
- resourceSize = dat->readUint32LE();
- combinationsSeg.read(dat, resourceSize);
+ // Store rest of the resources to eseg
+ eseg.read(dat, allResourcesSize);
delete dat;
- precomputeDialogOffsets();
- precomputeItemOffsets();
- precomputeCreditsOffsets();
- precomputeMessageOffsets();
- precomputeCombinationOffsets();
+ precomputeAllOffsets(resourceInfos);
FilePack varia;
varia.open("varia.res");
diff --git a/engines/teenagent/resources.h b/engines/teenagent/resources.h
index a096ab04f72..daeac2653d9 100644
--- a/engines/teenagent/resources.h
+++ b/engines/teenagent/resources.h
@@ -1500,6 +1500,25 @@ enum MessageType{
kObjCombineErrorMsg,
};
+// Number of resources in teenagent.dat file
+const byte kNumResources = 7;
+
+enum ResourceType {
+ kResDialogStacks = 0,
+ kResDialogs,
+ kResItems,
+ kResCredits,
+ kResSceneObjects,
+ kResMessages,
+ kResCombinations,
+};
+
+struct ResourceInfo {
+ byte _id;
+ uint32 _offset;
+ uint32 _size;
+};
+
class Resources {
public:
Resources();
@@ -1526,33 +1545,47 @@ public:
Font font7, font8;
//const byte *getDialog(uint16 dialogNum) { return eseg.ptr(dialogOffsets[dialogNum]); }
- uint16 getDialogAddr(uint16 dialogNum) { return dialogOffsets[dialogNum]; }
- uint16 getCreditAddr(uint16 creditNum) { return creditsOffsets[creditNum]; }
- uint16 getItemAddr(uint16 itemNum) { return itemOffsets[itemNum]; }
- uint16 getMessageAddr(MessageType msgType) { return messageOffsets[msgType]; }
- uint16 getCombinationAddr(uint16 msgNum) { return combinationOffsets[msgNum]; }
+ uint32 getDialogStartPos() { return _dialogsStartOffset; }
+ uint32 getDialogAddr(uint16 dialogNum) { return dialogOffsets[dialogNum]; }
+ uint32 getCreditAddr(uint16 creditNum) { return creditsOffsets[creditNum]; }
+ uint32 getItemAddr(uint16 itemNum) { return itemOffsets[itemNum]; }
+ uint32 getMessageAddr(MessageType msgType) { return messageOffsets[msgType]; }
+ uint32 getCombinationAddr(uint16 msgNum) { return combinationOffsets[msgNum]; }
- // Artificial segments added to support multiple languages
+ uint16 sceneObjectsBlockSize() { return _sceneObjectsBlockSize; }
+ uint32 getSceneObjectsStartPos() { return _sceneObjectsStartOffset; }
+
+ // Artificial segment that contains various
+ // string items (messages, dialogs, item names, etc.)
+ // Used to support multiple languages
Segment eseg;
- Segment creditsSeg, itemsSeg, sceneObjectsSeg;
- Segment messagesSeg;
- Segment combinationsSeg;
private:
- void precomputeResourceOffsets(Segment &seg, Common::Array<uint16> &offsets, uint numTerminators = 2);
+ void precomputeAllOffsets(const Common::Array<ResourceInfo> &resourceInfos);
+ void precomputeResourceOffsets(const ResourceInfo &resInfo, Common::Array<uint32> &offsets, uint numTerminators = 2);
- void precomputeDialogOffsets();
- void precomputeCreditsOffsets();
- void precomputeItemOffsets();
- void precomputeMessageOffsets();
- void precomputeCombinationOffsets();
+ void precomputeDialogOffsets(const ResourceInfo &resInfo);
+ void precomputeCreditsOffsets(const ResourceInfo &resInfo);
+ void precomputeItemOffsets(const ResourceInfo &resInfo);
+ void precomputeMessageOffsets(const ResourceInfo &resInfo);
+ void precomputeCombinationOffsets(const ResourceInfo &resInfo);
void readDialogStacks(byte *src);
- Common::Array<uint16> dialogOffsets;
- Common::Array<uint16> creditsOffsets, itemOffsets;
- Common::Array<uint16> messageOffsets;
- Common::Array<uint16> combinationOffsets;
+ Common::Array<uint32> dialogOffsets;
+ Common::Array<uint32> creditsOffsets, itemOffsets;
+ Common::Array<uint32> messageOffsets;
+ Common::Array<uint32> combinationOffsets;
+
+ uint32 _messagesStartOffset;
+
+ uint32 _sceneObjectsStartOffset;
+ uint32 _sceneObjectsBlockSize; // Needed to know how much to write to savefile
+
+ uint32 _combinationsStartOffset;
+ uint32 _itemsStartOffset;
+ uint32 _creditsStartOffset;
+ uint32 _dialogsStartOffset;
};
} // End of namespace TeenAgent
diff --git a/engines/teenagent/scene.cpp b/engines/teenagent/scene.cpp
index 171655214c3..b2a55bb57ba 100644
--- a/engines/teenagent/scene.cpp
+++ b/engines/teenagent/scene.cpp
@@ -247,11 +247,12 @@ void Scene::loadObjectData() {
Common::Array<Object> &sceneObjects = objects[i];
sceneObjects.clear();
- uint16 sceneTable = _vm->res->sceneObjectsSeg.get_word(i * 2);
- uint16 objectAddr;
- while ((objectAddr = _vm->res->sceneObjectsSeg.get_word(sceneTable)) != 0) {
+ uint32 sceneObjectStartAddr = _vm->res->getSceneObjectsStartPos();
+ uint32 sceneTable = _vm->res->eseg.get_word(sceneObjectStartAddr + i * 2);
+ uint32 objectAddr;
+ while ((objectAddr = _vm->res->eseg.get_word(sceneObjectStartAddr + sceneTable)) != 0) {
Object obj;
- obj.load(_vm->res->sceneObjectsSeg.ptr(objectAddr), i + 1);
+ obj.load(_vm->res->eseg.ptr(sceneObjectStartAddr + objectAddr), i + 1);
//obj.dump();
sceneObjects.push_back(obj);
sceneTable += 2;
diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp
index bbd062fd0cb..2831064a47f 100644
--- a/engines/teenagent/teenagent.cpp
+++ b/engines/teenagent/teenagent.cpp
@@ -242,20 +242,21 @@ Common::Error TeenAgentEngine::loadGameState(int slot) {
uint32 tag = in->readUint32BE();
if (tag == MKTAG('T', 'H', 'M', 'B')) { // Old save (before TEENAGENT_SAVEGAME_VERSION was added)
uint16 baseAddr = dsAddr_sceneObjectTablePtr;
+ uint32 sceneObjectStartAddr = res->getSceneObjectsStartPos();
// Copy scene object data in the dseg to sceneObjectsSeg
- Common::copy(res->dseg.ptr(baseAddr), res->dseg.ptr(0xb4f3), res->sceneObjectsSeg.ptr(0));
+ Common::copy(res->dseg.ptr(baseAddr), res->dseg.ptr(0xb4f3), res->eseg.ptr(sceneObjectStartAddr));
// Set correct addresses, i.e., make them relative to dsAddr_sceneObjectTablePtr
for (byte i = 0; i < 42; i++) {
uint16 sceneTable = res->dseg.get_word(baseAddr + (i * 2));
- res->sceneObjectsSeg.set_word(i * 2, sceneTable - baseAddr);
+ res->eseg.set_word(sceneObjectStartAddr + i * 2, sceneTable - baseAddr);
uint16 objectAddr;
while ((objectAddr = res->dseg.get_word(sceneTable)) != 0) {
- res->sceneObjectsSeg.set_word(sceneTable - baseAddr, objectAddr - baseAddr);
+ res->eseg.set_word(sceneObjectStartAddr + sceneTable - baseAddr, objectAddr - baseAddr);
sceneTable += 2;
}
- res->sceneObjectsSeg.set_word(sceneTable - baseAddr, 0);
+ res->eseg.set_word(sceneObjectStartAddr + sceneTable - baseAddr, 0);
}
} else {
if (tag != MKTAG('T', 'N', 'G', 'T')) {
@@ -270,7 +271,7 @@ Common::Error TeenAgentEngine::loadGameState(int slot) {
}
uint32 resourceSize = in->readUint32LE();
- if (in->read(res->sceneObjectsSeg.ptr(0), resourceSize) != resourceSize) {
+ if (in->read(res->eseg.ptr(res->getSceneObjectsStartPos()), resourceSize) != resourceSize) {
warning("loadGameState(): corrupted data");
return Common::kReadingFailed;
}
@@ -318,8 +319,8 @@ Common::Error TeenAgentEngine::saveGameState(int slot, const Common::String &des
out->writeByte(TEENAGENT_SAVEGAME_VERSION);
// Write scene object data
- out->writeUint32LE(res->sceneObjectsSeg.size());
- out->write(res->sceneObjectsSeg.ptr(0), res->sceneObjectsSeg.size());
+ out->writeUint32LE(res->sceneObjectsBlockSize());
+ out->write(res->eseg.ptr(res->getSceneObjectsStartPos()), res->sceneObjectsBlockSize());
if (!Graphics::saveThumbnail(*out))
warning("saveThumbnail failed");
@@ -767,10 +768,10 @@ Common::Error TeenAgentEngine::run() {
return Common::kNoError;
}
-Common::String TeenAgentEngine::parseMessage(uint16 addr) {
+Common::String TeenAgentEngine::parseMessage(uint32 addr) {
Common::String message;
for (
- const char *str = (const char *)res->messagesSeg.ptr(addr);
+ const char *str = (const char *)res->eseg.ptr(addr);
str[0] != 0 || str[1] != 0;
++str) {
char c = str[0];
@@ -813,11 +814,11 @@ void TeenAgentEngine::displayMessage(const Common::String &str, CharacterID char
}
}
-void TeenAgentEngine::displayMessage(uint16 addr, CharacterID characterID, uint16 x, uint16 y) {
+void TeenAgentEngine::displayMessage(uint32 addr, CharacterID characterID, uint16 x, uint16 y) {
displayMessage(parseMessage(addr), characterID, x, y);
}
-void TeenAgentEngine::displayAsyncMessage(uint16 addr, uint16 x, uint16 y, uint16 firstFrame, uint16 lastFrame, CharacterID characterID) {
+void TeenAgentEngine::displayAsyncMessage(uint32 addr, uint16 x, uint16 y, uint16 firstFrame, uint16 lastFrame, CharacterID characterID) {
SceneEvent event(SceneEvent::kMessage);
event.message = parseMessage(addr);
event.slot = 0;
@@ -831,7 +832,7 @@ void TeenAgentEngine::displayAsyncMessage(uint16 addr, uint16 x, uint16 y, uint1
scene->push(event);
}
-void TeenAgentEngine::displayAsyncMessageInSlot(uint16 addr, byte slot, uint16 firstFrame, uint16 lastFrame, byte color) {
+void TeenAgentEngine::displayAsyncMessageInSlot(uint32 addr, byte slot, uint16 firstFrame, uint16 lastFrame, byte color) {
SceneEvent event(SceneEvent::kMessage);
event.message = parseMessage(addr);
event.slot = slot + 1;
@@ -842,10 +843,10 @@ void TeenAgentEngine::displayAsyncMessageInSlot(uint16 addr, byte slot, uint16 f
scene->push(event);
}
-void TeenAgentEngine::displayCredits(uint16 addr, uint16 timer) {
+void TeenAgentEngine::displayCredits(uint32 addr, uint16 timer) {
SceneEvent event(SceneEvent::kCreditsMessage);
- const byte *src = res->creditsSeg.ptr(addr);
+ const byte *src = res->eseg.ptr(addr);
event.orientation = *src++;
event.color = *src++;
event.lan = 8;
@@ -883,7 +884,7 @@ void TeenAgentEngine::displayCredits() {
scene->push(event);
}
-void TeenAgentEngine::displayCutsceneMessage(uint16 addr, uint16 x, uint16 y) {
+void TeenAgentEngine::displayCutsceneMessage(uint32 addr, uint16 x, uint16 y) {
SceneEvent event(SceneEvent::kCreditsMessage);
event.message = parseMessage(addr);
diff --git a/engines/teenagent/teenagent.h b/engines/teenagent/teenagent.h
index 03adbcfb4b2..18d45d14ca8 100644
--- a/engines/teenagent/teenagent.h
+++ b/engines/teenagent/teenagent.h
@@ -62,7 +62,7 @@ class Resources;
class Inventory;
class Pack;
-#define TEENAGENT_DAT_VERSION 5
+#define TEENAGENT_DAT_VERSION 6
#define TEENAGENT_SAVEGAME_VERSION 1
// Engine Debug Flags
@@ -120,15 +120,15 @@ public:
bool showMetropolis();
int skipEvents() const;
- Common::String parseMessage(uint16 addr);
+ Common::String parseMessage(uint32 addr);
//event driven:
- void displayMessage(uint16 addr, CharacterID characterID = kMark, uint16 x = 0, uint16 y = 0);
+ void displayMessage(uint32 addr, CharacterID characterID = kMark, uint16 x = 0, uint16 y = 0);
void displayMessage(const Common::String &str, CharacterID characterID = kMark, uint16 x = 0, uint16 y = 0);
- void displayAsyncMessage(uint16 addr, uint16 x, uint16 y, uint16 firstFrame, uint16 lastFrame, CharacterID characterID = kMark);
- void displayAsyncMessageInSlot(uint16 addr, byte slot, uint16 firstFrame, uint16 lastFrame, byte color = textColorMark);
- void displayCredits(uint16 addr, uint16 timer = 0);
- void displayCutsceneMessage(uint16 addr, uint16 x, uint16 y);
+ void displayAsyncMessage(uint32 addr, uint16 x, uint16 y, uint16 firstFrame, uint16 lastFrame, CharacterID characterID = kMark);
+ void displayAsyncMessageInSlot(uint32 addr, byte slot, uint16 firstFrame, uint16 lastFrame, byte color = textColorMark);
+ void displayCredits(uint32 addr, uint16 timer = 0);
+ void displayCutsceneMessage(uint32 addr, uint16 x, uint16 y);
void moveTo(const Common::Point &dst, byte o, bool warp = false);
void moveTo(uint16 x, uint16 y, byte o, bool warp = false);
void moveTo(Object *obj);
Commit: 4768231b0e8c95443175386b1fcf2ce4be1482a6
https://github.com/scummvm/scummvm/commit/4768231b0e8c95443175386b1fcf2ce4be1482a6
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-08-09T21:03:44+02:00
Commit Message:
TEENAGENT: Add support for Polish voice acting
Changed paths:
engines/teenagent/dialog.cpp
engines/teenagent/inventory.cpp
engines/teenagent/objects.cpp
engines/teenagent/objects.h
engines/teenagent/resources.cpp
engines/teenagent/resources.h
engines/teenagent/scene.cpp
engines/teenagent/scene.h
engines/teenagent/teenagent.cpp
engines/teenagent/teenagent.h
diff --git a/engines/teenagent/dialog.cpp b/engines/teenagent/dialog.cpp
index 2e43d6b53c9..00e122cbe1b 100644
--- a/engines/teenagent/dialog.cpp
+++ b/engines/teenagent/dialog.cpp
@@ -42,6 +42,7 @@ void Dialog::show(uint16 dialogNum, Scene *scene, uint16 animation1, uint16 anim
void Dialog::show(Scene *scene, uint32 addr, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2) {
debugC(0, kDebugDialog, "Dialog::show(%04x, %u:%u, %u:%u)", addr, slot1, animation1, slot2, animation2);
int n = 0;
+ uint16 voiceId = 0;
Common::String message;
byte color = characterDialogData[character1ID].textColor;
byte color1 = color;
@@ -61,6 +62,10 @@ void Dialog::show(Scene *scene, uint32 addr, uint16 animation1, uint16 animation
scene->push(e2);
}
+ // Number of ANIM_WAIT (0xff) bytes.
+ // Used to correctly find voice index.
+ uint numOfAnimWaits = 0;
+
while (n < 4) {
byte c = _vm->res->eseg.get_byte(addr++);
debugC(1, kDebugDialog, "%02x: %c", c, c > 0x20? c: '.');
@@ -99,6 +104,7 @@ void Dialog::show(Scene *scene, uint32 addr, uint16 animation1, uint16 animation
}
message.trim();
+ voiceId = _vm->res->getVoiceIndex(addr - message.size() - numOfAnimWaits - 2); // -2 for '\n'
if (!message.empty()) {
SceneEvent em(SceneEvent::kMessage);
em.message = message;
@@ -111,8 +117,10 @@ void Dialog::show(Scene *scene, uint32 addr, uint16 animation1, uint16 animation
em.slot = slot2;
em.characterID = character2ID;
}
+ em.voiceId = voiceId;
scene->push(em);
message.clear();
+ numOfAnimWaits = 0;
}
break;
@@ -127,6 +135,7 @@ void Dialog::show(Scene *scene, uint32 addr, uint16 animation1, uint16 animation
break;
case 0xff:
+ numOfAnimWaits++;
//FIXME : wait for the next cycle of the animation
break;
diff --git a/engines/teenagent/inventory.cpp b/engines/teenagent/inventory.cpp
index bfab6558697..69ff688cb5a 100644
--- a/engines/teenagent/inventory.cpp
+++ b/engines/teenagent/inventory.cpp
@@ -202,7 +202,8 @@ bool Inventory::processEvent(const Common::Event &event) {
return true;
//activate(false);
int w = _vm->res->font7.render(NULL, 0, 0, _hoveredObj->description, textColorMark);
- _vm->scene->displayMessage(_hoveredObj->description, textColorMark, Common::Point((kScreenWidth - w) / 2, 162));
+ uint16 voiceIndex = _vm->res->getVoiceIndex(_vm->res->getItemAddr(_hoveredObj->id - 1));
+ _vm->scene->displayMessage(_hoveredObj->description, voiceIndex, textColorMark, Common::Point((kScreenWidth - w) / 2, 162));
return true;
}
@@ -213,7 +214,8 @@ bool Inventory::processEvent(const Common::Event &event) {
debugC(0, kDebugInventory, "combine(%u, %u)!", id1, id2);
for (uint i = 0; i < kNumCombinations; i++) {
- byte *table = _vm->res->eseg.ptr(_vm->res->getCombinationAddr(i));
+ uint32 addr = _vm->res->getCombinationAddr(i);
+ byte *table = _vm->res->eseg.ptr(addr);
if ((id1 == table[0] && id2 == table[1]) || (id2 == table[0] && id1 == table[1])) {
byte newObj = table[2];
@@ -225,7 +227,7 @@ bool Inventory::processEvent(const Common::Event &event) {
_vm->playSoundNow(&_vm->res->sam_sam, 69);
}
Common::String msg = Object::parseDescription((const char *)(table + 3));
- _vm->displayMessage(msg);
+ _vm->displayMessage(msg, _vm->res->getVoiceIndex(addr));
activate(false);
resetSelectedObject();
return true;
diff --git a/engines/teenagent/objects.cpp b/engines/teenagent/objects.cpp
index e8120bec7e6..45d61b90f8d 100644
--- a/engines/teenagent/objects.cpp
+++ b/engines/teenagent/objects.cpp
@@ -55,6 +55,7 @@ void Rect::render(Graphics::Surface *surface, uint8 color) const {
void Object::load(byte *src, byte sceneId) {
_base = src;
+ _addr = src - g_engine->res->eseg.ptr(0);
id = *src++;
@@ -79,6 +80,9 @@ void Object::load(byte *src, byte sceneId) {
src++;
}
+ if (*src == 1)
+ _hasDefaultDescription = true;
+
description = parseDescription((const char *)src);
if (hasRealName) {
diff --git a/engines/teenagent/objects.h b/engines/teenagent/objects.h
index 957a1b0dfc8..941ef6562d8 100644
--- a/engines/teenagent/objects.h
+++ b/engines/teenagent/objects.h
@@ -164,12 +164,15 @@ struct Object {
//19
Common::String name, description;
- Object(): _base(NULL), _nameSize(0) { id = 0; actorOrientation = 0; enabled = 0; }
+ Object(): _base(NULL), _nameSize(0) { id = 0; actorOrientation = 0; enabled = 0; _hasDefaultDescription = false; }
void dump(int level = 0) const;
void setRealName();
void load(byte *addr, byte sceneId = 0);
void save() const;
+ bool hasDefaultDescription() { return _hasDefaultDescription; }
+ uint32 getAddr() { return _addr; };
+
static Common::String parseDescription(const char *desc);
protected:
@@ -178,6 +181,9 @@ protected:
// New name that will be set when certain event is triggered
Common::String _realName;
+
+ bool _hasDefaultDescription;
+ uint32 _addr = 0; // Address inside eseg
};
struct InventoryObject {
diff --git a/engines/teenagent/resources.cpp b/engines/teenagent/resources.cpp
index 836093a38aa..63f8c12253a 100644
--- a/engines/teenagent/resources.cpp
+++ b/engines/teenagent/resources.cpp
@@ -179,6 +179,138 @@ void Resources::precomputeAllOffsets(const Common::Array<ResourceInfo> &resource
}
}
+bool Resources::isVoiceIndexEmpty(uint16 index) {
+ uint size = voices.getSize(index);
+ if (size == 4 || size == 5)
+ return true;
+ return false;
+}
+
+void Resources::precomputeVoiceIndices(const Common::Array<ResourceInfo>& resourceInfos) {
+ byte numTerminators = 0;
+ uint16 voiceIndex = 0;
+
+ for (auto &resInfo : resourceInfos) {
+ switch ((ResourceType)resInfo._id) {
+ case kResMessages:
+ voiceIndex = 1;
+ numTerminators = 2;
+ break;
+ case kResCombinations:
+ voiceIndex = 567;
+ numTerminators = 2;
+ break;
+ case kResItems:
+ voiceIndex = 592;
+ numTerminators = 2;
+ break;
+ case kResDialogs:
+ voiceIndex = 902;
+ numTerminators = 4;
+ break;
+ case kResCredits:
+ case kResDialogStacks:
+ case kResSceneObjects:
+ // There are no voiceovers for credits and dialog stacks.
+ // For scene objects, voice indices calculated separately
+ // in Scene::loadObjectData()
+ continue;
+ default:
+ break;
+ }
+
+ _addrToVoiceIndx[resInfo._offset] = voiceIndex++;
+
+ uint16 currentNum = 1;
+ uint n = 0; // number of consecutive zero bytes
+ byte current, last = 0xff;
+
+ bool setNoIMessage = false;
+
+ for (uint32 i = resInfo._offset; i < resInfo._offset + resInfo._size; i++) {
+ current = eseg.get_byte(i);
+
+ if (n == numTerminators) {
+ currentNum++;
+ n = 0;
+
+ if ((ResourceType)resInfo._id == kResCombinations) {
+ uint16 nthCombination = currentNum - 1;
+ // For dublicate combination messages don't increment voice index
+ if (nthCombination == 3 || nthCombination == 5 ||
+ nthCombination == 15 || nthCombination == 16 || nthCombination == 17 ||
+ nthCombination == 18 || nthCombination == 22 || nthCombination == 26) {
+ _addrToVoiceIndx[i] = voiceIndex - 1;
+ } else if (nthCombination == 28) {
+ _addrToVoiceIndx[i] = voiceIndex - 2;
+ } else {
+ _addrToVoiceIndx[i] = voiceIndex++;
+ }
+ } else if ((ResourceType)resInfo._id == kResDialogs) {
+ if (voiceIndex == 1416) {
+ // "Dzie= dobry, panie robocie." starts at 1418
+ voiceIndex += 2;
+ _addrToVoiceIndx[i] = voiceIndex++;
+ } else if (voiceIndex == 1864) {
+ // "Jak ju< powiedzia%em, nasza organizacja" starts at 1867
+ voiceIndex += 3;
+ _addrToVoiceIndx[i] = voiceIndex++;
+ } else if (isVoiceIndexEmpty(voiceIndex)) {
+ voiceIndex += 1;
+ if (current != 0x00)
+ _addrToVoiceIndx[i] = voiceIndex++;
+ } else if (voiceIndex == 1801) {
+ _addrToVoiceIndx[i] = 2041; // "]adna pogoda."
+ } else if (voiceIndex == 1809) {
+ _addrToVoiceIndx[i] = 2042; // "Sir, mamy sygna%y, <e..."
+ } else {
+ if (current != 0x00)
+ _addrToVoiceIndx[i] = voiceIndex++;
+ }
+ } else if ((ResourceType)resInfo._id == kResMessages) {
+ if (currentNum == 334) { // Combination error message
+ // HACK: Use most good sounding (sigh) version
+ // TODO: Find the correct voice index used in the original
+ _addrToVoiceIndx[i] = 1304;
+ } else
+ _addrToVoiceIndx[i] = voiceIndex++;
+ } else {
+ _addrToVoiceIndx[i] = voiceIndex++;
+ }
+ }
+
+ if (current != 0x00 && last == 0x00) {
+ if ((ResourceType)resInfo._id == kResDialogs) {
+ if (n == 2 || n == 3) {
+ // "...to czemu nie u<y^ dziwnych" at 1886
+ // "Sze$^ miesi#cy temu z%oto i got*wka" at 1921
+ if (voiceIndex == 1885 || voiceIndex == 1920 || isVoiceIndexEmpty(voiceIndex)) {
+ voiceIndex += 1;
+ _addrToVoiceIndx[i] = voiceIndex++;
+ } else if (voiceIndex == 1923 && !setNoIMessage) {
+ _addrToVoiceIndx[i] = 1885; // "No i?..."
+ setNoIMessage = true;
+ } else {
+ _addrToVoiceIndx[i] = voiceIndex++;
+ }
+ } else if (n == 1 && (voiceIndex == 1720 || voiceIndex == 1852)) {
+ // Because of the rare case with
+ // NEW_LINE at the beginning of dialogs 163, 190
+ // we have to assign voiceIndex here
+ _addrToVoiceIndx[i] = voiceIndex++;
+ }
+ }
+ n = 0;
+ }
+
+ if (current == 0x00)
+ n++;
+
+ last = current;
+ }
+ }
+}
+
bool Resources::loadArchives(const ADGameDescription *gd) {
Common::File *dat_file = new Common::File();
Common::String filename = "teenagent.dat";
@@ -278,6 +410,9 @@ bool Resources::loadArchives(const ADGameDescription *gd) {
sam_sam.open("sam_sam.res");
voices.open("voices.res");
+ if (gd->language == Common::PL_POL)
+ precomputeVoiceIndices(resourceInfos);
+
return true;
}
diff --git a/engines/teenagent/resources.h b/engines/teenagent/resources.h
index daeac2653d9..621a6abbc59 100644
--- a/engines/teenagent/resources.h
+++ b/engines/teenagent/resources.h
@@ -1555,6 +1555,13 @@ public:
uint16 sceneObjectsBlockSize() { return _sceneObjectsBlockSize; }
uint32 getSceneObjectsStartPos() { return _sceneObjectsStartOffset; }
+ uint16 getVoiceIndex(uint32 addr) {
+ if (_addrToVoiceIndx.contains(addr))
+ return _addrToVoiceIndx[addr];
+ return 0;
+ }
+ void setVoiceIndex(uint32 addr, uint16 index) { _addrToVoiceIndx[addr] = index; }
+
// Artificial segment that contains various
// string items (messages, dialogs, item names, etc.)
// Used to support multiple languages
@@ -1570,6 +1577,9 @@ private:
void precomputeMessageOffsets(const ResourceInfo &resInfo);
void precomputeCombinationOffsets(const ResourceInfo &resInfo);
+ void precomputeVoiceIndices(const Common::Array<ResourceInfo> &resourceInfos);
+ bool isVoiceIndexEmpty(uint16 index);
+
void readDialogStacks(byte *src);
Common::Array<uint32> dialogOffsets;
@@ -1586,6 +1596,8 @@ private:
uint32 _itemsStartOffset;
uint32 _creditsStartOffset;
uint32 _dialogsStartOffset;
+
+ Common::HashMap<uint32, uint16> _addrToVoiceIndx;
};
} // End of namespace TeenAgent
diff --git a/engines/teenagent/scene.cpp b/engines/teenagent/scene.cpp
index b2a55bb57ba..5c87a81df75 100644
--- a/engines/teenagent/scene.cpp
+++ b/engines/teenagent/scene.cpp
@@ -73,6 +73,7 @@ Scene::Scene(TeenAgentEngine *vm) : _vm(vm), intro(false), _id(0), ons(0),
_onsCount = 0;
_messageColor = 0;
+ _voiceId = 0;
}
Scene::~Scene() {
@@ -243,6 +244,8 @@ void Scene::loadObjectData() {
walkboxes.resize(42);
fades.resize(42);
+ uint16 voiceStartIndx = 334;
+
for (byte i = 0; i < 42; ++i) {
Common::Array<Object> &sceneObjects = objects[i];
sceneObjects.clear();
@@ -254,6 +257,14 @@ void Scene::loadObjectData() {
Object obj;
obj.load(_vm->res->eseg.ptr(sceneObjectStartAddr + objectAddr), i + 1);
//obj.dump();
+ if (obj.hasDefaultDescription()) {
+ uint32 coolMsgAddr = _vm->res->getMessageAddr(kCoolMsg);
+ _vm->res->setVoiceIndex(sceneObjectStartAddr + objectAddr, _vm->res->getVoiceIndex(coolMsgAddr));
+ } else {
+ _vm->res->setVoiceIndex(sceneObjectStartAddr + objectAddr, voiceStartIndx);
+ voiceStartIndx++;
+ }
+
sceneObjects.push_back(obj);
sceneTable += 2;
}
@@ -497,6 +508,7 @@ bool Scene::processEvent(const Common::Event &event) {
_vm->playMusic(4);
_vm->loadScene(10, Common::Point(136, 153));
_vm->stopTextToSpeech();
+ _vm->stopVoice();
_vm->setTTSVoice(kMark);
return true;
}
@@ -504,6 +516,7 @@ bool Scene::processEvent(const Common::Event &event) {
case kActionSkipDialog:
if (!message.empty() && messageFirstFrame == 0) {
_vm->stopTextToSpeech();
+ _vm->stopVoice();
clearMessage();
nextEvent();
return true;
@@ -848,6 +861,7 @@ bool Scene::render(bool tickGame, bool tickMark, uint32 messageDelta) {
}
}
_vm->sayText(ttsMessage);
+ _vm->playVoiceNow(&_vm->res->voices, _voiceId);
}
}
@@ -993,6 +1007,7 @@ bool Scene::processEventQueue() {
case SceneEvent::kMessage: {
_vm->setTTSVoice((CharacterID)currentEvent.characterID);
message = currentEvent.message;
+ _voiceId = currentEvent.voiceId;
messageAnimation = NULL;
if (currentEvent.firstFrame) {
messageTimer = 0;
@@ -1253,13 +1268,14 @@ uint Scene::messageDuration(const Common::String &str) {
return delay * 10;
}
-void Scene::displayMessage(const Common::String &str, byte color, const Common::Point &pos) {
+void Scene::displayMessage(const Common::String &str, uint16 voiceIndex, byte color, const Common::Point &pos) {
//assert(!str.empty());
debugC(0, kDebugScene, "displayMessage: %s", str.c_str());
message = str;
messagePos = (pos.x | pos.y) ? pos : messagePosition(str, position);
_messageColor = color;
messageTimer = messageDuration(message);
+ _voiceId = voiceIndex;
}
void Scene::clear() {
@@ -1277,6 +1293,7 @@ void Scene::clear() {
void Scene::clearMessage() {
message.clear();
messageTimer = 0;
+ _voiceId = 0;
// Reset TTS voice to Mark's voice so that objects and items are always narrated
// with his voice
diff --git a/engines/teenagent/scene.h b/engines/teenagent/scene.h
index 7eaf415beb8..7b4db526858 100644
--- a/engines/teenagent/scene.h
+++ b/engines/teenagent/scene.h
@@ -69,6 +69,7 @@ struct SceneEvent {
} type;
Common::String message;
+ uint16 voiceId;
byte color;
byte slot;
union {
@@ -99,6 +100,7 @@ struct SceneEvent {
void clear() {
type = kNone;
message.clear();
+ voiceId = 0;
color = textColorMark;
slot = 0;
orientation = 0;
@@ -140,7 +142,7 @@ public:
void moveTo(const Common::Point &point, byte orientation = 0, bool validate = false);
Common::Point getPosition() const { return position; }
- void displayMessage(const Common::String &str, byte color = textColorMark, const Common::Point &pos = Common::Point());
+ void displayMessage(const Common::String &str, uint16 voiceIndex, byte color = textColorMark, const Common::Point &pos = Common::Point());
void setOrientation(uint8 o) { orientation = o; }
void push(const SceneEvent &event);
byte peekFlagEvent(uint16 addr) const;
@@ -220,6 +222,8 @@ private:
byte messageLastFrame;
Animation *messageAnimation;
+ uint16 _voiceId;
+
typedef Common::List<SceneEvent> EventList;
EventList events;
SceneEvent currentEvent;
diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp
index 2831064a47f..3934bc35637 100644
--- a/engines/teenagent/teenagent.cpp
+++ b/engines/teenagent/teenagent.cpp
@@ -138,7 +138,7 @@ void TeenAgentEngine::processObject() {
dcall += 2 * _dstObject->id - 2;
uint16 callback = READ_LE_UINT16(dcall);
if (callback == 0 || !processCallback(callback))
- displayMessage(_dstObject->description);
+ displayMessage(_dstObject->description, res->getVoiceIndex(_dstObject->getAddr()));
}
break;
case kActionUse: {
@@ -150,7 +150,7 @@ void TeenAgentEngine::processObject() {
dcall += 2 * _dstObject->id - 2;
uint16 callback = READ_LE_UINT16(dcall);
if (!processCallback(callback))
- displayMessage(_dstObject->description);
+ displayMessage(_dstObject->description, 0);
}
break;
@@ -783,7 +783,7 @@ Common::String TeenAgentEngine::parseMessage(uint32 addr) {
return message;
}
-void TeenAgentEngine::displayMessage(const Common::String &str, CharacterID characterID, uint16 x, uint16 y) {
+void TeenAgentEngine::displayMessage(const Common::String &str, uint16 voiceIndex, CharacterID characterID, uint16 x, uint16 y) {
if (str.empty()) {
return;
}
@@ -803,6 +803,7 @@ void TeenAgentEngine::displayMessage(const Common::String &str, CharacterID char
event.dst.x = x;
event.dst.y = y;
event.characterID = characterID;
+ event.voiceId = voiceIndex;
scene->push(event);
}
@@ -815,12 +816,13 @@ void TeenAgentEngine::displayMessage(const Common::String &str, CharacterID char
}
void TeenAgentEngine::displayMessage(uint32 addr, CharacterID characterID, uint16 x, uint16 y) {
- displayMessage(parseMessage(addr), characterID, x, y);
+ displayMessage(parseMessage(addr), res->getVoiceIndex(addr), characterID, x, y);
}
void TeenAgentEngine::displayAsyncMessage(uint32 addr, uint16 x, uint16 y, uint16 firstFrame, uint16 lastFrame, CharacterID characterID) {
SceneEvent event(SceneEvent::kMessage);
event.message = parseMessage(addr);
+ event.voiceId = res->getVoiceIndex(addr);
event.slot = 0;
event.color = characterDialogData[characterID].textColor;
event.dst.x = x;
@@ -835,6 +837,7 @@ void TeenAgentEngine::displayAsyncMessage(uint32 addr, uint16 x, uint16 y, uint1
void TeenAgentEngine::displayAsyncMessageInSlot(uint32 addr, byte slot, uint16 firstFrame, uint16 lastFrame, byte color) {
SceneEvent event(SceneEvent::kMessage);
event.message = parseMessage(addr);
+ event.voiceId = res->getVoiceIndex(addr);
event.slot = slot + 1;
event.color = color;
event.firstFrame = firstFrame;
@@ -892,6 +895,7 @@ void TeenAgentEngine::displayCutsceneMessage(uint32 addr, uint16 x, uint16 y) {
event.dst.y = y;
event.lan = 7;
event.characterID = kMark;
+ event.voiceId = res->getVoiceIndex(addr);
scene->push(event);
}
@@ -1106,6 +1110,29 @@ void TeenAgentEngine::playSoundNow(Pack *pack, uint32 id) {
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, stream); // dispose is YES by default
}
+void TeenAgentEngine::playVoiceNow(Pack *pack, uint32 id) {
+ uint size = pack->getSize(id);
+ if (size == 0) {
+ warning("skipping invalid sound %u", id);
+ return;
+ }
+
+ if (!_mixer->isSoundHandleActive(_voiceHandle) && id != _previousVoiceId) {
+ byte *data = (byte *)malloc(size);
+ pack->read(id, data, size);
+ debug(3, "playing %u samples...", size);
+
+ Audio::AudioStream *stream = Audio::makeRawStream(data, size, 11025, 0);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_voiceHandle, stream);
+ _previousVoiceId = id;
+ }
+}
+
+void TeenAgentEngine::stopVoice() {
+ _mixer->stopHandle(_voiceHandle);
+ _previousVoiceId = 0;
+}
+
void TeenAgentEngine::setMusic(byte id) {
debugC(0, kDebugMusic, "starting music %u", id);
diff --git a/engines/teenagent/teenagent.h b/engines/teenagent/teenagent.h
index 18d45d14ca8..07394d7be7e 100644
--- a/engines/teenagent/teenagent.h
+++ b/engines/teenagent/teenagent.h
@@ -124,7 +124,7 @@ public:
//event driven:
void displayMessage(uint32 addr, CharacterID characterID = kMark, uint16 x = 0, uint16 y = 0);
- void displayMessage(const Common::String &str, CharacterID characterID = kMark, uint16 x = 0, uint16 y = 0);
+ void displayMessage(const Common::String &str, uint16 voiceIndex, CharacterID characterID = kMark, uint16 x = 0, uint16 y = 0);
void displayAsyncMessage(uint32 addr, uint16 x, uint16 y, uint16 firstFrame, uint16 lastFrame, CharacterID characterID = kMark);
void displayAsyncMessageInSlot(uint32 addr, byte slot, uint16 firstFrame, uint16 lastFrame, byte color = textColorMark);
void displayCredits(uint32 addr, uint16 timer = 0);
@@ -149,6 +149,8 @@ public:
void playMusic(byte id); //schedules play
void playSound(byte id, byte skipFrames);
void playSoundNow(Pack *pack, uint32 id);
+ void playVoiceNow(Pack *pack, uint32 id);
+ void stopVoice();
void enableObject(byte id, byte sceneId = 0);
void disableObject(byte id, byte sceneId = 0);
void hideActor();
@@ -178,7 +180,8 @@ public:
Common::U32String convertCyrillic(const Common::String &text) const;
Common::String _previousSaid;
-
+ uint16 _previousVoiceId;
+
private:
void processObject();
bool trySelectedObject();
@@ -188,7 +191,7 @@ private:
Object *_dstObject;
Audio::AudioStream *_musicStream;
- Audio::SoundHandle _musicHandle, _soundHandle;
+ Audio::SoundHandle _musicHandle, _soundHandle, _voiceHandle;
const ADGameDescription *_gameDescription;
uint _markDelay, _gameDelay;
Commit: 2faa0d7f034a9204f6a9268be7904083a9f61e53
https://github.com/scummvm/scummvm/commit/2faa0d7f034a9204f6a9268be7904083a9f61e53
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-08-09T21:03:44+02:00
Commit Message:
TEENAGENT: Remove unused variables in Resources class
Changed paths:
engines/teenagent/resources.cpp
engines/teenagent/resources.h
diff --git a/engines/teenagent/resources.cpp b/engines/teenagent/resources.cpp
index 63f8c12253a..fca70d1457e 100644
--- a/engines/teenagent/resources.cpp
+++ b/engines/teenagent/resources.cpp
@@ -31,13 +31,9 @@
namespace TeenAgent {
Resources::Resources() {
- _combinationsStartOffset = 0;
- _creditsStartOffset = 0;
_dialogsStartOffset = 0;
- _messagesStartOffset = 0;
_sceneObjectsStartOffset = 0;
_sceneObjectsBlockSize = 0;
- _itemsStartOffset = 0;
}
Resources::~Resources() {
@@ -148,11 +144,9 @@ void Resources::precomputeAllOffsets(const Common::Array<ResourceInfo> &resource
for (const auto &resInfo : resourceInfos) {
switch ((ResourceType)resInfo._id) {
case kResCombinations:
- _combinationsStartOffset = resInfo._offset;
precomputeCombinationOffsets(resInfo);
break;
case kResCredits:
- _creditsStartOffset = resInfo._offset;
precomputeCreditsOffsets(resInfo);
break;
case kResDialogs:
@@ -160,11 +154,9 @@ void Resources::precomputeAllOffsets(const Common::Array<ResourceInfo> &resource
precomputeDialogOffsets(resInfo);
break;
case kResItems:
- _itemsStartOffset = resInfo._offset;
precomputeItemOffsets(resInfo);
break;
case kResMessages:
- _messagesStartOffset = resInfo._offset;
precomputeMessageOffsets(resInfo);
break;
case kResSceneObjects:
diff --git a/engines/teenagent/resources.h b/engines/teenagent/resources.h
index 621a6abbc59..ceb04fa5cec 100644
--- a/engines/teenagent/resources.h
+++ b/engines/teenagent/resources.h
@@ -1587,14 +1587,9 @@ private:
Common::Array<uint32> messageOffsets;
Common::Array<uint32> combinationOffsets;
- uint32 _messagesStartOffset;
-
uint32 _sceneObjectsStartOffset;
uint32 _sceneObjectsBlockSize; // Needed to know how much to write to savefile
- uint32 _combinationsStartOffset;
- uint32 _itemsStartOffset;
- uint32 _creditsStartOffset;
uint32 _dialogsStartOffset;
Common::HashMap<uint32, uint16> _addrToVoiceIndx;
Commit: e358d02685fe8bb820e6de49b3752c6b3bbc9ea2
https://github.com/scummvm/scummvm/commit/e358d02685fe8bb820e6de49b3752c6b3bbc9ea2
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-08-09T21:03:44+02:00
Commit Message:
TEENAGENT: Fix description being not shown for inventory items
Changed paths:
engines/teenagent/inventory.cpp
diff --git a/engines/teenagent/inventory.cpp b/engines/teenagent/inventory.cpp
index 69ff688cb5a..5944bfc4211 100644
--- a/engines/teenagent/inventory.cpp
+++ b/engines/teenagent/inventory.cpp
@@ -264,6 +264,8 @@ bool Inventory::processEvent(const Common::Event &event) {
activate(!_active);
return true;
}
+ if (event.customType == kActionSkipDialog)
+ return true;
return false;
case Common::EVENT_LBUTTONUP:
More information about the Scummvm-git-logs
mailing list