1 #ifndef __PLATFORMS_H
2 #define __PLATFORMS_H
3 
4 /*
5 PLATFORMS.H
6 
7 	Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
8 	and the "Aleph One" developers.
9 
10 	This program is free software; you can redistribute it and/or modify
11 	it under the terms of the GNU General Public License as published by
12 	the Free Software Foundation; either version 3 of the License, or
13 	(at your option) any later version.
14 
15 	This program is distributed in the hope that it will be useful,
16 	but WITHOUT ANY WARRANTY; without even the implied warranty of
17 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 	GNU General Public License for more details.
19 
20 	This license is contained in the file "COPYING",
21 	which is included with this source code; it is available online at
22 	http://www.gnu.org/licenses/gpl.html
23 
24 Friday, July 15, 1994 3:42:39 PM
25 
26 Saturday, October 29, 1994 2:42:22 AM (Jason)
27 	razed.
28 
29 May 18, 2000 (Loren Petrich):
30 	Added XML-parser support
31 */
32 
33 #include "map.h"
34 
35 /* ---------- constants */
36 
37 // #define MAXIMUM_PLATFORMS_PER_MAP 64
38 
39 enum /* platform types */
40 {
41 	_platform_is_spht_door,
42 	_platform_is_spht_split_door,
43 	_platform_is_locked_spht_door,
44 	_platform_is_spht_platform,
45 	_platform_is_noisy_spht_platform,
46 	_platform_is_heavy_spht_door,
47 	_platform_is_pfhor_door,
48 	_platform_is_heavy_spht_platform,
49 	_platform_is_pfhor_platform,
50 
51 	NUMBER_OF_PLATFORM_TYPES
52 };
53 
54 enum /* platform speeds */
55 {
56 	_very_slow_platform= WORLD_ONE/(4*TICKS_PER_SECOND),
57 	_slow_platform= WORLD_ONE/(2*TICKS_PER_SECOND),
58 	_fast_platform= 2*_slow_platform,
59 	_very_fast_platform= 3*_slow_platform,
60 	_blindingly_fast_platform= 4*_slow_platform
61 };
62 
63 enum /* platform delays */
64 {
65 	_no_delay_platform= 0, /* use carefully; difficult to reincarnate on */
66 	_short_delay_platform= TICKS_PER_SECOND,
67 	_long_delay_platform= 2*TICKS_PER_SECOND,
68 	_very_long_delay_platform= 4*TICKS_PER_SECOND,
69 	_extremely_long_delay_platform= 8*TICKS_PER_SECOND
70 };
71 
72 enum /* static platform flags */
73 {
74 	_platform_is_initially_active, /* otherwise inactive */
75 	_platform_is_initially_extended, /* high for floor platforms, low for ceiling platforms, closed for two-way platforms */
76 	_platform_deactivates_at_each_level, /* this platform will deactivate each time it reaches a discrete level */
77 	_platform_deactivates_at_initial_level, /* this platform will deactivate upon returning to its original position */
78 	_platform_activates_adjacent_platforms_when_deactivating, /* when deactivating, this platform activates adjacent platforms */
79 	_platform_extends_floor_to_ceiling, /* i.e., there is no empty space when the platform is fully extended */
80 	_platform_comes_from_floor, /* platform rises from floor */
81 	_platform_comes_from_ceiling, /* platform lowers from ceiling */
82 	_platform_causes_damage, /* when obstructed by monsters, this platform causes damage */
83 	_platform_does_not_activate_parent, /* does not reactive it�s parent (i.e., that platform which activated it) */
84 	_platform_activates_only_once, /* cannot be activated a second time */
85 	_platform_activates_light, /* activates floor and ceiling lightsources while activating */
86 	_platform_deactivates_light, /* deactivates floor and ceiling lightsources while deactivating */
87 	_platform_is_player_controllable, /* i.e., door: players can use action key to change the state and/or direction of this platform */
88 	_platform_is_monster_controllable, /* i.e., door: monsters can expect to be able to move this platform even if inactive */
89 	_platform_reverses_direction_when_obstructed,
90 	_platform_cannot_be_externally_deactivated, /* when active, can only be deactivated by itself */
91 	_platform_uses_native_polygon_heights, /* complicated interpretation; uses native polygon heights during automatic min,max calculation */
92 	_platform_delays_before_activation, /* whether or not the platform begins with the maximum delay before moving */
93 	_platform_activates_adjacent_platforms_when_activating,
94 	_platform_deactivates_adjacent_platforms_when_activating,
95 	_platform_deactivates_adjacent_platforms_when_deactivating,
96 	_platform_contracts_slower,
97 	_platform_activates_adjacent_platforms_at_each_level,
98 	_platform_is_locked,
99 	_platform_is_secret,
100 	_platform_is_door,
101 	_platform_floods_m1,
102 	NUMBER_OF_STATIC_PLATFORM_FLAGS /* <=32 */
103 };
104 
105 #define PLATFORM_IS_INITIALLY_ACTIVE(p) TEST_FLAG32((p)->static_flags, _platform_is_initially_active)
106 #define PLATFORM_IS_INITIALLY_EXTENDED(p) TEST_FLAG32((p)->static_flags, _platform_is_initially_extended)
107 #define PLATFORM_IS_INITIALLY_CONTRACTED(p) (!PLATFORM_IS_INITIALLY_EXTENDED(p))
108 #define PLATFORM_EXTENDS_FLOOR_TO_CEILING(p) TEST_FLAG32((p)->static_flags, _platform_extends_floor_to_ceiling)
109 #define PLATFORM_COMES_FROM_FLOOR(p) TEST_FLAG32((p)->static_flags, _platform_comes_from_floor)
110 #define PLATFORM_COMES_FROM_CEILING(p) TEST_FLAG32((p)->static_flags, _platform_comes_from_ceiling)
111 #define PLATFORM_GOES_BOTH_WAYS(p) (PLATFORM_COMES_FROM_FLOOR(p)&&PLATFORM_COMES_FROM_CEILING(p))
112 #define PLATFORM_CAUSES_DAMAGE(p) TEST_FLAG32((p)->static_flags, _platform_causes_damage)
113 #define PLATFORM_REVERSES_DIRECTION_WHEN_OBSTRUCTED(p) TEST_FLAG32((p)->static_flags, _platform_reverses_direction_when_obstructed)
114 #define PLATFORM_ACTIVATES_ONLY_ONCE(p) TEST_FLAG32((p)->static_flags, _platform_activates_only_once)
115 #define PLATFORM_ACTIVATES_ADJACENT_PLATFORMS_WHEN_DEACTIVATING(p) TEST_FLAG32((p)->static_flags, _platform_activates_adjacent_platforms_when_deactivating)
116 #define PLATFORM_ACTIVATES_LIGHT(p) TEST_FLAG32((p)->static_flags, _platform_activates_light)
117 #define PLATFORM_DEACTIVATES_LIGHT(p) TEST_FLAG32((p)->static_flags, _platform_deactivates_light)
118 #define PLATFORM_DEACTIVATES_AT_EACH_LEVEL(p) TEST_FLAG32((p)->static_flags, _platform_deactivates_at_each_level)
119 #define PLATFORM_DEACTIVATES_AT_INITIAL_LEVEL(p) TEST_FLAG32((p)->static_flags, _platform_deactivates_at_initial_level)
120 #define PLATFORM_DOES_NOT_ACTIVATE_PARENT(p) TEST_FLAG32((p)->static_flags, _platform_does_not_activate_parent)
121 #define PLATFORM_IS_PLAYER_CONTROLLABLE(p) TEST_FLAG32((p)->static_flags, _platform_is_player_controllable)
122 #define PLATFORM_IS_MONSTER_CONTROLLABLE(p) TEST_FLAG32((p)->static_flags, _platform_is_monster_controllable)
123 #define PLATFORM_CANNOT_BE_EXTERNALLY_DEACTIVATED(p) TEST_FLAG32((p)->static_flags, _platform_cannot_be_externally_deactivated)
124 #define PLATFORM_USES_NATIVE_POLYGON_HEIGHTS(p) TEST_FLAG32((p)->static_flags, _platform_uses_native_polygon_heights)
125 #define PLATFORM_DELAYS_BEFORE_ACTIVATION(p) TEST_FLAG32((p)->static_flags, _platform_delays_before_activation)
126 #define PLATFORM_ACTIVATES_ADJACENT_PLATFORMS_WHEN_ACTIVATING(p) TEST_FLAG32((p)->static_flags, _platform_activates_adjacent_platforms_when_activating)
127 #define PLATFORM_DEACTIVATES_ADJACENT_PLATFORMS_WHEN_ACTIVATING(p) TEST_FLAG32((p)->static_flags, _platform_deactivates_adjacent_platforms_when_activating)
128 #define PLATFORM_DEACTIVATES_ADJACENT_PLATFORMS_WHEN_DEACTIVATING(p) TEST_FLAG32((p)->static_flags, _platform_deactivates_adjacent_platforms_when_deactivating)
129 #define PLATFORM_CONTRACTS_SLOWER(p) TEST_FLAG32((p)->static_flags, _platform_contracts_slower)
130 #define PLATFORM_ACTIVATES_ADJACENT_PLATFORMS_AT_EACH_LEVEL(p) TEST_FLAG32((p)->static_flags, _platform_activates_adjacent_platforms_at_each_level)
131 #define PLATFORM_IS_LOCKED(p) TEST_FLAG32((p)->static_flags, _platform_is_locked)
132 #define PLATFORM_IS_SECRET(p) TEST_FLAG32((p)->static_flags, _platform_is_secret)
133 #define PLATFORM_IS_DOOR(p) TEST_FLAG32((p)->static_flags, _platform_is_door)
134 #define PLATFORM_FLOODS_M1(p) TEST_FLAG32((p)->static_flags, _platform_floods_m1)
135 
136 #define SET_PLATFORM_IS_INITIALLY_ACTIVE(p, v) SET_FLAG32((p)->static_flags, _platform_is_initially_active, (v))
137 #define SET_PLATFORM_IS_INITIALLY_EXTENDED(p, v) SET_FLAG32((p)->static_flags, _platform_is_initially_extended, (v))
138 #define SET_PLATFORM_EXTENDS_FLOOR_TO_CEILING(p, v) SET_FLAG32((p)->static_flags, _platform_extends_floor_to_ceiling, (v))
139 #define SET_PLATFORM_COMES_FROM_FLOOR(p, v) SET_FLAG32((p)->static_flags, _platform_comes_from_floor, (v))
140 #define SET_PLATFORM_COMES_FROM_CEILING(p, v) SET_FLAG32((p)->static_flags, _platform_comes_from_ceiling, (v))
141 #define SET_PLATFORM_CAUSES_DAMAGE(p, v) SET_FLAG32((p)->static_flags, _platform_causes_damage, (v))
142 #define SET_PLATFORM_REVERSES_DIRECTION_WHEN_OBSTRUCTED(p, v) SET_FLAG32((p)->static_flags, _platform_reverses_direction_when_obstructed, (v))
143 #define SET_PLATFORM_ACTIVATES_ONLY_ONCE(p, v) SET_FLAG32((p)->static_flags, _platform_activates_only_once, (v))
144 #define SET_PLATFORM_ACTIVATES_ADJACENT_PLATFORMS_WHEN_DEACTIVATING(p, v) SET_FLAG32((p)->static_flags, _platform_activates_adjacent_platforms_when_deactivating, (v))
145 #define SET_PLATFORM_ACTIVATES_LIGHT(p, v) SET_FLAG32((p)->static_flags, _platform_activates_light, (v))
146 #define SET_PLATFORM_DEACTIVATES_LIGHT(p, v) SET_FLAG32((p)->static_flags, _platform_deactivates_light, (v))
147 #define SET_PLATFORM_DEACTIVATES_AT_EACH_LEVEL(p, v) SET_FLAG32((p)->static_flags, _platform_deactivates_at_each_level, (v))
148 #define SET_PLATFORM_DEACTIVATES_AT_INITIAL_LEVEL(p, v) SET_FLAG32((p)->static_flags, _platform_deactivates_at_initial_level, (v))
149 #define SET_PLATFORM_DOES_NOT_ACTIVATE_PARENT(p, v) SET_FLAG32((p)->static_flags, _platform_does_not_activate_parent, (v))
150 #define SET_PLATFORM_IS_PLAYER_CONTROLLABLE(p, v) SET_FLAG32((p)->static_flags, _platform_is_player_controllable, (v))
151 #define SET_PLATFORM_IS_MONSTER_CONTROLLABLE(p, v) SET_FLAG32((p)->static_flags, _platform_is_monster_controllable, (v))
152 #define SET_PLATFORM_CANNOT_BE_EXTERNALLY_DEACTIVATED(p, v) SET_FLAG32((p)->static_flags, _platform_cannot_be_externally_deactivated, (v))
153 #define SET_PLATFORM_USES_NATIVE_POLYGON_HEIGHTS(p, v) SET_FLAG32((p)->static_flags, _platform_uses_native_polygon_heights, (v))
154 #define SET_PLATFORM_DELAYS_BEFORE_ACTIVATION(p, v) SET_FLAG32((p)->static_flags, _platform_delays_before_activation, (v))
155 #define SET_PLATFORM_ACTIVATES_ADJACENT_PLATFORMS_WHEN_ACTIVATING(p, v) SET_FLAG32((p)->static_flags, _platform_activates_adjacent_platforms_when_activating, (v))
156 #define SET_PLATFORM_DEACTIVATES_ADJACENT_PLATFORMS_WHEN_ACTIVATING(p, v) SET_FLAG32((p)->static_flags, _platform_deactivates_adjacent_platforms_when_activating, (v))
157 #define SET_PLATFORM_DEACTIVATES_ADJACENT_PLATFORMS_WHEN_DEACTIVATING(p, v) SET_FLAG32((p)->static_flags, _platform_deactivates_adjacent_platforms_when_deactivating, (v))
158 #define SET_PLATFORM_CONTRACTS_SLOWER(p, v) SET_FLAG32((p)->static_flags, _platform_contracts_slower, (v))
159 #define SET_PLATFORM_ACTIVATES_ADJACENT_PLATFORMS_AT_EACH_LEVEL(p, v) SET_FLAG32((p)->static_flags, _platform_activates_adjacent_platforms_at_each_level, (v))
160 #define SET_PLATFORM_IS_LOCKED(p, v) SET_FLAG32((p)->static_flags, _platform_is_locked, (v))
161 #define SET_PLATFORM_IS_SECRET(p, v) SET_FLAG32((p)->static_flags, _platform_is_secret, (v))
162 #define SET_PLATFORM_IS_DOOR(p, v) SET_FLAG32((p)->static_flags, _platform_is_door, (v))
163 #define SET_PLATFORM_FLOODS_M1(p, v) SET_FLAG32((p)->static_flags, _platform_floods_m1, (v))
164 
165 enum /* dynamic platform flags */
166 {
167 	_platform_is_active, /* otherwise inactive */
168 	_platform_is_extending, /* otherwise contracting; could be waiting between levels */
169 	_platform_is_moving, /* otherwise at rest (waiting between levels) */
170 	_platform_has_been_activated, /* in case we can only be activated once */
171 	_platform_was_moving, /* the platform moved unobstructed last tick */
172 	_platform_is_fully_extended,
173 	_platform_is_fully_contracted,
174 	_platform_was_just_activated_or_deactivated,
175 	_platform_floor_below_media,
176 	_platform_ceiling_below_media,
177 	NUMBER_OF_DYNAMIC_PLATFORM_FLAGS /* <=16 */
178 };
179 
180 #define PLATFORM_IS_ACTIVE(p) TEST_FLAG16((p)->dynamic_flags, _platform_is_active)
181 #define PLATFORM_IS_EXTENDING(p) TEST_FLAG16((p)->dynamic_flags, _platform_is_extending)
182 #define PLATFORM_IS_CONTRACTING(p) (!PLATFORM_IS_EXTENDING(p))
183 #define PLATFORM_IS_MOVING(p) TEST_FLAG16((p)->dynamic_flags, _platform_is_moving)
184 #define PLATFORM_HAS_BEEN_ACTIVATED(p) TEST_FLAG16((p)->dynamic_flags, _platform_has_been_activated)
185 #define PLATFORM_WAS_MOVING(p) TEST_FLAG16((p)->dynamic_flags, _platform_was_moving)
186 #define PLATFORM_IS_FULLY_EXTENDED(p) TEST_FLAG16((p)->dynamic_flags, _platform_is_fully_extended)
187 #define PLATFORM_IS_FULLY_CONTRACTED(p) TEST_FLAG16((p)->dynamic_flags, _platform_is_fully_contracted)
188 #define PLATFORM_WAS_JUST_ACTIVATED_OR_DEACTIVATED(p) TEST_FLAG16((p)->dynamic_flags, _platform_was_just_activated_or_deactivated)
189 #define PLATFORM_FLOOR_BELOW_MEDIA(p) TEST_FLAG16((p)->dynamic_flags, _platform_floor_below_media)
190 #define PLATFORM_CEILING_BELOW_MEDIA(p) TEST_FLAG16((p)->dynamic_flags, _platform_ceiling_below_media)
191 
192 #define SET_PLATFORM_IS_ACTIVE(p, v) SET_FLAG16((p)->dynamic_flags, _platform_is_active, (v))
193 #define SET_PLATFORM_IS_EXTENDING(p) SET_FLAG16((p)->dynamic_flags, _platform_is_extending, true)
194 #define SET_PLATFORM_IS_CONTRACTING(p) SET_FLAG16((p)->dynamic_flags, _platform_is_extending, false)
195 #define SET_PLATFORM_IS_MOVING(p, v) SET_FLAG16((p)->dynamic_flags, _platform_is_moving, (v))
196 #define SET_PLATFORM_HAS_BEEN_ACTIVATED(p) SET_FLAG16((p)->dynamic_flags, _platform_has_been_activated, true)
197 #define SET_PLATFORM_WAS_MOVING(p) SET_FLAG16((p)->dynamic_flags, _platform_was_moving, true)
198 #define SET_PLATFORM_WAS_BLOCKED(p) SET_FLAG16((p)->dynamic_flags, _platform_was_moving, false)
199 #define SET_PLATFORM_IS_FULLY_EXTENDED(p) SET_FLAG16((p)->dynamic_flags, _platform_is_fully_extended, true)
200 #define SET_PLATFORM_IS_FULLY_CONTRACTED(p) SET_FLAG16((p)->dynamic_flags, _platform_is_fully_contracted, true)
201 #define CLEAR_PLATFORM_POSITIONING_FLAGS(p) SET_FLAG16((p)->dynamic_flags, _platform_is_fully_contracted, false), SET_FLAG16((p)->dynamic_flags, _platform_is_fully_extended, false)
202 #define SET_PLATFORM_WAS_JUST_ACTIVATED_OR_DEACTIVATED(p) SET_FLAG16((p)->dynamic_flags, _platform_was_just_activated_or_deactivated, true)
203 #define CLEAR_PLATFORM_WAS_JUST_ACTIVATED_OR_DEACTIVATED(p) SET_FLAG16((p)->dynamic_flags, _platform_was_just_activated_or_deactivated, false)
204 #define SET_PLATFORM_FLOOR_BELOW_MEDIA(p, v) SET_FLAG16((p)->dynamic_flags, _platform_floor_below_media, v)
205 #define SET_PLATFORM_CEILING_BELOW_MEDIA(p, v) SET_FLAG16((p)->dynamic_flags, _platform_ceiling_below_media, v)
206 
207 // using "fully contracted" is close enough to act like Marathon... I hope
208 #define PLATFORM_IS_FLOODED(p) (PLATFORM_FLOODS_M1(p) && PLATFORM_IS_FULLY_CONTRACTED(p))
209 
210 struct endpoint_owner_data
211 {
212 	int16 first_polygon_index, polygon_index_count;
213 	int16 first_line_index, line_index_count;
214 };
215 
216 struct static_platform_data /* size platform-dependant */
217 {
218 	int16 type;
219 	int16 speed, delay;
220 	world_distance maximum_height, minimum_height; /* if NONE then calculated in some reasonable way */
221 
222 	uint32 static_flags;
223 
224 	int16 polygon_index;
225 
226 	int16 tag;
227 
228 	int16 unused[7];
229 };
230 const int SIZEOF_static_platform_data = 32;
231 
232 struct platform_data /* 140 bytes */
233 {
234 	int16 type;
235 	uint32 static_flags;
236 	int16 speed, delay;
237 	world_distance minimum_floor_height, maximum_floor_height;
238 	world_distance minimum_ceiling_height, maximum_ceiling_height;
239 
240 	int16 polygon_index;
241 
242 	uint16 dynamic_flags;
243 	world_distance floor_height, ceiling_height;
244 	int16 ticks_until_restart; /* if we�re not moving but are active, this is our delay until we move again */
245 
246 	struct endpoint_owner_data endpoint_owners[MAXIMUM_VERTICES_PER_POLYGON];
247 
248 	int16 parent_platform_index; /* the platform_index which activated us, if any */
249 
250 	int16 tag;
251 
252 	int16 unused[22];
253 };
254 const int SIZEOF_platform_data = 140;
255 
256 /* --------- globals */
257 
258 // Turned the list of platforms into a variable array;
259 // took over their maximum number as how many of them
260 
261 extern vector<platform_data> PlatformList;
262 #define platforms (PlatformList.data())
263 #define MAXIMUM_PLATFORMS_PER_MAP (PlatformList.size())
264 
265 // extern struct platform_data *platforms;
266 
267 /* --------- prototypes/PLATFORMS.C */
268 
269 short new_platform(struct static_platform_data *data, short polygon_index, short version);
270 struct static_platform_data *get_defaults_for_platform_type(short type);
271 
272 void update_platforms(void);
273 
274 void platform_was_entered(short platform_index, bool player);
275 
276 bool try_and_change_platform_state(short platform_index, bool state);
277 bool try_and_change_tagged_platform_states(short tag, bool state);
278 
279 enum /* return values from monster_can_enter_platform() and monster_can_leave_platform() */
280 {
281 	_platform_will_never_be_accessable,
282 	_platform_will_be_accessable,
283 	_platform_might_be_accessable,
284 	_platform_is_accessable,
285 
286 	_exit_will_never_be_accessable,
287 	_exit_will_be_accessable,
288 	_exit_might_be_accessable,
289 	_exit_is_accessable
290 };
291 short monster_can_enter_platform(short platform_index, short source_polygon_index, world_distance height, world_distance minimum_ledge_delta, world_distance maximum_ledge_delta);
292 short monster_can_leave_platform(short platform_index, short destination_polygon_index, world_distance height, world_distance minimum_ledge_delta, world_distance maximum_ledge_delta);
293 
294 bool platform_is_on(short platform_index);
295 
296 void adjust_platform_for_media(short platform_index, bool initialize);
297 void adjust_platform_endpoint_and_line_heights(short platform_index);
298 
299 void player_touch_platform_state(short player_index, short platform_index);
300 bool platform_is_legal_player_target(short platform_index);
301 
302 bool platform_is_at_initial_state(short platform_index);
303 
304 short get_platform_moving_sound(short platform_index);
305 
306 platform_data *get_platform_data(
307 	short platform_index);
308 
309 // LP: to pack and unpack this data;
310 // these do not make the definitions visible to the outside world
311 
312 uint8 *unpack_static_platform_data(uint8 *Stream, static_platform_data *Objects, size_t Count);
313 uint8 *pack_static_platform_data(uint8 *Stream, static_platform_data *Objects, size_t Count);
314 uint8 *unpack_platform_data(uint8 *Stream, platform_data *Objects, size_t Count);
315 uint8 *pack_platform_data(uint8 *Stream, platform_data *Objects, size_t Count);
316 
317 class InfoTree;
318 void parse_mml_platforms(const InfoTree& root);
319 void reset_mml_platforms();
320 
321 #endif
322