Initial commit
This commit is contained in:
10
engines/dm/.gitattributes
vendored
Normal file
10
engines/dm/.gitattributes
vendored
Normal 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
3
engines/dm/POTFILES
Normal file
@@ -0,0 +1,3 @@
|
||||
engines/dm/dm.cpp
|
||||
engines/dm/loadsave.cpp
|
||||
engines/dm/metaengine.cpp
|
||||
215
engines/dm/TODOs/methodtree.txt
Normal file
215
engines/dm/TODOs/methodtree.txt
Normal 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
21
engines/dm/TODOs/todo.txt
Normal 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
2689
engines/dm/champion.cpp
Normal file
File diff suppressed because it is too large
Load Diff
582
engines/dm/champion.h
Normal file
582
engines/dm/champion.h
Normal 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
|
||||
3
engines/dm/configure.engine
Normal file
3
engines/dm/configure.engine
Normal 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
289
engines/dm/console.cpp
Normal 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
60
engines/dm/console.h
Normal 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
4
engines/dm/credits.pl
Normal file
@@ -0,0 +1,4 @@
|
||||
begin_section("DM");
|
||||
add_person("Arnaud Boutonné", "Strangerke", "");
|
||||
add_person("Bendegúz Nagy", "WinterGrascph", "");
|
||||
end_section();
|
||||
114
engines/dm/detection.cpp
Normal file
114
engines/dm/detection.cpp
Normal 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
86
engines/dm/detection.h
Normal 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
270
engines/dm/dialog.cpp
Normal 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
62
engines/dm/dialog.h
Normal 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
1043
engines/dm/dm.cpp
Normal file
File diff suppressed because it is too large
Load Diff
304
engines/dm/dm.h
Normal file
304
engines/dm/dm.h
Normal 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
57
engines/dm/dmglobals.cpp
Normal 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
1694
engines/dm/dungeonman.cpp
Normal file
File diff suppressed because it is too large
Load Diff
711
engines/dm/dungeonman.h
Normal file
711
engines/dm/dungeonman.h
Normal 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
1681
engines/dm/eventman.cpp
Normal file
File diff suppressed because it is too large
Load Diff
324
engines/dm/eventman.h
Normal file
324
engines/dm/eventman.h
Normal 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
4004
engines/dm/gfx.cpp
Normal file
File diff suppressed because it is too large
Load Diff
837
engines/dm/gfx.h
Normal file
837
engines/dm/gfx.h
Normal 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
2132
engines/dm/group.cpp
Normal file
File diff suppressed because it is too large
Load Diff
255
engines/dm/group.h
Normal file
255
engines/dm/group.h
Normal 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
1096
engines/dm/inventory.cpp
Normal file
File diff suppressed because it is too large
Load Diff
98
engines/dm/inventory.h
Normal file
98
engines/dm/inventory.h
Normal 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
451
engines/dm/loadsave.cpp
Normal 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
41
engines/dm/loadsave.h
Normal 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
186
engines/dm/lzw.cpp
Normal 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
68
engines/dm/lzw.h
Normal 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
1858
engines/dm/menus.cpp
Normal file
File diff suppressed because it is too large
Load Diff
140
engines/dm/menus.h
Normal file
140
engines/dm/menus.h
Normal 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
269
engines/dm/metaengine.cpp
Normal 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
64
engines/dm/module.mk
Normal 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
1027
engines/dm/movesens.cpp
Normal file
File diff suppressed because it is too large
Load Diff
80
engines/dm/movesens.h
Normal file
80
engines/dm/movesens.h
Normal 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
279
engines/dm/objectman.cpp
Normal 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
76
engines/dm/objectman.h
Normal 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
567
engines/dm/projexpl.cpp
Normal 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
71
engines/dm/projexpl.h
Normal 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
228
engines/dm/sounds.cpp
Normal 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
144
engines/dm/sounds.h
Normal 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
254
engines/dm/text.cpp
Normal 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
81
engines/dm/text.h
Normal 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
1000
engines/dm/timeline.cpp
Normal file
File diff suppressed because it is too large
Load Diff
203
engines/dm/timeline.h
Normal file
203
engines/dm/timeline.h
Normal 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
|
||||
Reference in New Issue
Block a user