1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 /* 24 * Based on the Reverse Engineering work of Christophe Fontanel, 25 * maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/) 26 */ 27 28 #ifndef DM_TIMELINE_H 29 #define DM_TIMELINE_H 30 31 #include "dm/dm.h" 32 33 namespace DM { 34 class Champion; 35 class Sensor; 36 37 /* Event types */ 38 enum TimelineEventType { 39 /* 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 */ 40 kDMEventTypeCreateReactionDangerOnSquare = -3, // @ CM3_EVENT_CREATE_REACTION_EVENT_29_DANGER_ON_SQUARE 41 /* Used when a projectile impacts with a creature in a group */ 42 kDMEventTypeCreateReactionHitByProjectile = -2, // @ CM2_EVENT_CREATE_REACTION_EVENT_30_HIT_BY_PROJECTILE 43 /* Used when the party bumps into a group or performs a melee attack */ 44 kDMEventTypeCreateReactionPartyIsAdjacent = -1, // @ CM1_EVENT_CREATE_REACTION_EVENT_31_PARTY_IS_ADJACENT 45 kDMEventTypeNone = 0, // @ C00_EVENT_NONE 46 kDMEventTypeDoorAnimation = 1, // @ C01_EVENT_DOOR_ANIMATION 47 kDMEventTypeDoorDestruction = 2, // @ C02_EVENT_DOOR_DESTRUCTION 48 kDMEventTypeCorridor = 5, // @ C05_EVENT_CORRIDOR 49 kDMEventTypeWall = 6, // @ C06_EVENT_WALL 50 kDMEventTypeFakeWall = 7, // @ C07_EVENT_FAKEWALL 51 kDMEventTypeTeleporter = 8, // @ C08_EVENT_TELEPORTER 52 kDMEventTypePit = 9, // @ C09_EVENT_PIT 53 kDMEventTypeDoor = 10, // @ C10_EVENT_DOOR 54 kDMEventTypeEnableChampionAction = 11, // @ C11_EVENT_ENABLE_CHAMPION_ACTION 55 kDMEventTypeHideDamageReceived = 12, // @ C12_EVENT_HIDE_DAMAGE_RECEIVED 56 kDMEventTypeViAltarRebirth = 13, // @ C13_EVENT_VI_ALTAR_REBIRTH 57 kDMEventTypePlaySound = 20, // @ C20_EVENT_PLAY_SOUND 58 kDMEventTypeCPSE = 22, // @ C22_EVENT_CPSE 59 kDMEventTypeRemoveFluxcage = 24, // @ C24_EVENT_REMOVE_FLUXCAGE 60 kDMEventTypeExplosion = 25, // @ C25_EVENT_EXPLOSION 61 kDMEventTypeGroupReactionDangerOnSquare = 29, // @ C29_EVENT_GROUP_REACTION_DANGER_ON_SQUARE 62 kDMEventTypeGroupReacionHitByProjectile = 30, // @ C30_EVENT_GROUP_REACTION_HIT_BY_PROJECTILE 63 kDMEventTypeGroupReactionPartyIsAdjecent = 31, // @ C31_EVENT_GROUP_REACTION_PARTY_IS_ADJACENT 64 kDMEventTypeUpdateAspectGroup = 32, // @ C32_EVENT_UPDATE_ASPECT_GROUP 65 /* Events = 33,-36 and = 38,-41 are used for individual creatures only while the group is attacking the party */ 66 kDMEventTypeUpdateAspectCreature0 = 33, // @ C33_EVENT_UPDATE_ASPECT_CREATURE_0 67 kDMEventTypeUpdateAspectCreature1 = 34, // @ C34_EVENT_UPDATE_ASPECT_CREATURE_1 68 kDMEventTypeUpdateAspectCreature2 = 35, // @ C35_EVENT_UPDATE_ASPECT_CREATURE_2 69 kDMEventTypeUpdateAspectCreature3 = 36, // @ C36_EVENT_UPDATE_ASPECT_CREATURE_3 70 kDMEventTypeUpdateBehaviourGroup = 37, // @ C37_EVENT_UPDATE_BEHAVIOR_GROUP 71 kDMEventTypeUpdateBehavior0 = 38, // @ C38_EVENT_UPDATE_BEHAVIOR_CREATURE_0 72 kDMEventTypeUpdateBehavior1 = 39, // @ C39_EVENT_UPDATE_BEHAVIOR_CREATURE_1 73 kDMEventTypeUpdateBehavior2 = 40, // @ C40_EVENT_UPDATE_BEHAVIOR_CREATURE_2 74 kDMEventTypeUpdateBehavior3 = 41, // @ C41_EVENT_UPDATE_BEHAVIOR_CREATURE_3 75 /* 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 */ 76 kDMEventTypeMoveProjectileIgnoreImpacts = 48, // @ C48_EVENT_MOVE_PROJECTILE_IGNORE_IMPACTS 77 /* Projectiles created by projectile launcher sensors never ignore impacts as well as all other projectiles after their first movement */ 78 kDMEventTypeMoveProjectile = 49, // @ C49_EVENT_MOVE_PROJECTILE 79 kDMEventTypeWatchdoge = 53, // @ C53_EVENT_WATCHDOG 80 kDMEventTypeMoveGroupSilent = 60, // @ C60_EVENT_MOVE_GROUP_SILENT 81 kDMEventTypeMoveGroupAudible = 61, // @ C61_EVENT_MOVE_GROUP_AUDIBLE 82 kDMEventTypeEnableGroupGenerator = 65, // @ C65_EVENT_ENABLE_GROUP_GENERATOR 83 kDMEventTypeLight = 70, // @ C70_EVENT_LIGHT 84 kDMEventTypeInvisibility = 71, // @ C71_EVENT_INVISIBILITY 85 kDMEventTypeChampionShield = 72, // @ C72_EVENT_CHAMPION_SHIELD 86 kDMEventTypeThievesEye = 73, // @ C73_EVENT_THIEVES_EYE 87 kDMEventTypePartyShield = 74, // @ C74_EVENT_PARTY_SHIELD 88 kDMEventTypePoisonChampion = 75, // @ C75_EVENT_POISON_CHAMPION 89 kDMEventTypeSpellShield = 77, // @ C77_EVENT_SPELLSHIELD 90 kDMEventTypeFireShield = 78, // @ C78_EVENT_FIRESHIELD 91 kDMEventTypeFootprints = 79, // @ C79_EVENT_FOOTPRINTS 92 kDMEventTypeMagicMap0 = 80, // @ C80_EVENT_MAGIC_MAP 93 kDMEventTypeMagicMap1 = 81, // @ C81_EVENT_MAGIC_MAP 94 kDMEventTypeMagicMap2 = 82, // @ C82_EVENT_MAGIC_MAP 95 kDMEventTypeMagicMap3 = 83 // @ C83_EVENT_MAGIC_MAP 96 }; 97 98 #define kDMMaskGeneratedCreatureCount 0x0007 // @ MASK0x0007_GENERATED_CREATURE_COUNT 99 #define kDMMaskRandomizeGeneratedCreatureCount 0x0008 // @ MASK0x0008_RANDOMIZE_GENERATED_CREATURE_COUNT 100 101 class TimelineEvent { 102 public: 103 int32 _mapTime; 104 TimelineEventType _type; 105 byte _priority; // CHECKME: byte? or int16? Inconsistency in the code 106 getTypePriority()107 uint16 getTypePriority() { return (_type << 8) + _priority; } 108 109 union B_unionTimelineEvent { 110 struct { 111 byte _mapX; 112 byte _mapY; 113 } _location; 114 int16 _attack; 115 int16 _defense; 116 int16 _lightPower; 117 uint16 _slot; // Thing 118 int16 _slotOrdinal; 119 }; 120 121 B_unionTimelineEvent _Bu; 122 getMapXY()123 int16 getMapXY() { return (_Bu._location._mapX << 8) + _Bu._location._mapY; } 124 125 union C_uionTimelineEvent { 126 struct { 127 byte _cell; 128 byte _effect; 129 } A; 130 131 class { 132 uint16 _backing; 133 public: getMapX()134 uint16 getMapX() { return _backing & 0x1F; } getMapY()135 uint16 getMapY() { return (_backing >> 5) & 0x1F; } getDir()136 Direction getDir() { return (Direction)((_backing >> 10) & 0x3); } getStepEnergy()137 uint16 getStepEnergy() { return (_backing >> 12) & 0xF; } setMapX(uint16 val)138 void setMapX(uint16 val) { _backing = (_backing & ~0x1F) | (val & 0x1F); } setMapY(uint16 val)139 void setMapY(uint16 val) { _backing = (_backing & ~(0x1F << 5)) | ((val & 0x1F) << 5); } setDir(Direction val)140 void setDir(Direction val) { _backing = (_backing & ~(0x3 << 10)) | ((val & 0x3) << 10); } setStepEnergy(uint16 val)141 void setStepEnergy(uint16 val) { _backing = (_backing & ~(0xF << 12)) | ((val & 0xF) << 12); } 142 } _projectile; 143 144 uint16 _slot; 145 int16 _soundIndex; 146 byte _ticks; 147 }; 148 149 C_uionTimelineEvent _Cu; 150 }; // @ EVENT 151 152 class Timeline { 153 DMEngine *_vm; 154 public: 155 uint16 _eventMaxCount; // @ G0369_ui_EventMaximumCount 156 TimelineEvent *_events; // @ G0370_ps_Events 157 uint16 _eventCount; // @ G0372_ui_EventCount 158 uint16 *_timeline; // @ G0371_pui_Timeline 159 uint16 _firstUnusedEventIndex; // @ G0373_ui_FirstUnusedEventIndex 160 161 explicit Timeline(DMEngine *vm); 162 ~Timeline(); 163 void initTimeline(); // @ F0233_TIMELINE_Initialize 164 void deleteEvent(uint16 eventIndex);// @ F0237_TIMELINE_DeleteEvent 165 void fixChronology(uint16 timelineIndex); // @ F0236_TIMELINE_FixChronology 166 bool isEventABeforeB(TimelineEvent *eventA, TimelineEvent *eventB); // @ F0234_TIMELINE_IsEventABeforeEventB 167 uint16 getIndex(uint16 eventIndex); // @ F0235_TIMELINE_GetIndex 168 uint16 addEventGetEventIndex(TimelineEvent *event); // @ F0238_TIMELINE_AddEvent_GetEventIndex_CPSE 169 void processTimeline(); // @ F0261_TIMELINE_Process_CPSEF 170 bool isFirstEventExpiered(); // @ F0240_TIMELINE_IsFirstEventExpired_CPSE 171 void extractFirstEvent(TimelineEvent *event); // @ F0239_TIMELINE_ExtractFirstEvent 172 void processEventDoorAnimation(TimelineEvent *event); // @ F0241_TIMELINE_ProcessEvent1_DoorAnimation 173 void processEventSquareFakewall(TimelineEvent *event); // @ F0242_TIMELINE_ProcessEvent7_Square_FakeWall 174 void processEventDoorDestruction(TimelineEvent *event); // @ F0243_TIMELINE_ProcessEvent2_DoorDestruction 175 void processEventSquareDoor(TimelineEvent *event); // @ F0244_TIMELINE_ProcessEvent10_Square_Door 176 void processEventSquarePit(TimelineEvent *event); // @ F0251_TIMELINE_ProcessEvent9_Square_Pit 177 void moveTeleporterOrPitSquareThings(uint16 mapX, uint16 mapY); // @ F0249_TIMELINE_MoveTeleporterOrPitSquareThings 178 void processEventSquareTeleporter(TimelineEvent *event); // @ F0250_TIMELINE_ProcessEvent8_Square_Teleporter 179 void processEventSquareWall(TimelineEvent *event); // @ F0248_TIMELINE_ProcessEvent6_Square_Wall 180 void triggerProjectileLauncher(Sensor *sensor, TimelineEvent *event); // @ F0247_TIMELINE_TriggerProjectileLauncher 181 void processEventSquareCorridor(TimelineEvent *event); // @ F0245_TIMELINE_ProcessEvent5_Square_Corridor 182 void processEventsMoveGroup(TimelineEvent *event); // @ F0252_TIMELINE_ProcessEvents60to61_MoveGroup 183 void procesEventEnableGroupGenerator(TimelineEvent *event); // @ F0246_TIMELINE_ProcessEvent65_EnableGroupGenerator 184 void processEventEnableChampionAction(uint16 champIndex); // @ F0253_TIMELINE_ProcessEvent11Part1_EnableChampionAction 185 void processEventMoveWeaponFromQuiverToSlot(uint16 champIndex, uint16 slotIndex);// @ F0259_TIMELINE_ProcessEvent11Part2_MoveWeaponFromQuiverToSlot 186 bool hasWeaponMovedSlot(int16 champIndex, Champion *champ, 187 uint16 sourceSlotIndex, int16 destSlotIndex); // @ F0258_TIMELINE_HasWeaponMovedToSlot 188 void processEventHideDamageReceived(uint16 champIndex); // @ F0254_TIMELINE_ProcessEvent12_HideDamageReceived 189 void processEventLight(TimelineEvent *event); // @ F0257_TIMELINE_ProcessEvent70_Light 190 void refreshAllChampionStatusBoxes(); // @ F0260_TIMELINE_RefreshAllChampionStatusBoxes 191 void processEventViAltarRebirth(TimelineEvent *event); // @ F0255_TIMELINE_ProcessEvent13_ViAltarRebirth 192 void saveEventsPart(Common::OutSaveFile *file); 193 void saveTimelinePart(Common::OutSaveFile *file); 194 void loadEventsPart(Common::InSaveFile *file); 195 void loadTimelinePart(Common::InSaveFile *file); 196 197 signed char _actionDefense[44]; // @ G0495_ac_Graphic560_ActionDefense 198 199 void initConstants(); 200 }; 201 202 } 203 204 #endif 205