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