1 /*
2 ITEMS.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 Monday, January 3, 1994 10:06:08 PM
22
23 Monday, September 5, 1994 2:17:43 PM
24 razed.
25 Friday, October 21, 1994 3:44:11 PM
26 changed inventory updating mechanism, added maximum counts of items.
27 Wednesday, November 2, 1994 3:49:57 PM (Jason)
28 object_was_just_destroyed is now called immediately on powerups.
29 Tuesday, January 31, 1995 1:24:10 PM (Jason')
30 can only hold unlimited ammo on total carnage (not everything)
31 Wednesday, October 11, 1995 3:10:34 PM (Jason)
32 network-only items
33
34 Feb 4, 2000 (Loren Petrich):
35 Changed halt() to assert(false) for better debugging
36
37 Feb 15, 2000 (Loren Petrich):
38 Added item-animation handling
39 Non-animated items ought to be randomized, but one problem is that
40 randomize_object_sequence() only works when the shapes are loaded,
41 and the shapes are usually not loaded when the map items are created.
42
43 May 16, 2000 (Loren Petrich):
44 Added XML support for configuring various item features
45
46 May 26, 2000 (Loren Petrich):
47 Added XML shapes support
48
49 Jul 1, 2000 (Loren Petrich):
50 Did some inlining of the item-definition accessor
51
52 Added Benad's netgame-type changes
53
54 Aug 10, 2000 (Loren Petrich):
55 Added Chris Pruett's Pfhortran changes
56
57 Feb 11, 2001 (Loren Petrich):
58 Reversed the "polarity" of the "facing" member of "object",
59 which is used as a flag in the case of randomized unanimated objects.
60 It will become NONE when these objects are inited.
61 */
62
63 #include "cseries.h"
64
65 #include "map.h"
66 #include "interface.h"
67 #include "monsters.h"
68 #include "player.h"
69 #include "SoundManager.h"
70 #include "platforms.h"
71 #include "fades.h"
72 #include "FilmProfile.h"
73 #include "items.h"
74 #include "flood_map.h"
75 #include "effects.h"
76 #include "game_window.h"
77 #include "weapons.h" /* needed for process_new_item_for_reloading */
78 #include "network_games.h"
79 #include "InfoTree.h"
80
81 // LP addition: for the XML stuff
82 #include <string.h>
83 #include <limits.h>
84
85 //MH: Lua scripting
86 #include "lua_script.h"
87
88 /* ---------- structures */
89
90 #define strITEM_NAME_LIST 150
91 #define strHEADER_NAME_LIST 151
92
93 #define MAXIMUM_ARM_REACH (3*WORLD_ONE_FOURTH)
94
95 /* ---------- private prototypes */
96
97 /* ---------- globals */
98
99 #include "item_definitions.h"
100
101 /* ---------- private prototypes */
102
103 // Item-definition accessor
104 static item_definition *get_item_definition(
105 const short type);
106
107 static bool get_item(short player_index, short object_index);
108
109 static bool test_item_retrieval(short polygon_index1, world_point3d *location1, world_point3d *location2);
110
111 static int32 item_trigger_cost_function(short source_polygon_index, short line_index,
112 short destination_polygon_index, void *unused);
113
114 /* ---------- code */
115
116 // Item-definition accessor
get_item_definition(const short type)117 item_definition *get_item_definition(
118 const short type)
119 {
120 return GetMemberWithBounds(item_definitions,type,NUMBER_OF_DEFINED_ITEMS);
121 }
122
123 //a non-inlined version for external use
get_item_definition_external(const short type)124 item_definition *get_item_definition_external(
125 const short type)
126 {
127 return get_item_definition(type);
128 }
129
new_item(struct object_location * location,short type)130 short new_item(
131 struct object_location *location,
132 short type)
133 {
134 short object_index;
135 struct item_definition *definition= get_item_definition(type);
136 // LP change: added idiot-proofing
137 if (!definition) return false;
138
139 bool add_item= true;
140
141 assert(sizeof(item_definitions)/sizeof(struct item_definition)==NUMBER_OF_DEFINED_ITEMS);
142
143 /* Do NOT add items that are network-only in a single player game, and vice-versa */
144 if (dynamic_world->player_count>1)
145 {
146 if (definition->invalid_environments & _environment_network) add_item= false;
147 if (get_item_kind(type)==_ball && !current_game_has_balls()) add_item= false;
148 }
149 else
150 {
151 if (definition->invalid_environments & _environment_single_player) add_item= false;
152 }
153
154 if (add_item)
155 {
156 /* add the object to the map */
157 object_index= new_map_object(location, definition->base_shape);
158 if (object_index!=NONE)
159 {
160 struct object_data *object= get_object_data(object_index);
161
162 // LP addition: using the facing direction as a flag in the "unanimated" case:
163 // will be initially zero, but will become nonzero when initialized,
164 // so that the shape randomization will be done only once.
165
166 SET_OBJECT_OWNER(object, _object_is_item);
167 object->permutation= type;
168
169 if ((location->flags&_map_object_is_network_only) && dynamic_world->player_count<=1)
170 {
171 // dprintf("killed #%d;g;", type);
172 SET_OBJECT_INVISIBILITY(object, true);
173 object->permutation= NONE;
174 }
175 else if ((get_item_kind(type) == _ball) && !static_world->ball_in_play)
176 {
177 static_world->ball_in_play = true;
178 SoundManager::instance()->PlayLocalSound(_snd_got_ball);
179 }
180
181 /* let PLACEMENT.C keep track of how many there are */
182 object_was_just_added(_object_is_item, type);
183 // and let Lua know too
184 L_Call_Item_Created(object_index);
185 }
186 }
187 else
188 {
189 object_index= NONE;
190 }
191
192 return object_index;
193 }
194
trigger_nearby_items(short polygon_index)195 void trigger_nearby_items(
196 short polygon_index)
197 {
198 polygon_index= flood_map(polygon_index, INT32_MAX, item_trigger_cost_function, _breadth_first, (void *) NULL);
199 while (polygon_index!=NONE)
200 {
201 struct object_data *object;
202 short object_index;
203
204 for (object_index= get_polygon_data(polygon_index)->first_object; object_index!=NONE; object_index= object->next_object)
205 {
206 object= get_object_data(object_index);
207 switch (GET_OBJECT_OWNER(object))
208 {
209 case _object_is_item:
210 if (OBJECT_IS_INVISIBLE(object) && object->permutation!=NONE)
211 {
212 teleport_object_in(object_index);
213 }
214 break;
215 }
216 }
217
218 polygon_index= flood_map(NONE, INT32_MAX, item_trigger_cost_function, _breadth_first, (void *) NULL);
219 }
220 }
221
222 /* returns the color of the ball or NONE if they don't have one */
find_player_ball_color(short player_index)223 short find_player_ball_color(
224 short player_index)
225 {
226 struct player_data *player= get_player_data(player_index);
227 short ball_color= NONE;
228 short index;
229
230 for(index= BALL_ITEM_BASE; ball_color==NONE && index<BALL_ITEM_BASE+MAXIMUM_NUMBER_OF_PLAYERS; ++index)
231 {
232 if(player->items[index]>0)
233 {
234 ball_color= index-BALL_ITEM_BASE;
235 }
236 }
237
238 return ball_color;
239 }
240
get_item_name(char * buffer,short item_id,bool plural)241 void get_item_name(
242 char *buffer,
243 short item_id,
244 bool plural)
245 {
246 struct item_definition *definition= get_item_definition(item_id);
247 // LP change: added idiot-proofing
248 if (!definition)
249 {
250 if (plural)
251 sprintf(buffer,"Unlisted items with ID %d",item_id);
252 else
253 sprintf(buffer,"Unlisted item with ID %d",item_id);
254
255 return;
256 }
257
258 getcstr(buffer, strITEM_NAME_LIST, plural ? definition->plural_name_id :
259 definition->singular_name_id);
260 }
261
get_header_name(char * buffer,short type)262 void get_header_name(
263 char *buffer,
264 short type)
265 {
266 getcstr(buffer, strHEADER_NAME_LIST, type);
267 }
268
calculate_player_item_array(short player_index,short type,short * items,short * counts,short * array_count)269 void calculate_player_item_array(
270 short player_index,
271 short type,
272 short *items,
273 short *counts,
274 short *array_count)
275 {
276 struct player_data *player= get_player_data(player_index);
277 short loop;
278 short count= 0;
279
280 for(loop=0; loop<NUMBER_OF_DEFINED_ITEMS; ++loop)
281 {
282 if (loop==_i_knife) continue;
283 if(player->items[loop] != NONE)
284 {
285 if(get_item_kind(loop)==type)
286 {
287 items[count]= loop;
288 counts[count]= player->items[loop];
289 count++;
290 }
291 }
292 }
293
294 *array_count= count;
295 }
296
count_inventory_lines(short player_index)297 short count_inventory_lines(
298 short player_index)
299 {
300 struct player_data *player= get_player_data(player_index);
301 bool types[NUMBER_OF_ITEM_TYPES];
302 short count= 0;
303 short loop;
304
305 /* Clean out the header array, so we can count properly */
306 for(loop=0; loop<NUMBER_OF_ITEM_TYPES; ++loop)
307 {
308 types[loop]= false;
309 }
310
311 for(loop=0; loop<NUMBER_OF_DEFINED_ITEMS; ++loop)
312 {
313 if (loop==_i_knife) continue;
314 if (player->items[loop] != NONE)
315 {
316 count++;
317 types[get_item_kind(loop)]= true;
318 }
319 }
320
321 /* Now add in the header lines.. */
322 for(loop= 0; loop<NUMBER_OF_ITEM_TYPES; ++loop)
323 {
324 if(types[loop]) count++;
325 }
326
327 return count;
328 }
329
a1_swipe_nearby_items(short player_index)330 static void a1_swipe_nearby_items(
331 short player_index)
332 {
333 struct object_data *object;
334 struct object_data *player_object;
335 struct player_data *player= get_player_data(player_index);
336 short next_object;
337 struct polygon_data *polygon;
338 short *neighbor_indexes;
339 short i;
340
341 player_object= get_object_data(get_monster_data(player->monster_index)->object_index);
342
343 polygon= get_polygon_data(player_object->polygon);
344 neighbor_indexes= get_map_indexes(polygon->first_neighbor_index, polygon->neighbor_count);
345
346 // Skip this step if neighbor indexes were not found
347 if (!neighbor_indexes) return;
348
349 for (i=0;i<polygon->neighbor_count;++i)
350 {
351
352 struct polygon_data *neighboring_polygon= get_polygon_data(*neighbor_indexes++);
353
354 /*
355 LP change: since precalculate_map_indexes() and its associated routine
356 intersecting_flood_proc() appear to have some bugs in them, I will
357 instead search the neighbors of each indexed polygon.
358
359 Starting the search from -1 is a kludge designed to include a search
360 for the current polygon.
361 */
362 struct polygon_data *source_polygon = neighboring_polygon;
363 for (int ngbr_indx = -1; ngbr_indx<source_polygon->vertex_count; ngbr_indx++)
364 {
365 if (ngbr_indx >= 0)
366 {
367 // Be sure to check on whether there is a valid polygon on the other side
368 short adjacent_index = source_polygon->adjacent_polygon_indexes[ngbr_indx];
369 if (adjacent_index == NONE) continue;
370 neighboring_polygon = get_polygon_data(adjacent_index);
371 }
372 else
373 neighboring_polygon = source_polygon;
374
375 if (!POLYGON_IS_DETACHED(neighboring_polygon))
376 {
377 next_object= neighboring_polygon->first_object;
378
379 while(next_object != NONE)
380 {
381 object= get_object_data(next_object);
382 if (GET_OBJECT_OWNER(object)==_object_is_item && !OBJECT_IS_INVISIBLE(object))
383 {
384 if (guess_distance2d((world_point2d *) &player->location, (world_point2d *) &object->location)<=MAXIMUM_ARM_REACH)
385 {
386 world_distance radius, height;
387
388 get_monster_dimensions(player->monster_index, &radius, &height);
389
390 if (object->location.z >= player->location.z - MAXIMUM_ARM_REACH && object->location.z <= player->location.z + height &&
391 test_item_retrieval(player_object->polygon, &player_object->location, &object->location))
392 {
393 if(get_item(player_index, next_object))
394 {
395 /* Start the search again.. */
396 next_object= neighboring_polygon->first_object;
397 continue;
398 }
399 }
400 }
401 }
402
403 next_object= object->next_object;
404 }
405 }
406 // LP addition: end of that kludgy search loop
407 }
408 }
409 }
410
m2_swipe_nearby_items(short player_index)411 static void m2_swipe_nearby_items(
412 short player_index)
413 {
414 struct object_data *object;
415 struct object_data *player_object;
416 struct player_data *player= get_player_data(player_index);
417 short next_object;
418 struct polygon_data *polygon;
419 short *neighbor_indexes;
420 short i;
421
422 player_object= get_object_data(get_monster_data(player->monster_index)->object_index);
423
424 polygon= get_polygon_data(player_object->polygon);
425 neighbor_indexes= get_map_indexes(polygon->first_neighbor_index, polygon->neighbor_count);
426
427 // Skip this step if neighbor indexes were not found
428 if (!neighbor_indexes) return;
429
430 for (i=0;i<polygon->neighbor_count;++i)
431 {
432
433 struct polygon_data *neighboring_polygon= get_polygon_data(*neighbor_indexes++);
434
435 if (!POLYGON_IS_DETACHED(neighboring_polygon))
436 {
437 next_object= neighboring_polygon->first_object;
438
439 while(next_object != NONE)
440 {
441 object= get_object_data(next_object);
442 if (GET_OBJECT_OWNER(object)==_object_is_item && !OBJECT_IS_INVISIBLE(object))
443 {
444 if (guess_distance2d((world_point2d *) &player->location, (world_point2d *) &object->location)<=MAXIMUM_ARM_REACH)
445 {
446 world_distance radius, height;
447
448 get_monster_dimensions(player->monster_index, &radius, &height);
449
450 if (object->location.z >= player->location.z - MAXIMUM_ARM_REACH && object->location.z <= player->location.z + height &&
451 test_item_retrieval(player_object->polygon, &player_object->location, &object->location))
452 {
453 if(get_item(player_index, next_object))
454 {
455 /* Start the search again.. */
456 next_object= neighboring_polygon->first_object;
457 continue;
458 }
459 }
460 }
461 }
462
463 next_object= object->next_object;
464 }
465 }
466 }
467 }
468
swipe_nearby_items(short player_index)469 void swipe_nearby_items(short player_index)
470 {
471 if (film_profile.swipe_nearby_items_fix)
472 {
473 a1_swipe_nearby_items(player_index);
474 }
475 else
476 {
477 m2_swipe_nearby_items(player_index);
478 }
479 }
480
481
mark_item_collections(bool loading)482 void mark_item_collections(
483 bool loading)
484 {
485 mark_collection(_collection_items, loading);
486 }
487
unretrieved_items_on_map(void)488 bool unretrieved_items_on_map(
489 void)
490 {
491 bool found_item= false;
492 struct object_data *object;
493 short object_index;
494
495 for (object_index= 0, object= objects; object_index<MAXIMUM_OBJECTS_PER_MAP; ++object_index, ++object)
496 {
497 if (SLOT_IS_USED(object) && GET_OBJECT_OWNER(object)==_object_is_item)
498 {
499 if (get_item_kind(object->permutation)==_item)
500 {
501 found_item= true;
502 break;
503 }
504 }
505 }
506
507 return found_item;
508 }
509
item_valid_in_current_environment(short item_type)510 bool item_valid_in_current_environment(
511 short item_type)
512 {
513 bool valid= true;
514 struct item_definition *definition= get_item_definition(item_type);
515 // LP change: added idiot-proofing
516 if (!definition) return false;
517
518 if (definition->invalid_environments & static_world->environment_flags)
519 {
520 valid= false;
521 }
522
523 return valid;
524 }
525
get_item_kind(short item_id)526 short get_item_kind(
527 short item_id)
528 {
529 struct item_definition *definition= get_item_definition(item_id);
530 // LP change: added idiot-proofing
531 if (!definition) return NONE;
532
533 return definition->item_kind;
534 }
535
get_item_shape(short item_id)536 short get_item_shape(
537 short item_id)
538 {
539 struct item_definition *definition= get_item_definition(item_id);
540 // LP change: added idiot-proofing
541 if (!definition) return NONE;
542
543 return definition->base_shape;
544 }
545
try_and_add_player_item(short player_index,short type)546 bool try_and_add_player_item(
547 short player_index,
548 short type)
549 {
550 struct item_definition *definition= get_item_definition(type);
551 // LP change: added idiot-proofing
552 if (!definition) return false;
553
554 struct player_data *player= get_player_data(player_index);
555 short grabbed_sound_index= NONE;
556 bool success= false;
557
558 switch (definition->item_kind)
559 {
560 case _powerup: /* powerups don�t get added to your inventory */
561 if (legal_player_powerup(player_index, type))
562 {
563 process_player_powerup(player_index, type);
564 object_was_just_destroyed(_object_is_item, type);
565 grabbed_sound_index= Sound_GotPowerup();
566 success= true;
567 }
568 break;
569
570 case _ball:
571 // START Benad
572 /* Note that you can only carry ONE ball (ever) */
573 if(find_player_ball_color(player_index)==NONE)
574 {
575 struct player_data *player= get_player_data(player_index);
576
577 // When taking ball of your own team, it returns to its original
578 // position on the map, unless it's already in our base (or hill).
579 if ( (GET_GAME_TYPE() == _game_of_capture_the_flag) &&
580 (type - BALL_ITEM_BASE == player->team) )
581 {
582 // START Benad modified oct. 1st
583 struct polygon_data *polygon= get_polygon_data(player->supporting_polygon_index);
584 if (polygon->type!=_polygon_is_base)
585 {
586 object_was_just_destroyed(_object_is_item, type);
587 grabbed_sound_index= Sound_GotItem();
588 success= true;
589 goto DONE;
590 }
591 else // _polygon_is_base and base == player->team
592 // base != player->team taken care of in update_net_game
593 // (your ball should NEVER get there)
594 {
595 success= false;
596 goto DONE;
597 }
598 // END Benad modified oct. 1st
599 }
600 else if (GET_GAME_TYPE() == _game_of_rugby)
601 {
602 // ghs: work around for SF 2894880
603
604 // if you're in an enemy base
605 // and pick up the ball, you
606 // score
607 struct polygon_data* polygon = get_polygon_data(player->supporting_polygon_index);
608 if (polygon->type == _polygon_is_base && polygon->permutation != player->team)
609 {
610 /* Goal! */
611
612 // defined in network_games.cpp
613 const int _points_scored = 0;
614 player->netgame_parameters[_points_scored]++;
615 team_netgame_parameters[player->team][_points_scored]++;
616 object_was_just_destroyed(_object_is_item, type);
617 grabbed_sound_index = Sound_GotItem();
618 success = true;
619 goto DONE;
620 }
621 }
622
623 player->items[type]= 1;
624
625 // OK, since only for loading weapon. Ignores item_type, cares
626 // only about item_kind (here, _ball).
627 /* Load the ball weapon.. */
628 process_new_item_for_reloading(player_index, _i_red_ball);
629
630 /* Tell the interface to redraw next time it has to */
631 mark_player_inventory_as_dirty(player_index, type);
632
633 success= true;
634 }
635 grabbed_sound_index= NONE;
636 break;
637 // END Benad
638
639 case _weapon:
640 case _ammunition:
641 case _item:
642 /* Increment the count */
643 assert(type>=0 && type<NUMBER_OF_ITEMS);
644 if(player->items[type]==NONE)
645 {
646 /* just got the first one.. */
647 player->items[type]= 1;
648 success= true;
649 }
650 else if(player->items[type]+1<=definition->maximum_count_per_player ||
651 (dynamic_world->game_information.difficulty_level==_total_carnage_level && ((static_world->environment_flags & _environment_m1_weapons) || definition->item_kind==_ammunition)))
652 {
653 /* Increment your count.. */
654 player->items[type]++;
655 success= true;
656 } else {
657 /* You have exceeded the count of these items */
658 }
659
660 grabbed_sound_index= Sound_GotItem();
661
662 if(success)
663 {
664 /* Reload or whatever.. */
665 process_new_item_for_reloading(player_index, type);
666
667 /* Tell the interface to redraw next time it has to */
668 mark_player_inventory_as_dirty(player_index, type);
669 }
670 break;
671
672 default:
673 assert(false);
674 break;
675 }
676 // Benad. Burk.
677 DONE:
678
679 //CP Addition: call any script traps available
680 // jkvw: but only if we actually got the item
681 if (success)
682 {
683 //MH: Call Lua script hook
684 L_Call_Got_Item(type, player_index);
685 }
686
687 /* Play the pickup sound */
688 if (success && player_index==current_player_index)
689 {
690 SoundManager::instance()->PlayLocalSound(grabbed_sound_index);
691
692 /* Flash screen */
693 start_fade(_fade_bonus);
694 }
695
696 return success;
697 }
698
699 /* ---------- private code */
700
701
item_trigger_cost_function(short source_polygon_index,short line_index,short destination_polygon_index,void * unused)702 static int32 item_trigger_cost_function(
703 short source_polygon_index,
704 short line_index,
705 short destination_polygon_index,
706 void *unused)
707 {
708 struct polygon_data *destination_polygon= get_polygon_data(destination_polygon_index);
709 // struct polygon_data *source_polygon= get_polygon_data(source_polygon_index);
710 // struct line_data *line= get_line_data(line_index);
711 int32 cost= 1;
712
713 (void) (unused);
714 (void) (source_polygon_index);
715 (void) (line_index);
716
717 if (destination_polygon->type==_polygon_is_zone_border) cost= -1;
718
719 return cost;
720 }
721
get_item(short player_index,short object_index)722 static bool get_item(
723 short player_index,
724 short object_index)
725 {
726 struct object_data *object= get_object_data(object_index);
727 bool success;
728
729 assert(GET_OBJECT_OWNER(object)==_object_is_item);
730
731 success= try_and_add_player_item(player_index, object->permutation);
732 if (success)
733 {
734 /* remove it */
735 remove_map_object(object_index);
736 }
737
738 return success;
739 }
740
test_item_retrieval(short polygon_index1,world_point3d * location1,world_point3d * location2)741 static bool test_item_retrieval(
742 short polygon_index1,
743 world_point3d *location1,
744 world_point3d *location2)
745 {
746 bool valid_retrieval= true;
747 short polygon_index= polygon_index1;
748
749 do
750 {
751 short line_index= find_line_crossed_leaving_polygon(polygon_index, (world_point2d *) location1,
752 (world_point2d *) location2);
753
754 if (line_index!=NONE)
755 {
756 polygon_index= find_adjacent_polygon(polygon_index, line_index);
757 if (LINE_IS_SOLID(get_line_data(line_index))) valid_retrieval= false;
758 if (polygon_index!=NONE)
759 {
760 struct polygon_data *polygon= get_polygon_data(polygon_index);
761
762 if (polygon->type==_polygon_is_platform)
763 {
764 struct platform_data *platform= get_platform_data(polygon->permutation);
765
766 if (PLATFORM_IS_MOVING(platform)) valid_retrieval= false;
767 }
768 }
769 }
770 else
771 {
772 polygon_index= NONE;
773 }
774 }
775 while (polygon_index!=NONE && valid_retrieval);
776
777 return valid_retrieval;
778 }
779
780
781 // LP addition: initializer
initialize_items(void)782 void initialize_items(void) {
783 }
784
785 // LP addition: animator
animate_items(void)786 void animate_items(void) {
787
788 short object_index;
789 object_data *object;
790 for (object_index= 0, object= objects; object_index<MAXIMUM_OBJECTS_PER_MAP; ++object_index, ++object)
791 {
792 if (SLOT_IS_USED(object) && GET_OBJECT_OWNER(object)==_object_is_item && !OBJECT_IS_INVISIBLE(object))
793 {
794 short type = object->permutation;
795 if (get_item_kind(type) != NONE)
796 {
797 struct item_definition *ItemDef = get_item_definition(type);
798 // LP change: added idiot-proofing
799 if (!ItemDef) continue;
800
801 shape_descriptor shape = ItemDef->base_shape;
802 struct shape_animation_data *animation= get_shape_animation_data(shape);
803 if (!animation) continue;
804
805 // Randomize if non-animated; do only once
806 if (object->facing >= 0) {
807 if (randomize_object_sequence(object_index,shape))
808 {
809 object->facing = NONE;
810 }
811 }
812 // Now the animation
813 if (object->facing >= 0)
814 animate_object(object_index);
815 }
816 }
817 }
818 }
819
820 struct item_definition *original_item_definitions = NULL;
821
reset_mml_items()822 void reset_mml_items()
823 {
824 if (original_item_definitions) {
825 for (unsigned i = 0; i < NUMBER_OF_DEFINED_ITEMS; i++)
826 item_definitions[i] = original_item_definitions[i];
827 free(original_item_definitions);
828 original_item_definitions = NULL;
829 }
830 }
831
parse_mml_items(const InfoTree & root)832 void parse_mml_items(const InfoTree& root)
833 {
834 // back up old values first
835 if (!original_item_definitions) {
836 original_item_definitions = (struct item_definition *) malloc(sizeof(struct item_definition) * NUMBER_OF_DEFINED_ITEMS);
837 assert(original_item_definitions);
838 for (unsigned i = 0; i < NUMBER_OF_DEFINED_ITEMS; i++)
839 original_item_definitions[i] = item_definitions[i];
840 }
841
842 BOOST_FOREACH(InfoTree itree, root.children_named("item"))
843 {
844 int16 index;
845 if (!itree.read_indexed("index", index, NUMBER_OF_DEFINED_ITEMS))
846 continue;
847
848 item_definition& def = item_definitions[index];
849 itree.read_attr("singular", def.singular_name_id);
850 itree.read_attr("plural", def.plural_name_id);
851 itree.read_indexed("maximum", def.maximum_count_per_player, SHRT_MAX+1);
852 itree.read_attr("invalid", def.invalid_environments);
853 itree.read_indexed("type", def.item_kind, NUMBER_OF_ITEM_TYPES);
854
855 BOOST_FOREACH(InfoTree shape, itree.children_named("shape"))
856 shape.read_shape(def.base_shape);
857 }
858 }
859