1 /*
2 PLATFORMS.C
3
4 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5 and the "Aleph One" developers.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (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 This license is contained in the file "COPYING",
18 which is included with this source code; it is available online at
19 http://www.gnu.org/licenses/gpl.html
20
21 Saturday, April 30, 1994 1:18:29 AM
22
23 Friday, September 16, 1994 7:50:32 PM (alain)
24 fixed update_polygon_endpoint_data_for_height_change() so that it actually
25 calculates highest_adjacent_floor and lowest_adjacent_ceiling correctly.
26 Saturday, September 17, 1994 6:04:11 PM (alain)
27 added _one_stop_platform which moves one level, then won't move until you get off and back on.
28 Saturday, October 29, 1994 2:42:22 AM (Jason)
29 razed.
30 Saturday, November 5, 1994 2:53:39 PM (Jason)
31 added _platform_cannot_be_externally_deactivated.
32 Sunday, November 6, 1994 8:31:29 PM (Jason)
33 added _platform_uses_native_polygon_heights.
34 Tuesday, November 15, 1994 11:36:37 PM (Jason)
35 fixed recursive activates/deactivates; added flooding.
36 Wednesday, May 3, 1995 4:37:18 PM (Jason)
37 updates endpoint transparency correctly.
38 Friday, June 9, 1995 11:43:11 AM (Jason')
39 keys.
40 Tuesday, July 11, 1995 11:32:46 AM (Jason)
41 media sounds.
42
43 Feb. 4, 2000 (Loren Petrich):
44 Changed halt() to assert(false) for better debugging
45
46 Feb 25, 2000 (Loren Petrich):
47 Suppressed consistency check for platform extrema in calculate_platform_extrema()
48 as possibly unnecessary
49
50 May 17, 2000 (Loren Petrich):
51 Added XML support, including a damage parser
52
53 Dec 19, 2000 (Loren Petrich):
54 Suppressed assertion that a platform polygon must have at least one moving surface;
55 this is for compatibility with some Pfhorte maps like "Descent". Also, added softer
56 failure mode for get_platform_definition().
57 Also suppressed an assertion that platform[polygon[platform]] = platform;
58 currently handling failure in that by skipping over the platform.
59
60 Jun 30, 2002 (tiennou):
61 Added support for Pfhortran Procedure: platform_activated
62 */
63
64 #include <string.h>
65 #include "cseries.h"
66
67 #include "world.h"
68 #include "map.h"
69 #include "platforms.h"
70 #include "lightsource.h"
71 #include "SoundManager.h"
72 #include "player.h"
73 #include "media.h"
74 #include "InfoTree.h"
75
76 // LP addition: XML parser for damage
77 #include "items.h"
78 #include "Packing.h"
79
80 //MH: Lua scripting
81 #include "lua_script.h"
82
83 #include <string.h>
84
85 #include "editor.h" // MARATHON_ONE_DATA_VERSION
86
87 /*
88 //opening sounds made by closed platforms are sometimes obscured
89 */
90
91 /* ---------- constants */
92
93 /* ---------- structures */
94
95 /* ---------- globals */
96
97 #include "platform_definitions.h"
98
99 /* ---------- private prototypes */
100
101 static short polygon_index_to_platform_index(short polygon_index);
102
103 bool set_platform_state(short platform_index, bool state, short parent_platform_index);
104 static void set_adjacent_platform_states(short platform_index, bool state);
105
106 static void take_out_the_garbage(short platform_index);
107 static void adjust_platform_sides(short platform_index, world_distance old_ceiling_height, world_distance new_ceiling_height);
108 static void calculate_platform_extrema(short platform_index, world_distance lowest_level,
109 world_distance highest_level);
110
111 static void play_platform_sound(short platform_index, short sound_code);
112
113 static platform_definition *get_platform_definition(const short type);
114
115 /* ---------- code */
116
get_platform_data(short platform_index)117 platform_data *get_platform_data(
118 short platform_index)
119 {
120 struct platform_data *platform = GetMemberWithBounds(platforms,platform_index,dynamic_world->platform_count);
121
122 vassert(platform, csprintf(temporary, "platform index #%d is out of range", platform_index));
123
124 return platform;
125 }
126
get_platform_definition(const short type)127 platform_definition *get_platform_definition(const short type)
128 {
129 return GetMemberWithBounds(platform_definitions,type,NUMBER_OF_PLATFORM_TYPES);
130 }
131
132
new_platform(struct static_platform_data * data,short polygon_index,short version)133 short new_platform(
134 struct static_platform_data *data,
135 short polygon_index,
136 short version)
137 {
138 short platform_index= NONE;
139 struct platform_data *platform;
140
141 assert(NUMBER_OF_DYNAMIC_PLATFORM_FLAGS<=16);
142 assert(NUMBER_OF_STATIC_PLATFORM_FLAGS<=32);
143 // LP: OK for a platform to be a do-nothing platform
144 // assert(data->static_flags&(FLAG(_platform_comes_from_floor)|FLAG(_platform_comes_from_ceiling)));
145
146 if (dynamic_world->platform_count<int(MAXIMUM_PLATFORMS_PER_MAP))
147 {
148 struct polygon_data *polygon= get_polygon_data(polygon_index);
149 short i;
150
151 platform_index= dynamic_world->platform_count++;
152 platform= platforms+platform_index;
153
154 /* remember the platform_index in the polygon�s .permutation field */
155 polygon->permutation= platform_index;
156 polygon->type= _polygon_is_platform;
157
158 /* initialize the platform */
159 platform->type= data->type;
160 platform->static_flags= data->static_flags;
161 platform->tag= data->tag;
162 platform->speed= data->speed;
163 platform->delay= data->delay;
164 platform->polygon_index= polygon_index;
165 platform->parent_platform_index= NONE;
166 calculate_platform_extrema(platform_index, data->minimum_height, data->maximum_height);
167
168 if (version == MARATHON_ONE_DATA_VERSION)
169 {
170 switch (platform->type)
171 {
172 case 0: // marathon door
173 case 3: // pfhor door
174 SET_PLATFORM_IS_DOOR(platform, true);
175 break;
176 }
177
178 if (PLATFORM_IS_LOCKED(platform))
179 {
180 SET_PLATFORM_IS_LOCKED(platform, false);
181 SET_PLATFORM_FLOODS_M1(platform, true);
182 }
183 }
184
185 #if 0
186 switch (platform->type)
187 {
188 case _platform_is_spht_door:
189 case _platform_is_spht_split_door:
190 case _platform_is_locked_spht_door:
191 case _platform_is_pfhor_door:
192 SET_PLATFORM_IS_DOOR(platform, true);
193 break;
194 }
195 #endif
196
197 /* stuff in the correct defaults; if the platform is initially active it begins moving
198 immediately */
199 platform->dynamic_flags= 0;
200 platform->floor_height= polygon->floor_height;
201 platform->ceiling_height= polygon->ceiling_height;
202 if (PLATFORM_IS_INITIALLY_ACTIVE(platform))
203 {
204 SET_PLATFORM_IS_ACTIVE(platform, true);
205 SET_PLATFORM_HAS_BEEN_ACTIVATED(platform);
206 SET_PLATFORM_IS_MOVING(platform, true);
207 }
208 if (PLATFORM_IS_INITIALLY_EXTENDED(platform))
209 {
210 if (PLATFORM_COMES_FROM_FLOOR(platform)) platform->floor_height= platform->maximum_floor_height;
211 if (PLATFORM_COMES_FROM_CEILING(platform)) platform->ceiling_height= platform->minimum_ceiling_height;
212 SET_PLATFORM_IS_CONTRACTING(platform);
213 SET_PLATFORM_IS_FULLY_EXTENDED(platform);
214 }
215 else
216 {
217 if (PLATFORM_COMES_FROM_FLOOR(platform)) platform->floor_height= platform->minimum_floor_height;
218 if (PLATFORM_COMES_FROM_CEILING(platform)) platform->ceiling_height= platform->maximum_ceiling_height;
219 SET_PLATFORM_IS_EXTENDING(platform);
220 SET_PLATFORM_IS_FULLY_CONTRACTED(platform);
221 }
222
223 /* remember what polygons and lines are adjacent to the endpoints of the platform
224 polygon so we can quickly recalculate heights later */
225 for (i= 0; i<polygon->vertex_count; ++i)
226 {
227 calculate_endpoint_polygon_owners(polygon->endpoint_indexes[i], &platform->endpoint_owners[i].first_polygon_index,
228 &platform->endpoint_owners[i].polygon_index_count);
229 calculate_endpoint_line_owners(polygon->endpoint_indexes[i], &platform->endpoint_owners[i].first_line_index,
230 &platform->endpoint_owners[i].line_index_count);
231 }
232
233 polygon->floor_height= platform->floor_height;
234 polygon->ceiling_height= platform->ceiling_height;
235 adjust_platform_endpoint_and_line_heights(platform_index);
236 adjust_platform_for_media(platform_index, true);
237 }
238
239 return platform_index;
240 }
241
get_defaults_for_platform_type(short type)242 struct static_platform_data *get_defaults_for_platform_type(
243 short type)
244 {
245 struct platform_definition *definition= get_platform_definition(type);
246 // Fallback for out-of-range type
247 if (!definition) definition = get_platform_definition(0);
248
249 return &definition->defaults;
250 }
251
update_platforms(void)252 void update_platforms(
253 void)
254 {
255 short platform_index;
256 struct platform_data *platform;
257
258 for (platform_index= 0, platform= platforms; platform_index<dynamic_world->platform_count; ++platform_index, ++platform)
259 {
260 CLEAR_PLATFORM_WAS_JUST_ACTIVATED_OR_DEACTIVATED(platform);
261
262 if (PLATFORM_IS_ACTIVE(platform))
263 {
264 struct polygon_data *polygon= get_polygon_data(platform->polygon_index);
265 short sound_code= NONE;
266 bool was_flooded = PLATFORM_IS_FLOODED(platform);
267
268 // Should there be some warning message about platform-polygon inconsistences?
269 // assert(polygon->permutation==platform_index);
270 if (!(polygon->permutation==platform_index)) continue;
271
272 if (!PLATFORM_IS_MOVING(platform))
273 {
274 /* waiting to move */
275 if ((platform->ticks_until_restart-= 1)<=0)
276 {
277 SET_PLATFORM_IS_MOVING(platform, true);
278 sound_code= _starting_sound;
279 }
280 }
281
282 if (PLATFORM_IS_MOVING(platform))
283 {
284 struct platform_definition *definition= get_platform_definition(platform->type);
285 if (!definition) continue;
286 world_distance new_floor_height= platform->floor_height, new_ceiling_height= platform->ceiling_height;
287 world_distance delta_height= PLATFORM_IS_EXTENDING(platform) ? platform->speed :
288 (PLATFORM_CONTRACTS_SLOWER(platform) ? (-(platform->speed>>2)) : -platform->speed);
289
290 /* adjust and pin heights: if we think we�re fully contracted or expanded, make
291 sure our heights reflect that (we don�t want a split platform to have blank
292 space between it because it didn�t quite close all the way) */
293 CLEAR_PLATFORM_POSITIONING_FLAGS(platform);
294 if (PLATFORM_COMES_FROM_FLOOR(platform))
295 {
296 new_floor_height+= delta_height;
297 if (new_floor_height>=platform->maximum_floor_height)
298 SET_PLATFORM_IS_FULLY_EXTENDED(platform);
299 if (new_floor_height<=platform->minimum_floor_height)
300 SET_PLATFORM_IS_FULLY_CONTRACTED(platform);
301 }
302 if (PLATFORM_COMES_FROM_CEILING(platform))
303 {
304 new_ceiling_height-= delta_height;
305 if (new_ceiling_height>=platform->maximum_ceiling_height)
306 SET_PLATFORM_IS_FULLY_CONTRACTED(platform);
307 if (new_ceiling_height<=platform->minimum_ceiling_height)
308 SET_PLATFORM_IS_FULLY_EXTENDED(platform);
309 }
310 if (PLATFORM_IS_FULLY_EXTENDED(platform))
311 {
312 if (PLATFORM_COMES_FROM_FLOOR(platform)) new_floor_height= platform->maximum_floor_height;
313 if (PLATFORM_COMES_FROM_CEILING(platform)) new_ceiling_height= platform->minimum_ceiling_height;
314 }
315 if (PLATFORM_IS_FULLY_CONTRACTED(platform))
316 {
317 if (PLATFORM_COMES_FROM_FLOOR(platform)) new_floor_height= platform->minimum_floor_height;
318 if (PLATFORM_COMES_FROM_CEILING(platform)) new_ceiling_height= platform->maximum_ceiling_height;
319 }
320
321 /* calculate new ceiling and floor heights for the platform polygon and see if
322 the change is obstructed */
323 if (change_polygon_height(platform->polygon_index, new_floor_height, new_ceiling_height,
324 PLATFORM_CAUSES_DAMAGE(platform) ? &definition->damage : (struct damage_definition *) NULL))
325 {
326 /* if we weren�t blocked, remember that we moved last time, change our current
327 level, adjust the textures if we�re coming down from the ceiling,
328 and finally adjust the heights of all endpoints and lines which make
329 up our polygon to reflect the height change */
330 if (PLATFORM_COMES_FROM_CEILING(platform))
331 adjust_platform_sides(platform_index, platform->ceiling_height, new_ceiling_height);
332 platform->ceiling_height= new_ceiling_height, platform->floor_height= new_floor_height;
333 SET_PLATFORM_WAS_MOVING(platform);
334 adjust_platform_endpoint_and_line_heights(platform_index);
335 adjust_platform_for_media(platform_index, false);
336 }
337 else
338 {
339 /* if we were blocked, play a sound if we weren�t blocked last time and reverse
340 directions if we�re supposed to */
341 if (PLATFORM_WAS_MOVING(platform)) sound_code= _obstructed_sound;
342 if (PLATFORM_REVERSES_DIRECTION_WHEN_OBSTRUCTED(platform))
343 {
344 PLATFORM_IS_EXTENDING(platform) ?
345 SET_PLATFORM_IS_CONTRACTING(platform) :
346 SET_PLATFORM_IS_EXTENDING(platform);
347 }
348 else
349 {
350 SET_PLATFORM_WAS_BLOCKED(platform);
351 }
352 }
353
354 if (PLATFORM_IS_FULLY_EXTENDED(platform) || PLATFORM_IS_FULLY_CONTRACTED(platform))
355 {
356 bool deactivate= false;
357
358 SET_PLATFORM_IS_MOVING(platform, false);
359 platform->ticks_until_restart= platform->delay;
360 sound_code= _stopping_sound;
361
362 /* handle changing directions at extremes and deactivating if necessary */
363 if (PLATFORM_IS_FULLY_CONTRACTED(platform))
364 {
365 if (PLATFORM_IS_INITIALLY_CONTRACTED(platform) && PLATFORM_DEACTIVATES_AT_INITIAL_LEVEL(platform))
366 deactivate= true;
367 SET_PLATFORM_IS_EXTENDING(platform);
368 }
369 else
370 {
371 if (PLATFORM_IS_FULLY_EXTENDED(platform))
372 {
373 if (platform->floor_height==platform->ceiling_height)
374 take_out_the_garbage(platform_index);
375 if (PLATFORM_IS_INITIALLY_EXTENDED(platform)
376 && PLATFORM_DEACTIVATES_AT_INITIAL_LEVEL(platform))
377 deactivate= true;
378 SET_PLATFORM_IS_CONTRACTING(platform);
379 }
380 else
381 {
382 assert(false);
383 }
384 }
385 if (PLATFORM_DEACTIVATES_AT_EACH_LEVEL(platform)) deactivate= true;
386
387 if (PLATFORM_ACTIVATES_ADJACENT_PLATFORMS_AT_EACH_LEVEL(platform)) set_adjacent_platform_states(platform_index, true);
388 if (deactivate) set_platform_state(platform_index, false, NONE);
389 }
390 }
391
392 if (sound_code!=NONE) play_platform_sound(platform_index, sound_code);
393
394 if (was_flooded != PLATFORM_IS_FLOODED(platform))
395 {
396 // flood status changed - update side lights
397 // FIXME: this assumes Marathon 1 map lighting
398 for (int i = 0; i < polygon->vertex_count; i++)
399 {
400 short side_index = polygon->side_indexes[i];
401 if (side_index == NONE) continue;
402 guess_side_lightsource_indexes(side_index);
403 }
404 }
405 }
406 }
407 }
408
platform_is_on(short platform_index)409 bool platform_is_on(
410 short platform_index)
411 {
412 struct platform_data *platform;
413
414 platform= get_platform_data(platform_index);
415
416 return PLATFORM_IS_ACTIVE(platform) ? true : false;
417 }
418
monster_can_enter_platform(short platform_index,short source_polygon_index,world_distance height,world_distance minimum_ledge_delta,world_distance maximum_ledge_delta)419 short monster_can_enter_platform(
420 short platform_index,
421 short source_polygon_index,
422 world_distance height,
423 world_distance minimum_ledge_delta,
424 world_distance maximum_ledge_delta)
425 {
426 struct polygon_data *source_polygon= get_polygon_data(source_polygon_index);
427 struct platform_data *platform= get_platform_data(platform_index);
428 struct polygon_data *destination_polygon= get_polygon_data(platform->polygon_index);
429 world_distance destination_floor_height= destination_polygon->floor_height;
430 world_distance destination_ceiling_height= destination_polygon->ceiling_height;
431 world_distance delta_height;
432 short result_code= _platform_is_accessable;
433
434 if (PLATFORM_IS_DOOR(platform))
435 {
436 if (PLATFORM_IS_MONSTER_CONTROLLABLE(platform) && platform->delay>=_short_delay_platform)
437 {
438 destination_floor_height= platform->minimum_floor_height;
439 destination_ceiling_height= platform->maximum_ceiling_height;
440
441 result_code= PLATFORM_IS_FULLY_CONTRACTED(platform) ? _platform_is_accessable : _platform_will_be_accessable;
442 }
443 }
444 else
445 {
446 if (PLATFORM_IS_ACTIVE(platform) && PLATFORM_COMES_FROM_FLOOR(platform) && !PLATFORM_COMES_FROM_CEILING(platform))
447 {
448 /* if this platform doesn�t go floor to ceiling and it stops at the source polygon, it might be ok */
449 if (platform->maximum_floor_height!=platform->minimum_ceiling_height &&
450 (platform->minimum_floor_height==source_polygon->floor_height ||
451 platform->maximum_floor_height==source_polygon->floor_height))
452 {
453 if (platform->minimum_floor_height==source_polygon->floor_height)
454 {
455 destination_floor_height= platform->minimum_floor_height;
456 destination_ceiling_height= platform->maximum_ceiling_height;
457 }
458 else
459 {
460 destination_floor_height= platform->maximum_floor_height;
461 destination_ceiling_height= platform->minimum_ceiling_height;
462 }
463 result_code= (platform->floor_height==source_polygon->floor_height) ? _platform_is_accessable : _platform_will_be_accessable;
464 }
465 }
466 }
467
468 delta_height= destination_floor_height-source_polygon->floor_height;
469 if (delta_height<minimum_ledge_delta || delta_height>maximum_ledge_delta ||
470 MIN(destination_ceiling_height, source_polygon->ceiling_height) - MAX(destination_floor_height, source_polygon->floor_height)<height)
471 {
472 result_code= _platform_will_never_be_accessable;
473 }
474
475 return result_code;
476 }
477
monster_can_leave_platform(short platform_index,short destination_polygon_index,world_distance height,world_distance minimum_ledge_delta,world_distance maximum_ledge_delta)478 short monster_can_leave_platform(
479 short platform_index,
480 short destination_polygon_index,
481 world_distance height,
482 world_distance minimum_ledge_delta,
483 world_distance maximum_ledge_delta) /* negative */
484 {
485 struct polygon_data *destination_polygon= get_polygon_data(destination_polygon_index);
486 struct platform_data *platform= get_platform_data(platform_index);
487 struct polygon_data *source_polygon= get_polygon_data(platform->polygon_index);
488 world_distance source_floor_height= source_polygon->floor_height;
489 world_distance source_ceiling_height= source_polygon->ceiling_height;
490 world_distance delta_height;
491 short result_code= _exit_is_accessable;
492
493 if (PLATFORM_IS_DOOR(platform))
494 {
495 source_floor_height= platform->minimum_floor_height;
496 source_ceiling_height= platform->maximum_ceiling_height;
497 }
498 else
499 {
500 if (PLATFORM_IS_ACTIVE(platform) && PLATFORM_COMES_FROM_FLOOR(platform) && !PLATFORM_COMES_FROM_CEILING(platform))
501 {
502 if (platform->minimum_floor_height==destination_polygon->floor_height ||
503 platform->maximum_floor_height==destination_polygon->floor_height)
504 {
505 source_floor_height= destination_polygon->floor_height;
506 result_code= (platform->floor_height==destination_polygon->floor_height) ? _exit_is_accessable : _exit_will_be_accessable;
507 }
508 }
509 }
510
511 delta_height= destination_polygon->floor_height-source_floor_height;
512 if (delta_height<minimum_ledge_delta || delta_height>maximum_ledge_delta ||
513 MIN(destination_polygon->ceiling_height, source_ceiling_height) - MAX(destination_polygon->floor_height, source_floor_height)<height)
514 {
515 result_code= _exit_will_never_be_accessable;
516 }
517
518 return result_code;
519 }
520
player_touch_platform_state(short player_index,short platform_index)521 void player_touch_platform_state(
522 short player_index,
523 short platform_index)
524 {
525 struct platform_data *platform= get_platform_data(platform_index);
526 struct platform_definition *definition= get_platform_definition(platform->type);
527 if (!definition) return;
528 short sound_code= NONE;
529
530 /* if we can�t control this platform, play the uncontrollable sound, if it�s inactive activate
531 it and if it�s active and moving reverse it�s direction if that�s what it does when it�s
532 obstructed, if it�s active but not moving then zero the delay */
533 if (PLATFORM_IS_PLAYER_CONTROLLABLE(platform))
534 {
535 if (PLATFORM_IS_ACTIVE(platform))
536 {
537 if (PLATFORM_CANNOT_BE_EXTERNALLY_DEACTIVATED(platform))
538 {
539 sound_code= _uncontrollable_sound;
540 }
541 else
542 {
543 if (PLATFORM_IS_MOVING(platform))
544 {
545 if (PLATFORM_REVERSES_DIRECTION_WHEN_OBSTRUCTED(platform))
546 {
547 PLATFORM_IS_EXTENDING(platform) ?
548 SET_PLATFORM_IS_CONTRACTING(platform) :
549 SET_PLATFORM_IS_EXTENDING(platform);
550 sound_code= _starting_sound;
551 }
552 else
553 {
554 sound_code= _uncontrollable_sound;
555 }
556 }
557 else
558 {
559 platform->ticks_until_restart= 0;
560 }
561 }
562 }
563 else
564 {
565 if (definition->key_item_index==NONE || try_and_subtract_player_item(player_index, definition->key_item_index))
566 {
567 set_platform_state(platform_index, true, NONE);
568 }
569 else
570 {
571 // no key
572 sound_code= _uncontrollable_sound;
573 }
574 }
575 }
576 else
577 {
578 sound_code= _uncontrollable_sound;
579 }
580
581 if (sound_code!=NONE) play_platform_sound(platform_index, sound_code);
582 }
583
584
platform_was_entered(short platform_index,bool player)585 void platform_was_entered(
586 short platform_index,
587 bool player)
588 {
589 struct platform_data *platform= get_platform_data(platform_index);
590
591 if (!PLATFORM_IS_DOOR(platform))
592 {
593 if ((player && PLATFORM_IS_PLAYER_CONTROLLABLE(platform)) ||
594 (!player && PLATFORM_IS_MONSTER_CONTROLLABLE(platform)))
595 {
596 try_and_change_platform_state(platform_index, true);
597 }
598 }
599 }
600
platform_is_legal_player_target(short platform_index)601 bool platform_is_legal_player_target(
602 short platform_index)
603 {
604 struct platform_data *platform= get_platform_data(platform_index);
605 struct platform_definition *definition= get_platform_definition(platform->type);
606 if (!definition) return false;
607 bool legal_player_target= false;
608
609 if (PLATFORM_IS_DOOR(platform))
610 {
611 if ((PLATFORM_IS_PLAYER_CONTROLLABLE(platform) || definition->uncontrollable_sound!=NONE) &&
612 (!PLATFORM_ACTIVATES_ONLY_ONCE(platform) || !PLATFORM_HAS_BEEN_ACTIVATED(platform)))
613 {
614 legal_player_target= true;
615 }
616 }
617
618 return legal_player_target;
619 }
620
platform_is_at_initial_state(short platform_index)621 bool platform_is_at_initial_state(
622 short platform_index)
623 {
624 struct platform_data *platform= get_platform_data(platform_index);
625
626 return (PLATFORM_HAS_BEEN_ACTIVATED(platform) && (!PLATFORM_IS_ACTIVE(platform) || PLATFORM_CANNOT_BE_EXTERNALLY_DEACTIVATED(platform))) ? false : true;
627 }
628
try_and_change_platform_state(short platform_index,bool state)629 bool try_and_change_platform_state(
630 short platform_index,
631 bool state)
632 {
633 struct platform_data *platform= get_platform_data(platform_index);
634 bool changed= false;
635
636 if (state || !PLATFORM_IS_ACTIVE(platform) || !PLATFORM_CANNOT_BE_EXTERNALLY_DEACTIVATED(platform))
637 {
638 bool new_state= set_platform_state(platform_index, state, NONE);
639
640 changed= (new_state && state) || (!new_state && !state);
641 }
642
643 return changed;
644 }
645
try_and_change_tagged_platform_states(short tag,bool state)646 bool try_and_change_tagged_platform_states(
647 short tag,
648 bool state)
649 {
650 struct platform_data *platform;
651 bool changed= false;
652 short platform_index;
653
654 if (tag)
655 {
656 for (platform_index= 0, platform= platforms; platform_index<dynamic_world->platform_count; ++platform_index, ++platform)
657 {
658 if (platform->tag==tag)
659 {
660 if (try_and_change_platform_state(platform_index, state))
661 {
662 changed= true;
663 }
664 }
665 }
666 }
667
668 return changed;
669 }
670
get_platform_moving_sound(short platform_index)671 short get_platform_moving_sound(
672 short platform_index)
673 {
674 struct platform_data *platform= get_platform_data(platform_index);
675 struct platform_definition *definition= get_platform_definition(platform->type);
676 if (!definition) return NONE;
677
678 return definition->moving_sound;
679 }
680
681 /* ---------- private code */
682
683
polygon_index_to_platform_index(short polygon_index)684 static short polygon_index_to_platform_index(
685 short polygon_index)
686 {
687 short platform_index;
688 struct platform_data *platform;
689
690 for (platform_index= 0, platform= platforms; platform_index<dynamic_world->platform_count; ++platform_index, ++platform)
691 {
692 if (platform->polygon_index==polygon_index) break;
693 }
694 if (platform_index==dynamic_world->platform_count) platform_index= NONE;
695
696 return platform_index;
697 }
698
set_platform_state(short platform_index,bool state,short parent_platform_index)699 bool set_platform_state(
700 short platform_index,
701 bool state,
702 short parent_platform_index)
703 {
704 struct platform_data *platform= get_platform_data(platform_index);
705 bool new_state= PLATFORM_IS_ACTIVE(platform) ? true : false;
706 short sound_code= NONE;
707
708 if (!PLATFORM_WAS_JUST_ACTIVATED_OR_DEACTIVATED(platform))
709 {
710 if (!state || !PLATFORM_ACTIVATES_ONLY_ONCE(platform) || !PLATFORM_HAS_BEEN_ACTIVATED(platform))
711 {
712 if ((state && !PLATFORM_IS_ACTIVE(platform)) || (!state && PLATFORM_IS_ACTIVE(platform)))
713 {
714 struct polygon_data *polygon= get_polygon_data(platform->polygon_index);
715
716 /* the state of this platform cannot be changed again this tick */
717 SET_PLATFORM_WAS_JUST_ACTIVATED_OR_DEACTIVATED(platform);
718
719 if (state)
720 {
721 SET_PLATFORM_HAS_BEEN_ACTIVATED(platform);
722 SET_PLATFORM_IS_MOVING(platform, false);
723 platform->ticks_until_restart= PLATFORM_DELAYS_BEFORE_ACTIVATION(platform) ?
724 platform->delay : 0;
725
726 if (PLATFORM_ACTIVATES_LIGHT(platform))
727 {
728 set_light_status(polygon->floor_lightsource_index, true);
729 set_light_status(polygon->ceiling_lightsource_index, true);
730 }
731
732 platform->parent_platform_index= parent_platform_index;
733
734 if (PLATFORM_ACTIVATES_ADJACENT_PLATFORMS_WHEN_ACTIVATING(platform)) set_adjacent_platform_states(platform_index, true);
735 if (PLATFORM_DEACTIVATES_ADJACENT_PLATFORMS_WHEN_ACTIVATING(platform)) set_adjacent_platform_states(platform_index, false);
736 }
737 else
738 {
739 if (PLATFORM_DEACTIVATES_LIGHT(platform))
740 {
741 set_light_status(polygon->floor_lightsource_index, false);
742 set_light_status(polygon->ceiling_lightsource_index, false);
743 }
744
745 if (PLATFORM_ACTIVATES_ADJACENT_PLATFORMS_WHEN_DEACTIVATING(platform)) set_adjacent_platform_states(platform_index, true);
746 if (PLATFORM_DEACTIVATES_ADJACENT_PLATFORMS_WHEN_DEACTIVATING(platform)) set_adjacent_platform_states(platform_index, false);
747
748 if (PLATFORM_IS_MOVING(platform)) sound_code= _obstructed_sound;
749 }
750
751 /* assume the correct state, and correctly update all switches referencing this platform */
752 SET_PLATFORM_IS_ACTIVE(platform, state);
753 //MH: Lua script hook
754 L_Call_Platform_Activated(platform->polygon_index);
755 assume_correct_switch_position(_panel_is_platform_switch, platform->polygon_index, state);
756
757 new_state= state;
758 }
759 }
760
761 if (sound_code!=NONE) play_platform_sound(platform_index, sound_code);
762 }
763
764 return new_state;
765 }
766
set_adjacent_platform_states(short platform_index,bool state)767 static void set_adjacent_platform_states(
768 short platform_index,
769 bool state)
770 {
771 struct platform_data *platform= get_platform_data(platform_index);
772 struct polygon_data *polygon= get_polygon_data(platform->polygon_index);
773 short i;
774
775 for (i= 0; i<polygon->vertex_count; ++i)
776 {
777 short adjacent_polygon_index= polygon->adjacent_polygon_indexes[i];
778 short adjacent_platform_index= polygon_index_to_platform_index(adjacent_polygon_index);
779
780 if (adjacent_platform_index!=NONE)
781 {
782 struct polygon_data *adjacent_polygon= get_polygon_data(adjacent_polygon_index);
783
784 if (!PLATFORM_DOES_NOT_ACTIVATE_PARENT(platform) || platform->parent_platform_index!=adjacent_platform_index)
785 {
786 set_platform_state(adjacent_polygon->permutation, state, platform_index);
787 }
788 }
789 }
790 }
791
792 /* remove all garbage objects in the platform */
take_out_the_garbage(short platform_index)793 static void take_out_the_garbage(
794 short platform_index)
795 {
796 struct platform_data *platform= get_platform_data(platform_index);
797 struct polygon_data *polygon= get_polygon_data(platform->polygon_index);
798 short object_index= polygon->first_object;
799
800 while (object_index!=NONE)
801 {
802 struct object_data *object= get_object_data(object_index);
803
804 if (GET_OBJECT_OWNER(object)==_object_is_garbage) remove_map_object(object_index);
805 object_index= object->next_object; /* relies on remove_map_object() not changing this */
806 }
807 }
808
adjust_platform_for_media(short platform_index,bool initialize)809 void adjust_platform_for_media(
810 short platform_index,
811 bool initialize)
812 {
813 struct platform_data *platform= get_platform_data(platform_index);
814 struct polygon_data *polygon= get_polygon_data(platform->polygon_index);
815
816 if (polygon->media_index!=NONE)
817 {
818 // LP change: idiot-proofing
819 struct media_data *media= get_media_data(polygon->media_index);
820 if (media)
821 {
822 bool floor_below_media= platform->floor_height<media->height;
823 bool ceiling_below_media= platform->ceiling_height<media->height;
824
825 if (!initialize)
826 {
827 short sound_code= NONE;
828
829 if ((PLATFORM_FLOOR_BELOW_MEDIA(platform) && !floor_below_media) ||
830 (PLATFORM_CEILING_BELOW_MEDIA(platform) && !ceiling_below_media))
831 {
832 sound_code= _media_snd_platform_leaving;
833 }
834 if ((!PLATFORM_FLOOR_BELOW_MEDIA(platform) && floor_below_media) ||
835 (!PLATFORM_CEILING_BELOW_MEDIA(platform) && ceiling_below_media))
836 {
837 sound_code= _media_snd_platform_entering;
838 }
839
840 if (sound_code!=NONE)
841 {
842 play_polygon_sound(platform->polygon_index, get_media_sound(polygon->media_index, sound_code));
843 }
844 }
845
846 SET_PLATFORM_FLOOR_BELOW_MEDIA(platform, floor_below_media);
847 SET_PLATFORM_CEILING_BELOW_MEDIA(platform, ceiling_below_media);
848 }
849 }
850 }
851
adjust_platform_endpoint_and_line_heights(short platform_index)852 void adjust_platform_endpoint_and_line_heights(
853 short platform_index)
854 {
855 struct platform_data *platform= get_platform_data(platform_index);
856 struct polygon_data *polygon= get_polygon_data(platform->polygon_index);
857 short i;
858
859 for (i= 0; i<polygon->vertex_count; ++i)
860 {
861 struct endpoint_data *endpoint= get_endpoint_data(polygon->endpoint_indexes[i]);
862 struct line_data *line= get_line_data(polygon->line_indexes[i]);
863 short polygon_count= platform->endpoint_owners[i].polygon_index_count;
864 short *polygon_indexes= get_map_indexes(platform->endpoint_owners[i].first_polygon_index, polygon_count);
865 short line_count= platform->endpoint_owners[i].line_index_count;
866 short *line_indexes= get_map_indexes(platform->endpoint_owners[i].first_line_index, line_count);
867 short lowest_adjacent_ceiling= 0, highest_adjacent_floor= 0, supporting_polygon_index = NONE;
868 struct polygon_data *adjacent_polygon;
869 short j;
870
871 /* adjust line heights and set proper line transparency and solidity */
872 // Skip this step if line indexes were not found
873 if (polygon->adjacent_polygon_indexes[i]!=NONE && line_indexes)
874 {
875 adjacent_polygon= get_polygon_data(polygon->adjacent_polygon_indexes[i]);
876 line->highest_adjacent_floor= MAX(polygon->floor_height, adjacent_polygon->floor_height);
877 line->lowest_adjacent_ceiling= MIN(polygon->ceiling_height, adjacent_polygon->ceiling_height);
878
879 /* only worry about transparency and solidity if there�s a polygon on the other side */
880 if (LINE_IS_VARIABLE_ELEVATION(line))
881 {
882 SET_LINE_TRANSPARENCY(line, line->highest_adjacent_floor<line->lowest_adjacent_ceiling);
883 SET_LINE_SOLIDITY(line, line->highest_adjacent_floor>=line->lowest_adjacent_ceiling);
884 }
885
886 /* and only if there is another polygon does this endpoint have a chance of being transparent */
887 for (j= 0; j<line_count; ++j) if (LINE_IS_SOLID(get_line_data(line_indexes[j]))) break;
888 SET_ENDPOINT_SOLIDITY(endpoint, (j!=line_count));
889
890 /* and only if there is another polygon does this endpoint have a chance of being transparent */
891 for (j= 0; j<line_count; ++j) if (!LINE_IS_TRANSPARENT(get_line_data(line_indexes[j]))) break;
892 SET_ENDPOINT_TRANSPARENCY(endpoint, (j==line_count));
893 }
894 else
895 {
896 line->highest_adjacent_floor= polygon->floor_height;
897 line->lowest_adjacent_ceiling= polygon->ceiling_height;
898 }
899
900 /* adjust endpoint heights */
901 // Skip this step if no polygon indexes were found
902 if (polygon_indexes)
903 {
904 for (j= 0; j<polygon_count; ++j)
905 {
906 adjacent_polygon= get_polygon_data(polygon_indexes[j]);
907 if (!j || highest_adjacent_floor<adjacent_polygon->floor_height) highest_adjacent_floor= adjacent_polygon->floor_height, supporting_polygon_index= polygon_indexes[j];
908 if (!j || lowest_adjacent_ceiling>adjacent_polygon->ceiling_height) lowest_adjacent_ceiling= adjacent_polygon->ceiling_height;
909 }
910 }
911 endpoint->highest_adjacent_floor_height= highest_adjacent_floor;
912 endpoint->lowest_adjacent_ceiling_height= lowest_adjacent_ceiling;
913 endpoint->supporting_polygon_index= supporting_polygon_index;
914 }
915 }
916
play_platform_sound(short platform_index,short type)917 static void play_platform_sound(
918 short platform_index,
919 short type)
920 {
921 struct platform_data *platform= get_platform_data(platform_index);
922 struct platform_definition *definition= get_platform_definition(platform->type);
923 if (!definition) return;
924 short sound_code;
925
926 switch (type)
927 {
928 case _obstructed_sound:
929 sound_code= definition->obstructed_sound;
930 break;
931
932 case _uncontrollable_sound:
933 sound_code= definition->uncontrollable_sound;
934 break;
935
936 case _starting_sound:
937 sound_code= PLATFORM_IS_EXTENDING(platform) ? definition->starting_extension : definition->starting_contraction;
938 break;
939 case _stopping_sound:
940 sound_code= PLATFORM_IS_FULLY_CONTRACTED(platform) ? definition->stopping_contraction : definition->stopping_extension;
941 break;
942
943 default:
944 assert(false);
945 break;
946 }
947
948 play_polygon_sound(platform->polygon_index, sound_code);
949 SoundManager::instance()->CauseAmbientSoundSourceUpdate();
950 }
951
952 /* rules for using native polygon heights: a) if this is a floor platform, then take the polygon�s
953 native floor height to be the maximum height if it is greater than the minimum height, otherwise
954 use it as the minimum height; b) if this is a ceiling platform, then take the polygon�s native
955 ceiling height to be the minimum height if it is less than the maximum height, otherwise use it
956 as the maximum height; c) native polygon height is not used for floor/ceiling platforms */
calculate_platform_extrema(short platform_index,world_distance lowest_level,world_distance highest_level)957 static void calculate_platform_extrema(
958 short platform_index,
959 world_distance lowest_level,
960 world_distance highest_level)
961 {
962 short i;
963 struct platform_data *platform= get_platform_data(platform_index);
964 struct polygon_data *polygon= get_polygon_data(platform->polygon_index);
965 world_distance lowest_adjacent_floor, highest_adjacent_ceiling;
966 world_distance highest_adjacent_floor, lowest_adjacent_ceiling;
967
968 // LP change: no need for this test
969 // assert(lowest_level==NONE||highest_level==NONE||lowest_level<highest_level);
970
971 /* calculate lowest and highest adjacent floors and ceilings */
972 lowest_adjacent_floor= highest_adjacent_floor= polygon->floor_height;
973 lowest_adjacent_ceiling= highest_adjacent_ceiling= polygon->ceiling_height;
974 for (i= 0; i<polygon->vertex_count; ++i)
975 {
976 if (polygon->adjacent_polygon_indexes[i]!=NONE)
977 {
978 struct polygon_data *adjacent_polygon= get_polygon_data(polygon->adjacent_polygon_indexes[i]);
979
980 if (adjacent_polygon->floor_height<lowest_adjacent_floor) lowest_adjacent_floor= adjacent_polygon->floor_height;
981 if (adjacent_polygon->floor_height>highest_adjacent_floor) highest_adjacent_floor= adjacent_polygon->floor_height;
982 if (adjacent_polygon->ceiling_height<lowest_adjacent_ceiling) lowest_adjacent_ceiling= adjacent_polygon->ceiling_height;
983 if (adjacent_polygon->ceiling_height>highest_adjacent_ceiling) highest_adjacent_ceiling= adjacent_polygon->ceiling_height;
984 }
985 }
986
987 /* take into account the EXTENDS_FLOOR_TO_CEILING flag */
988 if (PLATFORM_EXTENDS_FLOOR_TO_CEILING(platform))
989 {
990 if (polygon->ceiling_height>highest_adjacent_floor) highest_adjacent_floor= polygon->ceiling_height;
991 if (polygon->floor_height<lowest_adjacent_ceiling) lowest_adjacent_ceiling= polygon->floor_height;
992 }
993
994 /* calculate floor and ceiling min, max values as appropriate for the platform direction */
995 if (PLATFORM_GOES_BOTH_WAYS(platform))
996 {
997 /* split platforms always meet in the center */
998 platform->minimum_floor_height= lowest_level==NONE ? lowest_adjacent_floor : lowest_level;
999 platform->maximum_ceiling_height= highest_level==NONE ? highest_adjacent_ceiling : highest_level;
1000 platform->maximum_floor_height= platform->minimum_ceiling_height=
1001 (platform->minimum_floor_height+platform->maximum_ceiling_height)/2;
1002 }
1003 else
1004 {
1005 if (PLATFORM_COMES_FROM_FLOOR(platform))
1006 {
1007 if (PLATFORM_USES_NATIVE_POLYGON_HEIGHTS(platform))
1008 {
1009 if (polygon->floor_height<lowest_adjacent_floor || PLATFORM_EXTENDS_FLOOR_TO_CEILING(platform))
1010 {
1011 lowest_adjacent_floor= polygon->floor_height;
1012 }
1013 else
1014 {
1015 highest_adjacent_floor= polygon->floor_height;
1016 }
1017 }
1018
1019 platform->minimum_floor_height= lowest_level==NONE ? lowest_adjacent_floor : lowest_level;
1020 platform->maximum_floor_height= highest_level==NONE ? highest_adjacent_floor : highest_level;
1021 platform->minimum_ceiling_height= platform->maximum_ceiling_height= polygon->ceiling_height;
1022 }
1023 else if (PLATFORM_COMES_FROM_CEILING(platform))
1024 {
1025
1026 if (PLATFORM_USES_NATIVE_POLYGON_HEIGHTS(platform))
1027 {
1028 if (polygon->ceiling_height>highest_adjacent_ceiling || PLATFORM_EXTENDS_FLOOR_TO_CEILING(platform))
1029 {
1030 highest_adjacent_ceiling= polygon->ceiling_height;
1031 }
1032 else
1033 {
1034 lowest_adjacent_ceiling= polygon->ceiling_height;
1035 }
1036 }
1037
1038 platform->minimum_ceiling_height= lowest_level==NONE ? lowest_adjacent_ceiling : lowest_level;
1039 platform->maximum_ceiling_height= highest_level==NONE ? highest_adjacent_ceiling : highest_level;
1040 platform->minimum_floor_height= platform->maximum_floor_height= polygon->floor_height;
1041 }
1042 }
1043 }
1044
adjust_platform_sides(short platform_index,world_distance old_ceiling_height,world_distance new_ceiling_height)1045 static void adjust_platform_sides(
1046 short platform_index,
1047 world_distance old_ceiling_height,
1048 world_distance new_ceiling_height)
1049 {
1050 struct platform_data *platform= get_platform_data(platform_index);
1051 struct polygon_data *polygon= get_polygon_data(platform->polygon_index);
1052 world_distance delta_height= new_ceiling_height-old_ceiling_height;
1053 short i;
1054
1055 for (i= 0; i<polygon->vertex_count; ++i)
1056 {
1057 short side_index;
1058 struct side_data *side;
1059 struct line_data *line= get_line_data(polygon->line_indexes[i]);
1060 short adjacent_polygon_index= polygon->adjacent_polygon_indexes[i];
1061
1062 /* adjust the platform side (i.e., the texture on the side of the platform) */
1063 if (adjacent_polygon_index!=NONE)
1064 {
1065 side_index= adjacent_polygon_index==line->clockwise_polygon_owner ? line->clockwise_polygon_side_index : line->counterclockwise_polygon_side_index;
1066 if (side_index!=NONE)
1067 {
1068 side= get_side_data(side_index);
1069 switch (side->type)
1070 {
1071 case _full_side:
1072 case _high_side:
1073 case _split_side:
1074 side->primary_texture.y0+= delta_height;
1075 break;
1076 }
1077 }
1078 }
1079
1080 /* adjust the shaft side (i.e., the texture the platform slides against) */
1081 side_index= polygon->side_indexes[i];
1082 if (side_index!=NONE)
1083 {
1084 world_distance top_of_side_height;
1085
1086 side= get_side_data(side_index);
1087 switch (side->type)
1088 {
1089 case _split_side: /* secondary */
1090 top_of_side_height= MIN(line->highest_adjacent_floor, polygon->ceiling_height);
1091 side->primary_texture.y0-= (old_ceiling_height<top_of_side_height && new_ceiling_height<top_of_side_height) ?
1092 delta_height : new_ceiling_height-top_of_side_height;
1093 break;
1094 case _high_side: /* primary */
1095 // top_of_side_height= polygon->ceiling_height;
1096 side->primary_texture.y0-= delta_height; //(old_ceiling_height<top_of_side_height && new_ceiling_height<top_of_side_height) ?
1097 // delta_height : new_ceiling_height-top_of_side_height;
1098 break;
1099 case _full_side: /* primary */
1100 side->primary_texture.y0-= delta_height;
1101 break;
1102 case _low_side: /* primary */
1103 // ghs: the following doesn't appear to be necessary at all!
1104 /*
1105 top_of_side_height= MIN(line->highest_adjacent_floor, polygon->ceiling_height);
1106 side->primary_texture.y0-= (old_ceiling_height<top_of_side_height && new_ceiling_height<top_of_side_height) ?
1107 delta_height : new_ceiling_height-top_of_side_height;
1108 */
1109 break;
1110
1111 default:
1112 vhalt(csprintf(temporary, "wasn't expecting side #%d to have type #%d", side_index, side->type));
1113 break;
1114 }
1115 }
1116 }
1117 }
1118
unpack_static_platform_data(uint8 * Stream,static_platform_data * Objects,size_t Count)1119 uint8 *unpack_static_platform_data(uint8 *Stream, static_platform_data* Objects, size_t Count)
1120 {
1121 uint8* S = Stream;
1122 static_platform_data* ObjPtr = Objects;
1123
1124 for (size_t k = 0; k < Count; k++, ObjPtr++)
1125 {
1126 StreamToValue(S,ObjPtr->type);
1127 StreamToValue(S,ObjPtr->speed);
1128 StreamToValue(S,ObjPtr->delay);
1129 StreamToValue(S,ObjPtr->maximum_height);
1130 StreamToValue(S,ObjPtr->minimum_height);
1131
1132 StreamToValue(S,ObjPtr->static_flags);
1133
1134 StreamToValue(S,ObjPtr->polygon_index);
1135
1136 StreamToValue(S,ObjPtr->tag);
1137
1138 S += 7*2;
1139 }
1140
1141 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_static_platform_data));
1142 return S;
1143 }
1144
pack_static_platform_data(uint8 * Stream,static_platform_data * Objects,size_t Count)1145 uint8 * pack_static_platform_data(uint8 *Stream, static_platform_data* Objects, size_t Count)
1146 {
1147 uint8* S = Stream;
1148 static_platform_data* ObjPtr = Objects;
1149
1150 for (size_t k = 0; k < Count; k++, ObjPtr++)
1151 {
1152 ValueToStream(S,ObjPtr->type);
1153 ValueToStream(S,ObjPtr->speed);
1154 ValueToStream(S,ObjPtr->delay);
1155 ValueToStream(S,ObjPtr->maximum_height);
1156 ValueToStream(S,ObjPtr->minimum_height);
1157
1158 ValueToStream(S,ObjPtr->static_flags);
1159
1160 ValueToStream(S,ObjPtr->polygon_index);
1161
1162 ValueToStream(S,ObjPtr->tag);
1163
1164 S += 7*2;
1165 }
1166
1167 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_static_platform_data));
1168 return S;
1169 }
1170
1171
StreamToEndpointOwner(uint8 * & S,endpoint_owner_data & Object)1172 inline void StreamToEndpointOwner(uint8* &S, endpoint_owner_data& Object)
1173 {
1174 StreamToValue(S,Object.first_polygon_index);
1175 StreamToValue(S,Object.polygon_index_count);
1176 StreamToValue(S,Object.first_line_index);
1177 StreamToValue(S,Object.line_index_count);
1178 }
1179
EndpointOwnerToStream(uint8 * & S,endpoint_owner_data & Object)1180 inline void EndpointOwnerToStream(uint8* &S, endpoint_owner_data& Object)
1181 {
1182 ValueToStream(S,Object.first_polygon_index);
1183 ValueToStream(S,Object.polygon_index_count);
1184 ValueToStream(S,Object.first_line_index);
1185 ValueToStream(S,Object.line_index_count);
1186 }
1187
1188
unpack_platform_data(uint8 * Stream,platform_data * Objects,size_t Count)1189 uint8 *unpack_platform_data(uint8 *Stream, platform_data* Objects, size_t Count)
1190 {
1191 uint8* S = Stream;
1192 platform_data* ObjPtr = Objects;
1193
1194 for (size_t k = 0; k < Count; k++, ObjPtr++)
1195 {
1196 StreamToValue(S,ObjPtr->type);
1197 StreamToValue(S,ObjPtr->static_flags);
1198 StreamToValue(S,ObjPtr->speed);
1199 StreamToValue(S,ObjPtr->delay);
1200 StreamToValue(S,ObjPtr->minimum_floor_height);
1201 StreamToValue(S,ObjPtr->maximum_floor_height);
1202 StreamToValue(S,ObjPtr->minimum_ceiling_height);
1203 StreamToValue(S,ObjPtr->maximum_ceiling_height);
1204
1205 StreamToValue(S,ObjPtr->polygon_index);
1206 StreamToValue(S,ObjPtr->dynamic_flags);
1207 StreamToValue(S,ObjPtr->floor_height);
1208 StreamToValue(S,ObjPtr->ceiling_height);
1209 StreamToValue(S,ObjPtr->ticks_until_restart);
1210
1211 for (int k=0; k<MAXIMUM_VERTICES_PER_POLYGON; k++)
1212 StreamToEndpointOwner(S,ObjPtr->endpoint_owners[k]);
1213
1214 StreamToValue(S,ObjPtr->parent_platform_index);
1215
1216 StreamToValue(S,ObjPtr->tag);
1217
1218 S += 22*2;
1219 }
1220
1221 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_platform_data));
1222 return S;
1223 }
1224
pack_platform_data(uint8 * Stream,platform_data * Objects,size_t Count)1225 uint8 *pack_platform_data(uint8 *Stream, platform_data* Objects, size_t Count)
1226 {
1227 uint8* S = Stream;
1228 platform_data* ObjPtr = Objects;
1229
1230 for (size_t k = 0; k < Count; k++, ObjPtr++)
1231 {
1232 ValueToStream(S,ObjPtr->type);
1233 ValueToStream(S,ObjPtr->static_flags);
1234 ValueToStream(S,ObjPtr->speed);
1235 ValueToStream(S,ObjPtr->delay);
1236 ValueToStream(S,ObjPtr->minimum_floor_height);
1237 ValueToStream(S,ObjPtr->maximum_floor_height);
1238 ValueToStream(S,ObjPtr->minimum_ceiling_height);
1239 ValueToStream(S,ObjPtr->maximum_ceiling_height);
1240
1241 ValueToStream(S,ObjPtr->polygon_index);
1242 ValueToStream(S,ObjPtr->dynamic_flags);
1243 ValueToStream(S,ObjPtr->floor_height);
1244 ValueToStream(S,ObjPtr->ceiling_height);
1245 ValueToStream(S,ObjPtr->ticks_until_restart);
1246
1247 for (int k=0; k<MAXIMUM_VERTICES_PER_POLYGON; k++)
1248 EndpointOwnerToStream(S,ObjPtr->endpoint_owners[k]);
1249
1250 ValueToStream(S,ObjPtr->parent_platform_index);
1251
1252 ValueToStream(S,ObjPtr->tag);
1253
1254 S += 22*2;
1255 }
1256
1257 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_platform_data));
1258 return S;
1259 }
1260
1261 struct platform_definition *original_platform_definitions = NULL;
1262
reset_mml_platforms()1263 void reset_mml_platforms()
1264 {
1265 if (original_platform_definitions) {
1266 for (int i = 0; i < NUMBER_OF_PLATFORM_TYPES; i++)
1267 platform_definitions[i] = original_platform_definitions[i];
1268 free(original_platform_definitions);
1269 original_platform_definitions = NULL;
1270 }
1271 }
1272
parse_mml_platforms(const InfoTree & root)1273 void parse_mml_platforms(const InfoTree& root)
1274 {
1275 // back up old values first
1276 if (!original_platform_definitions) {
1277 original_platform_definitions = (struct platform_definition *) malloc(sizeof(struct platform_definition) * NUMBER_OF_PLATFORM_TYPES);
1278 assert(original_platform_definitions);
1279 for (int i = 0; i < NUMBER_OF_PLATFORM_TYPES; i++)
1280 original_platform_definitions[i] = platform_definitions[i];
1281 }
1282
1283 BOOST_FOREACH(InfoTree ptree, root.children_named("platform"))
1284 {
1285 int16 index;
1286 if (!ptree.read_indexed("index", index, NUMBER_OF_PLATFORM_TYPES))
1287 continue;
1288 platform_definition& def = platform_definitions[index];
1289
1290 ptree.read_indexed("start_extend", def.starting_extension, SHRT_MAX+1, true);
1291 ptree.read_indexed("start_contract", def.starting_contraction, SHRT_MAX+1, true);
1292 ptree.read_indexed("stop_extend", def.stopping_extension, SHRT_MAX+1, true);
1293 ptree.read_indexed("stop_contract", def.stopping_contraction, SHRT_MAX+1, true);
1294 ptree.read_indexed("obstructed", def.obstructed_sound, SHRT_MAX+1, true);
1295 ptree.read_indexed("uncontrollable", def.uncontrollable_sound, SHRT_MAX+1, true);
1296 ptree.read_indexed("moving", def.moving_sound, SHRT_MAX+1, true);
1297 ptree.read_indexed("item", def.key_item_index, NUMBER_OF_DEFINED_ITEMS, true);
1298
1299 BOOST_FOREACH(InfoTree dmg, ptree.children_named("damage"))
1300 {
1301 dmg.read_damage(def.damage);
1302 }
1303 }
1304 }
1305