1 /*
2 GAME_WINDOW.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 Thursday, December 30, 1993 9:51:24 PM
22 
23 Tuesday, May 24, 1994 6:42:32 PM
24 	functions beginning with underscores are mac-specific and always have a corresponding portable
25 	function which sets up game-specific information (see update_compass and _update_compass for
26 	an example).
27 Friday, June 10, 1994 3:56:57 AM
28 	gutted, rewritten.  Much cleaner now.
29 Sunday, September 4, 1994 6:32:05 PM
30 	made scroll_inventory() non-static so that shell.c can call it.
31 Saturday, September 24, 1994 10:33:19 AM
32 	fixed some things, twice...
33 Friday, October 7, 1994 3:13:22 PM
34 	New interface.  Draws panels from PICT resources for memory consumption.  Inventory is
35 	different panels, which are switched to whenever you grab an item.  There is no scrolling.
36 Tuesday, June 6, 1995 3:37:50 PM
37 	Marathon II modifications.
38 Tuesday, August 29, 1995 4:02:15 PM
39 	Reestablishing a level of portablility...
40 
41 Feb 4, 2000 (Loren Petrich):
42 	Added SMG display stuff
43 
44 Apr 30, 2000 (Loren Petrich): Added XML parser object for all the screen_drawing data,
45 	and also essentiall all the data here.
46 
47 May 28, 2000 (Loren Petrich): Added support for buffering the Heads-Up Display
48 
49 Jul 2, 2000 (Loren Petrich):
50 	The HUD is now always buffered
51 
52 Jul 16, 2001 (Loren Petrich):
53 	Using "temporary" as storage space for count_text and weapon_name;
54 	it is 256 bytes long, which should be more than enough for most text.
55 	This fixes the long-weapon-name bug.
56 
57 Mar 08, 2002 (Woody Zenfell):
58     SDL network microphone support
59 */
60 
61 #include "cseries.h"
62 
63 #ifdef __WIN32__
64 #include <windows.h>
65 #endif
66 
67 #ifdef HAVE_OPENGL
68 #include "OGL_Headers.h"
69 #endif
70 
71 #include "HUDRenderer_SW.h"
72 #include "game_window.h"
73 
74 // LP addition: color and font parsers
75 #include "FontHandler.h"
76 #include "screen.h"
77 
78 #include "shell.h"
79 #include "preferences.h"
80 #include "screen.h"
81 #include "screen_definitions.h"
82 #include "images.h"
83 #include "InfoTree.h"
84 
85 #include    "network_sound.h"
86 
87 extern void draw_panels(void);
88 extern void validate_world_window(void);
89 static void set_current_inventory_screen(short player_index, short screen);
90 
91 /* --------- globals */
92 
93 // LP addition: whether or not the motion sensor is active
94 bool MotionSensorActive = true;
95 
96 struct interface_state_data interface_state;
97 
98 #define NUMBER_OF_WEAPON_INTERFACE_DEFINITIONS	10
99 struct weapon_interface_data weapon_interface_definitions[NUMBER_OF_WEAPON_INTERFACE_DEFINITIONS] =
100 {
101 	/* Mac, the knife.. */
102 	{
103 		_i_knife,
104 		UNONE,
105 		433, 432,
106 		NONE, NONE,
107 		0, 0,
108 		false,
109 		{
110 			{ _unused_interface_data, 0, 0, 0, 0, 0, 0, UNONE, UNONE, true},
111 			{ _unused_interface_data, 0, 0, 0, 0, 0, 0, UNONE, UNONE, true}
112 		},
113 		UNONE, UNONE,
114 		0, 0
115 	},
116 
117 	/* Harry, the .44 */
118 	{
119 		_i_magnum,
120 		BUILD_DESCRIPTOR(_collection_interface, _magnum_panel),
121 		432, 444,
122 		420, NONE,
123 		366, 517,
124 		true,
125 		{
126 			{ _uses_bullets, 517, 412, 8, 1, 5, 14, BUILD_DESCRIPTOR(_collection_interface, _magnum_bullet), BUILD_DESCRIPTOR(_collection_interface, _magnum_casing), false},
127 			{ _uses_bullets, 452, 412, 8, 1, 5, 14, BUILD_DESCRIPTOR(_collection_interface, _magnum_bullet), BUILD_DESCRIPTOR(_collection_interface, _magnum_casing), true}
128 		},
129 		BUILD_DESCRIPTOR(_collection_interface, _left_magnum),
130 		BUILD_DESCRIPTOR(_collection_interface, _left_magnum_unusable),
131 		-97, 0
132 	},
133 
134 	/* Ripley, the plasma pistol. */
135 	{
136 		_i_plasma_pistol,
137 		BUILD_DESCRIPTOR(_collection_interface, _zeus_panel),
138 		431, 443,
139 		401, NONE,
140 		366, 475,
141 		false,
142 		{
143 			{ _uses_energy, 414, 366, 20, 0, 38, 57, _energy_weapon_full_color, _energy_weapon_empty_color, true},
144 			{ _unused_interface_data, 450, 410, 50, 0, 62, 7, _energy_weapon_full_color, _energy_weapon_empty_color, true}
145 		},
146 		UNONE, UNONE,
147 		0, 0
148 	},
149 
150 	/* Arnold, the assault rifle */
151 	{
152 		_i_assault_rifle,
153 		BUILD_DESCRIPTOR(_collection_interface, _assault_panel),
154 		430, 452,
155 		439, NONE, //��
156 		366, 460,
157 		false,
158 		{
159 			{ _uses_bullets, 391, 368, 13, 4, 4, 10, BUILD_DESCRIPTOR(_collection_interface, _assault_rifle_bullet), BUILD_DESCRIPTOR(_collection_interface, _assault_rifle_casing), true},
160 			{ _uses_bullets, 390, 413, 7, 1, 8, 12, BUILD_DESCRIPTOR(_collection_interface, _assault_rifle_grenade), BUILD_DESCRIPTOR(_collection_interface, _assault_rifle_grenade_casing), true},
161 		},
162 		UNONE, UNONE,
163 		0, 0
164 	},
165 
166 	/* John R., the missile launcher */
167 	{
168 		_i_missile_launcher,
169 		BUILD_DESCRIPTOR(_collection_interface, _missile_panel),
170 		433, 445,
171 		426, NONE,
172 		365, 419,
173 		false,
174 		{
175 			{ _uses_bullets, 385, 376, 2, 1, 16, 49, BUILD_DESCRIPTOR(_collection_interface, _missile), BUILD_DESCRIPTOR(_collection_interface, _missile_casing), true},
176 			{ _unused_interface_data, 0, 0, 0, 0, 0, 0, UNONE, UNONE, true }
177 		},
178 		UNONE, UNONE,
179 		0, 0
180 	},
181 
182 	/* ???, the flame thrower */
183 	{
184 		_i_flamethrower,
185 		BUILD_DESCRIPTOR(_collection_interface, _flamethrower_panel),
186 		433, 445,
187 		398, NONE,
188 		363, 475,
189 		false,
190 		{
191 			/* This weapon has 7 seconds of flamethrower carnage.. */
192 			{ _uses_energy, 427, 369, 7*TICKS_PER_SECOND, 0, 38, 57, _energy_weapon_full_color, _energy_weapon_empty_color, true},
193 			{ _unused_interface_data, 450, 410, 50, 0, 62, 7, _energy_weapon_full_color, _energy_weapon_empty_color, true}
194 		},
195 		UNONE, UNONE,
196 		0, 0
197 	},
198 
199 	/* Predator, the alien shotgun */
200 	{
201 		_i_alien_shotgun,
202 		BUILD_DESCRIPTOR(_collection_interface, _alien_weapon_panel),
203 		418, 445,
204 		395, 575,
205 		359, 400,
206 		false,
207 		{
208 			{ _unused_interface_data, 425, 411, 50, 0, 96, 7, _energy_weapon_full_color, _energy_weapon_empty_color, true},
209 			{ _unused_interface_data, 450, 410, 50, 0, 62, 7, _energy_weapon_full_color, _energy_weapon_empty_color, true}
210 		},
211 		UNONE, UNONE,
212 		0, 0
213 	},
214 
215 	/* Shotgun */
216 	{
217 		_i_shotgun,
218 		BUILD_DESCRIPTOR(_collection_interface, _single_shotgun),
219 		432, 444,
220 		420, NONE,
221 		373, 451,
222 		true,
223 		{
224 			{ _uses_bullets, 483, 411, 2, 1, 12, 16, BUILD_DESCRIPTOR(_collection_interface, _shotgun_bullet), BUILD_DESCRIPTOR(_collection_interface, _shotgun_casing), true},
225 			{ _uses_bullets, 451, 411, 2, 1, 12, 16, BUILD_DESCRIPTOR(_collection_interface, _shotgun_bullet), BUILD_DESCRIPTOR(_collection_interface, _shotgun_casing), true}
226 		},
227 		BUILD_DESCRIPTOR(_collection_interface, _double_shotgun),
228 		UNONE,
229 		0, -12
230 	},
231 
232 	/* Ball */
233 	{
234 		_i_red_ball, // statistically unlikely to be valid (really should be SKULL)
235 		BUILD_DESCRIPTOR(_collection_interface, _skull),
236 		432, 444,
237 		402, NONE,
238 		366, 465,
239 		false,
240 		{
241 			{ _unused_interface_data, 451, 411, 2, 1, 12, 16, BUILD_DESCRIPTOR(_collection_interface, _shotgun_bullet), BUILD_DESCRIPTOR(_collection_interface, _shotgun_casing), true},
242 			{ _unused_interface_data, 483, 411, 2, 1, 12, 16, BUILD_DESCRIPTOR(_collection_interface, _shotgun_bullet), BUILD_DESCRIPTOR(_collection_interface, _shotgun_casing), true}
243 		},
244 		UNONE, UNONE,
245 		0, 0
246 	},
247 
248 	/* LP addition: SMG (clone of assault rifle) */
249 	{
250 		_i_smg,
251 		BUILD_DESCRIPTOR(_collection_interface, _smg),
252 		430, 452,
253 		439, NONE, //��
254 		366, 460,
255 		false,
256 		{
257 			{ _uses_bullets, 405, 382, 8, 4, 5, 10, BUILD_DESCRIPTOR(_collection_interface, _smg_bullet), BUILD_DESCRIPTOR(_collection_interface, _smg_casing), true},
258 			{ _unused_interface_data, 390, 413, 7, 1, 8, 12, BUILD_DESCRIPTOR(_collection_interface, _assault_rifle_grenade), BUILD_DESCRIPTOR(_collection_interface, _assault_rifle_grenade_casing), true},
259 		},
260 		UNONE, UNONE,
261 		0, 0
262 	},
263 };
264 
265 // Software rendering
266 HUD_SW_Class HUD_SW;
267 
268 /* --------- code */
269 
initialize_game_window(void)270 void initialize_game_window(void)
271 {
272 	initialize_motion_sensor(
273 		BUILD_DESCRIPTOR(_collection_interface, _motion_sensor_mount),
274 		BUILD_DESCRIPTOR(_collection_interface, _motion_sensor_virgin_mount),
275 		BUILD_DESCRIPTOR(_collection_interface, _motion_sensor_alien),
276 		BUILD_DESCRIPTOR(_collection_interface, _motion_sensor_friend),
277 		BUILD_DESCRIPTOR(_collection_interface, _motion_sensor_enemy),
278 		BUILD_DESCRIPTOR(_collection_interface, _network_compass_shape_nw),
279 		MOTION_SENSOR_SIDE_LENGTH);
280 }
281 
282 /* draws the entire interface */
draw_interface(void)283 void draw_interface(void)
284 {
285 	if (alephone::Screen::instance()->openGL())
286 		return;
287 
288 	if (!game_window_is_full_screen())
289 	{
290 		/* draw the frame */
291 		draw_panels();
292 	}
293 
294 	validate_world_window();
295 }
296 
297 /* updates only what needs changing (time_elapsed==NONE means redraw everything no matter what,
298 	but skip the interface frame) */
update_interface(short time_elapsed)299 void update_interface(short time_elapsed)
300 {
301 	if (time_elapsed == NONE)
302         reset_motion_sensor(current_player_index);
303 	if (alephone::Screen::instance()->openGL() || alephone::Screen::instance()->lua_hud())
304         return;
305 
306 	if (!game_window_is_full_screen())
307 	{
308 		// LP addition: don't force an update unless explicitly requested
309 		bool force_update = (time_elapsed == NONE);
310 
311 		ensure_HUD_buffer();
312 
313 		// LP addition: added support for HUD buffer;
314 		_set_port_to_HUD();
315 		if (HUD_SW.update_everything(time_elapsed))
316 			force_update = true;
317 		_restore_port();
318 
319 		// Draw the whole thing if doing so is requested
320 		// (may need some smart way of drawing only what has to be drawn)
321 		if (force_update)
322 			RequestDrawingHUD();
323 	}
324 }
325 
mark_interface_collections(bool loading)326 void mark_interface_collections(bool loading)
327 {
328 	loading ? mark_collection_for_loading(_collection_interface) :
329 		mark_collection_for_unloading(_collection_interface);
330 }
331 
mark_weapon_display_as_dirty(void)332 void mark_weapon_display_as_dirty(void)
333 {
334 	interface_state.weapon_is_dirty = true;
335 }
336 
mark_ammo_display_as_dirty(void)337 void mark_ammo_display_as_dirty(void)
338 {
339 	interface_state.ammo_is_dirty = true;
340 }
341 
mark_shield_display_as_dirty(void)342 void mark_shield_display_as_dirty(void)
343 {
344 	interface_state.shield_is_dirty = true;
345 }
346 
mark_oxygen_display_as_dirty(void)347 void mark_oxygen_display_as_dirty(void)
348 {
349 	interface_state.oxygen_is_dirty = true;
350 }
351 
mark_player_inventory_screen_as_dirty(short player_index,short screen)352 void mark_player_inventory_screen_as_dirty(short player_index, short screen)
353 {
354 	struct player_data *player= get_player_data(player_index);
355 
356 	set_current_inventory_screen(player_index, screen);
357 	SET_INVENTORY_DIRTY_STATE(player, true);
358 }
359 
mark_player_inventory_as_dirty(short player_index,short dirty_item)360 void mark_player_inventory_as_dirty(short player_index, short dirty_item)
361 {
362 	struct player_data *player= get_player_data(player_index);
363 
364 	/* If the dirty item is not NONE, then goto that item kind display.. */
365 	if(dirty_item != NONE)
366 	{
367 		short item_kind= get_item_kind(dirty_item);
368 		short current_screen= GET_CURRENT_INVENTORY_SCREEN(player);
369 
370 		/* Don't change if it is a powerup, or you are in the network statistics screen */
371 		if(item_kind != _powerup && item_kind != current_screen) // && current_screen!=_network_statistics)
372 		{
373 			/* Goto that type of item.. */
374 			set_current_inventory_screen(player_index, item_kind);
375 		}
376 	}
377 	SET_INVENTORY_DIRTY_STATE(player, true);
378 }
379 
mark_player_network_stats_as_dirty(short player_index)380 void mark_player_network_stats_as_dirty(short player_index)
381 {
382 	if (GET_GAME_OPTIONS()&_live_network_stats)
383 	{
384 		struct player_data *player= get_player_data(player_index);
385 
386 		set_current_inventory_screen(player_index, _network_statistics);
387 		SET_INVENTORY_DIRTY_STATE(player, true);
388 	}
389 }
390 
set_interface_microphone_recording_state(bool state)391 void set_interface_microphone_recording_state(bool state)
392 {
393 #if !defined(DISABLE_NETWORKING)
394 	set_network_microphone_state(state);
395 #endif // !defined(DISABLE_NETWORKING)
396 }
397 
scroll_inventory(short dy)398 void scroll_inventory(short dy)
399 {
400 	short mod_value, index, current_inventory_screen, section_count, test_inventory_screen = 0;
401 	short section_items[NUMBER_OF_ITEMS];
402 	short section_counts[NUMBER_OF_ITEMS];
403 
404 	current_inventory_screen= GET_CURRENT_INVENTORY_SCREEN(current_player);
405 
406 	if(dynamic_world->player_count>1)
407 	{
408 		mod_value= NUMBER_OF_ITEM_TYPES+1;
409 	} else {
410 		mod_value= NUMBER_OF_ITEM_TYPES;
411 	}
412 
413 	if(dy>0)
414 	{
415 		for(index= 1; index<mod_value; ++index)
416 		{
417 			test_inventory_screen= (current_inventory_screen+index)%mod_value;
418 
419 			assert(test_inventory_screen>=0 && test_inventory_screen<NUMBER_OF_ITEM_TYPES+1);
420 			if(test_inventory_screen != NUMBER_OF_ITEM_TYPES)
421 			{
422 				calculate_player_item_array(current_player_index, test_inventory_screen,
423 					section_items, section_counts, &section_count);
424 				if(section_count) break; /* Go tho this one! */
425 			} else {
426 				/* Network statistics! */
427 				break;
428 			}
429 		}
430 
431 		current_inventory_screen= test_inventory_screen;
432 	} else {
433 		/* Going down.. */
434 		for(index= mod_value-1; index>0; --index)
435 		{
436 			test_inventory_screen= (current_inventory_screen+index)%mod_value;
437 
438 			assert(test_inventory_screen>=0 && test_inventory_screen<NUMBER_OF_ITEM_TYPES+1);
439 			if(test_inventory_screen != NUMBER_OF_ITEM_TYPES)
440 			{
441 				calculate_player_item_array(current_player_index, test_inventory_screen,
442 					section_items, section_counts, &section_count);
443 				if(section_count) break; /* Go tho this one! */
444 			} else {
445 				/* Network statistics! */
446 				break;
447 			}
448 		}
449 
450 		current_inventory_screen= test_inventory_screen;
451 	}
452 	set_current_inventory_screen(current_player_index, current_inventory_screen);
453 
454 	SET_INVENTORY_DIRTY_STATE(current_player, true);
455 }
456 
set_current_inventory_screen(short player_index,short screen)457 static void set_current_inventory_screen(
458 	short player_index,
459 	short screen)
460 {
461 	struct player_data *player= get_player_data(player_index);
462 
463 	assert(screen>=0 && screen<7);
464 
465 	player->interface_flags&= ~INVENTORY_MASK_BITS;
466 	player->interface_flags|= screen;
467 	player->interface_decay= 5*TICKS_PER_SECOND;
468 }
469 
470 // From sreen_sdl.cpp
471 extern SDL_Surface *HUD_Buffer;
472 extern void build_sdl_color_table(const color_table *color_table, SDL_Color *colors);
473 
474 // From game_window.cpp
475 extern HUD_SW_Class HUD_SW;
476 
477 extern void draw_panels(void);
478 
ensure_HUD_buffer(void)479 void ensure_HUD_buffer(void) {
480 
481   // Allocate surface for HUD if not present
482   if (HUD_Buffer == NULL) {
483     HUD_Buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480, 32,
484 									  0x00ff0000,
485 									  0x0000ff00,
486 									  0x000000ff,
487 									  0xff000000);
488     if (HUD_Buffer == NULL)
489       alert_out_of_memory();
490   }
491 }
492 
493 /*
494  *  Draw HUD (to HUD surface)
495  */
496 
497 extern int LuaTexturePaletteSize();
498 
draw_panels(void)499 void draw_panels(void)
500 {
501 	if (alephone::Screen::instance()->openGL())
502 		return;
503 
504 	ensure_HUD_buffer();
505 
506 	// Draw static HUD picture
507 	static SDL_Surface *static_hud_pict = NULL;
508 	static bool hud_pict_not_found = false;
509 	if (static_hud_pict == NULL && !hud_pict_not_found) {
510 		LoadedResource rsrc;
511 		if (get_picture_resource_from_images(INTERFACE_PANEL_BASE, rsrc))
512 			static_hud_pict = picture_to_surface(rsrc);
513 		else
514 			hud_pict_not_found = true;
515 	}
516 
517 	if (!hud_pict_not_found) {
518 		SDL_Rect dst_rect = {0, 320, 640, 160};
519 		if (!LuaTexturePaletteSize())
520 			SDL_BlitSurface(static_hud_pict, NULL, HUD_Buffer, &dst_rect);
521 		else
522 			SDL_FillRect(HUD_Buffer, &dst_rect, 0);
523 	}
524 
525 	// Add dynamic elements
526 	_set_port_to_HUD();
527 	HUD_SW.update_everything(NONE);
528 	_restore_port();
529 
530 	// Tell main loop to render the HUD in the next run
531 	RequestDrawingHUD();
532 }
533 
534 extern short vidmasterStringSetID; // shell.cpp
535 struct weapon_interface_data *original_weapon_interface_definitions = NULL;
536 
reset_mml_interface()537 void reset_mml_interface()
538 {
539 	if (original_weapon_interface_definitions) {
540 		for (unsigned i = 0; i < NUMBER_OF_WEAPON_INTERFACE_DEFINITIONS; i++)
541 			weapon_interface_definitions[i] = original_weapon_interface_definitions[i];
542 		free(original_weapon_interface_definitions);
543 		original_weapon_interface_definitions = NULL;
544 	}
545 }
546 
parse_mml_interface(const InfoTree & root)547 void parse_mml_interface(const InfoTree& root)
548 {
549 	// back up old values first
550 	if (!original_weapon_interface_definitions) {
551 		original_weapon_interface_definitions = (struct weapon_interface_data *) malloc(sizeof(struct weapon_interface_data) * NUMBER_OF_WEAPON_INTERFACE_DEFINITIONS);
552 		assert(original_weapon_interface_definitions);
553 		for (unsigned i = 0; i < NUMBER_OF_WEAPON_INTERFACE_DEFINITIONS; i++)
554 			original_weapon_interface_definitions[i] = weapon_interface_definitions[i];
555 	}
556 
557 	root.read_attr("motion_sensor", MotionSensorActive);
558 
559 	BOOST_FOREACH(InfoTree rect, root.children_named("rect"))
560 	{
561 		int16 index;
562 		if (!rect.read_indexed("index", index, NUMBER_OF_INTERFACE_RECTANGLES))
563 			continue;
564 		screen_rectangle *r = get_interface_rectangle(index);
565 
566 		int16 top, left, bottom, right;
567 		if (rect.read_attr("top", top) &&
568 			rect.read_attr("left", left) &&
569 			rect.read_attr("bottom", bottom) &&
570 			rect.read_attr("right", right))
571 		{
572 			r->top = top;
573 			r->left = left;
574 			r->bottom = bottom;
575 			r->right = right;
576 		}
577 	}
578 
579 	BOOST_FOREACH(InfoTree color, root.children_named("color"))
580 	{
581 		int16 index;
582 		if (!color.read_indexed("index", index, NUMBER_OF_INTERFACE_COLORS))
583 			continue;
584 		color.read_color(get_interface_color(index));
585 	}
586 	BOOST_FOREACH(InfoTree font, root.children_named("font"))
587 	{
588 		int16 index;
589 		if (!font.read_indexed("index", index, NUMBER_OF_INTERFACE_FONTS))
590 			continue;
591 		font.read_font(get_interface_font(index));
592 	}
593 
594 	BOOST_FOREACH(InfoTree vid, root.children_named("vidmaster"))
595 	{
596 		vidmasterStringSetID = -1;
597 		vid.read_attr_bounded<int16>("stringset_index", vidmasterStringSetID, -1, SHRT_MAX);
598 	}
599 
600 	BOOST_FOREACH(InfoTree weapon, root.children_named("weapon"))
601 	{
602 		int16 index;
603 		if (!weapon.read_indexed("index", index, MAXIMUM_WEAPON_INTERFACE_DEFINITIONS))
604 			continue;
605 		weapon_interface_data& def = weapon_interface_definitions[index];
606 
607 		weapon.read_attr("shape", def.weapon_panel_shape);
608 		weapon.read_attr("start_y", def.weapon_name_start_y);
609 		weapon.read_attr("end_y", def.weapon_name_end_y);
610 		weapon.read_attr("start_x", def.weapon_name_start_x);
611 		weapon.read_attr("end_x", def.weapon_name_end_x);
612 		weapon.read_attr("top", def.standard_weapon_panel_top);
613 		weapon.read_attr("left", def.standard_weapon_panel_left);
614 		weapon.read_attr("multiple", def.multi_weapon);
615 		weapon.read_attr("multiple_shape", def.multiple_shape);
616 		weapon.read_attr("multiple_unusable_shape", def.multiple_unusable_shape);
617 		weapon.read_attr("multiple_delta_x", def.multiple_delta_x);
618 		weapon.read_attr("multiple_delta_y", def.multiple_delta_y);
619 
620 		BOOST_FOREACH(InfoTree ammo, weapon.children_named("ammo"))
621 		{
622 			int16 index;
623 			if (!ammo.read_indexed("index", index, NUMBER_OF_WEAPON_INTERFACE_ITEMS))
624 				continue;
625 			weapon_interface_ammo_data& adef = def.ammo_data[index];
626 
627 			ammo.read_attr("type", adef.type);
628 			ammo.read_attr("left", adef.screen_left);
629 			ammo.read_attr("top", adef.screen_top);
630 			ammo.read_attr("across", adef.ammo_across);
631 			ammo.read_attr("down", adef.ammo_down);
632 			ammo.read_attr("delta_x", adef.delta_x);
633 			ammo.read_attr("delta_y", adef.delta_y);
634 			ammo.read_attr("bullet_shape", adef.bullet);
635 			ammo.read_attr("empty_shape", adef.empty_bullet);
636 			ammo.read_attr("right_to_left", adef.right_to_left);
637 		}
638 	}
639 }
640