/* GAME_WINDOW.C Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc. and the "Aleph One" developers. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. This license is contained in the file "COPYING", which is included with this source code; it is available online at http://www.gnu.org/licenses/gpl.html Thursday, December 30, 1993 9:51:24 PM Tuesday, May 24, 1994 6:42:32 PM functions beginning with underscores are mac-specific and always have a corresponding portable function which sets up game-specific information (see update_compass and _update_compass for an example). Friday, June 10, 1994 3:56:57 AM gutted, rewritten. Much cleaner now. Sunday, September 4, 1994 6:32:05 PM made scroll_inventory() non-static so that shell.c can call it. Saturday, September 24, 1994 10:33:19 AM fixed some things, twice... Friday, October 7, 1994 3:13:22 PM New interface. Draws panels from PICT resources for memory consumption. Inventory is different panels, which are switched to whenever you grab an item. There is no scrolling. Tuesday, June 6, 1995 3:37:50 PM Marathon II modifications. Tuesday, August 29, 1995 4:02:15 PM Reestablishing a level of portablility... Feb 4, 2000 (Loren Petrich): Added SMG display stuff Apr 30, 2000 (Loren Petrich): Added XML parser object for all the screen_drawing data, and also essentiall all the data here. May 28, 2000 (Loren Petrich): Added support for buffering the Heads-Up Display Jul 2, 2000 (Loren Petrich): The HUD is now always buffered Jul 16, 2001 (Loren Petrich): Using "temporary" as storage space for count_text and weapon_name; it is 256 bytes long, which should be more than enough for most text. This fixes the long-weapon-name bug. Mar 08, 2002 (Woody Zenfell): SDL network microphone support */ #include "cseries.h" #ifdef __WIN32__ #include #endif #ifdef HAVE_OPENGL # if defined (__APPLE__) && defined (__MACH__) # include # elif defined mac # include # else # include # endif #endif #include "HUDRenderer_SW.h" #include "game_window.h" // LP addition: color and font parsers #include "ColorParser.h" #include "FontHandler.h" #include "screen.h" #include "shell.h" #include "preferences.h" #include "screen.h" #include "screen_definitions.h" #include "images.h" #include "network_sound.h" #ifdef HAVE_OPENGL # if defined (__APPLE__) && defined (__MACH__) # include # elif defined mac # include # else # include # endif #endif #ifdef env68k #pragma segment screen #endif extern void draw_panels(void); extern void validate_world_window(void); static void set_current_inventory_screen(short player_index, short screen); /* --------- globals */ // LP addition: whether or not the motion sensor is active bool MotionSensorActive = true; struct interface_state_data interface_state; #define NUMBER_OF_WEAPON_INTERFACE_DEFINITIONS 10 struct weapon_interface_data weapon_interface_definitions[NUMBER_OF_WEAPON_INTERFACE_DEFINITIONS] = { /* Mac, the knife.. */ { _i_knife, UNONE, 433, 432, NONE, NONE, 0, 0, false, { { _unused_interface_data, 0, 0, 0, 0, 0, 0, UNONE, UNONE, true}, { _unused_interface_data, 0, 0, 0, 0, 0, 0, UNONE, UNONE, true} }, UNONE, UNONE, 0, 0 }, /* Harry, the .44 */ { _i_magnum, BUILD_DESCRIPTOR(_collection_interface, _magnum_panel), 432, 444, 420, NONE, 366, 517, true, { { _uses_bullets, 517, 412, 8, 1, 5, 14, BUILD_DESCRIPTOR(_collection_interface, _magnum_bullet), BUILD_DESCRIPTOR(_collection_interface, _magnum_casing), false}, { _uses_bullets, 452, 412, 8, 1, 5, 14, BUILD_DESCRIPTOR(_collection_interface, _magnum_bullet), BUILD_DESCRIPTOR(_collection_interface, _magnum_casing), true} }, BUILD_DESCRIPTOR(_collection_interface, _left_magnum), BUILD_DESCRIPTOR(_collection_interface, _left_magnum_unusable), -97, 0 }, /* Ripley, the plasma pistol. */ { _i_plasma_pistol, BUILD_DESCRIPTOR(_collection_interface, _zeus_panel), 431, 443, 401, NONE, 366, 475, false, { { _uses_energy, 414, 366, 20, 0, 38, 57, _energy_weapon_full_color, _energy_weapon_empty_color, true}, { _unused_interface_data, 450, 410, 50, 0, 62, 7, _energy_weapon_full_color, _energy_weapon_empty_color, true} }, UNONE, UNONE, 0, 0 }, /* Arnold, the assault rifle */ { _i_assault_rifle, BUILD_DESCRIPTOR(_collection_interface, _assault_panel), 430, 452, 439, NONE, //ее 366, 460, false, { { _uses_bullets, 391, 368, 13, 4, 4, 10, BUILD_DESCRIPTOR(_collection_interface, _assault_rifle_bullet), BUILD_DESCRIPTOR(_collection_interface, _assault_rifle_casing), true}, { _uses_bullets, 390, 413, 7, 1, 8, 12, BUILD_DESCRIPTOR(_collection_interface, _assault_rifle_grenade), BUILD_DESCRIPTOR(_collection_interface, _assault_rifle_grenade_casing), true}, }, UNONE, UNONE, 0, 0 }, /* John R., the missile launcher */ { _i_missile_launcher, BUILD_DESCRIPTOR(_collection_interface, _missile_panel), 433, 445, 426, NONE, 365, 419, false, { { _uses_bullets, 385, 376, 2, 1, 16, 49, BUILD_DESCRIPTOR(_collection_interface, _missile), BUILD_DESCRIPTOR(_collection_interface, _missile_casing), true}, { _unused_interface_data, 0, 0, 0, 0, 0, 0, UNONE, UNONE, true } }, UNONE, UNONE, 0, 0 }, /* ???, the flame thrower */ { _i_flamethrower, BUILD_DESCRIPTOR(_collection_interface, _flamethrower_panel), 433, 445, 398, NONE, 363, 475, false, { /* This weapon has 7 seconds of flamethrower carnage.. */ { _uses_energy, 427, 369, 7*TICKS_PER_SECOND, 0, 38, 57, _energy_weapon_full_color, _energy_weapon_empty_color, true}, { _unused_interface_data, 450, 410, 50, 0, 62, 7, _energy_weapon_full_color, _energy_weapon_empty_color, true} }, UNONE, UNONE, 0, 0 }, /* Predator, the alien shotgun */ { _i_alien_shotgun, BUILD_DESCRIPTOR(_collection_interface, _alien_weapon_panel), 418, 445, 395, 575, 359, 400, false, { { _unused_interface_data, 425, 411, 50, 0, 96, 7, _energy_weapon_full_color, _energy_weapon_empty_color, true}, { _unused_interface_data, 450, 410, 50, 0, 62, 7, _energy_weapon_full_color, _energy_weapon_empty_color, true} }, UNONE, UNONE, 0, 0 }, /* Shotgun */ { _i_shotgun, BUILD_DESCRIPTOR(_collection_interface, _single_shotgun), 432, 444, 420, NONE, 373, 451, true, { { _uses_bullets, 483, 411, 2, 1, 12, 16, BUILD_DESCRIPTOR(_collection_interface, _shotgun_bullet), BUILD_DESCRIPTOR(_collection_interface, _shotgun_casing), true}, { _uses_bullets, 451, 411, 2, 1, 12, 16, BUILD_DESCRIPTOR(_collection_interface, _shotgun_bullet), BUILD_DESCRIPTOR(_collection_interface, _shotgun_casing), true} }, BUILD_DESCRIPTOR(_collection_interface, _double_shotgun), UNONE, 0, -12 }, /* Ball */ { _i_red_ball, // statistically unlikely to be valid (really should be SKULL) BUILD_DESCRIPTOR(_collection_interface, _skull), 432, 444, 402, NONE, 366, 465, false, { { _unused_interface_data, 451, 411, 2, 1, 12, 16, BUILD_DESCRIPTOR(_collection_interface, _shotgun_bullet), BUILD_DESCRIPTOR(_collection_interface, _shotgun_casing), true}, { _unused_interface_data, 483, 411, 2, 1, 12, 16, BUILD_DESCRIPTOR(_collection_interface, _shotgun_bullet), BUILD_DESCRIPTOR(_collection_interface, _shotgun_casing), true} }, UNONE, UNONE, 0, 0 }, /* LP addition: SMG (clone of assault rifle) */ { _i_smg, BUILD_DESCRIPTOR(_collection_interface, _smg), 430, 452, 439, NONE, //ее 366, 460, false, { { _uses_bullets, 405, 382, 8, 4, 5, 10, BUILD_DESCRIPTOR(_collection_interface, _smg_bullet), BUILD_DESCRIPTOR(_collection_interface, _smg_casing), true}, { _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}, }, UNONE, UNONE, 0, 0 }, }; // Is OpenGL rendering of the HUD currently active? bool OGL_HUDActive = false; // Software rendering HUD_SW_Class HUD_SW; /* --------- code */ void initialize_game_window(void) { initialize_motion_sensor( BUILD_DESCRIPTOR(_collection_interface, _motion_sensor_mount), BUILD_DESCRIPTOR(_collection_interface, _motion_sensor_virgin_mount), BUILD_DESCRIPTOR(_collection_interface, _motion_sensor_alien), BUILD_DESCRIPTOR(_collection_interface, _motion_sensor_friend), BUILD_DESCRIPTOR(_collection_interface, _motion_sensor_enemy), BUILD_DESCRIPTOR(_collection_interface, _network_compass_shape_nw), MOTION_SENSOR_SIDE_LENGTH); } /* draws the entire interface */ void draw_interface(void) { if (OGL_HUDActive) return; if (!game_window_is_full_screen()) { /* draw the frame */ draw_panels(); } validate_world_window(); } /* updates only what needs changing (time_elapsed==NONE means redraw everything no matter what, but skip the interface frame) */ void update_interface(short time_elapsed) { if (OGL_HUDActive) { if (time_elapsed == NONE) reset_motion_sensor(current_player_index); else return; } if (!game_window_is_full_screen()) { // LP addition: don't force an update unless explicitly requested bool force_update = (time_elapsed == NONE); ensure_HUD_buffer(); // LP addition: added support for HUD buffer; _set_port_to_HUD(); if (HUD_SW.update_everything(time_elapsed)) force_update = true; _restore_port(); // Draw the whole thing if doing so is requested // (may need some smart way of drawing only what has to be drawn) if (force_update) RequestDrawingHUD(); } } void mark_interface_collections(bool loading) { loading ? mark_collection_for_loading(_collection_interface) : mark_collection_for_unloading(_collection_interface); } void mark_weapon_display_as_dirty(void) { interface_state.weapon_is_dirty = true; } void mark_ammo_display_as_dirty(void) { interface_state.ammo_is_dirty = true; } void mark_shield_display_as_dirty(void) { interface_state.shield_is_dirty = true; } void mark_oxygen_display_as_dirty(void) { interface_state.oxygen_is_dirty = true; } void mark_player_inventory_screen_as_dirty(short player_index, short screen) { struct player_data *player= get_player_data(player_index); set_current_inventory_screen(player_index, screen); SET_INVENTORY_DIRTY_STATE(player, true); } void mark_player_inventory_as_dirty(short player_index, short dirty_item) { struct player_data *player= get_player_data(player_index); /* If the dirty item is not NONE, then goto that item kind display.. */ if(dirty_item != NONE) { short item_kind= get_item_kind(dirty_item); short current_screen= GET_CURRENT_INVENTORY_SCREEN(player); /* Don't change if it is a powerup, or you are in the network statistics screen */ if(item_kind != _powerup && item_kind != current_screen) // && current_screen!=_network_statistics) { /* Goto that type of item.. */ set_current_inventory_screen(player_index, item_kind); } } SET_INVENTORY_DIRTY_STATE(player, true); } void mark_player_network_stats_as_dirty(short player_index) { if (GET_GAME_OPTIONS()&_live_network_stats) { struct player_data *player= get_player_data(player_index); set_current_inventory_screen(player_index, _network_statistics); SET_INVENTORY_DIRTY_STATE(player, true); } } void set_interface_microphone_recording_state(bool state) { #if !defined(DISABLE_NETWORKING) set_network_microphone_state(state); #endif // !defined(DISABLE_NETWORKING) } void scroll_inventory(short dy) { short mod_value, index, current_inventory_screen, section_count, test_inventory_screen = 0; short section_items[NUMBER_OF_ITEMS]; short section_counts[NUMBER_OF_ITEMS]; current_inventory_screen= GET_CURRENT_INVENTORY_SCREEN(current_player); if(dynamic_world->player_count>1) { mod_value= NUMBER_OF_ITEM_TYPES+1; } else { mod_value= NUMBER_OF_ITEM_TYPES; } if(dy>0) { for(index= 1; index=0 && test_inventory_screen0; --index) { test_inventory_screen= (current_inventory_screen+index)%mod_value; assert(test_inventory_screen>=0 && test_inventory_screen=0 && screen<7); player->interface_flags&= ~INVENTORY_MASK_BITS; player->interface_flags|= screen; player->interface_decay= 5*TICKS_PER_SECOND; } // From sreen_sdl.cpp extern SDL_Surface *HUD_Buffer; extern void build_sdl_color_table(const color_table *color_table, SDL_Color *colors); // From game_window.cpp extern HUD_SW_Class HUD_SW; extern bool OGL_HUDActive; extern void draw_panels(void); void ensure_HUD_buffer(void) { // Allocate surface for HUD if not present if (HUD_Buffer == NULL) { SDL_Surface *s = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480, 8, 0xff, 0xff, 0xff, 0xff); if (s == NULL) alert_user(fatalError, strERRORS, outOfMemory, -1); HUD_Buffer = SDL_DisplayFormat(s); if (HUD_Buffer == NULL) alert_user(fatalError, strERRORS, outOfMemory, -1); SDL_FreeSurface(s); } } /* * Draw HUD (to HUD surface) */ void draw_panels(void) { if (OGL_HUDActive) return; ensure_HUD_buffer(); // Draw static HUD picture static SDL_Surface *static_hud_pict = NULL; static bool hud_pict_not_found = false; if (static_hud_pict == NULL && !hud_pict_not_found) { LoadedResource rsrc; if (get_picture_resource_from_images(INTERFACE_PANEL_BASE, rsrc)) static_hud_pict = picture_to_surface(rsrc); else hud_pict_not_found = true; } if (!hud_pict_not_found) { SDL_Rect dst_rect = {0, 320, 640, 160}; SDL_BlitSurface(static_hud_pict, NULL, HUD_Buffer, &dst_rect); } // Add dynamic elements _set_port_to_HUD(); HUD_SW.update_everything(NONE); _restore_port(); // Tell main loop to render the HUD in the next run RequestDrawingHUD(); } /* MML parser for the 'vidmaster' tag */ extern short vidmasterStringSetID; // shell.cpp class XML_VidmasterParser: public XML_ElementParser { short StringSetIndex; public: bool Start(); bool HandleAttribute(const char *Tag, const char *Value); bool AttributesDone(); XML_VidmasterParser(): XML_ElementParser("vidmaster") {} }; bool XML_VidmasterParser::Start() { StringSetIndex = -1; return true; } bool XML_VidmasterParser::HandleAttribute(const char *Tag, const char *Value) { if (StringsEqual(Tag, "stringset_index")) return ReadBoundedInt16Value(Value, StringSetIndex, -1, SHRT_MAX); /* Ideas for other attributes: enabled="{boolean}" (if not, no go-to-level for you) keys="shift,control"? */ UnrecognizedTag(); return false; } bool XML_VidmasterParser::AttributesDone() { vidmasterStringSetID = StringSetIndex; return true; } static XML_VidmasterParser VidmasterParser; /* * MML parser for interface elements */ class XML_AmmoDisplayParser: public XML_ElementParser { // Intended one to replace short Index; // Ammo data weapon_interface_ammo_data Data; // What is present? bool IndexPresent; enum {NumberOfValues = 10}; bool IsPresent[NumberOfValues]; public: bool Start(); bool HandleAttribute(const char *Tag, const char *Value); bool AttributesDone(); // Pointer to list of ammo data types, from the weapon parser weapon_interface_ammo_data *OrigAmmo; XML_AmmoDisplayParser(): XML_ElementParser("ammo") {OrigAmmo=0;} }; bool XML_AmmoDisplayParser::Start() { IndexPresent = false; for (int k=0; k