[Scummvm-git-logs] scummvm-tools master -> 934a64251c950aec46a0e149bad38953d6ab8dd1
mgerhardy
noreply at scummvm.org
Tue Jul 14 14:11:07 UTC 2026
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm-tools' repo located at https://api.github.com/repos/scummvm/scummvm-tools .
Summary:
d0aa56f4eb MACS2: fixed obj names
934a64251c MACS2: add hotspot labels from the sis game
Commit: d0aa56f4ebedd09fd7fc669b5971ab8d0be79581
https://github.com/scummvm/scummvm-tools/commit/d0aa56f4ebedd09fd7fc669b5971ab8d0be79581
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-07-14T11:23:52+02:00
Commit Message:
MACS2: fixed obj names
Changed paths:
engines/macs2/demacs2.cpp
diff --git a/engines/macs2/demacs2.cpp b/engines/macs2/demacs2.cpp
index 6545b39f..d1a087f2 100644
--- a/engines/macs2/demacs2.cpp
+++ b/engines/macs2/demacs2.cpp
@@ -1462,11 +1462,10 @@ static std::string formatVarAccess(uint16_t idx) {
}
static const char *getObjectName(uint16_t idx) {
- // Full game object names from Macs2::GameObjects::init()
- // Characters/NPCs
+ // Full-game character/NPC indices (validated against strings_object*.txt and scene dialogue)
switch (idx) {
case 1:
- return "OBJ_PLAYER";
+ return "OBJ_PLAYER"; // Old Firehand
case 2:
return "OBJ_CAPTAIN";
case 3:
@@ -1476,37 +1475,37 @@ static const char *getObjectName(uint16_t idx) {
case 5:
return "OBJ_NARRATOR";
case 6:
- return "OBJ_CORNEL";
+ return "OBJ_TRAMP"; // tramp henchman
case 7:
- return "OBJ_BEAR";
+ return "OBJ_GIRL"; // girl threatened by panther
case 9:
- return "OBJ_WOLF";
+ return "OBJ_PANTHER";
case 12:
return "OBJ_DROLL";
case 13:
return "OBJ_PATTERSON";
case 15:
- return "OBJ_ROLLINS";
+ return "OBJ_CORNEL"; // Cornel Brinkley, tramp leader
case 18:
return "OBJ_SHIP_GUARD";
case 19:
- return "OBJ_HILTON";
+ return "OBJ_TRAMP2"; // tramp henchman
case 22:
return "OBJ_WOMAN_SHIP";
case 33:
return "OBJ_SAILOR";
case 39:
- return "OBJ_WAGON_OWNER";
+ return "OBJ_WAGON_OWNER"; // Branshky
case 53:
return "OBJ_THIEF";
case 69:
- return "OBJ_SHERIFF";
+ return "OBJ_RAFTERS"; // rafter lumberjack
case 77:
- return "OBJ_INDIAN_COMPANION";
+ return "OBJ_TRAMP3"; // tramp henchman
case 105:
return "OBJ_BARKEEPER";
case 110:
- return "OBJ_COLONEL";
+ return "OBJ_MRS_BUTLER";
case 144:
return "OBJ_BANDIT_1";
case 145:
@@ -1514,15 +1513,15 @@ static const char *getObjectName(uint16_t idx) {
case 146:
return "OBJ_BANDIT_3";
case 147:
- return "OBJ_WINNETOU";
+ return "OBJ_WINNETOU"; // farm assault scene
case 149:
- return "OBJ_CHIEF";
+ return "OBJ_GROSSER_BAER"; // scene 45
case 167:
- return "OBJ_WINNETOU_INDIANS";
+ return "OBJ_WINNETOU"; // scene 45 (second sprite)
case 168:
- return "OBJ_INDIAN_ELDER";
+ return "OBJ_KLEINER_BAER"; // scene 45
case 181:
- return "OBJ_WINNETOU_ENDING";
+ return "OBJ_WINNETOU"; // ending / silver lake scenes
// Items (full game, indices from _objectNames)
case 0x08:
return "OBJ_BOARD";
@@ -1573,13 +1572,15 @@ static const char *getObjectName(uint16_t idx) {
case 0x2C:
return "OBJ_ENVELOPE_SEALED";
case 0x2D:
- return "OBJ_RACCOON_FUR";
+ return "OBJ_RACCOON_CAP";
case 0x2E:
return "OBJ_WHISKY_GLASS";
case 0x2F:
return "OBJ_LEATHER_BELT";
case 0x30:
return "OBJ_POKER";
+ case 0x31:
+ return "OBJ_WATCHDOG";
case 0x34:
return "OBJ_BOARD_SOLID";
case 0x36:
@@ -1595,13 +1596,13 @@ static const char *getObjectName(uint16_t idx) {
case 0x3C:
return "OBJ_PEBBLES";
case 0x3D:
- return "OBJ_SUITCASE_DYNAMITE";
+ return "OBJ_SUITCASE_LAUNDRY";
case 0x3E:
- return "OBJ_BANKNOTES";
+ return "OBJ_LAUNDRY";
case 0x3F:
return "OBJ_LEATHER_POUCH";
case 0x40:
- return "OBJ_SLINGSHOT";
+ return "OBJ_FIRECRACKER_POUCH";
case 0x41:
return "OBJ_FIRECRACKERS";
case 0x42:
@@ -1612,6 +1613,8 @@ static const char *getObjectName(uint16_t idx) {
return "OBJ_PAPER";
case 0x47:
return "OBJ_KNIFE_RUSTY";
+ case 0x4A:
+ return "OBJ_SCARF";
case 0x4B:
return "OBJ_REEDS_DRY";
case 0x4C:
Commit: 934a64251c950aec46a0e149bad38953d6ab8dd1
https://github.com/scummvm/scummvm-tools/commit/934a64251c950aec46a0e149bad38953d6ab8dd1
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-07-14T16:10:23+02:00
Commit Message:
MACS2: add hotspot labels from the sis game
Changed paths:
.gitignore
engines/macs2/TRANSLATE.md
engines/macs2/create_macs2_translation.cpp
diff --git a/.gitignore b/.gitignore
index ab28e83b..b7acfd68 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,11 +7,13 @@
/.gdb_history
/construct_mohawk
+/create_macs2_translation
/create_sjisfnt
/decine
/decompile
/degob
/dekyra
+/demacs2
/deprince
/descumm
/desword2
diff --git a/engines/macs2/TRANSLATE.md b/engines/macs2/TRANSLATE.md
index 08cb74ce..19c1e264 100644
--- a/engines/macs2/TRANSLATE.md
+++ b/engines/macs2/TRANSLATE.md
@@ -14,6 +14,10 @@ create_macs2_translation extract RESOURCE.MCS macs2.pot
This produces a `.pot` file with all game strings grouped by dialog context. The format uses `msgctxt` to identify the source (scene or object) and `\n` to separate lines within a dialog unit.
+Hotspot overlay labels are appended as one entry per unique German noun (`msgctxt "hotspotlabel"`). Object and NPC overlay names use `msgctxt "objectlabel"`. Both lists are embedded in `create_macs2_translation.cpp` and cover the **full game** only (`kSceneHotspotNames[]` and the non-demo branch of `gameobjects.cpp`); the demo reuses the same hotspot label strings for its subset of scene/hotspot indices, but object indices can differ between demo and full game.
+
+When packing, hotspot and object labels share one CP850 lookup table in the DAT file (duplicate German strings need only one translation).
+
The `\n` separators correspond to individual display lines in the game. Keep the same number of lines as the original.
### 3. Pack into binary
diff --git a/engines/macs2/create_macs2_translation.cpp b/engines/macs2/create_macs2_translation.cpp
index 54aec097..adabcc2d 100644
--- a/engines/macs2/create_macs2_translation.cpp
+++ b/engines/macs2/create_macs2_translation.cpp
@@ -28,12 +28,22 @@
* 3. Pack: create_macs2_translation pack <translated.po> <macs2_translation.dat>
*
* PO format:
- * msgctxt "scene:2" (or "object:42")
+ * msgctxt "scene:2:0" (or "object:42:0")
* msgid "line1\nline2\nline3"
* msgstr "translated1\ntranslated2\ntranslated3"
*
+ * msgctxt "hotspotlabel"
+ * msgid "Tür"
+ * msgstr "Door"
+ *
+ * msgctxt "objectlabel"
+ * msgid "Bowiemesser"
+ * msgstr "Bowie knife"
+ *
* Each msgid groups consecutive strings that form one dialog/description unit.
* The \n separates individual lines that the engine displays separately.
+ * Hotspot and object overlay labels are embedded below (full game only).
+ * Keep in sync with engines/macs2/hotspot_names.cpp and gameobjects.cpp.
*/
#include <algorithm>
@@ -224,6 +234,52 @@ static std::string cp850ToUtf8(const std::string &s) {
return out;
}
+// UTF-8 to CP850 (subset used by MACS2 German strings)
+static std::string utf8ToCp850(const std::string &s) {
+ std::string out;
+ for (size_t i = 0; i < s.size();) {
+ unsigned char c = (unsigned char)s[i];
+ if (c < 0x80) {
+ out += (char)c;
+ i++;
+ continue;
+ }
+ uint32_t codepoint = 0;
+ if ((c & 0xE0) == 0xC0 && i + 1 < s.size()) {
+ codepoint = ((c & 0x1F) << 6) | (s[i + 1] & 0x3F);
+ i += 2;
+ } else if ((c & 0xF0) == 0xE0 && i + 2 < s.size()) {
+ codepoint = ((c & 0x0F) << 12) | ((s[i + 1] & 0x3F) << 6) | (s[i + 2] & 0x3F);
+ i += 3;
+ } else {
+ out += '?';
+ i++;
+ continue;
+ }
+ bool mapped = false;
+ static const uint16_t cp850map[128] = {
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0,
+ };
+ for (int j = 0; j < 128; ++j) {
+ if (cp850map[j] == codepoint) {
+ out += (char)(0x80 + j);
+ mapped = true;
+ break;
+ }
+ }
+ if (!mapped)
+ out += '?';
+ }
+ return out;
+}
+
static std::string decryptString(const uint8_t *data, uint16_t length) {
std::string result;
for (int i = 1; i <= length; i++) {
@@ -473,6 +529,338 @@ static void writePoEntry(FILE *out, const char *ctx, int startIdx,
fprintf(out, "msgstr \"\"\n\n");
}
+static void writePoLabelEntry(FILE *out, const char *ctx, const std::string &cp850) {
+ fprintf(out, "msgctxt \"%s\"\n", ctx);
+ fprintf(out, "msgid \"%s\"\n", poEscape(cp850ToUtf8(cp850)).c_str());
+ fprintf(out, "msgstr \"\"\n\n");
+}
+
+// Unique hotspot overlay nouns (CP850), full game only (kSceneHotspotNames[]).
+// Demo uses the same labels for its subset of scene/hotspot indices.
+// Sync with ScummVM engines/macs2/hotspot_names.cpp when labels change.
+static const char *const kHotspotLabels[] = {
+ "Abgrund",
+ "Angreifer",
+ "Asche",
+ "Aufbauten",
+ "Ausgang",
+ "Balken",
+ "Bar",
+ "Barmann",
+ "Baum",
+ "Berge",
+ "Bett",
+ "Beutel",
+ "Bild",
+ "Bildrahmen",
+ "Bildrand",
+ "Bl" "\x84" "tterdach",
+ "Boden",
+ "Bohlen",
+ "Brecheisen",
+ "Brett",
+ "Br" "\x81" "cke",
+ "Busch",
+ "B" "\x84" "renfell",
+ "Dach",
+ "Damm",
+ "Decke",
+ "Deckel",
+ "Deckung",
+ "Dickicht",
+ "Dynamit",
+ "Eichenfass",
+ "Eimer",
+ "Eingang",
+ "Emblem",
+ "Fackel",
+ "Farm",
+ "Fass",
+ "Felsbl" "\x94" "cke",
+ "Felsen",
+ "Felswand",
+ "Fenster",
+ "Flasche",
+ "Fluss",
+ "Fracht",
+ "Fr" "\x81" "chte",
+ "Gang",
+ "Gangsystem",
+ "Gebirge",
+ "Gef" "\x84" "hrt",
+ "Gegenstand",
+ "Gel" "\x84" "nder",
+ "Ger" "\x94" "ll",
+ "Gew" "\x94" "lbe",
+ "Gras",
+ "Gussofen",
+ "Gusspfannen",
+ "Hackenspitze",
+ "Hanfseil",
+ "Haus",
+ "Heizkessel",
+ "Heuwagen",
+ "Himmel",
+ "Holz",
+ "Holzbank",
+ "Holzdach",
+ "Holzeier",
+ "Holzfass",
+ "Holzpferd",
+ "Holzscheite",
+ "Holztisch",
+ "Holzt" "\x81" "r",
+ "Hund",
+ "H" "\x81" "tte",
+ "Insel",
+ "Kabine",
+ "Kachel",
+ "Kahn",
+ "Kaj" "\x81" "te",
+ "Kamin",
+ "Kammer",
+ "Kanone",
+ "Kerze",
+ "Kiselsteine",
+ "Kiste",
+ "Koffer",
+ "Kohlen",
+ "Konstruktion",
+ "Kopf",
+ "Ladung",
+ "Lagerfeuer",
+ "Lampe",
+ "Landschaft",
+ "Leiter",
+ "Leuchter",
+ "Loch",
+ "Lore",
+ "Luke",
+ "Mauer",
+ "Mine",
+ "Mist",
+ "Musketen",
+ "M" "\x94" "glichkeit",
+ "Ofen",
+ "Pfad",
+ "Pfahl",
+ "Pferd",
+ "Pferdekoppel",
+ "Pf" "\x81" "tze",
+ "Planken",
+ "Plateau",
+ "Plattform",
+ "Pumpe",
+ "Rasen",
+ "Raum",
+ "Ruhig",
+ "Schaufel",
+ "Schienen",
+ "Schilf",
+ "Schlange",
+ "Schleier",
+ "Schleifspuren",
+ "Schrank",
+ "Schublade",
+ "Sch" "\x81" "ssel",
+ "Sch" "\x84" "del",
+ "Sch" "\x84" "tze",
+ "See",
+ "Seekoffer",
+ "Seil",
+ "Speer",
+ "Spiegel",
+ "Spielkl" "\x94" "tze",
+ "Stahlkugeln",
+ "Stamm",
+ "Steg",
+ "Stein",
+ "Steine",
+ "Steinpyramide",
+ "Steins" "\x84" "ule",
+ "Steint" "\x81" "r",
+ "Stelle",
+ "Stofftasche",
+ "Stuhl",
+ "St" "\x81" "ck",
+ "St" "\x81" "tze",
+ "S" "\x84" "ulen",
+ "Tapete",
+ "Tasse",
+ "Teddyb" "\x84" "r",
+ "Teppich",
+ "Tier",
+ "Tintenfass",
+ "Tisch",
+ "Tonvase",
+ "Totempfahl",
+ "Treppe",
+ "Truhe",
+ "T" "\x81" "r",
+ "Ufer",
+ "Unkraut",
+ "Verkleidung",
+ "Vertiefungen",
+ "Vogelk" "\x84" "fig",
+ "Vorplatz",
+ "Wald",
+ "Wand",
+ "Wasser",
+ "Wasserkrug",
+ "Weg",
+ "Whiskyglas",
+ "Winde",
+ "Windlicht",
+ "Witterung",
+ "Wolken",
+ "W" "\x84" "nde",
+ "W" "\x84" "sche",
+ "Zelt",
+ "Zeug",
+};
+
+static const uint kHotspotLabelsCount = sizeof(kHotspotLabels) / sizeof(kHotspotLabels[0]);
+
+static const char *const kObjectLabels[] = {
+ "Axt",
+ "Axtklinge",
+ "Bandit",
+ "Blasebalg",
+ "Blechdose",
+ "Blecheimer",
+ "Bohlen",
+ "Bootsjunge",
+ "Bowiemesser",
+ "Branshky",
+ "Brecheisen",
+ "Brennholz",
+ "Brett",
+ "Brief",
+ "Brot",
+ "Brotmesser",
+ "B" "\x81" "cher",
+ "Clownpuppe",
+ "Cornel",
+ "Damenhut",
+ "Dieb",
+ "Droll",
+ "Dynamit",
+ "Eimer",
+ "Eisen",
+ "Eisenstange",
+ "Fackel",
+ "Feuerhaken",
+ "Figur",
+ "Flaschenzug",
+ "Griff",
+ "Grosser B" "\xe4" "r",
+ "Hackenspitze",
+ "Haken",
+ "Haken und Seil",
+ "Hanfschnur",
+ "Hanfseil",
+ "Hanfseile",
+ "Holzente",
+ "Holzfass",
+ "Holzfigur",
+ "Holzkohle",
+ "Holzpfahl",
+ "Holzw" "\x81" "rfel",
+ "Hutschachtel",
+ "Kacheln",
+ "Kakerlake",
+ "Kapit" "\xe4" "n",
+ "Kartoffeln",
+ "Kartonschachtel",
+ "Kerze",
+ "Kerzen",
+ "Kieselsteine",
+ "Kleider",
+ "Kleiner B" "\xe4" "r",
+ "Knallfr" "\x94" "sche",
+ "Koffer",
+ "Kohlenschaufel",
+ "Korkenzieher",
+ "Kuvert",
+ "Laib Brot",
+ "Lampe",
+ "Lampenschirm",
+ "Lampenschirme",
+ "Landkarte",
+ "Lederbeutel",
+ "Lederg" "\x81" "rtel",
+ "Lore",
+ "Matrose",
+ "Messer",
+ "Messingschl" "\x81" "ssel",
+ "Metalleimer",
+ "Mrs. Butler",
+ "Murmeln",
+ "Musketen",
+ "M" "\xe4" "dchen",
+ "Nase",
+ "Old Firehand",
+ "Panther",
+ "Papier",
+ "Papierdrachen",
+ "Passagierin",
+ "Patterson",
+ "Quarzsand",
+ "Rafter",
+ "Reservestiel",
+ "Salpeterpulver",
+ "Sand",
+ "Schal",
+ "Schaufel",
+ "Schaufelspitze",
+ "Schilfrohr",
+ "Schnapsflasche",
+ "Schraubenzieher",
+ "Schwarzpulver",
+ "Schwefel",
+ "Sch" "\x81" "rhaken",
+ "Sch" "\x81" "ssel",
+ "Sicheln",
+ "Socken",
+ "Spachtel",
+ "Spitzhacke",
+ "Stoffbeutel",
+ "Streichholz",
+ "Tasse",
+ "Teig",
+ "Tomahawk",
+ "Topflappen",
+ "Tramp",
+ "Vogelk" "\x84" "fig",
+ "Wachhund",
+ "Wachposten",
+ "Wagenrad",
+ "Waschb" "\x84" "rm" "\x81" "tze",
+ "Whiskyglas",
+ "Windlicht",
+ "Winnetou",
+ "Wirt",
+ "Wolle",
+};
+
+static const uint kObjectLabelsCount = sizeof(kObjectLabels) / sizeof(kObjectLabels[0]);
+
+static void extractObjectLabels(FILE *out, int &totalEntries) {
+ fprintf(out, "# Object/NPC overlay labels (unique names, full game, CP850/latin-1 source)\n\n");
+ for (uint i = 0; i < kObjectLabelsCount; ++i) {
+ writePoLabelEntry(out, "objectlabel", kObjectLabels[i]);
+ totalEntries++;
+ }
+}
+
+static void extractHotspotLabels(FILE *out, int &totalEntries) {
+ fprintf(out, "# Hotspot overlay labels (unique nouns, CP850 source in engine)\n\n");
+ for (uint i = 0; i < kHotspotLabelsCount; ++i) {
+ writePoLabelEntry(out, "hotspotlabel", kHotspotLabels[i]);
+ totalEntries++;
+ }
+}
+
static int doExtract(const char *resPath, const char *outPath) {
resFile = fopen(resPath, "rb");
if (!resFile) {
@@ -565,9 +953,12 @@ static int doExtract(const char *resPath, const char *outPath) {
}
}
+ extractHotspotLabels(out, totalEntries);
+ extractObjectLabels(out, totalEntries);
+
fclose(out);
fclose(resFile);
- printf("Extracted %d dialog entries to %s\n", totalEntries, outPath);
+ printf("Extracted %d entries (%u hotspot + %u object labels) to %s\n", totalEntries, kHotspotLabelsCount, kObjectLabelsCount, outPath);
return 0;
}
@@ -583,13 +974,15 @@ static int doPack(const char *poPath, const char *outPath) {
return 1;
}
- // Parse PO: msgctxt "scene:N:startIdx" or "object:N:startIdx"
+ // Parse PO: msgctxt "scene:N:startIdx", "object:N:startIdx", "hotspotlabel", or "objectlabel"
// msgstr contains \n-separated translated lines
std::map<uint16_t, std::map<int, std::vector<std::string> > > sceneStrings;
std::map<uint16_t, std::map<int, std::vector<std::string> > > objectStrings;
+ std::map<std::string, std::string> overlayLabelStrings;
+ std::string currentMsgid;
+ enum PoCtxKind { kPoCtxNone, kPoCtxScene, kPoCtxObjectDialog, kPoCtxHotspotLabel, kPoCtxObjectLabel } ctxKind = kPoCtxNone;
char line[8192];
- bool isScene = false;
uint16_t currentId = 0;
int currentStartIdx = 0;
bool hasCtx = false;
@@ -600,28 +993,36 @@ static int doPack(const char *poPath, const char *outPath) {
auto flushEntry = [&]() {
if (hasCtx && !currentMsgstr.empty()) {
std::string text = poUnescape(currentMsgstr);
- std::vector<std::string> lines;
- size_t start = 0;
- while (start < text.size()) {
- size_t nl = text.find('\n', start);
- if (nl == std::string::npos) {
- lines.push_back(text.substr(start));
- break;
+ if (ctxKind == kPoCtxHotspotLabel || ctxKind == kPoCtxObjectLabel) {
+ std::string source = poUnescape(currentMsgid);
+ if (!source.empty())
+ overlayLabelStrings[source] = text;
+ } else {
+ std::vector<std::string> lines;
+ size_t start = 0;
+ while (start < text.size()) {
+ size_t nl = text.find('\n', start);
+ if (nl == std::string::npos) {
+ lines.push_back(text.substr(start));
+ break;
+ }
+ lines.push_back(text.substr(start, nl - start));
+ start = nl + 1;
+ }
+ if (!lines.empty()) {
+ if (ctxKind == kPoCtxScene)
+ sceneStrings[currentId][currentStartIdx] = lines;
+ else if (ctxKind == kPoCtxObjectDialog)
+ objectStrings[currentId][currentStartIdx] = lines;
}
- lines.push_back(text.substr(start, nl - start));
- start = nl + 1;
- }
- if (!lines.empty()) {
- if (isScene)
- sceneStrings[currentId][currentStartIdx] = lines;
- else
- objectStrings[currentId][currentStartIdx] = lines;
}
}
hasCtx = false;
currentMsgstr.clear();
+ currentMsgid.clear();
inMsgstr = false;
inMsgid = false;
+ ctxKind = kPoCtxNone;
};
while (fgets(line, sizeof(line), in)) {
@@ -633,15 +1034,21 @@ static int doPack(const char *poPath, const char *outPath) {
flushEntry();
int id = 0, idx = 0;
if (sscanf(line + 9, "scene:%d:%d", &id, &idx) == 2) {
- isScene = true;
+ ctxKind = kPoCtxScene;
currentId = (uint16_t)id;
currentStartIdx = idx;
hasCtx = true;
} else if (sscanf(line + 9, "object:%d:%d", &id, &idx) == 2) {
- isScene = false;
+ ctxKind = kPoCtxObjectDialog;
currentId = (uint16_t)id;
currentStartIdx = idx;
hasCtx = true;
+ } else if (!strncmp(line + 9, "hotspotlabel\"", 13)) {
+ ctxKind = kPoCtxHotspotLabel;
+ hasCtx = true;
+ } else if (!strncmp(line + 9, "objectlabel\"", 13)) {
+ ctxKind = kPoCtxObjectLabel;
+ hasCtx = true;
}
continue;
}
@@ -660,6 +1067,14 @@ static int doPack(const char *poPath, const char *outPath) {
if (strncmp(line, "msgid ", 6) == 0) {
inMsgid = true;
inMsgstr = false;
+ currentMsgid.clear();
+ char *s = strchr(line + 6, '"');
+ if (s) {
+ s++;
+ char *e = strrchr(s, '"');
+ if (e)
+ currentMsgid = std::string(s, e - s);
+ }
continue;
}
if (line[0] == '"' && inMsgstr) {
@@ -670,8 +1085,12 @@ static int doPack(const char *poPath, const char *outPath) {
continue;
}
if (line[0] == '"' && inMsgid) {
+ char *s = line + 1;
+ char *e = strrchr(s, '"');
+ if (e)
+ currentMsgid += std::string(s, e - s);
continue;
- } // skip msgid continuation
+ }
if (line[0] == '\0')
flushEntry();
}
@@ -720,9 +1139,10 @@ static int doPack(const char *poPath, const char *outPath) {
}
fwrite("MCS2", 1, 4, out);
- writeU16(out, 1);
+ writeU16(out, 2);
writeU16(out, (uint16_t)sceneBlocks.size());
writeU16(out, (uint16_t)objectBlocks.size());
+ writeU16(out, (uint16_t)overlayLabelStrings.size());
long indexStart = ftell(out);
uint32_t indexSize = ((uint32_t)sceneBlocks.size() + (uint32_t)objectBlocks.size()) * 8;
@@ -760,9 +1180,20 @@ static int doPack(const char *poPath, const char *outPath) {
writeU32(out, objectOffsets[i]);
}
+ for (const auto &kv : overlayLabelStrings) {
+ const std::string source = utf8ToCp850(kv.first);
+ const std::string translated = utf8ToCp850(kv.second);
+ writeU16(out, (uint16_t)source.size());
+ if (!source.empty())
+ fwrite(source.data(), 1, source.size(), out);
+ writeU16(out, (uint16_t)translated.size());
+ if (!translated.empty())
+ fwrite(translated.data(), 1, translated.size(), out);
+ }
+
fclose(out);
- printf("Packed %zu scene + %zu object blocks into %s\n",
- sceneBlocks.size(), objectBlocks.size(), outPath);
+ printf("Packed %zu scene + %zu object blocks + %zu overlay labels into %s\n",
+ sceneBlocks.size(), objectBlocks.size(), overlayLabelStrings.size(), outPath);
return 0;
}
More information about the Scummvm-git-logs
mailing list