Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

10
engines/dm/.gitattributes vendored Normal file
View File

@@ -0,0 +1,10 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.cpp text
*.h text
# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf

3
engines/dm/POTFILES Normal file
View File

@@ -0,0 +1,3 @@
engines/dm/dm.cpp
engines/dm/loadsave.cpp
engines/dm/metaengine.cpp

View File

@@ -0,0 +1,215 @@
# This file is obsolete
F0115_DUNGEONVIEW_DrawObjectsCreaturesProjectilesExplosions_CPSEF
F0113_DUNGEONVIEW_DrawField // stub method
F0133_VIDEO_BlitBoxFilledWithMaskedBitmap // dummy
FIELD_ASPECT // done
F0114_DUNGEONVIEW_GetExplosionBitmap // done
F0133_VIDEO_BlitBoxFilledWithMaskedBitmap // dummy
F0141_DUNGEON_GetObjectInfoIndex // done
F0142_DUNGEON_GetProjectileAspect // done
F0158_DUNGEON_GetWeaponInfo // done
M66_PROJECTILE_ASPECT_ORDINAL // done
F0176_GROUP_GetCreatureOrdinalInCell // done
F0145_DUNGEON_GetGroupCells // done
F0147_DUNGEON_GetGroupDirections // done
GROUP // done
CreatureType // done
G0077_B_DoNotDrawFluxcagesDuringEndgame // done
G0105_s_Graphic558_Box_ExplosionPattern_D0C // one
G0188_as_Graphic558_FieldAspects // done
G0216_auc_Graphic558_ExplosionBaseScales // done
G0217_aauc_Graphic558_ObjectPileShiftSetIndices // done
G0218_aaaauc_Graphic558_ObjectCoordinateSets // done
G0223_aac_Graphic558_ShiftSets // done
G0224_aaaauc_Graphic558_CreatureCoordinateSets // done
G0225_aai_Graphic558_CenteredExplosionCoordinates // done
G0226_aaai_Graphic558_ExplosionCoordinates // done
G0227_aai_Graphic558_RebirthStep2ExplosionCoordinates // done
G0228_aai_Graphic558_RebirthStep1ExplosionCoordinates // done
G0292_aT_PileTopObject // done
G0370_ps_Events // done
F0380_COMMAND_ProcessQueue_CPSC // in progress
C080_COMMAND_CLICK_IN_DUNGEON_VIEW // cool
F0377_COMMAND_ProcessType80_ClickInDungeonView // done so-so
F0372_COMMAND_ProcessType80_ClickInDungeonView_TouchFrontWall // done so-so
F0275_SENSOR_IsTriggeredByClickOnWall // done so-so
F0280_CHAMPION_AddCandidateChampionToParty // done, so-so
F0378_COMMAND_ProcessType81_ClickInPanel // done so-so
F0282_CHAMPION_ProcessCommands160To162_ClickInResurrectReincarnatePanel // done
F0368_COMMAND_SetLeader // done
F0457_START_DrawEnabledMenus_CPSF // can't yet see it's purpose
F0281_CHAMPION_Rename // stub
F0394_MENUS_SetMagicCasterAndDrawSpellArea // done
F0393_MENUS_DrawSpellAreaControls // done
F0051_TEXT_MESSAGEAREA_PrintLineFeed // post skip
F0047_TEXT_MESSAGEAREA_PrintMessage // post skip
F0067_MOUSE_SetPointerToNormal // skip
F0280_CHAMPION_AddCandidateChampionToParty // done, so-so
M27_PORTRAIT_X // done
M28_PORTRAIT_Y // done
F0285_CHAMPION_GetIndexInCell // done
F0279_CHAMPION_GetDecodedValue // done
F0368_COMMAND_SetLeader // done
F0292_CHAMPION_DrawState // done
G0407_s_Party // done
G0048_s_Graphic562_Box_Mouth // done
G0049_s_Graphic562_Box_Eye // done
G0054_ai_Graphic562_Box_ChampionIcons // done
G0353_ac_StringBuildBuffer // done
G0046_auc_Graphic562_ChampionColor // done
F0354_INVENTORY_DrawStatusBoxPortrait // done
F0287_CHAMPION_DrawBarGraphs // done
F0290_CHAMPION_DrawHealthStaminaManaValues // done
F0309_CHAMPION_GetMaximumLoad // done
F0306_CHAMPION_GetStaminaAdjustedValue // done
F0288_CHAMPION_GetStringFromInteger // done
F0345_INVENTORY_DrawPanel_FoodWaterPoisoned // done
F0344_INVENTORY_DrawPanel_FoodOrWaterBar // done
F0343_INVENTORY_DrawPanel_HorizontalBar // done
G0032_s_Graphic562_Box_Panel // done
G0035_s_Graphic562_Box_Food // done
G0036_s_Graphic562_Box_Water // done
G0037_s_Graphic562_Box_Poisoned // done
F0351_INVENTORY_DrawChampionSkillsAndStatistics // skip -----------------
F0347_INVENTORY_DrawPanel // done
F0342_INVENTORY_DrawPanel_Object // done
F0341_INVENTORY_DrawPanel_Scroll // done
F0340_INVENTORY_DrawPanel_ScrollTextLine // done
F0333_INVENTORY_OpenAndDrawChest // done
F0303_CHAMPION_GetSkillLevel // done
F0332_INVENTORY_DrawIconToViewport // done
F0336_INVENTORY_DrawPanel_BuildObjectAttributesString // done
F0335_INVENTORY_DrawPanel_ObjectDescriptionString // done
G0421_i_ObjectDescriptionTextX // done
G0422_i_ObjectDescriptionTextY // done
F0339_INVENTORY_DrawPanel_ArrowOrEye // done
G0430_apc_DirectionNames // done
G0034_s_Graphic562_Box_ObjectDescriptionCircle // done
G0032_s_Graphic562_Box_Panel // done
G0352_apc_ObjectNames // done
G0237_as_Graphic559_ObjectInfo // done
G0422_i_ObjectDescriptionTextY // done
F0346_INVENTORY_DrawPanel_ResurrectReincarnate // done
F0291_CHAMPION_DrawSlot // done
F0038_OBJECT_DrawIconInSlotBox // done
F0140_DUNGEON_GetObjectWeight // done
G0238_as_Graphic559_WeaponInfo // done
WEAPON_INFO // done
G0239_as_Graphic559_ArmourInfo // done
ARMOUR_INFO // done
G0241_auc_Graphic559_JunkInfo // done
JUNK_INFO // done
G0411_i_LeaderIndex // done
G0299_ui_CandidateChampionOrdinal // done
F0388_MENUS_ClearActingChampion // done
F0292_CHAMPION_DrawState // done
G0508_B_RefreshActionArea // done
G0506_ui_ActingChampionOrdinal // done
F0386_MENUS_DrawActionIcon // done
F0141_DUNGEON_GetObjectInfoIndex // done
F0033_OBJECT_GetIconIndex // done
F0032_OBJECT_GetType // done
G0237_as_Graphic559_ObjectInfo // done
OBJECT_INFO // done
G0029_auc_Graphic562_ChargeCountToTorchType // done
F0134_VIDEO_FillBitmap // done
D24_FillScreenBox // done
F0036_OBJECT_ExtractIconFromBitmap // done
G0026_ai_Graphic562_IconGraphicFirstIconIndex // done
F0129_VIDEO_BlitShrinkWithPaletteChanges // eeeh
F0136_VIDEO_ShadeScreenBox // skip
G0498_auc_Graphic560_PaletteChanges_ActionAreaObjectIcon // done
G0237_as_Graphic559_ObjectInfo // done
G0509_B_ActionAreaContainsIcons // done
F0301_CHAMPION_AddObjectInSlot // done
F0299_CHAMPION_ApplyObjectModifiersToStatistics // done
F0296_CHAMPION_DrawChangedObjectIcons // done
F0068_MOUSE_SetPointerToObject // skip
F0077_MOUSE_HidePointer_CPSE // skip
F0078_MOUSE_ShowPointer // skip
F0034_OBJECT_DrawLeaderHandObjectName // done
F0386_MENUS_DrawActionIcon // done
F0295_CHAMPION_HasObjectIconInSlotBoxChanged // done
F0039_OBJECT_GetIconIndexInSlotBox // done
M70_HAND_SLOT_INDEX // done
G0420_B_MousePointerHiddenToDrawChangedObjectIconOnScreen // done
G0412_puc_Bitmap_ObjectIconForMousePointer // done
G0413_i_LeaderHandObjectIconIndex // done
G0414_T_LeaderHandObject // done
F0337_INVENTORY_SetDungeonViewPalette // skip
G0407_s_Party // done
G0039_ai_Graphic562_LightPowerToLightAmount // skip
F0355_INVENTORY_Toggle_CPSE // done
F0292_CHAMPION_DrawState // done
F0334_INVENTORY_CloseChest // done
F0163_DUNGEON_LinkThingToList // done
G0426_T_OpenChest // done
G0425_aT_ChestSlots // done
F0395_MENUS_DrawMovementArrows // done
F0357_COMMAND_DiscardAllInput // skip
F0098_DUNGEONVIEW_DrawFloorAndCeiling // wat
F0136_VIDEO_ShadeScreenBox // skip
D25_F0135_VIDEO_FillBox // done
G0423_i_InventoryChampionOrdinal
G0326_B_RefreshMousePointerInMainLoop // lol you wat m8
G0002_s_Graphic562_Box_MovementArrows // done
G0041_s_Graphic562_Box_ViewportFloppyZzzCross // done
G0296_puc_Bitmap_Viewport // done
G0598_B_MousePointerBitmapUpdated // done
F0456_START_DrawDisabledMenus // done
G0415_B_LeaderEmptyHanded // done
G0305_ui_PartyChampionCount // done
G0578_B_UseByteBoxCoordinates // done
G0047_s_Graphic562_Box_ChampionPortrait // done
G0308_i_PartyDirection // done
G0306_i_PartyMapX // done
G0307_i_PartyMapY // done
G0299_ui_CandidateChampionOrdinal // done
G0508_B_RefreshActionArea // done
G0233_ai_Graphic559_DirectionToStepEastCount // done
G0234_ai_Graphic559_DirectionToStepNorthCount // done
G0237_as_Graphic559_ObjectInfo // done
G0038_ai_Graphic562_SlotMasks // done
F0462_START_StartGame_CPSF
F0003_MAIN_ProcessNewPartyMap_CPSE // partially done
F0278_CHAMPION_ResetDataToStartGame // paritally done
G0331_B_PressingEye // dm // done
G0332_B_StopPressingEye // dm // done
G0333_B_PressingMouth // dm // done
G0334_B_StopPressingMouth // dm // done
G0340_B_HighlightBoxInversionRequested // dm, useless // done
G0341_B_HighlightBoxEnabled // eventman // done
G0300_B_PartyIsSleeping // champion // done
G0506_ui_ActingChampionOrdinal // champion // done
G0509_B_ActionAreaContainsIcons // menus // done
G0599_ui_UseChampionIconOrdinalAsMousePointerBitmap // eventman // done
F0463_START_InitializeGame_CPSADEF // partially done
F0267_MOVE_GetMoveResult_CPSCE // skip, really though
F0357_COMMAND_DiscardAllInput // done
C013_GRAPHIC_MOVEMENT_ARROWS
F0395_MENUS_DrawMovementArrows
F0355_INVENTORY_Toggle_CPSE
F0462_START_StartGame_CPSF
F0457_START_DrawEnabledMenus_CPSF
F0314_CHAMPION_WakeUp
F0282_CHAMPION_ProcessCommands160To162_ClickInResurrectReincarnatePanel
F0380_COMMAND_ProcessQueue_CPSC
F0433_STARTEND_ProcessCommand140_SaveGame_CPSCDF

21
engines/dm/TODOs/todo.txt Normal file
View File

@@ -0,0 +1,21 @@
Bugs:
Display:
Spellcasting tabs are displayed inproperly, switching between them is possible tho
Cursor icons are drawn twice
DisplayMan::blitBoxFilledWithMaskedBitmap does not produce the same effect as the original
Logic:
Items thrown on the right side end up on the left side
Restarting the game after the party is dead segfaults
Todo:
Add wiki entry for DM
Double check enums with hex literals
Double check strcat, strstr usages
I forgot to add a bunch of warning for show/hide mouse pointer and other mouse functions
Code stuff todo:
Complete stub methods(blitShrink)
Add proper save header, add error handling to it
Add translations to f433_processCommand140_saveGame 'LOAD'

2689
engines/dm/champion.cpp Normal file

File diff suppressed because it is too large Load Diff

582
engines/dm/champion.h Normal file
View File

@@ -0,0 +1,582 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_CHAMPION_H
#define DM_CHAMPION_H
#include "common/str.h"
#include "dm/dm.h"
#include "dm/gfx.h"
namespace DM {
#define kDMIgnoreObjectModifiers 0x4000 // @ MASK0x4000_IGNORE_OBJECT_MODIFIERS
#define kDMIgnoreTemporaryExperience 0x8000 // @ MASK0x8000_IGNORE_TEMPORARY_EXPERIENCE
class Scent {
uint16 _scent;
public:
explicit Scent(uint16 scent = 0): _scent(scent) {}
uint16 getMapX() { return _scent & 0x1F; }
uint16 getMapY() { return (_scent >> 5) & 0x1F; }
uint16 getMapIndex() { return (_scent >> 10) & 0x3F; }
void setMapX(uint16 val) { _scent = (_scent & ~0x1F) | (val & 0x1F); }
void setMapY(uint16 val) { _scent = (_scent & ~(0x1F << 5)) | (val & 0x1F); }
void setMapIndex(uint16 val) { _scent = (_scent & ~(0x1F << 10)) | (val & 0x3F); }
void setVal(uint16 val) { _scent = val; }
uint16 toUint16() { return _scent; }
}; // @ SCENT
class Party {
public:
Party() {
resetToZero();
}
int16 _magicalLightAmount;
byte _event73Count_ThievesEye;
byte _event79Count_Footprints;
int16 _shieldDefense;
int16 _fireShieldDefense;
int16 _spellShieldDefense;
byte _scentCount;
byte _freezeLifeTicks;
byte _firstScentIndex;
byte _lastScentIndex;
Scent _scents[24]; // if I remember correctly, user defined default constructors are always called
byte _scentStrengths[24];
byte _event71Count_Invisibility;
void resetToZero() {
_magicalLightAmount = 0;
_event73Count_ThievesEye = 0;
_event79Count_Footprints = 0;
_shieldDefense = 0;
_fireShieldDefense = 0;
_spellShieldDefense = 0;
_scentCount = 0;
_freezeLifeTicks = 0;
_firstScentIndex = 0;
_lastScentIndex = 0;
for (int16 i = 0; i < 24; ++i) {
_scents[i].setVal(0);
_scentStrengths[i] = 0;
}
_event71Count_Invisibility = 0;
}
}; // @ PARTY
enum IconIndice {
kDMIconIndiceNone = -1, // @ CM1_ICON_NONE
kDMIconIndiceJunkCompassNorth = 0, // @ C000_ICON_JUNK_COMPASS_NORTH
kDMIconIndiceJunkCompassWest = 3, // @ C003_ICON_JUNK_COMPASS_WEST
kDMIconIndiceWeaponTorchUnlit = 4, // @ C004_ICON_WEAPON_TORCH_UNLIT
kDMIconIndiceWeaponTorchLit = 7, // @ C007_ICON_WEAPON_TORCH_LIT
kDMIconIndiceJunkWater = 8, // @ C008_ICON_JUNK_WATER
kDMIconIndiceJunkWaterSkin = 9, // @ C009_ICON_JUNK_WATERSKIN
kDMIconIndiceJunkJewelSymalUnequipped = 10, // @ C010_ICON_JUNK_JEWEL_SYMAL_UNEQUIPPED
kDMIconIndiceJunkJewelSymalEquipped = 11, // @ C011_ICON_JUNK_JEWEL_SYMAL_EQUIPPED
kDMIconIndiceJunkIllumuletUnequipped = 12, // @ C012_ICON_JUNK_ILLUMULET_UNEQUIPPED
kDMIconIndiceJunkIllumuletEquipped = 13, // @ C013_ICON_JUNK_ILLUMULET_EQUIPPED
kDMIconIndiceWeaponFlamittEmpty = 14, // @ C014_ICON_WEAPON_FLAMITT_EMPTY
kDMIconIndiceWeaponEyeOfTimeEmpty = 16, // @ C016_ICON_WEAPON_EYE_OF_TIME_EMPTY
kDMIconIndiceWeaponStormringEmpty = 18, // @ C018_ICON_WEAPON_STORMRING_EMPTY
kDMIconIndiceWeaponStaffOfClawsEmpty = 20, // @ C020_ICON_WEAPON_STAFF_OF_CLAWS_EMPTY
kDMIconIndiceWeaponStaffOfClawsFull = 22, // @ C022_ICON_WEAPON_STAFF_OF_CLAWS_FULL
kDMIconIndiceWeaponBoltBladeStormEmpty = 23, // @ C023_ICON_WEAPON_BOLT_BLADE_STORM_EMPTY
kDMIconIndiceWeaponFuryRaBladeEmpty = 25, // @ C025_ICON_WEAPON_FURY_RA_BLADE_EMPTY
kDMIconIndiceWeaponTheFirestaff = 27, // @ C027_ICON_WEAPON_THE_FIRESTAFF
kDMIconIndiceWeaponTheFirestaffComplete = 28, // @ C028_ICON_WEAPON_THE_FIRESTAFF_COMPLETE
kDMIconIndiceScrollOpen = 30, // @ C030_ICON_SCROLL_SCROLL_OPEN
kDMIconIndiceScrollClosed = 31, // @ C031_ICON_SCROLL_SCROLL_CLOSED
kDMIconIndiceWeaponDagger = 32, // @ C032_ICON_WEAPON_DAGGER
kDMIconIndiceWeaponDeltaSideSplitter = 38, // @ C038_ICON_WEAPON_DELTA_SIDE_SPLITTER
kDMIconIndiceWeaponDiamondEdge = 39, // @ C039_ICON_WEAPON_DIAMOND_EDGE
kDMIconIndiceWeaponVorpalBlade = 40, // @ C040_ICON_WEAPON_VORPAL_BLADE
kDMIconIndiceWeaponTheInquisitorDragonFang = 41, // @ C041_ICON_WEAPON_THE_INQUISITOR_DRAGON_FANG
kDMIconIndiceWeaponHardcleaveExecutioner = 43, // @ C043_ICON_WEAPON_HARDCLEAVE_EXECUTIONER
kDMIconIndiceWeaponMaceOfOrder = 45, // @ C045_ICON_WEAPON_MACE_OF_ORDER
kDMIconIndiceWeaponArrow = 51, // @ C051_ICON_WEAPON_ARROW
kDMIconIndiceWeaponSlayer = 52, // @ C052_ICON_WEAPON_SLAYER
kDMIconIndiceWeaponRock = 54, // @ C054_ICON_WEAPON_ROCK
kDMIconIndiceWeaponPoisonDart = 55, // @ C055_ICON_WEAPON_POISON_DART
kDMIconIndiceWeaponThrowingStar = 56, // @ C056_ICON_WEAPON_THROWING_STAR
kDMIconIndiceWeaponStaff = 58, // @ C058_ICON_WEAPON_STAFF
kDMIconIndiceWeaponWand = 59, // @ C059_ICON_WEAPON_WAND
kDMIconIndiceWeaponTeowand = 60, // @ C060_ICON_WEAPON_TEOWAND
kDMIconIndiceWeaponYewStaff = 61, // @ C061_ICON_WEAPON_YEW_STAFF
kDMIconIndiceWeaponStaffOfManarStaffOfIrra = 62, // @ C062_ICON_WEAPON_STAFF_OF_MANAR_STAFF_OF_IRRA
kDMIconIndiceWeaponSnakeStaffCrossOfNeta = 63, // @ C063_ICON_WEAPON_SNAKE_STAFF_CROSS_OF_NETA
kDMIconIndiceWeaponTheConduitSerpentStaff = 64, // @ C064_ICON_WEAPON_THE_CONDUIT_SERPENT_STAFF
kDMIconIndiceWeaponDragonSpit = 65, // @ C065_ICON_WEAPON_DRAGON_SPIT
kDMIconIndiceWeaponSceptreOfLyf = 66, // @ C066_ICON_WEAPON_SCEPTRE_OF_LYF
kDMIconIndiceArmourCloakOfNight = 81, // @ C081_ICON_ARMOUR_CLOAK_OF_NIGHT
kDMIconIndiceArmourCrownOfNerra = 104, // @ C104_ICON_ARMOUR_CROWN_OF_NERRA
kDMIconIndiceArmourElvenBoots = 119, // @ C119_ICON_ARMOUR_ELVEN_BOOTS
kDMIconIndiceJunkGemOfAges = 120, // @ C120_ICON_JUNK_GEM_OF_AGES
kDMIconIndiceJunkEkkhardCross = 121, // @ C121_ICON_JUNK_EKKHARD_CROSS
kDMIconIndiceJunkMoonstone = 122, // @ C122_ICON_JUNK_MOONSTONE
kDMIconIndiceJunkPendantFeral = 124, // @ C124_ICON_JUNK_PENDANT_FERAL
kDMIconIndiceJunkBoulder = 128, // @ C128_ICON_JUNK_BOULDER
kDMIconIndiceJunkRabbitsFoot = 137, // @ C137_ICON_JUNK_RABBITS_FOOT
kDMIconIndiceArmourDexhelm = 140, // @ C140_ICON_ARMOUR_DEXHELM
kDMIconIndiceArmourFlamebain = 141, // @ C141_ICON_ARMOUR_FLAMEBAIN
kDMIconIndiceArmourPowertowers = 142, // @ C142_ICON_ARMOUR_POWERTOWERS
kDMIconIndiceContainerChestClosed = 144, // @ C144_ICON_CONTAINER_CHEST_CLOSED
kDMIconIndiceContainerChestOpen = 145, // @ C145_ICON_CONTAINER_CHEST_OPEN
kDMIconIndiceJunkChampionBones = 147, // @ C147_ICON_JUNK_CHAMPION_BONES
kDMIconIndicePotionMaPotionMonPotion = 148, // @ C148_ICON_POTION_MA_POTION_MON_POTION
kDMIconIndicePotionWaterFlask = 163, // @ C163_ICON_POTION_WATER_FLASK
kDMIconIndiceJunkApple = 168, // @ C168_ICON_JUNK_APPLE
kDMIconIndiceJunkIronKey = 176, // @ C176_ICON_JUNK_IRON_KEY
kDMIconIndiceJunkMasterKey = 191, // @ C191_ICON_JUNK_MASTER_KEY
kDMIconIndiceArmourBootOfSpeed = 194, // @ C194_ICON_ARMOUR_BOOT_OF_SPEED
kDMIconIndicePotionEmptyFlask = 195, // @ C195_ICON_POTION_EMPTY_FLASK
kDMIconIndiceJunkZokathra = 197, // @ C197_ICON_JUNK_ZOKATHRA
kDMIconIndiceActionEmptyHand = 201, // @ C201_ICON_ACTION_ICON_EMPTY_HAND
kDMIconIndiceEyeNotLooking = 202, // @ C202_ICON_EYE_NOT_LOOKING /* One pixel is different in this bitmap from the eye in C017_GRAPHIC_INVENTORY. This is visible by selecting another champion after clicking the eye */
kDMIconIndiceEyeLooking = 203, // @ C203_ICON_EYE_LOOKING
kDMIconIndiceEmptyBox = 204, // @ C204_ICON_EMPTY_BOX
kDMIconIndiceMouthOpen = 205, // @ C205_ICON_MOUTH_OPEN
kDMIconIndiceNeck = 208, // @ C208_ICON_NECK
kDMIconIndiceReadyHand = 212 // @ C212_ICON_READY_HAND
};
enum ChampionIndex {
kDMChampionNone = -1, // @ CM1_CHAMPION_NONE
kDMChampionFirst = 0, // @ C00_CHAMPION_FIRST
kDMChampionSecond = 1,
kDMChampionThird = 2,
kDMChampionFourth = 3,
kDMChampionCloseInventory = 4, // @ C04_CHAMPION_CLOSE_INVENTORY
kDMChampionSpecialInventory = 5 // @ C05_CHAMPION_SPECIAL_INVENTORY
};
enum ChampionAttribute {
kDMAttributNone = 0x0000, // @ MASK0x0000_NONE
kDMAttributeDisableAction = 0x0008, // @ MASK0x0008_DISABLE_ACTION
kDMAttributeMale = 0x0010, // @ MASK0x0010_MALE
kDMAttributeNameTitle = 0x0080, // @ MASK0x0080_NAME_TITLE
kDMAttributeStatistics = 0x0100, // @ MASK0x0100_STATISTICS
kDMAttributeLoad = 0x0200, // @ MASK0x0200_LOAD
kDMAttributeIcon = 0x0400, // @ MASK0x0400_ICON
kDMAttributePanel = 0x0800, // @ MASK0x0800_PANEL
kDMAttributeStatusBox = 0x1000, // @ MASK0x1000_STATUS_BOX
kDMAttributeWounds = 0x2000, // @ MASK0x2000_WOUNDS
kDMAttributeViewport = 0x4000, // @ MASK0x4000_VIEWPORT
kDMAttributeActionHand = 0x8000 // @ MASK0x8000_ACTION_HAND
};
enum ChampionWound {
kDMWoundNone = 0x0000, // @ MASK0x0000_NO_WOUND
kDMWoundReadHand = 0x0001, // @ MASK0x0001_READY_HAND
kDMWoundActionHand = 0x0002, // @ MASK0x0002_ACTION_HAND
kDMWoundHead = 0x0004, // @ MASK0x0004_HEAD
kDMWoundTorso = 0x0008, // @ MASK0x0008_TORSO
kDMWoundLegs = 0x0010, // @ MASK0x0010_LEGS
kDMWoundFeet = 0x0020 // @ MASK0x0020_FEET
};
enum ChampionStatType {
kDMStatLuck = 0, // @ C0_STATISTIC_LUCK
kDMStatStrength = 1, // @ C1_STATISTIC_STRENGTH
kDMStatDexterity = 2, // @ C2_STATISTIC_DEXTERITY
kDMStatWisdom = 3, // @ C3_STATISTIC_WISDOM
kDMStatVitality = 4, // @ C4_STATISTIC_VITALITY
kDMStatAntimagic = 5, // @ C5_STATISTIC_ANTIMAGIC
kDMStatAntifire = 6, // @ C6_STATISTIC_ANTIFIRE
kDMStatMana = 8 // @ C8_STATISTIC_MANA /* Used as a fake statistic index for objects granting a Mana bonus */
};
enum ChampionStatValue {
kDMStatMaximum = 0, // @ C0_MAXIMUM
kDMStatCurrent = 1, // @ C1_CURRENT
kDMStatMinimum = 2 // @ C2_MINIMUM
};
enum ChampionSkill {
kDMSkillFighter = 0, // @ C00_SKILL_FIGHTER
kDMSkillNinja = 1, // @ C01_SKILL_NINJA
kDMSkillPriest = 2, // @ C02_SKILL_PRIEST
kDMSkillWizard = 3, // @ C03_SKILL_WIZARD
kDMSkillSwing = 4, // @ C04_SKILL_SWING
kDMSkillThrust = 5, // @ C05_SKILL_THRUST
kDMSkillClub = 6, // @ C06_SKILL_CLUB
kDMSkillParry = 7, // @ C07_SKILL_PARRY
kDMSkillSteal = 8, // @ C08_SKILL_STEAL
kDMSkillFight = 9, // @ C09_SKILL_FIGHT
kDMSkillThrow = 10, // @ C10_SKILL_THROW
kDMSkillShoot = 11, // @ C11_SKILL_SHOOT
kDMSkillIdentify = 12, // @ C12_SKILL_IDENTIFY
kDMSkillHeal = 13, // @ C13_SKILL_HEAL
kDMSkillInfluence = 14, // @ C14_SKILL_INFLUENCE
kDMSkillDefend = 15, // @ C15_SKILL_DEFEND
kDMSkillFire = 16, // @ C16_SKILL_FIRE
kDMSkillAir = 17, // @ C17_SKILL_AIR
kDMSkillEarth = 18, // @ C18_SKILL_EARTH
kDMSkillWater = 19 // @ C19_SKILL_WATER
};
enum ChampionSlot {
kDMSlotLeaderHand = -1, // @ CM1_SLOT_LEADER_HAND
kDMSlotReadyHand = 0, // @ C00_SLOT_READY_HAND
kDMSlotActionHand = 1, // @ C01_SLOT_ACTION_HAND
kDMSlotHead = 2, // @ C02_SLOT_HEAD
kDMSlotTorso = 3, // @ C03_SLOT_TORSO
kDMSlotLegs = 4, // @ C04_SLOT_LEGS
kDMSlotFeet = 5, // @ C05_SLOT_FEET
kDMSlotPouch_2 = 6, // @ C06_SLOT_POUCH_2
kDMSlotQuiverLine2_1 = 7, // @ C07_SLOT_QUIVER_LINE2_1
kDMSlotQuiverLine1_2 = 8, // @ C08_SLOT_QUIVER_LINE1_2
kDMSlotQuiverLine2_2 = 9, // @ C09_SLOT_QUIVER_LINE2_2
kDMSlotNeck = 10, // @ C10_SLOT_NECK
kDMSlotPouch1 = 11, // @ C11_SLOT_POUCH_1
kDMSlotQuiverLine1_1 = 12, // @ C12_SLOT_QUIVER_LINE1_1
kDMSlotBackpackLine1_1 = 13, // @ C13_SLOT_BACKPACK_LINE1_1
kDMSlotBackpackLine2_2 = 14, // @ C14_SLOT_BACKPACK_LINE2_2
kDMSlotBackpackLine2_3 = 15, // @ C15_SLOT_BACKPACK_LINE2_3
kDMSlotBackpackLine2_4 = 16, // @ C16_SLOT_BACKPACK_LINE2_4
kDMSlotBackpackLine2_5 = 17, // @ C17_SLOT_BACKPACK_LINE2_5
kDMSlotBackpackLine2_6 = 18, // @ C18_SLOT_BACKPACK_LINE2_6
kDMSlotBackpackLine2_7 = 19, // @ C19_SLOT_BACKPACK_LINE2_7
kDMSlotBackpackLine2_8 = 20, // @ C20_SLOT_BACKPACK_LINE2_8
kDMSlotBackpackLine2_9 = 21, // @ C21_SLOT_BACKPACK_LINE2_9
kDMSlotBackpackLine1_2 = 22, // @ C22_SLOT_BACKPACK_LINE1_2
kDMSlotBackpackLine1_3 = 23, // @ C23_SLOT_BACKPACK_LINE1_3
kDMSlotBackpackLine1_4 = 24, // @ C24_SLOT_BACKPACK_LINE1_4
kDMSlotBackpackLine1_5 = 25, // @ C25_SLOT_BACKPACK_LINE1_5
kDMSlotBackpackLine1_6 = 26, // @ C26_SLOT_BACKPACK_LINE1_6
kDMSlotBackpackLine1_7 = 27, // @ C27_SLOT_BACKPACK_LINE1_7
kDMSlotBackpackLine1_8 = 28, // @ C28_SLOT_BACKPACK_LINE1_8
kDMSlotBackpackLine1_9 = 29, // @ C29_SLOT_BACKPACK_LINE1_9
kDMSlotChest1 = 30, // @ C30_SLOT_CHEST_1
kDMSlotChest2 = 31, // @ C31_SLOT_CHEST_2
kDMSlotChest3 = 32, // @ C32_SLOT_CHEST_3
kDMSlotChest4 = 33, // @ C33_SLOT_CHEST_4
kDMSlotChest5 = 34, // @ C34_SLOT_CHEST_5
kDMSlotChest6 = 35, // @ C35_SLOT_CHEST_6
kDMSlotChest7 = 36, // @ C36_SLOT_CHEST_7
kDMSlotChest8 = 37 // @ C37_SLOT_CHEST_8
};
enum ChampionAction {
kDMActionN = 0, // @ C000_ACTION_N
kDMActionBlock = 1, // @ C001_ACTION_BLOCK
kDMActionChop = 2, // @ C002_ACTION_CHOP
kDMActionX = 3, // @ C003_ACTION_X
kDMActionBlowHorn = 4, // @ C004_ACTION_BLOW_HORN
kDMActionFlip = 5, // @ C005_ACTION_FLIP
kDMActionPunch = 6, // @ C006_ACTION_PUNCH
kDMActionKick = 7, // @ C007_ACTION_KICK
kDMActionWarCry = 8, // @ C008_ACTION_WAR_CRY
kDMActionStab9 = 9, // @ C009_ACTION_STAB
kDMActionClimbDown = 10, // @ C010_ACTION_CLIMB_DOWN
kDMActionFreezeLife = 11, // @ C011_ACTION_FREEZE_LIFE
kDMActionHit = 12, // @ C012_ACTION_HIT
kDMActionSwing = 13, // @ C013_ACTION_SWING
kDMActionStab14 = 14, // @ C014_ACTION_STAB
kDMActionThrust = 15, // @ C015_ACTION_THRUST
kDMActionJab = 16, // @ C016_ACTION_JAB
kDMActionParry = 17, // @ C017_ACTION_PARRY
kDMActionHack = 18, // @ C018_ACTION_HACK
kDMActionBerzerk = 19, // @ C019_ACTION_BERZERK
kDMActionFireball = 20, // @ C020_ACTION_FIREBALL
kDMActionDispel = 21, // @ C021_ACTION_DISPELL
kDMActionConfuse = 22, // @ C022_ACTION_CONFUSE
kDMActionLightning = 23, // @ C023_ACTION_LIGHTNING
kDMActionDisrupt = 24, // @ C024_ACTION_DISRUPT
kDMActionMelee = 25, // @ C025_ACTION_MELEE
kDMActionX_C026 = 26, // @ C026_ACTION_X
kDMActionInvoke = 27, // @ C027_ACTION_INVOKE
kDMActionSlash = 28, // @ C028_ACTION_SLASH
kDMActionCleave = 29, // @ C029_ACTION_CLEAVE
kDMActionBash = 30, // @ C030_ACTION_BASH
kDMActionStun = 31, // @ C031_ACTION_STUN
kDMActionShoot = 32, // @ C032_ACTION_SHOOT
kDMActionSpellshield = 33, // @ C033_ACTION_SPELLSHIELD
kDMActionFireshield = 34, // @ C034_ACTION_FIRESHIELD
kDMActionFluxcage = 35, // @ C035_ACTION_FLUXCAGE
kDMActionHeal = 36, // @ C036_ACTION_HEAL
kDMActionCalm = 37, // @ C037_ACTION_CALM
kDMActionLight = 38, // @ C038_ACTION_LIGHT
kDMActionWindow = 39, // @ C039_ACTION_WINDOW
kDMActionSpit = 40, // @ C040_ACTION_SPIT
kDMActionBrandish = 41, // @ C041_ACTION_BRANDISH
kDMActionThrow = 42, // @ C042_ACTION_THROW
kDMActionFuse = 43, // @ C043_ACTION_FUSE
kDMActionNone = 255 // @ C255_ACTION_NONE
};
enum AttackType {
kDMAttackTypeNormal = 0, // @ C0_ATTACK_NORMAL
kDMAttackTypeFire = 1, // @ C1_ATTACK_FIRE
kDMAttackTypeSelf = 2, // @ C2_ATTACK_SELF
kDMAttackTypeBlunt = 3, // @ C3_ATTACK_BLUNT
kDMAttackTypeSharp = 4, // @ C4_ATTACK_SHARP
kDMAttackTypeMagic = 5, // @ C5_ATTACK_MAGIC
kDMAttackTypePsychic = 6, // @ C6_ATTACK_PSYCHIC
kDMAttackTypeLightning = 7 // @ C7_ATTACK_LIGHTNING
};
enum SpellCastResult {
kDMSpellCastFailure = 0, // @ C0_SPELL_CAST_FAILURE
kDMSpellCastSuccess = 1, // @ C1_SPELL_CAST_SUCCESS
kDMSpellCastFailureNeedsFlask = 3 // @ C3_SPELL_CAST_FAILURE_NEEDS_FLASK
};
enum SpellFailure {
kDMFailureNeedsMorePractice = 0, // @ C00_FAILURE_NEEDS_MORE_PRACTICE
kDMFailureMeaninglessSpell = 1, // @ C01_FAILURE_MEANINGLESS_SPELL
kDMFailureNeedsFlaskInHand = 10, // @ C10_FAILURE_NEEDS_FLASK_IN_HAND
kDMFailureNeedsMagicMapInHand = 11 // @ C11_FAILURE_NEEDS_MAGIC_MAP_IN_HAND
};
enum SpellKind {
kDMSpellKindPotion = 1, // @ C1_SPELL_KIND_POTION
kDMSpellKindProjectile = 2, // @ C2_SPELL_KIND_PROJECTILE
kDMSpellKindOther = 3, // @ C3_SPELL_KIND_OTHER
kDMSpellKindMagicMap = 4 // @ C4_SPELL_KIND_MAGIC_MAP
};
enum SpellType {
kDMSpellTypeProjectileOpenDoor = 4, // @ C4_SPELL_TYPE_PROJECTILE_OPEN_DOOR
kDMSpellTypeOtherLight = 0, // @ C0_SPELL_TYPE_OTHER_LIGHT
kDMSpellTypeOtherDarkness = 1, // @ C1_SPELL_TYPE_OTHER_DARKNESS
kDMSpellTypeOtherThievesEye = 2, // @ C2_SPELL_TYPE_OTHER_THIEVES_EYE
kDMSpellTypeOtherInvisibility = 3, // @ C3_SPELL_TYPE_OTHER_INVISIBILITY
kDMSpellTypeOtherPartyShield = 4, // @ C4_SPELL_TYPE_OTHER_PARTY_SHIELD
kDMSpellTypeOtherMagicTorch = 5, // @ C5_SPELL_TYPE_OTHER_MAGIC_TORCH
kDMSpellTypeOtherFootprints = 6, // @ C6_SPELL_TYPE_OTHER_FOOTPRINTS
kDMSpellTypeOtherZokathra = 7, // @ C7_SPELL_TYPE_OTHER_ZOKATHRA
kDMSpellTypeOtherFireshield = 8, // @ C8_SPELL_TYPE_OTHER_FIRESHIELD
kDMSpellTypeMagicMap0 = 0, // @ C0_SPELL_TYPE_MAGIC_MAP
kDMSpellTypeMagicMap1 = 1, // @ C1_SPELL_TYPE_MAGIC_MAP
kDMSpellTypeMagicMap2 = 2, // @ C2_SPELL_TYPE_MAGIC_MAP
kDMSpellTypeMagicMap3 = 3 // @ C3_SPELL_TYPE_MAGIC_MAP
};
#define kDMMaskNoSharpDefense 0x0000 // @ MASK0x0000_DO_NOT_USE_SHARP_DEFENSE
#define kDMMaskSharpDefense 0x8000 // @ MASK0x8000_USE_SHARP_DEFENSE
class Skill {
public:
int16 _temporaryExperience;
int32 _experience;
void resetToZero() { _temporaryExperience = _experience = 0; }
}; // @ SKILL
class Champion {
private:
DMEngine *_vm;
public:
uint16 _attributes;
uint16 _wounds;
byte _statistics[7][3];
Thing _slots[30];
Skill _skills[20];
char _name[8];
char _title[20];
Direction _dir;
ViewCell _cell;
ChampionAction _actionIndex;
uint16 _symbolStep;
char _symbols[5];
uint16 _directionMaximumDamageReceived;
uint16 _maximumDamageReceived;
uint16 _poisonEventCount;
int16 _enableActionEventIndex;
int16 _hideDamageReceivedIndex;
int16 _currHealth;
int16 _maxHealth;
int16 _currStamina;
int16 _maxStamina;
int16 _currMana;
int16 _maxMana;
int16 _actionDefense;
int16 _food;
int16 _water;
uint16 _load;
int16 _shieldDefense;
byte _portrait[928]; // 32 x 29 pixel portrait
Champion() {}
void setVm(DMEngine *vm) { _vm = vm; }
Thing &getSlot(ChampionSlot slot) { return _slots[slot]; }
void setSlot(ChampionSlot slot, Thing val) { _slots[slot] = val; }
Skill &getSkill(ChampionSkill skill) { return _skills[skill]; }
void setSkillExp(ChampionSkill skill, int32 val) { _skills[skill]._experience = val; }
void setSkillTempExp(ChampionSkill skill, int16 val) { _skills[skill]._temporaryExperience= val; }
byte& getStatistic(ChampionStatType type, ChampionStatValue valType) { return _statistics[type][valType]; }
void setStatistic(ChampionStatType type, ChampionStatValue valType, byte newVal) { _statistics[type][valType] = newVal; }
uint16 getAttributes() { return _attributes; }
uint16 getAttributes(ChampionAttribute flag) { return _attributes & flag; }
void setAttributeFlag(ChampionAttribute flag, bool value);
void clearAttributes(ChampionAttribute attribute = kDMAttributNone) { _attributes = attribute; }
uint16 getWounds() { return _wounds; }
void setWoundsFlag(ChampionWound flag, bool value);
uint16 getWoundsFlag(ChampionWound wound) { return _wounds & wound; }
void clearWounds() { _wounds = kDMWoundNone; }
void resetSkillsToZero() {
for (int16 i = 0; i < 20; ++i)
_skills[i].resetToZero();
}
void resetToZero();
}; // @ CHAMPION_INCLUDING_PORTRAIT
class Spell {
public:
Spell() {}
Spell(int32 symbols, byte baseSkillReq, byte skillIndex, uint16 attributes)
: _symbols(symbols), _baseRequiredSkillLevel(baseSkillReq), _skillIndex(skillIndex), _attributes(attributes) {}
int32 _symbols; /* Most significant byte: 0 (spell definition does not include power symbol) / not 0 (spell definition includes power symbol) */
byte _baseRequiredSkillLevel;
byte _skillIndex;
uint16 _attributes; /* Bits 15-10: Duration, Bits 9-4: Type, Bits 3-0: Kind */
uint16 getKind() { return _attributes & 0xF; } // @ M67_SPELL_KIND
uint16 getType() { return (_attributes >> 4) & 0x3F; } // @ M68_SPELL_TYPE
uint16 getDuration() { return (_attributes >> 10) & 0x3F; } // @ M69_SPELL_DURATION
}; // @ SPELL
class ChampionMan {
DMEngine *_vm;
uint16 getChampionPortraitX(uint16 index); // @ M27_PORTRAIT_X
uint16 getChampionPortraitY(uint16 index); // @ M28_PORTRAIT_Y
int16 getDecodedValue(char *string, uint16 characterCount); // @ F0279_CHAMPION_GetDecodedValue
void drawHealthOrStaminaOrManaValue(int16 posy, int16 currVal, int16 maxVal); // @ F0289_CHAMPION_DrawHealthOrStaminaOrManaValue
uint16 getHandSlotIndex(uint16 slotBoxIndex);// @ M70_HAND_SLOT_INDEX
int16 _championPendingWounds[4]; // @ G0410_ai_ChampionPendingWounds
int16 _championPendingDamage[4]; // @ G0409_ai_ChampionPendingDamage
void initConstants();
public:
Champion *_champions; // @ K0071_as_Champions
uint16 _partyChampionCount; // @ G0305_ui_PartyChampionCount
bool _partyDead; // @ G0303_B_PartyDead
Thing _leaderHandObject; // @ G0414_T_LeaderHandObject
ChampionIndex _leaderIndex; // @ G0411_i_LeaderIndex
uint16 _candidateChampionOrdinal; // @ G0299_ui_CandidateChampionOrdinal
bool _partyIsSleeping; // @ G0300_B_PartyIsSleeping
uint16 _actingChampionOrdinal; // @ G0506_ui_ActingChampionOrdinal
IconIndice _leaderHandObjectIconIndex; // @ G0413_i_LeaderHandObjectIconIndex
bool _leaderEmptyHanded; // @ G0415_B_LeaderEmptyHanded
Party _party; // @ G0407_s_Party
ChampionIndex _magicCasterChampionIndex; // @ G0514_i_MagicCasterChampionIndex
bool _mousePointerHiddenToDrawChangedObjIconOnScreen; // @ G0420_B_MousePointerHiddenToDrawChangedObjectIconOnScreen
explicit ChampionMan(DMEngine *vm);
~ChampionMan();
ChampionIndex getIndexInCell(int16 cell); // @ F0285_CHAMPION_GetIndexInCell
bool isLeaderHandObjectThrown(int16 side); // @ F0329_CHAMPION_IsLeaderHandObjectThrown
bool isObjectThrown(uint16 champIndex, int16 slotIndex, int16 side); // @ F0328_CHAMPION_IsObjectThrown
void resetDataToStartGame(); // @ F0278_CHAMPION_ResetDataToStartGame
void addCandidateChampionToParty(uint16 championPortraitIndex); // @ F0280_CHAMPION_AddCandidateChampionToParty
void drawChampionBarGraphs(ChampionIndex champIndex); // @ F0287_CHAMPION_DrawBarGraphs
uint16 getStaminaAdjustedValue(Champion *champ, int16 val); // @ F0306_CHAMPION_GetStaminaAdjustedValue
uint16 getMaximumLoad(Champion *champ); // @ F0309_CHAMPION_GetMaximumLoad
void drawChampionState(ChampionIndex champIndex); // @ F0292_CHAMPION_DrawState
uint16 getChampionIconIndex(int16 val, Direction dir); // @ M26_CHAMPION_ICON_INDEX
void drawHealthStaminaManaValues(Champion *champ); // @ F0290_CHAMPION_DrawHealthStaminaManaValues
void drawSlot(uint16 champIndex, int16 slotIndex); // @ F0291_CHAMPION_DrawSlot
void renameChampion(Champion *champ); // @ F0281_CHAMPION_Rename
uint16 getSkillLevel(int16 champIndex, uint16 skillIndex);// @ F0303_CHAMPION_GetSkillLevel
Common::String getStringFromInteger(uint16 val, bool padding, uint16 paddingCharCount); // @ F0288_CHAMPION_GetStringFromInteger
void applyModifiersToStatistics(Champion *champ, int16 slotIndex, int16 iconIndex,
int16 modifierFactor, Thing thing); // @ F0299_CHAMPION_ApplyObjectModifiersToStatistics
bool hasObjectIconInSlotBoxChanged(int16 slotBoxIndex, Thing thing); // @ F0295_CHAMPION_HasObjectIconInSlotBoxChanged
void drawChangedObjectIcons(); // @ F0296_CHAMPION_DrawChangedObjectIcons
void addObjectInSlot(ChampionIndex champIndex, Thing thing, ChampionSlot slotIndex); // @ F0301_CHAMPION_AddObjectInSlot
int16 getScentOrdinal(int16 mapX, int16 mapY); // @ F0315_CHAMPION_GetScentOrdinal
Thing getObjectRemovedFromLeaderHand(); // @ F0298_CHAMPION_GetObjectRemovedFromLeaderHand
uint16 getStrength(int16 champIndex, int16 slotIndex); // @ F0312_CHAMPION_GetStrength
Thing getObjectRemovedFromSlot(uint16 champIndex, uint16 slotIndex); // @ F0300_CHAMPION_GetObjectRemovedFromSlot
void decrementStamina(int16 championIndex, int16 decrement); // @ F0325_CHAMPION_DecrementStamina
int16 addPendingDamageAndWounds_getDamage(int16 champIndex, int16 attack, int16 allowedWounds,
uint16 attackType); // @ F0321_CHAMPION_AddPendingDamageAndWounds_GetDamage
int16 getWoundDefense(int16 champIndex, uint16 woundIndex); // @ F0313_CHAMPION_GetWoundDefense
uint16 getStatisticAdjustedAttack(Champion *champ, uint16 statIndex, uint16 attack); // @ F0307_CHAMPION_GetStatisticAdjustedAttack
void wakeUp(); // @ F0314_CHAMPION_WakeUp
int16 getThrowingStaminaCost(Thing thing);// @ F0305_CHAMPION_GetThrowingStaminaCost
void disableAction(uint16 champIndex, uint16 ticks); // @ F0330_CHAMPION_DisableAction
void addSkillExperience(uint16 champIndex, uint16 skillIndex, uint16 exp);// @ F0304_CHAMPION_AddSkillExperience
int16 getDamagedChampionCount(uint16 attack, int16 wounds,
int16 attackType); // @ F0324_CHAMPION_DamageAll_GetDamagedChampionCount
int16 getTargetChampionIndex(int16 mapX, int16 mapY, uint16 cell); // @ F0286_CHAMPION_GetTargetChampionIndex
int16 getDexterity(Champion *champ); // @ F0311_CHAMPION_GetDexterity
bool isLucky(Champion *champ, uint16 percentage); // @ F0308_CHAMPION_IsLucky
void championPoison(int16 championIndex, uint16 attack); // @ F0322_CHAMPION_Poison
void setPartyDirection(int16 dir); // @ F0284_CHAMPION_SetPartyDirection
void deleteScent(uint16 scentIndex); // @ F0316_CHAMPION_DeleteScent
void addScentStrength(int16 mapX, int16 mapY, int32 cycleCount); // @ F0317_CHAMPION_AddScentStrength
void putObjectInLeaderHand(Thing thing, bool setMousePointer); // @ F0297_CHAMPION_PutObjectInLeaderHand
int16 getMovementTicks(Champion *champ); // @ F0310_CHAMPION_GetMovementTicks
bool isAmmunitionCompatibleWithWeapon(uint16 champIndex, uint16 weaponSlotIndex,
uint16 ammunitionSlotIndex); // @ F0294_CHAMPION_IsAmmunitionCompatibleWithWeapon
void drawAllChampionStates(); // @ F0293_CHAMPION_DrawAllChampionStates
void viAltarRebirth(uint16 champIndex); // @ F0283_CHAMPION_ViAltarRebirth
void clickOnSlotBox(uint16 slotBoxIndex); // @ F0302_CHAMPION_ProcessCommands28To65_ClickOnSlotBox
bool isProjectileSpellCast(uint16 champIndex, Thing thing, int16 kineticEnergy, uint16 requiredManaAmount); // @ F0327_CHAMPION_IsProjectileSpellCast
void championShootProjectile(Champion *champ, Thing thing, int16 kineticEnergy,
int16 attack, int16 stepEnergy); // @ F0326_CHAMPION_ShootProjectile
void applyAndDrawPendingDamageAndWounds(); // @ F0320_CHAMPION_ApplyAndDrawPendingDamageAndWounds
void championKill(uint16 champIndex); // @ F0319_CHAMPION_Kill
void dropAllObjects(uint16 champIndex); // @ F0318_CHAMPION_DropAllObjects
void unpoison(int16 champIndex); // @ F0323_CHAMPION_Unpoison
void applyTimeEffects(); // @ F0331_CHAMPION_ApplyTimeEffects_CPSF
void savePartyPart2(Common::OutSaveFile *file);
void loadPartyPart2(Common::InSaveFile *file);
Box _boxChampionIcons[4];
Color _championColor[4];
int16 _lightPowerToLightAmount[16]; // g039_LightPowerToLightAmount
Box _boxChampionPortrait;
uint16 _slotMasks[38];
const char *_baseSkillName[4];
};
}
#endif

View File

@@ -0,0 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
add_engine dm "Dungeon Master" no

289
engines/dm/console.cpp Normal file
View File

@@ -0,0 +1,289 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#include "dm/console.h"
#include "dm/dm.h"
#include "dm/champion.h"
#include "dm/dungeonman.h"
#include "dm/movesens.h"
#include "dm/objectman.h"
namespace DM {
bool cstrEquals(const char* a, const char *b) { return strcmp(a, b) == 0; }
class SingleUseFlag {
bool _flag;
public:
SingleUseFlag() : _flag(true) {}
bool check() {
bool currFlagState = _flag;
_flag = false;
return currFlagState;
}
};
const char *Console::debugGetDirectionName(int16 dir) {
static const char *directionNames[] = {"North", "East", "South", "West"};
if (dir < 0 || dir > 3)
return "Invalid direction";
return directionNames[dir];
}
Console::Console(DM::DMEngine* vm) : _vm(vm) {
_debugGodmodeMana = false;
_debugGodmodeHP = false;
_debugGodmodeStamina = false;
_debugNoclip = false;
registerCmd("godmode", WRAP_METHOD(Console, Cmd_godmode));
registerCmd("noclip", WRAP_METHOD(Console, Cmd_noclip));
registerCmd("pos", WRAP_METHOD(Console, Cmd_pos));
registerCmd("map", WRAP_METHOD(Console, Cmd_map));
registerCmd("listItems", WRAP_METHOD(Console, Cmd_listItems));
registerCmd("gimme", WRAP_METHOD(Console, Cmd_gimme));
}
bool Console::Cmd_godmode(int argc, const char** argv) {
if (argc != 3)
goto argumentError;
bool setFlagTo;
if (cstrEquals("on", argv[2])) {
setFlagTo = true;
} else if (cstrEquals("off", argv[2])) {
setFlagTo = false;
} else
goto argumentError;
if (cstrEquals("all", argv[1])) {
_debugGodmodeHP = _debugGodmodeMana = _debugGodmodeStamina = setFlagTo;
} else if (cstrEquals("mana", argv[1])) {
_debugGodmodeMana = setFlagTo;
} else if (cstrEquals("hp", argv[1])) {
_debugGodmodeHP = setFlagTo;
} else if (cstrEquals("stamina", argv[1])) {
_debugGodmodeStamina = setFlagTo;
} else
goto argumentError;
debugPrintf("God mode set for %s to %s\n", argv[1], argv[2]);
return true;
argumentError:
debugPrintf("Usage: %s <all/mana/hp/stamina> <on/off>\n", argv[0]);
return true;
}
bool Console::Cmd_noclip(int argc, const char** argv) {
if (argc != 2)
goto argumentError;
if (cstrEquals("on", argv[1])) {
_debugNoclip = true;
static SingleUseFlag haventWarned;
if (haventWarned.check())
debugPrintf("Noclip can cause glitches and crashes.\n");
} else if (cstrEquals("off", argv[1])) {
_debugNoclip = false;
} else
goto argumentError;
debugPrintf("Noclip set to %s\n", argv[1]);
return true;
argumentError:
debugPrintf("Usage: %s <on/off>\n", argv[0]);
return true;
}
bool Console::Cmd_pos(int argc, const char** argv) {
DungeonMan &dm = *_vm->_dungeonMan;
if (argc == 2 && cstrEquals("get", argv[1])) {
debugPrintf("Position: (%d, %d) Direction: %s\n", dm._partyMapX + dm._currMap->_offsetMapX,
dm._partyMapY + dm._currMap->_offsetMapY, debugGetDirectionName(_vm->_dungeonMan->_partyDir));
} else if (argc == 4 && cstrEquals("set", argv[1])) {
int x = atoi(argv[2]);
int y = atoi(argv[3]);
if ((x == 0 && !cstrEquals("0", argv[2])) || (y == 0 && !cstrEquals("0", argv[3]))) {
debugPrintf("Error, supply two numbers to '%s set' command\n", argv[0]);
return true;
}
Map &currMap = *_vm->_dungeonMan->_currMap;
// not >= because dimensions are inslucsive
if (x < currMap._offsetMapX || x > currMap._width + currMap._offsetMapX
|| y < currMap._offsetMapY || y > currMap._height + currMap._offsetMapY) {
debugPrintf("Position (%d, %d) is out of bounds, possible values: ([1-%d],[1-%d])\n", x, y,
currMap._width + currMap._offsetMapX, currMap._height + currMap._offsetMapY);
return true;
}
static SingleUseFlag haventWarned;
if (haventWarned.check())
debugPrintf("Setting position directly can cause glitches and crashes.\n");
debugPrintf("Position set to (%d, %d)\n", x, y);
_vm->_moveSens->getMoveResult(_vm->_thingParty, _vm->_dungeonMan->_partyMapX, _vm->_dungeonMan->_partyMapY,
x - currMap._offsetMapX, y - currMap._offsetMapY);
} else
goto argumentError;
return true;
argumentError:
debugPrintf("Usage: %s get\n", argv[0]);
debugPrintf("Usage: %s set <#> <#>\n", argv[0]);
return true;
}
bool Console::Cmd_map(int argc, const char** argv) {
if (argc == 2 && cstrEquals("get", argv[1])) {
debugPrintf("Map index: %d\n", _vm->_dungeonMan->_partyMapIndex);
} else if (argc == 3 && cstrEquals("set", argv[1])) {
int index = atoi(argv[2]);
if (index == 0 && !cstrEquals("0", argv[2])) {
debugPrintf("Error, supply a number to '%s set' command\n", argv[0]);
return true;
}
// not >= because dimensions are inslucsive
if (index < 0 || index >= _vm->_dungeonMan->_dungeonFileHeader._mapCount) {
debugPrintf("Map index %d is out of bounds, possible values [0, %d]\n", index, _vm->_dungeonMan->_dungeonFileHeader._mapCount - 1);
return true;
}
static SingleUseFlag haventWarned;
if (haventWarned.check())
debugPrintf("Setting map directly can cause glitches and crashes.\n");
debugPrintf("Map set to %d\n", index);
_vm->_moveSens->getMoveResult(_vm->_thingParty, _vm->_dungeonMan->_partyMapX, _vm->_dungeonMan->_partyMapY, kDMMapXNotOnASquare, 0);
_vm->_newPartyMapIndex = _vm->_dungeonMan->getLocationAfterLevelChange(
_vm->_dungeonMan->_partyMapIndex, index - _vm->_dungeonMan->_partyMapIndex,
&_vm->_dungeonMan->_partyMapX, &_vm->_dungeonMan->_partyMapY);
if (_vm->_newPartyMapIndex == -1)
_vm->_newPartyMapIndex = index;
_vm->_dungeonMan->setCurrentMap(_vm->_newPartyMapIndex);
_vm->_championMan->setPartyDirection(_vm->_dungeonMan->getStairsExitDirection(_vm->_dungeonMan->_partyMapX, _vm->_dungeonMan->_partyMapY));
_vm->_dungeonMan->setCurrentMap(_vm->_dungeonMan->_partyMapIndex);
} else
goto argumentError;
return true;
argumentError:
debugPrintf("Usage: %s get\n", argv[0]);
debugPrintf("Usage: %s set <#>\n", argv[0]);
return true;
}
bool Console::Cmd_listItems(int argc, const char** argv) {
Common::String searchedString = "";
for (int16 i = 1; i < argc; ++i) {
searchedString += argv[i];
searchedString += " ";
}
searchedString.deleteLastChar();
bool atleastOneFound = false;
int16 namesPrintedInLine = 0;
if(strstr(_vm->_objectMan->_objectNames[0], searchedString.c_str()) != nullptr)
debugPrintf("| %s", _vm->_objectMan->_objectNames[0]);
for (uint16 i = 1; i < kDMObjectNameCount; ++i) {
const char *name = _vm->_objectMan->_objectNames[i - 1];
const char *prevName = _vm->_objectMan->_objectNames[i];
if (!cstrEquals(name, prevName) && (strstr(name, searchedString.c_str()) != nullptr)) {
debugPrintf(" | %s", name);
atleastOneFound = true;
if ((++namesPrintedInLine % 6) == 0) {
namesPrintedInLine = 0;
debugPrintf("\n");
}
}
}
if (atleastOneFound) {
debugPrintf("\n");
} else {
debugPrintf("No itemnames found containing '%s'\n", searchedString.c_str());
}
return true;
}
bool Console::Cmd_gimme(int argc, const char** argv) {
if (argc < 2) {
debugPrintf("Usage: gimme <item name> // item name can have spaces\n");
return true;
}
Common::String requestedItemName;
for (int16 i = 1; i < argc; ++i) {
requestedItemName += argv[i];
requestedItemName += " ";
}
requestedItemName.deleteLastChar();
for (int16 thingType = 0; thingType < 16; ++thingType) { // 16 number of item types
uint16 *thingDataArray = _vm->_dungeonMan->_thingData[thingType];
uint16 thingTypeSize = _vm->_dungeonMan->_thingDataWordCount[thingType];
uint16 thingCount = _vm->_dungeonMan->_dungeonFileHeader._thingCounts[thingType];
Thing dummyThing(0);
dummyThing.setType(thingType);
for (int16 thingIndex = 0; thingIndex < thingCount; ++thingIndex) {
dummyThing.setIndex(thingIndex);
int16 iconIndex = _vm->_objectMan->getIconIndex(dummyThing);
if (iconIndex != -1) {
const char *displayName = _vm->_objectMan->_objectNames[iconIndex];
if (cstrEquals(displayName, requestedItemName.c_str())) {
uint16 *newThingData = new uint16[(thingCount + 1) * thingTypeSize];
memcpy(newThingData, thingDataArray, sizeof(uint16) * thingTypeSize * thingCount);
delete[] thingDataArray;
for (uint16 i = 0; i < thingTypeSize; ++i)
newThingData[thingCount * thingTypeSize + i] = newThingData[thingIndex * thingTypeSize + i];
_vm->_dungeonMan->_dungeonFileHeader._thingCounts[thingType]++;
_vm->_dungeonMan->_thingData[thingType] = newThingData;
_vm->_championMan->addObjectInSlot((ChampionIndex)0, dummyThing, (ChampionSlot)29);
debugPrintf("Item gimmed to the first champion, last slot\n");
return true;
}
}
}
}
debugPrintf("No item found with name '%s'\n", requestedItemName.c_str());
return true;
}
}

60
engines/dm/console.h Normal file
View File

@@ -0,0 +1,60 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_CONSOLE_H
#define DM_CONSOLE_H
#include "gui/debugger.h"
namespace DM {
class DMEngine;
class Console : public GUI::Debugger {
private:
DMEngine *_vm;
bool Cmd_godmode(int argc, const char **argv);
bool Cmd_noclip(int argc, const char **argv);
bool Cmd_pos(int argc, const char **argv);
bool Cmd_map(int argc, const char **argv);
bool Cmd_listItems(int argc, const char **argv);
bool Cmd_gimme(int argc, const char **argv);
const char *debugGetDirectionName(int16 dir);
public:
explicit Console(DM::DMEngine *vm);
~Console(void) override {}
bool _debugGodmodeMana;
bool _debugGodmodeHP;
bool _debugGodmodeStamina;
bool _debugNoclip;
};
}
#endif

4
engines/dm/credits.pl Normal file
View File

@@ -0,0 +1,4 @@
begin_section("DM");
add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
add_person("Bendeg&uacute;z Nagy", "WinterGrascph", "");
end_section();

114
engines/dm/detection.cpp Normal file
View File

@@ -0,0 +1,114 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#include "base/plugins.h"
#include "engines/advancedDetector.h"
#include "dm/detection.h"
namespace DM {
static const PlainGameDescriptor DMGames[] = {
{"dm", "Dungeon Master"},
{nullptr, nullptr}
};
static const DMADGameDescription gameDescriptions[] = {
{
{"dm", "Amiga v2.0 English",
AD_ENTRY2s("graphics.dat", "c2205f6225bde728417de29394f97d55", 411960,
"Dungeon.dat", "43a213da8eda413541dd12f90ce202f6", 25006),
Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, GUIO1(GUIO_NOMIDI)
},
kDMSaveTargetDM21, kDMSaveFormatAmigaPC98FmTowns, kDMSavePlatformAmiga,
{ kDMSaveTargetDM21, kDMSaveTargetEndOfList },
{ kDMSaveFormatAmigaPC98FmTowns, kDMSaveFormatEndOfList},
{ kDMSavePlatformAcceptAny}
},
{
{"dm", "Atari v??? English",
AD_ENTRY2s("graphics.dat", "6ffff2a17e2df0effa9a12fb4b1bf6b6", 271911,
"Dungeon.dat", "be9468b460515741babec9a70501e2e9", 33286),
Common::EN_ANY, Common::kPlatformAtariST, ADGF_NO_FLAGS, GUIO1(GUIO_NOMIDI),
},
kDMSaveTargetDM21, kDMSaveFormatAmigaPC98FmTowns, kDMSavePlatformAtariSt,
{ kDMSaveTargetDM21, kDMSaveTargetEndOfList},
{ kDMSaveFormatAmigaPC98FmTowns, kDMSaveFormatEndOfList},
{ kDMSavePlatformAcceptAny }
},
{
// Added by Strangerke
{"dm", "Amiga Demo v2.0 English",
AD_ENTRY2s("graphics.dat", "3932c8359bb36c24291b09e915114d38", 192421,
"DemoDun.dat", "78848e1a2d3d5a11e5954deb8c7b772b", 1209),
Common::EN_ANY, Common::kPlatformAmiga, ADGF_DEMO, GUIO1(GUIO_NOMIDI),
},
kDMSaveTargetDM21, kDMSaveFormatAmigaPC98FmTowns, kDMSavePlatformAtariSt,
{ kDMSaveTargetDM21, kDMSaveTargetEndOfList},
{ kDMSaveFormatAmigaPC98FmTowns, kDMSaveFormatEndOfList},
{ kDMSavePlatformAcceptAny }
},
{
// Added by trembyle
{"dm", "Apple IIgs Demo v1.4 English",
AD_ENTRY2s("DEMOIIGS.DAT", "6d30bde1f4d7be1cee500e7bb160658b", 190792,
"DEMODUN.DAT", "9c1b9996aceacb3fffb5bd21ca408fa8", 1487),
Common::EN_ANY, Common::kPlatformApple2GS, ADGF_DEMO, GUIO1(GUIO_NOMIDI),
},
kDMSaveTargetDM21, kDMSaveFormatAmigaPC98FmTowns, kDMSavePlatformAtariSt,
{ kDMSaveTargetDM21, kDMSaveTargetEndOfList},
{ kDMSaveFormatAmigaPC98FmTowns, kDMSaveFormatEndOfList},
{ kDMSavePlatformAcceptAny }
},
{
AD_TABLE_END_MARKER, kDMSaveTargetNone, kDMSaveFormatNone, kDMSavePlatformNone,
{kDMSaveTargetNone}, {kDMSaveFormatNone}, {kDMSavePlatformNone}
}
};
class DMMetaEngineDetection : public AdvancedMetaEngineDetection<DMADGameDescription> {
public:
DMMetaEngineDetection() : AdvancedMetaEngineDetection(DM::gameDescriptions, DMGames) {
}
const char *getName() const override {
return "dm";
}
const char *getEngineName() const override {
return "Dungeon Master";
}
const char *getOriginalCopyright() const override {
return "Dungeon Master (C) 1987 FTL Games";
}
};
} // End of namespace DM
REGISTER_PLUGIN_STATIC(DM_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, DM::DMMetaEngineDetection);

86
engines/dm/detection.h Normal file
View File

@@ -0,0 +1,86 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_DETECTION_H
#define DM_DETECTION_H
#include "engines/advancedDetector.h"
namespace DM {
enum OriginalSaveFormat {
kDMSaveFormatAcceptAny = -1,
kDMSaveFormatEndOfList = 0,
kDMSaveFormatNone = 0,
kDMSaveFormatAtari = 1,
kDMSaveFormatAmigaPC98FmTowns = 2,
kCSBSaveFormatAtari = 2,
kDMSaveFormatAppleIIgs = 3,
kDMSaveFormatAmiga36PC = 5,
kCSBSaveFormatAmigaPC98FmTowns = 5,
kDMSaveFormatTotal
};
enum OriginalSavePlatform {
kDMSavePlatformAcceptAny = -1,
kDMSavePlatformEndOfList = 0,
kDMSavePlatformNone = 0,
kDMSavePlatformAtariSt = 1, // @ C1_PLATFORM_ATARI_ST
kDMSavePlatformAppleIIgs = 2, // @ C2_PLATFORM_APPLE_IIGS
kDMSavePlatformAmiga = 3, // @ C3_PLATFORM_AMIGA
kDMSavePlatformPC98 = 5, // @ C5_PLATFORM_PC98
kDMSavePlatformX68000 = 6, // @ C6_PLATFORM_X68000
kDMSavePlatformFmTownsEN = 7, // @ C7_PLATFORM_FM_TOWNS_EN
kDMSavePlatformFmTownsJP = 8, // @ C8_PLATFORM_FM_TOWNS_JP
kDMSavePlatformPC = 9, // @ C9_PLATFORM_PC
kDMSavePlatformTotal
};
enum SaveTarget {
kDMSaveTargetAcceptAny = -1,
kDMSaveTargetEndOfList = 0,
kDMSaveTargetNone = 0,
kDMSaveTargetDM21 = 1,
kDMSaveTargetTotal
};
struct DMADGameDescription {
AD_GAME_DESCRIPTION_HELPERS(_desc);
ADGameDescription _desc;
SaveTarget _saveTargetToWrite;
OriginalSaveFormat _origSaveFormatToWrite;
OriginalSavePlatform _origPlatformToWrite;
SaveTarget _saveTargetToAccept[kDMSaveTargetTotal + 1];
OriginalSaveFormat _saveFormatToAccept[kDMSaveFormatTotal + 1];
OriginalSavePlatform _origPlatformToAccept[kDMSavePlatformTotal + 1];
};
} // End of namespace DM
#endif // DM_DETECTION_H

270
engines/dm/dialog.cpp Normal file
View File

@@ -0,0 +1,270 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#include "dm/dialog.h"
#include "dm/gfx.h"
#include "dm/text.h"
#include "dm/eventman.h"
#include "backends/keymapper/keymapper.h"
namespace DM {
DialogMan::DialogMan(DMEngine *vm) : _vm(vm) {
_selectedDialogChoice = 0;
}
void DialogMan::dialogDraw(const char *msg1, const char *msg2, const char *choice1, const char *choice2, const char *choice3, const char *choice4, bool screenDialog, bool clearScreen, bool fading) {
static Box constBox1 = Box(0, 223, 101, 125);
static Box constBox2 = Box(0, 223, 76, 100);
static Box constBox3 = Box(0, 223, 51, 75);
static Box dialog2ChoicesPatch = Box(102, 122, 89, 125);
static Box dialog4ChoicesPatch = Box(102, 122, 62, 97);
EventManager &evtMan = *_vm->_eventMan;
DisplayMan &displMan = *_vm->_displayMan;
TextMan &txtMan = *_vm->_textMan;
displMan.loadIntoBitmap(kDMGraphicIdxDialogBox, displMan._bitmapViewport);
//Strangerke: the version should be replaced by a ScummVM/RogueVM (?) string
// TODO: replace with ScummVM version string
txtMan.printTextToBitmap(displMan._bitmapViewport, k112_byteWidthViewport, 192, 7, kDMColorLightGray, kDMColorDarkGary, "V2.2", k136_heightViewport);
int16 choiceCount = 1;
if (choice2)
choiceCount++;
if (choice3)
choiceCount++;
if (choice4)
choiceCount++;
if (fading)
displMan.startEndFadeToPalette(displMan._blankBuffer);
if (clearScreen)
displMan.fillScreen(kDMColorBlack);
displMan._useByteBoxCoordinates = false;
if (choiceCount == 1) {
displMan.blitToBitmap(displMan._bitmapViewport, displMan._bitmapViewport, constBox1, 0, 64, k112_byteWidthViewport, k112_byteWidthViewport, kDMColorNoTransparency, k136_heightViewport, k136_heightViewport);
displMan.blitToBitmap(displMan._bitmapViewport, displMan._bitmapViewport, constBox2, 0, 39, k112_byteWidthViewport, k112_byteWidthViewport, kDMColorNoTransparency, k136_heightViewport, k136_heightViewport);
displMan.blitToBitmap(displMan._bitmapViewport, displMan._bitmapViewport, constBox3, 0, 14, k112_byteWidthViewport, k112_byteWidthViewport, kDMColorNoTransparency, k136_heightViewport, k136_heightViewport);
printCenteredChoice(displMan._bitmapViewport, choice1, 112, 114);
} else if (choiceCount == 2) {
displMan.blitToBitmap(displMan._bitmapViewport, displMan._bitmapViewport, dialog2ChoicesPatch, 102, 52, k112_byteWidthViewport, k112_byteWidthViewport, kDMColorNoTransparency, k136_heightViewport, k136_heightViewport);
printCenteredChoice(displMan._bitmapViewport, choice1, 112, 77);
printCenteredChoice(displMan._bitmapViewport, choice2, 112, 114);
} else if (choiceCount == 3) {
printCenteredChoice(displMan._bitmapViewport, choice1, 112, 77);
printCenteredChoice(displMan._bitmapViewport, choice2, 59, 114);
printCenteredChoice(displMan._bitmapViewport, choice3, 166, 114);
} else if (choiceCount == 4) {
displMan.blitToBitmap(displMan._bitmapViewport, displMan._bitmapViewport, dialog4ChoicesPatch, 102, 99, k112_byteWidthViewport, k112_byteWidthViewport, kDMColorNoTransparency, k136_heightViewport, k136_heightViewport);
printCenteredChoice(displMan._bitmapViewport, choice1, 59, 77);
printCenteredChoice(displMan._bitmapViewport, choice2, 166, 77);
printCenteredChoice(displMan._bitmapViewport, choice3, 59, 114);
printCenteredChoice(displMan._bitmapViewport, choice4, 166, 114);
}
int16 textPosX;
int16 textPosY = 29;
if (msg1) {
char L1312_ac_StringPart1[70];
char L1313_ac_StringPart2[70];
if (isMessageOnTwoLines(msg1, L1312_ac_StringPart1, L1313_ac_StringPart2)) {
textPosY = 21;
textPosX = 113 - ((strlen(L1312_ac_StringPart1) * 6) >> 1);
txtMan.printTextToBitmap(displMan._bitmapViewport, k112_byteWidthViewport, textPosX, textPosY, kDMColorYellow, kDMColorLightBrown, L1312_ac_StringPart1, k136_heightViewport);
textPosY += 8;
textPosX = 113 - ((strlen(L1313_ac_StringPart2) * 6) >> 1);
txtMan.printTextToBitmap(displMan._bitmapViewport, k112_byteWidthViewport, textPosX, textPosY, kDMColorYellow, kDMColorLightBrown, L1313_ac_StringPart2, k136_heightViewport);
textPosY += 8;
} else {
textPosX = 113 - ((strlen(msg1) * 6) >> 1);
txtMan.printTextToBitmap(displMan._bitmapViewport, k112_byteWidthViewport, textPosX, textPosY, kDMColorYellow, kDMColorLightBrown, msg1, k136_heightViewport);
textPosY += 8;
}
}
if (msg2) {
char L1312_ac_StringPart1[70];
char L1313_ac_StringPart2[70];
if (isMessageOnTwoLines(msg2, L1312_ac_StringPart1, L1313_ac_StringPart2)) {
textPosX = 113 - ((strlen(L1312_ac_StringPart1) * 6) >> 1);
txtMan.printTextToBitmap(displMan._bitmapViewport, k112_byteWidthViewport, textPosX, textPosY, kDMColorGold, kDMColorLightBrown, L1312_ac_StringPart1, k136_heightViewport);
textPosY += 8;
textPosX = 113 - ((strlen(L1313_ac_StringPart2) * 6) >> 1);
txtMan.printTextToBitmap(displMan._bitmapViewport, k112_byteWidthViewport, textPosX, textPosY, kDMColorGold, kDMColorLightBrown, L1313_ac_StringPart2, k136_heightViewport);
} else {
textPosX = 113 - ((strlen(msg2) * 6) >> 1);
txtMan.printTextToBitmap(displMan._bitmapViewport, k112_byteWidthViewport, textPosX, textPosY, kDMColorGold, kDMColorLightBrown, msg2, k136_heightViewport);
}
}
if (screenDialog) {
Box displayBox(47, 270, 33, 168);
evtMan.showMouse();
displMan.blitToScreen(displMan._bitmapViewport, &displayBox, k112_byteWidthViewport, kDMColorNoTransparency, k136_heightViewport);
evtMan.hideMouse();
} else {
displMan.drawViewport(k0_viewportNotDungeonView);
_vm->delay(1);
}
if (fading)
displMan.startEndFadeToPalette(displMan._paletteTopAndBottomScreen);
displMan._drawFloorAndCeilingRequested = true;
displMan.updateScreen();
}
void DialogMan::printCenteredChoice(byte *bitmap, const char *str, int16 posX, int16 posY) {
if (str) {
posX -= (strlen(str) * 6) >> 1;
_vm->_textMan->printTextToBitmap(bitmap, k112_byteWidthViewport, posX, posY, kDMColorGold, kDMColorLightBrown, str, k136_heightViewport);
}
}
bool DialogMan::isMessageOnTwoLines(const char *str, char *part1, char *part2) {
uint16 strLength = strlen(str);
if (strLength <= 30)
return false;
Common::strcpy_s(part1, 70, str);
uint16 splitPosition = strLength >> 1;
while ((splitPosition < strLength) && (part1[splitPosition] != ' '))
splitPosition++;
part1[splitPosition] = '\0';
Common::strcpy_s(part2, 70, &part1[splitPosition + 1]);
return true;
}
int16 DialogMan::getChoice(uint16 choiceCount, uint16 dialogSetIndex, int16 driveType, int16 automaticChoiceIfFlopyInDrive) {
EventManager &evtMan = *_vm->_eventMan;
DisplayMan &displMan = *_vm->_displayMan;
evtMan.hideMouse();
MouseInput *primaryMouseInputBackup = evtMan._primaryMouseInput;
MouseInput *secondaryMouseInputBackup = evtMan._secondaryMouseInput;
KeyboardInput *primaryKeyboardInputBackup = evtMan._primaryKeyboardInput;
KeyboardInput *secondaryKeyboardInputBackup = evtMan._secondaryKeyboardInput;
evtMan._secondaryMouseInput = nullptr;
evtMan._primaryKeyboardInput = nullptr;
evtMan._secondaryKeyboardInput = nullptr;
evtMan._primaryMouseInput = evtMan._primaryMouseInputDialogSets[dialogSetIndex][choiceCount - 1];
evtMan.discardAllInput();
_selectedDialogChoice = 99;
Common::Keymapper *keymapper = _vm->getEventManager()->getKeymapper();
keymapper->getKeymap("game-shortcuts")->setEnabled(false);
keymapper->getKeymap("choice-selection")->setEnabled(true);
do {
Common::Event key;
Common::EventType eventType = evtMan.processInput(&key);
evtMan.processCommandQueue();
_vm->delay(1);
displMan.updateScreen();
if ((_selectedDialogChoice == 99) && (choiceCount == 1)
&& (eventType == Common::EVENT_CUSTOM_ENGINE_ACTION_START) && key.customType == kActionSelectChoice) {
/* If a choice has not been made yet with the mouse and the dialog has only one possible choice and carriage return was pressed on the keyboard */
_selectedDialogChoice = kDMDialogChoice1;
}
} while (_selectedDialogChoice == 99);
keymapper->getKeymap("choice-selection")->setEnabled(false);
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
displMan._useByteBoxCoordinates = false;
Box boxA = evtMan._primaryMouseInput[_selectedDialogChoice - 1]._hitbox;
boxA._rect.left -= 3;
boxA._rect.right += 3;
boxA._rect.top -= 3;
boxA._rect.bottom += 4;
evtMan.showMouse();
displMan._drawFloorAndCeilingRequested = true;
Box boxB(0, 0, boxA._rect.right - boxA._rect.left + 3, boxA._rect.bottom - boxA._rect.top + 3);
displMan.blitToBitmap(displMan._bitmapScreen, displMan._bitmapViewport,
boxB, boxA._rect.left, boxA._rect.top, k160_byteWidthScreen, k160_byteWidthScreen, kDMColorNoTransparency, 200, 25);
_vm->delay(1);
boxB = boxA;
boxB._rect.bottom = boxB._rect.top;
displMan.fillScreenBox(boxB, kDMColorLightBrown);
boxB = boxA;
boxB._rect.right = boxB._rect.left;
boxB._rect.bottom--;
displMan.fillScreenBox(boxB, kDMColorLightBrown);
boxB = boxA;
boxB._rect.bottom--;
boxB._rect.top = boxB._rect.bottom;
boxB._rect.left -= 2;
displMan.fillScreenBox(boxB, kDMColorBlack);
boxB = boxA;
boxB._rect.left = boxB._rect.right;
displMan.fillScreenBox(boxB, kDMColorBlack);
_vm->delay(2);
boxB = boxA;
boxB._rect.top++;
boxB._rect.bottom = boxB._rect.top;
boxB._rect.right -= 2;
displMan.fillScreenBox(boxB, kDMColorLightBrown);
boxB = boxA;
boxB._rect.left++;
boxB._rect.right = boxB._rect.left;
boxB._rect.bottom--;
displMan.fillScreenBox(boxB, kDMColorLightBrown);
boxB = boxA;
boxB._rect.right--;
boxB._rect.left = boxB._rect.right;
displMan.fillScreenBox(boxB, kDMColorBlack);
boxB = boxA;
boxB._rect.top = boxB._rect.bottom = boxB._rect.bottom - 2;
boxB._rect.left++;
displMan.fillScreenBox(boxB, kDMColorBlack);
boxB = boxA;
boxB._rect.top = boxB._rect.bottom = boxB._rect.bottom + 2;
boxB._rect.left--;
boxB._rect.right += 2;
displMan.fillScreenBox(boxB, kDMColorLightestGray);
boxB = boxA;
boxB._rect.left = boxB._rect.right = boxB._rect.right + 3;
boxB._rect.bottom += 2;
displMan.fillScreenBox(boxB, kDMColorLightestGray);
_vm->delay(2);
boxA._rect.right += 3;
boxA._rect.bottom += 3;
displMan.blitToBitmap(displMan._bitmapViewport, displMan._bitmapScreen,
boxA, 0, 0, k160_byteWidthScreen, k160_byteWidthScreen, kDMColorNoTransparency, 25, k200_heightScreen);
evtMan.hideMouse();
evtMan._primaryMouseInput = primaryMouseInputBackup;
evtMan._secondaryMouseInput = secondaryMouseInputBackup;
evtMan._primaryKeyboardInput = primaryKeyboardInputBackup;
evtMan._secondaryKeyboardInput = secondaryKeyboardInputBackup;
evtMan.discardAllInput();
evtMan.showMouse();
return _selectedDialogChoice;
}
}

62
engines/dm/dialog.h Normal file
View File

@@ -0,0 +1,62 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_DIALOG_H
#define DM_DIALOG_H
#include "dm/dm.h"
namespace DM {
enum DialogCommand {
kDMDialogCommandSetViewport = 0,
kDMDialogCommandSetScreen = 1,
kDMDialogCommandSetUnknown = 2
};
enum DialogChoice {
kDMDialogChoiceNone = 0,
kDMDialogChoice1 = 1,
kDMDialogChoice2 = 2,
kDMDialogChoice3 = 3,
kDMDialogChoice4 = 4
};
class DialogMan {
DMEngine *_vm;
public:
uint16 _selectedDialogChoice; // @ G0335_ui_SelectedDialogChoice
explicit DialogMan(DMEngine *vm);
void dialogDraw(const char *msg1, const char *msg2, const char *choice1, const char *choice2,
const char *choice3, const char *choice4, bool screenDialog, bool clearScreen, bool fading); // @ F0427_DIALOG_Draw
void printCenteredChoice(byte *bitmap, const char *str, int16 posX, int16 posY); // @ F0425_DIALOG_PrintCenteredChoice
bool isMessageOnTwoLines(const char *str, char *part1, char *part2); // @ F0426_DIALOG_IsMessageOnTwoLines
int16 getChoice(uint16 choiceCount, uint16 dialogSetIndex, int16 driveType, int16 automaticChoiceIfFlopyInDrive); // @ F0424_DIALOG_GetChoice
};
}
#endif

1043
engines/dm/dm.cpp Normal file

File diff suppressed because it is too large Load Diff

304
engines/dm/dm.h Normal file
View File

@@ -0,0 +1,304 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_DM_H
#define DM_DM_H
#include "engines/engine.h"
#include "engines/savestate.h"
#include "common/random.h"
#include "common/savefile.h"
#include "common/str.h"
#include "common/memstream.h"
#include "advancedDetector.h"
#include "dm/console.h"
#include "dm/detection.h"
namespace DM {
class DisplayMan;
class DungeonMan;
class EventManager;
class MenuMan;
class ChampionMan;
class ObjectMan;
class InventoryMan;
class TextMan;
class MovesensMan;
class GroupMan;
class Timeline;
class ProjExpl;
class DialogMan;
class SoundMan;
enum DMActions {
kActionNone,
kActionToggleInventoryChampion0,
kActionToggleInventoryChampion1,
kActionToggleInventoryChampion2,
kActionToggleInventoryChampion3,
kActionSave,
kActionFreezeGame,
kActionTurnLeft,
kActionMoveForward,
kActionTurnRight,
kActionMoveLeft,
kActionMoveBackward,
kActionMoveRight,
kActionWakeUp,
kActionSelectChoice,
};
enum Direction {
kDMDirNorth = 0,
kDMDirEast = 1,
kDMDirSouth = 2,
kDMDirWest = 3
};
enum ThingType {
kDMThingTypeParty = -1, // @ CM1_THING_TYPE_PARTY
kDMThingTypeDoor = 0, // @ C00_THING_TYPE_DOOR
kDMThingTypeTeleporter = 1, // @ C01_THING_TYPE_TELEPORTER
kDMstringTypeText = 2, // @ C02_THING_TYPE_TEXTSTRING
kDMThingTypeSensor = 3, // @ C03_THING_TYPE_SENSOR
kDMThingTypeGroup = 4, // @ C04_THING_TYPE_GROUP
kDMThingTypeWeapon = 5, // @ C05_THING_TYPE_WEAPON
kDMThingTypeArmour = 6, // @ C06_THING_TYPE_ARMOUR
kDMThingTypeScroll = 7, // @ C07_THING_TYPE_SCROLL
kDMThingTypePotion = 8, // @ C08_THING_TYPE_POTION
kDMThingTypeContainer = 9, // @ C09_THING_TYPE_CONTAINER
kDMThingTypeJunk = 10, // @ C10_THING_TYPE_JUNK
kDMThingTypeProjectile = 14, // @ C14_THING_TYPE_PROJECTILE
kDMThingTypeExplosion = 15, // @ C15_THING_TYPE_EXPLOSION
kDMThingTypeTotal = 16 // +1 than the last (explosionThingType)
}; // @ C[00..15]_THING_TYPE_...
enum Cell {
kDMCellAny = -1, // @ CM1_CELL_ANY
kDMCellNorthWest = 0, // @ C00_CELL_NORTHWEST
kDMCellNorthEast = 1, // @ C01_CELL_NORTHEAST
kDMCellSouthEast = 2, // @ C02_CELL_SOUTHEAST
kDMCellSouthWest = 3 // @ C03_CELL_SOUTHWEST
};
enum GameMode {
kDMModeLoadSavedGame = 0, // @ C000_MODE_LOAD_SAVED_GAME
kDMModeLoadDungeon = 1, // @ C001_MODE_LOAD_DUNGEON
kDMModeWaitingOnEntrance = 99, // @ C099_MODE_WAITING_ON_ENTRANCE
kDMModeEntranceDrawCredits = 202 // @ C202_MODE_ENTRANCE_DRAW_CREDITS
};
enum LoadgameResult {
kDMLoadgameFailure = -1, // @ CM1_LOAD_GAME_FAILURE
kDMLoadgameSuccess = 1// @ C01_LOAD_GAME_SUCCESS
};
enum MapIndice {
kDMMapIndexNone = -1, // @ CM1_MAP_INDEX_NONE
kDMMapIndexEntrance = 255 // @ C255_MAP_INDEX_ENTRANCE
};
#define kDMMaskDecodeEvenIfInvisible 0x8000 // @ MASK0x8000_DECODE_EVEN_IF_INVISIBLE
#define kDMMaskMergeCycles 0x8000 // @ MASK0x8000_MERGE_CYCLES
#define kDMSlotBoxInventoryFirstSlot 8 // @ C08_SLOT_BOX_INVENTORY_FIRST_SLOT
#define kDMSlotBoxInventoryActionHand 9 // @ C09_SLOT_BOX_INVENTORY_ACTION_HAND
#define kDMSlotBoxChestFirstSlot 38 // @ C38_SLOT_BOX_CHEST_FIRST_SLOT
class Thing {
public:
uint16 _data;
Thing() : _data(0) {}
explicit Thing(uint16 d) { set(d); }
void set(uint16 d) {
_data = d;
}
byte getCell() const { return _data >> 14; }
ThingType getType() const { return (ThingType)((_data >> 10) & 0xF); }
uint16 getIndex() const { return _data & 0x3FF; }
void setCell(uint16 cell) { _data = (_data & ~(0x3 << 14)) | ((cell & 0x3) << 14); }
void setType(uint16 type) { _data = (_data & ~(0xF << 10)) | ((type & 0xF) << 10); }
void setIndex(uint16 index) { _data = (_data & ~0x3FF) | (index & 0x3FF); }
uint16 getTypeAndIndex() { return _data & 0x3FFF; }
uint16 toUint16() const { return _data; } // I don't like 'em cast operators
bool operator==(const Thing &rhs) const { return _data == rhs._data; }
bool operator!=(const Thing &rhs) const { return _data != rhs._data; }
}; // @ THING
#define setFlag(val, mask) ((val) |= (mask))
#define getFlag(val, mask) ((val) & (mask))
#define clearFlag(val, mask) ((val) &= (~(mask))) // @ M09_CLEAR
// Note: F0026_MAIN_GetBoundedValue<T> has been replaced by CLIP<T>
#define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember))
struct SaveGameHeader {
byte _version;
SaveStateDescriptor _descr;
};
class DMEngine : public Engine {
private:
void startGame(); // @ F0462_START_StartGame_CPSF
void processNewPartyMap(uint16 mapIndex); // @ F0003_MAIN_ProcessNewPartyMap_CPSE
void initializeGame(); // @ F0463_START_InitializeGame_CPSADEF
void initMemoryManager(); // @ F0448_STARTUP1_InitializeMemoryManager_CPSADEF
void gameloop(); // @ F0002_MAIN_GameLoop_CPSDF
void initConstants();
Common::String getSavefileName(uint16 slot);
void writeSaveGameHeader(Common::OutSaveFile *out, const Common::String &saveName);
bool writeCompleteSaveFile(int16 slot, Common::String &desc, int16 saveAndPlayChoice);
void drawEntrance(); // @ F0439_STARTEND_DrawEntrance
void fuseSequenceUpdate(); // @ F0445_STARTEND_FuseSequenceUpdate
void processEntrance(); // @ F0441_STARTEND_ProcessEntrance
void openEntranceDoors(); // @ F0438_STARTEND_OpenEntranceDoors
void drawTittle(); // @ F0437_STARTEND_DrawTitle
public:
explicit DMEngine(OSystem *syst, const DMADGameDescription *gameDesc);
~DMEngine() override;
bool hasFeature(EngineFeature f) const override;
Common::Error loadGameState(int slot) override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
bool isDemo() const;
void delay(uint16 verticalBlank); // @ F0022_MAIN_Delay
uint16 getScaledProduct(uint16 val, uint16 scale, uint16 vale2); // @ F0030_MAIN_GetScaledProduct
uint16 getRandomNumber(uint32 max) { return _rnd->getRandomNumber(max - 1); }
int16 ordinalToIndex(int16 val); // @ M01_ORDINAL_TO_INDEX
int16 indexToOrdinal(int16 val); // @ M00_INDEX_TO_ORDINAL
Common::Error run() override; // @ main
void saveGame(); // @ F0433_STARTEND_ProcessCommand140_SaveGame_CPSCDF
LoadgameResult loadgame(int16 slot); // @ F0435_STARTEND_LoadGame_CPSF
void endGame(bool doNotDrawCreditsOnly); // @ F0444_STARTEND_Endgame
void entranceDrawCredits();
void fuseSequence(); // @ F0446_STARTEND_FuseSequence
Common::Language getGameLanguage();
Direction turnDirRight(int16 dir); // @ M17_NEXT
Direction turnDirLeft(int16 dir); // @ M19_PREVIOUS
Direction returnOppositeDir(int16 dir); // @ M18_OPPOSITE
bool isOrientedWestEast(int16 dir); // @ M16_IS_ORIENTED_WEST_EAST
uint16 normalizeModulo4(int16 dir); // @ M21_NORMALIZE
int32 filterTime(int32 mapTime); // @ M30_TIME
int32 setMapAndTime(uint32 map, uint32 time); // @ M33_SET_MAP_AND_TIME
uint16 getMap(int32 mapTime); // @ M29_MAP
Thing thingWithNewCell(Thing thing, int16 cell); // @ M15_THING_WITH_NEW_CELL
int16 getDistance(int16 mapx1, int16 mapy1, int16 mapx2, int16 mapy2); // @ M38_DISTANCE
int32 setMap(int32 mapTime, uint32 map); // @ M31_setMap
private:
uint16 _dungeonId; // @ G0526_ui_DungeonID
byte *_entranceDoorAnimSteps[10]; // @ G0562_apuc_Bitmap_EntranceDoorAnimationSteps
byte *_interfaceCredits; // @ G0564_puc_Graphic5_InterfaceCredits
Common::RandomSource *_rnd;
byte *_savedScreenForOpenEntranceDoors; // ad-hoc HACK
const DMADGameDescription *_gameVersion;
bool _canLoadFromGMM;
public:
Console *_console;
DisplayMan *_displayMan;
DungeonMan *_dungeonMan;
EventManager *_eventMan;
MenuMan *_menuMan;
ChampionMan *_championMan;
ObjectMan *_objectMan;
InventoryMan *_inventoryMan;
TextMan *_textMan;
MovesensMan *_moveSens;
GroupMan *_groupMan;
Timeline *_timeline;
ProjExpl *_projexpl;
DialogMan *_dialog;
SoundMan *_sound;
Common::MemoryWriteStreamDynamic *_saveThumbnail;
bool _engineShouldQuit;
int _loadSaveSlotAtRuntime;
GameMode _gameMode; // @ G0298_B_NewGame
bool _restartGameRequest; // @ G0523_B_RestartGameRequested
bool _stopWaitingForPlayerInput; // @ G0321_B_StopWaitingForPlayerInput
bool _gameTimeTicking; // @ G0301_B_GameTimeTicking
bool _restartGameAllowed; // @ G0524_B_RestartGameAllowed
bool _pressingEye; // @ G0331_B_PressingEye
bool _stopPressingEye; // @ G0332_B_StopPressingEye
bool _pressingMouth; // @ G0333_B_PressingMouth
bool _stopPressingMouth; // @ G0334_B_StopPressingMouth
bool _highlightBoxInversionRequested; // @ G0340_B_HighlightBoxInversionRequested
int16 _projectileDisableMovementTicks; // @ G0311_i_ProjectileDisabledMovementTicks
int16 _lastProjectileDisabledMovementDirection; // @ G0312_i_LastProjectileDisabledMovementDirection
bool _gameWon; // @ G0302_B_GameWon
int16 _newPartyMapIndex; // @ G0327_i_NewPartyMapIndex
bool _setMousePointerToObjectInMainLoop; // @ G0325_B_SetMousePointerToObjectInMainLoop
int16 _disabledMovementTicks; // @ G0310_i_DisabledMovementTicks
int8 _dirIntoStepCountEast[4]; // @ G0233_ai_Graphic559_DirectionToStepEastCount
int8 _dirIntoStepCountNorth[4]; // @ G0234_ai_Graphic559_DirectionToStepNorthCount
int32 _gameTime; // @ G0313_ul_GameTime
char _stringBuildBuffer[128]; // @ G0353_ac_StringBuildBuffer
int16 _waitForInputMaxVerticalBlankCount; // @ G0318_i_WaitForInputMaximumVerticalBlankCount
Thing _thingNone; // @ C0xFFFF_THING_NONE
Thing _thingEndOfList; // @ C0xFFFE_THING_ENDOFLIST
Thing _thingFirstExplosion; // @ C0xFF80_THING_FIRST_EXPLOSION
Thing _thingExplFireBall; // @ C0xFF80_THING_EXPLOSION_FIREBALL
Thing _thingExplSlime; // @ C0xFF81_THING_EXPLOSION_SLIME
Thing _thingExplLightningBolt; // @ C0xFF82_THING_EXPLOSION_LIGHTNING_BOLT
Thing _thingExplHarmNonMaterial; // @ C0xFF83_THING_EXPLOSION_HARM_NON_MATERIAL
Thing _thingExplOpenDoor; // @ C0xFF84_THING_EXPLOSION_OPEN_DOOR
Thing _thingExplPoisonBolt; // @ C0xFF86_THING_EXPLOSION_POISON_BOLT
Thing _thingExplPoisonCloud; // @ C0xFF87_THING_EXPLOSION_POISON_CLOUD
Thing _thingExplSmoke; // @ C0xFFA8_THING_EXPLOSION_SMOKE
Thing _thingExplFluxcage; // @ C0xFFB2_THING_EXPLOSION_FLUXCAGE
Thing _thingExplRebirthStep1; // @ C0xFFE4_THING_EXPLOSION_REBIRTH_STEP1
Thing _thingExplRebirthStep2; // @ C0xFFE5_THING_EXPLOSION_REBIRTH_STEP2
Thing _thingParty; // @ C0xFFFF_THING_PARTY
};
WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header, bool skipThumbnail = true);
} // End of namespace DM
#endif

57
engines/dm/dmglobals.cpp Normal file
View File

@@ -0,0 +1,57 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#include "common/system.h"
#include "dm/dm.h"
#include "dm/gfx.h"
#include "dm/dungeonman.h"
#include "dm/eventman.h"
#include "dm/menus.h"
#include "dm/champion.h"
#include "dm/loadsave.h"
#include "dm/objectman.h"
#include "dm/inventory.h"
#include "dm/text.h"
#include "dm/movesens.h"
namespace DM {
void DMEngine::initConstants() {
// G0233_ai_Graphic559_DirectionToStepEastCount
_dirIntoStepCountEast[0] = 0; // North
_dirIntoStepCountEast[1] = 1; // East
_dirIntoStepCountEast[2] = 0; // West
_dirIntoStepCountEast[3] = -1; // South
// G0234_ai_Graphic559_DirectionToStepNorthCount
_dirIntoStepCountNorth[0] = -1; // North
_dirIntoStepCountNorth[1] = 0; // East
_dirIntoStepCountNorth[2] = 1; // West
_dirIntoStepCountNorth[3] = 0; // South
}
} // End of namespace DM

1694
engines/dm/dungeonman.cpp Normal file

File diff suppressed because it is too large Load Diff

711
engines/dm/dungeonman.h Normal file
View File

@@ -0,0 +1,711 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_DUNGEONMAN_H
#define DM_DUNGEONMAN_H
#include "dm/dm.h"
#include "dm/gfx.h"
namespace DM {
/* Object info */
enum ObjectInfoIndexConst {
kDMObjectInfoIndexFirstScroll = 0, // @ C000_OBJECT_INFO_INDEX_FIRST_SCROLL
kDMObjectInfoIndexFirstContainer = 1, // @ C001_OBJECT_INFO_INDEX_FIRST_CONTAINER
kDMObjectInfoIndexFirstPotion = 2, // @ C002_OBJECT_INFO_INDEX_FIRST_POTION
kDMObjectInfoIndexFirstWeapon = 23, // @ C023_OBJECT_INFO_INDEX_FIRST_WEAPON
kDMObjectInfoIndexFirstArmour = 69, // @ C069_OBJECT_INFO_INDEX_FIRST_ARMOUR
kDMObjectInfoIndexFirstJunk = 127 // @ C127_OBJECT_INFO_INDEX_FIRST_JUNK
};
#define kDMMapXNotOnASquare -1 // @ CM1_MAPX_NOT_ON_A_SQUARE
enum ElementType {
kDMElementTypeChampion = -2, // @ CM2_ELEMENT_CHAMPION /* Values -2 and -1 are only used as projectile impact types */
kDMElementTypeCreature = -1, // @ CM1_ELEMENT_CREATURE
kDMElementTypeWall = 0, // @ C00_ELEMENT_WALL /* Values 0-6 are used as square types and projectile impact types. Values 0-2 and 5-6 are also used for square aspect */
kDMElementTypeCorridor = 1, // @ C01_ELEMENT_CORRIDOR
kDMElementTypePit = 2, // @ C02_ELEMENT_PIT
kDMElementTypeStairs = 3, // @ C03_ELEMENT_STAIRS
kDMElementTypeDoor = 4, // @ C04_ELEMENT_DOOR
kDMElementTypeTeleporter = 5, // @ C05_ELEMENT_TELEPORTER
kDMElementTypeFakeWall = 6, // @ C06_ELEMENT_FAKEWALL
kDMElementTypeDoorSide = 16, // @ C16_ELEMENT_DOOR_SIDE /* Values 16-19 are only used for square aspect */
kDMElementTypeDoorFront = 17, // @ C17_ELEMENT_DOOR_FRONT
kDMElementTypeStairsSide = 18, // @ C18_ELEMENT_STAIRS_SIDE
kDMElementTypeStairsFront = 19 // @ C19_ELEMENT_STAIRS_FRONT
};
enum ObjectAllowedSlot {
kDMMaskMouth = 0x0001, // @ MASK0x0001_MOUTH
kDMMaskHead = 0x0002, // @ MASK0x0002_HEAD
kDMMaskNeck = 0x0004, // @ MASK0x0004_NECK
kDMMaskTorso = 0x0008, // @ MASK0x0008_TORSO
kDMMaskLegs = 0x0010, // @ MASK0x0010_LEGS
kDMMaskFeet = 0x0020, // @ MASK0x0020_FEET
kDMMaskQuiverLine1 = 0x0040, // @ MASK0x0040_QUIVER_LINE1
kDMMaskQuiverLine2 = 0x0080, // @ MASK0x0080_QUIVER_LINE2
kDMMaskPouchPassAndThroughDoors = 0x0100, // @ MASK0x0100_POUCH_PASS_AND_THROUGH_DOORS
kDMMaskHands = 0x0200, // @ MASK0x0200_HANDS
kDMMaskContainer = 0x0400, // @ MASK0x0400_CONTAINER
kDMMaskFootprints = 0x8000, // @ MASK0x8000_FOOTPRINTS
kDMMaskRandomDrop = 0x8000 // @ MASK0x8000_RANDOM_DROP
};
enum ArmourAttribute {
kDMArmourAttributeShield = 0x0080, // @ MASK0x0080_IS_A_SHIELD
kDMArmourAttributeSharpDefense = 0x0007 // @ MASK0x0007_SHARP_DEFENSE
};
enum WeaponClass {
kDMWeaponClassNone = -1,
/* Class 0: SWING weapons */
kDMWeaponClassSwingWeapon = 0, // @ C000_CLASS_SWING_WEAPON
/* Class 1 to 15: THROW weapons */
kDMWeaponClassDaggerAndAxes = 2, // @ C002_CLASS_DAGGER_AND_AXES
kDMWeaponClassBowAmmunition = 10, // @ C010_CLASS_BOW_AMMUNITION
kDMWeaponClassSlingAmmunition = 11, // @ C011_CLASS_SLING_AMMUNITION
kDMWeaponClassPoisinDart = 12, // @ C012_CLASS_POISON_DART
/* Class 16 to 111: SHOOT weapons */
kDMWeaponClassFirstBow = 16, // @ C016_CLASS_FIRST_BOW
kDMWeaponClassLastBow = 31, // @ C031_CLASS_LAST_BOW
kDMWeaponClassFirstSling = 32, // @ C032_CLASS_FIRST_SLING
kDMWeaponClassLastSling = 47, // @ C047_CLASS_LAST_SLING
/* Class 112 to 255: Magic and special weapons */
kDMWeaponClassFirstMagicWeapon = 112 // @ C112_CLASS_FIRST_MAGIC_WEAPON
};
enum TextType {
/* Used for text on walls */
kDMTextTypeInscription = 0, // @ C0_TEXT_TYPE_INSCRIPTION
/* Used for messages displayed when the party walks on a square */
kDMTextTypeMessage = 1, // @ C1_TEXT_TYPE_MESSAGE
/* Used for text on scrolls and champion information */
kDMTextTypeScroll = 2 // @ C2_TEXT_TYPE_SCROLL
};
enum SquareAspect {
kDMSquareAspectElement = 0, // @ C0_ELEMENT
kDMSquareAspectFirstGroupOrObject = 1, // @ C1_FIRST_GROUP_OR_OBJECT
kDMSquareAspectRightWallOrnOrd = 2, // @ C2_RIGHT_WALL_ORNAMENT_ORDINAL
kDMSquareFrontWallOrnOrd = 3, // @ C3_FRONT_WALL_ORNAMENT_ORDINAL
kDMSquareAspectLeftWallOrnOrd = 4, // @ C4_LEFT_WALL_ORNAMENT_ORDINAL
kDMSquareAspectPitInvisible = 2, // @ C2_PIT_INVISIBLE
kDMSquareAspectTeleporterVisible = 2, // @ C2_TELEPORTER_VISIBLE
kDMSquareAspectStairsUp = 2, // @ C2_STAIRS_UP
kDMSquareAspectDoorState = 2, // @ C2_DOOR_STATE
kDMSquareAspectDoorThingIndex = 3, // @ C3_DOOR_THING_INDEX
kDMSquareAspectFloorOrn = 4 // @ C4_FLOOR_ORNAMENT_ORDINAL
};
#define kDMImmuneToFire 15 // @ C15_IMMUNE_TO_FIRE
#define kDMImmuneToPoison 15 // @ C15_IMMUNE_TO_POISON
enum TeleporterScope {
kDMTeleporterScopeCreatures = 1, // @ MASK0x0001_SCOPE_CREATURES
kDMTeleporterScopeObjectsOrParty = 2 // @ MASK0x0002_SCOPE_OBJECTS_OR_PARTY
};
enum SensorType {
kDMSensorDisabled = 0, // @ C000_SENSOR_DISABLED /* Never triggered, may be used for a floor or wall ornament */
kDMSensorFloorTheronPartyCreatureObj = 1, // @ C001_SENSOR_FLOOR_THERON_PARTY_CREATURE_OBJECT /* Triggered by party/thing F0276_SENSOR_ProcessThingAdditionOrRemoval */
kDMSensorFloorTheronPartyCreature = 2, // @ C002_SENSOR_FLOOR_THERON_PARTY_CREATURE /* Triggered by party/thing F0276_SENSOR_ProcessThingAdditionOrRemoval */
kDMSensorFloorParty = 3, // @ C003_SENSOR_FLOOR_PARTY /* Triggered by party/thing F0276_SENSOR_ProcessThingAdditionOrRemoval */
kDMSensorFloorObj = 4, // @ C004_SENSOR_FLOOR_OBJECT /* Triggered by party/thing F0276_SENSOR_ProcessThingAdditionOrRemoval */
kDMSensorFloorPartyOnStairs = 5, // @ C005_SENSOR_FLOOR_PARTY_ON_STAIRS /* Triggered by party/thing F0276_SENSOR_ProcessThingAdditionOrRemoval */
kDMSensorFloorGroupGenerator = 6, // @ C006_SENSOR_FLOOR_GROUP_GENERATOR /* Triggered by event F0245_TIMELINE_ProcessEvent5_Square_Corridor */
kDMSensorFloorCreature = 7, // @ C007_SENSOR_FLOOR_CREATURE /* Triggered by party/thing F0276_SENSOR_ProcessThingAdditionOrRemoval */
kDMSensorFloorPartyPossession = 8, // @ C008_SENSOR_FLOOR_PARTY_POSSESSION /* Triggered by party/thing F0276_SENSOR_ProcessThingAdditionOrRemoval */
kDMSensorFloorVersionChecker = 9, // @ C009_SENSOR_FLOOR_VERSION_CHECKER /* Triggered by party/thing F0276_SENSOR_ProcessThingAdditionOrRemoval */
kDMSensorWallOrnClick = 1, // @ C001_SENSOR_WALL_ORNAMENT_CLICK /* Triggered by player click F0275_SENSOR_IsTriggeredByClickOnWall */
kDMSensorWallOrnClickWithAnyObj = 2, // @ C002_SENSOR_WALL_ORNAMENT_CLICK_WITH_ANY_OBJECT /* Triggered by player click F0275_SENSOR_IsTriggeredByClickOnWall */
kDMSensorWallOrnClickWithSpecObj = 3, // @ C003_SENSOR_WALL_ORNAMENT_CLICK_WITH_SPECIFIC_OBJECT /* Triggered by player click F0275_SENSOR_IsTriggeredByClickOnWall */
kDMSensorWallOrnClickWithSpecObjRemoved = 4, // @ C004_SENSOR_WALL_ORNAMENT_CLICK_WITH_SPECIFIC_OBJECT_REMOVED /* Triggered by player click F0275_SENSOR_IsTriggeredByClickOnWall */
kDMSensorWallAndOrGate = 5, // @ C005_SENSOR_WALL_AND_OR_GATE /* Triggered by event F0248_TIMELINE_ProcessEvent6_Square_Wall */
kDMSensorWallCountdown = 6, // @ C006_SENSOR_WALL_COUNTDOWN /* Triggered by event F0248_TIMELINE_ProcessEvent6_Square_Wall */
kDMSensorWallSingleProjLauncherNewObj = 7, // @ C007_SENSOR_WALL_SINGLE_PROJECTILE_LAUNCHER_NEW_OBJECT /* Triggered by event F0248_TIMELINE_ProcessEvent6_Square_Wall */
kDMSensorWallSingleProjLauncherExplosion = 8, // @ C008_SENSOR_WALL_SINGLE_PROJECTILE_LAUNCHER_EXPLOSION /* Triggered by event F0248_TIMELINE_ProcessEvent6_Square_Wall */
kDMSensorWallDoubleProjLauncherNewObj = 9, // @ C009_SENSOR_WALL_DOUBLE_PROJECTILE_LAUNCHER_NEW_OBJECT /* Triggered by event F0248_TIMELINE_ProcessEvent6_Square_Wall */
kDMSensorWallDoubleProjLauncherExplosion = 10, // @ C010_SENSOR_WALL_DOUBLE_PROJECTILE_LAUNCHER_EXPLOSION /* Triggered by event F0248_TIMELINE_ProcessEvent6_Square_Wall */
kDMSensorWallOrnClickWithSpecObjRemovedRotateSensors = 11, // @ C011_SENSOR_WALL_ORNAMENT_CLICK_WITH_SPECIFIC_OBJECT_REMOVED_ROTATE_SENSORS /* Triggered by player click F0275_SENSOR_IsTriggeredByClickOnWall */
kDMSensorWallObjGeneratorRotateSensors = 12, // @ C012_SENSOR_WALL_OBJECT_GENERATOR_ROTATE_SENSORS /* Triggered by player click F0275_SENSOR_IsTriggeredByClickOnWall */
kDMSensorWallSingleObjStorageRotateSensors = 13, // @ C013_SENSOR_WALL_SINGLE_OBJECT_STORAGE_ROTATE_SENSORS /* Triggered by player click F0275_SENSOR_IsTriggeredByClickOnWall */
kDMSensorWallSingleProjLauncherSquareObj = 14, // @ C014_SENSOR_WALL_SINGLE_PROJECTILE_LAUNCHER_SQUARE_OBJECT /* Triggered by event F0248_TIMELINE_ProcessEvent6_Square_Wall */
kDMSensorWallDoubleProjLauncherSquareObj = 15, // @ C015_SENSOR_WALL_DOUBLE_PROJECTILE_LAUNCHER_SQUARE_OBJECT /* Triggered by event F0248_TIMELINE_ProcessEvent6_Square_Wall */
kDMSensorWallObjExchanger = 16, // @ C016_SENSOR_WALL_OBJECT_EXCHANGER /* Triggered by player click F0275_SENSOR_IsTriggeredByClickOnWall */
kDMSensorWallOrnClickWithSpecObjRemovedSensor = 17, // @ C017_SENSOR_WALL_ORNAMENT_CLICK_WITH_SPECIFIC_OBJECT_REMOVED_REMOVE_SENSOR /* Triggered by player click F0275_SENSOR_IsTriggeredByClickOnWall */
kDMSensorWallEndGame = 18, // @ C018_SENSOR_WALL_END_GAME /* Triggered by event F0248_TIMELINE_ProcessEvent6_Square_Wall */
kDMSensorWallChampionPortrait = 127 // @ C127_SENSOR_WALL_CHAMPION_PORTRAIT /* Triggered by player click F0275_SENSOR_IsTriggeredByClickOnWall */
};
enum WeaponType {
kDMWeaponTorch = 2, // @ C02_WEAPON_TORCH
kDMWeaponDagger = 8, // @ C08_WEAPON_DAGGER
kDMWeaponFalchion = 9, // @ C09_WEAPON_FALCHION
kDMWeaponSword = 10, // @ C10_WEAPON_SWORD
kDMWeaponClub = 23, // @ C23_WEAPON_CLUB
kDMWeaponStoneClub = 24, // @ C24_WEAPON_STONE_CLUB
kDMWeaponArrow = 27, // @ C27_WEAPON_ARROW
kDMWeaponSlayer = 28, // @ C28_WEAPON_SLAYER
kDMWeaponRock = 30, // @ C30_WEAPON_ROCK
kDMWeaponPoisonDart = 31, // @ C31_WEAPON_POISON_DART
kDMWeaponThrowingStar = 32 // @ C32_WEAPON_THROWING_STAR
};
enum ArmourType {
kDMArmourWoodenShield = 30, // @ C30_ARMOUR_WOODEN_SHIELD
kDMArmourArmet = 38, // @ C38_ARMOUR_ARMET
kDMArmourTorsoPlate = 39, // @ C39_ARMOUR_TORSO_PLATE
kDMArmourLegPlate = 40, // @ C40_ARMOUR_LEG_PLATE
kDMArmourFootPlate = 41 // @ C41_ARMOUR_FOOT_PLATE
};
enum PotionType {
kDMPotionTypeVen = 3, // @ C03_POTION_VEN_POTION,
kDMPotionTypeRos = 6, // @ C06_POTION_ROS_POTION,
kDMPotionTypeKu = 7, // @ C07_POTION_KU_POTION,
kDMPotionTypeDane = 8, // @ C08_POTION_DANE_POTION,
kDMPotionTypeNeta = 9, // @ C09_POTION_NETA_POTION,
kDMPotionTypeAntivenin = 10, // @ C10_POTION_ANTIVENIN,
kDMPotionTypeMon = 11, // @ C11_POTION_MON_POTION,
kDMPotionTypeYa = 12, // @ C12_POTION_YA_POTION,
kDMPotionTypeEe = 13, // @ C13_POTION_EE_POTION,
kDMPotionTypeVi = 14, // @ C14_POTION_VI_POTION,
kDMPotionTypeWaterFlask = 15, // @ C15_POTION_WATER_FLASK,
kDMPotionTypeFulBomb = 19, // @ C19_POTION_FUL_BOMB,
kDMPotionTypeEmptyFlask = 20 // @ C20_POTION_EMPTY_FLASK,
};
enum JunkType {
kDMJunkTypeWaterskin = 1, // @ C01_JUNK_WATERSKIN,
kDMJunkTypeBones = 5, // @ C05_JUNK_BONES,
kDMJunkTypeBoulder = 25, // @ C25_JUNK_BOULDER,
kDMJunkTypeScreamerSlice = 33, // @ C33_JUNK_SCREAMER_SLICE,
kDMJunkTypeWormRound = 34, // @ C34_JUNK_WORM_ROUND,
kDMJunkTypeDrumstickShank = 35, // @ C35_JUNK_DRUMSTICK_SHANK,
kDMJunkTypeDragonSteak = 36, // @ C36_JUNK_DRAGON_STEAK,
kDMJunkTypeMagicalBoxBlue = 42, // @ C42_JUNK_MAGICAL_BOX_BLUE,
kDMJunkTypeMagicalBoxGreen = 43, // @ C43_JUNK_MAGICAL_BOX_GREEN,
kDMJunkTypeZokathra = 51 // @ C51_JUNK_ZOKATHRA,
};
enum ExplosionType {
kDMExplosionTypeFireball = 0, // @ C000_EXPLOSION_FIREBALL
kDMExplosionTypeSlime = 1, // @ C001_EXPLOSION_SLIME
kDMExplosionTypeLightningBolt = 2, // @ C002_EXPLOSION_LIGHTNING_BOLT
kDMExplosionTypeHarmNonMaterial = 3, // @ C003_EXPLOSION_HARM_NON_MATERIAL
kDMExplosionTypeOpenDoor = 4, // @ C004_EXPLOSION_OPEN_DOOR
kDMExplosionTypePoisonBolt = 6, // @ C006_EXPLOSION_POISON_BOLT
kDMExplosionTypePoisonCloud = 7, // @ C007_EXPLOSION_POISON_CLOUD
kDMExplosionTypeSmoke = 40, // @ C040_EXPLOSION_SMOKE
kDMExplosionTypeFluxcage = 50, // @ C050_EXPLOSION_FLUXCAGE
kDMExplosionTypeRebirthStep1 = 100, // @ C100_EXPLOSION_REBIRTH_STEP1
kDMExplosionTypeRebirthStep2 = 101 // @ C101_EXPLOSION_REBIRTH_STEP2
};
enum SquareMask {
kDMSquareMaskWallWestRandOrnament = 0x1, // @ MASK0x0001_WALL_WEST_RANDOM_ORNAMENT_ALLOWED
kDMSquareMaslWallSouthRandOrnament = 0x2, // @ MASK0x0002_WALL_SOUTH_RANDOM_ORNAMENT_ALLOWED
kDMSquareMaskWallEastRandOrnament = 0x4, // @ MASK0x0004_WALL_EAST_RANDOM_ORNAMENT_ALLOWED
kDMSquareMaskWallNorthRandOrnament = 0x8, // @ MASK0x0008_WALL_NORTH_RANDOM_ORNAMENT_ALLOWED
kDMSquareMaskCorridorRandOrnament = 0x8, // @ MASK0x0008_CORRIDOR_RANDOM_ORNAMENT_ALLOWED
kDMSquareMaskPitImaginary = 0x1, // @ MASK0x0001_PIT_IMAGINARY
kDMSquareMaskPitInvisible = 0x4, // @ MASK0x0004_PIT_INVISIBLE
kDMSquareMaskPitOpen = 0x8, // @ MASK0x0008_PIT_OPEN
kDMSquareMaskStairsUp = 0x4, // @ MASK0x0004_STAIRS_UP
kDMSquareMaskStairsNorthSouth = 0x8, // @ MASK0x0008_STAIRS_NORTH_SOUTH_ORIENTATION
kDMSquareMaskDoorNorthSouth = 0x8, // @ MASK0x0008_DOOR_NORTH_SOUTH_ORIENTATION
kDMSquareMaskTeleporterVisible = 0x4, // @ MASK0x0004_TELEPORTER_VISIBLE
kDMSquareMaskTeleporterOpen = 0x8, // @ MASK0x0008_TELEPORTER_OPEN
kDMSquareMaskFakeWallImaginary = 0x1, // @ MASK0x0001_FAKEWALL_IMAGINARY
kDMSquareMaskFakeWallOpen = 0x4, // @ MASK0x0004_FAKEWALL_OPEN
kDMSquareMaskFakeWallRandOrnamentOrFootprintsAllowed = 0x8, // @ MASK0x0008_FAKEWALL_RANDOM_ORNAMENT_OR_FOOTPRINTS_ALLOWED
kDMSquareMaskThingListPresent = 0x10 // @ MASK0x0010_THING_LIST_PRESENT
};
#define kDMMaskChampionBones 0x8000 // @ MASK0x8000_CHAMPION_BONES
#define kDMMaskThingType 0x7FFF // @ MASK0x7FFF_THING_TYPE
class ObjectInfoIndex {
public:
int16 _type;
uint16 _objectAspectIndex;
uint16 _actionSetIndex;
uint16 _allowedSlots;
ObjectInfoIndex(int16 type, uint16 objectAspectIndex, uint16 actionSetIndex, uint16 allowedSlots)
: _type(type), _objectAspectIndex(objectAspectIndex), _actionSetIndex(actionSetIndex), _allowedSlots(allowedSlots) {}
ObjectInfoIndex() : _type(0), _objectAspectIndex(0), _actionSetIndex(0), _allowedSlots(0) {}
bool getAllowedSlot(ObjectAllowedSlot slot) { return _allowedSlots & slot; }
uint16 getAllowedSlots() { return _allowedSlots; }
void setAllowedSlot(ObjectAllowedSlot slot, bool val) {
if (val) {
_allowedSlots |= slot;
} else {
_allowedSlots &= ~slot;
}
}
}; // @ OBJECT_INFO
class ArmourInfo {
public:
uint16 _weight;
uint16 _defense;
uint16 _attributes;
ArmourInfo(uint16 weight, uint16 defense, uint16 attributes)
:_weight(weight), _defense(defense), _attributes(attributes) {}
ArmourInfo() :_weight(0), _defense(0), _attributes(0) {}
uint16 getAttribute(ArmourAttribute attribute) { return _attributes & attribute; }
void setAttribute(ArmourAttribute attribute) { _attributes |= attribute; }
}; // @ ARMOUR_INFO
class WeaponInfo {
public:
uint16 _weight;
uint16 _class;
uint16 _strength;
uint16 _kineticEnergy;
private:
uint16 _attributes; /* Bits 15-13 Unreferenced */
public:
WeaponInfo(uint16 weight, uint16 wClass, uint16 strength, uint16 kineticEnergy, uint16 attributes)
: _weight(weight), _class(wClass), _strength(strength), _kineticEnergy(kineticEnergy), _attributes(attributes) {}
WeaponInfo() : _weight(0), _class(0), _strength(0), _kineticEnergy(0), _attributes(0) {}
uint16 getShootAttack() { return _attributes & 0xFF; } // @ M65_SHOOT_ATTACK
uint16 getProjectileAspectOrdinal() { return (_attributes >> 8) & 0x1F; } // @ M66_PROJECTILE_ASPECT_ORDINAL
}; // @ WEAPON_INFO
class CreatureInfo {
public:
byte _creatureAspectIndex;
byte _attackSoundOrdinal;
uint16 _attributes; /* Bits 15-14 Unreferenced */
uint16 _graphicInfo; /* Bits 11 and 6 Unreferenced */
byte _movementTicks; /* Value 255 means the creature cannot move */
byte _attackTicks; /* Minimum ticks between attacks */
byte _defense;
byte _baseHealth;
byte _attack;
byte _poisonAttack;
byte _dexterity;
uint16 _ranges; /* Bits 7-4 Unreferenced */
uint16 _properties;
uint16 _resistances; /* Bits 15-12 and 3-0 Unreferenced */
uint16 _animationTicks; /* Bits 15-12 Unreferenced */
uint16 _woundProbabilities; /* Contains 4 probabilities to wound a champion's Head (Bits 15-12), Legs (Bits 11-8), Torso (Bits 7-4) and Feet (Bits 3-0) */
byte _attackType;
uint16 getFearResistance() { return (_properties >> 4) & 0xF; }
uint16 getExperience() { return (_properties >> 8) & 0xF; }
uint16 getWariness() { return (_properties >> 12) & 0xF; }
uint16 getFireResistance() { return (_resistances >> 4) & 0xF; }
uint16 getPoisonResistance() { return (_resistances >> 8) & 0xF; }
static uint16 getHeight(uint16 attrib) { return (attrib >> 7) & 0x3; }
uint16 getSightRange() { return (_ranges) & 0xF; }
uint16 getSmellRange() { return (_ranges >> 8) & 0xF; }
uint16 getAttackRange() { return (_ranges >> 12) & 0xF; }
}; // @ CREATURE_INFO
class Door {
Thing _nextThing;
uint16 _attributes;
public:
explicit Door(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
Thing getNextThing() { return _nextThing; }
bool isMeleeDestructible() { return (_attributes >> 8) & 1; }
bool isMagicDestructible() { return (_attributes >> 7) & 1; }
bool hasButton() { return (_attributes >> 6) & 1; }
bool opensVertically() { return (_attributes >> 5) & 1; }
byte getOrnOrdinal() { return (_attributes >> 1) & 0xF; }
byte getType() { return _attributes & 1; }
}; // @ DOOR
class Teleporter {
Thing _nextThing;
uint16 _attributes;
uint16 _destMapIndex;
public:
explicit Teleporter(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]), _destMapIndex(rawDat[2]) {}
Thing getNextThing() { return _nextThing; }
bool isAudible() { return (_attributes >> 15) & 1; }
TeleporterScope getScope() { return (TeleporterScope)((_attributes >> 13) & 1); }
bool getAbsoluteRotation() { return (_attributes >> 12) & 1; }
Direction getRotation() { return (Direction)((_attributes >> 10) & 1); }
byte getTargetMapY() { return (_attributes >> 5) & 0xF; }
byte getTargetMapX() { return _attributes & 0xF; }
uint16 getTargetMapIndex() { return _destMapIndex >> 8; }
}; // @ TELEPORTER
class TextString {
Thing _nextThing;
uint16 _textDataRef;
public:
explicit TextString(uint16 *rawDat) : _nextThing(rawDat[0]), _textDataRef(rawDat[1]) {}
Thing getNextThing() { return _nextThing; }
uint16 getWordOffset() { return _textDataRef >> 3; }
bool isVisible() { return _textDataRef & 1; }
void setVisible(bool visible) { _textDataRef = (_textDataRef & ~1) | (visible ? 1 : 0); }
}; // @ TEXTSTRING
class Sensor {
Thing _nextThing;
uint16 _datAndType;
uint16 _attributes; // A
uint16 _action; // B
public:
explicit Sensor(uint16 *rawDat) : _nextThing(rawDat[0]), _datAndType(rawDat[1]), _attributes(rawDat[2]), _action(rawDat[3]) {}
Thing getNextThing() { return _nextThing; }
void setNextThing(Thing thing) { _nextThing = thing; }
SensorType getType() { return (SensorType)(_datAndType & 0x7F); } // @ M39_TYPE
uint16 getData() { return (_datAndType >> 7) & 0x1FF; } // @ M40_DATA
static uint16 getDataMask1(uint16 data) { return (data >> 7) & 0xF; } // @ M42_MASK1
static uint16 getDataMask2(uint16 data) { return (data >> 11) & 0xF; } // @ M43_MASK2
void setData(uint16 dat) { _datAndType = dat; } // @ M41_SET_DATA
void setTypeDisabled() { _datAndType &= 0xFF80; } // @ M44_SET_TYPE_DISABLED
bool getAttrOnlyOnce() { return (_attributes >> 2) & 1; }
uint16 getAttrEffectA() { return (_attributes >> 3) & 0x3; }
bool getAttrRevertEffectA() { return (_attributes >> 5) & 0x1; }
bool getAttrAudibleA() { return (_attributes >> 6) & 0x1; }
uint16 getAttrValue() { return (_attributes >> 7) & 0xF; }
bool getAttrLocalEffect() { return (_attributes >> 11) & 1; }
uint16 getAttrOrnOrdinal() { return _attributes >> 12; }
uint16 getActionTargetMapY() { return (_action >> 11); }
uint16 getActionTargetMapX() { return (_action >> 6) & 0x1F; }
Cell getActionTargetCell() { return (Cell)((_action >> 4) & 3); }
uint16 getActionHealthMultiplier() { return ((_action >> 4) & 0xF); } // @ M45_HEALTH_MULTIPLIER
uint16 getActionTicks() { return ((_action >> 4) >> 4) & 0xFFF; } // @ M46_TICKS
uint16 getActionKineticEnergy() { return ((_action >> 4) & 0xFF); }// @ M47_KINETIC_ENERGY
uint16 getActionStepEnergy() { return ((_action >> 4) >> 8) & 0xFF; }// @ M48_STEP_ENERGY
uint16 getActionLocalEffect() { return (_action >> 4); } // @ M49_LOCAL_EFFECT
void setDatAndTypeWithOr(uint16 val) { _datAndType |= val; }
}; // @ SENSOR
class Weapon {
Thing _nextThing;
uint16 _desc;
public:
explicit Weapon(uint16 *rawDat) : _nextThing(rawDat[0]), _desc(rawDat[1]) {}
WeaponType getType() { return (WeaponType)(_desc & 0x7F); }
void setType(uint16 val) { _desc = (_desc & ~0x7F) | (val & 0x7F); }
bool isLit() { return (_desc >> 15) & 1; }
void setLit(bool val) {
if (val)
_desc |= (1 << 15);
else
_desc &= (~(1 << 15));
}
uint16 getChargeCount() { return (_desc >> 10) & 0xF; }
uint16 setChargeCount(uint16 val) { _desc = (_desc & ~(0xF << 10)) | ((val & 0xF) << 10); return (val & 0xF); }
Thing getNextThing() { return _nextThing; }
void setNextThing(Thing val) { _nextThing = val; }
uint16 getCursed() { return (_desc >> 8) & 1; }
void setCursed(uint16 val) { _desc = (_desc & ~(1 << 8)) | ((val & 1) << 8); }
uint16 getPoisoned() { return (_desc >> 9) & 1; }
uint16 getBroken() { return (_desc >> 14) & 1; }
uint16 getDoNotDiscard() { return (_desc >> 7) & 1; }
void setDoNotDiscard(uint16 val) { _desc = (_desc & ~(1 << 7)) | ((val & 1) << 7); }
}; // @ WEAPON
class Armour {
Thing _nextThing;
uint16 _attributes;
public:
explicit Armour(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
ArmourType getType() { return (ArmourType)(_attributes & 0x7F); }
Thing getNextThing() { return _nextThing; }
uint16 getCursed() { return (_attributes >> 8) & 1; }
uint16 getBroken() { return (_attributes >> 13) & 1; }
uint16 getDoNotDiscard() { return (_attributes >> 7) & 1; }
uint16 getChargeCount() { return (_attributes >> 9) & 0xF; }
void setChargeCount(uint16 val) { _attributes = (_attributes & ~(0xF << 9)) | ((val & 0xF) << 9); }
}; // @ ARMOUR
class Scroll {
Thing _nextThing;
uint16 _attributes;
public:
explicit Scroll(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
void set(Thing next, uint16 attribs) {
_nextThing = next;
_attributes = attribs;
}
Thing getNextThing() { return _nextThing; }
uint16 getClosed() { return (_attributes >> 10) & 0x3F; } // ??? dunno why, the original bitfield is 6 bits long
void setClosed(bool val) {
if (val)
_attributes |= (1 << 10);
else
_attributes &= (~(0x3F << 10));
}
uint16 getTextStringThingIndex() { return _attributes & 0x3FF; }
}; // @ SCROLL
class Potion {
public:
Thing _nextThing;
uint16 _attributes;
explicit Potion(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
PotionType getType() { return (PotionType)((_attributes >> 8) & 0x7F); }
void setType(PotionType val) { _attributes = (_attributes & ~(0x7F << 8)) | ((val & 0x7F) << 8); }
Thing getNextThing() { return _nextThing; }
uint16 getPower() { return _attributes & 0xFF; }
void setPower(uint16 val) { _attributes = (_attributes & ~0xFF) | (val & 0xFF); }
uint16 getDoNotDiscard() { return (_attributes >> 15) & 1; }
}; // @ POTION
class Container {
Thing _nextThing;
Thing _slot;
uint16 _type;
public:
explicit Container(uint16 *rawDat) : _nextThing(rawDat[0]), _slot(rawDat[1]), _type(rawDat[2]) {}
uint16 getType() { return (_type >> 1) & 0x3; }
Thing &getSlot() { return _slot; }
Thing &getNextThing() { return _nextThing; }
}; // @ CONTAINER
class Junk {
Thing _nextThing;
uint16 _attributes;
public:
explicit Junk(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
JunkType getType() { return (JunkType)(_attributes & 0x7F); }
void setType(uint16 val) { _attributes = (_attributes & ~0x7F) | (val & 0x7F); }
uint16 getChargeCount() { return (_attributes >> 14) & 0x3; }
void setChargeCount(uint16 val) { _attributes = (_attributes & ~(0x3 << 14)) | ((val & 0x3) << 14); }
uint16 getDoNotDiscard() { return (_attributes >> 7) & 1; }
void setDoNotDiscard(uint16 val) { _attributes = (_attributes & ~(1 << 7)) | ((val & 1) << 7); }
Thing getNextThing() { return _nextThing; }
void setNextThing(Thing thing) { _nextThing = thing; }
}; // @ JUNK
class Projectile {
public:
Thing _nextThing;
Thing _slot;
uint16 _kineticEnergy;
uint16 _attack;
uint16 _eventIndex;
explicit Projectile(uint16 *rawDat) : _nextThing(rawDat[0]), _slot(rawDat[1]), _kineticEnergy(rawDat[2]),
_attack(rawDat[3]), _eventIndex(rawDat[4]) {}
}; // @ PROJECTILE
class Explosion {
Thing _nextThing;
uint16 _attributes;
public:
explicit Explosion(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
Thing getNextThing() { return _nextThing; }
Thing setNextThing(Thing val) { return _nextThing = val; }
uint16 getType() { return _attributes & 0x7F; }
uint16 setType(uint16 val) { _attributes = (_attributes & ~0x7F) | (val & 0x7F); return (val & 0x7F); }
uint16 getAttack() { return (_attributes >> 8) & 0xFF; }
void setAttack(uint16 val) { _attributes = (_attributes & ~(0xFF << 8)) | ((val & 0xFF) << 8); }
uint16 getCentered() { return (_attributes >> 7) & 0x1; }
void setCentered(uint16 val) { _attributes = (_attributes & ~(1 << 7)) | ((val & 1) << 7); }
}; // @ EXPLOSION
class Square {
byte _data;
public:
explicit Square(byte dat = 0) : _data(dat) {}
explicit Square(ElementType type) { setType(type); }
explicit Square(byte element, byte mask) : _data((element << 5) | mask) {}
Square &set(byte dat) { this->_data = dat; return *this; }
Square &set(SquareMask mask) { _data |= mask; return *this; }
byte get(SquareMask mask) { return _data & mask; }
byte getDoorState() { return _data & 0x7; } // @ M36_DOOR_STATE
void setDoorState(byte state) { _data = ((_data & ~0x7) | state); } // @ M37_SET_DOOR_STATE
ElementType getType() { return (ElementType)(_data >> 5); } // @ M34_SQUARE_TYPE
void setType(ElementType type) { _data = (_data & 0x1F) | type << 5; }
byte toByte() { return _data; } // I don't like 'em casts
}; // wrapper for bytes which are used as squares
struct DungeonFileHeader {
uint16 _ornamentRandomSeed;
uint16 _rawMapDataSize;
uint8 _mapCount;
uint16 _textDataWordCount;
uint16 _partyStartLocation;
uint16 _squareFirstThingCount; // @ SquareFirstThingCount
uint16 _thingCounts[16]; // @ ThingCount[16]
}; // @ DUNGEON_HEADER
struct Map {
uint32 _rawDunDataOffset;
uint8 _offsetMapX, _offsetMapY;
uint8 _level; // only used in DMII
uint8 _width, _height; // !!! THESRE ARE INCLUSIVE BOUNDARIES
// orn short for Ornament
uint8 _wallOrnCount; /* May be used in a Sensor on a Wall or closed Fake Wall square */
uint8 _randWallOrnCount; /* Used only on some Wall squares and some closed Fake Wall squares */
uint8 _floorOrnCount; /* May be used in a Sensor on a Pit, open Fake Wall, Corridor or Teleporter square */
uint8 _randFloorOrnCount; /* Used only on some Corridor squares and some open Fake Wall squares */
uint8 _doorOrnCount;
uint8 _creatureTypeCount;
uint8 _difficulty;
FloorSet _floorSet;
WallSet _wallSet;
uint8 _doorSet0, _doorSet1;
}; // @ MAP
class DoorInfo {
public:
byte _attributes;
byte _defense;
DoorInfo(byte b1, byte b2) : _attributes(b1), _defense(b2) {}
DoorInfo() { resetToZero(); }
void resetToZero() { _attributes = _defense = 0; }
}; // @ DOOR_INFO
class Group;
class DungeonMan {
DMEngine *_vm;
DungeonMan(const DungeonMan &other); // no implementation on purpose
void operator=(const DungeonMan &rhs); // no implementation on purpose
Square getRelSquare(Direction dir, int16 stepsForward, int16 stepsRight, int16 posX, int16 posY); // @ F0152_DUNGEON_GetRelativeSquare
void decompressDungeonFile(); // @ F0455_FLOPPY_DecompressDungeon
int16 getSquareFirstThingIndex(int16 mapX, int16 mapY); // @ F0160_DUNGEON_GetSquareFirstThingIndex
int16 getRandomOrnOrdinal(bool allowed, int16 count, int16 mapX, int16 mapY, int16 modulo); // @ F0170_DUNGEON_GetRandomOrnamentOrdinal
void setSquareAspectOrnOrdinals(uint16 *aspectArray, bool leftAllowed, bool frontAllowed, bool rightAllowed, int16 dir,
int16 mapX, int16 mapY, bool isFakeWall); // @ F0171_DUNGEON_SetSquareAspectRandomWallOrnamentOrdinals
public:
explicit DungeonMan(DMEngine *dmEngine);
~DungeonMan();
Square getSquare(int16 mapX, int16 mapY); // @ F0151_DUNGEON_GetSquare
void setCurrentMap(uint16 mapIndex); // @ F0173_DUNGEON_SetCurrentMap
Thing getSquareFirstThing(int16 mapX, int16 mapY); // @ F0161_DUNGEON_GetSquareFirstThing
Thing getNextThing(Thing thing); // @ F0159_DUNGEON_GetNextThing(THING P0280_T_Thing)
uint16 *getThingData(Thing thing); // @ F0156_DUNGEON_GetThingData
uint16 *getSquareFirstThingData(int16 mapX, int16 mapY); // @ F0157_DUNGEON_GetSquareFirstThingData
// TODO: this does stuff other than load the file!
void loadDungeonFile(Common::InSaveFile *file); // @ F0434_STARTEND_IsLoadDungeonSuccessful_CPSC
void setCurrentMapAndPartyMap(uint16 mapIndex); // @ F0174_DUNGEON_SetCurrentMapAndPartyMap
bool isWallOrnAnAlcove(int16 wallOrnIndex); // @ F0149_DUNGEON_IsWallOrnamentAnAlcove
void mapCoordsAfterRelMovement(Direction dir, int16 stepsForward, int16 stepsRight, int16 &posX, int16 &posY); // @ F0150_DUNGEON_UpdateMapCoordinatesAfterRelativeMovement
ElementType getRelSquareType(Direction dir, int16 stepsForward, int16 stepsRight, int16 posX, int16 posY) {
return Square(getRelSquare(dir, stepsForward, stepsRight, posX, posY)).getType();
} // @ F0153_DUNGEON_GetRelativeSquareType
void setSquareAspect(uint16 *aspectArray, Direction dir, int16 mapX, int16 mapY); // @ F0172_DUNGEON_SetSquareAspect
void decodeText(char *destString, size_t maxSize, Thing thing, TextType type); // F0168_DUNGEON_DecodeText
Thing getUnusedThing(uint16 thingType); // @ F0166_DUNGEON_GetUnusedThing
uint16 getObjectWeight(Thing thing); // @ F0140_DUNGEON_GetObjectWeight
int16 getObjectInfoIndex(Thing thing); // @ F0141_DUNGEON_GetObjectInfoIndex
void linkThingToList(Thing thingToLink, Thing thingInList, int16 mapX, int16 mapY); // @ F0163_DUNGEON_LinkThingToList
WeaponInfo *getWeaponInfo(Thing thing); // @ F0158_DUNGEON_GetWeaponInfo
int16 getProjectileAspect(Thing thing); // @ F0142_DUNGEON_GetProjectileAspect
int16 getLocationAfterLevelChange(int16 mapIndex, int16 levelDelta, int16 *mapX, int16 *mapY); // @ F0154_DUNGEON_GetLocationAfterLevelChange
Thing getSquareFirstObject(int16 mapX, int16 mapY); // @ F0162_DUNGEON_GetSquareFirstObject
uint16 getArmourDefense(ArmourInfo *armourInfo, bool useSharpDefense); // @ F0143_DUNGEON_GetArmourDefense
Thing getDiscardThing(uint16 thingType); // @ F0165_DUNGEON_GetDiscardedThing
uint16 getCreatureAttributes(Thing thing); // @ F0144_DUNGEON_GetCreatureAttributes
void setGroupCells(Group *group, uint16 cells, uint16 mapIndex); // @ F0146_DUNGEON_SetGroupCells
void setGroupDirections(Group *group, int16 dir, uint16 mapIndex); // @ F0148_DUNGEON_SetGroupDirections
bool isCreatureAllowedOnMap(Thing thing, uint16 mapIndex); // @ F0139_DUNGEON_IsCreatureAllowedOnMap
void unlinkThingFromList(Thing thingToUnlink, Thing thingInList, int16 mapX, int16 mapY); // @ F0164_DUNGEON_UnlinkThingFromList
int16 getStairsExitDirection(int16 mapX, int16 mapY); // @ F0155_DUNGEON_GetStairsExitDirection
Thing getObjForProjectileLaucherOrObjGen(uint16 iconIndex); // @ F0167_DUNGEON_GetObjectForProjectileLauncherOrObjectGenerator
int16 getRandomOrnamentIndex(uint16 val1, uint16 val2, int16 modulo); // @ F0169_DUNGEON_GetRandomOrnamentIndex
uint32 _rawDunFileDataSize; // @ probably NONE
byte *_rawDunFileData; // @ ???
DungeonFileHeader _dungeonFileHeader; // @ G0278_ps_DungeonHeader
uint16 *_dungeonMapsFirstColumnIndex; // @ G0281_pui_DungeonMapsFirstColumnIndex
uint16 _dungeonColumCount; // @ G0282_ui_DungeonColumnCount
uint16 *_dungeonColumnsCumulativeSquareThingCount; // @ G0280_pui_DungeonColumnsCumulativeSquareThingCount
Thing *_squareFirstThings; // @ G0283_pT_SquareFirstThings
uint16 *_dungeonTextData; // @ G0260_pui_DungeonTextData
uint16 *_thingData[16]; // @ G0284_apuc_ThingData
byte ***_dungeonMapData; // @ G0279_pppuc_DungeonMapData
Direction _partyDir; // @ G0308_i_PartyDirection
int16 _partyMapX; // @ G0306_i_PartyMapX
int16 _partyMapY; // @ G0307_i_PartyMapY
uint8 _partyMapIndex; // @ G0309_i_PartyMapIndex
int16 _currMapIndex; // @ G0272_i_CurrentMapIndex
byte **_currMapData; // @ G0271_ppuc_CurrentMapData
Map *_currMap; // @ G0269_ps_CurrentMap
uint16 _currMapWidth; // @ G0273_i_CurrentMapWidth
uint16 _currMapHeight; // @ G0274_i_CurrentMapHeight
uint16 *_currMapColCumulativeSquareFirstThingCount; // @G0270_pui_CurrentMapColumnsCumulativeSquareFirstThingCount
Map *_dungeonMaps; // @ G0277_ps_DungeonMaps
byte *_dungeonRawMapData; // @ G0276_puc_DungeonRawMapData
int16 _currMapInscriptionWallOrnIndex; // @ G0265_i_CurrentMapInscriptionWallOrnamentIndex
Box _dungeonViewClickableBoxes[6]; // G0291_aauc_DungeonViewClickableBoxes
bool _isFacingAlcove; // @ G0286_B_FacingAlcove
bool _isFacingViAltar; // @ G0287_B_FacingViAltar
bool _isFacingFountain; // @ G0288_B_FacingFountain
ElementType _squareAheadElement; // @ G0285_i_SquareAheadElement
Thing _pileTopObject[5]; // @ G0292_aT_PileTopObject
DoorInfo _currMapDoorInfo[2]; // @ G0275_as_CurrentMapDoorInfo
ObjectInfoIndex _objectInfos[180]; // @ G0237_as_Graphic559_ObjectInfo
ArmourInfo _armourInfos[58]; // @ G0239_as_Graphic559_ArmourInfo
WeaponInfo _weaponInfos[46]; // @ G0238_as_Graphic559_WeaponInfo
CreatureInfo _creatureInfos[k27_CreatureTypeCount]; // @ G0243_as_Graphic559_CreatureInfo
byte _thingDataWordCount[16]; // @ G0235_auc_Graphic559_ThingDataByteCount
void setupConstants();
};
}
#endif

1681
engines/dm/eventman.cpp Normal file

File diff suppressed because it is too large Load Diff

324
engines/dm/eventman.h Normal file
View File

@@ -0,0 +1,324 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_EVENTMAN_H
#define DM_EVENTMAN_H
#include "common/events.h"
#include "common/queue.h"
#include "common/array.h"
#include "dm/dm.h"
#include "dm/gfx.h"
#include "dm/champion.h"
namespace DM {
enum MouseButton {
kDMMouseButtonNone = 0, // present only because of typesafety
kDMMouseButtonLeft = 1,
kDMMouseButtonRight = 2
};
enum CommandType {
kDMCommandNone = 0, // @ C000_COMMAND_NONE
kDMCommandTurnLeft = 1, // @ C001_COMMAND_TURN_LEFT
kDMCommandTurnRight = 2, // @ C002_COMMAND_TURN_RIGHT
kDMCommandMoveForward = 3, // @ C003_COMMAND_MOVE_FORWARD
kDMCommandMoveRight = 4, // @ C004_COMMAND_MOVE_RIGHT
kDMCommandMoveBackward = 5, // @ C005_COMMAND_MOVE_BACKWARD
kDMCommandMoveLeft = 6, // @ C006_COMMAND_MOVE_LEFT
kDMCommandToggleInventoryChampion0 = 7, // @ C007_COMMAND_TOGGLE_INVENTORY_CHAMPION_0
kDMCommandToggleInventoryChampion1 = 8, // @ C008_COMMAND_TOGGLE_INVENTORY_CHAMPION_1
kDMCommandToggleInventoryChampion2 = 9, // @ C009_COMMAND_TOGGLE_INVENTORY_CHAMPION_2
kDMCommandToggleInventoryChampion3 = 10, // @ C010_COMMAND_TOGGLE_INVENTORY_CHAMPION_3
kDMCommandCloseInventory = 11, // @ C011_COMMAND_CLOSE_INVENTORY
kDMCommandClickInChampion0StatusBox = 12, // @ C012_COMMAND_CLICK_IN_CHAMPION_0_STATUS_BOX
kDMCommandClickInChampion1StatusBox = 13, // @ C013_COMMAND_CLICK_IN_CHAMPION_1_STATUS_BOX
kDMCommandClickInChampion2StatusBox = 14, // @ C014_COMMAND_CLICK_IN_CHAMPION_2_STATUS_BOX
kDMCommandClickInChampion3StatusBox = 15, // @ C015_COMMAND_CLICK_IN_CHAMPION_3_STATUS_BOX
kDMCommandSetLeaderChampion0 = 16, // @ C016_COMMAND_SET_LEADER_CHAMPION_0
kDMCommandSetLeaderChampion1 = 17, // @ C017_COMMAND_SET_LEADER_CHAMPION_1
kDMCommandSetLeaderChampion2 = 18, // @ C018_COMMAND_SET_LEADER_CHAMPION_2
kDMCommandSetLeaderChampion3 = 19, // @ C019_COMMAND_SET_LEADER_CHAMPION_3
kDMCommandClickOnSlotBoxChampion0StatusBoxReadyHand = 20, // @ C020_COMMAND_CLICK_ON_SLOT_BOX_00_CHAMPION_0_STATUS_BOX_READY_HAND
kDMCommandClickOnSlotBoxChampion0StatusBoxActionHand = 21, // @ C021_COMMAND_CLICK_ON_SLOT_BOX_01_CHAMPION_0_STATUS_BOX_ACTION_HAND
kDMCommandClickOnSlotBoxChampion1StatusBoxReadyHand = 22, // @ C022_COMMAND_CLICK_ON_SLOT_BOX_02_CHAMPION_1_STATUS_BOX_READY_HAND
kDMCommandClickOnSlotBoxChampion1StatusBoxActionHand = 23, // @ C023_COMMAND_CLICK_ON_SLOT_BOX_03_CHAMPION_1_STATUS_BOX_ACTION_HAND
kDMCommandClickOnSlotBoxChampion2StatusBoxReadyHand = 24, // @ C024_COMMAND_CLICK_ON_SLOT_BOX_04_CHAMPION_2_STATUS_BOX_READY_HAND
kDMCommandClickOnSlotBoxChampion2StatusBoxActionHand = 25, // @ C025_COMMAND_CLICK_ON_SLOT_BOX_05_CHAMPION_2_STATUS_BOX_ACTION_HAND
kDMCommandClickOnSlotBoxChampion3StatusBoxReadyHand = 26, // @ C026_COMMAND_CLICK_ON_SLOT_BOX_06_CHAMPION_3_STATUS_BOX_READY_HAND
kDMCommandClickOnSlotBoxChampion3StatusBoxActionHand = 27, // @ C027_COMMAND_CLICK_ON_SLOT_BOX_07_CHAMPION_3_STATUS_BOX_ACTION_HAND
kDMCommandClickOnSlotBoxInventoryReadyHand = 28, // @ C028_COMMAND_CLICK_ON_SLOT_BOX_08_INVENTORY_READY_HAND
kDMCommandClickOnSlotBoxInventoryActionHand = 29, // @ C029_COMMAND_CLICK_ON_SLOT_BOX_09_INVENTORY_ACTION_HAND
kDMCommandClickOnSlotBoxInventoryHead = 30, // @ C030_COMMAND_CLICK_ON_SLOT_BOX_10_INVENTORY_HEAD
kDMCommandClickOnSlotBoxInventoryTorso = 31, // @ C031_COMMAND_CLICK_ON_SLOT_BOX_11_INVENTORY_TORSO
kDMCommandClickOnSlotBoxInventoryLegs = 32, // @ C032_COMMAND_CLICK_ON_SLOT_BOX_12_INVENTORY_LEGS
kDMCommandClickOnSlotBoxInventoryFeet = 33, // @ C033_COMMAND_CLICK_ON_SLOT_BOX_13_INVENTORY_FEET
kDMCommandClickOnSlotBoxInventoryPouch2 = 34, // @ C034_COMMAND_CLICK_ON_SLOT_BOX_14_INVENTORY_POUCH_2
kDMCommandClickOnSlotBoxInventoryQuiverLine2_1 = 35, // @ C035_COMMAND_CLICK_ON_SLOT_BOX_15_INVENTORY_QUIVER_LINE2_1
kDMCommandClickOnSlotBoxInventoryQuiverLine1_2 = 36, // @ C036_COMMAND_CLICK_ON_SLOT_BOX_16_INVENTORY_QUIVER_LINE1_2
kDMCommandClickOnSlotBoxInventoryQuiverLine2_2 = 37, // @ C037_COMMAND_CLICK_ON_SLOT_BOX_17_INVENTORY_QUIVER_LINE2_2
kDMCommandClickOnSlotBoxInventoryNeck = 38, // @ C038_COMMAND_CLICK_ON_SLOT_BOX_18_INVENTORY_NECK
kDMCommandClickOnSlotBoxInventoryPouch1 = 39, // @ C039_COMMAND_CLICK_ON_SLOT_BOX_19_INVENTORY_POUCH_1
kDMCommandClickOnSlotBoxInventoryQuiverLine1_1 = 40, // @ C040_COMMAND_CLICK_ON_SLOT_BOX_20_INVENTORY_QUIVER_LINE1_1
kDMCommandClickOnSlotBoxInventoryBackpackLine1_1 = 41, // @ C041_COMMAND_CLICK_ON_SLOT_BOX_21_INVENTORY_BACKPACK_LINE1_1
kDMCommandClickOnSlotBoxInventoryBackpackLine2_2 = 42, // @ C042_COMMAND_CLICK_ON_SLOT_BOX_22_INVENTORY_BACKPACK_LINE2_2
kDMCommandClickOnSlotBoxInventoryBackpackLine2_3 = 43, // @ C043_COMMAND_CLICK_ON_SLOT_BOX_23_INVENTORY_BACKPACK_LINE2_3
kDMCommandClickOnSlotBoxInventoryBackpackLine2_4 = 44, // @ C044_COMMAND_CLICK_ON_SLOT_BOX_24_INVENTORY_BACKPACK_LINE2_4
kDMCommandClickOnSlotBoxInventoryBackpackLine2_5 = 45, // @ C045_COMMAND_CLICK_ON_SLOT_BOX_25_INVENTORY_BACKPACK_LINE2_5
kDMCommandClickOnSlotBoxInventoryBackpackLine2_6 = 46, // @ C046_COMMAND_CLICK_ON_SLOT_BOX_26_INVENTORY_BACKPACK_LINE2_6
kDMCommandClickOnSlotBoxInventoryBackpackLine2_7 = 47, // @ C047_COMMAND_CLICK_ON_SLOT_BOX_27_INVENTORY_BACKPACK_LINE2_7
kDMCommandClickOnSlotBoxInventoryBackpackLine2_8 = 48, // @ C048_COMMAND_CLICK_ON_SLOT_BOX_28_INVENTORY_BACKPACK_LINE2_8
kDMCommandClickOnSlotBoxInventoryBackpackLine2_9 = 49, // @ C049_COMMAND_CLICK_ON_SLOT_BOX_29_INVENTORY_BACKPACK_LINE2_9
kDMCommandClickOnSlotBoxInventoryBackpackLine1_2 = 50, // @ C050_COMMAND_CLICK_ON_SLOT_BOX_30_INVENTORY_BACKPACK_LINE1_2
kDMCommandClickOnSlotBoxInventoryBackpackLine1_3 = 51, // @ C051_COMMAND_CLICK_ON_SLOT_BOX_31_INVENTORY_BACKPACK_LINE1_3
kDMCommandClickOnSlotBoxInventoryBackpackLine1_4 = 52, // @ C052_COMMAND_CLICK_ON_SLOT_BOX_32_INVENTORY_BACKPACK_LINE1_4
kDMCommandClickOnSlotBoxInventoryBackpackLine1_5 = 53, // @ C053_COMMAND_CLICK_ON_SLOT_BOX_33_INVENTORY_BACKPACK_LINE1_5
kDMCommandClickOnSlotBoxInventoryBackpackLine1_6 = 54, // @ C054_COMMAND_CLICK_ON_SLOT_BOX_34_INVENTORY_BACKPACK_LINE1_6
kDMCommandClickOnSlotBoxInventoryBackpackLine1_7 = 55, // @ C055_COMMAND_CLICK_ON_SLOT_BOX_35_INVENTORY_BACKPACK_LINE1_7
kDMCommandClickOnSlotBoxInventoryBackpackLine1_8 = 56, // @ C056_COMMAND_CLICK_ON_SLOT_BOX_36_INVENTORY_BACKPACK_LINE1_8
kDMCommandClickOnSlotBoxInventoryBackpackLine1_9 = 57, // @ C057_COMMAND_CLICK_ON_SLOT_BOX_37_INVENTORY_BACKPACK_LINE1_9
kDMCommandClickOnSlotBoxChest1 = 58, // @ C058_COMMAND_CLICK_ON_SLOT_BOX_38_CHEST_1
kDMCommandClickOnSlotBoxChest2 = 59, // @ C059_COMMAND_CLICK_ON_SLOT_BOX_39_CHEST_2
kDMCommandClickOnSlotBoxChest3 = 60, // @ C060_COMMAND_CLICK_ON_SLOT_BOX_40_CHEST_3
kDMCommandClickOnSlotBoxChest4 = 61, // @ C061_COMMAND_CLICK_ON_SLOT_BOX_41_CHEST_4
kDMCommandClickOnSlotBoxChest5 = 62, // @ C062_COMMAND_CLICK_ON_SLOT_BOX_42_CHEST_5
kDMCommandClickOnSlotBoxChest6 = 63, // @ C063_COMMAND_CLICK_ON_SLOT_BOX_43_CHEST_6
kDMCommandClickOnSlotBoxChest7 = 64, // @ C064_COMMAND_CLICK_ON_SLOT_BOX_44_CHEST_7
kDMCommandClickOnSlotBoxChest8 = 65, // @ C065_COMMAND_CLICK_ON_SLOT_BOX_45_CHEST_8
kDMCommandClickOnMouth = 70, // @ C070_COMMAND_CLICK_ON_MOUTH
kDMCommandClickOnEye = 71, // @ C071_COMMAND_CLICK_ON_EYE
kDMCommandClickInDungeonView = 80, // @ C080_COMMAND_CLICK_IN_DUNGEON_VIEW
kDMCommandClickInPanel = 81, // @ C081_COMMAND_CLICK_IN_PANEL
kDMCommandToggleInventoryLeader = 83, // @ C083_COMMAND_TOGGLE_INVENTORY_LEADER
kDMCommandClickInSpellArea = 100, // @ C100_COMMAND_CLICK_IN_SPELL_AREA
kDMCommandClickInSpellAreaSymbol1 = 101, // @ C101_COMMAND_CLICK_IN_SPELL_AREA_SYMBOL_1
kDMCommandClickInSpellAreaSymbol2 = 102, // @ C102_COMMAND_CLICK_IN_SPELL_AREA_SYMBOL_2
kDMCommandClickInSpellAreaSymbol3 = 103, // @ C103_COMMAND_CLICK_IN_SPELL_AREA_SYMBOL_3
kDMCommandClickInSpellAreaSymbol4 = 104, // @ C104_COMMAND_CLICK_IN_SPELL_AREA_SYMBOL_4
kDMCommandClickInSpellAreaSymbol5 = 105, // @ C105_COMMAND_CLICK_IN_SPELL_AREA_SYMBOL_5
kDMCommandClickInSpellAreaSymbol6 = 106, // @ C106_COMMAND_CLICK_IN_SPELL_AREA_SYMBOL_6
kDMCommandClickInSpellAreaRecantSymbol = 107, // @ C107_COMMAND_CLICK_IN_SPELL_AREA_RECANT_SYMBOL
kDMCommandClickInSpeallAreaCastSpell = 108, // @ C108_COMMAND_CLICK_IN_SPELL_AREA_CAST_SPELL
kDMCommandClickInActionArea = 111, // @ C111_COMMAND_CLICK_IN_ACTION_AREA
kDMCommandClickInActionAreaPass = 112, // @ C112_COMMAND_CLICK_IN_ACTION_AREA_PASS
kDMCommandClickInActionAreaAction0 = 113, // @ C113_COMMAND_CLICK_IN_ACTION_AREA_ACTION_0
kDMCommandClickInActionAreaAction1 = 114, // @ C114_COMMAND_CLICK_IN_ACTION_AREA_ACTION_1
kDMCommandClickInActionAreaAction2 = 115, // @ C115_COMMAND_CLICK_IN_ACTION_AREA_ACTION_2
kDMCommandClickInActionAreaChampion0Action = 116, // @ C116_COMMAND_CLICK_IN_ACTION_AREA_CHAMPION_0_ACTION
kDMCommandClickInActionAreaChampion1Action = 117, // @ C117_COMMAND_CLICK_IN_ACTION_AREA_CHAMPION_1_ACTION
kDMCommandClickInActionAreaChampion2Action = 118, // @ C118_COMMAND_CLICK_IN_ACTION_AREA_CHAMPION_2_ACTION
kDMCommandClickInActionAreaChampion3Action = 119, // @ C119_COMMAND_CLICK_IN_ACTION_AREA_CHAMPION_3_ACTION
kDMCommandClickOnChamptionIconTopLeft = 125, // @ C125_COMMAND_CLICK_ON_CHAMPION_ICON_TOP_LEFT
kDMCommandClickOnChamptionIconTopRight = 126, // @ C126_COMMAND_CLICK_ON_CHAMPION_ICON_TOP_RIGHT
kDMCommandClickOnChamptionIconLowerRight = 127, // @ C127_COMMAND_CLICK_ON_CHAMPION_ICON_LOWER_RIGHT
kDMCommandClickOnChamptionIconLowerLeft = 128, // @ C128_COMMAND_CLICK_ON_CHAMPION_ICON_LOWER_LEFT
kDMCommandSaveGame = 140, // @ C140_COMMAND_SAVE_GAME
kDMCommandSleep = 145, // @ C145_COMMAND_SLEEP
kDMCommandWakeUp = 146, // @ C146_COMMAND_WAKE_UP
kDMCommandFreezeGame = 147, // @ C147_COMMAND_FREEZE_GAME
kDMCommandUnfreezeGame = 148, // @ C148_COMMAND_UNFREEZE_GAME
kDMCommandClickInPanelResurrect = 160, // @ C160_COMMAND_CLICK_IN_PANEL_RESURRECT
kDMCommandClickInPanelReincarnate = 161, // @ C161_COMMAND_CLICK_IN_PANEL_REINCARNATE
kDMCommandClickInPanelCancel = 162, // @ C162_COMMAND_CLICK_IN_PANEL_CANCEL
kDMCommandEntranceEnterDungeon = 200, // @ C200_COMMAND_ENTRANCE_ENTER_DUNGEON
kDMCommandEntranceResume = 201, // @ C201_COMMAND_ENTRANCE_RESUME /* Versions 1.x and 2.x command */
kDMCommandEntranceDrawCredits = 202, // @ C202_COMMAND_ENTRANCE_DRAW_CREDITS /* Versions 1.x and 2.x command */
kDMCommandClickOnDialogChoice1 = 210, // @ C210_COMMAND_CLICK_ON_DIALOG_CHOICE_1
kDMCommandClickOnDialogChoice2 = 211, // @ C211_COMMAND_CLICK_ON_DIALOG_CHOICE_2
kDMCommandClickOnDialogChoice3 = 212, // @ C212_COMMAND_CLICK_ON_DIALOG_CHOICE_3
kDMCommandClickOnDialogChoice4 = 213, // @ C213_COMMAND_CLICK_ON_DIALOG_CHOICE_4
kDMCommandRestartGame = 215 // @ C215_COMMAND_RESTART_GAME
};
class Command {
public:
Common::Point _pos;
CommandType _type;
Command(Common::Point position, CommandType commandType) : _pos(position), _type(commandType) {}
}; // @ COMMAND
class MouseInput {
public:
CommandType _commandTypeToIssue;
Box _hitbox;
MouseButton _button;
MouseInput(CommandType type, uint16 x1, uint16 x2, uint16 y1, uint16 y2, MouseButton mouseButton)
: _commandTypeToIssue(type), _hitbox(x1, x2 + 1, y1, y2 + 1), _button(mouseButton) {}
MouseInput()
: _commandTypeToIssue(kDMCommandNone), _hitbox(0, 1, 0, 1), _button(kDMMouseButtonNone) {}
}; // @ MOUSE_INPUT
class KeyboardInput {
public:
CommandType _commandToIssue;
Common::CustomEventType _action;
KeyboardInput(CommandType command, Common::CustomEventType action) : _commandToIssue(command), _action(action) {}
KeyboardInput() : _commandToIssue(kDMCommandNone), _action(kActionNone) {}
}; // @ KEYBOARD_INPUT
class DMEngine;
#define k0_pointerArrow 0 // @ C0_POINTER_ARROW
#define k1_pointerHand 1 // @ C1_POINTER_HAND
#define k0_pointerTypeArrow 0 // @ C0_POINTER_TYPE_ARROW
#define k1_pointerTypeObjectIcon 1 // @ C1_POINTER_TYPE_OBJECT_ICON
#define k2_pointerTypeChampionIcon 2 // @ C2_POINTER_TYPE_CHAMPION_ICON
#define k3_pointerTypeHand 3 // @ C3_POINTER_TYPE_HAND
#define k4_pointerTypeAutoselect 4 // @ C4_POINTER_TYPE_AUTOSELECT
class EventManager {
DMEngine *_vm;
Common::Point _mousePos;
uint16 _dummyMapIndex;
bool _pendingClickPresent; // G0436_B_PendingClickPresent
Common::Point _pendingClickPos; // @ G0437_i_PendingClickX, G0438_i_PendingClickY
MouseButton _pendingClickButton; // @ G0439_i_PendingClickButtonsStatus
bool _useObjectAsMousePointerBitmap; // @ G0600_B_UseObjectAsMousePointerBitmap
bool _useHandAsMousePointerBitmap; // @ G0601_B_UseHandAsMousePointerBitmap
bool _preventBuildPointerScreenArea; // @ K0100_B_PreventBuildPointerScreenArea
byte *_mousePointerOriginalColorsObject; // @ G0615_puc_Bitmap_MousePointerOriginalColorsObject
byte *_mousePointerOriginalColorsChampionIcon; // @ G0613_puc_Bitmap_MousePointerOriginalColorsChampionIcon
byte *_mousePointerTempBuffer; // @ K0190_puc_Bitmap_MousePointerTemporaryBuffer
int16 _mousePointerType; // @ K0104_i_MousePointerType
int16 _previousMousePointerType; // @ K0105_i_PreviousMousePointerType
uint16 _mouseButtonStatus;// @ G0588_i_MouseButtonsStatus
// this doesn't seem to be used anywhere at all
bool _isCommandQueueLocked; // @ G0435_B_CommandQueueLocked
Common::Queue<Command> _commandQueue;
void commandTurnParty(CommandType cmdType); // @ F0365_COMMAND_ProcessTypes1To2_TurnParty
void commandMoveParty(CommandType cmdType); // @ F0366_COMMAND_ProcessTypes3To6_MoveParty
bool isLeaderHandObjThrown(int16 posX, int16 posY); // @ F0375_COMMAND_ProcessType80_ClickInDungeonView_IsLeaderHandObjectThrown
void setMousePointerFromSpriteData(byte *mouseSprite);
Box _highlightScreenBox; // @ G0336_i_HighlightBoxX1
public:
explicit EventManager(DMEngine *vm);
~EventManager();
MouseInput *_primaryMouseInput;// @ G0441_ps_PrimaryMouseInput
MouseInput *_secondaryMouseInput;// @ G0442_ps_SecondaryMouseInput
bool _mousePointerBitmapUpdated; // @ G0598_B_MousePointerBitmapUpdated
bool _refreshMousePointerInMainLoop; // @ G0326_B_RefreshMousePointerInMainLoop
bool _highlightBoxEnabled; // @ G0341_B_HighlightBoxEnabled
uint16 _useChampionIconOrdinalAsMousePointerBitmap; // @ G0599_ui_UseChampionIconOrdinalAsMousePointerBitmap
KeyboardInput *_primaryKeyboardInput; // @ G0443_ps_PrimaryKeyboardInput
KeyboardInput *_secondaryKeyboardInput; // @ G0444_ps_SecondaryKeyboardInput
bool _ignoreMouseMovements;// @ G0597_B_IgnoreMouseMovements
int16 _hideMousePointerRequestCount; // @ G0587_i_HideMousePointerRequestCount
void initMouse();
void setMousePointerToNormal(int16 mousePointer); // @ F0067_MOUSE_SetPointerToNormal
void setPointerToObject(byte *bitmap); // @ F0068_MOUSE_SetPointerToObject
void mouseDropChampionIcon(); // @ F0071_MOUSE_DropChampionIcon
void buildpointerScreenArea(int16 mousePosX, int16 mousePosY); // @ F0073_MOUSE_BuildPointerScreenArea
void setMousePointer(); // @ F0069_MOUSE_SetPointer
void showMouse(); // @ F0077_MOUSE_HidePointer_CPSE
void hideMouse(); // @ F0078_MOUSE_ShowPointer
bool isMouseButtonDown(MouseButton button);
void setMousePos(Common::Point pos);
Common::Point getMousePos() { return _mousePos; }
/**
* Upon encountering an event type for which the grab parameter is not null, the function
* will return with the event type, passes the event to the grab desitination and returns without
* processing the rest of the events into commands according to the current keyboard and mouse input.
* If there are no more events, it returns with Common::EVENT_INVALID.
*/
Common::EventType processInput(Common::Event *grabKey = nullptr, Common::Event *grabMouseClick = nullptr);
void processPendingClick(); // @ F0360_COMMAND_ProcessPendingClick
void processClick(Common::Point mousePos, MouseButton button); // @ F0359_COMMAND_ProcessClick_CPSC
CommandType getCommandTypeFromMouseInput(MouseInput *input, Common::Point mousePos, MouseButton button); // @ F0358_COMMAND_GetCommandFromMouseInput_CPSC
void processCommandQueue(); // @ F0380_COMMAND_ProcessQueue_CPSC
void commandSetLeader(ChampionIndex index); // @ F0368_COMMAND_SetLeader
void commandProcessType80ClickInDungeonViewTouchFrontWall(); // @ F0372_COMMAND_ProcessType80_ClickInDungeonView_TouchFrontWall
void commandProcessType80ClickInDungeonView(int16 posX, int16 posY); // @ F0377_COMMAND_ProcessType80_ClickInDungeonView
void commandProcessCommands160To162ClickInResurrectReincarnatePanel(CommandType commandType); // @ F0282_CHAMPION_ProcessCommands160To162_ClickInResurrectReincarnatePanel
void commandProcess81ClickInPanel(int16 x, int16 y); // @ F0378_COMMAND_ProcessType81_ClickInPanel
void processType80_clickInDungeonView_grabLeaderHandObject(uint16 viewCell); // @ F0373_COMMAND_ProcessType80_ClickInDungeonView_GrabLeaderHandObject
void clickInDungeonViewDropLeaderHandObject(uint16 viewCell); // @ F0374_COMMAND_ProcessType80_ClickInDungeonView_DropLeaderHandObject
bool hasPendingClick(Common::Point &point, MouseButton button); // @ F0360_COMMAND_ProcessPendingClick
void drawSleepScreen(); // @ F0379_COMMAND_DrawSleepScreen
void discardAllInput(); // @ F0357_COMMAND_DiscardAllInput
void commandTakeStairs(bool stairsGoDown);// @ F0364_COMMAND_TakeStairs
void commandProcessTypes12to27_clickInChampionStatusBox(uint16 champIndex, int16 posX,
int16 posY); // @ F0367_COMMAND_ProcessTypes12To27_ClickInChampionStatusBox
void mouseProcessCommands125To128_clickOnChampionIcon(uint16 champIconIndex); // @ F0070_MOUSE_ProcessCommands125To128_ClickOnChampionIcon
void commandProcessType100_clickInSpellArea(uint16 posX, uint16 posY); // @ F0370_COMMAND_ProcessType100_ClickInSpellArea
void commandProcessTypes101To108_clickInSpellSymbolsArea(CommandType cmdType); // @ F0369_COMMAND_ProcessTypes101To108_ClickInSpellSymbolsArea_CPSE
void commandProcessType111To115_ClickInActionArea(int16 posX, int16 posY); // @ F0371_COMMAND_ProcessType111To115_ClickInActionArea_CPSE
void resetPressingEyeOrMouth(); // @ F0544_INPUT_ResetPressingEyeOrMouth
void waitForMouseOrKeyActivity(); // @ F0541_INPUT_WaitForMouseOrKeyboardActivity
void commandHighlightBoxEnable(int16 x1, int16 x2, int16 y1, int16 y2); // @ F0362_COMMAND_HighlightBoxEnable
void highlightBoxDisable(); // @ F0363_COMMAND_HighlightBoxDisable
void highlightScreenBox(int16 x1, int16 x2, int16 y1, int16 y2) { warning("STUB METHOD: highlightScreenBox"); } // @ F0006_MAIN_HighlightScreenBox
KeyboardInput _primaryKeyboardInputInterface[7]; // @ G0458_as_Graphic561_PrimaryKeyboardInput_Interface
KeyboardInput _secondaryKeyboardInputMovement[19]; // @ G0459_as_Graphic561_SecondaryKeyboardInput_Movement
KeyboardInput _primaryKeyboardInputPartySleeping[3]; // @ G0460_as_Graphic561_PrimaryKeyboardInput_PartySleeping
KeyboardInput _primaryKeyboardInputFrozenGame[2]; // @ G0461_as_Graphic561_PrimaryKeyboardInput_FrozenGame
MouseInput _primaryMouseInputEntrance[4]; // @ G0445_as_Graphic561_PrimaryMouseInput_Entrance[4]
MouseInput _primaryMouseInputRestartGame[2]; // @ G0446_as_Graphic561_PrimaryMouseInput_RestartGame[2]
MouseInput _primaryMouseInputInterface[20]; // @ G0447_as_Graphic561_PrimaryMouseInput_Interface[20]
MouseInput _secondaryMouseInputMovement[9]; // @ G0448_as_Graphic561_SecondaryMouseInput_Movement[9]
MouseInput _secondaryMouseInputChampionInventory[38]; // @ G0449_as_Graphic561_SecondaryMouseInput_ChampionInventory[38]
MouseInput _primaryMouseInputPartySleeping[3]; // @ G0450_as_Graphic561_PrimaryMouseInput_PartySleeping[3]
MouseInput _primaryMouseInputFrozenGame[3]; // @ G0451_as_Graphic561_PrimaryMouseInput_FrozenGame[3]
MouseInput _mouseInputActionAreaNames[5]; // @ G0452_as_Graphic561_MouseInput_ActionAreaNames[5]
MouseInput _mouseInputActionAreaIcons[5]; // @ G0453_as_Graphic561_MouseInput_ActionAreaIcons[5]
MouseInput _mouseInputSpellArea[9]; // @ G0454_as_Graphic561_MouseInput_SpellArea[9]
MouseInput _mouseInputChampionNamesHands[13]; // @ G0455_as_Graphic561_MouseInput_ChampionNamesHands[13]
MouseInput _mouseInputPanelChest[9]; // @ G0456_as_Graphic561_MouseInput_PanelChest[9]
MouseInput _mouseInputPanelResurrectReincarnateCancel[4]; // @ G0457_as_Graphic561_MouseInput_PanelResurrectReincarnateCancel[4]
MouseInput _primaryMouseInputViewportDialog1Choice[2]; // @ G0471_as_Graphic561_PrimaryMouseInput_ViewportDialog1Choice[2]
MouseInput _primaryMouseInputScreenDialog1Choice[2]; // @ G0475_as_Graphic561_PrimaryMouseInput_ScreenDialog1Choice[2]
MouseInput _primaryMouseInputViewportDialog2Choices[3]; // @ G0472_as_Graphic561_PrimaryMouseInput_ViewportDialog2Choices[3]
MouseInput _primaryMouseInputScreenDialog2Choices[3]; // @ G0476_as_Graphic561_PrimaryMouseInput_ScreenDialog2Choices[3]
MouseInput _primaryMouseInputViewportDialog3Choices[4]; // @ G0473_as_Graphic561_PrimaryMouseInput_ViewportDialog3Choices[4]
MouseInput _primaryMouseInputScreenDialog3Choices[4]; // @ G0477_as_Graphic561_PrimaryMouseInput_ScreenDialog3Choices[4]
MouseInput _primaryMouseInputViewportDialog4Choices[5]; // @ G0474_as_Graphic561_PrimaryMouseInput_ViewportDialog4Choices[5]
MouseInput _primaryMouseInputScreenDialog4Choices[5]; // @ G0478_as_Graphic561_PrimaryMouseInput_ScreenDialog4Choices[5]
MouseInput *_primaryMouseInputDialogSets[2][4]; // @ G0480_aaps_PrimaryMouseInput_DialogSets
void initArrays();
};
}
#endif

4004
engines/dm/gfx.cpp Normal file

File diff suppressed because it is too large Load Diff

837
engines/dm/gfx.h Normal file
View File

@@ -0,0 +1,837 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_GFX_H
#define DM_GFX_H
#include "common/scummsys.h"
#include "common/rect.h"
#include "common/memstream.h"
#include "common/array.h"
#include "dm/dm.h"
namespace DM {
enum ViewFloor {
kDMViewFloorD3L = 0, // @ C0_VIEW_FLOOR_D3L
kDMViewFloorD3C = 1, // @ C1_VIEW_FLOOR_D3C
kDMViewFloorD3R = 2, // @ C2_VIEW_FLOOR_D3R
kDMViewFloorD2L = 3, // @ C3_VIEW_FLOOR_D2L
kDMViewFloorD2C = 4, // @ C4_VIEW_FLOOR_D2C
kDMViewFloorD2R = 5, // @ C5_VIEW_FLOOR_D2R
kDMViewFloorD1L = 6, // @ C6_VIEW_FLOOR_D1L
kDMViewFloorD1C = 7, // @ C7_VIEW_FLOOR_D1C
kDMViewFloorD1R = 8 // @ C8_VIEW_FLOOR_D1R
};
enum DoorState {
kDMDoorStateOpen = 0, // @ C0_DOOR_STATE_OPEN
kDMDoorStateOneFourth = 1, // @ C1_DOOR_STATE_CLOSED_ONE_FOURTH
kDMDoorStateHalf = 2, // @ k2_DoorStateAspect_CLOSED_HALF
kDMDoorStateThreeFourth = 3, // @ C3_DOOR_STATE_CLOSED_THREE_FOURTH
kDMDoorStateClosed = 4, // @ C4_DOOR_STATE_CLOSED
kDMDoorStateDestroyed = 5 // @ C5_DOOR_STATE_DESTROYED
};
enum DoorOrnament {
kDMDoorOrnamentD3LCR = 0, // @ C0_VIEW_DOOR_ORNAMENT_D3LCR
kDMDoorOrnamentD2LCR = 1, // @ C1_VIEW_DOOR_ORNAMENT_D2LCR
kDMDoorOrnamentD1LCR = 2 // @ C2_VIEW_DOOR_ORNAMENT_D1LCR
};
enum DoorButton {
kDMDoorButtonD3R = 0, // @ C0_VIEW_DOOR_BUTTON_D3R
kDMDoorButtonD3C = 1, // @ C1_VIEW_DOOR_BUTTON_D3C
kDMDoorButtonD2C = 2, // @ C2_VIEW_DOOR_BUTTON_D2C
kDMDoorButtonD1C = 3 // @ C3_VIEW_DOOR_BUTTON_D1C
};
/* View lanes */
enum ViewLane {
kDMViewLaneCenter = 0, // @ C0_VIEW_LANE_CENTER
kDMViewLaneLeft = 1, // @ C1_VIEW_LANE_LEFT
kDMViewLaneRight = 2 // @ C2_VIEW_LANE_RIGHT
};
/* Explosion aspects */
enum ExplosionAspectEnum {
kDMExplosionAspectFire = 0, // @ C0_EXPLOSION_ASPECT_FIRE
kDMExplosionAspectSpell = 1, // @ C1_EXPLOSION_ASPECT_SPELL
kDMExplosionAspectPoison = 2, // @ C2_EXPLOSION_ASPECT_POISON
kDMExplosionAspectSmoke = 3 // @ C3_EXPLOSION_ASPECT_SMOKE
};
enum WallSet {
kDMWallSetStone = 0 // @ C0_WALL_SET_STONE
};
enum FloorSet {
kDMFloorSetStone = 0 // @ C0_FLOOR_SET_STONE
};
enum ViewWall {
kDMViewWallD3LRight = 0, // @ C00_VIEW_WALL_D3L_RIGHT
kDMViewWallD3RLeft = 1, // @ C01_VIEW_WALL_D3R_LEFT
kDMViewWallD3LFront = 2, // @ C02_VIEW_WALL_D3L_FRONT
kDMViewWallD3CFront = 3, // @ C03_VIEW_WALL_D3C_FRONT
kDMViewWallD3RFront = 4, // @ C04_VIEW_WALL_D3R_FRONT
kDMViewWallD2LRight = 5, // @ C05_VIEW_WALL_D2L_RIGHT
kDMViewWallD2RLeft = 6, // @ C06_VIEW_WALL_D2R_LEFT
kDMViewWallD2LFront = 7, // @ C07_VIEW_WALL_D2L_FRONT
kDMViewWallD2CFront = 8, // @ C08_VIEW_WALL_D2C_FRONT
kDMViewWallD2RFront = 9, // @ C09_VIEW_WALL_D2R_FRONT
kDMViewWallD1LRight = 10, // @ C10_VIEW_WALL_D1L_RIGHT
kDMViewWallD1RLeft = 11, // @ C11_VIEW_WALL_D1R_LEFT
kDMViewWallD1CFront = 12 // @ C12_VIEW_WALL_D1C_FRONT
};
enum CellOrder {
kDMCellOrderNone = 0xFFFF,
kDMCellOrderAlcove = 0x0000, // @ C0000_CELL_ORDER_ALCOVE
kDMCellOrderBackLeft = 0x0001, // @ C0001_CELL_ORDER_BACKLEFT
kDMCellOrderBackRight = 0x0002, // @ C0002_CELL_ORDER_BACKRIGHT
kDMCellOrderDoorPass1BackLeft = 0x0018, // @ C0018_CELL_ORDER_DOORPASS1_BACKLEFT
kDMCellOrderBackLeftBackRight = 0x0021, // @ C0021_CELL_ORDER_BACKLEFT_BACKRIGHT
kDMCellOrderDoorPass1BackRight = 0x0028, // @ C0028_CELL_ORDER_DOORPASS1_BACKRIGHT
kDMCellOrderBackRightFrontRight = 0x0032, // @ C0032_CELL_ORDER_BACKRIGHT_FRONTRIGHT
kDMCellOrderDoorPass2FrontRight = 0x0039, // @ C0039_CELL_ORDER_DOORPASS2_FRONTRIGHT
kDMCellOrderBackLeftFrontLeft = 0x0041, // @ C0041_CELL_ORDER_BACKLEFT_FRONTLEFT
kDMCellOrderDoorPass2FrontLeft = 0x0049, // @ C0049_CELL_ORDER_DOORPASS2_FRONTLEFT
kDMCellOrderDoorPass1BackRightBackLeft = 0x0128, // @ C0128_CELL_ORDER_DOORPASS1_BACKRIGHT_BACKLEFT
kDMCellOrderDoorPass1BackLeftBackRight = 0x0218, // @ C0218_CELL_ORDER_DOORPASS1_BACKLEFT_BACKRIGHT
kDMCellOrderBackLeftBackRightFrontRight = 0x0321, // @ C0321_CELL_ORDER_BACKLEFT_BACKRIGHT_FRONTRIGHT
kDMCellOrderBackRightFrontLeftFrontRight = 0x0342, // @ C0342_CELL_ORDER_BACKRIGHT_FRONTLEFT_FRONTRIGHT
kDMCellOrderDoorPass2FrontLeftFrontRight = 0x0349, // @ C0349_CELL_ORDER_DOORPASS2_FRONTLEFT_FRONTRIGHT
kDMCellOrderBackRightBackLeftFrontLeft = 0x0412, // @ C0412_CELL_ORDER_BACKRIGHT_BACKLEFT_FRONTLEFT
kDMCellOrderBackLeftFrontRightFrontLeft = 0x0431, // @ C0431_CELL_ORDER_BACKLEFT_FRONTRIGHT_FRONTLEFT
kDMCellOrderDoorPass2FrontRightFrontLeft = 0x0439, // @ C0439_CELL_ORDER_DOORPASS2_FRONTRIGHT_FRONTLEFT
kDMCellOrderBackLeftBackRightFrontLeftFrontRight = 0x3421, // @ C3421_CELL_ORDER_BACKLEFT_BACKRIGHT_FRONTLEFT_FRONTRIGHT
kDMCellOrderBackRightBackLeftFrontRightFrontLeft = 0x4312 // @ C4312_CELL_ORDER_BACKRIGHT_BACKLEFT_FRONTRIGHT_FRONTLEFT
};
enum DerivedBitmap {
kDMDerivedBitmapViewport = 0, // @ C000_DERIVED_BITMAP_VIEWPORT
kDMDerivedBitmapThievesEyeVisibleArea = 1, // @ C001_DERIVED_BITMAP_THIEVES_EYE_VISIBLE_AREA
kDMDerivedBitmapDamageToCreatureMedium = 2, // @ C002_DERIVED_BITMAP_DAMAGE_TO_CREATURE_MEDIUM
kDMDerivedBitmapDamageToCreatureSmall = 3, // @ C003_DERIVED_BITMAP_DAMAGE_TO_CREATURE_SMALL
kDMDerivedBitmapFirstWallOrnament = 4, // @ C004_DERIVED_BITMAP_FIRST_WALL_ORNAMENT
kDMDerivedBitmapFirstDoorOrnamentD3 = 68, // @ C068_DERIVED_BITMAP_FIRST_DOOR_ORNAMENT_D3
kDMDerivedBitmapFirstDoorOrnamentD2 = 69, // @ C069_DERIVED_BITMAP_FIRST_DOOR_ORNAMENT_D2
kDMDerivedBitmapFirstDoorButton = 102, // @ C102_DERIVED_BITMAP_FIRST_DOOR_BUTTON
kDMDerivedBitmapFirstObject = 104, // @ C104_DERIVED_BITMAP_FIRST_OBJECT
kDMDerivedBitmapFirstProjectile = 282, // @ C282_DERIVED_BITMAP_FIRST_PROJECTILE
kDMDerivedBitmapFirstExplosion = 438, // @ C438_DERIVED_BITMAP_FIRST_EXPLOSION
kDMDerivedBitmapFirstCreature = 495 // @ C495_DERIVED_BITMAP_FIRST_CREATURE
};
enum ViewSquare {
kDMViewSquareD4C = -3, // @ CM3_VIEW_SQUARE_D4C
kViewSquareD4L = -2, // @ CM2_VIEW_SQUARE_D4L
kDMViewSquareD4R = -1, // @ CM1_VIEW_SQUARE_D4R
kDMViewSquareD3C = 0, // @ C00_VIEW_SQUARE_D3C
kDMViewSquareD3L = 1, // @ C01_VIEW_SQUARE_D3L
kDMViewSquareD3R = 2, // @ C02_VIEW_SQUARE_D3R
kDMViewSquareD2C = 3, // @ C03_VIEW_SQUARE_D2C
kDMViewSquareD2L = 4, // @ C04_VIEW_SQUARE_D2L
kDMViewSquareD2R = 5, // @ C05_VIEW_SQUARE_D2R
kDMViewSquareD1C = 6, // @ C06_VIEW_SQUARE_D1C
kDMViewSquareD1L = 7, // @ C07_VIEW_SQUARE_D1L
kDMViewSquareD1R = 8, // @ C08_VIEW_SQUARE_D1R
kDMViewSquareD0C = 9, // @ C09_VIEW_SQUARE_D0C
kDMViewSquareD0L = 10, // @ C10_VIEW_SQUARE_D0L
kDMViewSquareD0R = 11, // @ C11_VIEW_SQUARE_D0R
kDMViewSquareD3CExplosion = 3, // @ C03_VIEW_SQUARE_D3C_EXPLOSION
kDMViewSquareD3LExplosion = 4, // @ C04_VIEW_SQUARE_D3L_EXPLOSION
kDMViewSquareD1CExplosion = 9, // @ C09_VIEW_SQUARE_D1C_EXPLOSION
kDMViewSquareD0CExplosion = 12 // @ C12_VIEW_SQUARE_D0C_EXPLOSION
};
enum ViewCell {
kDMViewCellFronLeft = 0, // @ C00_VIEW_CELL_FRONT_LEFT
kDMViewCellFrontRight = 1, // @ C01_VIEW_CELL_FRONT_RIGHT
kDMViewCellBackRight = 2, // @ C02_VIEW_CELL_BACK_RIGHT
kDMViewCellBackLeft = 3, // @ C03_VIEW_CELL_BACK_LEFT
kDMViewCellAlcove = 4, // @ C04_VIEW_CELL_ALCOVE
kDMViewCellDoorButtonOrWallOrn = 5 // @ C05_VIEW_CELL_DOOR_BUTTON_OR_WALL_ORNAMENT
};
enum Color {
kDMColorNoTransparency = -1,
kDMColorBlack = 0,
kDMColorDarkGary = 1,
kDMColorLightGray = 2,
kDMColorDarkBrown = 3,
kDMColorCyan = 4,
kDMColorLightBrown = 5,
kDMColorDarkGreen = 6,
kDMColorLightGreen = 7,
kDMColorRed = 8,
kDMColorGold = 9,
kDMColorFlesh = 10,
kDMColorYellow = 11,
kDMColorDarkestGray = 12,
kDMColorLightestGray = 13,
kDMColorBlue = 14,
kDMColorWhite = 15
};
enum GraphicIndice {
kDMGraphicIdxDialogBox = 0, // @ C000_GRAPHIC_DIALOG_BOX
kDMGraphicIdxTitle = 1, // @ C001_GRAPHIC_TITLE
kDMGraphicIdxEntranceLeftDoor = 2, // @ C002_GRAPHIC_ENTRANCE_LEFT_DOOR
kDMGraphicIdxEntranceRightDoor = 3, // @ C003_GRAPHIC_ENTRANCE_RIGHT_DOOR
kDMGraphicIdxEntrance = 4, // @ C004_GRAPHIC_ENTRANCE
kDMGraphicIdxCredits = 5, // @ C005_GRAPHIC_CREDITS
kDMGraphicIdxTheEnd = 6, // @ C006_GRAPHIC_THE_END
kDMGraphicIdxStatusBoxDeadChampion = 8, // @ C008_GRAPHIC_STATUS_BOX_DEAD_CHAMPION
kDMGraphicIdxMenuSpellAreaBackground = 9, // @ C009_GRAPHIC_MENU_SPELL_AREA_BACKGROUND
kDMGraphicIdxMenuActionArea = 10, // @ C010_GRAPHIC_MENU_ACTION_AREA
kDMGraphicIdxMenuSpellAreLines = 11, // @ C011_GRAPHIC_MENU_SPELL_AREA_LINES
kDMGraphicIdxMovementArrows = 13, // @ C013_GRAPHIC_MOVEMENT_ARROWS
kDMGraphicIdxDamageToCreature = 14, // @ C014_GRAPHIC_DAMAGE_TO_CREATURE
kDMGraphicIdxDamageToChampionSmall = 15, // @ C015_GRAPHIC_DAMAGE_TO_CHAMPION_SMALL
kDMGraphicIdxDamageToChampionBig = 16, // @ C016_GRAPHIC_DAMAGE_TO_CHAMPION_BIG
kDMGraphicIdxInventory = 17, // @ C017_GRAPHIC_INVENTORY
kDMGraphicIdxArrowForChestContent = 18, // @ C018_GRAPHIC_ARROW_FOR_CHEST_CONTENT
kDMGraphicIdxEyeForObjectDescription = 19, // @ C019_GRAPHIC_EYE_FOR_OBJECT_DESCRIPTION
kDMGraphicIdxPanelEmpty = 20, // @ C020_GRAPHIC_PANEL_EMPTY
kDMGraphicIdxPanelOpenScroll = 23, // @ C023_GRAPHIC_PANEL_OPEN_SCROLL
kDMGraphicIdxPanelOpenChest = 25, // @ C025_GRAPHIC_PANEL_OPEN_CHEST
kDMGraphicIdxChampionPortraits = 26, // @ C026_GRAPHIC_CHAMPION_PORTRAITS
kDMGraphicIdxPanelRenameChampion = 27, // @ C027_GRAPHIC_PANEL_RENAME_CHAMPION
kDMGraphicIdxChampionIcons = 28, // @ C028_GRAPHIC_CHAMPION_ICONS
kDMGraphicIdxObjectDescCircle = 29, // @ C029_GRAPHIC_OBJECT_DESCRIPTION_CIRCLE
kDMGraphicIdxFoodLabel = 30, // @ C030_GRAPHIC_FOOD_LABEL
kDMGraphicIdxWaterLabel = 31, // @ C031_GRAPHIC_WATER_LABEL
kDMGraphicIdxPoisionedLabel = 32, // @ C032_GRAPHIC_POISONED_LABEL
kDMGraphicIdxSlotBoxNormal = 33, // @ C033_GRAPHIC_SLOT_BOX_NORMAL
kDMGraphicIdxSlotBoxWounded = 34, // @ C034_GRAPHIC_SLOT_BOX_WOUNDED
kDMGraphicIdxSlotBoxActingHand = 35, // @ C035_GRAPHIC_SLOT_BOX_ACTING_HAND
kDMGraphicIdxBorderPartyShield = 37, // @ C037_GRAPHIC_BORDER_PARTY_SHIELD
kDMGraphicIdxBorderPartyFireshield = 38, // @ C038_GRAPHIC_BORDER_PARTY_FIRESHIELD
kDMGraphicIdxBorderPartySpellshield = 39, // @ C039_GRAPHIC_BORDER_PARTY_SPELLSHIELD
kDMGraphicIdxPanelResurectReincarnate = 40, // @ C040_GRAPHIC_PANEL_RESURRECT_REINCARNATE
kDMGraphicIdxHoleInWall = 41, // @ C041_GRAPHIC_HOLE_IN_WALL
kDMGraphicIdxObjectIcons000To031 = 42, // @ C042_GRAPHIC_OBJECT_ICONS_000_TO_031
kDMGraphicIdxObjectIcons032To063 = 43, // @ C043_GRAPHIC_OBJECT_ICONS_032_TO_063
kDMGraphicIdxObjectIcons064To095 = 44, // @ C044_GRAPHIC_OBJECT_ICONS_064_TO_095
kDMGraphicIdxObjectIcons096To127 = 45, // @ C045_GRAPHIC_OBJECT_ICONS_096_TO_127
kDMGraphicIdxObjectIcons128To159 = 46, // @ C046_GRAPHIC_OBJECT_ICONS_128_TO_159
kDMGraphicIdxObjectIcons160To191 = 47, // @ C047_GRAPHIC_OBJECT_ICONS_160_TO_191
kDMGraphicIdxObjectIcons192To223 = 48, // @ C048_GRAPHIC_OBJECT_ICONS_192_TO_223
kDMGraphicIdxFloorPitD3L = 49, // @ C049_GRAPHIC_FLOOR_PIT_D3L
kDMGraphicIdxFloorPitD3C = 50, // @ C050_GRAPHIC_FLOOR_PIT_D3C
kDMGraphicIdxFloorPitD2L = 51, // @ C051_GRAPHIC_FLOOR_PIT_D2L
kDMGraphicIdxFloorPitD2C = 52, // @ C052_GRAPHIC_FLOOR_PIT_D2C
kDMGraphicIdxFloorPitD1L = 53, // @ C053_GRAPHIC_FLOOR_PIT_D1L
kDMGraphicIdxFloorPitD1C = 54, // @ C054_GRAPHIC_FLOOR_PIT_D1C
kDMGraphicIdxFloorPitD0L = 55, // @ C055_GRAPHIC_FLOOR_PIT_D0L
kDMGraphicIdxFloorPitD0C = 56, // @ C056_GRAPHIC_FLOOR_PIT_D0C
kDMGraphicIdxFloorPitInvisibleD2L = 57, // @ C057_GRAPHIC_FLOOR_PIT_INVISIBLE_D2L
kDMGraphicIdxFloorPitInvisibleD2C = 58, // @ C058_GRAPHIC_FLOOR_PIT_INVISIBLE_D2C
kDMGraphicIdxFloorPitInvisibleD1L = 59, // @ C059_GRAPHIC_FLOOR_PIT_INVISIBLE_D1L
kDMGraphicIdxFloorPitInvisibleD1C = 60, // @ C060_GRAPHIC_FLOOR_PIT_INVISIBLE_D1C
kDMGraphicIdxFloorPitInvisibleD0L = 61, // @ C061_GRAPHIC_FLOOR_PIT_INVISIBLE_D0L
kDMGraphicIdxFloorPitInvisibleD0C = 62, // @ C062_GRAPHIC_FLOOR_PIT_INVISIBLE_D0C
kDMGraphicIdxCeilingPitD2L = 63, // @ C063_GRAPHIC_CEILING_PIT_D2L
kDMGraphicIdxCeilingPitD2C = 64, // @ C064_GRAPHIC_CEILING_PIT_D2C
kDMGraphicIdxCeilingPitD1L = 65, // @ C065_GRAPHIC_CEILING_PIT_D1L
kDMGraphicIdxCeilingPitD1C = 66, // @ C066_GRAPHIC_CEILING_PIT_D1C
kDMGraphicIdxCeilingPitD0L = 67, // @ C067_GRAPHIC_CEILING_PIT_D0L
kDMGraphicIdxCeilingPitD0C = 68, // @ C068_GRAPHIC_CEILING_PIT_D0C
kDMGraphicIdxFieldMaskD3R = 69, // @ C069_GRAPHIC_FIELD_MASK_D3R
kDMGraphicIdxFieldTeleporter = 73, // @ C073_GRAPHIC_FIELD_TELEPORTER
kDMGraphicIdxInscriptionFont = 120, // @ C120_GRAPHIC_INSCRIPTION_FONT
kDMGraphicIdxWallOrnChampMirror = 208, // @ C208_GRAPHIC_WALL_ORNAMENT_43_CHAMPION_MIRROR
kDMGraphicIdxFloorOrnD3LFootprints = 241, // @ C241_GRAPHIC_FLOOR_ORNAMENT_15_D3L_FOOTPRINTS
kDMGraphicIdxDoorMaskDestroyed = 301, // @ C301_GRAPHIC_DOOR_MASK_DESTROYED
kDMGraphicIdxFirstDoorButton = 315, // @ C315_GRAPHIC_FIRST_DOOR_BUTTON
kDMGraphicIdxFirstProjectile = 316, // @ C316_GRAPHIC_FIRST_PROJECTILE
kDMGraphicIdxFirstExplosion = 348, // @ C348_GRAPHIC_FIRST_EXPLOSION
kDMGraphicIdxFirstExplosionPattern = 351, // @ C351_GRAPHIC_FIRST_EXPLOSION_PATTERN
kDMGraphicIdxFirstObject = 360, // @ C360_GRAPHIC_FIRST_OBJECT
kDMGraphicIdxFirstCreature = 446, // @ C446_GRAPHIC_FIRST_CREATURE
kDMGraphicIdxFont = 557 // @ C557_GRAPHIC_FONT
};
#define kDMMaskDoorInfoCreaturesCanSeeThrough 0x0001 // @ MASK0x0001_CREATURES_CAN_SEE_THROUGH
#define kDMMaskDoorInfoProjectilesCanPassThrough 0x0002 // @ MASK0x0002_PROJECTILES_CAN_PASS_THROUGH
#define kDMMaskDoorInfoAnimated 0x0004 // @ MASK0x0004_ANIMATED
#define kDMMaskDoorFront 0x0008 // @ MASK0x0008_DOOR_FRONT
/* Field Aspect Mask */
#define kMaskFieldAspectFlipMask 0x0080 // @ MASK0x0080_FLIP_MASK
#define kMaskFieldAspectIndex 0x007F // @ MASK0x007F_MASK_INDEX
#define kMaskFieldAspectNoMask 255 // @ C255_NO_MASK
#define kDMCreatureMaskAdditional 0x0003 // @ MASK0x0003_ADDITIONAL
#define kDMCreatureMaskFlipNonAttack 0x0004 // @ MASK0x0004_FLIP_NON_ATTACK
#define kDMCreatureMaskSide 0x0008 // @ MASK0x0008_SIDE
#define kDMCreatureMaskBack 0x0010 // @ MASK0x0010_BACK
#define kDMCreatureMaskAttack 0x0020 // @ MASK0x0020_ATTACK
#define kDMCreatureMaskSpecialD2Front 0x0080 // @ MASK0x0080_SPECIAL_D2_FRONT
#define kDMCreatureMaskSpecialD2FrontIsFlipped 0x0100 // @ MASK0x0100_SPECIAL_D2_FRONT_IS_FLIPPED_FRONT
#define kDMCreatureMaskFlipAttack 0x0200 // @ MASK0x0200_FLIP_ATTACK
#define kDMCreatureMaskFlipDuringAttack 0x0400 // @ MASK0x0400_FLIP_DURING_ATTACK
#define k2_FloorSetGraphicCount 2 // @ C002_FLOOR_SET_GRAPHIC_COUNT
#define k13_WallSetGraphicCount 13 // @ C013_WALL_SET_GRAPHIC_COUNT
#define k18_StairsGraphicCount 18 // @ C018_STAIRS_GRAPHIC_COUNT
#define k3_DoorSetGraphicsCount 3 // @ C003_DOOR_SET_GRAPHIC_COUNT
#define k1_DoorButtonCount 1 // @ C001_DOOR_BUTTON_COUNT
#define k3_AlcoveOrnCount 3 // @ C003_ALCOVE_ORNAMENT_COUNT
#define k1_FountainOrnCount 1 // @ C001_FOUNTAIN_ORNAMENT_COUNT
#define k27_CreatureTypeCount 27 // @ C027_CREATURE_TYPE_COUNT
#define k4_ExplosionAspectCount 4 // @ C004_EXPLOSION_ASPECT_COUNT
#define k14_ProjectileAspectCount 14 // @ C014_PROJECTILE_ASPECT_COUNT
#define k85_ObjAspectCount 85 // @ C085_OBJECT_ASPECT_COUNT
#define k0_HalfSizedViewCell_LeftColumn 0 // @ C00_VIEW_CELL_LEFT_COLUMN
#define k1_HalfSizedViewCell_RightColumn 1 // @ C01_VIEW_CELL_RIGHT_COLUMN
#define k2_HalfSizedViewCell_BackRow 2 // @ C02_VIEW_CELL_BACK_ROW
#define k3_HalfSizedViewCell_CenterColumn 3 // @ C03_VIEW_CELL_CENTER_COLUMN
#define k4_HalfSizedViewCell_FrontRow 4 // @ C04_VIEW_CELL_FRONT_ROW
/* Shift sets */
#define k0_ShiftSet_D0BackD1Front 0 // @ C0_SHIFT_SET_D0_BACK_OR_D1_FRONT
#define k1_ShiftSet_D1BackD2Front 1 // @ C1_SHIFT_SET_D1_BACK_OR_D2_FRONT
#define k2_ShiftSet_D2BackD3Front 2 // @ C2_SHIFT_SET_D2_BACK_OR_D3_FRONT
#define k75_FirstFloorSet 75 // @ C075_GRAPHIC_FIRST_FLOOR_SET
#define k77_FirstWallSet 77 // @ C077_GRAPHIC_FIRST_WALL_SET
#define k90_FirstStairs 90 // @ C090_GRAPHIC_FIRST_STAIRS
#define k108_FirstDoorSet 108 // @ C108_GRAPHIC_FIRST_DOOR_SET
#define k120_InscriptionFont 120 // @ C120_GRAPHIC_INSCRIPTION_FONT
#define k121_FirstWallOrn 121 // @ C121_GRAPHIC_FIRST_WALL_ORNAMENT
#define k247_FirstFloorOrn 247 // @ C247_GRAPHIC_FIRST_FLOOR_ORNAMENT
#define k303_FirstDoorOrn 303 // @ C303_GRAPHIC_FIRST_DOOR_ORNAMENT
#define k730_DerivedBitmapMaximumCount 730 // @ C730_DERIVED_BITMAP_MAXIMUM_COUNT
#define k16_Scale_D3 16 // @ C16_SCALE_D3
#define k20_Scale_D2 20 // @ C20_SCALE_D2
/* Object aspect GraphicInfo */
#define k0x0001_ObjectFlipOnRightMask 0x0001 // @ MASK0x0001_FLIP_ON_RIGHT
#define k0x0010_ObjectAlcoveMask 0x0010 // @ MASK0x0010_ALCOVE
/* Projectile aspect GraphicInfo */
#define k0x0010_ProjectileSideMask 0x0010 // @ MASK0x0010_SIDE
#define k0x0100_ProjectileScaleWithKineticEnergyMask 0x0100 // @ MASK0x0100_SCALE_WITH_KINETIC_ENERGY
#define k0x0003_ProjectileAspectTypeMask 0x0003 // @ MASK0x0003_ASPECT_TYPE
/* Projectile aspect type */
#define k0_ProjectileAspectHasBackGraphicRotation 0 // @ C0_PROJECTILE_ASPECT_TYPE_HAS_BACK_GRAPHIC_AND_ROTATION
#define k1_ProjectileAspectBackGraphic 1 // @ C1_PROJECTILE_ASPECT_TYPE_HAS_BACK_GRAPHIC_AND_NO_ROTATION
#define k2_ProjectileAspectHasRotation 2 // @ C2_PROJECTILE_ASPECT_TYPE_NO_BACK_GRAPHIC_AND_ROTATION
#define k3_ProjectileAspectHasNone 3 // @ C3_PROJECTILE_ASPECT_TYPE_NO_BACK_GRAPHIC_AND_NO_ROTATION
/* Projectile aspects */
#define k3_ProjectileAspectExplosionLightningBolt 3 // @ C03_PROJECTILE_ASPECT_EXPLOSION_LIGHTNING_BOLT
#define k10_ProjectileAspectExplosionFireBall 10 // @ C10_PROJECTILE_ASPECT_EXPLOSION_FIREBALL
#define k11_ProjectileAspectExplosionDefault 11 // @ C11_PROJECTILE_ASPECT_EXPLOSION_DEFAULT
#define k12_ProjectileAspectExplosionSlime 12 // @ C12_PROJECTILE_ASPECT_EXPLOSION_SLIME
#define k13_ProjectileAspectExplosionPoisonBoltCloud 13 // @ C13_PROJECTILE_ASPECT_EXPLOSION_POISON_BOLT_POISON_CLOUD
#define k0x0080_BlitDoNotUseMask 0x0080 // @ MASK0x0080_DO_NOT_USE_MASK
#define kScaleThreshold 32768
class ExplosionAspect {
public:
uint16 _byteWidth;
uint16 _height;
ExplosionAspect(uint16 byteWidth, uint16 height) :_byteWidth(byteWidth), _height(height) {}
ExplosionAspect() : _byteWidth(0), _height(0) {}
}; // @ EXPLOSION_ASPECT
// in all cases, where a function takes a Box, it expects it to contain inclusive boundaries
class Box {
public:
Common::Rect _rect;
Box(int16 x1, int16 x2, int16 y1, int16 y2) {
// +1 because Rect.constains is not inclusive for right and bottom, at the opposite of the isPointInside
_rect = Common::Rect(x1, y1, x2, y2);
}
Box() = default;
bool isPointInside(Common::Point point) {
// not using Common::Rect::contains() because we need both boundaries to be included
return (_rect.left <= point.x) && (point.x <= _rect.right) && (_rect.top <= point.y) && (point.y <= _rect.bottom);
}
bool isPointInside(int16 x, int16 y) {
return isPointInside(Common::Point(x, y));
}
void setToZero() { _rect = Common::Rect(0, 0, 0, 0); }
}; // @ BOX_BYTE, BOX_WORD
extern Box g2_BoxMovementArrows; // @ G0002_s_Graphic562_Box_MovementArrows
class Frame {
public:
Box _box;
uint16 _srcByteWidth, _srcHeight;
uint16 _srcX, _srcY;
Frame(){
_srcByteWidth = _srcHeight = 0;
_srcX = _srcY = 0;
}
Frame(uint16 destFromX, uint16 destToX, uint16 destFromY, uint16 destToY,
uint16 srcWidth, uint16 srcHeight, uint16 srcX, uint16 srcY) :
_box(destFromX, destToX, destFromY, destToY),
_srcByteWidth(srcWidth), _srcHeight(srcHeight), _srcX(srcX), _srcY(srcY) {}
};
class FieldAspect {
public:
uint16 _nativeBitmapRelativeIndex;
uint16 _baseStartUnitIndex; /* Index of the unit (16 pixels = 8 bytes) in bitmap where blit will start from. A random value of 0 or 1 is added to this base index */
uint16 _transparentColor; /* Bit 7: Do not use mask if set, Bits 6-0: Transparent color index. 0xFF = no transparency */
byte _mask; /* Bit 7: Flip, Bits 6-0: Mask index. 0xFF = no mask */
uint16 _byteWidth;
uint16 _height;
uint16 _xPos;
uint16 _bitplaneWordCount;
FieldAspect(uint16 native, uint16 base, uint16 transparent, byte mask, uint16 byteWidth, uint16 height, uint16 xPos, uint16 bitplane);
FieldAspect();
}; // @ FIELD_ASPECT
class CreatureAspect {
public:
uint16 _firstNativeBitmapRelativeIndex;
uint16 _firstDerivedBitmapIndex;
byte _byteWidthFront;
byte _heightFront;
byte _byteWidthSide;
byte _heightSide;
byte _byteWidthAttack;
byte _heightAttack;
private:
byte _coordinateSet_TransparentColor;
byte _replacementColorSetIndices;
public:
CreatureAspect(uint16 uint161, uint16 uint162, byte byte0, byte byte1, byte byte2, byte byte3, byte byte4, byte byte5, byte byte6, byte byte7)
: _firstNativeBitmapRelativeIndex(uint161), _firstDerivedBitmapIndex(uint162), _byteWidthFront(byte0),
_heightFront(byte1), _byteWidthSide(byte2), _heightSide(byte3), _byteWidthAttack(byte4),
_heightAttack(byte5), _coordinateSet_TransparentColor(byte6), _replacementColorSetIndices(byte7) {}
CreatureAspect() :
_firstNativeBitmapRelativeIndex(0), _firstDerivedBitmapIndex(0), _byteWidthFront(0),
_heightFront(0), _byteWidthSide(0), _heightSide(0), _byteWidthAttack(0),
_heightAttack(0), _coordinateSet_TransparentColor(0), _replacementColorSetIndices(0) {}
byte getCoordSet() { return (_coordinateSet_TransparentColor >> 4) & 0xF; } // @ M71_COORDINATE_SET
byte getTranspColour() { return _coordinateSet_TransparentColor & 0xF; } // @ M72_TRANSPARENT_COLOR
byte getReplColour10() { return (_replacementColorSetIndices >> 4) & 0xF; } // @ M74_COLOR_10_REPLACEMENT_COLOR_SET
byte getReplColour9() { return _replacementColorSetIndices & 0xF; } // @ M73_COLOR_09_REPLACEMENT_COLOR_SET
}; // @ CREATURE_ASPECT
class ObjectAspect {
public:
byte _firstNativeBitmapRelativeIndex;
byte _firstDerivedBitmapRelativeIndex;
byte _byteWidth;
byte _height;
byte _graphicInfo; /* Bits 7-5 and 3-1 Unreferenced */
byte _coordinateSet;
ObjectAspect(byte firstN, byte firstD, byte byteWidth, byte h, byte grap, byte coord) :
_firstNativeBitmapRelativeIndex(firstN), _firstDerivedBitmapRelativeIndex(firstD),
_byteWidth(byteWidth), _height(h), _graphicInfo(grap), _coordinateSet(coord) {}
ObjectAspect() : _firstNativeBitmapRelativeIndex(0), _firstDerivedBitmapRelativeIndex(0),
_byteWidth(0), _height(0), _graphicInfo(0), _coordinateSet(0) {}
}; // @ OBJECT_ASPECT
class ProjectileAspect {
public:
byte _firstNativeBitmapRelativeIndex;
byte _firstDerivedBitmapRelativeIndex;
byte _byteWidth;
byte _height;
uint16 _graphicInfo; /* Bits 15-9, 7-5 and 3-2 Unreferenced */
ProjectileAspect(byte firstN, byte firstD, byte byteWidth, byte h, uint16 grap) :
_firstNativeBitmapRelativeIndex(firstN), _firstDerivedBitmapRelativeIndex(firstD),
_byteWidth(byteWidth), _height(h), _graphicInfo(grap) {}
ProjectileAspect() : _firstNativeBitmapRelativeIndex(0),
_firstDerivedBitmapRelativeIndex(0), _byteWidth(0), _height(0), _graphicInfo(0) {}
}; // @ PROJECTIL_ASPECT
class CreatureReplColorSet {
public:
uint16 _RGBColor[6];
byte _d2ReplacementColor;
byte _d3ReplacementColor;
CreatureReplColorSet(uint16 col1, uint16 col2, uint16 col3, uint16 col4, uint16 col5, uint16 col6, byte d2Rep, byte d3Rep) {
_RGBColor[0] = col1;
_RGBColor[1] = col2;
_RGBColor[2] = col3;
_RGBColor[3] = col4;
_RGBColor[4] = col5;
_RGBColor[5] = col6;
_d2ReplacementColor = d2Rep;
_d3ReplacementColor = d3Rep;
}
}; // @ CREATURE_REPLACEMENT_COLOR_SET
struct OrnamentInfo {
int16 nativeIndice;
int16 coordinateSet;
};
#define k0_DoorButton 0 // @ C0_DOOR_BUTTON
#define k0_WallOrnInscription 0 // @ C0_WALL_ORNAMENT_INSCRIPTION
#define k15_FloorOrnFootprints 15 // @ C15_FLOOR_ORNAMENT_FOOTPRINTS
#define k15_DoorOrnDestroyedMask 15 // @ C15_DOOR_ORNAMENT_DESTROYED_MASK
#define k16_DoorOrnThivesEyeMask 16 // @ C16_DOOR_ORNAMENT_THIEVES_EYE_MASK
#define k0_viewportNotDungeonView 0 // @ C0_VIEWPORT_NOT_DUNGEON_VIEW
#define k1_viewportDungeonView 1 // @ C1_VIEWPORT_DUNGEON_VIEW
#define k2_viewportAsBeforeSleepOrFreezeGame 2 // @ C2_VIEWPORT_AS_BEFORE_SLEEP_OR_FREEZE_GAME
#define k112_byteWidthViewport 112 // @ C112_BYTE_WIDTH_VIEWPORT
#define k136_heightViewport 136 // @ C136_HEIGHT_VIEWPORT
#define k160_byteWidthScreen 160 // @ C160_BYTE_WIDTH_SCREEN
#define k200_heightScreen 200 // @ C200_HEIGHT_SCREEN
#define k8_byteWidth 8 // @ C008_BYTE_WIDTH
#define k16_byteWidth 16 // @ C016_BYTE_WIDTH
#define k24_byteWidth 24 // @ C024_BYTE_WIDTH
#define k32_byteWidth 32 // @ C032_BYTE_WIDTH
#define k40_byteWidth 40 // @ C040_BYTE_WIDTH
#define k48_byteWidth 48 // @ C048_BYTE_WIDTH
#define k64_byteWidth 64 // @ C064_BYTE_WIDTH
#define k72_byteWidth 72 // @ C072_BYTE_WIDTH
#define k128_byteWidth 128 // @ C128_BYTE_WIDTH
#define k144_byteWidth 144 // @ C144_BYTE_WIDTH
class DoorFrames {
public:
Frame _closedOrDestroyed;
Frame _vertical[3];
Frame _leftHorizontal[3];
Frame _rightHorizontal[3];
DoorFrames(Frame f1, Frame f2_1, Frame f2_2, Frame f2_3,
Frame f3_1, Frame f3_2, Frame f3_3,
Frame f4_1, Frame f4_2, Frame f4_3);
}; // @ DOOR_FRAMES
#define D00_RGB_BLACK 0x0000
#define D01_RGB_DARK_BLUE 0x0004
#define D02_RGB_LIGHT_BROWN 0x0842
#define D03_RGB_PINK 0x086F
#define D04_RGB_LIGHTER_BROWN 0x0A62
#define D05_RGB_DARK_GOLD 0x0A82
#define D06_RGB_GOLD 0x0CA2
#define D07_RGB_RED 0x0F00
#define D08_RGB_YELLOW 0x0FF4
#define D09_RGB_WHITE 0x0FFF
#define D10_MASK_RED_COMPONENT 0x0F00
#define D10_MASK_RED_COMPONENT 0x0F00
#define D11_MASK_GREEN_COMPONENT 0x00F0
#define D12_MASK_BLUE_COMPONENT 0x000F
class DisplayMan {
friend class DM::TextMan;
DMEngine *_vm;
uint16 _grapItemCount; // @ G0632_ui_GraphicCount
uint32 *_bitmapCompressedByteCount;
uint32 *_bitmapDecompressedByteCount;
uint32 *_packedItemPos;
byte *_packedBitmaps;
byte **_bitmaps;
DoorFrames *_doorFrameD1C;
// pointers are not owned by these fields
byte *_palChangesProjectile[4]; // @G0075_apuc_PaletteChanges_Projectile
DisplayMan(const DisplayMan &other); // no implementation on purpose
void operator=(const DisplayMan &rhs); // no implementation on purpose
byte *getCurrentVgaBuffer();
// the original function has two position parameters, but they are always set to zero
void unpackGraphics();
void loadFNT1intoBitmap(uint16 index, byte *destBitmap);
void viewportSetPalette(uint16 *middleScreenPalette, uint16 *topAndBottomScreen); // @ F0565_VIEWPORT_SetPalette
void viewportBlitToScreen(); // @ F0566_VIEWPORT_BlitToScreen
void drawFloorPitOrStairsBitmapFlippedHorizontally(uint16 nativeIndex, Frame &frame); // @ F0105_DUNGEONVIEW_DrawFloorPitOrStairsBitmapFlippedHorizontally
void drawFloorPitOrStairsBitmap(uint16 nativeIndex, Frame &frame); // @ F0104_DUNGEONVIEW_DrawFloorPitOrStairsBitmap
void drawWallSetBitmap(byte *bitmap, Frame &f); // @ F0100_DUNGEONVIEW_DrawWallSetBitmap
void drawWallSetBitmapWithoutTransparency(byte *bitmap, Frame &f); // @ F0101_DUNGEONVIEW_DrawWallSetBitmapWithoutTransparency
void drawSquareD3L(Direction dir, int16 posX, int16 posY); // @ F0116_DUNGEONVIEW_DrawSquareD3L
void drawSquareD3R(Direction dir, int16 posX, int16 posY); // @ F0117_DUNGEONVIEW_DrawSquareD3R
void drawSquareD3C(Direction dir, int16 posX, int16 posY); // @ F0118_DUNGEONVIEW_DrawSquareD3C_CPSF
void drawSquareD2L(Direction dir, int16 posX, int16 posY); // @ F0119_DUNGEONVIEW_DrawSquareD2L
void drawSquareD2R(Direction dir, int16 posX, int16 posY); // @ F0120_DUNGEONVIEW_DrawSquareD2R_CPSF
void drawSquareD2C(Direction dir, int16 posX, int16 posY); // @ F0121_DUNGEONVIEW_DrawSquareD2C
void drawSquareD1L(Direction dir, int16 posX, int16 posY); // @ F0122_DUNGEONVIEW_DrawSquareD1L
void drawSquareD1R(Direction dir, int16 posX, int16 posY); // @ F0123_DUNGEONVIEW_DrawSquareD1R
void drawSquareD1C(Direction dir, int16 posX, int16 posY); // @ F0124_DUNGEONVIEW_DrawSquareD1C
void drawSquareD0L(Direction dir, int16 posX, int16 posY); // @ F0125_DUNGEONVIEW_DrawSquareD0L
void drawSquareD0R(Direction dir, int16 posX, int16 posY); // @ F0126_DUNGEONVIEW_DrawSquareD0R
void drawSquareD0C(Direction dir, int16 posX, int16 posY); // @ F0127_DUNGEONVIEW_DrawSquareD0C
void applyCreatureReplColors(int replacedColor, int replacementColor); // @ F0093_DUNGEONVIEW_ApplyCreatureReplacementColors
bool isDrawnWallOrnAnAlcove(int16 wallOrnOrd, ViewWall viewWallIndex); // @ F0107_DUNGEONVIEW_IsDrawnWallOrnamentAnAlcove_CPSF
uint16 *_derivedBitmapByteCount; // @ G0639_pui_DerivedBitmapByteCount
byte **_derivedBitmaps; // @ G0638_pui_DerivedBitmapBlockIndices
int16 _stairsNativeBitmapIndexUpFrontD3L; // @ G0675_i_StairsNativeBitmapIndex_Up_Front_D3L
int16 _stairsNativeBitmapIndexUpFrontD3C; // @ G0676_i_StairsNativeBitmapIndex_Up_Front_D3C
int16 _stairsNativeBitmapIndexUpFrontD2L; // @ G0677_i_StairsNativeBitmapIndex_Up_Front_D2L
int16 _stairsNativeBitmapIndexUpFrontD2C; // @ G0678_i_StairsNativeBitmapIndex_Up_Front_D2C
int16 _stairsNativeBitmapIndexUpFrontD1L; // @ G0679_i_StairsNativeBitmapIndex_Up_Front_D1L
int16 _stairsNativeBitmapIndexUpFrontD1C; // @ G0680_i_StairsNativeBitmapIndex_Up_Front_D1C
int16 _stairsNativeBitmapIndexUpFrontD0CLeft; // @ G0681_i_StairsNativeBitmapIndex_Up_Front_D0C_Left
int16 _stairsNativeBitmapIndexDownFrontD3L; // @ G0682_i_StairsNativeBitmapIndex_Down_Front_D3L
int16 _stairsNativeBitmapIndexDownFrontD3C; // @ G0683_i_StairsNativeBitmapIndex_Down_Front_D3C
int16 _stairsNativeBitmapIndexDownFrontD2L; // @ G0684_i_StairsNativeBitmapIndex_Down_Front_D2L
int16 _stairsNativeBitmapIndexDownFrontD2C; // @ G0685_i_StairsNativeBitmapIndex_Down_Front_D2C
int16 _stairsNativeBitmapIndexDownFrontD1L; // @ G0686_i_StairsNativeBitmapIndex_Down_Front_D1L
int16 _stairsNativeBitmapIndexDownFrontD1C; // @ G0687_i_StairsNativeBitmapIndex_Down_Front_D1C
int16 _stairsNativeBitmapIndexDownFrontD0CLeft; // @ G0688_i_StairsNativeBitmapIndex_Down_Front_D0C_Left
int16 _stairsNativeBitmapIndexSideD2L; // @ G0689_i_StairsNativeBitmapIndex_Side_D2L
int16 _stairsNativeBitmapIndexUpSideD1L; // @ G0690_i_StairsNativeBitmapIndex_Up_Side_D1L
int16 _stairsNativeBitmapIndexDownSideD1L; // @ G0691_i_StairsNativeBitmapIndex_Down_Side_D1L
int16 _stairsNativeBitmapIndexSideD0L; // @ G0692_i_StairsNativeBitmapIndex_Side_D0L
byte *_bitmapFloor; // @ G0084_puc_Bitmap_Floor
byte *_bitmapCeiling; // @ G0085_puc_Bitmap_Ceiling
byte *_bitmapWallSetD3L2; // @ G0697_puc_Bitmap_WallSet_Wall_D3L2
byte *_bitmapWallSetD3R2; // @ G0696_puc_Bitmap_WallSet_Wall_D3R2
byte *_bitmapWallSetD3LCR; // @ G0698_puc_Bitmap_WallSet_Wall_D3LCR
byte *_bitmapWallSetD2LCR; // @ G0699_puc_Bitmap_WallSet_Wall_D2LCR
public:
byte *_bitmapWallSetD1LCR; // @ G0700_puc_Bitmap_WallSet_Wall_D1LCR
private:
Box _boxThievesEyeViewPortVisibleArea; // @ G0106_s_Graphic558_Box_ThievesEye_ViewportVisibleArea
byte _palChangesDoorButtonAndWallOrnD3[16]; // @ G0198_auc_Graphic558_PaletteChanges_DoorButtonAndWallOrnament_D3
byte _palChangesDoorButtonAndWallOrnD2[16]; // @ G0199_auc_Graphic558_PaletteChanges_DoorButtonAndWallOrnament_D2
byte *_bitmapWallSetWallD0L; // @ G0701_puc_Bitmap_WallSet_Wall_D0L
byte *_bitmapWallSetWallD0R; // @ G0702_puc_Bitmap_WallSet_Wall_D0R
byte *_bitmapWallSetDoorFrameTopD2LCR; // @ G0703_puc_Bitmap_WallSet_DoorFrameTop_D2LCR
byte *_bitmapWallSetDoorFrameTopD1LCR; // @ G0704_puc_Bitmap_WallSet_DoorFrameTop_D1LCR
byte *_bitmapWallSetDoorFrameLeftD3L; // @ G0705_puc_Bitmap_WallSet_DoorFrameLeft_D3L
byte *_bitmapWallSetDoorFrameLeftD3C; // @ G0706_puc_Bitmap_WallSet_DoorFrameLeft_D3C
byte *_bitmapWallSetDoorFrameLeftD2C; // @ G0707_puc_Bitmap_WallSet_DoorFrameLeft_D2C
byte *_bitmapWallSetDoorFrameLeftD1C; // @ G0708_puc_Bitmap_WallSet_DoorFrameLeft_D1C
byte *_bitmapWallSetDoorFrameRightD1C; // @ G0710_puc_Bitmap_WallSet_DoorFrameRight_D1C
byte *_bitmapWallSetDoorFrameFront; // @ G0709_puc_Bitmap_WallSet_DoorFrameFront
byte *_bitmapWallD3LCRFlipped; // @ G0090_puc_Bitmap_WallD3LCR_Flipped;
byte *_bitmapWallD2LCRFlipped; // @ G0091_puc_Bitmap_WallD2LCR_Flipped;
byte *_bitmapWallD1LCRFlipped; // @ G0092_puc_Bitmap_WallD1LCR_Flipped;
byte *_bitmapWallD0LFlipped; // @ G0093_puc_Bitmap_WallD0L_Flipped;
byte *_bitmapWallD0RFlipped; // @ G0094_puc_Bitmap_WallD0R_Flipped;
byte *_bitmapWallD3LCRNative; // @ G0095_puc_Bitmap_WallD3LCR_Native;
byte *_bitmapWallD2LCRNative; // @ G0096_puc_Bitmap_WallD2LCR_Native;
byte *_bitmapWallD1LCRNative; // @ G0097_puc_Bitmap_WallD1LCR_Native;
byte *_bitmapWallD0LNative; // @ G0098_puc_Bitmap_WallD0L_Native;
byte *_bitmapWallD0RNative; // @ G0099_puc_Bitmap_WallD0R_Native;
int16 _currentWallSet; // @ G0231_i_CurrentWallSet
int16 _currentFloorSet;// @ G0230_i_CurrentFloorSet
bool _useFlippedWallAndFootprintsBitmap; // @ G0076_B_UseFlippedWallAndFootprintsBitmaps
byte _wallOrnamentCoordSets[8][13][6]; // @ G0205_aaauc_Graphic558_WallOrnamentCoordinateSets
uint16 _doorOrnCoordSets[4][3][6]; // @ G0207_aaauc_Graphic558_DoorOrnamentCoordinateSet
byte _doorButtonCoordSet[1]; // @ G0197_auc_Graphic558_DoorButtonCoordinateSet
uint16 _doorButtonCoordSets[1][4][6]; // @ G0208_aaauc_Graphic558_DoorButtonCoordinate
int16 _doorNativeBitmapIndexFrontD3LCR[2]; // @ G0693_ai_DoorNativeBitmapIndex_Front_D3LCR
int16 _doorNativeBitmapIndexFrontD2LCR[2]; // @ G0694_ai_DoorNativeBitmapIndex_Front_D2LCR
int16 _doorNativeBitmapIndexFrontD1LCR[2]; // @ G0695_ai_DoorNativeBitmapIndex_Front_D1LCR
uint16 *_paletteFadeFrom; // @ K0017_pui_Palette_FadeFrom
uint16 _paletteFadeTemporary[16]; // @ K0016_aui_Palette_FadeTemporary
public:
uint16 _screenWidth;
uint16 _screenHeight;
byte *_bitmapScreen; // @ G0348_pl_Bitmap_Screen
byte *_bitmapViewport; // @ G0296_puc_Bitmap_Viewport
// some methods use this for a stratchpad, don't make assumptions about content between function calls
byte *_tmpBitmap; // @ G0074_puc_Bitmap_Temporary
bool _paletteSwitchingEnabled; // @ G0322_B_PaletteSwitchingEnabled
bool _refreshDungeonViewPaleteRequested; // @ G0342_B_RefreshDungeonViewPaletteRequested
int16 _dungeonViewPaletteIndex; // @ G0304_i_DungeonViewPaletteIndex
uint16 _blankBuffer[32]; // @G0345_aui_BlankBuffer
uint16 _paletteTopAndBottomScreen[16]; // @ G0347_aui_Palette_TopAndBottomScreen
uint16 _paletteMiddleScreen[16]; // @ G0346_aui_Palette_MiddleScreen
explicit DisplayMan(DMEngine *dmEngine);
~DisplayMan();
void loadWallSet(WallSet set); // @ F0095_DUNGEONVIEW_LoadWallSet
void loadFloorSet(FloorSet set); // @ F0094_DUNGEONVIEW_LoadFloorSet
void loadIntoBitmap(uint16 index, byte *destBitmap); // @ F0466_EXPAND_GraphicToBitmap
void setUpScreens(uint16 width, uint16 height);
void loadGraphics(); // @ F0479_MEMORY_ReadGraphicsDatHeader
void initializeGraphicData(); // @ F0460_START_InitializeGraphicData
void loadCurrentMapGraphics(); // @ F0096_DUNGEONVIEW_LoadCurrentMapGraphics_CPSDF
void allocateFlippedWallBitmaps(); // @ F0461_START_AllocateFlippedWallBitmaps
void drawDoorBitmap(Frame *frame);// @ F0102_DUNGEONVIEW_DrawDoorBitmap
void drawDoorFrameBitmapFlippedHorizontally(byte *bitmap, Frame *frame); // @ F0103_DUNGEONVIEW_DrawDoorFrameBitmapFlippedHorizontally
void drawDoorButton(int16 doorButtonOrdinal, DoorButton doorButton); // @ F0110_DUNGEONVIEW_DrawDoorButton
/// Gives the width of an IMG0 type item
uint16 getPixelWidth(uint16 index);
/// Gives the height of an IMG1 type item
uint16 getPixelHeight(uint16 index);
void copyBitmapAndFlipHorizontal(byte *srcBitmap, byte *destBitmap, uint16 byteWidth, uint16 height); // @ F0099_DUNGEONVIEW_CopyBitmapAndFlipHorizontal
void drawFloorOrnament(uint16 floorOrnOrdinal, ViewFloor viewFloorIndex); // @ F0108_DUNGEONVIEW_DrawFloorOrnament
void drawDoor(uint16 doorThingIndex, DoorState doorState, int16 *doorNativeBitmapIndices, int16 byteCount,
DoorOrnament doorOrnament, DoorFrames *doorFrames); // @ F0111_DUNGEONVIEW_DrawDoor
void drawDoorOrnament(int16 doorOrnOdinal, DoorOrnament doorOrnament); // @ F0109_DUNGEONVIEW_DrawDoorOrnament
void drawCeilingPit(int16 nativeBitmapIndex, Frame *frame, int16 mapX, int16 mapY, bool flipHorizontal); // @ F0112_DUNGEONVIEW_DrawCeilingPit
void blitToViewport(byte *bitmap, Box &box, int16 byteWidth, Color transparent, int16 height); // @ F0020_MAIN_BlitToViewport
void blitToViewport(byte *bitmap, int16 *box, int16 byteWidth, Color transparent, int16 height); // @ F0020_MAIN_BlitToViewport
void blitToScreen(byte *bitmap, const Box *box, int16 byteWidth, Color transparent, int16 height); // @ F0021_MAIN_BlitToScreen
/* srcHeight and destHeight are not necessary for blitting, only error checking, thus they are defaulted for existing code which
does not pass anything, newly imported calls do pass srcHeght and srcWidth, so this is a convenience change so the parameters
match the original exactly, if need arises for heights then we'll have to retrospectively add them in old function calls*/
/* Expects inclusive boundaries in box */
void blitToBitmap(byte *srcBitmap, byte *destBitmap, const Box &box, uint16 srcX, uint16 srcY, uint16 srcByteWidth,
uint16 destByteWidth, Color transparent, int16 srcHeight, int16 destHight); // @ F0132_VIDEO_Blit
/* Expects inclusive boundaries in box */
void blitBoxFilledWithMaskedBitmap(byte *src, byte *dest, byte *mask, byte *tmp, Box &box, int16 lastUnitIndex,
int16 firstUnitIndex, int16 destByteWidth, Color transparent,
int16 xPos, int16 yPos, int16 destHeight, int16 height2); // @ F0133_VIDEO_BlitBoxFilledWithMaskedBitmap
// this function takes pixel widths
void blitToBitmapShrinkWithPalChange(byte *srcBitmap, byte *destBitmap,
int16 srcPixelWidth, int16 srcHight, int16 destPixelWidth, int16 destHeight, byte *palChange); // @ F0129_VIDEO_BlitShrinkWithPaletteChanges
void flipBitmapHorizontal(byte *bitmap, uint16 byteWidth, uint16 height); // @ F0130_VIDEO_FlipHorizontal
void flipBitmapVertical(byte *bitmap, uint16 byteWidth, uint16 height);
byte *getExplosionBitmap(uint16 explosionAspIndex, uint16 scale, int16 &returnByteWidth, int16 &returnHeight); // @ F0114_DUNGEONVIEW_GetExplosionBitmap
void fillBitmap(byte *bitmap, Color color, uint16 byteWidth, uint16 height); // @ F0134_VIDEO_FillBitmap
void fillScreen(Color color);
/* Expects inclusive boundaries in box */
void fillScreenBox(Box &box, Color color); // @ D24_FillScreenBox, F0550_VIDEO_FillScreenBox
/* Expects inclusive boundaries in box */
void fillBoxBitmap(byte *destBitmap, Box &box, Color color, int16 byteWidth, int16 height); // @ F0135_VIDEO_FillBox
void drawDungeon(Direction dir, int16 posX, int16 posY); // @ F0128_DUNGEONVIEW_Draw_CPSF
void drawFloorAndCeiling(); // @ F0098_DUNGEONVIEW_DrawFloorAndCeiling
void updateScreen();
void drawViewport(int16 palSwitchingRequestedState); // @ F0097_DUNGEONVIEW_DrawViewport
byte *getNativeBitmapOrGraphic(uint16 index); // @ F0489_MEMORY_GetNativeBitmapOrGraphic
Common::MemoryReadStream getCompressedData(uint16 index);
uint32 getCompressedDataSize(uint16 index);
void drawField(FieldAspect *fieldAspect, Box &box); // @ F0113_DUNGEONVIEW_DrawField
int16 getScaledBitmapByteCount(int16 byteWidth, int16 height, int16 scale); // @ F0459_START_GetScaledBitmapByteCount
int16 getScaledDimension(int16 dimension, int16 scale); // @ M78_SCALED_DIMENSION
void drawObjectsCreaturesProjectilesExplosions(Thing thingParam, Direction directionParam,
int16 mapXpos, int16 mapYpos, int16 viewSquareIndex,
CellOrder orderedViewCellOrdinals); // @ F0115_DUNGEONVIEW_DrawObjectsCreaturesProjectilesExplosions_CPSEF
uint16 getNormalizedByteWidth(uint16 byteWidth); // @ M77_NORMALIZED_BYTE_WIDTH
uint16 getVerticalOffsetM23(uint16 val); // @ M23_VERTICAL_OFFSET
uint16 getHorizontalOffsetM22(uint16 val); // @ M22_HORIZONTAL_OFFSET
int16 _championPortraitOrdinal; // @ G0289_i_DungeonView_ChampionPortraitOrdinal
int16 _currMapAlcoveOrnIndices[k3_AlcoveOrnCount]; // @ G0267_ai_CurrentMapAlcoveOrnamentIndices
int16 _currMapFountainOrnIndices[k1_FountainOrnCount]; // @ G0268_ai_CurrentMapFountainOrnamentIndices
OrnamentInfo _currMapWallOrnInfo[16]; // @ G0101_aai_CurrentMapWallOrnamentsInfo
OrnamentInfo _currMapFloorOrnInfo[16]; // @ G0102_aai_CurrentMapFloorOrnamentsInfo
OrnamentInfo _currMapDoorOrnInfo[17]; // @ G0103_aai_CurrentMapDoorOrnamentsInfo
byte *_currMapAllowedCreatureTypes; // @ G0264_puc_CurrentMapAllowedCreatureTypes
byte _currMapWallOrnIndices[16]; // @ G0261_auc_CurrentMapWallOrnamentIndices
byte _currMapFloorOrnIndices[16]; // @ G0262_auc_CurrentMapFloorOrnamentIndices
byte _currMapDoorOrnIndices[18]; // @ G0263_auc_CurrentMapDoorOrnamentIndices
int16 _currMapViAltarIndex; // @ G0266_i_CurrentMapViAltarWallOrnamentIndex
Thing _inscriptionThing; // @ G0290_T_DungeonView_InscriptionThing
bool _drawFloorAndCeilingRequested; // @ G0297_B_DrawFloorAndCeilingRequested
// This tells blitting functions whether to assume a BYTE_BOX or a WORD_BOX has been passed to them,
// I only use WORD_BOX, so this will probably deem useless
bool _useByteBoxCoordinates; // @ G0578_B_UseByteBoxCoordinates
bool _doNotDrawFluxcagesDuringEndgame; // @ G0077_B_DoNotDrawFluxcagesDuringEndgame
Frame _doorFrameLeftD1C; // @ G0170_s_Graphic558_Frame_DoorFrameLeft_D1C
Frame _doorFrameRightD1C; // @ G0171_s_Graphic558_Frame_DoorFrameRight_D1C
FieldAspect _fieldAspects188[12];
Box _boxMovementArrows;
byte _palChangeSmoke[16];
byte _projectileScales[7];
ExplosionAspect _explosionAspects[k4_ExplosionAspectCount];
Frame _frameWallD3R2;
Frame _frameWalls163[12];
CreatureAspect _creatureAspects219[k27_CreatureTypeCount];
ObjectAspect _objectAspects209[k85_ObjAspectCount]; // @ G0209_as_Graphic558_ObjectAspects
ProjectileAspect _projectileAspect[k14_ProjectileAspectCount]; // @ G0210_as_Graphic558_ProjectileAspects
uint16 _palCredits[16]; // @ G0019_aui_Graphic562_Palette_Credits
uint16 _palDungeonView[6][16]; // @ G0021_aaui_Graphic562_Palette_DungeonView
byte _palChangesCreatureD3[16]; // @ G0221_auc_Graphic558_PaletteChanges_Creature_D3
byte _palChangesCreatureD2[16]; // @ G0222_auc_Graphic558_PaletteChanges_Creature_D2
byte _palChangesNoChanges[16]; // @ G0017_auc_Graphic562_PaletteChanges_NoChanges
byte _palChangesFloorOrnD3[16]; // @ G0213_auc_Graphic558_PaletteChanges_FloorOrnament_D3
byte _palChangesFloorOrnD2[16]; // @ G0214_auc_Graphic558_PaletteChanges_FloorOrnament_D2
bool isDerivedBitmapInCache(int16 derivedBitmapIndex); // @ F0491_CACHE_IsDerivedBitmapInCache
byte *getDerivedBitmap(int16 derivedBitmapIndex); // @ F0492_CACHE_GetDerivedBitmap
void addDerivedBitmap(int16 derivedBitmapIndex); // @ F0493_CACHE_AddDerivedBitmap
void releaseBlock(uint16 index); // @ F0480_CACHE_ReleaseBlock
uint16 getDarkenedColor(uint16 RGBcolor);
void startEndFadeToPalette(uint16 *P0849_pui_Palette); // @ F0436_STARTEND_FadeToPalette
void buildPaletteChangeCopperList(uint16 *middleScreen, uint16 *topAndBottom); // @ F0508_AMIGA_BuildPaletteChangeCopperList
void shadeScreenBox(Box *box, Color color) { warning("STUB METHOD: shadeScreenBox"); } // @ F0136_VIDEO_ShadeScreenBox
private:
void initConstants();
uint16 getBitmapByteCount(uint16 pixelWidth, uint16 height); // @ M75_BITMAP_BYTE_COUNT
};
}
#endif

2132
engines/dm/group.cpp Normal file

File diff suppressed because it is too large Load Diff

255
engines/dm/group.h Normal file
View File

@@ -0,0 +1,255 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_GROUP_H
#define DM_GROUP_H
#include "dm/dm.h"
#include "dm/sounds.h"
#include "dm/timeline.h"
namespace DM {
class Champion;
class TimelineEvent;
class CreatureInfo;
/* Creature types */
enum CreatureType {
kDMCreatureTypeGiantScorpion = 0, // @ C00_CREATURE_GIANT_SCORPION_SCORPION
kDMCreatureTypeSwampSlime = 1, // @ C01_CREATURE_SWAMP_SLIME_SLIME_DEVIL
kDMCreatureTypeGiggler = 2, // @ C02_CREATURE_GIGGLER
kDMCreatureTypeWizardEye = 3, // @ C03_CREATURE_WIZARD_EYE_FLYING_EYE
kDMCreatureTypePainRat = 4, // @ C04_CREATURE_PAIN_RAT_HELLHOUND
kDMCreatureTypeRuster = 5, // @ C05_CREATURE_RUSTER
kDMCreatureTypeScreamer = 6, // @ C06_CREATURE_SCREAMER
kDMCreatureTypeRockpile = 7, // @ C07_CREATURE_ROCK_ROCKPILE
kDMCreatureTypeGhostRive = 8, // @ C08_CREATURE_GHOST_RIVE
kDMCreatureTypeStoneGolem = 9, // @ C09_CREATURE_STONE_GOLEM
kDMCreatureTypeMummy = 10, // @ C10_CREATURE_MUMMY
kDMCreatureTypeBlackFlame = 11, // @ C11_CREATURE_BLACK_FLAME
kDMCreatureTypeSkeleton = 12, // @ C12_CREATURE_SKELETON
kDMCreatureTypeCouatl = 13, // @ C13_CREATURE_COUATL
kDMCreatureTypeVexirk = 14, // @ C14_CREATURE_VEXIRK
kDMCreatureTypeMagentaWorm = 15, // @ C15_CREATURE_MAGENTA_WORM_WORM
kDMCreatureTypeAntman = 16, // @ C16_CREATURE_TROLIN_ANTMAN
kDMCreatureTypeGiantWasp = 17, // @ C17_CREATURE_GIANT_WASP_MUNCHER
kDMCreatureTypeAnimatedArmour = 18, // @ C18_CREATURE_ANIMATED_ARMOUR_DETH_KNIGHT
kDMCreatureTypeMaterializerZytaz = 19, // @ C19_CREATURE_MATERIALIZER_ZYTAZ
kDMCreatureTypeWaterElemental = 20, // @ C20_CREATURE_WATER_ELEMENTAL
kDMCreatureTypeOitu = 21, // @ C21_CREATURE_OITU
kDMCreatureTypeDemon = 22, // @ C22_CREATURE_DEMON
kDMCreatureTypeLordChaos = 23, // @ C23_CREATURE_LORD_CHAOS
kDMCreatureTypeRedDragon = 24, // @ C24_CREATURE_RED_DRAGON
kDMCreatureTypeLordOrder = 25, // @ C25_CREATURE_LORD_ORDER
kDMCreatureTypeGreyLord = 26 // @ C26_CREATURE_GREY_LORD
};
enum CreatureSize {
kDMCreatureSizeQuarter = 0, // @ C0_SIZE_QUARTER_SQUARE
kDMCreatureSizeHalf = 1, // @ C1_SIZE_HALF_SQUARE
kDMCreatureSizeFull = 2 // @ C2_SIZE_FULL_SQUARE
};
enum Behavior {
kDMBehaviorWander = 0, // @ C0_BEHAVIOR_WANDER
kDMBehaviorUnknown2 = 2, // @ C2_BEHAVIOR_USELESS
kDMBehaviorUnknown3 = 3, // @ C3_BEHAVIOR_USELESS
kDMBehaviorUnknown4 = 4, // @ C4_BEHAVIOR_USELESS
kDMBehaviorFlee = 5, // @ C5_BEHAVIOR_FLEE
kDMBehaviorAttack = 6, // @ C6_BEHAVIOR_ATTACK
kDMBehaviorApproach = 7 // @ C7_BEHAVIOR_APPROACH
};
#define kDMImmuneToFear 15 // @ C15_IMMUNE_TO_FEAR
#define kDMMovementTicksImmobile 255 // @ C255_IMMOBILE
#define kDMWholeCreatureGroup -1 // @ CM1_WHOLE_CREATURE_GROUP
#define kDMCreatureTypeSingleCenteredCreature 255 // @ C255_SINGLE_CENTERED_CREATURE
enum CreatureMask {
kDMCreatureMaskSize = 0x0003, // @ MASK0x0003_SIZE
kDMCreatureMaskSideAttack = 0x0004, // @ MASK0x0004_SIDE_ATTACK
kDMCreatureMaskPreferBackRow = 0x0008, // @ MASK0x0008_PREFER_BACK_ROW
kDMCreatureMaskAttackAnyChamp = 0x0010, // @ MASK0x0010_ATTACK_ANY_CHAMPION
kDMCreatureMaskLevitation = 0x0020, // @ MASK0x0020_LEVITATION
kDMCreatureMaskNonMaterial = 0x0040, // @ MASK0x0040_NON_MATERIAL
kDMCreatureMaskDropFixedPoss = 0x0200, // @ MASK0x0200_DROP_FIXED_POSSESSIONS
kDMCreatureMaskKeepThrownSharpWeapon = 0x0400, // @ MASK0x0400_KEEP_THROWN_SHARP_WEAPONS
kDMCreatureMaskSeeInvisible = 0x0800, // @ MASK0x0800_SEE_INVISIBLE
kDMCreatureMaskNightVision = 0x1000, // @ MASK0x1000_NIGHT_VISION
kDMCreatureMaskArchenemy = 0x2000, // @ MASK0x2000_ARCHENEMY
kDMCreatureMaskMagicMap = 0x4000 // @ MASK0x4000_MAGICMAP
};
enum aspectMask {
kDMAspectMaskActiveGroupFlipBitmap = 0x0040, // @ MASK0x0040_FLIP_BITMAP
kDMAspectMaskActiveGroupIsAttacking = 0x0080 // @ MASK0x0080_IS_ATTACKING
};
class ActiveGroup {
public:
int16 _groupThingIndex;
Direction _directions;
byte _cells;
byte _lastMoveTime;
byte _delayFleeingFromTarget;
byte _targetMapX;
byte _targetMapY;
byte _priorMapX;
byte _priorMapY;
byte _homeMapX;
byte _homeMapY;
byte _aspect[4];
}; // @ ACTIVE_GROUP
class Group {
public:
Thing _nextThing;
Thing _slot;
CreatureType _type;
uint16 _cells;
uint16 _health[4];
uint16 _flags;
public:
explicit Group(uint16 *rawDat) : _nextThing(rawDat[0]), _slot(rawDat[1]), _cells(rawDat[3]), _flags(rawDat[8]) {
_type = (CreatureType)rawDat[2];
_health[0] = rawDat[4];
_health[1] = rawDat[5];
_health[2] = rawDat[6];
_health[3] = rawDat[7];
}
uint16 &getActiveGroupIndex() { return _cells; }
uint16 getBehaviour() { return _flags & 0xF; }
uint16 setBehaviour(uint16 val) { _flags = (_flags & ~0xF) | (val & 0xF); return (val & 0xF); }
uint16 getCount() { return (_flags >> 5) & 0x3; }
void setCount(uint16 val) { _flags = (_flags & ~(0x3 << 5)) | ((val & 0x3) << 5); }
Direction getDir() { return (Direction)((_flags >> 8) & 0x3); }
void setDir(uint16 val) { _flags = (_flags & ~(0x3 << 8)) | ((val & 0x3) << 8); }
uint16 getDoNotDiscard() { return (_flags >> 10) & 0x1; }
void setDoNotDiscard(bool val) { _flags = (_flags & ~(1 << 10)) | ((val & 1) << 10); }
}; // @ GROUP
class GroupMan {
DMEngine *_vm;
byte _dropMovingCreatureFixedPossessionsCell[4]; // @ G0392_auc_DropMovingCreatureFixedPossessionsCells
uint16 _dropMovingCreatureFixedPossCellCount; // @ G0391_ui_DropMovingCreatureFixedPossessionsCellCount
uint16 _fluxCageCount; // @ G0386_ui_FluxCageCount
int16 _fluxCages[4]; // @ G0385_ac_FluxCages
int16 _currentGroupMapX; // @ G0378_i_CurrentGroupMapX
int16 _currentGroupMapY; // @ G0379_i_CurrentGroupMapY
Thing _currGroupThing; // @ G0380_T_CurrentGroupThing
int16 _groupMovementTestedDirections[4]; // @ G0384_auc_GroupMovementTestedDirections
uint16 _currGroupDistanceToParty; // @ G0381_ui_CurrentGroupDistanceToParty
int16 _currGroupPrimaryDirToParty; // @ G0382_i_CurrentGroupPrimaryDirectionToParty
int16 _currGroupSecondaryDirToParty; // @ G0383_i_CurrentGroupSecondaryDirectionToParty
Thing _groupMovementBlockedByGroupThing; // @ G0388_T_GroupMovementBlockedByGroupThing
bool _groupMovementBlockedByDoor; // @ G0389_B_GroupMovementBlockedByDoor
bool _groupMovementBlockedByParty; // @ G0390_B_GroupMovementBlockedByParty
bool _groupMovBlockedByWallStairsPitFakeWalFluxCageTeleporter; // @ G0387_B_GroupMovementBlockedByWallStairsPitFakeWallFluxcageTeleporter
int32 twoHalfSquareSizedCreaturesGroupLastDirectionSetTime; // @ G0395_l_TwoHalfSquareSizedCreaturesGroupLastDirectionSetTime
uint16 toggleFlag(uint16 &val, uint16 mask); // @ M10_TOGGLE
int32 setTime(int32 &map_time, int32 time); // @ M32_SET_TIME
public:
uint16 _maxActiveGroupCount; // @ G0376_ui_MaximumActiveGroupCount
ActiveGroup *_activeGroups; // @ G0375_ps_ActiveGroups
uint16 _currActiveGroupCount; // @ G0377_ui_CurrentActiveGroupCount
explicit GroupMan(DMEngine *vm);
~GroupMan();
void initActiveGroups(); // @ F0196_GROUP_InitializeActiveGroups
uint16 getGroupCells(Group *group, int16 mapIndex); // @ F0145_DUNGEON_GetGroupCells
uint16 getGroupDirections(Group *group, int16 mapIndex); // @ F0147_DUNGEON_GetGroupDirections
int16 getCreatureOrdinalInCell(Group *group, uint16 cell); // @ F0176_GROUP_GetCreatureOrdinalInCell
uint16 getCreatureValue(uint16 groupVal, uint16 creatureIndex); // @ M50_CREATURE_VALUE
void dropGroupPossessions(int16 mapX, int16 mapY, Thing groupThing, SoundMode mode); // @ F0188_GROUP_DropGroupPossessions
void dropCreatureFixedPossessions(CreatureType creatureType, int16 mapX, int16 mapY, uint16 cell,
SoundMode soundMode); // @ F0186_GROUP_DropCreatureFixedPossessions
int16 getDirsWhereDestIsVisibleFromSource(int16 srcMapX, int16 srcMapY,
int16 destMapX, int16 destMapY); // @ F0228_GROUP_GetDirectionsWhereDestinationIsVisibleFromSource
bool isDestVisibleFromSource(uint16 dir, int16 srcMapX, int16 srcMapY, int16 destMapX,
int16 destMapY); // @ F0227_GROUP_IsDestinationVisibleFromSource
bool groupIsDoorDestoryedByAttack(uint16 mapX, uint16 mapY, int16 attack,
bool magicAttack, int16 ticks); // @ F0232_GROUP_IsDoorDestroyedByAttack
Thing groupGetThing(int16 mapX, int16 mapY); // @ F0175_GROUP_GetThing
int16 groupGetDamageCreatureOutcome(Group *group, uint16 creatureIndex,
int16 mapX, int16 mapY, int16 damage, bool notMoving); // @ F0190_GROUP_GetDamageCreatureOutcome
void groupDelete(int16 mapX, int16 mapY); // @ F0189_GROUP_Delete
void groupDeleteEvents(int16 mapX, int16 mapY); // @ F0181_GROUP_DeleteEvents
uint16 getGroupValueUpdatedWithCreatureValue(uint16 groupVal, uint16 creatureIndex, uint16 creatureVal); // @ F0178_GROUP_GetGroupValueUpdatedWithCreatureValue
int16 getDamageAllCreaturesOutcome(Group *group, int16 mapX, int16 mapY, int16 attack, bool notMoving); // @ F0191_GROUP_GetDamageAllCreaturesOutcome
int16 groupGetResistanceAdjustedPoisonAttack(CreatureType creatureType, int16 poisonAttack); // @ F0192_GROUP_GetResistanceAdjustedPoisonAttack
void processEvents29to41(int16 eventMapX, int16 eventMapY, TimelineEventType eventType, uint16 ticks); // @ F0209_GROUP_ProcessEvents29to41
bool isMovementPossible(CreatureInfo *creatureInfo, int16 mapX, int16 mapY,
uint16 dir, bool allowMovementOverImaginaryPitsAndFakeWalls); // @ F0202_GROUP_IsMovementPossible
int16 getDistanceBetweenSquares(int16 srcMapX, int16 srcMapY, int16 destMapX,
int16 destMapY); // @ F0226_GROUP_GetDistanceBetweenSquares
int16 groupGetDistanceToVisibleParty(Group *group, int16 creatureIndex, int16 mapX, int16 mapY); // @ F0200_GROUP_GetDistanceToVisibleParty
int16 getDistanceBetweenUnblockedSquares(int16 srcMapX, int16 srcMapY,
int16 destMapX, int16 destMapY, bool (GroupMan::*isBlocked)(uint16, uint16)); // @ F0199_GROUP_GetDistanceBetweenUnblockedSquares
bool isViewPartyBlocked(uint16 mapX, uint16 mapY); // @ F0197_GROUP_IsViewPartyBlocked
int32 getCreatureAspectUpdateTime(ActiveGroup *activeGroup, int16 creatureIndex,
bool isAttacking); // @ F0179_GROUP_GetCreatureAspectUpdateTime
void setGroupDirection(ActiveGroup *activeGroup, int16 dir, int16 creatureIndex, bool twoHalfSquareSizedCreatures); // @ F0205_GROUP_SetDirection
void addGroupEvent(TimelineEvent *event, uint32 time); // @ F0208_GROUP_AddEvent
int16 getSmelledPartyPrimaryDirOrdinal(CreatureInfo *creatureInfo, int16 mapY, int16 mapX); // @ F0201_GROUP_GetSmelledPartyPrimaryDirectionOrdinal
bool isSmellPartyBlocked(uint16 mapX, uint16 mapY); // @ F0198_GROUP_IsSmellPartyBlocked
int16 getFirstPossibleMovementDirOrdinal(CreatureInfo *info, int16 mapX, int16 mapY,
bool allowMovementOverImaginaryPitsAndFakeWalls); // @ F0203_GROUP_GetFirstPossibleMovementDirectionOrdinal
void setDirGroup(ActiveGroup *activeGroup, int16 dir, int16 creatureIndex,
int16 creatureSize); // @ F0206_GROUP_SetDirectionGroup
void stopAttacking(ActiveGroup *group, int16 mapX, int16 mapY);// @ F0182_GROUP_StopAttacking
bool isArchenemyDoubleMovementPossible(CreatureInfo *info, int16 mapX, int16 mapY, uint16 dir); // @ F0204_GROUP_IsArchenemyDoubleMovementPossible
bool isCreatureAttacking(Group *group, int16 mapX, int16 mapY, uint16 creatureIndex); // @ F0207_GROUP_IsCreatureAttacking
void setOrderedCellsToAttack(signed char *orderedCellsToAttack, int16 targetMapX,
int16 targetMapY, int16 attackerMapX, int16 attackerMapY, uint16 cellSource); // @ F0229_GROUP_SetOrderedCellsToAttack
void stealFromChampion(Group *group, uint16 championIndex); // @ F0193_GROUP_StealFromChampion
int16 getChampionDamage(Group *group, uint16 champIndex); // @ F0230_GROUP_GetChampionDamage
void dropMovingCreatureFixedPossession(Thing thing, int16 mapX, int16 mapY); // @ F0187_GROUP_DropMovingCreatureFixedPossessions
void startWandering(int16 mapX, int16 mapY); // @ F0180_GROUP_StartWandering
void addActiveGroup(Thing thing, int16 mapX, int16 mapY); // @ F0183_GROUP_AddActiveGroup
void removeActiveGroup(uint16 activeGroupIndex); // @ F0184_GROUP_RemoveActiveGroup
void removeAllActiveGroups(); // @ F0194_GROUP_RemoveAllActiveGroups
void addAllActiveGroups(); // @ F0195_GROUP_AddAllActiveGroups
Thing groupGetGenerated(CreatureType creatureType, int16 healthMultiplier, uint16 creatureCount, Direction dir, int16 mapX, int16 mapY); // @ F0185_GROUP_GetGenerated
bool isSquareACorridorTeleporterPitOrDoor(int16 mapX, int16 mapY); // @ F0223_GROUP_IsSquareACorridorTeleporterPitOrDoor
int16 getMeleeTargetCreatureOrdinal(int16 groupX, int16 groupY, int16 partyX, int16 paryY,
uint16 champCell); // @ F0177_GROUP_GetMeleeTargetCreatureOrdinal
int16 getMeleeActionDamage(Champion *champ, int16 champIndex, Group *group, int16 creatureIndex,
int16 mapX, int16 mapY, uint16 actionHitProbability, uint16 actionDamageFactor, int16 skillIndex); // @ F0231_GROUP_GetMeleeActionDamage
void fluxCageAction(int16 mapX, int16 mapY); // @ F0224_GROUP_FluxCageAction
uint16 isLordChaosOnSquare(int16 mapX, int16 mapY); // @ F0222_GROUP_IsLordChaosOnSquare
bool isFluxcageOnSquare(int16 mapX, int16 mapY); // @ F0221_GROUP_IsFluxcageOnSquare
void fuseAction(uint16 mapX, uint16 mapY); // @ F0225_GROUP_FuseAction
void saveActiveGroupPart(Common::OutSaveFile *file);
void loadActiveGroupPart(Common::InSaveFile *file);
};
}
#endif

1096
engines/dm/inventory.cpp Normal file

File diff suppressed because it is too large Load Diff

98
engines/dm/inventory.h Normal file
View File

@@ -0,0 +1,98 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_INVENTORY_H
#define DM_INVENTORY_H
#include "dm/dm.h"
#include "dm/gfx.h"
#include "dm/champion.h"
#include "dm/dungeonman.h"
namespace DM {
enum DescriptionMask {
kDMDescriptionMaskConsumable = 0x0001, // @ MASK0x0001_DESCRIPTION_CONSUMABLE
kDMDescriptionMaskPoisoned = 0x0002, // @ MASK0x0002_DESCRIPTION_POISONED
kDMDescriptionMaskBroken = 0x0004, // @ MASK0x0004_DESCRIPTION_BROKEN
kDMDescriptionMaskCursed = 0x0008 // @ MASK0x0008_DESCRIPTION_CURSED
};
enum PanelContent {
kDMPanelContentFoodWaterPoisoned = 0, // @ C00_PANEL_FOOD_WATER_POISONED
kDMPanelContentScroll = 2, // @ C02_PANEL_SCROLL
kDMPanelContentChest = 4, // @ C04_PANEL_CHEST
kDMPanelContentResurrectReincarnate = 5 // @ C05_PANEL_RESURRECT_REINCARNATE
};
#define kDMChampionStatusBoxSpacing 69 // @ C69_CHAMPION_STATUS_BOX_SPACING
class InventoryMan {
DMEngine *_vm;
void initConstants();
public:
explicit InventoryMan(DMEngine *vm);
int16 _inventoryChampionOrdinal; // @ G0423_i_InventoryChampionOrdinal
PanelContent _panelContent; // @ G0424_i_PanelContent
Thing _chestSlots[8]; // @ G0425_aT_ChestSlots
Thing _openChest; // @ G0426_T_OpenChest
int16 _objDescTextXpos; // @ G0421_i_ObjectDescriptionTextX
int16 _objDescTextYpos; // @ G0422_i_ObjectDescriptionTextY
Box _boxPanel;
const char *_skillLevelNames[15];
void toggleInventory(ChampionIndex championIndex); // @ F0355_INVENTORY_Toggle_CPSE
void drawStatusBoxPortrait(ChampionIndex championIndex); // @ F0354_INVENTORY_DrawStatusBoxPortrait
void drawPanelHorizontalBar(int16 x, int16 y, int16 pixelWidth, Color color); // @ F0343_INVENTORY_DrawPanel_HorizontalBar
void drawPanelFoodOrWaterBar(int16 amount, int16 y, Color color); // @ F0344_INVENTORY_DrawPanel_FoodOrWaterBar
void drawPanelFoodWaterPoisoned(); // @ F0345_INVENTORY_DrawPanel_FoodWaterPoisoned
void drawPanelResurrectReincarnate(); // @ F0346_INVENTORY_DrawPanel_ResurrectReincarnate
void drawPanel(); // @ F0347_INVENTORY_DrawPanel
void closeChest(); // @ F0334_INVENTORY_CloseChest
void drawPanelScrollTextLine(int16 yPos, char *text); // @ F0340_INVENTORY_DrawPanel_ScrollTextLine
void drawPanelScroll(Scroll *scroll); // @ F0341_INVENTORY_DrawPanel_Scroll
void openAndDrawChest(Thing thingToOpen, Container *chest, bool isPressingEye); // @ F0333_INVENTORY_OpenAndDrawChest
void drawIconToViewport(IconIndice iconIndex, int16 xPos, int16 yPos); // @ F0332_INVENTORY_DrawIconToViewport
void buildObjectAttributeString(int16 potentialAttribMask, int16 actualAttribMask, const char ** attribStrings,
char *destString, const char *prefixString, const char *suffixString); // @ F0336_INVENTORY_DrawPanel_BuildObjectAttributesString
void drawPanelObjectDescriptionString(const char *descString); // @ F0335_INVENTORY_DrawPanel_ObjectDescriptionString
void drawPanelArrowOrEye(bool pressingEye); // @ F0339_INVENTORY_DrawPanel_ArrowOrEye
void drawPanelObject(Thing thingToDraw, bool pressingEye); // @ F0342_INVENTORY_DrawPanel_Object
void setDungeonViewPalette(); // @ F0337_INVENTORY_SetDungeonViewPalette
void decreaseTorchesLightPower(); // @ F0338_INVENTORY_DecreaseTorchesLightPower_CPSE
void drawChampionSkillsAndStatistics(); // @ F0351_INVENTORY_DrawChampionSkillsAndStatistics
void drawStopPressingMouth(); // @ F0350_INVENTORY_DrawStopPressingMouth
void drawStopPressingEye();// @ F0353_INVENTORY_DrawStopPressingEye
void clickOnMouth(); // @ F0349_INVENTORY_ProcessCommand70_ClickOnMouth
void adjustStatisticCurrentValue(Champion *champ, uint16 statIndex, int16 valueDelta); // @ F0348_INVENTORY_AdjustStatisticCurrentValue
void clickOnEye(); // @ F0352_INVENTORY_ProcessCommand71_ClickOnEye
};
}
#endif

451
engines/dm/loadsave.cpp Normal file
View File

@@ -0,0 +1,451 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#include "common/system.h"
#include "common/savefile.h"
#include "common/translation.h"
#include "graphics/thumbnail.h"
#include "gui/saveload.h"
#include "dm/dm.h"
#include "dm/dungeonman.h"
#include "dm/timeline.h"
#include "dm/group.h"
#include "dm/champion.h"
#include "dm/menus.h"
#include "dm/eventman.h"
#include "dm/projexpl.h"
#include "dm/dialog.h"
namespace DM {
LoadgameResult DMEngine::loadgame(int16 slot) {
if (slot == -1 && _gameMode == kDMModeLoadSavedGame)
return kDMLoadgameFailure;
bool fadePalette = true;
Common::String fileName;
Common::SaveFileManager *saveFileManager = nullptr;
Common::InSaveFile *file = nullptr;
struct {
SaveTarget _saveTarget;
int32 _saveVersion;
OriginalSaveFormat _saveFormat;
OriginalSavePlatform _savePlatform;
uint16 _dungeonId;
} dmSaveHeader;
if (_gameMode != kDMModeLoadSavedGame) {
//L1366_B_FadePalette = !F0428_DIALOG_RequireGameDiskInDrive_NoDialogDrawn(C0_DO_NOT_FORCE_DIALOG_DM_CSB, true);
_restartGameAllowed = false;
_championMan->_partyChampionCount = 0;
_championMan->_leaderHandObject = _thingNone;
} else {
fileName = getSavefileName(slot);
saveFileManager = _system->getSavefileManager();
file = saveFileManager->openForLoading(fileName);
SaveGameHeader header;
if (!readSaveGameHeader(file, &header)) {
delete file;
return kDMLoadgameFailure;
}
warning("MISSING CODE: missing check for matching format and platform in save in f435_loadgame");
dmSaveHeader._saveTarget = (SaveTarget)file->readSint32BE();
dmSaveHeader._saveVersion = file->readSint32BE();
dmSaveHeader._saveFormat = (OriginalSaveFormat)file->readSint32BE();
dmSaveHeader._savePlatform = (OriginalSavePlatform)file->readSint32BE();
// Skip _gameId, which was useless
file->readSint32BE();
dmSaveHeader._dungeonId = file->readUint16BE();
_gameTime = file->readSint32BE();
// G0349_ul_LastRandomNumber = L1371_s_GlobalData.LastRandomNumber;
_championMan->_partyChampionCount = file->readUint16BE();
_dungeonMan->_partyMapX = file->readSint16BE();
_dungeonMan->_partyMapY = file->readSint16BE();
_dungeonMan->_partyDir = (Direction)file->readUint16BE();
_dungeonMan->_partyMapIndex = file->readByte();
_championMan->_leaderIndex = (ChampionIndex)file->readSint16BE();
_championMan->_magicCasterChampionIndex = (ChampionIndex)file->readSint16BE();
_timeline->_eventCount = file->readUint16BE();
_timeline->_firstUnusedEventIndex = file->readUint16BE();
_timeline->_eventMaxCount = file->readUint16BE();
_groupMan->_currActiveGroupCount = file->readUint16BE();
_projexpl->_lastCreatureAttackTime = file->readSint32BE();
_projexpl->_lastPartyMovementTime = file->readSint32BE();
_disabledMovementTicks = file->readSint16BE();
_projectileDisableMovementTicks = file->readSint16BE();
_lastProjectileDisabledMovementDirection = file->readSint16BE();
_championMan->_leaderHandObject = Thing(file->readUint16BE());
_groupMan->_maxActiveGroupCount = file->readUint16BE();
if (!_restartGameRequest) {
_timeline->initTimeline();
_groupMan->initActiveGroups();
}
_groupMan->loadActiveGroupPart(file);
_championMan->loadPartyPart2(file);
_timeline->loadEventsPart(file);
_timeline->loadTimelinePart(file);
// read sentinel
uint32 sentinel = file->readUint32BE();
assert(sentinel == 0x6f85e3d3);
_dungeonId = dmSaveHeader._dungeonId;
}
_dungeonMan->loadDungeonFile(file);
delete file;
if (_gameMode != kDMModeLoadSavedGame) {
_timeline->initTimeline();
_groupMan->initActiveGroups();
if (fadePalette) {
_displayMan->startEndFadeToPalette(_displayMan->_blankBuffer);
delay(1);
_displayMan->fillScreen(kDMColorBlack);
_displayMan->startEndFadeToPalette(_displayMan->_paletteTopAndBottomScreen);
}
} else {
_restartGameAllowed = true;
switch (getGameLanguage()) { // localized
case Common::DE_DEU:
_dialog->dialogDraw(nullptr, "SPIEL WIRD GELADEN . . .", nullptr, nullptr, nullptr, nullptr, true, true, true);
break;
case Common::FR_FRA:
_dialog->dialogDraw(nullptr, "CHARGEMENT DU JEU . . .", nullptr, nullptr, nullptr, nullptr, true, true, true);
break;
default:
_dialog->dialogDraw(nullptr, "LOADING GAME . . .", nullptr, nullptr, nullptr, nullptr, true, true, true);
break;
}
}
_championMan->_partyDead = false;
return kDMLoadgameSuccess;
}
void DMEngine::saveGame() {
_menuMan->drawDisabledMenu();
_eventMan->showMouse();
switch (getGameLanguage()) { // localized
default:
case Common::EN_ANY:
_dialog->dialogDraw(nullptr, nullptr, "SAVE AND PLAY", "SAVE AND QUIT", "CANCEL", "LOAD", false, false, false);
break;
case Common::DE_DEU:
_dialog->dialogDraw(nullptr, nullptr, "SICHERN/SPIEL", "SICHERN/ENDEN", "WIDERRUFEN", "LOAD", false, false, false);
break;
case Common::FR_FRA:
_dialog->dialogDraw(nullptr, nullptr, "GARDER/JOUER", "GARDER/SORTIR", "ANNULLER", "LOAD", false, false, false);
break;
}
enum SaveAndPlayChoice {
kSaveAndPlay = 1,
kSaveAndQuit = 2,
kCancel = 3,
kLoad = 4
};
SaveAndPlayChoice saveAndPlayChoice = (SaveAndPlayChoice)_dialog->getChoice(4, kDMDialogCommandSetViewport, 0, kDMDialogChoiceNone);
if (saveAndPlayChoice == kLoad) {
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
int loadSlot = dialog->runModalWithCurrentTarget();
delete dialog;
if (loadSlot >= 0) {
_loadSaveSlotAtRuntime = loadSlot;
return;
}
saveAndPlayChoice = kCancel;
}
if (saveAndPlayChoice == kSaveAndQuit || saveAndPlayChoice == kSaveAndPlay) {
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
int16 saveSlot = dialog->runModalWithCurrentTarget();
Common::String saveDescription = dialog->getResultString();
if (saveDescription.empty())
saveDescription = "Nice save ^^";
delete dialog;
if (saveSlot >= 0) {
switch (getGameLanguage()) { // localized
default:
case Common::EN_ANY:
_dialog->dialogDraw(nullptr, "SAVING GAME . . .", nullptr, nullptr, nullptr, nullptr, false, false, false);
break;
case Common::DE_DEU:
_dialog->dialogDraw(nullptr, "SPIEL WIRD GESICHERT . . .", nullptr, nullptr, nullptr, nullptr, false, false, false);
break;
case Common::FR_FRA:
_dialog->dialogDraw(nullptr, "UN MOMENT A SAUVEGARDER DU JEU...", nullptr, nullptr, nullptr, nullptr, false, false, false);
break;
}
uint16 champHandObjWeight = 0;
if (!_championMan->_leaderEmptyHanded) {
champHandObjWeight = _dungeonMan->getObjectWeight(_championMan->_leaderHandObject);
_championMan->_champions[_championMan->_leaderIndex]._load -= champHandObjWeight;
}
if (!writeCompleteSaveFile(saveSlot, saveDescription, saveAndPlayChoice)) {
_dialog->dialogDraw(nullptr, "Unable to open file for saving", "OK", nullptr, nullptr, nullptr, false, false, false);
_dialog->getChoice(1, kDMDialogCommandSetViewport, 0, kDMDialogChoiceNone);
}
if (!_championMan->_leaderEmptyHanded) {
_championMan->_champions[_championMan->_leaderIndex]._load += champHandObjWeight;
}
} else
saveAndPlayChoice = kCancel;
}
if (saveAndPlayChoice == kSaveAndQuit) {
_eventMan->hideMouse();
endGame(false);
}
_restartGameAllowed = true;
_menuMan->drawEnabledMenus();
_eventMan->hideMouse();
}
Common::String DMEngine::getSavefileName(uint16 slot) {
return Common::String::format("%s.%03u", _targetName.c_str(), slot);
}
#define SAVEGAME_ID MKTAG('D', 'M', '2', '1')
#define SAVEGAME_VERSION 1
void DMEngine::writeSaveGameHeader(Common::OutSaveFile *out, const Common::String& saveName) {
out->writeUint32BE(SAVEGAME_ID);
// Write version
out->writeByte(SAVEGAME_VERSION);
// Write savegame name
out->writeString(saveName);
out->writeByte(0);
// Save the game thumbnail
if (_saveThumbnail)
out->write(_saveThumbnail->getData(), _saveThumbnail->size());
else
Graphics::saveThumbnail(*out);
// Creation date/time
TimeDate curTime;
_system->getTimeAndDate(curTime);
uint32 saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
uint16 saveTime = ((curTime.tm_hour & 0xFF) << 8) | ((curTime.tm_min) & 0xFF);
uint32 playTime = getTotalPlayTime() / 1000;
out->writeUint32BE(saveDate);
out->writeUint16BE(saveTime);
out->writeUint32BE(playTime);
}
bool DMEngine::writeCompleteSaveFile(int16 saveSlot, Common::String& saveDescription, int16 saveAndPlayChoice) {
Common::String savefileName = getSavefileName(saveSlot);
Common::SaveFileManager *saveFileManager = _system->getSavefileManager();
Common::OutSaveFile *file = saveFileManager->openForSaving(savefileName);
if (!file)
return false;
writeSaveGameHeader(file, saveDescription);
file->writeSint32BE(_gameVersion->_saveTargetToWrite);
file->writeSint32BE(1); // save version
file->writeSint32BE(_gameVersion->_origSaveFormatToWrite);
file->writeSint32BE(_gameVersion->_origPlatformToWrite);
// Was _gameID, useless.
file->writeSint32BE(0);
file->writeUint16BE(_dungeonId);
// write C0_SAVE_PART_GLOBAL_DATA part
file->writeSint32BE(_gameTime);
//L1348_s_GlobalData.LastRandomNumber = G0349_ul_LastRandomNumber;
file->writeUint16BE(_championMan->_partyChampionCount);
file->writeSint16BE(_dungeonMan->_partyMapX);
file->writeSint16BE(_dungeonMan->_partyMapY);
file->writeUint16BE(_dungeonMan->_partyDir);
file->writeByte(_dungeonMan->_partyMapIndex);
file->writeSint16BE(_championMan->_leaderIndex);
file->writeSint16BE(_championMan->_magicCasterChampionIndex);
file->writeUint16BE(_timeline->_eventCount);
file->writeUint16BE(_timeline->_firstUnusedEventIndex);
file->writeUint16BE(_timeline->_eventMaxCount);
file->writeUint16BE(_groupMan->_currActiveGroupCount);
file->writeSint32BE(_projexpl->_lastCreatureAttackTime);
file->writeSint32BE(_projexpl->_lastPartyMovementTime);
file->writeSint16BE(_disabledMovementTicks);
file->writeSint16BE(_projectileDisableMovementTicks);
file->writeSint16BE(_lastProjectileDisabledMovementDirection);
file->writeUint16BE(_championMan->_leaderHandObject.toUint16());
file->writeUint16BE(_groupMan->_maxActiveGroupCount);
// write C1_SAVE_PART_ACTIVE_GROUP part
_groupMan->saveActiveGroupPart(file);
// write C2_SAVE_PART_PARTY part
_championMan->savePartyPart2(file);
// write C3_SAVE_PART_EVENTS part
_timeline->saveEventsPart(file);
// write C4_SAVE_PART_TIMELINE part
_timeline->saveTimelinePart(file);
// write sentinel
file->writeUint32BE(0x6f85e3d3);
// save _g278_dungeonFileHeader
DungeonFileHeader &header = _dungeonMan->_dungeonFileHeader;
file->writeUint16BE(header._ornamentRandomSeed);
file->writeUint16BE(header._rawMapDataSize);
file->writeByte(header._mapCount);
file->writeByte(0); // to match the structure of dungeon.dat, will be discarded
file->writeUint16BE(header._textDataWordCount);
file->writeUint16BE(header._partyStartLocation);
file->writeUint16BE(header._squareFirstThingCount);
for (uint16 i = 0; i < 16; ++i)
file->writeUint16BE(header._thingCounts[i]);
// save _g277_dungeonMaps
for (uint16 i = 0; i < _dungeonMan->_dungeonFileHeader._mapCount; ++i) {
Map &map = _dungeonMan->_dungeonMaps[i];
file->writeUint16BE(map._rawDunDataOffset);
file->writeUint32BE(0); // to match the structure of dungeon.dat, will be discarded
file->writeByte(map._offsetMapX);
file->writeByte(map._offsetMapY);
uint16 tmp;
tmp = ((map._height & 0x1F) << 11) | ((map._width & 0x1F) << 6) | (map._level & 0x3F);
file->writeUint16BE(tmp);
tmp = ((map._randFloorOrnCount & 0xF) << 12) | ((map._floorOrnCount & 0xF) << 8)
| ((map._randWallOrnCount & 0xF) << 4) | (map._wallOrnCount & 0xF);
file->writeUint16BE(tmp);
tmp = ((map._difficulty & 0xF) << 12) | ((map._creatureTypeCount & 0xF) << 4) | (map._doorOrnCount & 0xF);
file->writeUint16BE(tmp);
tmp = ((map._doorSet1 & 0xF) << 12) | ((map._doorSet0 & 0xF) << 8)
| ((map._wallSet & 0xF) << 4) | (map._floorSet & 0xF);
file->writeUint16BE(tmp);
}
// save _g280_dungeonColumnsCumulativeSquareThingCount
for (uint16 i = 0; i < _dungeonMan->_dungeonColumCount; ++i)
file->writeUint16BE(_dungeonMan->_dungeonColumnsCumulativeSquareThingCount[i]);
// save _g283_squareFirstThings
for (uint16 i = 0; i < _dungeonMan->_dungeonFileHeader._squareFirstThingCount; ++i)
file->writeUint16BE(_dungeonMan->_squareFirstThings[i].toUint16());
// save _g260_dungeonTextData
for (uint16 i = 0; i < _dungeonMan->_dungeonFileHeader._textDataWordCount; ++i)
file->writeUint16BE(_dungeonMan->_dungeonTextData[i]);
// save _g284_thingData
for (uint16 thingIndex = 0; thingIndex < 16; ++thingIndex)
for (uint16 i = 0; i < _dungeonMan->_thingDataWordCount[thingIndex] * _dungeonMan->_dungeonFileHeader._thingCounts[thingIndex]; ++i)
file->writeUint16BE(_dungeonMan->_thingData[thingIndex][i]);
// save _g276_dungeonRawMapData
for (uint32 i = 0; i < _dungeonMan->_dungeonFileHeader._rawMapDataSize; ++i)
file->writeByte(_dungeonMan->_dungeonRawMapData[i]);
file->flush();
file->finalize();
delete file;
return true;
}
WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header, bool skipThumbnail) {
uint32 id = in->readUint32BE();
// Check if it's a valid ScummVM savegame
if (id != SAVEGAME_ID)
return false;
// Read in the version
header->_version = in->readByte();
// Check that the save version isn't newer than this binary
if (header->_version > SAVEGAME_VERSION)
return false;
// Read in the save name
Common::String saveName;
char ch;
while ((ch = (char)in->readByte()) != '\0')
saveName += ch;
header->_descr.setDescription(saveName);
// Get the thumbnail
Graphics::Surface *thumbnail;
if (!Graphics::loadThumbnail(*in, thumbnail, skipThumbnail)) {
return false;
}
header->_descr.setThumbnail(thumbnail);
uint32 saveDate = in->readUint32BE();
uint16 saveTime = in->readUint16BE();
uint32 playTime = in->readUint32BE();
int day = (saveDate >> 24) & 0xFF;
int month = (saveDate >> 16) & 0xFF;
int year = saveDate & 0xFFFF;
header->_descr.setSaveDate(year, month, day);
int hour = (saveTime >> 8) & 0xFF;
int minutes = saveTime & 0xFF;
header->_descr.setSaveTime(hour, minutes);
header->_descr.setPlayTime(playTime * 1000);
if (g_engine)
g_engine->setTotalPlayTime(playTime * 1000);
return true;
}
}

41
engines/dm/loadsave.h Normal file
View File

@@ -0,0 +1,41 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_LOADSAVE_H
#define DM_LOADSAVE_H
#include "dm/dm.h"
namespace DM {
class LoadsaveMan {
DMEngine *_vm;
public:
explicit LoadsaveMan(DMEngine *vm);
};
}
#endif

186
engines/dm/lzw.cpp Normal file
View File

@@ -0,0 +1,186 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#include "common/memstream.h"
#include "dm/lzw.h"
namespace DM {
LZWdecompressor::LZWdecompressor() {
_repetitionEnabled = false;
_codeBitCount = 0;
_currentMaximumCode = 0;
_absoluteMaximumCode = 4096;
for (int i = 0; i < 12; ++i)
_inputBuffer[i] = 0;
_dictNextAvailableCode = 0;
_dictFlushed = false;
byte leastSignificantBitmasks[9] = {0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F,0x7F,0xFF};
for (uint16 i = 0; i < 9; ++i)
_leastSignificantBitmasks[i] = leastSignificantBitmasks[i];
_inputBufferBitIndex = 0;
_inputBufferBitCount = 0;
_charToRepeat = 0;
_tempBuffer = new byte[5004];
_prefixCode = new int16[5003];
_appendCharacter = new byte[5226];
}
LZWdecompressor::~LZWdecompressor() {
delete[] _appendCharacter;
delete[] _prefixCode;
delete[] _tempBuffer;
}
int16 LZWdecompressor::getNextInputCode(Common::MemoryReadStream &inputStream, int32 *inputByteCount) {
byte *inputBuffer = _inputBuffer;
if (_dictFlushed || (_inputBufferBitIndex >= _inputBufferBitCount) || (_dictNextAvailableCode > _currentMaximumCode)) {
if (_dictNextAvailableCode > _currentMaximumCode) {
_codeBitCount++;
if (_codeBitCount == 12) {
_currentMaximumCode = _absoluteMaximumCode;
} else {
_currentMaximumCode = (1 << _codeBitCount) - 1;
}
}
if (_dictFlushed) {
_currentMaximumCode = (1 << (_codeBitCount = 9)) - 1;
_dictFlushed = false;
}
if (*inputByteCount > _codeBitCount) {
_inputBufferBitCount = _codeBitCount;
} else {
_inputBufferBitCount = *inputByteCount;
}
if (_inputBufferBitCount > 0) {
inputStream.read(_inputBuffer, _inputBufferBitCount);
*inputByteCount -= _inputBufferBitCount;
} else {
return -1;
}
_inputBufferBitIndex = 0;
_inputBufferBitCount = (_inputBufferBitCount << 3) - (_codeBitCount - 1);
}
int16 bitIndex = _inputBufferBitIndex;
int16 requiredInputBitCount = _codeBitCount;
inputBuffer += bitIndex >> 3; /* Address of byte in input buffer containing current bit */
bitIndex &= 0x0007; /* Bit index of the current bit in the byte */
int16 nextInputCode = *inputBuffer++ >> bitIndex; /* Get the first bits of the next input code from the input buffer byte */
requiredInputBitCount -= 8 - bitIndex; /* Remaining number of bits to get for a complete input code */
bitIndex = 8 - bitIndex;
if (requiredInputBitCount >= 8) {
nextInputCode |= *inputBuffer++ << bitIndex;
bitIndex += 8;
requiredInputBitCount -= 8;
}
nextInputCode |= (*inputBuffer & _leastSignificantBitmasks[requiredInputBitCount]) << bitIndex;
_inputBufferBitIndex += _codeBitCount;
return nextInputCode;
}
void LZWdecompressor::outputCharacter(byte character, byte **out) {
byte *output = *out;
if (false == _repetitionEnabled) {
if (character == 0x90)
_repetitionEnabled = true;
else
*output++ = _charToRepeat = character;
} else {
if (character) { /* If character following 0x90 is not 0x00 then it is the repeat count */
while (--character)
*output++ = _charToRepeat;
} else /* else output a 0x90 character */
*output++ = 0x90;
_repetitionEnabled = false;
}
*out = output;
return;
}
int32 LZWdecompressor::decompress(Common::MemoryReadStream &inStream, int32 inputByteCount, byte *out) {
byte *reversedDecodedStringStart;
byte *reversedDecodedStringEnd = reversedDecodedStringStart = _tempBuffer;
byte *originalOut = out;
_repetitionEnabled = false;
_codeBitCount = 9;
_dictFlushed = false;
_currentMaximumCode = (1 << (_codeBitCount = 9)) - 1;
for (int16 code = 255; code >= 0; code--) {
_prefixCode[code] = 0;
_appendCharacter[code] = code;
}
_dictNextAvailableCode = 257;
int16 oldCode;
int16 character = oldCode = getNextInputCode(inStream, &inputByteCount);
if (oldCode == -1) {
return -1L;
}
outputCharacter(character, &out);
int16 code;
while ((code = getNextInputCode(inStream, &inputByteCount)) > -1) {
if (code == 256) { /* This code is used to flush the dictionary */
for (int i = 0; i < 256; ++i)
_prefixCode[i] = 0;
_dictFlushed = true;
_dictNextAvailableCode = 256;
if ((code = getNextInputCode(inStream, &inputByteCount)) == -1) {
break;
}
}
/* This code checks for the special STRING+CHARACTER+STRING+CHARACTER+STRING case which generates an undefined code.
It handles it by decoding the last code, adding a single character to the end of the decoded string */
int16 newCode = code;
if (code >= _dictNextAvailableCode) { /* If code is not defined yet */
*reversedDecodedStringEnd++ = character;
code = oldCode;
}
/* Use the string table to decode the string corresponding to the code and store the string in the temporary buffer */
while (code >= 256) {
*reversedDecodedStringEnd++ = _appendCharacter[code];
code = _prefixCode[code];
}
*reversedDecodedStringEnd++ = (character = _appendCharacter[code]);
/* Output the decoded string in reverse order */
do {
outputCharacter(*(--reversedDecodedStringEnd), &out);
} while (reversedDecodedStringEnd > reversedDecodedStringStart);
/* If possible, add a new code to the string table */
if ((code = _dictNextAvailableCode) < _absoluteMaximumCode) {
_prefixCode[code] = oldCode;
_appendCharacter[code] = character;
_dictNextAvailableCode = code + 1;
}
oldCode = newCode;
}
return out - originalOut; /* Byte count of decompressed data */
}
}

68
engines/dm/lzw.h Normal file
View File

@@ -0,0 +1,68 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_LZW_H
#define DM_LZW_H
#include "common/file.h"
#include "dm/dm.h"
namespace Common {
class MemoryReadStream;
}
namespace DM {
class LZWdecompressor {
bool _repetitionEnabled;
int16 _codeBitCount;
int16 _currentMaximumCode;
int16 _absoluteMaximumCode;
byte _inputBuffer[12];
int16 _dictNextAvailableCode;
bool _dictFlushed;
byte _leastSignificantBitmasks[9];
int16 _inputBufferBitIndex;
int16 _inputBufferBitCount;
int16 _charToRepeat;
byte *_tempBuffer;
int16 *_prefixCode;
byte *_appendCharacter;
int16 getNextInputCode(Common::MemoryReadStream &stream, int32 *inputByteCount);
void outputCharacter(byte character, byte **out);
void operator=(const LZWdecompressor&); // deleted
public:
LZWdecompressor();
~LZWdecompressor();
int32 decompress(Common::MemoryReadStream &inputStream, int32 inputByteCount, byte *out);
};
}
#endif

1858
engines/dm/menus.cpp Normal file

File diff suppressed because it is too large Load Diff

140
engines/dm/menus.h Normal file
View File

@@ -0,0 +1,140 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_MENUS_H
#define DM_MENUS_H
#include "dm/dm.h"
#include "dm/champion.h"
#include "dm/dungeonman.h"
namespace DM {
enum Damage {
kDMDamageCantReach = -1, // @ CM1_DAMAGE_CANT_REACH
kDMDamageNoAmmunition = -2 // @ CM2_DAMAGE_NO_AMMUNITION
};
enum SpellArea {
kDMSpellAreaAvailableSymbols = 2, // @ C2_SPELL_AREA_AVAILABLE_SYMBOLS
kDMSpellAreaChampionSymbols = 3 // @ C3_SPELL_AREA_CHAMPION_SYMBOLS
};
enum ActionMask {
kDMActionMaskRequiresCharge = 0x0080, // @ MASK0x0080_ACTION_REQUIRES_CHARGE
kDMActionMaskHitNonMaterialCreatures = 0x8000 // @ MASK0x8000_HIT_NON_MATERIAL_CREATURES
};
class ActionList {
public:
byte _minimumSkillLevel[3]; /* Bit 7: requires charge, Bit 6-0: minimum skill level. */
ChampionAction _actionIndices[3];
ActionList() { resetToZero(); }
void resetToZero() {
for (uint16 i = 0; i < 3; ++i) {
_minimumSkillLevel[i] = 0;
_actionIndices[i] = (ChampionAction)0;
}
}
}; // @ ACTION_LIST
class ActionSet {
public:
byte _actionIndices[3]; /* 1 byte of padding inserted by compiler on Atari ST, not on Amiga */
byte _actionProperties[2]; /* Bit 7: requires charge, Bit 6-0: minimum skill level */
ActionSet(byte a1, byte a2, byte a3, byte b1, byte b2) {
_actionIndices[0] = a1;
_actionIndices[1] = a2;
_actionIndices[2] = a3;
_actionProperties[0] = b1;
_actionProperties[1] = b2;
}
}; // @ ACTION_SET
class MenuMan {
DMEngine *_vm;
public:
explicit MenuMan(DMEngine *vm);
~MenuMan();
bool _refreshActionArea; // @ G0508_B_RefreshActionArea
bool _actionAreaContainsIcons; // @ G0509_B_ActionAreaContainsIcons
int16 _actionDamage; // @ G0513_i_ActionDamage
ActionList _actionList; // @ G0713_s_ActionList
byte *_bitmapSpellAreaLine; // @ K0072_puc_Bitmap_SpellAreaLine
byte *_bitmapSpellAreaLines; // @ K0073_puc_Bitmap_SpellAreaLines
Thing _actionTargetGroupThing; // @ G0517_T_ActionTargetGroupThing
uint16 _actionCount; // @ G0507_ui_ActionCount
void clearActingChampion(); // @ F0388_MENUS_ClearActingChampion
void drawActionIcon(ChampionIndex championIndex); // @ F0386_MENUS_DrawActionIcon
void drawMovementArrows(); // @ F0395_MENUS_DrawMovementArrows
void drawDisabledMenu(); // @ F0456_START_DrawDisabledMenus
void refreshActionAreaAndSetChampDirMaxDamageReceived(); // @ F0390_MENUS_RefreshActionAreaAndSetChampionDirectionMaximumDamageReceived
void drawActionArea(); // @ F0387_MENUS_DrawActionArea
const char *getActionName(ChampionAction actionIndex); // @ F0384_MENUS_GetActionName
void drawSpellAreaControls(ChampionIndex champIndex); // @ F0393_MENUS_DrawSpellAreaControls
void buildSpellAreaLine(int16 spellAreaBitmapLine);// @ F0392_MENUS_BuildSpellAreaLine
void setMagicCasterAndDrawSpellArea(ChampionIndex champIndex); // @ F0394_MENUS_SetMagicCasterAndDrawSpellArea
void drawEnabledMenus(); // @ F0457_START_DrawEnabledMenus_CPSF
int16 getClickOnSpellCastResult(); // @ F0408_MENUS_GetClickOnSpellCastResult
int16 getChampionSpellCastResult(uint16 champIndex); // @ F0412_MENUS_GetChampionSpellCastResult
Spell *getSpellFromSymbols(byte *symbols); // @ F0409_MENUS_GetSpellFromSymbols
void menusPrintSpellFailureMessage(Champion *champ, uint16 failureType, uint16 skillIndex); // @ F0410_MENUS_PrintSpellFailureMessage
Potion *getEmptyFlaskInHand(Champion *champ, Thing *potionThing); // @ F0411_MENUS_GetEmptyFlaskInHand
void createEvent70_light(int16 lightPower, int16 ticks); // @ F0404_MENUS_CreateEvent70_Light
bool isPartySpellOrFireShieldSuccessful(Champion *champ, bool spellShield, uint16 ticks, bool useMana); // @ F0403_MENUS_IsPartySpellOrFireShieldSuccessful
void drawAvailableSymbols(uint16 symbolStep); // @ F0397_MENUS_DrawAvailableSymbols
void drawChampionSymbols(Champion *champ); // @ F0398_MENUS_DrawChampionSymbols
void addChampionSymbol(int16 symbolIndex); // @ F0399_MENUS_AddChampionSymbol
void deleteChampionSymbol(); // @ F0400_MENUS_DeleteChampionSymbol
bool didClickTriggerAction(int16 actionListIndex); // @ F0391_MENUS_DidClickTriggerAction
bool isActionPerformed(uint16 champIndex, int16 actionIndex); // @ F0407_MENUS_IsActionPerformed
void setChampionDirectionToPartyDirection(Champion *champ); // @ F0406_MENUS_SetChampionDirectionToPartyDirection
void decrementCharges(Champion *champ); // @ F0405_MENUS_DecrementCharges
bool isMeleeActionPerformed(int16 champIndex, Champion *champ, int16 actionIndex, int16 targetMapX,
int16 targetMapY, int16 skillIndex); // @ F0402_MENUS_IsMeleeActionPerformed
bool isGroupFrightenedByAction(int16 champIndex, uint16 actionIndex, int16 mapX, int16 mapY); // @ F0401_MENUS_IsGroupFrightenedByAction
void printMessageAfterReplacements(const char *str); // @ F0381_MENUS_PrintMessageAfterReplacements
void processCommands116To119_setActingChampion(uint16 champIndex); // @ F0389_MENUS_ProcessCommands116To119_SetActingChampion
void setActionList(ActionSet *actionSet); // @ F0383_MENUS_SetActionList
int16 getActionObjectChargeCount(); // @ F0382_MENUS_GetActionObjectChargeCount
void drawActionDamage(int16 damage); // @ F0385_MENUS_DrawActionDamage
Box _boxActionArea3ActionMenu; // @ G0499_s_Graphic560_Box_ActionArea3ActionsMenu
Box _boxActionArea2ActionMenu; // @ G0500_s_Graphic560_Box_ActionArea2ActionsMenu
Box _boxActionArea1ActionMenu; // @ G0501_s_Graphic560_Box_ActionArea1ActionMenu
Box _boxActionArea; // @ G0001_s_Graphic562_Box_ActionArea
Box _boxSpellArea;
unsigned char _actionSkillIndex[44]; // @ G0496_auc_Graphic560_ActionSkillIndex
unsigned char _actionDisabledTicks[44];
void initConstants();
};
}
#endif // DM_MENUS_H

269
engines/dm/metaengine.cpp Normal file
View File

@@ -0,0 +1,269 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#include "common/config-manager.h"
#include "common/error.h"
#include "common/fs.h"
#include "common/system.h"
#include "common/translation.h"
#include "engines/advancedDetector.h"
#include "dm/dm.h"
#include "backends/keymapper/action.h"
#include "backends/keymapper/keymapper.h"
#include "backends/keymapper/standard-actions.h"
namespace DM {
class DMMetaEngine : public AdvancedMetaEngine<DMADGameDescription> {
public:
const char *getName() const override {
return "dm";
}
Common::Error createInstance(OSystem *syst, Engine **engine, const DMADGameDescription *desc) const override {
*engine = new DM::DMEngine(syst, (const DMADGameDescription*)desc);
return Common::kNoError;
}
bool hasFeature(MetaEngineFeature f) const override {
return
(f == kSupportsListSaves) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSavesSupportThumbnail) ||
(f == kSavesSupportMetaInfo) ||
(f == kSimpleSavesNames) ||
(f == kSavesSupportCreationDate);
}
int getMaximumSaveSlot() const override { return 99; }
SaveStateList listSaves(const char *target) const override {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
SaveGameHeader header;
Common::String pattern = target;
pattern += ".###";
Common::StringArray filenames = saveFileMan->listSavefiles(pattern.c_str());
SaveStateList saveList;
for (const auto &filename : filenames) {
// Obtain the last 3 digits of the filename, since they correspond to the save slot
int slotNum = atoi(filename.c_str() + filename.size() - 3);
if ((slotNum >= 0) && (slotNum <= 999)) {
Common::InSaveFile *in = saveFileMan->openForLoading(filename.c_str());
if (in) {
if (DM::readSaveGameHeader(in, &header))
saveList.push_back(SaveStateDescriptor(this, slotNum, header._descr.getDescription()));
delete in;
}
}
}
// Sort saves based on slot number.
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override {
Common::String filename = Common::String::format("%s.%03u", target, slot);
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
if (in) {
DM::SaveGameHeader header;
bool successfulRead = DM::readSaveGameHeader(in, &header);
delete in;
if (successfulRead) {
SaveStateDescriptor desc(this, slot, header._descr.getDescription());
return header._descr;
}
}
return SaveStateDescriptor();
}
bool removeSaveState(const char *target, int slot) const override { return false; }
Common::KeymapArray initKeymaps(const char *target) const override;
};
Common::KeymapArray DMMetaEngine::initKeymaps(const char *target) const {
using namespace Common;
using namespace DM;
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "dm-default", _("Default keymappings"));
Keymap *choiceSelectionKeyMap = new Keymap(Keymap::kKeymapTypeGame, "choice-selection", _("Dialog choice selection keymappings"));
Keymap *gameKeyMap = new Keymap(Keymap::kKeymapTypeGame, "game-shortcuts", _("Game keymappings"));
Action *act;
act = new Action(kStandardActionLeftClick, _("Select / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
engineKeyMap->addAction(act);
// I18N: (Game name: Dungeon Master) The player has a team of 4 characters called "champions" which they choose themselves. One of them can be assigned the "leader". This action toggles the inventory screen of the leader champion.
act = new Action(kStandardActionRightClick, _("Toggle leader inventory"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
engineKeyMap->addAction(act);
// I18N: (Game name: Dungeon Master) The game has multi-choice dialogs. If there is only one choice, then this action can be used to select it.
act = new Action("SELECTCHOICE", _("Select dialog choice (only works if there is a single choice)"));
act->setCustomEngineActionEvent(kActionSelectChoice);
act->addDefaultInputMapping("RETURN");
act->addDefaultInputMapping("JOY_X");
choiceSelectionKeyMap->addAction(act);
// I18N: (Game name: Dungeon Master) The player has a team of 4 characters called "champions" which they choose themselves. This action toggles the inventory screen of champion 1.
act = new Action("CHAMPION1INV", _("Toggle champion 1 inventory"));
act->setCustomEngineActionEvent(kActionToggleInventoryChampion0);
act->addDefaultInputMapping("F1"); // F1 (<CSI>1~) Atari ST: Code = 0x3B00
gameKeyMap->addAction(act);
// I18N: (Game name: Dungeon Master) The player has a team of 4 characters called "champions" which they choose themselves. This action toggles the inventory screen of champion 2.
act = new Action("CHAMPION2INV", _("Toggle champion 2 inventory"));
act->setCustomEngineActionEvent(kActionToggleInventoryChampion1);
act->addDefaultInputMapping("F2"); // F2 (<CSI>2~) Atari ST: Code = 0x3C00
gameKeyMap->addAction(act);
// I18N: (Game name: Dungeon Master) The player has a team of 4 characters called "champions" which they choose themselves. This action toggles the inventory screen of champion 3.
act = new Action("CHAMPION3INV", _("Toggle champion 3 inventory"));
act->setCustomEngineActionEvent(kActionToggleInventoryChampion2);
act->addDefaultInputMapping("F3"); // F3 (<CSI>3~) Atari ST: Code = 0x3D00
gameKeyMap->addAction(act);
// I18N: (Game name: Dungeon Master) The player has a team of 4 characters called "champions" which they choose themselves. This action toggles the inventory screen of champion 4.
act = new Action("CHAMPION4INV", _("Toggle champion 4 inventory"));
act->setCustomEngineActionEvent(kActionToggleInventoryChampion3);
act->addDefaultInputMapping("F4"); // F4 (<CSI>4~) Atari ST: Code = 0x3E00
gameKeyMap->addAction(act);
act = new Action("SAVEGAME", _("Save game"));
act->setCustomEngineActionEvent(kActionSave);
act->addDefaultInputMapping("C+s"); // CTRL-S Atari ST: Code = 0x0013
act->addDefaultInputMapping("JOY_X");
gameKeyMap->addAction(act);
act = new Action("FREEZE", _("Pause"));
act->setCustomEngineActionEvent(kActionFreezeGame);
act->addDefaultInputMapping("ESCAPE"); // Esc (0x1B) Atari ST: Code = 0x001B
act->addDefaultInputMapping("JOY_Y");
gameKeyMap->addAction(act);
act = new Action("TURNLEFT", _("Turn left"));
act->setCustomEngineActionEvent(kActionTurnLeft);
act->addDefaultInputMapping("KP4"); // Numeric pad 4 Atari ST: Code = 0x5200
act->addDefaultInputMapping("q"); // Added for convenience
act->addDefaultInputMapping("S+q"); // Added for convenience
act->addDefaultInputMapping("DELETE"); // Del (0x7F)
act->addDefaultInputMapping("S+DELETE"); // Shift Del (0x7F)
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("MOVEFORWARD", _("Move forward"));
act->setCustomEngineActionEvent(kActionMoveForward);
act->addDefaultInputMapping("KP4"); // Numeric pad 5 Atari ST: Code = 0x4800
act->addDefaultInputMapping("w"); // Added for convenience
act->addDefaultInputMapping("S+w"); // Added for convenience
act->addDefaultInputMapping("UP"); // Up Arrow (<CSI>A)
act->addDefaultInputMapping("S+UP"); // Shift Up Arrow (<CSI>T)
act->addDefaultInputMapping("JOY_UP");
gameKeyMap->addAction(act);
act = new Action("TURNRIGHT", _("Turn right"));
act->setCustomEngineActionEvent(kActionTurnRight);
act->addDefaultInputMapping("KP6"); // Numeric pad 6 Atari ST: Code = 0x4700
act->addDefaultInputMapping("e"); // Added for convenience
act->addDefaultInputMapping("S+e"); // Added for convenience
act->addDefaultInputMapping("HELP"); // Help (<CSI>?~)
act->addDefaultInputMapping("S+HELP"); // Shift Help (<CSI>?~)
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
gameKeyMap->addAction(act);
act = new Action("MOVELEFT", _("Strafe left"));
act->setCustomEngineActionEvent(kActionMoveLeft);
act->addDefaultInputMapping("KP1"); // Numeric pad 1 Atari ST: Code = 0x4B00
act->addDefaultInputMapping("a"); // Added for convenience
act->addDefaultInputMapping("S+a"); // Added for convenience
act->addDefaultInputMapping("LEFT"); // Backward Arrow (<CSI>D)
act->addDefaultInputMapping("S+LEFT"); // Shift Backward Arrow (<CSI>V)
act->addDefaultInputMapping("JOY_LEFT");
gameKeyMap->addAction(act);
act = new Action("MOVEBACKWARD", _("Move backward"));
act->setCustomEngineActionEvent(kActionMoveBackward);
act->addDefaultInputMapping("KP2"); // Numeric pad 2 Atari ST: Code = 0x5000
act->addDefaultInputMapping("s"); // Added for convenience
act->addDefaultInputMapping("S+s"); // Added for convenience
act->addDefaultInputMapping("DOWN"); // Down Arrow (<CSI>B)
act->addDefaultInputMapping("S+DOWN"); // Shift Down Arrow (<CSI>S)
act->addDefaultInputMapping("JOY_DOWN");
gameKeyMap->addAction(act);
act = new Action("MOVERIGHT", _("Strafe right"));
act->setCustomEngineActionEvent(kActionMoveRight);
act->addDefaultInputMapping("KP3"); // Numeric pad 3 Atari ST: Code = 0x4D00.
act->addDefaultInputMapping("d"); // Added for convenience
act->addDefaultInputMapping("S+d"); // Added for convenience
act->addDefaultInputMapping("RIGHT"); // Forward Arrow (<CSI>C)
act->addDefaultInputMapping("S+RIGHT"); // Shift Forward Arrow (<CSI>U)
act->addDefaultInputMapping("JOY_RIGHT");
gameKeyMap->addAction(act);
// I18N: (Game name: Dungeon Master) The player has a team of 4 characters called "champions" which they choose themselves. The champions can be put to sleep. This action wakes up the sleeping champion.
act = new Action("WAKEUPCHAMPION", _("Wake up champion"));
act->setCustomEngineActionEvent(kActionWakeUp);
act->addDefaultInputMapping("RETURN");
gameKeyMap->addAction(act);
KeymapArray keymaps(3);
keymaps[0] = engineKeyMap;
keymaps[1] = choiceSelectionKeyMap;
keymaps[2] = gameKeyMap;
choiceSelectionKeyMap->setEnabled(false);
return keymaps;
}
} // End of namespace DM
#if PLUGIN_ENABLED_DYNAMIC(DM)
REGISTER_PLUGIN_DYNAMIC(DM, PLUGIN_TYPE_ENGINE, DM::DMMetaEngine);
#else
REGISTER_PLUGIN_STATIC(DM, PLUGIN_TYPE_ENGINE, DM::DMMetaEngine);
#endif

64
engines/dm/module.mk Normal file
View File

@@ -0,0 +1,64 @@
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
#
#
#
# Based on the Reverse Engineering work of Christophe Fontanel,
# maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
#
MODULE := engines/dm
MODULE_OBJS := \
champion.o \
console.o \
dialog.o \
dm.o \
dmglobals.o \
dungeonman.o \
eventman.o \
gfx.o \
group.o \
inventory.o \
loadsave.o \
lzw.o \
menus.o \
metaengine.o \
movesens.o \
objectman.o \
projexpl.o \
sounds.o \
text.o \
timeline.o
MODULE_DIRS += \
engines/dm
# This module can be built as a plugin
ifeq ($(ENABLE_DM), DYNAMIC_PLUGIN)
PLUGIN := 1
endif
# Include common rules
include $(srcdir)/rules.mk
# Detection objects
DETECT_OBJS += $(MODULE)/detection.o

1027
engines/dm/movesens.cpp Normal file

File diff suppressed because it is too large Load Diff

80
engines/dm/movesens.h Normal file
View File

@@ -0,0 +1,80 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_MOVESENS_H
#define DM_MOVESENS_H
#include "dm/dm.h"
#include "dm/group.h"
enum SensorEffect {
kDMSensorEffectNone = -1, // @ CM1_EFFECT_NONE
kDMSensorEffectSet = 0, // @ C00_EFFECT_SET
kDMSensorEffectClear = 1, // @ C01_EFFECT_CLEAR
kDMSensorEffectToggle = 2, // @ C02_EFFECT_TOGGLE
kDMSensorEffectHold = 3, // @ C03_EFFECT_HOLD
kDMSensorEffectAddExperience = 10 // @ C10_EFFECT_ADD_EXPERIENCE
};
namespace DM {
class Sensor;
class Teleporter;
class MovesensMan {
DMEngine *_vm;
public:
explicit MovesensMan(DMEngine *vm);
int16 _moveResultMapX; // @ G0397_i_MoveResultMapX
int16 _moveResultMapY; // @ G0398_i_MoveResultMapY
uint16 _moveResultMapIndex; // @ G0399_ui_MoveResultMapIndex
int16 _moveResultDir; // @ G0400_i_MoveResultDirection
uint16 _moveResultCell; // @ G0401_ui_MoveResultCell
bool _useRopeToClimbDownPit; // @ G0402_B_UseRopeToClimbDownPit
int16 _sensorRotationEffect; // @ G0403_i_SensorRotationEffect
int16 _sensorRotationEffMapX; // @ G0404_i_SensorRotationEffectMapX
int16 _sensorRotationEffMapY; // @ G0405_i_SensorRotationEffectMapY
int16 _sensorRotationEffCell; // @ G0406_i_SensorRotationEffectCell
bool sensorIsTriggeredByClickOnWall(int16 mapX, int16 mapY, uint16 cellParam); // @ F0275_SENSOR_IsTriggeredByClickOnWall
bool getMoveResult(Thing thing, int16 mapX, int16 mapY, int16 destMapX, int16 destMapY); // @ F0267_MOVE_GetMoveResult_CPSCE
bool isLevitating(Thing thing); // @ F0264_MOVE_IsLevitating
bool moveIsKilledByProjectileImpact(int16 srcMapX, int16 srcMapY, int16 destMapX, int16 destMapY, Thing thing); // @ F0266_MOVE_IsKilledByProjectileImpact
void addEvent(TimelineEventType type, byte mapX, byte mapY, Cell cell, SensorEffect effect, int32 time); // @ F0268_SENSOR_AddEvent
int16 getSound(CreatureType creatureType); // @ F0514_MOVE_GetSound
int16 getTeleporterRotatedGroupResult(Teleporter *teleporter, Thing thing, uint16 mapIndex);// @ F0262_MOVE_GetTeleporterRotatedGroupResult
Thing getTeleporterRotatedProjectileThing(Teleporter *teleporter, Thing projectileThing); // @ F0263_MOVE_GetTeleporterRotatedProjectileThing
void processThingAdditionOrRemoval(uint16 mapX, uint16 mapY, Thing thing, bool partySquare, bool addThing);// @ F0276_SENSOR_ProcessThingAdditionOrRemoval
bool isObjectInPartyPossession(int16 objectType); // @ F0274_SENSOR_IsObjectInPartyPossession
void triggerEffect(Sensor *sensor, SensorEffect effect, int16 mapX, int16 mapY, uint16 cell); // @ F0272_SENSOR_TriggerEffect
void triggerLocalEffect(SensorEffect localEffect, int16 effX, int16 effY, int16 effCell); // @ F0270_SENSOR_TriggerLocalEffect
void addSkillExperience(int16 skillIndex, uint16 exp, bool leaderOnly); // @ F0269_SENSOR_AddSkillExperience
void processRotationEffect();// @ F0271_SENSOR_ProcessRotationEffect
void createEventMoveGroup(Thing groupThing, int16 mapX, int16 mapY, int16 mapIndex, bool audible); // @ F0265_MOVE_CreateEvent60To61_MoveGroup
Thing getObjectOfTypeInCell(int16 mapX, int16 mapY, int16 cell, int16 objectType); // @ F0273_SENSOR_GetObjectOfTypeInCell
};
}
#endif

279
engines/dm/objectman.cpp Normal file
View File

@@ -0,0 +1,279 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#include "dm/objectman.h"
#include "dm/dungeonman.h"
#include "dm/text.h"
namespace DM {
void ObjectMan::initConstants() {
int16 iconGraphicHeight[7] = {32, 32, 32, 32, 32, 32, 32}; // @ K0077_ai_IconGraphicHeight
int16 iconGraphicFirstIndex[7] = { // G0026_ai_Graphic562_IconGraphicFirstIconIndex
0, /* First icon index in graphic #42 */
32, /* First icon index in graphic #43 */
64, /* First icon index in graphic #44 */
96, /* First icon index in graphic #45 */
128, /* First icon index in graphic #46 */
160, /* First icon index in graphic #47 */
192 /* First icon index in graphic #48 */
};
/* 8 for champion hands in status boxes, 30 for champion inventory, 8 for chest */
_slotBoxes[0] = SlotBox(4, 10, 0); /* Champion Status Box 0 Ready Hand */
_slotBoxes[1] = SlotBox(24, 10, 0); /* Champion Status Box 0 Action Hand */
_slotBoxes[2] = SlotBox(73, 10, 0); /* Champion Status Box 1 Ready Hand */
_slotBoxes[3] = SlotBox(93, 10, 0); /* Champion Status Box 1 Action Hand */
_slotBoxes[4] = SlotBox(142, 10, 0); /* Champion Status Box 2 Ready Hand */
_slotBoxes[5] = SlotBox(162, 10, 0); /* Champion Status Box 2 Action Hand */
_slotBoxes[6] = SlotBox(211, 10, 0); /* Champion Status Box 3 Ready Hand */
_slotBoxes[7] = SlotBox(231, 10, 0); /* Champion Status Box 3 Action Hand */
_slotBoxes[8] = SlotBox(6, 53, 0); /* Ready Hand */
_slotBoxes[9] = SlotBox(62, 53, 0); /* Action Hand */
_slotBoxes[10] = SlotBox(34, 26, 0); /* Head */
_slotBoxes[11] = SlotBox(34, 46, 0); /* Torso */
_slotBoxes[12] = SlotBox(34, 66, 0); /* Legs */
_slotBoxes[13] = SlotBox(34, 86, 0); /* Feet */
_slotBoxes[14] = SlotBox(6, 90, 0); /* Pouch 2 */
_slotBoxes[15] = SlotBox(79, 73, 0); /* Quiver Line2 1 */
_slotBoxes[16] = SlotBox(62, 90, 0); /* Quiver Line1 2 */
_slotBoxes[17] = SlotBox(79, 90, 0); /* Quiver Line2 2 */
_slotBoxes[18] = SlotBox(6, 33, 0); /* Neck */
_slotBoxes[19] = SlotBox(6, 73, 0); /* Pouch 1 */
_slotBoxes[20] = SlotBox(62, 73, 0); /* Quiver Line1 1 */
_slotBoxes[21] = SlotBox(66, 33, 0); /* Backpack Line1 1 */
_slotBoxes[22] = SlotBox(83, 16, 0); /* Backpack Line2 2 */
_slotBoxes[23] = SlotBox(100, 16, 0); /* Backpack Line2 3 */
_slotBoxes[24] = SlotBox(117, 16, 0); /* Backpack Line2 4 */
_slotBoxes[25] = SlotBox(134, 16, 0); /* Backpack Line2 5 */
_slotBoxes[26] = SlotBox(151, 16, 0); /* Backpack Line2 6 */
_slotBoxes[27] = SlotBox(168, 16, 0); /* Backpack Line2 7 */
_slotBoxes[28] = SlotBox(185, 16, 0); /* Backpack Line2 8 */
_slotBoxes[29] = SlotBox(202, 16, 0); /* Backpack Line2 9 */
_slotBoxes[30] = SlotBox(83, 33, 0); /* Backpack Line1 2 */
_slotBoxes[31] = SlotBox(100, 33, 0); /* Backpack Line1 3 */
_slotBoxes[32] = SlotBox(117, 33, 0); /* Backpack Line1 4 */
_slotBoxes[33] = SlotBox(134, 33, 0); /* Backpack Line1 5 */
_slotBoxes[34] = SlotBox(151, 33, 0); /* Backpack Line1 6 */
_slotBoxes[35] = SlotBox(168, 33, 0); /* Backpack Line1 7 */
_slotBoxes[36] = SlotBox(185, 33, 0); /* Backpack Line1 8 */
_slotBoxes[37] = SlotBox(202, 33, 0); /* Backpack Line1 9 */
_slotBoxes[38] = SlotBox(117, 59, 0); /* Chest 1 */
_slotBoxes[39] = SlotBox(106, 76, 0); /* Chest 2 */
_slotBoxes[40] = SlotBox(111, 93, 0); /* Chest 3 */
_slotBoxes[41] = SlotBox(128, 98, 0); /* Chest 4 */
_slotBoxes[42] = SlotBox(145, 101, 0); /* Chest 5 */
_slotBoxes[43] = SlotBox(162, 103, 0); /* Chest 6 */
_slotBoxes[44] = SlotBox(179, 104, 0); /* Chest 7 */
_slotBoxes[45] = SlotBox(196, 105, 0); /* Chest 8 */
for (int i = 0; i < 7; i++) {
_iconGraphicHeight[i] = iconGraphicHeight[i];
_iconGraphicFirstIndex[i] = iconGraphicFirstIndex[i];
}
}
ObjectMan::ObjectMan(DMEngine *vm) : _vm(vm) {
for (uint16 i = 0; i < kDMObjectNameCount; ++i)
_objectNames[i] = nullptr;
_objectIconForMousePointer = nullptr;
initConstants();
}
ObjectMan::~ObjectMan() {
delete[] _objectIconForMousePointer;
delete[] _objectNames[0];
}
void ObjectMan::loadObjectNames() {
DisplayMan &dispMan = *_vm->_displayMan;
_objectIconForMousePointer = new byte[16 * 16];
char *objectNames = new char[dispMan.getCompressedDataSize(kDMObjectNamesGraphicIndice) + kDMObjectNameCount];
Common::MemoryReadStream stream = dispMan.getCompressedData(kDMObjectNamesGraphicIndice);
for (uint16 objNameIndex = 0; objNameIndex < kDMObjectNameCount; ++objNameIndex) {
_objectNames[objNameIndex] = objectNames;
byte tmpByte;
for (tmpByte = stream.readByte(); !(tmpByte & 0x80); tmpByte = stream.readByte()) // last char of object name has 7th bit on
*objectNames++ = tmpByte; // write while not last char
*objectNames++ = tmpByte & 0x7F; // write without the 7th bit
*objectNames++ = '\0'; // terminate string
}
}
IconIndice ObjectMan::getObjectType(Thing thing) {
if (thing == _vm->_thingNone)
return kDMIconIndiceNone;
int16 objectInfoIndex = _vm->_dungeonMan->getObjectInfoIndex(thing);
if (objectInfoIndex != -1)
objectInfoIndex = _vm->_dungeonMan->_objectInfos[objectInfoIndex]._type;
return (IconIndice)objectInfoIndex;
}
IconIndice ObjectMan::getIconIndex(Thing thing) {
static byte chargeCountToTorchType[16] = {0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3}; // @ G0029_auc_Graphic562_ChargeCountToTorchType
int16 iconIndex = getObjectType(thing);
if (iconIndex != kDMIconIndiceNone) {
if (((iconIndex < kDMIconIndiceWeaponDagger) && (iconIndex >= kDMIconIndiceJunkCompassNorth)) ||
((iconIndex >= kDMIconIndicePotionMaPotionMonPotion) && (iconIndex <= kDMIconIndicePotionWaterFlask)) ||
(iconIndex == kDMIconIndicePotionEmptyFlask)) {
Junk *junkThing = (Junk*)_vm->_dungeonMan->getThingData(thing);
switch (iconIndex) {
case kDMIconIndiceJunkCompassNorth:
iconIndex += _vm->_dungeonMan->_partyDir;
break;
case kDMIconIndiceWeaponTorchUnlit:
if (((Weapon*)junkThing)->isLit())
iconIndex += chargeCountToTorchType[((Weapon*)junkThing)->getChargeCount()];
break;
case kDMIconIndiceScrollOpen:
if (((Scroll*)junkThing)->getClosed())
iconIndex++;
break;
case kDMIconIndiceJunkWater:
case kDMIconIndiceJunkIllumuletUnequipped:
case kDMIconIndiceJunkJewelSymalUnequipped:
if (junkThing->getChargeCount())
iconIndex++;
break;
case kDMIconIndiceWeaponBoltBladeStormEmpty:
case kDMIconIndiceWeaponFlamittEmpty:
case kDMIconIndiceWeaponStormringEmpty:
case kDMIconIndiceWeaponFuryRaBladeEmpty:
case kDMIconIndiceWeaponEyeOfTimeEmpty:
case kDMIconIndiceWeaponStaffOfClawsEmpty:
if (((Weapon*)junkThing)->getChargeCount())
iconIndex++;
break;
default:
break;
}
}
}
return (IconIndice)iconIndex;
}
void ObjectMan::extractIconFromBitmap(uint16 iconIndex, byte *destBitmap) {
uint16 counter;
for (counter = 0; counter < 7; counter++) {
if (_iconGraphicFirstIndex[counter] > iconIndex)
break;
}
--counter;
byte *iconBitmap = _vm->_displayMan->getNativeBitmapOrGraphic(kDMGraphicIdxObjectIcons000To031 + counter);
iconIndex -= _iconGraphicFirstIndex[counter];
_vm->_displayMan->_useByteBoxCoordinates = true;
Box blitBox(0, 15, 0, 15);
_vm->_displayMan->blitToBitmap(iconBitmap, destBitmap, blitBox, (iconIndex & 0x000F) << 4, iconIndex & 0x0FF0, 128, 8, kDMColorNoTransparency, _iconGraphicHeight[counter], 16);
}
void ObjectMan::drawIconInSlotBox(uint16 slotBoxIndex, int16 iconIndex) {
SlotBox *slotBox = &_slotBoxes[slotBoxIndex];
slotBox->_iconIndex = iconIndex;
if (slotBox->_iconIndex == kDMIconIndiceNone)
return;
Box blitBox;
blitBox._rect.left = slotBox->_x;
blitBox._rect.right = blitBox._rect.left + 15;
blitBox._rect.top = slotBox->_y;
blitBox._rect.bottom = blitBox._rect.top + 15;
uint16 iconGraphicIndex;
for (iconGraphicIndex = 0; iconGraphicIndex < 7; iconGraphicIndex++) {
if (_iconGraphicFirstIndex[iconGraphicIndex] > iconIndex)
break;
}
iconGraphicIndex--;
byte *iconBitmap = _vm->_displayMan->getNativeBitmapOrGraphic(iconGraphicIndex + kDMGraphicIdxObjectIcons000To031);
iconIndex -= _iconGraphicFirstIndex[iconGraphicIndex];
int16 byteWidth;
byte* blitDestination;
int16 destHeight;
if (slotBoxIndex >= kDMSlotBoxInventoryFirstSlot) {
blitDestination = _vm->_displayMan->_bitmapViewport;
byteWidth = k112_byteWidthViewport;
destHeight = 136;
} else {
blitDestination = (unsigned char*)_vm->_displayMan->_bitmapScreen;
byteWidth = k160_byteWidthScreen;
destHeight = 200;
}
_vm->_displayMan->_useByteBoxCoordinates = false;
_vm->_displayMan->blitToBitmap(iconBitmap, blitDestination, blitBox, (iconIndex & 0x000F) << 4, iconIndex & 0x0FF0, k128_byteWidth, byteWidth, kDMColorNoTransparency, _iconGraphicHeight[iconGraphicIndex], destHeight);
}
void ObjectMan::drawLeaderObjectName(Thing thing) {
Common::String objectName;
int16 iconIndex = getIconIndex(thing);
if (iconIndex == kDMIconIndiceJunkChampionBones) {
Junk *junk = (Junk*)_vm->_dungeonMan->getThingData(thing);
Common::String champBonesName;
switch (_vm->getGameLanguage()) { // localized
case Common::FR_FRA:
// Fix original bug: strcpy was coming after strcat
champBonesName = Common::String(_objectNames[iconIndex]);
champBonesName += Common::String(_vm->_championMan->_champions[junk->getChargeCount()]._name);
break;
default: // English and German version are the same
champBonesName = Common::String(_vm->_championMan->_champions[junk->getChargeCount()]._name);
champBonesName += Common::String(_objectNames[iconIndex]);
break;
}
objectName = champBonesName;
} else
objectName = Common::String(_objectNames[iconIndex]);
_vm->_textMan->printWithTrailingSpaces(_vm->_displayMan->_bitmapScreen, k160_byteWidthScreen, 233, 37, kDMColorCyan, kDMColorBlack, objectName.c_str(), kDMObjectNameMaximumLength, k200_heightScreen);
}
IconIndice ObjectMan::getIconIndexInSlotBox(uint16 slotBoxIndex) {
return (IconIndice)_slotBoxes[slotBoxIndex]._iconIndex;
}
void ObjectMan::clearLeaderObjectName() {
static Box boxLeaderHandObjectName(233, 319, 33, 38); // @ G0028_s_Graphic562_Box_LeaderHandObjectName
_vm->_displayMan->fillScreenBox(boxLeaderHandObjectName, kDMColorBlack);
}
void ObjectMan::drawIconToScreen(int16 iconIndex, int16 posX, int16 posY) {
static byte iconBitmap[16 * 16];
Box blitBox(posX, posX + 15, posY, posY + 15);
extractIconFromBitmap(iconIndex, iconBitmap);
_vm->_displayMan->blitToScreen(iconBitmap, &blitBox, k8_byteWidth, kDMColorNoTransparency, 16);
}
}

76
engines/dm/objectman.h Normal file
View File

@@ -0,0 +1,76 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_OBJECTMAN_H
#define DM_OBJECTMAN_H
#include "dm/dm.h"
#include "dm/champion.h"
namespace DM {
#define kDMObjectNameMaximumLength 14 // @ C014_OBJECT_NAME_MAXIMUM_LENGTH
#define kDMObjectNameCount 199 // @ C199_OBJECT_NAME_COUNT
#define kDMObjectNamesGraphicIndice 556 // @ C556_GRAPHIC_OBJECT_NAMES
class SlotBox {
public:
int16 _x;
int16 _y;
int16 _iconIndex;
SlotBox(int16 x, int16 y, int16 iconIndex): _x(x), _y(y), _iconIndex(iconIndex) {}
SlotBox(): _x(-1), _y(-1), _iconIndex(-1) {}
}; // @ SLOT_BOX
class ObjectMan {
DMEngine *_vm;
public:
explicit ObjectMan(DMEngine *vm);
~ObjectMan();
void loadObjectNames(); // @ F0031_OBJECT_LoadNames
SlotBox _slotBoxes[46]; // @ G0030_as_Graphic562_SlotBoxes;
char *_objectNames[kDMObjectNameCount]; // @ G0352_apc_ObjectNames
byte *_objectIconForMousePointer; // @ G0412_puc_Bitmap_ObjectIconForMousePointer
IconIndice getObjectType(Thing thing); // @ F0032_OBJECT_GetType
IconIndice getIconIndex(Thing thing); // @ F0033_OBJECT_GetIconIndex
void extractIconFromBitmap(uint16 iconIndex, byte *destBitmap); // @ F0036_OBJECT_ExtractIconFromBitmap
void drawIconInSlotBox(uint16 slotBoxIndex, int16 iconIndex); // @ F0038_OBJECT_DrawIconInSlotBox
void drawLeaderObjectName(Thing thing); // @ F0034_OBJECT_DrawLeaderHandObjectName
IconIndice getIconIndexInSlotBox(uint16 slotBoxIndex); // @ F0039_OBJECT_GetIconIndexInSlotBox
void clearLeaderObjectName(); // @ F0035_OBJECT_ClearLeaderHandObjectName
void drawIconToScreen(int16 iconIndex, int16 posX, int16 posY); // @ F0037_OBJECT_DrawIconToScreen
int16 _iconGraphicHeight[7]; // @ K0077_ai_IconGraphicHeight
int16 _iconGraphicFirstIndex[7]; // G0026_ai_Graphic562_IconGraphicFirstIconIndex
void initConstants();
};
}
#endif

567
engines/dm/projexpl.cpp Normal file
View File

@@ -0,0 +1,567 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#include "dm/projexpl.h"
#include "dm/dungeonman.h"
#include "dm/timeline.h"
#include "dm/group.h"
#include "dm/objectman.h"
#include "dm/movesens.h"
#include "dm/sounds.h"
namespace DM {
ProjExpl::ProjExpl(DMEngine *vm) : _vm(vm) {
_creatureDamageOutcome = 0;
_secondaryDirToOrFromParty = 0;
_lastCreatureAttackTime = -200;
_createLauncherProjectile = false;
_projectilePoisonAttack = 0;
_projectileAttackType = 0;
_lastPartyMovementTime = 0;
}
void ProjExpl::createProjectile(Thing thing, int16 mapX, int16 mapY, uint16 cell, Direction dir, byte kineticEnergy, byte attack, byte stepEnergy) {
Thing projectileThing = _vm->_dungeonMan->getUnusedThing(kDMThingTypeProjectile);
if (projectileThing == _vm->_thingNone) /* BUG0_16 If the game cannot create a projectile thing because it has run out of such things (60 maximum) then the object being thrown/shot/launched is orphaned. If the game has run out of projectile things it will try to remove a projectile from elsewhere in the dungeon, except in an area of 11x11 squares centered around the party (to make sure the player cannot actually see the thing disappear on screen) */
return;
projectileThing = _vm->thingWithNewCell(projectileThing, cell);
Projectile *projectilePtr = (Projectile *)_vm->_dungeonMan->getThingData(projectileThing);
projectilePtr->_slot = thing;
projectilePtr->_kineticEnergy = MIN((int16)kineticEnergy, (int16)255);
projectilePtr->_attack = attack;
_vm->_dungeonMan->linkThingToList(projectileThing, Thing(0), mapX, mapY); /* Projectiles are added on the square and not 'moved' onto the square. In the case of a projectile launcher sensor, this means that the new projectile traverses the square in front of the launcher without any trouble: there is no impact if it is a wall, the projectile direction is not changed if it is a teleporter. Impacts with creatures and champions are still processed */
TimelineEvent newEvent;
newEvent._mapTime = _vm->setMapAndTime(_vm->_dungeonMan->_currMapIndex, _vm->_gameTime + 1);
if (_createLauncherProjectile)
newEvent._type = kDMEventTypeMoveProjectile; /* Launcher projectiles can impact immediately */
else
newEvent._type = kDMEventTypeMoveProjectileIgnoreImpacts; /* Projectiles created by champions or creatures ignore impacts on their first movement */
newEvent._priority = 0;
newEvent._Bu._slot = projectileThing.toUint16();
newEvent._Cu._projectile.setMapX(mapX);
newEvent._Cu._projectile.setMapY(mapY);
newEvent._Cu._projectile.setStepEnergy(stepEnergy);
newEvent._Cu._projectile.setDir(dir);
projectilePtr->_eventIndex = _vm->_timeline->addEventGetEventIndex(&newEvent);
}
bool ProjExpl::hasProjectileImpactOccurred(int16 impactType, int16 mapXCombo, int16 mapYCombo, int16 cell, Thing projectileThing) {
Projectile *projectileThingData = (Projectile *)_vm->_dungeonMan->getThingData(Thing(projectileThing));
bool removePotion = false;
int16 potionPower = 0;
_creatureDamageOutcome = kDMKillOutcomeNoCreaturesInGroup;
Thing projectileAssociatedThing = projectileThingData->_slot;
int16 projectileAssociatedThingType = projectileAssociatedThing.getType();
Potion *potion = nullptr;
Thing explosionThing = _vm->_thingNone;
if (projectileAssociatedThingType == kDMThingTypePotion) {
Group *projectileAssociatedGroup = (Group *)_vm->_dungeonMan->getThingData(projectileAssociatedThing);
PotionType potionType = ((Potion *)projectileAssociatedGroup)->getType();
if ((potionType == kDMPotionTypeVen) || (potionType == kDMPotionTypeFulBomb)) {
explosionThing = (potionType == kDMPotionTypeVen) ? _vm->_thingExplPoisonCloud: _vm->_thingExplFireBall;
removePotion = true;
potionPower = ((Potion *)projectileAssociatedGroup)->getPower();
potion = (Potion *)projectileAssociatedGroup;
}
}
bool createExplosionOnImpact = (projectileAssociatedThingType == kDMThingTypeExplosion) && (projectileAssociatedThing != _vm->_thingExplSlime) && (projectileAssociatedThing != _vm->_thingExplPoisonBolt);
Thing *curGroupSlot = nullptr;
int16 projectileMapX;
int16 projectileMapY;
int16 projectileTargetMapX = mapXCombo;
int16 projectileTargetMapY = mapYCombo;
if (mapXCombo <= 255) {
projectileMapX = mapXCombo;
projectileMapY = mapYCombo;
} else {
projectileMapX = (mapXCombo >> 8) - 1;
projectileMapY = (mapYCombo >> 8);
projectileTargetMapX &= 0x00FF;
projectileTargetMapY &= 0x00FF;
}
int16 championAttack = 0;
int16 attack = 0;
int16 championIndex = 0;
switch (impactType) {
case kDMElementTypeDoor: {
byte curSquare = _vm->_dungeonMan->_currMapData[projectileTargetMapX][projectileTargetMapY];
int16 curDoorState = Square(curSquare).getDoorState();
Door *curDoor = (Door *)_vm->_dungeonMan->getSquareFirstThingData(projectileTargetMapX, projectileTargetMapY);
if ((curDoorState != kDMDoorStateDestroyed) && (projectileAssociatedThing == _vm->_thingExplOpenDoor)) {
if (curDoor->hasButton())
_vm->_moveSens->addEvent(kDMEventTypeDoor, projectileTargetMapX, projectileTargetMapY, kDMCellNorthWest, kDMSensorEffectToggle, _vm->_gameTime + 1);
break;
}
if ((curDoorState == kDMDoorStateDestroyed) || (curDoorState <= kDMDoorStateOneFourth))
return false;
DoorInfo curDoorInfo = _vm->_dungeonMan->_currMapDoorInfo[curDoor->getType()];
if (getFlag(curDoorInfo._attributes, kDMMaskDoorInfoProjectilesCanPassThrough)) {
if (projectileAssociatedThingType == kDMThingTypeExplosion) {
if (projectileAssociatedThing.toUint16() >= _vm->_thingExplHarmNonMaterial.toUint16())
return false;
} else {
int16 associatedThingIndex = _vm->_dungeonMan->getObjectInfoIndex(projectileAssociatedThing);
uint16 associatedAllowedSlots = _vm->_dungeonMan->_objectInfos[associatedThingIndex].getAllowedSlots();
int16 iconIndex = _vm->_objectMan->getIconIndex(projectileAssociatedThing);
if ((projectileThingData->_attack > _vm->getRandomNumber(128))
&& getFlag(associatedAllowedSlots, kDMMaskPouchPassAndThroughDoors)
&& ( (projectileAssociatedThingType != kDMThingTypeJunk)
|| (iconIndex < kDMIconIndiceJunkIronKey)
|| (iconIndex > kDMIconIndiceJunkMasterKey)
)) {
return false;
}
}
}
attack = getProjectileImpactAttack(projectileThingData, projectileAssociatedThing) + 1;
_vm->_groupMan->groupIsDoorDestoryedByAttack(projectileTargetMapX, projectileTargetMapY, attack + _vm->getRandomNumber(attack), false, 0);
}
break;
case kDMElementTypeChampion:
championIndex = _vm->_championMan->getIndexInCell(cell);
if (championIndex < 0)
return false;
championAttack = attack = getProjectileImpactAttack(projectileThingData, projectileAssociatedThing);
break;
case kDMElementTypeCreature: {
Group *curGroup = (Group *)_vm->_dungeonMan->getThingData(_vm->_groupMan->groupGetThing(projectileTargetMapX, projectileTargetMapY));
uint16 curCreatureIndex = _vm->_groupMan->getCreatureOrdinalInCell(curGroup, cell);
if (!curCreatureIndex)
return false;
curCreatureIndex--;
CreatureType curCreatureType = curGroup->_type;
CreatureInfo *curCreatureInfo = &_vm->_dungeonMan->_creatureInfos[curCreatureType];
if ((projectileAssociatedThing == _vm->_thingExplFireBall) && (curCreatureType == kDMCreatureTypeBlackFlame)) {
uint16 *curCreatureHealth = &curGroup->_health[curCreatureIndex];
*curCreatureHealth = MIN(1000, *curCreatureHealth + getProjectileImpactAttack(projectileThingData, projectileAssociatedThing));
goto T0217044;
}
if (getFlag(curCreatureInfo->_attributes, kDMCreatureMaskNonMaterial) && (projectileAssociatedThing != _vm->_thingExplHarmNonMaterial))
return false;
attack = (uint16)((unsigned long)getProjectileImpactAttack(projectileThingData, projectileAssociatedThing) << 6) / curCreatureInfo->_defense;
if (attack) {
int16 outcome = _vm->_groupMan->groupGetDamageCreatureOutcome(curGroup, curCreatureIndex, projectileTargetMapX, projectileTargetMapY, attack + _vm->_groupMan->groupGetResistanceAdjustedPoisonAttack(curCreatureType, _projectilePoisonAttack), true);
if (outcome != kDMKillOutcomeNoCreaturesInGroup)
_vm->_groupMan->processEvents29to41(projectileTargetMapX, projectileTargetMapY, kDMEventTypeCreateReactionHitByProjectile, 0);
_creatureDamageOutcome = outcome;
if (!createExplosionOnImpact && (outcome == kDMKillOutcomeNoCreaturesInGroup)
&& (projectileAssociatedThingType == kDMThingTypeWeapon)
&& getFlag(curCreatureInfo->_attributes, kDMCreatureMaskKeepThrownSharpWeapon)) {
Weapon *weapon = (Weapon *)_vm->_dungeonMan->getThingData(projectileAssociatedThing);
WeaponType weaponType = weapon->getType();
if ((weaponType == kDMWeaponDagger) || (weaponType == kDMWeaponArrow)
|| (weaponType == kDMWeaponSlayer) || (weaponType == kDMWeaponPoisonDart)
|| (weaponType == kDMWeaponThrowingStar))
curGroupSlot = &curGroup->_slot;
}
}
}
break;
default:
break;
}
if (championAttack && _projectilePoisonAttack && _vm->getRandomNumber(2)
&& _vm->_championMan->addPendingDamageAndWounds_getDamage(championIndex, attack, kDMWoundHead | kDMWoundTorso, _projectileAttackType))
_vm->_championMan->championPoison(championIndex, _projectilePoisonAttack);
if (createExplosionOnImpact || removePotion) {
uint16 explosionAttack;
if (removePotion) {
projectileAssociatedThing = explosionThing;
explosionAttack = potionPower;
} else {
explosionAttack = projectileThingData->_kineticEnergy;
}
if ((projectileAssociatedThing == _vm->_thingExplLightningBolt) && !(explosionAttack >>= 1))
goto T0217044;
createExplosion(projectileAssociatedThing, explosionAttack, mapXCombo, mapYCombo, (projectileAssociatedThing == _vm->_thingExplPoisonCloud) ? (uint16)kDMCreatureTypeSingleCenteredCreature : cell);
} else {
uint16 soundIndex;
if ((projectileAssociatedThing).getType() == kDMThingTypeWeapon)
soundIndex = kDMSoundIndexMetallicThud;
else if (projectileAssociatedThing == _vm->_thingExplPoisonBolt)
soundIndex = kDMSoundIndexSpell;
else
soundIndex = kDMSoundIndexWoodenThudAttackTrolinAntmanStoneGolem;
_vm->_sound->requestPlay(soundIndex, projectileMapX, projectileMapY, kDMSoundModePlayIfPrioritized);
}
T0217044:
if (removePotion) {
potion->_nextThing = _vm->_thingNone;
projectileThingData->_slot = explosionThing;
}
_vm->_dungeonMan->unlinkThingFromList(projectileThing, Thing(0), projectileMapX, projectileMapY);
projectileDelete(projectileThing, curGroupSlot, projectileMapX, projectileMapY);
return true;
}
uint16 ProjExpl::getProjectileImpactAttack(Projectile *projectile, Thing thing) {
_projectilePoisonAttack = 0;
_projectileAttackType = kDMAttackTypeBlunt;
uint16 kineticEnergy = projectile->_kineticEnergy;
ThingType thingType = thing.getType();
uint16 attack;
if (thingType != kDMThingTypeExplosion) {
if (thingType == kDMThingTypeWeapon) {
WeaponInfo *weaponInfo = _vm->_dungeonMan->getWeaponInfo(thing);
attack = weaponInfo->_kineticEnergy;
_projectileAttackType = kDMAttackTypeBlunt;
} else
attack = _vm->getRandomNumber(4);
attack += _vm->_dungeonMan->getObjectWeight(thing) >> 1;
} else if (thing == _vm->_thingExplSlime) {
attack = _vm->getRandomNumber(16);
_projectilePoisonAttack = attack + 10;
attack += _vm->getRandomNumber(32);
} else {
if (thing.toUint16() >= _vm->_thingExplHarmNonMaterial.toUint16()) {
_projectileAttackType = kDMAttackTypeMagic;
if (thing == _vm->_thingExplPoisonBolt) {
_projectilePoisonAttack = kineticEnergy;
return 1;
}
return 0;
}
_projectileAttackType = kDMAttackTypeFire;
attack = _vm->getRandomNumber(16) + _vm->getRandomNumber(16) + 10;
if (thing == _vm->_thingExplLightningBolt) {
_projectileAttackType = kDMAttackTypeLightning;
attack *= 5;
}
}
attack = ((attack + kineticEnergy) >> 4) + 1;
attack += _vm->getRandomNumber((attack >> 1) + 1) + _vm->getRandomNumber(4);
attack = MAX(attack >> 1, attack - (32 - (projectile->_attack >> 3)));
return attack;
}
void ProjExpl::createExplosion(Thing explThing, uint16 attack, uint16 mapXCombo, uint16 mapYCombo, uint16 cell) {
Thing unusedThing = _vm->_dungeonMan->getUnusedThing(kDMThingTypeExplosion);
if (unusedThing == _vm->_thingNone)
return;
Explosion *explosion = &((Explosion *)_vm->_dungeonMan->_thingData[kDMThingTypeExplosion])[(unusedThing).getIndex()];
int16 projectileTargetMapX;
int16 projectileTargetMapY;
uint16 projectileMapX = mapXCombo;
uint16 projectileMapY = mapYCombo;
if (mapXCombo <= 255) {
projectileTargetMapX = mapXCombo;
projectileTargetMapY = mapYCombo;
} else {
projectileTargetMapX = mapXCombo & 0x00FF;
projectileTargetMapY = mapYCombo & 0x00FF;
projectileMapX >>= 8;
projectileMapX--;
projectileMapY >>= 8;
}
if (cell == kDMCreatureTypeSingleCenteredCreature)
explosion->setCentered(true);
else {
explosion->setCentered(false);
unusedThing = _vm->thingWithNewCell(unusedThing, cell);
}
explosion->setType(explThing.toUint16() - _vm->_thingFirstExplosion.toUint16());
explosion->setAttack(attack);
if (explThing.toUint16() < _vm->_thingExplHarmNonMaterial.toUint16()) {
uint16 soundIndex = (attack > 80) ? kDMSoundIndexStrongExplosion : kDMSoundIndexWeakExplosion;
_vm->_sound->requestPlay(soundIndex, projectileMapX, projectileMapY, kDMSoundModePlayIfPrioritized);
} else if (explThing != _vm->_thingExplSmoke)
_vm->_sound->requestPlay(kDMSoundIndexSpell, projectileMapX, projectileMapY, kDMSoundModePlayIfPrioritized);
_vm->_dungeonMan->linkThingToList(unusedThing, Thing(0), projectileMapX, projectileMapY);
TimelineEvent newEvent;
newEvent._mapTime = _vm->setMapAndTime(_vm->_dungeonMan->_currMapIndex, _vm->_gameTime + ((explThing == _vm->_thingExplRebirthStep1) ? 5 : 1));
newEvent._type = kDMEventTypeExplosion;
newEvent._priority = 0;
newEvent._Cu._slot = unusedThing.toUint16();
newEvent._Bu._location._mapX = projectileMapX;
newEvent._Bu._location._mapY = projectileMapY;
_vm->_timeline->addEventGetEventIndex(&newEvent);
if ((explThing == _vm->_thingExplLightningBolt) || (explThing == _vm->_thingExplFireBall)) {
projectileMapX = projectileTargetMapX;
projectileMapY = projectileTargetMapY;
attack = (attack >> 1) + 1;
attack += _vm->getRandomNumber(attack) + 1;
if ((explThing == _vm->_thingExplFireBall) || (attack >>= 1)) {
if ((_vm->_dungeonMan->_currMapIndex == _vm->_dungeonMan->_partyMapIndex) && (projectileMapX == _vm->_dungeonMan->_partyMapX) && (projectileMapY == _vm->_dungeonMan->_partyMapY)) {
int16 wounds = kDMWoundReadHand | kDMWoundActionHand | kDMWoundHead | kDMWoundTorso | kDMWoundLegs | kDMWoundFeet;
_vm->_championMan->getDamagedChampionCount(attack, wounds, kDMAttackTypeFire);
} else {
unusedThing = _vm->_groupMan->groupGetThing(projectileMapX, projectileMapY);
if (unusedThing != _vm->_thingEndOfList) {
Group *creatureGroup = (Group *)_vm->_dungeonMan->getThingData(unusedThing);
CreatureInfo *creatureInfo = &_vm->_dungeonMan->_creatureInfos[creatureGroup->_type];
int16 creatureFireResistance = creatureInfo->getFireResistance();
if (creatureFireResistance != kDMImmuneToFire) {
if (getFlag(creatureInfo->_attributes, kDMCreatureMaskNonMaterial))
attack >>= 2;
if ((attack -= _vm->getRandomNumber((creatureFireResistance << 1) + 1)) > 0)
_creatureDamageOutcome = _vm->_groupMan->getDamageAllCreaturesOutcome(creatureGroup, projectileMapX, projectileMapY, attack, true);
}
}
}
}
}
}
int16 ProjExpl::projectileGetImpactCount(int16 impactType, int16 mapX, int16 mapY, int16 cell) {
int16 impactCount = 0;
_creatureDamageOutcome = kDMKillOutcomeNoCreaturesInGroup;
for (Thing curThing = _vm->_dungeonMan->getSquareFirstThing(mapX, mapY); curThing != _vm->_thingEndOfList; ) {
if (((curThing).getType() == kDMThingTypeProjectile) && ((curThing).getCell() == cell) &&
hasProjectileImpactOccurred(impactType, mapX, mapY, cell, curThing)) {
projectileDeleteEvent(curThing);
impactCount++;
if ((impactType == kDMElementTypeCreature) && (_creatureDamageOutcome == kDMKillOutcomeAllCreaturesInGroup))
break;
curThing = _vm->_dungeonMan->getSquareFirstThing(mapX, mapY);
} else
curThing = _vm->_dungeonMan->getNextThing(curThing);
}
return impactCount;
}
void ProjExpl::projectileDeleteEvent(Thing thing) {
Projectile *projectile = (Projectile *)_vm->_dungeonMan->getThingData(thing);
_vm->_timeline->deleteEvent(projectile->_eventIndex);
}
void ProjExpl::projectileDelete(Thing projectileThing, Thing *groupSlot, int16 mapX, int16 mapY) {
Projectile *projectile = (Projectile *)_vm->_dungeonMan->getThingData(projectileThing);
Thing projectileSlotThing = projectile->_slot;
if (projectileSlotThing.getType() != kDMThingTypeExplosion) {
if (groupSlot != nullptr) {
Thing previousThing = *groupSlot;
if (previousThing == _vm->_thingEndOfList) {
Thing *genericThing = (Thing *)_vm->_dungeonMan->getThingData(projectileSlotThing);
*genericThing = _vm->_thingEndOfList;
*groupSlot = projectileSlotThing;
} else
_vm->_dungeonMan->linkThingToList(projectileSlotThing, previousThing, kDMMapXNotOnASquare, 0);
} else
_vm->_moveSens->getMoveResult(Thing((projectileSlotThing).getTypeAndIndex() | getFlag(projectileThing.toUint16(), 0xC)), -2, 0, mapX, mapY);
}
projectile->_nextThing = _vm->_thingNone;
}
void ProjExpl::processEvents48To49(TimelineEvent *event) {
int16 sourceMapX = -1;
int16 sourceMapY = -1;
TimelineEvent firstEvent = *event;
TimelineEvent *curEvent = &firstEvent;
Thing projectileThingNewCell = Thing(curEvent->_Bu._slot);
Thing projectileThing = projectileThingNewCell;
Projectile *projectile = (Projectile *)_vm->_dungeonMan->getThingData(projectileThing);
int16 destinationMapX = curEvent->_Cu._projectile.getMapX();
int16 destinationMapY = curEvent->_Cu._projectile.getMapY();
if (curEvent->_type == kDMEventTypeMoveProjectileIgnoreImpacts)
curEvent->_type = kDMEventTypeMoveProjectile;
else {
uint16 projectileCurCell = projectileThingNewCell.getCell();
if ((_vm->_dungeonMan->_currMapIndex == _vm->_dungeonMan->_partyMapIndex) && (destinationMapX == _vm->_dungeonMan->_partyMapX) && (destinationMapY == _vm->_dungeonMan->_partyMapY) && hasProjectileImpactOccurred(kDMElementTypeChampion, destinationMapX, destinationMapY, projectileCurCell, projectileThingNewCell))
return;
if ((_vm->_groupMan->groupGetThing(destinationMapX, destinationMapY) != _vm->_thingEndOfList) && hasProjectileImpactOccurred(kDMElementTypeCreature, destinationMapX, destinationMapY, projectileCurCell, projectileThing))
return;
uint16 stepEnergy = curEvent->_Cu._projectile.getStepEnergy();
if (projectile->_kineticEnergy <= stepEnergy) {
_vm->_dungeonMan->unlinkThingFromList(projectileThingNewCell = projectileThing, Thing(0), destinationMapX, destinationMapY);
projectileDelete(projectileThingNewCell, nullptr, destinationMapX, destinationMapY);
return;
}
projectile->_kineticEnergy -= stepEnergy;
if (projectile->_attack < stepEnergy)
projectile->_attack = 0;
else
projectile->_attack -= stepEnergy;
}
uint16 projectileDirection = curEvent->_Cu._projectile.getDir();
projectileThingNewCell = Thing(curEvent->_Bu._slot);
uint16 projectileNewCell = projectileThingNewCell.getCell();
bool projectileMovesToOtherSquare = (projectileDirection == projectileNewCell) || (_vm->turnDirRight(projectileDirection) == projectileNewCell);
if (projectileMovesToOtherSquare) {
sourceMapX = destinationMapX;
sourceMapY = destinationMapY;
destinationMapX += _vm->_dirIntoStepCountEast[projectileDirection];
destinationMapY += _vm->_dirIntoStepCountNorth[projectileDirection];
Square destSquare = _vm->_dungeonMan->getSquare(destinationMapX, destinationMapY);
ElementType destSquareType = destSquare.getType();
if ((destSquareType == kDMElementTypeWall) ||
((destSquareType == kDMElementTypeFakeWall) && !getFlag(destSquare.toByte(), (kDMSquareMaskFakeWallImaginary | kDMSquareMaskFakeWallOpen))) ||
((destSquareType == kDMElementTypeStairs) && (Square(_vm->_dungeonMan->_currMapData[sourceMapX][sourceMapY]).getType() == kDMElementTypeStairs))) {
if (hasProjectileImpactOccurred(destSquare.getType(), sourceMapX, sourceMapY, projectileNewCell, projectileThingNewCell)) {
return;
}
}
}
if ((projectileDirection & 0x0001) == (projectileNewCell & 0x0001))
projectileNewCell--;
else
projectileNewCell++;
projectileThingNewCell = _vm->thingWithNewCell(projectileThingNewCell, projectileNewCell &= 0x0003);
if (projectileMovesToOtherSquare) {
_vm->_moveSens->getMoveResult(projectileThingNewCell, sourceMapX, sourceMapY, destinationMapX, destinationMapY);
curEvent->_Cu._projectile.setMapX(_vm->_moveSens->_moveResultMapX);
curEvent->_Cu._projectile.setMapY(_vm->_moveSens->_moveResultMapY);
curEvent->_Cu._projectile.setDir((Direction)_vm->_moveSens->_moveResultDir);
projectileThingNewCell = _vm->thingWithNewCell(projectileThingNewCell, _vm->_moveSens->_moveResultCell);
_vm->setMap(curEvent->_mapTime, _vm->_moveSens->_moveResultMapIndex);
} else {
if ((Square(_vm->_dungeonMan->getSquare(destinationMapX, destinationMapY)).getType() == kDMElementTypeDoor) && hasProjectileImpactOccurred(kDMElementTypeDoor, destinationMapX, destinationMapY, projectileNewCell, projectileThing))
return;
_vm->_dungeonMan->unlinkThingFromList(projectileThingNewCell, Thing(0), destinationMapX, destinationMapY);
_vm->_dungeonMan->linkThingToList(projectileThingNewCell, Thing(0), destinationMapX, destinationMapY);
}
// This code is from CSB20. The projectiles move at the same speed on all maps instead of moving slower on maps other than the party map */
curEvent->_mapTime++;
curEvent->_Bu._slot = projectileThingNewCell.toUint16();
projectile->_eventIndex = _vm->_timeline->addEventGetEventIndex(curEvent);
}
void ProjExpl::processEvent25(TimelineEvent *event) {
uint16 mapX = event->_Bu._location._mapX;
uint16 mapY = event->_Bu._location._mapY;
Explosion *explosion = &((Explosion *)_vm->_dungeonMan->_thingData[kDMThingTypeExplosion])[Thing((event->_Cu._slot)).getIndex()];
int16 curSquareType = Square(_vm->_dungeonMan->_currMapData[mapX][mapY]).getType();
bool explosionOnPartySquare = (_vm->_dungeonMan->_currMapIndex == _vm->_dungeonMan->_partyMapIndex) && (mapX == _vm->_dungeonMan->_partyMapX) && (mapY == _vm->_dungeonMan->_partyMapY);
Thing groupThing = _vm->_groupMan->groupGetThing(mapX, mapY);
Group *group = nullptr;
CreatureInfo *creatureInfo = nullptr;
CreatureType creatureType;
creatureType = kDMCreatureTypeGiantScorpion; // Value of 0 as default to avoid possible uninitialized usage
if (groupThing != _vm->_thingEndOfList) {
group = (Group *)_vm->_dungeonMan->getThingData(groupThing);
creatureType = group->_type;
creatureInfo = &_vm->_dungeonMan->_creatureInfos[creatureType];
}
Thing explosionThing = Thing(_vm->_thingFirstExplosion.toUint16() + explosion->getType());
int16 attack;
if (explosionThing == _vm->_thingExplPoisonCloud)
attack = MAX(1, MIN(explosion->getAttack() >> 5, 4) + _vm->getRandomNumber(2)); /* Value between 1 and 5 */
else {
attack = (explosion->getAttack() >> 1) + 1;
attack += _vm->getRandomNumber(attack) + 1;
}
bool AddEventFl = false;
switch (explosionThing.toUint16()) {
case 0xFF82:
if (!(attack >>= 1))
break;
// fall through
case 0xFF80:
if (curSquareType == kDMElementTypeDoor)
_vm->_groupMan->groupIsDoorDestoryedByAttack(mapX, mapY, attack, true, 0);
break;
case 0xFF83:
if ((groupThing != _vm->_thingEndOfList) && getFlag(creatureInfo->_attributes, kDMCreatureMaskNonMaterial)) {
if ((creatureType == kDMCreatureTypeMaterializerZytaz) && (_vm->_dungeonMan->_currMapIndex == _vm->_dungeonMan->_partyMapIndex)) {
int16 nonMaterialAdditionalAttack = attack >> 3;
attack -= nonMaterialAdditionalAttack;
nonMaterialAdditionalAttack <<= 1;
nonMaterialAdditionalAttack++;
int16 creatureCount = group->getCount();
do {
if (getFlag(_vm->_groupMan->_activeGroups[group->getActiveGroupIndex()]._aspect[creatureCount], kDMAspectMaskActiveGroupIsAttacking)) /* Materializer / Zytaz can only be damaged while they are attacking */
_vm->_groupMan->groupGetDamageCreatureOutcome(group, creatureCount, mapX, mapY, attack + _vm->getRandomNumber(nonMaterialAdditionalAttack) + _vm->getRandomNumber(4), true);
} while (--creatureCount >= 0);
} else
_vm->_groupMan->getDamageAllCreaturesOutcome(group, mapX, mapY, attack, true);
}
break;
case 0xFFE4:
explosion->setType(explosion->getType() + 1);
_vm->_sound->requestPlay(kDMSoundIndexStrongExplosion, mapX, mapY, kDMSoundModePlayIfPrioritized);
AddEventFl = true;
break;
case 0xFFA8:
if (explosion->getAttack() > 55) {
explosion->setAttack(explosion->getAttack() - 40);
AddEventFl = true;
}
break;
case 0xFF87:
if (explosionOnPartySquare)
_vm->_championMan->getDamagedChampionCount(attack, kDMWoundNone, kDMAttackTypeNormal);
else if ((groupThing != _vm->_thingEndOfList)
&& (attack = _vm->_groupMan->groupGetResistanceAdjustedPoisonAttack(creatureType, attack))
&& (_vm->_groupMan->getDamageAllCreaturesOutcome(group, mapX, mapY, attack, true) != kDMKillOutcomeAllCreaturesInGroup)
&& (attack > 2)) {
_vm->_groupMan->processEvents29to41(mapX, mapY, kDMEventTypeCreateReactionDangerOnSquare, 0);
}
if (explosion->getAttack() >= 6) {
explosion->setAttack(explosion->getAttack() - 3);
AddEventFl = true;
}
break;
default:
break;
}
if (AddEventFl) {
TimelineEvent newEvent;
newEvent = *event;
newEvent._mapTime++;
_vm->_timeline->addEventGetEventIndex(&newEvent);
} else {
_vm->_dungeonMan->unlinkThingFromList(Thing(event->_Cu._slot), Thing(0), mapX, mapY);
explosion->setNextThing(_vm->_thingNone);
}
}
}

71
engines/dm/projexpl.h Normal file
View File

@@ -0,0 +1,71 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_PROJEXPL_H
#define DM_PROJEXPL_H
#include "dm/dm.h"
namespace DM {
enum KillOutcome {
kDMKillOutcomeNoCreaturesInGroup = 0, // @ C0_OUTCOME_KILLED_NO_CREATURES_IN_GROUP
kDMKillOutcomeSomeCreaturesInGroup = 1, // @ C1_OUTCOME_KILLED_SOME_CREATURES_IN_GROUP
kDMKillOutcomeAllCreaturesInGroup = 2 // @ C2_OUTCOME_KILLED_ALL_CREATURES_IN_GROUP
};
class TimelineEvent;
class Projectile;
class ProjExpl {
DMEngine *_vm;
public:
int16 _creatureDamageOutcome; // @ G0364_i_CreatureDamageOutcome
int16 _secondaryDirToOrFromParty; // @ G0363_i_SecondaryDirectionToOrFromParty
int32 _lastCreatureAttackTime; // @ G0361_l_LastCreatureAttackTime
bool _createLauncherProjectile; // @ G0365_B_CreateLauncherProjectile
int16 _projectilePoisonAttack; // @ G0366_i_ProjectilePoisonAttack
int16 _projectileAttackType; // @ G0367_i_ProjectileAttackType
int32 _lastPartyMovementTime; // @ G0362_l_LastPartyMovementTime
explicit ProjExpl(DMEngine *vm);
void createProjectile(Thing thing, int16 mapX, int16 mapY, uint16 cell, Direction dir,
byte kineticEnergy, byte attack, byte stepEnergy); // @ F0212_PROJECTILE_Create
bool hasProjectileImpactOccurred(int16 impactType, int16 mapXCombo, int16 mapYCombo,
int16 cell, Thing projectileThing); // @ F0217_PROJECTILE_HasImpactOccurred
uint16 getProjectileImpactAttack(Projectile *projectile, Thing thing); // @ F0216_PROJECTILE_GetImpactAttack
void createExplosion(Thing explThing, uint16 attack, uint16 mapXCombo,
uint16 mapYCombo, uint16 cell); // @ F0213_EXPLOSION_Create
int16 projectileGetImpactCount(int16 impactType, int16 mapX, int16 mapY, int16 cell); // @ F0218_PROJECTILE_GetImpactCount
void projectileDeleteEvent(Thing thing); // @ F0214_PROJECTILE_DeleteEvent
void projectileDelete(Thing projectileThing, Thing *groupSlot, int16 mapX, int16 mapY); // @ F0215_PROJECTILE_Delete
void processEvents48To49(TimelineEvent *event); // @ F0219_PROJECTILE_ProcessEvents48To49_Projectile
void processEvent25(TimelineEvent *event); // @ F0220_EXPLOSION_ProcessEvent25_Explosion
};
}
#endif

228
engines/dm/sounds.cpp Normal file
View File

@@ -0,0 +1,228 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
#include "audio/mixer.h"
#include "advancedDetector.h"
#include "dm/dm.h"
#include "dm/gfx.h"
#include "dm/timeline.h"
#include "dm/dungeonman.h"
#include "dm/group.h"
#include "dm/sounds.h"
namespace DM {
SoundMan *SoundMan::getSoundMan(DMEngine *vm, const DMADGameDescription *gameVersion) {
switch (gameVersion->_desc.platform) {
default:
warning("Unknown platform, using default Amiga SoundMan");
// fall through
case Common::kPlatformAmiga:
return new SoundMan(vm);
case Common::kPlatformAtariST:
return new SoundMan_Atari(vm);
}
}
void SoundMan::initConstants() {
Sound sounds[kDMSoundCount] = {
Sound(533, 112, 11, 3, 6), /* k00_soundMETALLIC_THUD 0 */
Sound(534, 112, 15, 0, 3), /* k01_soundSWITCH 1 */
Sound(535, 112, 72, 3, 6), /* k02_soundDOOR_RATTLE 2 */
Sound(550, 112, 60, 3, 5), /* k03_soundATTACK_PAIN_RAT_HELLHOUND_RED_DRAGON 3 */
Sound(536, 112, 10, 3, 6), /* k04_soundWOODEN_THUD_ATTACK_TROLIN_ANTMAN_STONE_GOLEM 4 */
Sound(537, 112, 99, 3, 7), /* k05_soundSTRONG_EXPLOSION 5 */
Sound(539, 112, 110, 3, 6), /* k06_soundSCREAM 6 */
Sound(551, 112, 55, 3, 5), /* k07_soundATTACK_MUMMY_GHOST_RIVE 7 */
Sound(540, 112, 2, 3, 6), /* k08_soundSWALLOW 8 */
Sound(541, 112, 80, 3, 6), /* k09_soundCHAMPION_0_DAMAGED 9 */
Sound(542, 112, 82, 3, 6), /* k10_soundCHAMPION_1_DAMAGED 10 */
Sound(543, 112, 84, 3, 6), /* k11_soundCHAMPION_2_DAMAGED 11 */
Sound(544, 112, 86, 3, 6), /* k12_soundCHAMPION_3_DAMAGED 12 */
Sound(545, 112, 95, 3, 6), /* k13_soundSPELL 13 */
Sound(552, 112, 57, 3, 5), /* k14_soundATTACK_SCREAMER_OITU 14 */
Sound(553, 112, 52, 3, 5), /* k15_soundATTACK_GIANT_SCORPION_SCORPION 15 */
Sound(546, 112, 40, 2, 4), /* k16_soundCOMBAT_ATTACK_SKELETON_ANIMATED_ARMOUR_DETH_KNIGHT 16 */
Sound(547, 112, 70, 1, 4), /* k17_soundBUZZ 17 */
Sound(549, 138, 75, 3, 6), /* k18_soundPARTY_DAMAGED 18 */
Sound(554, 112, 50, 3, 5), /* k19_soundATTACK_MAGENTA_WORM_WORM 19 */
Sound(537, 112, 98, 0, 4), /* k20_soundWEAK_EXPLOSION 20 */
Sound(555, 112, 96, 2, 4), /* k21_soundATTACK_GIGGLER 21 */
Sound(563, 138, 24, 0, 4), /* k22_soundMOVE_ANIMATED_ARMOUR_DETH_KNIGHT 22 Atari ST: not present */
Sound(564, 138, 21, 0, 4), /* k23_soundMOVE_COUATL_GIANT_WASP_MUNCHER 23 Atari ST: not present */
Sound(565, 138, 23, 0, 4), /* k24_soundMOVE_MUMMY_TROLIN_ANTMAN_STONE_GOLEM_GIGGLER_VEXIRK_DEMON 24 Atari ST: not present */
Sound(566, 138, 105, 0, 4), /* k25_soundBLOW_HORN 25 Atari ST: not present */
Sound(567, 138, 27, 0, 4), /* k26_soundMOVE_SCREAMER_ROCK_ROCKPILE_MAGENTA_WORM_WORM_PAIN_RAT_HELLHOUND_RUSTER_GIANT_SCORPION_SCORPION_OITU 26 Atari ST: not present */
Sound(568, 138, 28, 0, 4), /* k27_soundMOVE_SWAMP_SLIME_SLIME_DEVIL_WATER_ELEMENTAL 27 Atari ST: not present */
Sound(569, 138, 106, 0, 4), /* k28_soundWAR_CRY 28 Atari ST: not present */
Sound(570, 138, 56, 0, 4), /* k29_soundATTACK_ROCK_ROCKPILE 29 Atari ST: not present */
Sound(571, 138, 58, 0, 4), /* k30_soundATTACK_WATER_ELEMENTAL 30 Atari ST: not present */
Sound(572, 112, 53, 0, 4), /* k31_soundATTACK_COUATL 31 Atari ST: not present */
Sound(573, 138, 29, 0, 4), /* k32_soundMOVE_RED_DRAGON 32 Atari ST: not present */
Sound(574, 150, 22, 0, 4) /* k33_soundMOVE_SKELETON 33 Atari ST: not present */
};
for (int i = 0; i < kDMSoundCount; i++)
_sounds[i] = sounds[i];
}
SoundMan::SoundMan(DMEngine *vm) : _vm(vm) {
initConstants();
}
SoundMan::~SoundMan() {
for (uint16 i = 0; i < kDMSoundCount; ++i)
delete[] _soundData[i]._firstSample;
}
void SoundMan::loadSounds() {
for (uint16 soundIndex = 0; soundIndex < kDMSoundCount; ++soundIndex) {
SoundData *soundData = _soundData + soundIndex;
uint16 graphicIndex = _sounds[soundIndex]._graphicIndex;
soundData->_byteCount = _vm->_displayMan->getCompressedDataSize(graphicIndex) - 2; // the header is 2 bytes long
soundData->_firstSample = new byte[soundData->_byteCount];
Common::MemoryReadStream stream = _vm->_displayMan->getCompressedData(graphicIndex);
soundData->_sampleCount = stream.readUint16BE();
stream.read(soundData->_firstSample, soundData->_byteCount);
}
}
void SoundMan::play(uint16 soundIndex, uint16 period, uint8 leftVolume, uint8 rightVolume) {
SoundData *sound = &_soundData[soundIndex];
Audio::AudioStream *stream = Audio::makeRawStream(sound->_firstSample, sound->_byteCount, (72800 / period) * 8, 0, DisposeAfterUse::NO);
signed char balance = ((int16)rightVolume - (int16)leftVolume) / 2;
Audio::SoundHandle handle;
_vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &handle, stream, -1, 127, balance);
}
void SoundMan::playPendingSound() {
while (!_pendingSounds.empty()) {
PendingSound pendingSound = _pendingSounds.pop();
play(pendingSound._soundIndex, _sounds[pendingSound._soundIndex]._period, pendingSound._leftVolume, pendingSound._rightVolume);
}
}
bool SoundMan::soundGetVolume(int16 mapX, int16 mapY, uint8 *leftVolume, uint8 *rightVolume) {
static byte distanceToSoundVolume[25][25] = {
{1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4},
{1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 5, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4},
{1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4},
{1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 5, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4},
{1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 5, 8, 8, 7, 7, 7, 7, 6, 6, 6, 5, 5, 5, 4},
{1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 4, 6, 9, 9, 8, 8, 8, 7, 7, 6, 6, 6, 5, 5, 5},
{1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 6, 10, 10, 10, 9, 8, 8, 7, 7, 6, 6, 5, 5, 5},
{1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 7, 12, 12, 11, 10, 9, 9, 8, 7, 7, 6, 6, 5, 5},
{1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 7, 15, 14, 13, 12, 11, 9, 8, 8, 7, 6, 6, 5, 5},
{1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 8, 20, 19, 16, 14, 12, 10, 9, 8, 7, 7, 6, 6, 5},
{1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 8, 29, 26, 21, 16, 13, 11, 10, 8, 7, 7, 6, 6, 5},
{1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 8, 58, 41, 26, 19, 14, 12, 10, 9, 8, 7, 6, 6, 5},
{1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 6, 64, 58, 29, 20, 15, 12, 10, 9, 8, 7, 6, 6, 5},
{0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 6, 41, 29, 19, 13, 10, 8, 7, 6, 6, 5, 5, 4, 4},
{0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 6, 21, 19, 15, 12, 10, 8, 7, 6, 5, 5, 4, 4, 4},
{0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 6, 14, 13, 12, 10, 9, 7, 7, 6, 5, 5, 4, 4, 4},
{0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5, 11, 10, 10, 9, 8, 7, 6, 6, 5, 5, 4, 4, 4},
{0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 5, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 4, 4},
{0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 5, 7, 7, 7, 7, 6, 6, 5, 5, 5, 4, 4, 4, 4},
{0, 1, 1, 1, 1, 1, 1, 2, 2, 1, 3, 4, 6, 6, 6, 6, 6, 5, 5, 5, 4, 4, 4, 4, 3},
{1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3},
{1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3},
{1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 5, 5, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3},
{1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3},
{1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3}};
int16 lineIndex = 0;
int16 rightVolumeColumnIndex = 0;
switch (_vm->_dungeonMan->_partyDir) {
case kDMDirNorth:
rightVolumeColumnIndex = mapX - _vm->_dungeonMan->_partyMapX;
lineIndex = mapY - _vm->_dungeonMan->_partyMapY;
break;
case kDMDirEast:
rightVolumeColumnIndex = mapY - _vm->_dungeonMan->_partyMapY;
lineIndex = -(mapX - _vm->_dungeonMan->_partyMapX);
break;
case kDMDirSouth:
rightVolumeColumnIndex = -(mapX - _vm->_dungeonMan->_partyMapX);
lineIndex = -(mapY - _vm->_dungeonMan->_partyMapY);
break;
case kDMDirWest:
rightVolumeColumnIndex = -(mapY - _vm->_dungeonMan->_partyMapY);
lineIndex = mapX - _vm->_dungeonMan->_partyMapX;
break;
default:
break;
}
if ((rightVolumeColumnIndex < -12) || (rightVolumeColumnIndex > 12)) /* Sound is not audible if source is more than 12 squares away from the party */
return false;
if ((lineIndex < -12) || (lineIndex > 12)) /* Sound is not audible if source is more than 12 squares away from the party */
return false;
int16 leftVolumeColumnIndex = -rightVolumeColumnIndex + 12;
rightVolumeColumnIndex += 12;
lineIndex += 12;
*rightVolume = distanceToSoundVolume[lineIndex][rightVolumeColumnIndex];
*leftVolume = distanceToSoundVolume[lineIndex][leftVolumeColumnIndex];
return true;
}
void SoundMan::requestPlay(uint16 soundIndex, int16 mapX, int16 mapY, SoundMode soundMode) {
if ((soundMode != kDMSoundModePlayImmediately) && (_vm->_dungeonMan->_currMapIndex != _vm->_dungeonMan->_partyMapIndex))
return;
Sound *sound = &_sounds[soundIndex];
if (soundMode == kDMSoundModePlayOneTickLater) { /* Add an event in the timeline to play the sound (mode - 1) ticks later */
TimelineEvent newEvent;
newEvent._mapTime = _vm->setMapAndTime(_vm->_dungeonMan->_currMapIndex, _vm->_gameTime + soundMode - 1);
newEvent._type = kDMEventTypePlaySound;
newEvent._priority = sound->_priority;
newEvent._Cu._soundIndex = soundIndex;
newEvent._Bu._location._mapX = mapX;
newEvent._Bu._location._mapY = mapY;
_vm->_timeline->addEventGetEventIndex(&newEvent);
return;
}
uint8 leftVolume, rightVolume;
if (!soundGetVolume(mapX, mapY, &leftVolume, &rightVolume))
return;
if (soundMode == kDMSoundModePlayImmediately) { /* Play the sound immediately */
play(soundIndex, sound->_period, leftVolume, rightVolume);
return;
}
_pendingSounds.push(PendingSound(leftVolume, rightVolume, soundIndex));
}
}

144
engines/dm/sounds.h Normal file
View File

@@ -0,0 +1,144 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_SOUND_H
#define DM_SOUND_H
#include "dm/dm.h"
namespace DM {
enum SoundMode {
kDMSoundModeDoNotPlaySound = -1, // @ CM1_MODE_DO_NOT_PLAY_SOUND
kDMSoundModePlayImmediately = 0, // @ C00_MODE_PLAY_IMMEDIATELY
kDMSoundModePlayIfPrioritized = 1, // @ C01_MODE_PLAY_IF_PRIORITIZED
kDMSoundModePlayOneTickLater = 2 // @ C02_MODE_PLAY_ONE_TICK_LATER
};
enum SoundIndex {
kDMSoundIndexMetallicThud = 0, // @ C00_SOUND_METALLIC_THUD
kDMSoundIndexSwitch = 1, // @ C01_SOUND_SWITCH
kDMSoundIndexDoorRattle = 2, // @ C02_SOUND_DOOR_RATTLE
kDMSoundIndexAttackPainRatHellHoundRedDragon = 3, // @ C03_SOUND_ATTACK_PAIN_RAT_HELLHOUND_RED_DRAGON
kDMSoundIndexWoodenThudAttackTrolinAntmanStoneGolem = 4, // @ C04_SOUND_WOODEN_THUD_ATTACK_TROLIN_ANTMAN_STONE_GOLEM
kDMSoundIndexStrongExplosion = 5, // @ C05_SOUND_STRONG_EXPLOSION
kDMSoundIndexScream = 6, // @ C06_SOUND_SCREAM
kDMSoundIndexAttackMummyGhostRive = 7, // @ C07_SOUND_ATTACK_MUMMY_GHOST_RIVE
kDMSoundIndexSwallow = 8, // @ C08_SOUND_SWALLOW
kDMSoundIndexChampion0Damaged = 9, // @ C09_SOUND_CHAMPION_0_DAMAGED
kDMSoundIndexChampion1Damaged = 10, // @ C10_SOUND_CHAMPION_1_DAMAGED
kDMSoundIndexChampion2Damaged = 11, // @ C11_SOUND_CHAMPION_2_DAMAGED
kDMSoundIndexChampion3Damaged = 12, // @ C12_SOUND_CHAMPION_3_DAMAGED
kDMSoundIndexSpell = 13, // @ C13_SOUND_SPELL
kDMSoundIndexAttackScreamerOitu = 14, // @ C14_SOUND_ATTACK_SCREAMER_OITU
kDMSoundIndexAttackGiantScorpion = 15, // @ C15_SOUND_ATTACK_GIANT_SCORPION_SCORPION
kDMSoundIndexAttackSkelettonAnimatedArmorDethKnight = 16, // @ C16_SOUND_COMBAT_ATTACK_SKELETON_ANIMATED_ARMOUR_DETH_KNIGHT
kDMSoundIndexBuzz = 17, // @ C17_SOUND_BUZZ
kDMSoundIndexPartyDamaged = 18, // @ C18_SOUND_PARTY_DAMAGED
kDMSoundIndexAttackMagentaWorm = 19, // @ C19_SOUND_ATTACK_MAGENTA_WORM_WORM
kDMSoundIndexWeakExplosion = 20, // @ C20_SOUND_WEAK_EXPLOSION
kDMSoundIndexAttackGiggler = 21, // @ C21_SOUND_ATTACK_GIGGLER
kDMSoundIndexMoveAnimatedArmorDethKnight = 22, // @ C22_SOUND_MOVE_ANIMATED_ARMOUR_DETH_KNIGHT
kDMSoundIndexMoveCouatlGiantWaspMuncher = 23, // @ C23_SOUND_MOVE_COUATL_GIANT_WASP_MUNCHER
kDMSoundIndexMoveMummyTrolinAntmanStoneGolemGiggleVexirkDemon = 24, // @ C24_SOUND_MOVE_MUMMY_TROLIN_ANTMAN_STONE_GOLEM_GIGGLER_VEXIRK_DEMON
kDMSoundIndexBlowHorn = 25, // @ C25_SOUND_BLOW_HORN
kDMSoundIndexMoveScreamerRocksWormPainRatHellHoundRusterScorpionsOitu = 26, // @ C26_SOUND_MOVE_SCREAMER_ROCK_ROCKPILE_MAGENTA_WORM_WORM_PAIN_RAT_HELLHOUND_RUSTER_GIANT_SCORPION_SCORPION_OITU
kDMSoundIndexMoveSlimesDevilWaterElemental = 27, // @ C27_SOUND_MOVE_SWAMP_SLIME_SLIME_DEVIL_WATER_ELEMENTAL
kDMSoundIndexWarCry = 28, // @ C28_SOUND_WAR_CRY
kDMSoundIndexAttackRocks = 29, // @ C29_SOUND_ATTACK_ROCK_ROCKPILE
kDMSoundIndexAttackWaterElemental = 30, // @ C30_SOUND_ATTACK_WATER_ELEMENTAL
kDMSoundIndexAttackCouatl = 31, // @ C31_SOUND_ATTACK_COUATL
kDMSoundIndexMoveRedDragon = 32, // @ C32_SOUND_MOVE_RED_DRAGON
kDMSoundIndexMoveSkeletton = 33 // @ C33_SOUND_MOVE_SKELETON
};
#define kDMSoundCount 34 // @ D13_SOUND_COUNT
class SoundData {
public:
uint32 _byteCount;
byte *_firstSample;
uint32 _sampleCount;
SoundData() : _byteCount(0), _firstSample(nullptr), _sampleCount(0) {}
}; // @ SOUND_DATA
class Sound {
public:
int16 _graphicIndex;
byte _period;
byte _priority;
byte _loudDistance;
byte _softDistance;
Sound(int16 index, byte period, byte priority, byte loudDist, byte softDist) :
_graphicIndex(index), _period(period), _priority(priority), _loudDistance(loudDist), _softDistance(softDist) {}
Sound() : _graphicIndex(0), _period(0), _priority(0), _loudDistance(0), _softDistance(0) {}
}; // @ Sound
class PendingSound {
public:
uint8 _leftVolume;
uint8 _rightVolume;
int16 _soundIndex;
PendingSound(uint8 leftVolume, uint8 rightVolume, int16 soundIndex) :
_leftVolume(leftVolume), _rightVolume(rightVolume), _soundIndex(soundIndex) {}
};
class SoundMan {
DMEngine *_vm;
protected:
SoundMan(DMEngine *vm);
public:
virtual ~SoundMan();
static SoundMan *getSoundMan(DMEngine *vm, const DMADGameDescription *gameVersion);
SoundData _soundData[kDMSoundCount]; // @ K0024_as_SoundData
Common::Queue<PendingSound> _pendingSounds;
virtual void loadSounds(); // @ F0503_SOUND_LoadAll
virtual void requestPlay(uint16 soundIndex, int16 mapX, int16 mapY, SoundMode soundMode); // @ F0064_SOUND_RequestPlay_CPSD
virtual void play(uint16 soundIndex, uint16 period, uint8 leftVolume, uint8 rightVolume); // @ F0060_SOUND_Play
void playPendingSound(); // @ F0065_SOUND_PlayPendingSound_CPSD
bool soundGetVolume(int16 mapX, int16 mapY, uint8 *leftVolume, uint8 *rightVolume); // @ F0505_SOUND_GetVolume
Sound _sounds[kDMSoundCount];
void initConstants();
};
class SoundMan_Atari: public SoundMan {
friend class SoundMan;
SoundMan_Atari(DMEngine *vm): SoundMan(vm) {};
public:
void loadSounds() override {} // @ F0503_SOUND_LoadAll
void requestPlay(uint16 soundIndex, int16 mapX, int16 mapY, SoundMode soundMode) override {} // @ F0064_SOUND_RequestPlay_CPSD
void play(uint16 soundIndex, uint16 period, uint8 leftVolume, uint8 rightVolume) override {} // @ F0060_SOUND_Play
};
}
#endif

254
engines/dm/text.cpp Normal file
View File

@@ -0,0 +1,254 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#include "common/system.h"
#include "dm/text.h"
namespace DM {
TextMan::TextMan(DMEngine *vm) : _vm(vm) {
_messageAreaCursorColumn = 0;
_messageAreaCursorRow = 0;
for (uint16 i = 0; i < 4; ++i)
_messageAreaRowExpirationTime[i] = 0;
_bitmapMessageAreaNewRow = new byte[320 * 7];
_isScrolling = false;
_startedScrollingAt = -1;
_messageAreaCopy = new byte[320 * 7 * 4];
}
TextMan::~TextMan() {
delete[] _bitmapMessageAreaNewRow;
delete[] _messageAreaCopy;
}
void TextMan::printTextToBitmap(byte *destBitmap, uint16 destByteWidth, int16 destX, int16 destY,
Color textColor, Color bgColor, const char *text, uint16 destHeight) {
if ((destX -= 1) < 0) // fixes missalignment, to be checked
destX = 0;
if ((destY -= 4) < 0) // fixes missalignment, to be checked
destY = 0;
uint16 destPixelWidth = destByteWidth * 2;
uint16 textLength = strlen(text);
uint16 nextX = destX;
uint16 nextY = destY;
byte *srcBitmap = _vm->_displayMan->getNativeBitmapOrGraphic(kDMGraphicIdxFont);
byte *tmp = _vm->_displayMan->_tmpBitmap;
for (uint16 i = 0; i < (kDMFontLetterWidth + 1) * kDMFontLetterHeight * 128; ++i)
tmp[i] = srcBitmap[i] ? textColor : bgColor;
srcBitmap = tmp;
for (const char *begin = text, *end = text + textLength; begin != end; ++begin) {
if (nextX + kDMFontLetterWidth + 1 >= destPixelWidth || (*begin == '\n')) {
nextX = destX;
nextY += kDMFontLetterHeight + 1;
}
if (nextY + kDMFontLetterHeight >= destHeight)
break;
uint16 srcX = (1 + 5) * *begin; // 1 + 5 is not the letter width, arbitrary choice of the unpacking code
Box box((nextX == destX) ? (nextX + 1) : nextX, nextX + kDMFontLetterWidth + 1, nextY, nextY + kDMFontLetterHeight - 1);
_vm->_displayMan->blitToBitmap(srcBitmap, destBitmap, box, (nextX == destX) ? (srcX + 1) : srcX, 0, 6 * 128 / 2, destByteWidth, kDMColorNoTransparency,
kDMFontLetterHeight, destHeight);
nextX += kDMFontLetterWidth + 1;
}
}
void TextMan::printToLogicalScreen(uint16 destX, uint16 destY, Color textColor, Color bgColor, const char *text) {
printTextToBitmap(_vm->_displayMan->_bitmapScreen, _vm->_displayMan->_screenWidth / 2, destX, destY, textColor, bgColor, text, _vm->_displayMan->_screenHeight);
}
void TextMan::printToViewport(int16 posX, int16 posY, Color textColor, const char *text, Color bgColor) {
printTextToBitmap(_vm->_displayMan->_bitmapViewport, k112_byteWidthViewport, posX, posY, textColor, bgColor, text, k136_heightViewport);
}
void TextMan::printWithTrailingSpaces(byte *destBitmap, int16 destByteWidth, int16 destX, int16 destY, Color textColor,
Color bgColor, const char *text, int16 requiredTextLength, int16 destHeight) {
Common::String str = text;
for (int16 i = str.size(); i < requiredTextLength; ++i)
str += ' ';
printTextToBitmap(destBitmap, destByteWidth, destX, destY, textColor, bgColor, str.c_str(), destHeight);
}
void TextMan::printLineFeed() {
printMessage(kDMColorBlack, "\n");
}
void TextMan::printMessage(Color color, const char *string, bool printWithScroll) {
uint16 characterIndex;
Common::String wrkString;
while (*string) {
if (*string == '\n') { /* New line */
string++;
if ((_messageAreaCursorColumn != 0) || (_messageAreaCursorRow != 0)) {
_messageAreaCursorColumn = 0;
createNewRow();
}
} else if (*string == ' ') {
string++;
if (_messageAreaCursorColumn != 53) {
printString(color, " "); // I'm not sure if this is like the original
}
} else {
characterIndex = 0;
do {
wrkString += *string++;
characterIndex++;
} while (*string && (*string != ' ') && (*string != '\n')); /* End of string, space or New line */
wrkString += '\0';
if (_messageAreaCursorColumn + characterIndex > 53) {
_messageAreaCursorColumn = 2;
createNewRow();
}
printString(color, wrkString.c_str());
}
}
}
void TextMan::createNewRow() {
if (_messageAreaCursorRow == 3) {
isTextScrolling(&_textScroller, true);
memset(_bitmapMessageAreaNewRow, kDMColorBlack, 320 * 7);
_isScrolling = true;
setScrollerCommand(&_textScroller, 1);
for (uint16 rowIndex = 0; rowIndex < 3; rowIndex++)
_messageAreaRowExpirationTime[rowIndex] = _messageAreaRowExpirationTime[rowIndex + 1];
_messageAreaRowExpirationTime[3] = -1;
} else
_messageAreaCursorRow++;
}
void TextMan::printString(Color color, const char* string) {
int16 stringLength = strlen(string);
if (isTextScrolling(&_textScroller, false))
printToLogicalScreen(_messageAreaCursorColumn * 6, (_messageAreaCursorRow * 7 - 1) + 177, color, kDMColorBlack, string);
else {
printTextToBitmap(_bitmapMessageAreaNewRow, k160_byteWidthScreen, _messageAreaCursorColumn * 6, 0, color, kDMColorBlack, string, 7);
_isScrolling = true;
if (isTextScrolling(&_textScroller, false))
setScrollerCommand(&_textScroller, 1);
}
_messageAreaCursorColumn += stringLength;
_messageAreaRowExpirationTime[_messageAreaCursorRow] = _vm->_gameTime + 200;
}
void TextMan::initialize() {
moveCursor(0, 3);
for (uint16 i = 0; i < 4; ++i)
_messageAreaRowExpirationTime[i] = -1;
}
void TextMan::moveCursor(int16 column, int16 row) {
if (column < 0)
column = 0;
else if (column >= 53)
column = 52;
_messageAreaCursorColumn = column;
if (row < 0)
row = 0;
else if (row >= 4)
row = 3;
_messageAreaCursorRow = row;
}
void TextMan::clearExpiredRows() {
_vm->_displayMan->_useByteBoxCoordinates = false;
Box displayBox;
displayBox._rect.left = 0;
displayBox._rect.right = 319;
for (uint16 rowIndex = 0; rowIndex < 4; rowIndex++) {
int32 expirationTime = _messageAreaRowExpirationTime[rowIndex];
if ((expirationTime == -1) || (expirationTime > _vm->_gameTime) || _isScrolling)
continue;
displayBox._rect.top = 172 + (rowIndex * 7);
displayBox._rect.bottom = displayBox._rect.top + 6;
isTextScrolling(&_textScroller, true);
_vm->_displayMan->fillBoxBitmap(_vm->_displayMan->_bitmapScreen, displayBox, kDMColorBlack, k160_byteWidthScreen, k200_heightScreen);
_messageAreaRowExpirationTime[rowIndex] = -1;
}
}
void TextMan::printEndGameString(int16 x, int16 y, Color textColor, const char* text) {
char modifiedString[50];
char *wrkStringPtr = modifiedString;
*wrkStringPtr = *text++;
while (*wrkStringPtr) {
if ((*wrkStringPtr >= 'A') && (*wrkStringPtr <= 'Z'))
*wrkStringPtr -= 64; /* Use the same font as the one used for scrolls */
wrkStringPtr++;
*wrkStringPtr = *text++;
}
printToLogicalScreen(x, y, textColor, kDMColorDarkestGray, modifiedString);
}
void TextMan::clearAllRows() {
isTextScrolling(&_textScroller, true);
Box tmpBox(0, 319, 169, 199);
_vm->_displayMan->fillScreenBox(tmpBox, kDMColorBlack);
_messageAreaCursorRow = 3;
_messageAreaCursorColumn = 0;
for (int16 rowIndex = 0; rowIndex < 4; rowIndex++)
_messageAreaRowExpirationTime[rowIndex] = -1;
}
void TextMan::updateMessageArea() {
if (_isScrolling) {
if (_startedScrollingAt == -1) {
_startedScrollingAt = g_system->getMillis();
memcpy(_messageAreaCopy, _vm->_displayMan->_bitmapScreen + (200 - 7 * 4) * 320, 320 * 7 * 4);
}
int linesToCopy = (g_system->getMillis() - _startedScrollingAt) / 50;
if (linesToCopy >= 7) {
linesToCopy = 7;
_startedScrollingAt = -1;
_isScrolling = false;
}
memcpy(_vm->_displayMan->_bitmapScreen + (200 - 7 * 4) * 320, _messageAreaCopy + linesToCopy * 320,
320 * (7 * 4 - linesToCopy));
memcpy(_vm->_displayMan->_bitmapScreen + (200 - linesToCopy) * 320, _bitmapMessageAreaNewRow, 320 * linesToCopy);
}
}
}

81
engines/dm/text.h Normal file
View File

@@ -0,0 +1,81 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_TEXT_H
#define DM_TEXT_H
#include "dm/dm.h"
#include "dm/gfx.h"
namespace DM {
struct TextScroller {
// Placeholder, empty for now
}; // @ Text_Scroller
#define kDMFontLetterWidth 5
#define kDMFontLetterHeight 6
class TextMan {
DMEngine *_vm;
int16 _messageAreaCursorColumn; // @ G0359_i_MessageAreaCursorColumn
int16 _messageAreaCursorRow; // @ G0358_i_MessageAreaCursorRow
int32 _messageAreaRowExpirationTime[4]; // @ G0360_al_MessageAreaRowExpirationTime
byte *_bitmapMessageAreaNewRow; // @ G0356_puc_Bitmap_MessageAreaNewRow
// for scrolling 'em messages
bool _isScrolling;
int64 _startedScrollingAt;
byte *_messageAreaCopy;
public:
TextScroller _textScroller;
explicit TextMan(DMEngine *vm);
~TextMan();
void printTextToBitmap(byte *destBitmap, uint16 destByteWidth, int16 destX, int16 destY,
Color textColor, Color bgColor, const char *text, uint16 destHeight); // @ F0040_TEXT_Print
void printToLogicalScreen(uint16 destX, uint16 destY, Color textColor, Color bgColor, const char *text); // @ F0053_TEXT_PrintToLogicalScreen
void printToViewport(int16 posX, int16 posY, Color textColor, const char *text, Color bgColor = kDMColorDarkestGray); // @ F0052_TEXT_PrintToViewport
void printWithTrailingSpaces(byte *destBitmap, int16 destByteWidth, int16 destX, int16 destY, Color textColor, Color bgColor,
const char *text, int16 strLenght, int16 destHeight); // @ F0041_TEXT_PrintWithTrailingSpaces
void printLineFeed(); // @ F0051_TEXT_MESSAGEAREA_PrintLineFeed
void printMessage(Color color, const char *string, bool printWithScroll = true); // @ F0047_TEXT_MESSAGEAREA_PrintMessage
void createNewRow(); // @ F0045_TEXT_MESSAGEAREA_CreateNewRow
void printString(Color color, const char* string);// @ F0046_TEXT_MESSAGEAREA_PrintString
void initialize(); // @ F0054_TEXT_Initialize
void moveCursor(int16 column, int16 row); // @ F0042_TEXT_MESSAGEAREA_MoveCursor
void clearExpiredRows(); // @ F0044_TEXT_MESSAGEAREA_ClearExpiredRows
void printEndGameString(int16 x, int16 y, Color textColor, const char *text); // @ F0443_STARTEND_EndgamePrintString
bool isTextScrolling(TextScroller *scroller, bool waitEndOfScrolling) { return false; } // @ F0561_SCROLLER_IsTextScrolling
void setScrollerCommand(TextScroller *scroller, int16 command) { } // @ F0560_SCROLLER_SetCommand
void clearAllRows(); // @ F0043_TEXT_MESSAGEAREA_ClearAllRows
void updateMessageArea();
};
}
#endif

1000
engines/dm/timeline.cpp Normal file

File diff suppressed because it is too large Load Diff

203
engines/dm/timeline.h Normal file
View File

@@ -0,0 +1,203 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on the Reverse Engineering work of Christophe Fontanel,
* maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/)
*/
#ifndef DM_TIMELINE_H
#define DM_TIMELINE_H
#include "dm/dm.h"
namespace DM {
class Champion;
class Sensor;
/* Event types */
enum TimelineEventType {
/* Used when a creature in a group was damaged or killed by a Poison Cloud or by a closing door or if Lord Chaos is surrounded by = 3, Fluxcages */
kDMEventTypeCreateReactionDangerOnSquare = -3, // @ CM3_EVENT_CREATE_REACTION_EVENT_29_DANGER_ON_SQUARE
/* Used when a projectile impacts with a creature in a group */
kDMEventTypeCreateReactionHitByProjectile = -2, // @ CM2_EVENT_CREATE_REACTION_EVENT_30_HIT_BY_PROJECTILE
/* Used when the party bumps into a group or performs a melee attack */
kDMEventTypeCreateReactionPartyIsAdjacent = -1, // @ CM1_EVENT_CREATE_REACTION_EVENT_31_PARTY_IS_ADJACENT
kDMEventTypeNone = 0, // @ C00_EVENT_NONE
kDMEventTypeDoorAnimation = 1, // @ C01_EVENT_DOOR_ANIMATION
kDMEventTypeDoorDestruction = 2, // @ C02_EVENT_DOOR_DESTRUCTION
kDMEventTypeCorridor = 5, // @ C05_EVENT_CORRIDOR
kDMEventTypeWall = 6, // @ C06_EVENT_WALL
kDMEventTypeFakeWall = 7, // @ C07_EVENT_FAKEWALL
kDMEventTypeTeleporter = 8, // @ C08_EVENT_TELEPORTER
kDMEventTypePit = 9, // @ C09_EVENT_PIT
kDMEventTypeDoor = 10, // @ C10_EVENT_DOOR
kDMEventTypeEnableChampionAction = 11, // @ C11_EVENT_ENABLE_CHAMPION_ACTION
kDMEventTypeHideDamageReceived = 12, // @ C12_EVENT_HIDE_DAMAGE_RECEIVED
kDMEventTypeViAltarRebirth = 13, // @ C13_EVENT_VI_ALTAR_REBIRTH
kDMEventTypePlaySound = 20, // @ C20_EVENT_PLAY_SOUND
kDMEventTypeCPSE = 22, // @ C22_EVENT_CPSE
kDMEventTypeRemoveFluxcage = 24, // @ C24_EVENT_REMOVE_FLUXCAGE
kDMEventTypeExplosion = 25, // @ C25_EVENT_EXPLOSION
kDMEventTypeGroupReactionDangerOnSquare = 29, // @ C29_EVENT_GROUP_REACTION_DANGER_ON_SQUARE
kDMEventTypeGroupReacionHitByProjectile = 30, // @ C30_EVENT_GROUP_REACTION_HIT_BY_PROJECTILE
kDMEventTypeGroupReactionPartyIsAdjecent = 31, // @ C31_EVENT_GROUP_REACTION_PARTY_IS_ADJACENT
kDMEventTypeUpdateAspectGroup = 32, // @ C32_EVENT_UPDATE_ASPECT_GROUP
/* Events = 33,-36 and = 38,-41 are used for individual creatures only while the group is attacking the party */
kDMEventTypeUpdateAspectCreature0 = 33, // @ C33_EVENT_UPDATE_ASPECT_CREATURE_0
kDMEventTypeUpdateAspectCreature1 = 34, // @ C34_EVENT_UPDATE_ASPECT_CREATURE_1
kDMEventTypeUpdateAspectCreature2 = 35, // @ C35_EVENT_UPDATE_ASPECT_CREATURE_2
kDMEventTypeUpdateAspectCreature3 = 36, // @ C36_EVENT_UPDATE_ASPECT_CREATURE_3
kDMEventTypeUpdateBehaviourGroup = 37, // @ C37_EVENT_UPDATE_BEHAVIOR_GROUP
kDMEventTypeUpdateBehavior0 = 38, // @ C38_EVENT_UPDATE_BEHAVIOR_CREATURE_0
kDMEventTypeUpdateBehavior1 = 39, // @ C39_EVENT_UPDATE_BEHAVIOR_CREATURE_1
kDMEventTypeUpdateBehavior2 = 40, // @ C40_EVENT_UPDATE_BEHAVIOR_CREATURE_2
kDMEventTypeUpdateBehavior3 = 41, // @ C41_EVENT_UPDATE_BEHAVIOR_CREATURE_3
/* Projectiles created by a champion (by casting a spell, shooting a weapon or throwing an object) or by a creature (by casting a spell) ignore impacts during their first movement otherwise an impact would always occur immediately as these projectiles are created on the champion or creature square */
kDMEventTypeMoveProjectileIgnoreImpacts = 48, // @ C48_EVENT_MOVE_PROJECTILE_IGNORE_IMPACTS
/* Projectiles created by projectile launcher sensors never ignore impacts as well as all other projectiles after their first movement */
kDMEventTypeMoveProjectile = 49, // @ C49_EVENT_MOVE_PROJECTILE
kDMEventTypeWatchdoge = 53, // @ C53_EVENT_WATCHDOG
kDMEventTypeMoveGroupSilent = 60, // @ C60_EVENT_MOVE_GROUP_SILENT
kDMEventTypeMoveGroupAudible = 61, // @ C61_EVENT_MOVE_GROUP_AUDIBLE
kDMEventTypeEnableGroupGenerator = 65, // @ C65_EVENT_ENABLE_GROUP_GENERATOR
kDMEventTypeLight = 70, // @ C70_EVENT_LIGHT
kDMEventTypeInvisibility = 71, // @ C71_EVENT_INVISIBILITY
kDMEventTypeChampionShield = 72, // @ C72_EVENT_CHAMPION_SHIELD
kDMEventTypeThievesEye = 73, // @ C73_EVENT_THIEVES_EYE
kDMEventTypePartyShield = 74, // @ C74_EVENT_PARTY_SHIELD
kDMEventTypePoisonChampion = 75, // @ C75_EVENT_POISON_CHAMPION
kDMEventTypeSpellShield = 77, // @ C77_EVENT_SPELLSHIELD
kDMEventTypeFireShield = 78, // @ C78_EVENT_FIRESHIELD
kDMEventTypeFootprints = 79, // @ C79_EVENT_FOOTPRINTS
kDMEventTypeMagicMap0 = 80, // @ C80_EVENT_MAGIC_MAP
kDMEventTypeMagicMap1 = 81, // @ C81_EVENT_MAGIC_MAP
kDMEventTypeMagicMap2 = 82, // @ C82_EVENT_MAGIC_MAP
kDMEventTypeMagicMap3 = 83 // @ C83_EVENT_MAGIC_MAP
};
#define kDMMaskGeneratedCreatureCount 0x0007 // @ MASK0x0007_GENERATED_CREATURE_COUNT
#define kDMMaskRandomizeGeneratedCreatureCount 0x0008 // @ MASK0x0008_RANDOMIZE_GENERATED_CREATURE_COUNT
class TimelineEvent {
public:
int32 _mapTime;
TimelineEventType _type;
byte _priority; // CHECKME: byte? or int16? Inconsistency in the code
uint16 getTypePriority() { return (_type << 8) + _priority; }
union B_unionTimelineEvent {
struct {
byte _mapX;
byte _mapY;
} _location;
int16 _attack;
int16 _defense;
int16 _lightPower;
uint16 _slot; // Thing
int16 _slotOrdinal;
};
B_unionTimelineEvent _Bu;
int16 getMapXY() { return (_Bu._location._mapX << 8) + _Bu._location._mapY; }
union C_uionTimelineEvent {
struct {
byte _cell;
byte _effect;
} A;
class {
uint16 _backing;
public:
uint16 getMapX() { return _backing & 0x1F; }
uint16 getMapY() { return (_backing >> 5) & 0x1F; }
Direction getDir() { return (Direction)((_backing >> 10) & 0x3); }
uint16 getStepEnergy() { return (_backing >> 12) & 0xF; }
void setMapX(uint16 val) { _backing = (_backing & ~0x1F) | (val & 0x1F); }
void setMapY(uint16 val) { _backing = (_backing & ~(0x1F << 5)) | ((val & 0x1F) << 5); }
void setDir(Direction val) { _backing = (_backing & ~(0x3 << 10)) | ((val & 0x3) << 10); }
void setStepEnergy(uint16 val) { _backing = (_backing & ~(0xF << 12)) | ((val & 0xF) << 12); }
} _projectile;
uint16 _slot;
int16 _soundIndex;
byte _ticks;
};
C_uionTimelineEvent _Cu;
}; // @ EVENT
class Timeline {
DMEngine *_vm;
public:
uint16 _eventMaxCount; // @ G0369_ui_EventMaximumCount
TimelineEvent *_events; // @ G0370_ps_Events
uint16 _eventCount; // @ G0372_ui_EventCount
uint16 *_timeline; // @ G0371_pui_Timeline
uint16 _firstUnusedEventIndex; // @ G0373_ui_FirstUnusedEventIndex
explicit Timeline(DMEngine *vm);
~Timeline();
void initTimeline(); // @ F0233_TIMELINE_Initialize
void deleteEvent(uint16 eventIndex);// @ F0237_TIMELINE_DeleteEvent
void fixChronology(uint16 timelineIndex); // @ F0236_TIMELINE_FixChronology
bool isEventABeforeB(TimelineEvent *eventA, TimelineEvent *eventB); // @ F0234_TIMELINE_IsEventABeforeEventB
uint16 getIndex(uint16 eventIndex); // @ F0235_TIMELINE_GetIndex
uint16 addEventGetEventIndex(TimelineEvent *event); // @ F0238_TIMELINE_AddEvent_GetEventIndex_CPSE
void processTimeline(); // @ F0261_TIMELINE_Process_CPSEF
bool isFirstEventExpiered(); // @ F0240_TIMELINE_IsFirstEventExpired_CPSE
void extractFirstEvent(TimelineEvent *event); // @ F0239_TIMELINE_ExtractFirstEvent
void processEventDoorAnimation(TimelineEvent *event); // @ F0241_TIMELINE_ProcessEvent1_DoorAnimation
void processEventSquareFakewall(TimelineEvent *event); // @ F0242_TIMELINE_ProcessEvent7_Square_FakeWall
void processEventDoorDestruction(TimelineEvent *event); // @ F0243_TIMELINE_ProcessEvent2_DoorDestruction
void processEventSquareDoor(TimelineEvent *event); // @ F0244_TIMELINE_ProcessEvent10_Square_Door
void processEventSquarePit(TimelineEvent *event); // @ F0251_TIMELINE_ProcessEvent9_Square_Pit
void moveTeleporterOrPitSquareThings(uint16 mapX, uint16 mapY); // @ F0249_TIMELINE_MoveTeleporterOrPitSquareThings
void processEventSquareTeleporter(TimelineEvent *event); // @ F0250_TIMELINE_ProcessEvent8_Square_Teleporter
void processEventSquareWall(TimelineEvent *event); // @ F0248_TIMELINE_ProcessEvent6_Square_Wall
void triggerProjectileLauncher(Sensor *sensor, TimelineEvent *event); // @ F0247_TIMELINE_TriggerProjectileLauncher
void processEventSquareCorridor(TimelineEvent *event); // @ F0245_TIMELINE_ProcessEvent5_Square_Corridor
void processEventsMoveGroup(TimelineEvent *event); // @ F0252_TIMELINE_ProcessEvents60to61_MoveGroup
void procesEventEnableGroupGenerator(TimelineEvent *event); // @ F0246_TIMELINE_ProcessEvent65_EnableGroupGenerator
void processEventEnableChampionAction(uint16 champIndex); // @ F0253_TIMELINE_ProcessEvent11Part1_EnableChampionAction
void processEventMoveWeaponFromQuiverToSlot(uint16 champIndex, uint16 slotIndex);// @ F0259_TIMELINE_ProcessEvent11Part2_MoveWeaponFromQuiverToSlot
bool hasWeaponMovedSlot(int16 champIndex, Champion *champ,
uint16 sourceSlotIndex, int16 destSlotIndex); // @ F0258_TIMELINE_HasWeaponMovedToSlot
void processEventHideDamageReceived(uint16 champIndex); // @ F0254_TIMELINE_ProcessEvent12_HideDamageReceived
void processEventLight(TimelineEvent *event); // @ F0257_TIMELINE_ProcessEvent70_Light
void refreshAllChampionStatusBoxes(); // @ F0260_TIMELINE_RefreshAllChampionStatusBoxes
void processEventViAltarRebirth(TimelineEvent *event); // @ F0255_TIMELINE_ProcessEvent13_ViAltarRebirth
void saveEventsPart(Common::OutSaveFile *file);
void saveTimelinePart(Common::OutSaveFile *file);
void loadEventsPart(Common::InSaveFile *file);
void loadTimelinePart(Common::InSaveFile *file);
signed char _actionDefense[44]; // @ G0495_ac_Graphic560_ActionDefense
void initConstants();
};
}
#endif