scummvm/devtools/create_kyradat/create_kyradat.cpp

2358 lines
74 KiB
C++

/* 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.
*
*/
// Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL
// HACK to allow building with the SDL backend on MinGW
// see bug #1800764 "TOOLS: MinGW tools building broken"
#ifdef main
#undef main
#endif // main
#include "create_kyradat.h"
#include "search.h"
#include "pak.h"
#include "tables.h"
#include "extract.h"
#include "md5.h"
#include <string>
#include <map>
#include <algorithm>
#include <map>
enum {
kKyraDatVersion = 79
};
const ExtractFilename extractFilenames[] = {
// GENERIC ID MAP
{ kIdMap, -1, true },
// INTRO / OUTRO sequences
{ k1ForestSeq, kTypeForestSeqData, false },
{ k1KallakWritingSeq, kTypeRawData, false },
{ k1KyrandiaLogoSeq, kTypeRawData, false },
{ k1KallakMalcolmSeq, kTypeRawData, false },
{ k1MalcolmTreeSeq, kTypeRawData, false },
{ k1WestwoodLogoSeq, kTypeRawData, false },
{ k1Demo1Seq, kTypeRawData, false },
{ k1Demo2Seq, kTypeRawData, false },
{ k1Demo3Seq, kTypeRawData, false },
{ k1Demo4Seq, kTypeRawData, false },
{ k1OutroReunionSeq, kTypeRawData, false },
// INTRO / OUTRO strings
{ k1IntroCPSStrings, kTypeStringList, false },
{ k1IntroCOLStrings, kTypeStringList, false },
{ k1IntroWSAStrings, kTypeStringList, false },
{ k1IntroStrings, kTypeStringList, true },
{ k1OutroHomeString, kTypeStringList, true },
// INGAME strings
{ k1ItemNames, kTypeStringList, true },
{ k1TakenStrings, kTypeStringList, true },
{ k1PlacedStrings, kTypeStringList, true },
{ k1DroppedStrings, kTypeStringList, true },
{ k1NoDropStrings, kTypeStringList, true },
{ k1PutDownString, kTypeStringList, true },
{ k1WaitAmuletString, kTypeStringList, true },
{ k1BlackJewelString, kTypeStringList, true },
{ k1PoisonGoneString, kTypeStringList, true },
{ k1HealingTipString, kTypeStringList, true },
{ k1ThePoisonStrings, kTypeStringList, true },
{ k1FluteStrings, kTypeStringList, true },
{ k1WispJewelStrings, kTypeStringList, true },
{ k1MagicJewelStrings, kTypeStringList, true },
{ k1FlaskFullString, kTypeStringList, true },
{ k1FullFlaskString, kTypeStringList, true },
{ k1VeryCleverString, kTypeStringList, true },
{ k1NewGameString, kTypeStringList, true },
// GUI strings table
{ k1GUIStrings, kTypeStringList, true },
{ k1ConfigStrings, kTypeStringList, true },
// ROOM table/filenames
{ k1RoomList, kTypeRoomList, false },
{ k1RoomFilenames, kTypeStringList, false },
// SHAPE tables
{ k1DefaultShapes, kTypeShapeList, false },
{ k1Healing1Shapes, kTypeShapeList, false },
{ k1Healing2Shapes, kTypeShapeList, false },
{ k1PoisonDeathShapes, kTypeShapeList, false },
{ k1FluteShapes, kTypeShapeList, false },
{ k1Winter1Shapes, kTypeShapeList, false },
{ k1Winter2Shapes, kTypeShapeList, false },
{ k1Winter3Shapes, kTypeShapeList, false },
{ k1DrinkShapes, kTypeShapeList, false },
{ k1WispShapes, kTypeShapeList, false },
{ k1MagicAnimShapes, kTypeShapeList, false },
{ k1BranStoneShapes, kTypeShapeList, false },
// IMAGE filename table
{ k1CharacterImageFilenames, kTypeStringList, false },
// AUDIO filename table
{ k1AudioTracks, kTypeStringList, false },
{ k1AudioTracks2, kTypeStringList, false },
{ k1AudioTracksIntro, kTypeStringList, false },
// AMULET anim
{ k1AmuleteAnimSeq, kTypeRawData, false },
// PALETTE table
{ k1SpecialPalette1, kTypeRawData, false },
{ k1SpecialPalette2, kTypeRawData, false },
{ k1SpecialPalette3, kTypeRawData, false },
{ k1SpecialPalette4, kTypeRawData, false },
{ k1SpecialPalette5, kTypeRawData, false },
{ k1SpecialPalette6, kTypeRawData, false },
{ k1SpecialPalette7, kTypeRawData, false },
{ k1SpecialPalette8, kTypeRawData, false },
{ k1SpecialPalette9, kTypeRawData, false },
{ k1SpecialPalette10, kTypeRawData, false },
{ k1SpecialPalette11, kTypeRawData, false },
{ k1SpecialPalette12, kTypeRawData, false },
{ k1SpecialPalette13, kTypeRawData, false },
{ k1SpecialPalette14, kTypeRawData, false },
{ k1SpecialPalette15, kTypeRawData, false },
{ k1SpecialPalette16, kTypeRawData, false },
{ k1SpecialPalette17, kTypeRawData, false },
{ k1SpecialPalette18, kTypeRawData, false },
{ k1SpecialPalette19, kTypeRawData, false },
{ k1SpecialPalette20, kTypeRawData, false },
{ k1SpecialPalette21, kTypeRawData, false },
{ k1SpecialPalette22, kTypeRawData, false },
{ k1SpecialPalette23, kTypeRawData, false },
{ k1SpecialPalette24, kTypeRawData, false },
{ k1SpecialPalette25, kTypeRawData, false },
{ k1SpecialPalette26, kTypeRawData, false },
{ k1SpecialPalette27, kTypeRawData, false },
{ k1SpecialPalette28, kTypeRawData, false },
{ k1SpecialPalette29, kTypeRawData, false },
{ k1SpecialPalette30, kTypeRawData, false },
{ k1SpecialPalette31, kTypeRawData, false },
{ k1SpecialPalette32, kTypeRawData, false },
{ k1SpecialPalette33, kTypeRawData, false },
// CREDITS (used in FM-TOWNS and AMIGA)
{ k1CreditsStrings, kTypeRawData, true },
// FM-TOWNS specific
{ k1TownsMusicFadeTable, k3TypeRaw16to8, false },
{ k1TownsSFXwdTable, kTypeTownsWDSfxTable, false },
{ k1TownsSFXbtTable, kTypeRawData, false },
{ k1TownsCDATable, kTypeRawData, false },
// PC98 specific
{ k1PC98StoryStrings, kTypeStringList, true },
{ k1PC98IntroSfx, kTypeRawData, false },
// AMIGA specific
{ k1AmigaIntroSFXTable, kTypeAmigaSfxTable, false },
{ k1AmigaGameSFXTable, kTypeAmigaSfxTable, false },
// HAND OF FATE
// Sequence Player
{ k2SeqplayPakFiles, kTypeStringList, false },
{ k2SeqplayCredits, kTypeRawData, false },
{ k2SeqplayCreditsSpecial, kTypeStringList, false },
{ k2SeqplayStrings, kTypeStringList, true },
{ k2SeqplaySfxFiles, k2TypeSoundList, false },
{ k2SeqplayTlkFiles, k2TypeLangSoundList, true },
{ k2SeqplaySeqData, k2TypeSeqData, false },
{ k2SeqplayIntroTracks, kTypeStringList, false },
{ k2SeqplayFinaleTracks, kTypeStringList, false },
{ k2SeqplayIntroCDA, kTypeRawData, false },
{ k2SeqplayFinaleCDA, kTypeRawData, false },
{ k2SeqplayShapeAnimData, k2TypeShpDataV1, false },
// Ingame
{ k2IngamePakFiles, kTypeStringList, false },
{ k2IngameSfxFiles, k2TypeSize10StringList, false },
{ k2IngameSfxIndex, kTypeRawData, false },
{ k2IngameTracks, kTypeStringList, false },
{ k2IngameCDA, kTypeRawData, false },
{ k2IngameTalkObjIndex, kTypeRawData, false },
{ k2IngameTimJpStrings, kTypeStringList, false },
{ k2IngameShapeAnimData, k2TypeShpDataV2, false },
{ k2IngameTlkDemoStrings, kTypeStringList, true },
// MALCOLM'S REVENGE
{ k3MainMenuStrings, kTypeStringList, false },
{ k3MusicFiles, k2TypeSoundList, false },
{ k3ScoreTable, kTypeRawData, false },
{ k3SfxFiles, k2TypeSfxList, false },
{ k3SfxMap, k3TypeRaw16to8, false },
{ k3ItemAnimData, k3TypeShpData, false },
{ k3ItemMagicTable, k3TypeRaw16to8, false },
{ k3ItemStringMap, kTypeRawData, false },
// EYE OF THE BEHOLDER COMMON
{ kEobBaseChargenStrings1, kTypeStringList, true },
{ kEobBaseChargenStrings2, kTypeStringList, true },
{ kEobBaseChargenStartLevels, kTypeRawData, false },
{ kEobBaseChargenStatStrings, kTypeStringList, true},
{ kEobBaseChargenRaceSexStrings, kTypeStringList, true },
{ kEobBaseChargenClassStrings, kTypeStringList, true },
{ kEobBaseChargenAlignmentStrings, kTypeStringList, true },
{ kEobBaseChargenEnterGameStrings, kTypeStringList, true },
{ kEobBaseChargenClassMinStats, k3TypeRaw16to8, false },
{ kEobBaseChargenRaceMinStats, k3TypeRaw16to8, false },
{ kEobBaseChargenRaceMaxStats, kLolTypeRaw16, false },
{ kEobBaseConstModTable1, kTypeRawData, false },
{ kEobBaseConstModTable2, kTypeRawData, false },
{ kEobBaseConstModTable3, kTypeRawData, false },
{ kEobBaseConstModTable4, kTypeRawData, false },
{ kEobBaseConstModLvlIndex, kTypeRawData, false },
{ kEobBaseConstModDiv, kTypeRawData, false },
{ kEobBaseConstModExt, kTypeRawData, false },
{ kEobBasePryDoorStrings, kTypeStringList, true },
{ kEobBaseWarningStrings, kTypeStringList, true },
{ kEobBaseItemSuffixStringsRings, kTypeStringList, true },
{ kEobBaseItemSuffixStringsPotions, kTypeStringList, true },
{ kEobBaseItemSuffixStringsWands, kTypeStringList, true },
{ kEobBaseRipItemStrings, kTypeStringList, true },
{ kEobBaseCursedString, kTypeStringList, true },
{ kEobBaseEnchantedString, kTypeStringList, false },
{ kEobBaseMagicObjectStrings, kTypeStringList, true },
{ kEobBaseMagicObject5String, kTypeStringList, true },
{ kEobBasePatternSuffix, kTypeStringList, true },
{ kEobBasePatternGrFix1, kTypeStringList, true },
{ kEobBasePatternGrFix2, kTypeStringList, true },
{ kEobBaseValidateArmorString, kTypeStringList, true },
{ kEobBaseValidateCursedString, kTypeStringList, true },
{ kEobBaseValidateNoDropString, kTypeStringList, true },
{ kEobBasePotionStrings, kTypeStringList, true },
{ kEobBaseWandString, kTypeStringList, true },
{ kEobBaseItemMisuseStrings, kTypeStringList, true },
{ kEobBaseTakenStrings, kTypeStringList, true },
{ kEobBasePotionEffectStrings, kTypeStringList, true },
{ kEobBaseYesNoStrings, kTypeStringList, true },
{ kLolEobCommonMoreStrings, kTypeStringList, true },
{ kEobBaseNpcMaxStrings, kTypeStringList, true },
{ kEobBaseOkStrings, kTypeStringList, true },
{ kEobBaseNpcJoinStrings, kTypeStringList, true },
{ kEobBaseCancelStrings, kTypeStringList, true },
{ kEobBaseAbortStrings, kTypeStringList, true },
{ kEobBaseMenuStringsMain, kTypeStringList, true },
{ kEobBaseMenuStringsSaveLoad, kTypeStringList, true },
{ kEobBaseMenuStringsOnOff, kTypeStringList, true },
{ kEobBaseMenuStringsSpells, kTypeStringList, true },
{ kEobBaseMenuStringsRest, kTypeStringList, true },
{ kEobBaseMenuStringsDrop, kTypeStringList, true },
{ kEobBaseMenuStringsExit, kTypeStringList, true },
{ kEobBaseMenuStringsStarve, kTypeStringList, true },
{ kEobBaseMenuStringsScribe, kTypeStringList, true },
{ kEobBaseMenuStringsDrop2, kTypeStringList, true },
{ kEobBaseMenuStringsHead, kTypeStringList, true },
{ kEobBaseMenuStringsPoison, kTypeStringList, true },
{ kEobBaseMenuStringsMgc, kTypeStringList, true },
{ kEobBaseMenuStringsPrefs, kTypeStringList, true },
{ kEobBaseMenuStringsRest2, kTypeStringList, true },
{ kEobBaseMenuStringsRest3, kTypeStringList, true },
{ kEobBaseMenuStringsRest4, kTypeStringList, true },
{ kEobBaseMenuStringsDefeat, kTypeStringList, true },
{ kEobBaseMenuStringsTransfer, kTypeStringList, true },
{ kEobBaseMenuStringsSpec, kTypeStringList, true },
{ kEobBaseMenuStringsSpellNo, kTypeStringList, false },
{ kEobBaseMenuYesNoStrings, kTypeStringList, true },
{ kEobBaseSpellLevelsMage, kTypeRawData, false },
{ kEobBaseSpellLevelsCleric, kTypeRawData, false },
{ kEobBaseNumSpellsCleric, kTypeRawData, false },
{ kEobBaseNumSpellsWisAdj, kTypeRawData, false },
{ kEobBaseNumSpellsPal, kTypeRawData, false },
{ kEobBaseNumSpellsMage, kTypeRawData, false },
{ kEobBaseCharGuiStringsHp, kTypeStringList, true },
{ kEobBaseCharGuiStringsWp1, kTypeStringList, true },
{ kEobBaseCharGuiStringsWp2, kTypeStringList, true },
{ kEobBaseCharGuiStringsWr, kTypeStringList, true },
{ kEobBaseCharGuiStringsSt1, kTypeStringList, true },
{ kEobBaseCharGuiStringsSt2, kTypeStringList, true },
{ kEobBaseCharGuiStringsIn, kTypeStringList, true },
{ kEobBaseCharStatusStrings7, kTypeStringList, true },
{ kEobBaseCharStatusStrings81, kTypeStringList, true },
{ kEobBaseCharStatusStrings82, kTypeStringList, true },
{ kEobBaseCharStatusStrings9, kTypeStringList, true },
{ kEobBaseCharStatusStrings12, kTypeStringList, true },
{ kEobBaseCharStatusStrings131, kTypeStringList, true },
{ kEobBaseCharStatusStrings132, kTypeStringList, true },
{ kEobBaseLevelGainStrings, kTypeStringList, true },
{ kEobBaseExperienceTable0, kLolTypeRaw32, false },
{ kEobBaseExperienceTable1, kLolTypeRaw32, false },
{ kEobBaseExperienceTable2, kLolTypeRaw32, false },
{ kEobBaseExperienceTable3, kLolTypeRaw32, false },
{ kEobBaseExperienceTable4, kLolTypeRaw32, false },
{ kEobBaseWllFlagPreset, kTypeRawData, false },
{ kEobBaseDscShapeCoords, kLolTypeRaw16, false },
{ kEobBaseDscDoorScaleOffs, kTypeRawData, false },
{ kEobBaseDscDoorScaleMult1, kTypeRawData, false },
{ kEobBaseDscDoorScaleMult2, kTypeRawData, false },
{ kEobBaseDscDoorScaleMult3, kTypeRawData, false },
{ kEobBaseDscDoorScaleMult4, kTypeRawData, false },
{ kEobBaseDscDoorScaleMult5, kTypeRawData, false },
{ kEobBaseDscDoorScaleMult6, kTypeRawData, false },
{ kEobBaseDscDoorType5Offs, kTypeRawData, false },
{ kEobBaseDscDoorY1, kTypeRawData, false },
{ kEobBaseDscDoorY3, kTypeRawData, false },
{ kEobBaseDscDoorY4, kTypeRawData, false },
{ kEobBaseDscDoorY5, kTypeRawData, false },
{ kEobBaseDscDoorY6, kTypeRawData, false },
{ kEobBaseDscDoorCoordsExt, kLolTypeRaw16, false },
{ kEobBaseDscItemPosIndex, kTypeRawData, false },
{ kEobBaseDscItemShpX, kLolTypeRaw16, false },
{ kEobBaseDscItemPosUnk, kTypeRawData, false },
{ kEobBaseDscItemTileIndex, kTypeRawData, false },
{ kEobBaseDscItemShapeMap, kTypeRawData, false },
{ kEobBaseDscTelptrShpCoords, kTypeRawData, false },
{ kEobBasePortalSeqData, kTypeRawData, false },
{ kEobBaseManDef, kTypeRawData, true },
{ kEobBaseManWord, kTypeStringList, true },
{ kEobBaseManPrompt, kTypeStringList, true },
{ kEobBaseDscMonsterFrmOffsTbl1, kTypeRawData, false },
{ kEobBaseDscMonsterFrmOffsTbl2, kTypeRawData, false },
{ kEobBaseInvSlotX, kLolTypeRaw16, false },
{ kEobBaseInvSlotY, kTypeRawData, false },
{ kEobBaseSlotValidationFlags, kLolTypeRaw16, false },
{ kEobBaseProjectileWeaponTypes, kTypeRawData, false },
{ kEobBaseWandTypes, kTypeRawData, false },
{ kEobBaseDrawObjPosIndex, kTypeRawData, false },
{ kEobBaseFlightObjFlipIndex, kTypeRawData, false },
{ kEobBaseFlightObjShpMap, kTypeRawData, false },
{ kEobBaseFlightObjSclIndex, kTypeRawData, false },
{ kEobBaseBookNumbers, kTypeStringList, true },
{ kEobBaseMageSpellsList, kTypeStringList, true },
{ kEobBaseClericSpellsList, kTypeStringList, true },
{ kEobBaseSpellNames, kTypeStringList, true },
{ kEobBaseMagicStrings1, kTypeStringList, true },
{ kEobBaseMagicStrings2, kTypeStringList, true },
{ kEobBaseMagicStrings3, kTypeStringList, true },
{ kEobBaseMagicStrings4, kTypeStringList, true },
{ kEobBaseMagicStrings6, kTypeStringList, true },
{ kEobBaseMagicStrings7, kTypeStringList, true },
{ kEobBaseMagicStrings8, kTypeStringList, true },
{ kEobBaseExpObjectTlMode, kTypeRawData, false },
{ kEobBaseExpObjectTblIndex, kTypeRawData, false },
{ kEobBaseExpObjectShpStart, kTypeRawData, false },
{ kEobBaseExpObjectTbl1, kTypeRawData, false },
{ kEobBaseExpObjectTbl2, kTypeRawData, false },
{ kEobBaseExpObjectTbl3, kTypeRawData, false },
{ kEobBaseExpObjectY, k3TypeRaw16to8, false },
{ kEobBaseSparkDefSteps, kTypeRawData, false },
{ kEobBaseSparkDefSubSteps, kTypeRawData, false },
{ kEobBaseSparkDefShift, kTypeRawData, false },
{ kEobBaseSparkDefAdd, kTypeRawData, false },
{ kEobBaseSparkDefX, k3TypeRaw16to8, false },
{ kEobBaseSparkDefY, kTypeRawData, false },
{ kEobBaseSparkOfFlags1, kLolTypeRaw32, false },
{ kEobBaseSparkOfFlags2, kLolTypeRaw32, false },
{ kEobBaseSparkOfShift, kTypeRawData, false },
{ kEobBaseSparkOfX, kTypeRawData, false },
{ kEobBaseSparkOfY, kTypeRawData, false },
{ kEobBaseSpellProperties, kTypeRawData, false },
{ kEobBaseMagicFlightProps, kTypeRawData, false },
{ kEobBaseTurnUndeadEffect, kTypeRawData, false },
// EYE OF THE BEHOLDER I
{ kEob1MainMenuStrings, kTypeStringList, true },
{ kEob1DoorShapeDefs, kTypeRawData, false },
{ kEob1DoorSwitchShapeDefs, kTypeRawData, false },
{ kEob1DoorSwitchCoords, kTypeRawData, false },
{ kEob1MonsterProperties, kTypeRawData, false },
{ kEob1MonsterDistAttType10, kTypeRawData, false },
{ kEob1MonsterDistAttSfx10, kTypeRawData, false },
{ kEob1MonsterDistAttType17, kTypeRawData, false },
{ kEob1MonsterDistAttSfx17, kTypeRawData, false },
{ kEob1TurnUndeadString, kTypeStringList, true },
{ kEob1NpcShpData, kTypeRawData, false },
{ kEob1NpcSubShpIndex1, kTypeRawData, false },
{ kEob1NpcSubShpIndex2, kTypeRawData, false },
{ kEob1NpcSubShpY, kTypeRawData, false },
{ kEob1Npc0Strings, kTypeStringList, true },
{ kEob1Npc11Strings, kTypeStringList, true },
{ kEob1Npc12Strings, kTypeStringList, true },
{ kEob1Npc21Strings, kTypeStringList, true },
{ kEob1Npc22Strings, kTypeStringList, true },
{ kEob1Npc31Strings, kTypeStringList, true },
{ kEob1Npc32Strings, kTypeStringList, true },
{ kEob1Npc4Strings, kTypeStringList, true },
{ kEob1Npc5Strings, kTypeStringList, true },
{ kEob1Npc6Strings, kTypeStringList, true },
{ kEob1Npc7Strings, kTypeStringList, true },
// EYE OF THE BEHOLDER II
{ kEob2MainMenuStrings, kTypeStringList, true },
{ kEob2IntroStrings, k2TypeSfxList, true },
{ kEob2IntroCPSFiles, kTypeStringList, true },
{ kEob2IntroSeqData00, kEob2TypeSeqData, false },
{ kEob2IntroSeqData01, kEob2TypeSeqData, false },
{ kEob2IntroSeqData02, kEob2TypeSeqData, false },
{ kEob2IntroSeqData03, kEob2TypeSeqData, false },
{ kEob2IntroSeqData04, kEob2TypeSeqData, false },
{ kEob2IntroSeqData05, kEob2TypeSeqData, false },
{ kEob2IntroSeqData06, kEob2TypeSeqData, false },
{ kEob2IntroSeqData07, kEob2TypeSeqData, false },
{ kEob2IntroSeqData08, kEob2TypeSeqData, false },
{ kEob2IntroSeqData09, kEob2TypeSeqData, false },
{ kEob2IntroSeqData10, kEob2TypeSeqData, false },
{ kEob2IntroSeqData11, kEob2TypeSeqData, false },
{ kEob2IntroSeqData12, kEob2TypeSeqData, false },
{ kEob2IntroSeqData13, kEob2TypeSeqData, false },
{ kEob2IntroSeqData14, kEob2TypeSeqData, false },
{ kEob2IntroSeqData15, kEob2TypeSeqData, false },
{ kEob2IntroSeqData16, kEob2TypeSeqData, false },
{ kEob2IntroSeqData17, kEob2TypeSeqData, false },
{ kEob2IntroSeqData18, kEob2TypeSeqData, false },
{ kEob2IntroSeqData19, kEob2TypeSeqData, false },
{ kEob2IntroSeqData20, kEob2TypeSeqData, false },
{ kEob2IntroSeqData21, kEob2TypeSeqData, false },
{ kEob2IntroSeqData22, kEob2TypeSeqData, false },
{ kEob2IntroSeqData23, kEob2TypeSeqData, false },
{ kEob2IntroSeqData24, kEob2TypeSeqData, false },
{ kEob2IntroSeqData25, kEob2TypeSeqData, false },
{ kEob2IntroSeqData26, kEob2TypeSeqData, false },
{ kEob2IntroSeqData27, kEob2TypeSeqData, false },
{ kEob2IntroSeqData28, kEob2TypeSeqData, false },
{ kEob2IntroSeqData29, kEob2TypeSeqData, false },
{ kEob2IntroSeqData30, kEob2TypeSeqData, false },
{ kEob2IntroSeqData31, kEob2TypeSeqData, false },
{ kEob2IntroSeqData32, kEob2TypeSeqData, false },
{ kEob2IntroSeqData33, kEob2TypeSeqData, false },
{ kEob2IntroSeqData34, kEob2TypeSeqData, false },
{ kEob2IntroSeqData35, kEob2TypeSeqData, false },
{ kEob2IntroSeqData36, kEob2TypeSeqData, false },
{ kEob2IntroSeqData37, kEob2TypeSeqData, false },
{ kEob2IntroSeqData38, kEob2TypeSeqData, false },
{ kEob2IntroSeqData39, kEob2TypeSeqData, false },
{ kEob2IntroSeqData40, kEob2TypeSeqData, false },
{ kEob2IntroSeqData41, kEob2TypeSeqData, false },
{ kEob2IntroSeqData42, kEob2TypeSeqData, false },
{ kEob2IntroSeqData43, kEob2TypeSeqData, false },
{ kEob2IntroShapes00, kEob2TypeShapeData, false },
{ kEob2IntroShapes01, kEob2TypeShapeData, false },
{ kEob2IntroShapes04, kEob2TypeShapeData, false },
{ kEob2IntroShapes07, kEob2TypeShapeData, false },
{ kEob2FinaleStrings, k2TypeSfxList, true },
{ kEob2CreditsData, kTypeRawData, true },
{ kEob2FinaleCPSFiles, kTypeStringList, true },
{ kEob2FinaleSeqData00, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData01, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData02, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData03, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData04, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData05, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData06, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData07, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData08, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData09, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData10, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData11, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData12, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData13, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData14, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData15, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData16, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData17, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData18, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData19, kEob2TypeSeqData, false },
{ kEob2FinaleSeqData20, kEob2TypeSeqData, false },
{ kEob2FinaleShapes00, kEob2TypeShapeData, false },
{ kEob2FinaleShapes03, kEob2TypeShapeData, false },
{ kEob2FinaleShapes07, kEob2TypeShapeData, false },
{ kEob2FinaleShapes09, kEob2TypeShapeData, false },
{ kEob2FinaleShapes10, kEob2TypeShapeData, false },
{ kEob2NpcShapeData, kTypeRawData, false },
{ kEobBaseClassModifierFlags, kTypeRawData, false },
{ kEobBaseMonsterStepTable01, kTypeRawData, false },
{ kEobBaseMonsterStepTable02, kTypeRawData, false },
{ kEobBaseMonsterStepTable1, kTypeRawData, false },
{ kEobBaseMonsterStepTable2, k3TypeRaw16to8, false },
{ kEobBaseMonsterStepTable3, k3TypeRaw16to8, false },
{ kEobBaseMonsterCloseAttPosTable1, kTypeRawData, false },
{ kEobBaseMonsterCloseAttPosTable21, kTypeRawData, false },
{ kEobBaseMonsterCloseAttPosTable22, kTypeRawData, false },
{ kEobBaseMonsterCloseAttUnkTable, kTypeRawData, false },
{ kEobBaseMonsterCloseAttChkTable1, kTypeRawData, false },
{ kEobBaseMonsterCloseAttChkTable2, kTypeRawData, false },
{ kEobBaseMonsterCloseAttDstTable1, kTypeRawData, false },
{ kEobBaseMonsterCloseAttDstTable2, kTypeRawData, false },
{ kEobBaseMonsterProximityTable, kTypeRawData, false },
{ kEobBaseFindBlockMonstersTable, kTypeRawData, false },
{ kEobBaseMonsterDirChangeTable, kTypeRawData, false },
{ kEobBaseMonsterDistAttStrings, kTypeStringList, true },
{ kEobBaseEncodeMonsterDefs, kLolTypeRaw16, false },
{ kEobBaseNpcPresets, kEobTypeNpcData, false },
{ kEob2Npc1Strings, kTypeStringList, true },
{ kEob2Npc2Strings, kTypeStringList, true },
{ kEob2MonsterDustStrings, kTypeStringList, true },
{ kEob2DranFoolsStrings, kTypeStringList, true },
{ kEob2HornStrings, kTypeStringList, true },
{ kEob2HornSounds, kTypeRawData, false },
// LANDS OF LORE
// Ingame
{ kLolIngamePakFiles, kTypeStringList, false },
{ kLolCharacterDefs, kLolTypeCharData, true },
{ kLolIngameSfxFiles, k2TypeSfxList, false },
{ kLolIngameSfxIndex, kTypeRawData, false },
{ kLolMusicTrackMap, kTypeRawData, false },
{ kLolIngameGMSfxIndex, kTypeRawData, false },
{ kLolIngameMT32SfxIndex, kTypeRawData, false },
{ kLolIngamePcSpkSfxIndex, kTypeRawData, false },
{ kLolSpellProperties, kLolTypeSpellData, false },
{ kLolGameShapeMap, kTypeRawData, false },
{ kLolSceneItemOffs, kTypeRawData, false },
{ kLolCharInvIndex, k3TypeRaw16to8, false },
{ kLolCharInvDefs, kTypeRawData, false },
{ kLolCharDefsMan, kLolTypeRaw16, false },
{ kLolCharDefsWoman, kLolTypeRaw16, false },
{ kLolCharDefsKieran, kLolTypeRaw16, false },
{ kLolCharDefsAkshel, kLolTypeRaw16, false },
{ kLolExpRequirements, kLolTypeRaw32, false },
{ kLolMonsterModifiers, kLolTypeRaw16, false },
{ kLolMonsterShiftOffsets, kTypeRawData, false },
{ kLolMonsterDirFlags, kTypeRawData, false },
{ kLolMonsterScaleY, kTypeRawData, false },
{ kLolMonsterScaleX, kTypeRawData, false },
{ kLolMonsterScaleWH, kLolTypeRaw16, false },
{ kLolFlyingObjectShp, kLolTypeFlightShpData, false },
{ kLolInventoryDesc, kLolTypeRaw16, false },
{ kLolLevelShpList, kTypeStringList, false },
{ kLolLevelDatList, kTypeStringList, false },
{ kLolCompassDefs, kLolTypeCompassData, false },
{ kLolItemPrices, kLolTypeRaw16, false },
{ kLolStashSetup, kTypeRawData, false },
{ kLolDscWalls, kTypeRawData, false },
{ kLolEobCommonDscShapeIndex, kTypeRawData, false },
{ kLolDscOvlMap, kTypeRawData, false },
{ kLolDscScaleWidthData, kLolTypeRaw16, false },
{ kLolDscScaleHeightData, kLolTypeRaw16, false },
{ kLolEobCommonDscX, kLolTypeRaw16, false },
{ kLolDscY, kTypeRawData, false },
{ kLolEobCommonDscTileIndex, kTypeRawData, false },
{ kLolEobCommonDscUnk2, kTypeRawData, false },
{ kLolEobCommonDscDoorShapeIndex, kTypeRawData, false },
{ kLolEobCommonDscDimData1, kTypeRawData, false },
{ kLolEobCommonDscDimData2, kTypeRawData, false },
{ kLolEobCommonDscBlockMap, kTypeRawData, false },
{ kLolEobCommonDscDimMap, kTypeRawData, false },
{ kLolDscDoorScale, kLolTypeRaw16, false },
{ kLolDscOvlIndex, k3TypeRaw16to8, false },
{ kLolEobCommonDscBlockIndex, kTypeRawData, false },
{ kLolDscDoor4, kLolTypeRaw16, false },
{ kLolEobCommonDscDoorY2, kTypeRawData, false },
{ kLolDscDoorX, kLolTypeRaw16, false },
{ kLolDscDoorY, kLolTypeRaw16, false },
{ kLolScrollXTop, k3TypeRaw16to8, false },
{ kLolScrollYTop, k3TypeRaw16to8, false },
{ kLolScrollXBottom, k3TypeRaw16to8, false },
{ kLolScrollYBottom, k3TypeRaw16to8, false },
{ kLolButtonDefs, kLolTypeButtonDef, false },
{ kLolButtonList1, kLolTypeRaw16, false },
{ kLolButtonList2, kLolTypeRaw16, false },
{ kLolButtonList3, kLolTypeRaw16, false },
{ kLolButtonList4, kLolTypeRaw16, false },
{ kLolButtonList5, kLolTypeRaw16, false },
{ kLolButtonList6, kLolTypeRaw16, false },
{ kLolButtonList7, kLolTypeRaw16, false },
{ kLolButtonList8, kLolTypeRaw16, false },
{ kLolLegendData, kTypeRawData, false },
{ kLolMapCursorOvl, kTypeRawData, false },
{ kLolMapStringId, kLolTypeRaw16, false },
{ kLolSpellbookAnim, k3TypeRaw16to8, false },
{ kLolSpellbookCoords, k3TypeRaw16to8, false },
{ kLolHealShapeFrames, kTypeRawData, false },
{ kLolLightningDefs, kTypeRawData, false },
{ kLolFireballCoords, kLolTypeRaw16, false },
{ kLolCredits, kTypeRawData, false },
{ kLolHistory, kTypeRawData, false },
{ -1, 0, 0 }
};
const ExtractFilename *getFilenameDesc(const int id) {
for (const ExtractFilename *i = extractFilenames; i->id != -1; ++i) {
if (i->id == id)
return i;
}
return 0;
}
bool isLangSpecific(const int id) {
const ExtractFilename *desc = getFilenameDesc(id);
if (!desc)
return false;
return desc->langSpecific;
}
// misc tables
const TypeTable gameTable[] = {
{ kKyra1, 0 },
{ kKyra2, 1 },
{ kKyra3, 2 },
{ kEob1, 3 },
{ kEob2, 4 },
{ kLol, 5 },
{ -1, -1 }
};
byte getGameID(int game) {
return std::find(gameTable, ARRAYEND(gameTable) - 1, game)->value;
}
const TypeTable languageTable[] = {
{ UNK_LANG, 0 },
{ EN_ANY, 1 },
{ FR_FRA, 2 },
{ DE_DEU, 3 },
{ ES_ESP, 4 },
{ IT_ITA, 5 },
{ JA_JPN, 6 },
{ RU_RUS, 7 },
{ -1, -1 }
};
byte getLanguageID(int lang) {
return std::find(languageTable, ARRAYEND(languageTable) - 1, lang)->value;
}
const TypeTable platformTable[] = {
{ kPlatformPC, 0 },
{ kPlatformAmiga, 1 },
{ kPlatformFMTowns, 2 },
{ kPlatformPC98, 3 },
{ kPlatformMacintosh, 4 },
{ -1, -1 }
};
byte getPlatformID(int platform) {
return std::find(platformTable, ARRAYEND(platformTable) - 1, platform)->value;
}
const TypeTable specialTable[] = {
{ kNoSpecial, 0 },
{ kTalkieVersion, 1 },
{ kDemoVersion, 2 },
{ kTalkieDemoVersion, 3 },
{ kOldFloppy, 4 },
{ -1, -1 }
};
byte getSpecialID(int special) {
return std::find(specialTable, ARRAYEND(specialTable) - 1, special)->value;
}
// filename processing
uint32 getFilename(const ExtractInformation *info, const int id) {
const ExtractFilename *fDesc = getFilenameDesc(id);
if (!fDesc)
return 0;
// GAME, PLATFORM, SPECIAL, ID, LANG
return ((getGameID(info->game) & 0xF) << 24) |
((getPlatformID(info->platform) & 0xF) << 20) |
((getSpecialID(info->special) & 0xF) << 16) |
((id & 0xFFF) << 4) |
((getLanguageID(fDesc->langSpecific ? info->lang : UNK_LANG) & 0xF) << 0);
}
// TODO: Get rid of this
bool getFilename(char *dstFilename, const ExtractInformation *info, const int id) {
sprintf(dstFilename, "%08X", getFilename(info, id));
return true;
}
// index generation
typedef uint16 GameDef;
GameDef createGameDef(const ExtractInformation *eI) {
return ((getGameID(eI->game) & 0xF) << 12) |
((getPlatformID(eI->platform) & 0xF) << 8) |
((getSpecialID(eI->special) & 0xF) << 4) |
((getLanguageID(eI->lang) & 0xF) << 0);
}
struct Index {
Index() : version(0), includedGames(0), gameList() {}
uint32 version;
uint32 includedGames;
typedef std::list<GameDef> GameList;
GameList gameList;
};
Index parseIndex(const uint8 *data, uint32 size) {
Index result;
if (size < 8)
return result;
result.version = READ_BE_UINT32(data); data += 4;
result.includedGames = READ_BE_UINT32(data); data += 4;
if (result.includedGames * 2 + 8 != size) {
result.version = result.includedGames = 0;
return result;
}
for (uint32 i = 0; i < result.includedGames; ++i) {
GameDef game = READ_BE_UINT16(data); data += 2;
result.gameList.push_back(game);
}
return result;
}
bool updateIndex(PAKFile &out, const ExtractInformation *eI) {
uint32 size = 0;
const uint8 *data = out.getFileData("INDEX", &size);
Index index;
if (data)
index = parseIndex(data, size);
GameDef gameDef = createGameDef(eI);
if (index.version == kKyraDatVersion) {
if (std::find(index.gameList.begin(), index.gameList.end(), gameDef) == index.gameList.end()) {
++index.includedGames;
index.gameList.push_back(gameDef);
} else {
// Already included in the game list, thus we do not need any further processing here.
return true;
}
} else {
index.version = kKyraDatVersion;
index.includedGames = 1;
index.gameList.push_back(gameDef);
}
const uint32 indexBufferSize = 8 + index.includedGames * 2;
uint8 *indexBuffer = new uint8[indexBufferSize];
assert(indexBuffer);
uint8 *dst = indexBuffer;
WRITE_BE_UINT32(dst, index.version); dst += 4;
WRITE_BE_UINT32(dst, index.includedGames); dst += 4;
for (Index::GameList::const_iterator i = index.gameList.begin(); i != index.gameList.end(); ++i) {
WRITE_BE_UINT16(dst, *i); dst += 2;
}
out.removeFile("INDEX");
if (!out.addFile("INDEX", indexBuffer, indexBufferSize)) {
fprintf(stderr, "ERROR: couldn't update kyra.dat INDEX\n");
delete[] indexBuffer;
return false;
}
return true;
}
bool checkIndex(PAKFile &file) {
uint32 size = 0;
const uint8 *data = file.getFileData("INDEX", &size);
if (!data)
return false;
Index index = parseIndex(data, size);
if (index.version != kKyraDatVersion)
return false;
if (index.includedGames * 2 + 8 != size)
return false;
return true;
}
// main processing
void printHelp(const char *f) {
printf("Usage:\n");
printf("%s output inputfiles ...\n", f);
}
bool process(PAKFile &out, const Game *g, const byte *data, const uint32 size);
const Game *findGame(const byte *buffer, const uint32 size);
typedef std::map<std::string, std::string> MD5Map;
MD5Map createMD5Sums(int files, const char * const *filenames);
struct File {
File() : data(0), size(0) {}
File(uint8 *d, uint32 s) : data(d), size(s) {}
uint8 *data;
uint32 size;
};
typedef std::map<const Game *, File> GameMap;
GameMap createGameMap(const MD5Map &map);
int main(int argc, char *argv[]) {
if (argc < 3) {
printHelp(argv[0]);
return -1;
}
// Special case for developer mode of this tool:
// With "--create filename offset size" the tool will output
// a search entry for the specifed data in the specified file.
if (!strcmp(argv[1], "--create")) {
if (argc < 5) {
printf("Developer usage: %s --create input_file hex_offset hex_size\n", argv[0]);
return -1;
}
uint32 offset, size;
sscanf(argv[3], "%x", &offset);
sscanf(argv[4], "%x", &size);
FILE *input = fopen(argv[2], "rb");
if (!input)
error("Couldn't open file '%s'", argv[2]);
byte *buffer = new byte[size];
fseek(input, offset, SEEK_SET);
if (fread(buffer, 1, size, input) != size) {
delete[] buffer;
error("Couldn't read from file '%s'", argv[2]);
}
fclose(input);
SearchData d = SearchCreator::create(buffer, size);
delete[] buffer;
printf("{ 0x%.08X, 0x%.08X, { {", d.size, d.byteSum);
for (int j = 0; j < 16; ++j) {
printf(" 0x%.2X", d.hash.digest[j]);
if (j != 15)
printf(",");
else
printf(" } } }\n");
}
return 0;
}
PAKFile out;
out.loadFile(argv[1], false);
// When the output file is no valid kyra.dat file, we will delete
// all the output.
if (!checkIndex(out))
out.clearFile();
MD5Map inputFiles = createMD5Sums(argc - 2, &argv[2]);
GameMap games = createGameMap(inputFiles);
// Check for unused input files
MD5Map unusedFiles = inputFiles;
for (GameMap::const_iterator i = games.begin(); i != games.end(); ++i) {
unusedFiles.erase(i->first->md5[0]);
if (i->first->md5[1])
unusedFiles.erase(i->first->md5[1]);
}
for (MD5Map::const_iterator i = unusedFiles.begin(); i != unusedFiles.end(); ++i)
printf("Input file '%s' with md5 sum '%s' is not known.\n", i->second.c_str(), i->first.c_str());
unusedFiles.clear();
// Short circuit, in case no games are found.
if (games.empty()) {
printf("No games found. Exiting prematurely\n");
return -1;
}
// Process all games found
for (GameMap::const_iterator i = games.begin(); i != games.end(); ++i) {
MD5Map::const_iterator f1 = inputFiles.find(i->first->md5[0]);
MD5Map::const_iterator f2 = inputFiles.end();
if (i->first->md5[1])
f2 = inputFiles.find(i->first->md5[1]);
if (f2 != inputFiles.end())
printf("Processing files '%s' and '%s'...\n", f1->second.c_str(), f2->second.c_str());
else
printf("Processing file '%s'...\n", f1->second.c_str());
if (!process(out, i->first, i->second.data, i->second.size))
printf("FAILED\n");
else
printf("OK\n");
}
// Free up memory
for (GameMap::iterator i = games.begin(); i != games.end(); ++i)
delete[] i->second.data;
games.clear();
inputFiles.clear();
if (!out.saveFile(argv[1]))
error("couldn't save changes to '%s'", argv[1]);
uint8 digest[16];
if (!md5_file(argv[1], digest, 0))
error("couldn't calc. md5 for file '%s'", argv[1]);
FILE *f = fopen(argv[1], "ab");
if (!f)
error("couldn't open file '%s'", argv[1]);
if (fwrite(digest, 1, 16, f) != 16)
error("couldn't write md5sum to file '%s'", argv[1]);
fclose(f);
return 0;
}
MD5Map createMD5Sums(int files, const char * const *filenames) {
MD5Map result;
while (files--) {
const char *inputFile = *filenames++;
FILE *input = fopen(inputFile, "rb");
uint32 size = fileSize(input);
fseek(input, 0, SEEK_SET);
byte *buffer = new uint8[size];
assert(buffer);
if (fread(buffer, 1, size, input) != size) {
warning("couldn't read from file '%s', skipping it", inputFile);
delete[] buffer;
fclose(input);
continue;
}
fclose(input);
md5_context ctx;
uint8 digest[16];
char md5Str[33];
md5_starts(&ctx);
md5_update(&ctx, buffer, size);
md5_finish(&ctx, digest);
for (int j = 0; j < 16; ++j)
sprintf(md5Str + j*2, "%02x", (int)digest[j]);
delete[] buffer;
result[md5Str] = inputFile;
}
return result;
}
GameMap createGameMap(const MD5Map &map) {
GameMap result;
for (const Game * const *g = gameDescs; *g != 0; ++g) {
for (const Game *sub = *g; sub->game != -1; ++sub) {
MD5Map::const_iterator file1 = map.find(sub->md5[0]);
if (file1 == map.end())
continue;
MD5Map::const_iterator file2 = map.end();
if (sub->md5[1] != 0) {
file2 = map.find(sub->md5[1]);
if (file2 == map.end())
continue;
}
FILE *f1 = fopen(file1->second.c_str(), "rb");
FILE *f2 = 0;
if (file2 != map.end())
f2 = fopen(file2->second.c_str(), "rb");
uint32 file1Size = fileSize(f1);
uint32 file2Size = 0;
if (f2)
file2Size = fileSize(f2);
uint8 *buffer = new uint8[file1Size + file2Size];
assert(buffer);
fread(buffer, 1, file1Size, f1);
if (f2)
fread(buffer + file1Size, 1, file2Size, f2);
fclose(f1);
if (f2)
fclose(f2);
result[sub] = File(buffer, file1Size + file2Size);
}
}
return result;
}
const char *getIdString(const int id) {
switch (id) {
case k1ForestSeq:
return "k1ForestSeq";
case k1KallakWritingSeq:
return "k1KallakWritingSeq";
case k1KyrandiaLogoSeq:
return "k1KyrandiaLogoSeq";
case k1KallakMalcolmSeq:
return "k1KallakMalcolmSeq";
case k1MalcolmTreeSeq:
return "k1MalcolmTreeSeq";
case k1WestwoodLogoSeq:
return "k1WestwoodLogoSeq";
case k1Demo1Seq:
return "k1Demo1Seq";
case k1Demo2Seq:
return "k1Demo2Seq";
case k1Demo3Seq:
return "k1Demo3Seq";
case k1Demo4Seq:
return "k1Demo4Seq";
case k1AmuleteAnimSeq:
return "k1AmuleteAnimSeq";
case k1OutroReunionSeq:
return "k1OutroReunionSeq";
case k1IntroCPSStrings:
return "k1IntroCPSStrings";
case k1IntroCOLStrings:
return "k1IntroCOLStrings";
case k1IntroWSAStrings:
return "k1IntroWSAStrings";
case k1IntroStrings:
return "k1IntroStrings";
case k1OutroHomeString:
return "k1OutroHomeString";
case k1RoomFilenames:
return "k1RoomFilenames";
case k1RoomList:
return "k1RoomList";
case k1CharacterImageFilenames:
return "k1CharacterImageFilenames";
case k1AudioTracks:
return "k1AudioTracks";
case k1AudioTracks2:
return "k1AudioTracks2";
case k1AudioTracksIntro:
return "k1AudioTracksIntro";
case k1ItemNames:
return "k1ItemNames";
case k1TakenStrings:
return "k1TakenStrings";
case k1PlacedStrings:
return "k1PlacedStrings";
case k1DroppedStrings:
return "k1DroppedStrings";
case k1NoDropStrings:
return "k1NoDropStrings";
case k1PutDownString:
return "k1PutDownString";
case k1WaitAmuletString:
return "k1WaitAmuletString";
case k1BlackJewelString:
return "k1BlackJewelString";
case k1PoisonGoneString:
return "k1PoisonGoneString";
case k1HealingTipString:
return "k1HealingTipString";
case k1WispJewelStrings:
return "k1WispJewelStrings";
case k1MagicJewelStrings:
return "k1MagicJewelStrings";
case k1ThePoisonStrings:
return "k1ThePoisonStrings";
case k1FluteStrings:
return "k1FluteStrings";
case k1FlaskFullString:
return "k1FlaskFullString";
case k1FullFlaskString:
return "k1FullFlaskString";
case k1VeryCleverString:
return "k1VeryCleverString";
case k1NewGameString:
return "k1NewGameString";
case k1DefaultShapes:
return "k1DefaultShapes";
case k1Healing1Shapes:
return "k1Healing1Shapes";
case k1Healing2Shapes:
return "k1Healing2Shapes";
case k1PoisonDeathShapes:
return "k1PoisonDeathShapes";
case k1FluteShapes:
return "k1FluteShapes";
case k1Winter1Shapes:
return "k1Winter1Shapes";
case k1Winter2Shapes:
return "k1Winter2Shapes";
case k1Winter3Shapes:
return "k1Winter3Shapes";
case k1DrinkShapes:
return "k1DrinkShapes";
case k1WispShapes:
return "k1WispShapes";
case k1MagicAnimShapes:
return "k1MagicAnimShapes";
case k1BranStoneShapes:
return "k1BranStoneShapes";
case k1SpecialPalette1:
return "k1SpecialPalette1";
case k1SpecialPalette2:
return "k1SpecialPalette2";
case k1SpecialPalette3:
return "k1SpecialPalette3";
case k1SpecialPalette4:
return "k1SpecialPalette4";
case k1SpecialPalette5:
return "k1SpecialPalette5";
case k1SpecialPalette6:
return "k1SpecialPalette6";
case k1SpecialPalette7:
return "k1SpecialPalette7";
case k1SpecialPalette8:
return "k1SpecialPalette8";
case k1SpecialPalette9:
return "k1SpecialPalette9";
case k1SpecialPalette10:
return "k1SpecialPalette10";
case k1SpecialPalette11:
return "k1SpecialPalette11";
case k1SpecialPalette12:
return "k1SpecialPalette12";
case k1SpecialPalette13:
return "k1SpecialPalette13";
case k1SpecialPalette14:
return "k1SpecialPalette14";
case k1SpecialPalette15:
return "k1SpecialPalette15";
case k1SpecialPalette16:
return "k1SpecialPalette16";
case k1SpecialPalette17:
return "k1SpecialPalette17";
case k1SpecialPalette18:
return "k1SpecialPalette18";
case k1SpecialPalette19:
return "k1SpecialPalette19";
case k1SpecialPalette20:
return "k1SpecialPalette20";
case k1SpecialPalette21:
return "k1SpecialPalette21";
case k1SpecialPalette22:
return "k1SpecialPalette22";
case k1SpecialPalette23:
return "k1SpecialPalette23";
case k1SpecialPalette24:
return "k1SpecialPalette24";
case k1SpecialPalette25:
return "k1SpecialPalette25";
case k1SpecialPalette26:
return "k1SpecialPalette26";
case k1SpecialPalette27:
return "k1SpecialPalette27";
case k1SpecialPalette28:
return "k1SpecialPalette28";
case k1SpecialPalette29:
return "k1SpecialPalette29";
case k1SpecialPalette30:
return "k1SpecialPalette30";
case k1SpecialPalette31:
return "k1SpecialPalette31";
case k1SpecialPalette32:
return "k1SpecialPalette32";
case k1SpecialPalette33:
return "k1SpecialPalette33";
case k1GUIStrings:
return "k1GUIStrings";
case k1ConfigStrings:
return "k1ConfigStrings";
case k1TownsMusicFadeTable:
return "k1TownsMusicFadeTable";
case k1TownsSFXwdTable:
return "k1TownsSFXwdTable";
case k1TownsSFXbtTable:
return "k1TownsSFXbtTable";
case k1TownsCDATable:
return "k1TownsCDATable";
case k1PC98StoryStrings:
return "k1PC98StoryStrings";
case k1PC98IntroSfx:
return "k1PC98IntroSfx";
case k1CreditsStrings:
return "k1CreditsStrings";
case k1AmigaIntroSFXTable:
return "k1AmigaIntroSFXTable";
case k1AmigaGameSFXTable:
return "k1AmigaGameSFXTable";
case k2SeqplayPakFiles:
return "k2SeqplayPakFiles";
case k2SeqplayStrings:
return "k2SeqplayStrings";
case k2SeqplaySfxFiles:
return "k2SeqplaySfxFiles";
case k2SeqplayTlkFiles:
return "k2SeqplayTlkFiles";
case k2SeqplaySeqData:
return "k2SeqplaySeqData";
case k2SeqplayCredits:
return "k2SeqplayCredits";
case k2SeqplayCreditsSpecial:
return "k2SeqplayCreditsSpecial";
case k2SeqplayIntroTracks:
return "k2SeqplayIntroTracks";
case k2SeqplayFinaleTracks:
return "k2SeqplayFinaleTracks";
case k2SeqplayIntroCDA:
return "k2SeqplayIntroCDA";
case k2SeqplayFinaleCDA:
return "k2SeqplayFinaleCDA";
case k2SeqplayShapeAnimData:
return "k2SeqplayShapeAnimData";
case k2IngamePakFiles:
return "k2IngamePakFiles";
case k2IngameSfxFiles:
return "k2IngameSfxFiles";
case k2IngameSfxIndex:
return "k2IngameSfxIndex";
case k2IngameTracks:
return "k2IngameTracks";
case k2IngameCDA:
return "k2IngameCDA";
case k2IngameTalkObjIndex:
return "k2IngameTalkObjIndex";
case k2IngameTimJpStrings:
return "k2IngameTimJpStrings";
case k2IngameShapeAnimData:
return "k2IngameShapeAnimData";
case k2IngameTlkDemoStrings:
return "k2IngameTlkDemoStrings";
case k3MainMenuStrings:
return "k3MainMenuStrings";
case k3MusicFiles:
return "k3MusicFiles";
case k3ScoreTable:
return "k3ScoreTable";
case k3SfxFiles:
return "k3SfxFiles";
case k3SfxMap:
return "k3SfxMap";
case k3ItemAnimData:
return "k3ItemAnimData";
case k3ItemMagicTable:
return "k3ItemMagicTable";
case k3ItemStringMap:
return "k3ItemStringMap";
case kEobBaseChargenStrings1:
return "kEobBaseChargenStrings1";
case kEobBaseChargenStrings2:
return "kEobBaseChargenStrings2";
case kEobBaseChargenStartLevels:
return "kEobBaseChargenStartLevels";
case kEobBaseChargenStatStrings:
return "kEobBaseChargenStatStrings";
case kEobBaseChargenRaceSexStrings:
return "kEobBaseChargenRaceSexStrings";
case kEobBaseChargenClassStrings:
return "kEobBaseChargenClassStrings";
case kEobBaseChargenAlignmentStrings:
return "kEobBaseChargenAlignmentStrings";
case kEobBaseChargenEnterGameStrings:
return "kEobBaseChargenEnterGameStrings";
case kEobBaseChargenClassMinStats:
return "kEobBaseChargenClassMinStats";
case kEobBaseChargenRaceMinStats:
return "kEobBaseChargenRaceMinStats";
case kEobBaseChargenRaceMaxStats:
return "kEobBaseChargenRaceMaxStats";
case kEobBaseConstModTable1:
return "kEobBaseConstModTable1";
case kEobBaseConstModTable2:
return "kEobBaseConstModTable2";
case kEobBaseConstModTable3:
return "kEobBaseConstModTable3";
case kEobBaseConstModTable4:
return "kEobBaseConstModTable4";
case kEobBaseConstModLvlIndex:
return "kEobBaseConstModLvlIndex";
case kEobBaseConstModDiv:
return "kEobBaseConstModDiv";
case kEobBaseConstModExt:
return "kEobBaseConstModExt";
case kEobBasePryDoorStrings:
return "kEobBasePryDoorStrings";
case kEobBaseWarningStrings:
return "kEobBaseWarningStrings";
case kEobBaseItemSuffixStringsRings:
return "kEobBaseItemSuffixStringsRings";
case kEobBaseItemSuffixStringsPotions:
return "kEobBaseItemSuffixStringsPotions";
case kEobBaseItemSuffixStringsWands:
return "kEobBaseItemSuffixStringsWands";
case kEobBaseRipItemStrings:
return "kEobBaseRipItemStrings";
case kEobBaseCursedString:
return "kEobBaseCursedString";
case kEobBaseEnchantedString:
return "kEobBaseEnchantedString";
case kEobBaseMagicObjectStrings:
return "kEobBaseMagicObjectStrings";
case kEobBaseMagicObject5String:
return "kEobBaseMagicObject5String";
case kEobBasePatternSuffix:
return "kEobBasePatternSuffix";
case kEobBasePatternGrFix1:
return "kEobBasePatternGrFix1";
case kEobBasePatternGrFix2:
return "kEobBasePatternGrFix2";
case kEobBaseValidateArmorString:
return "kEobBaseValidateArmorString";
case kEobBaseValidateCursedString:
return "kEobBaseValidateCursedString";
case kEobBaseValidateNoDropString:
return "kEobBaseValidateNoDropString";
case kEobBasePotionStrings:
return "kEobBasePotionStrings";
case kEobBaseWandString:
return "kEobBaseWandString";
case kEobBaseItemMisuseStrings:
return "kEobBaseItemMisuseStrings";
case kEobBaseTakenStrings:
return "kEobBaseTakenStrings";
case kEobBasePotionEffectStrings:
return "kEobBasePotionEffectStrings";
case kEobBaseYesNoStrings:
return "kEobBaseYesNoStrings";
case kLolEobCommonMoreStrings:
return "kLolEobCommonMoreStrings";
case kEobBaseNpcMaxStrings:
return "kEobBaseNpcMaxStrings";
case kEobBaseOkStrings:
return "kEobBaseOkStrings";
case kEobBaseNpcJoinStrings:
return "kEobBaseNpcJoinStrings";
case kEobBaseCancelStrings:
return "kEobBaseCancelStrings";
case kEobBaseAbortStrings:
return "kEobBaseAbortStrings";
case kEobBaseMenuStringsMain:
return "kEobBaseMenuStringsMain";
case kEobBaseMenuStringsSaveLoad:
return "kEobBaseMenuStringsSaveLoad";
case kEobBaseMenuStringsOnOff:
return "kEobBaseMenuStringsOnOff";
case kEobBaseMenuStringsSpells:
return "kEobBaseMenuStringsSpells";
case kEobBaseMenuStringsRest:
return "kEobBaseMenuStringsRest";
case kEobBaseMenuStringsDrop:
return "kEobBaseMenuStringsDrop";
case kEobBaseMenuStringsExit:
return "kEobBaseMenuStringsExit";
case kEobBaseMenuStringsStarve:
return "kEobBaseMenuStringsStarve";
case kEobBaseMenuStringsScribe:
return "kEobBaseMenuStringsScribe";
case kEobBaseMenuStringsDrop2:
return "kEobBaseMenuStringsDrop2";
case kEobBaseMenuStringsHead:
return "kEobBaseMenuStringsHead";
case kEobBaseMenuStringsPoison:
return "kEobBaseMenuStringsPoison";
case kEobBaseMenuStringsMgc:
return "kEobBaseMenuStringsMgc";
case kEobBaseMenuStringsPrefs:
return "kEobBaseMenuStringsPrefs";
case kEobBaseMenuStringsRest2:
return "kEobBaseMenuStringsRest2";
case kEobBaseMenuStringsRest3:
return "kEobBaseMenuStringsRest3";
case kEobBaseMenuStringsRest4:
return "kEobBaseMenuStringsRest4";
case kEobBaseMenuStringsDefeat:
return "kEobBaseMenuStringsDefeat";
case kEobBaseMenuStringsTransfer:
return "kEobBaseMenuStringsTransfer";
case kEobBaseMenuStringsSpec:
return "kEobBaseMenuStringsSpec";
case kEobBaseMenuStringsSpellNo:
return "kEobBaseMenuStringsSpellNo";
case kEobBaseMenuYesNoStrings:
return "kEobBaseMenuYesNoStrings";
case kEobBaseSpellLevelsMage:
return "kEobBaseSpellLevelsMage";
case kEobBaseSpellLevelsCleric:
return "kEobBaseSpellLevelsCleric";
case kEobBaseNumSpellsCleric:
return "kEobBaseNumSpellsCleric";
case kEobBaseNumSpellsWisAdj:
return "kEobBaseNumSpellsWisAdj";
case kEobBaseNumSpellsPal:
return "kEobBaseNumSpellsPal";
case kEobBaseNumSpellsMage:
return "kEobBaseNumSpellsMage";
case kEobBaseCharGuiStringsHp:
return "kEobBaseCharGuiStringsHp";
case kEobBaseCharGuiStringsWp1:
return "kEobBaseCharGuiStringsWp1";
case kEobBaseCharGuiStringsWp2:
return "kEobBaseCharGuiStringsWp2";
case kEobBaseCharGuiStringsWr:
return "kEobBaseCharGuiStringsWr";
case kEobBaseCharGuiStringsSt1:
return "kEobBaseCharGuiStringsSt1";
case kEobBaseCharGuiStringsSt2:
return "kEobBaseCharGuiStringsSt2";
case kEobBaseCharGuiStringsIn:
return "kEobBaseCharGuiStringsIn";
case kEobBaseCharStatusStrings7:
return "kEobBaseCharStatusStrings7";
case kEobBaseCharStatusStrings81:
return "kEobBaseCharStatusStrings81";
case kEobBaseCharStatusStrings82:
return "kEobBaseCharStatusStrings82";
case kEobBaseCharStatusStrings9:
return "kEobBaseCharStatusStrings9";
case kEobBaseCharStatusStrings12:
return "kEobBaseCharStatusStrings12";
case kEobBaseCharStatusStrings131:
return "kEobBaseCharStatusStrings131";
case kEobBaseCharStatusStrings132:
return "kEobBaseCharStatusStrings132";
case kEobBaseLevelGainStrings:
return "kEobBaseLevelGainStrings";
case kEobBaseExperienceTable0:
return "kEobBaseExperienceTable0";
case kEobBaseExperienceTable1:
return "kEobBaseExperienceTable1";
case kEobBaseExperienceTable2:
return "kEobBaseExperienceTable2";
case kEobBaseExperienceTable3:
return "kEobBaseExperienceTable3";
case kEobBaseExperienceTable4:
return "kEobBaseExperienceTable4";
case kEobBaseWllFlagPreset:
return "kEobBaseWllFlagPreset";
case kEobBaseDscShapeCoords:
return "kEobBaseDscShapeCoords";
case kEobBaseDscDoorScaleOffs:
return "kEobBaseDscDoorScaleOffs";
case kEobBaseDscDoorScaleMult1:
return "kEobBaseDscDoorScaleMult1";
case kEobBaseDscDoorScaleMult2:
return "kEobBaseDscDoorScaleMult2";
case kEobBaseDscDoorScaleMult3:
return "kEobBaseDscDoorScaleMult3";
case kEobBaseDscDoorScaleMult4:
return "kEobBaseDscDoorScaleMult4";
case kEobBaseDscDoorScaleMult5:
return "kEobBaseDscDoorScaleMult5";
case kEobBaseDscDoorScaleMult6:
return "kEobBaseDscDoorScaleMult6";
case kEobBaseDscDoorType5Offs:
return "kEobBaseDscDoorType5Offs";
case kEobBaseDscDoorY1:
return "kEobBaseDscDoorY1";
case kEobBaseDscDoorY3:
return "kEobBaseDscDoorY3";
case kEobBaseDscDoorY4:
return "kEobBaseDscDoorY4";
case kEobBaseDscDoorY5:
return "kEobBaseDscDoorY5";
case kEobBaseDscDoorY6:
return "kEobBaseDscDoorY6";
case kEobBaseDscDoorCoordsExt:
return "kEobBaseDscDoorCoordsExt";
case kEobBaseDscItemPosIndex:
return "kEobBaseDscItemPosIndex";
case kEobBaseDscItemShpX:
return "kEobBaseDscItemShpX";
case kEobBaseDscItemPosUnk:
return "kEobBaseDscItemPosUnk";
case kEobBaseDscItemTileIndex:
return "kEobBaseDscItemTileIndex";
case kEobBaseDscItemShapeMap:
return "kEobBaseDscItemShapeMap";
case kEobBaseDscMonsterFrmOffsTbl1:
return "kEobBaseDscMonsterFrmOffsTbl1";
case kEobBaseDscMonsterFrmOffsTbl2:
return "kEobBaseDscMonsterFrmOffsTbl2";
case kEobBaseInvSlotX:
return "kEobBaseInvSlotX";
case kEobBaseInvSlotY:
return "kEobBaseInvSlotY";
case kEobBaseSlotValidationFlags:
return "kEobBaseSlotValidationFlags";
case kEobBaseProjectileWeaponTypes:
return "kEobBaseProjectileWeaponTypes";
case kEobBaseWandTypes:
return "kEobBaseWandTypes";
case kEobBaseDrawObjPosIndex:
return "kEobBaseDrawObjPosIndex";
case kEobBaseFlightObjFlipIndex:
return "kEobBaseFlightObjFlipIndex";
case kEobBaseFlightObjShpMap:
return "kEobBaseFlightObjShpMap";
case kEobBaseFlightObjSclIndex:
return "kEobBaseFlightObjSclIndex";
case kEobBaseDscTelptrShpCoords:
return "kEobBaseDscTelptrShpCoords";
case kEobBasePortalSeqData:
return "kEobBasePortalSeqData";
case kEobBaseManDef:
return "kEobBaseManDef";
case kEobBaseManWord:
return "kEobBaseManWord";
case kEobBaseManPrompt:
return "kEobBaseManPrompt";
case kEobBaseBookNumbers:
return "kEobBaseBookNumbers";
case kEobBaseMageSpellsList:
return "kEobBaseMageSpellsList";
case kEobBaseClericSpellsList:
return "kEobBaseClericSpellsList";
case kEobBaseSpellNames:
return "kEobBaseSpellNames";
case kEobBaseMagicStrings1:
return "kEobBaseMagicStrings1";
case kEobBaseMagicStrings2:
return "kEobBaseMagicStrings2";
case kEobBaseMagicStrings3:
return "kEobBaseMagicStrings3";
case kEobBaseMagicStrings4:
return "kEobBaseMagicStrings4";
case kEobBaseMagicStrings6:
return "kEobBaseMagicStrings6";
case kEobBaseMagicStrings7:
return "kEobBaseMagicStrings7";
case kEobBaseMagicStrings8:
return "kEobBaseMagicStrings8";
case kEobBaseExpObjectTlMode:
return "kEobBaseExpObjectTlMode";
case kEobBaseExpObjectTblIndex:
return "kEobBaseExpObjectTblIndex";
case kEobBaseExpObjectShpStart:
return "kEobBaseExpObjectShpStart";
case kEobBaseExpObjectTbl1:
return "kEobBaseExpObjectTbl1";
case kEobBaseExpObjectTbl2:
return "kEobBaseExpObjectTbl2";
case kEobBaseExpObjectTbl3:
return "kEobBaseExpObjectTbl3";
case kEobBaseExpObjectY:
return "kEobBaseExpObjectY";
case kEobBaseSparkDefSteps:
return "kEobBaseSparkDefSteps";
case kEobBaseSparkDefSubSteps:
return "kEobBaseSparkDefSubSteps";
case kEobBaseSparkDefShift:
return "kEobBaseSparkDefShift";
case kEobBaseSparkDefAdd:
return "kEobBaseSparkDefAdd";
case kEobBaseSparkDefX:
return "kEobBaseSparkDefX";
case kEobBaseSparkDefY:
return "kEobBaseSparkDefY";
case kEobBaseSparkOfFlags1:
return "kEobBaseSparkOfFlags1";
case kEobBaseSparkOfFlags2:
return "kEobBaseSparkOfFlags2";
case kEobBaseSparkOfShift:
return "kEobBaseSparkOfShift";
case kEobBaseSparkOfX:
return "kEobBaseSparkOfX";
case kEobBaseSparkOfY:
return "kEobBaseSparkOfY";
case kEobBaseSpellProperties:
return "kEobBaseSpellProperties";
case kEobBaseMagicFlightProps:
return "kEobBaseMagicFlightProps";
case kEobBaseTurnUndeadEffect:
return "kEobBaseTurnUndeadEffect";
case kEob1MainMenuStrings:
return "kEob1MainMenuStrings";
case kEob1DoorShapeDefs:
return "kEob1DoorShapeDefs";
case kEob1DoorSwitchCoords:
return "kEob1DoorSwitchCoords";
case kEob1MonsterProperties:
return "kEob1MonsterProperties";
case kEob1MonsterDistAttType10:
return "kEob1MonsterDistAttType10";
case kEob1MonsterDistAttSfx10:
return "kEob1MonsterDistAttSfx10";
case kEob1MonsterDistAttType17:
return "kEob1MonsterDistAttType17";
case kEob1MonsterDistAttSfx17:
return "kEob1MonsterDistAttSfx17";
case kEob1TurnUndeadString:
return "kEob1TurnUndeadString";
case kEob1NpcShpData:
return "kEob1NpcShpData";
case kEob1NpcSubShpIndex1:
return "kEob1NpcSubShpIndex1";
case kEob1NpcSubShpIndex2:
return "kEob1NpcSubShpIndex2";
case kEob1NpcSubShpY:
return "kEob1NpcSubShpY";
case kEob1Npc0Strings:
return "kEob1Npc0Strings";
case kEob1Npc11Strings:
return "kEob1Npc11Strings";
case kEob1Npc12Strings:
return "kEob1Npc12Strings";
case kEob1Npc21Strings:
return "kEob1Npc21Strings";
case kEob1Npc22Strings:
return "kEob1Npc22Strings";
case kEob1Npc31Strings:
return "kEob1Npc31Strings";
case kEob1Npc32Strings:
return "kEob1Npc32Strings";
case kEob1Npc4Strings:
return "kEob1Npc4Strings";
case kEob1Npc5Strings:
return "kEob1Npc5Strings";
case kEob1Npc6Strings:
return "kEob1Npc6Strings";
case kEob1Npc7Strings:
return "kEob1Npc7Strings";
case kEob2MainMenuStrings:
return "kEob2MainMenuStrings";
case kEob2IntroStrings:
return "kEob2IntroStrings";
case kEob2IntroCPSFiles:
return "kEob2IntroCPSFiles";
case kEob2IntroSeqData00:
return "kEob2IntroSeqData00";
case kEob2IntroSeqData01:
return "kEob2IntroSeqData01";
case kEob2IntroSeqData02:
return "kEob2IntroSeqData02";
case kEob2IntroSeqData03:
return "kEob2IntroSeqData03";
case kEob2IntroSeqData04:
return "kEob2IntroSeqData04";
case kEob2IntroSeqData05:
return "kEob2IntroSeqData05";
case kEob2IntroSeqData06:
return "kEob2IntroSeqData06";
case kEob2IntroSeqData07:
return "kEob2IntroSeqData07";
case kEob2IntroSeqData08:
return "kEob2IntroSeqData08";
case kEob2IntroSeqData09:
return "kEob2IntroSeqData09";
case kEob2IntroSeqData10:
return "kEob2IntroSeqData10";
case kEob2IntroSeqData11:
return "kEob2IntroSeqData11";
case kEob2IntroSeqData12:
return "kEob2IntroSeqData12";
case kEob2IntroSeqData13:
return "kEob2IntroSeqData13";
case kEob2IntroSeqData14:
return "kEob2IntroSeqData14";
case kEob2IntroSeqData15:
return "kEob2IntroSeqData15";
case kEob2IntroSeqData16:
return "kEob2IntroSeqData16";
case kEob2IntroSeqData17:
return "kEob2IntroSeqData17";
case kEob2IntroSeqData18:
return "kEob2IntroSeqData18";
case kEob2IntroSeqData19:
return "kEob2IntroSeqData19";
case kEob2IntroSeqData20:
return "kEob2IntroSeqData20";
case kEob2IntroSeqData21:
return "kEob2IntroSeqData21";
case kEob2IntroSeqData22:
return "kEob2IntroSeqData22";
case kEob2IntroSeqData23:
return "kEob2IntroSeqData23";
case kEob2IntroSeqData24:
return "kEob2IntroSeqData24";
case kEob2IntroSeqData25:
return "kEob2IntroSeqData25";
case kEob2IntroSeqData26:
return "kEob2IntroSeqData26";
case kEob2IntroSeqData27:
return "kEob2IntroSeqData27";
case kEob2IntroSeqData28:
return "kEob2IntroSeqData28";
case kEob2IntroSeqData29:
return "kEob2IntroSeqData29";
case kEob2IntroSeqData30:
return "kEob2IntroSeqData30";
case kEob2IntroSeqData31:
return "kEob2IntroSeqData31";
case kEob2IntroSeqData32:
return "kEob2IntroSeqData32";
case kEob2IntroSeqData33:
return "kEob2IntroSeqData33";
case kEob2IntroSeqData34:
return "kEob2IntroSeqData34";
case kEob2IntroSeqData35:
return "kEob2IntroSeqData35";
case kEob2IntroSeqData36:
return "kEob2IntroSeqData36";
case kEob2IntroSeqData37:
return "kEob2IntroSeqData37";
case kEob2IntroSeqData38:
return "kEob2IntroSeqData38";
case kEob2IntroSeqData39:
return "kEob2IntroSeqData39";
case kEob2IntroSeqData40:
return "kEob2IntroSeqData40";
case kEob2IntroSeqData41:
return "kEob2IntroSeqData41";
case kEob2IntroSeqData42:
return "kEob2IntroSeqData42";
case kEob2IntroSeqData43:
return "kEob2IntroSeqData43";
case kEob2IntroShapes00:
return "kEob2IntroShapes00";
case kEob2IntroShapes01:
return "kEob2IntroShapes01";
case kEob2IntroShapes04:
return "kEob2IntroShapes04";
case kEob2IntroShapes07:
return "kEob2IntroShapes07";
case kEob2FinaleStrings:
return "kEob2FinaleStrings";
case kEob2CreditsData:
return "kEob2CreditsData";
case kEob2FinaleCPSFiles:
return "kEob2FinaleCPSFiles";
case kEob2FinaleSeqData00:
return "kEob2FinaleSeqData00";
case kEob2FinaleSeqData01:
return "kEob2FinaleSeqData01";
case kEob2FinaleSeqData02:
return "kEob2FinaleSeqData02";
case kEob2FinaleSeqData03:
return "kEob2FinaleSeqData03";
case kEob2FinaleSeqData04:
return "kEob2FinaleSeqData04";
case kEob2FinaleSeqData05:
return "kEob2FinaleSeqData05";
case kEob2FinaleSeqData06:
return "kEob2FinaleSeqData06";
case kEob2FinaleSeqData07:
return "kEob2FinaleSeqData07";
case kEob2FinaleSeqData08:
return "kEob2FinaleSeqData08";
case kEob2FinaleSeqData09:
return "kEob2FinaleSeqData09";
case kEob2FinaleSeqData10:
return "kEob2FinaleSeqData10";
case kEob2FinaleSeqData11:
return "kEob2FinaleSeqData11";
case kEob2FinaleSeqData12:
return "kEob2FinaleSeqData12";
case kEob2FinaleSeqData13:
return "kEob2FinaleSeqData13";
case kEob2FinaleSeqData14:
return "kEob2FinaleSeqData14";
case kEob2FinaleSeqData15:
return "kEob2FinaleSeqData15";
case kEob2FinaleSeqData16:
return "kEob2FinaleSeqData16";
case kEob2FinaleSeqData17:
return "kEob2FinaleSeqData17";
case kEob2FinaleSeqData18:
return "kEob2FinaleSeqData18";
case kEob2FinaleSeqData19:
return "kEob2FinaleSeqData19";
case kEob2FinaleSeqData20:
return "kEob2FinaleSeqData20";
case kEob2FinaleShapes00:
return "kEob2FinaleShapes00";
case kEob2FinaleShapes03:
return "kEob2FinaleShapes03";
case kEob2FinaleShapes07:
return "kEob2FinaleShapes07";
case kEob2FinaleShapes09:
return "kEob2FinaleShapes09";
case kEob2FinaleShapes10:
return "kEob2FinaleShapes10";
case kEob2NpcShapeData:
return "kEob2NpcShapeData";
case kEobBaseClassModifierFlags:
return "kEobBaseClassModifierFlags";
case kEobBaseMonsterStepTable01:
return "kEobBaseMonsterStepTable01";
case kEobBaseMonsterStepTable02:
return "kEobBaseMonsterStepTable02";
case kEobBaseMonsterStepTable1:
return "kEobBaseMonsterStepTable1";
case kEobBaseMonsterStepTable2:
return "kEobBaseMonsterStepTable2";
case kEobBaseMonsterStepTable3:
return "kEobBaseMonsterStepTable3";
case kEobBaseMonsterCloseAttPosTable1:
return "kEobBaseMonsterCloseAttPosTable1";
case kEobBaseMonsterCloseAttPosTable21:
return "kEobBaseMonsterCloseAttPosTable21";
case kEobBaseMonsterCloseAttPosTable22:
return "kEobBaseMonsterCloseAttPosTable22";
case kEobBaseMonsterCloseAttUnkTable:
return "kEobBaseMonsterCloseAttUnkTable";
case kEobBaseMonsterCloseAttChkTable1:
return "kEobBaseMonsterCloseAttChkTable1";
case kEobBaseMonsterCloseAttChkTable2:
return "kEobBaseMonsterCloseAttChkTable2";
case kEobBaseMonsterCloseAttDstTable1:
return "kEobBaseMonsterCloseAttDstTable1";
case kEobBaseMonsterCloseAttDstTable2:
return "kEobBaseMonsterCloseAttDstTable2";
case kEobBaseMonsterProximityTable:
return "kEobBaseMonsterProximityTable";
case kEobBaseFindBlockMonstersTable:
return "kEobBaseFindBlockMonstersTable";
case kEobBaseMonsterDirChangeTable:
return "kEobBaseMonsterDirChangeTable";
case kEobBaseMonsterDistAttStrings:
return "kEobBaseMonsterDistAttStrings";
case kEobBaseEncodeMonsterDefs:
return "kEobBaseEncodeMonsterDefs";
case kEobBaseNpcPresets:
return "kEobBaseNpcPresets";
case kEob2Npc1Strings:
return "kEob2Npc1Strings";
case kEob2Npc2Strings:
return "kEob2Npc2Strings";
case kEob2MonsterDustStrings:
return "kEob2MonsterDustStrings";
case kEob2DranFoolsStrings:
return "kEob2DranFoolsStrings";
case kEob2HornStrings:
return "kEob2HornStrings";
case kEob2HornSounds:
return "kEob2HornSounds";
case kLolIngamePakFiles:
return "kLolIngamePakFiles";
case kLolCharacterDefs:
return "kLolCharacterDefs";
case kLolIngameSfxFiles:
return "kLolIngameSfxFiles";
case kLolIngameSfxIndex:
return "kLolIngameSfxIndex";
case kLolMusicTrackMap:
return "kLolMusicTrackMap";
case kLolIngameGMSfxIndex:
return "kLolIngameGMSfxIndex";
case kLolIngameMT32SfxIndex:
return "kLolIngameMT32SfxIndex";
case kLolIngamePcSpkSfxIndex:
return "kLolIngamePcSpkSfxIndex";
case kLolSpellProperties:
return "kLolSpellProperties";
case kLolGameShapeMap:
return "kLolGameShapeMap";
case kLolSceneItemOffs:
return "kLolSceneItemOffs";
case kLolCharInvIndex:
return "kLolCharInvIndex";
case kLolCharInvDefs:
return "kLolCharInvDefs";
case kLolCharDefsMan:
return "kLolCharDefsMan";
case kLolCharDefsWoman:
return "kLolCharDefsWoman";
case kLolCharDefsKieran:
return "kLolCharDefsKieran";
case kLolCharDefsAkshel:
return "kLolCharDefsAkshel";
case kLolExpRequirements:
return "kLolExpRequirements";
case kLolMonsterModifiers:
return "kLolMonsterModifiers";
case kLolMonsterShiftOffsets:
return "kLolMonsterShiftOffsets";
case kLolMonsterDirFlags:
return "kLolMonsterDirFlags";
case kLolMonsterScaleY:
return "kLolMonsterScaleY";
case kLolMonsterScaleX:
return "kLolMonsterScaleX";
case kLolMonsterScaleWH:
return "kLolMonsterScaleWH";
case kLolFlyingObjectShp:
return "kLolFlyingObjectShp";
case kLolInventoryDesc:
return "kLolInventoryDesc";
case kLolLevelShpList:
return "kLolLevelShpList";
case kLolLevelDatList:
return "kLolLevelDatList";
case kLolCompassDefs:
return "kLolCompassDefs";
case kLolItemPrices:
return "kLolItemPrices";
case kLolStashSetup:
return "kLolStashSetup";
case kLolDscWalls:
return "kLolDscWalls";
case kLolEobCommonDscShapeIndex:
return "kLolEobCommonDscShapeIndex";
case kLolDscOvlMap:
return "kLolDscOvlMap";
case kLolDscScaleWidthData:
return "kLolDscScaleWidthData";
case kLolDscScaleHeightData:
return "kLolDscScaleHeightData";
case kLolEobCommonDscX:
return "kLolEobCommonDscX";
case kLolDscY:
return "kLolDscY";
case kLolEobCommonDscTileIndex:
return "kLolEobCommonDscTileIndex";
case kLolEobCommonDscUnk2:
return "kLolEobCommonDscUnk2";
case kLolEobCommonDscDoorShapeIndex:
return "kLolEobCommonDscDoorShapeIndex";
case kLolEobCommonDscDimData1:
return "kLolEobCommonDscDimData1";
case kLolEobCommonDscDimData2:
return "kLolEobCommonDscDimData2";
case kLolEobCommonDscBlockMap:
return "kLolEobCommonDscBlockMap";
case kLolEobCommonDscDimMap:
return "kLolEobCommonDscDimMap";
case kLolDscOvlIndex:
return "kLolDscOvlIndex";
case kLolEobCommonDscBlockIndex:
return "kLolEobCommonDscBlockIndex";
case kLolEobCommonDscDoorY2:
return "kLolEobCommonDscDoorY2";
case kLolDscDoorScale:
return "kLolDscDoorScale";
case kLolDscDoor4:
return "kLolDscDoor4";
case kLolDscDoorX:
return "kLolDscDoorX";
case kLolDscDoorY:
return "kLolDscDoorY";
case kLolScrollXTop:
return "kLolScrollXTop";
case kLolScrollYTop:
return "kLolScrollYTop";
case kLolScrollXBottom:
return "kLolScrollXBottom";
case kLolScrollYBottom:
return "kLolScrollYBottom";
case kLolButtonDefs:
return "kLolButtonDefs";
case kLolButtonList1:
return "kLolButtonList1";
case kLolButtonList2:
return "kLolButtonList2";
case kLolButtonList3:
return "kLolButtonList3";
case kLolButtonList4:
return "kLolButtonList4";
case kLolButtonList5:
return "kLolButtonList5";
case kLolButtonList6:
return "kLolButtonList6";
case kLolButtonList7:
return "kLolButtonList7";
case kLolButtonList8:
return "kLolButtonList8";
case kLolLegendData:
return "kLolLegendData";
case kLolMapCursorOvl:
return "kLolMapCursorOvl";
case kLolMapStringId:
return "kLolMapStringId";
case kLolSpellbookAnim:
return "kLolSpellbookAnim";
case kLolSpellbookCoords:
return "kLolSpellbookCoords";
case kLolHealShapeFrames:
return "kLolHealShapeFrames";
case kLolLightningDefs:
return "kLolLightningDefs";
case kLolFireballCoords:
return "kLolFireballCoords";
case kLolHistory:
return "kLolHistory";
default:
return "Unknown";
}
}
struct ExtractData {
ExtractData() : desc(), offset() {}
ExtractData(ExtractEntrySearchData d, uint32 o) : desc(d), offset(o) {}
ExtractEntrySearchData desc;
uint32 offset;
};
typedef std::pair<int, ExtractEntrySearchData> SearchMapEntry;
typedef std::multimap<int, ExtractEntrySearchData> SearchMap;
typedef std::pair<int, ExtractData> ExtractMapEntry;
typedef std::multimap<int, ExtractData> ExtractMap;
bool getExtractionData(const Game *g, Search &search, ExtractMap &map);
bool createIDMap(PAKFile &out, const ExtractInformation *eI, const int *needList);
bool process(PAKFile &out, const Game *g, const byte *data, const uint32 size) {
char filename[128];
Search search(data, size);
ExtractMap ids;
if (!getExtractionData(g, search, ids))
return false;
const int *needList = getNeedList(g);
if (!needList) {
fprintf(stderr, "ERROR: No entry need list available\n");
return false;
}
ExtractInformation extractInfo;
extractInfo.game = g->game;
extractInfo.platform = g->platform;
extractInfo.special = g->special;
for (ExtractMap::const_iterator i = ids.begin(); i != ids.end(); ++i) {
const int id = i->first;
extractInfo.lang = i->second.desc.lang;
const ExtractFilename *fDesc = getFilenameDesc(id);
if (!fDesc) {
fprintf(stderr, "ERROR: couldn't find file description for id %d/%s\n", id, getIdString(id));
return false;
}
filename[0] = 0;
if (!getFilename(filename, &extractInfo, id)) {
fprintf(stderr, "ERROR: couldn't get filename for id %d/%s\n", id, getIdString(id));
return false;
}
const ExtractType *tDesc = findExtractType(fDesc->type);
if (!tDesc) {
fprintf(stderr, "ERROR: couldn't find type description for id %d/%s (%d)\n", id, getIdString(id), fDesc->type);
return false;
}
PAKFile::cFileList *list = out.getFileList();
if (list && list->findEntry(filename) != 0)
continue;
if (!tDesc->extract(out, &extractInfo, data + i->second.offset, i->second.desc.hint.size, filename, id)) {
fprintf(stderr, "ERROR: couldn't extract id %d/%s\n", id, getIdString(id));
return false;
}
}
for (int i = 0; i < 3; ++i) {
if (g->lang[i] == -1)
continue;
extractInfo.lang = g->lang[i];
if (!createIDMap(out, &extractInfo, needList))
return false;
if (!updateIndex(out, &extractInfo)) {
error("couldn't update INDEX file, stop processing of all files");
return false;
}
}
return true;
}
bool createIDMap(PAKFile &out, const ExtractInformation *eI, const int *needList) {
int dataEntries = 0;
// Count entries in the need list
for (const int *n = needList; *n != -1; ++n)
++dataEntries;
const int mapSize = 2 + dataEntries * (2 + 1 + 4);
uint8 *map = new uint8[mapSize];
uint8 *dst = map;
WRITE_BE_UINT16(dst, dataEntries); dst += 2;
for (const int *id = needList; *id != -1; ++id) {
WRITE_BE_UINT16(dst, *id); dst += 2;
const ExtractFilename *fDesc = getFilenameDesc(*id);
if (!fDesc)
return false;
*dst++ = getTypeID(fDesc->type);
WRITE_BE_UINT32(dst, getFilename(eI, *id)); dst += 4;
}
char filename[12];
if (!getFilename(filename, eI, 0)) {
fprintf(stderr, "ERROR: Could not create ID map for game\n");
return false;
}
out.removeFile(filename);
if (!out.addFile(filename, map, mapSize)) {
fprintf(stderr, "ERROR: Could not add ID map \"%s\" to kyra.dat\n", filename);
return false;
}
return true;
}
// Uncomment this to get various debug information about the detection table entries.
//#define DEBUG_EXTRACTION_TABLES
bool setupSearch(const Game *g, const int *needList, Search &search, SearchMap &searchData) {
for (const int *entry = needList; *entry != -1; ++entry) {
ExtractEntryList providers = getProvidersForId(*entry);
if (providers.empty()) {
fprintf(stderr, "ERROR: No provider for id %d/%s\n", *entry, getIdString(*entry));
return false;
} else {
for (ExtractEntryList::const_iterator i = providers.begin(); i != providers.end(); ++i) {
// Only add generic or partly matching providers here.
#ifndef DEBUG_EXTRACTION_TABLES
if ((i->lang == UNK_LANG || i->lang == g->lang[0] || i->lang == g->lang[1] || i->lang == g->lang[2]) &&
(i->platform == kPlatformUnknown || (i->platform == g->platform))) {
#endif
search.addData(i->hint);
searchData.insert(SearchMapEntry(*entry, *i));
#ifndef DEBUG_EXTRACTION_TABLES
}
#endif
}
}
}
return true;
}
typedef std::list<ExtractMap::const_iterator> MatchList;
MatchList filterPlatformMatches(const Game *g, std::pair<ExtractMap::const_iterator, ExtractMap::const_iterator> range) {
bool hasPlatformMatch = false;
for (ExtractMap::const_iterator i = range.first; i != range.second; ++i) {
if (i->second.desc.platform == g->platform) {
hasPlatformMatch = true;
break;
}
}
MatchList result;
if (hasPlatformMatch) {
for (ExtractMap::const_iterator i = range.first; i != range.second; ++i) {
if (i->second.desc.platform == g->platform)
result.push_back(i);
}
} else {
for (ExtractMap::const_iterator i = range.first; i != range.second; ++i)
result.push_back(i);
}
return result;
}
MatchList filterLanguageMatches(const int lang, const MatchList &input) {
std::list<ExtractMap::const_iterator> result;
for (MatchList::const_iterator i = input.begin(); i != input.end(); ++i) {
if ((*i)->second.desc.lang == lang)
result.push_back(*i);
}
return result;
}
MatchList::const_iterator filterOutBestMatch(const MatchList &input) {
MatchList::const_iterator result = input.begin();
if (input.size() > 1)
warning("Multiple entries found for id %d/%s", (*result)->first, getIdString((*result)->first));
for (MatchList::const_iterator i = input.begin(); i != input.end(); ++i) {
// Reduce all entries to one single entry.
//
// We use the following rules for this (in this order):
// - Prefer the entry with the higest size
// - Prefer the entry, which starts at the smallest offest
//
// TODO: These rules might not be safe for all games, but hopefully
// they will work fine. If there are any problems it should be rather
// easy to identify them, since we print out a warning for multiple
// entries found.
if ((*result)->second.desc.hint.size <= (*i)->second.desc.hint.size) {
if ((*result)->second.offset >= (*i)->second.offset)
result = i;
}
}
return result;
}
bool getExtractionData(const Game *g, Search &search, ExtractMap &map) {
SearchMap searchMap;
const int *needList = getNeedList(g);
if (!needList) {
fprintf(stderr, "ERROR: No entry need list available\n");
return false;
}
if (!setupSearch(g, needList, search, searchMap))
return false;
// Process the data search
Search::ResultList results;
search.search(results);
if (results.empty()) {
fprintf(stderr, "ERROR: Couldn't find any required data\n");
return false;
}
ExtractMap temporaryExtractMap;
for (const int *entry = needList; *entry != -1; ++entry) {
typedef std::pair<SearchMap::const_iterator, SearchMap::const_iterator> KeyRange;
KeyRange idRange = searchMap.equal_range(*entry);
for (Search::ResultList::const_iterator i = results.begin(); i != results.end(); ++i) {
for (SearchMap::const_iterator j = idRange.first; j != idRange.second; ++j) {
if (j->second.hint == i->data)
temporaryExtractMap.insert(ExtractMapEntry(*entry, ExtractData(j->second, i->offset)));
}
}
}
// Free up some memory
results.clear();
searchMap.clear();
bool result = true;
for (const int *entry = needList; *entry != -1; ++entry) {
MatchList possibleMatches = filterPlatformMatches(g, temporaryExtractMap.equal_range(*entry));
if (possibleMatches.empty()) {
fprintf(stderr, "ERROR: No entry found for id %d/%s\n", *entry, getIdString(*entry));
result = false;
continue;
}
if (isLangSpecific(*entry)) {
for (int i = 0; i < 3; ++i) {
if (g->lang[i] == -1)
continue;
MatchList langMatches = filterLanguageMatches(g->lang[i], possibleMatches);
MatchList::const_iterator bestMatch = filterOutBestMatch(langMatches);
if (bestMatch == langMatches.end()) {
// TODO: Add nice language name to output message.
fprintf(stderr, "ERROR: No entry found for id %d/%s for language %d\n", *entry, getIdString(*entry), g->lang[i]);
result = false;
continue;
}
#ifdef DEBUG_EXTRACTION_TABLES
if (((*bestMatch)->second.desc.platform != kPlatformUnknown && (*bestMatch)->second.desc.platform != g->platform))
printf("%s: %.8X %.8X %d %d\n", getIdString(*entry), (*bestMatch)->second.desc.hint.size, (*bestMatch)->second.desc.hint.byteSum, (*bestMatch)->second.desc.lang, (*bestMatch)->second.desc.platform);
#endif
map.insert(**bestMatch);
}
} else {
MatchList::const_iterator bestMatch = filterOutBestMatch(possibleMatches);
if (bestMatch == possibleMatches.end()) {
fprintf(stderr, "ERROR: No entry found for id %d/%s\n", *entry, getIdString(*entry));
result = false;
continue;
}
#ifdef DEBUG_EXTRACTION_TABLES
if (((*bestMatch)->second.desc.platform != kPlatformUnknown && (*bestMatch)->second.desc.platform != g->platform))
printf("%s: %.8X %.8X %d %d\n", getIdString(*entry), (*bestMatch)->second.desc.hint.size, (*bestMatch)->second.desc.hint.byteSum, (*bestMatch)->second.desc.lang, (*bestMatch)->second.desc.platform);
#endif
map.insert(**bestMatch);
}
}
return result;
}