mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 04:49:39 -10:00
Also includes support for more than two mainhall resolutions, zooming so one mainhall can adapt to multiple resolutions, setting new mainhall fonts, help overlays for all resolutions and adjustable tooltip padding. Also allows preload screens to be any resolution & aspect ratio. git-svn-id: svn://svn.icculus.org/fs2open/trunk/fs2_open@10844 387891d4-d844-0410-90c0-e4c51a9137d3
1280 lines
33 KiB
C++
1280 lines
33 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
#include "globalincs/pstypes.h"
|
|
#include "mission/missionhotkey.h"
|
|
#include "gamesequence/gamesequence.h"
|
|
#include "freespace2/freespace.h"
|
|
#include "io/key.h"
|
|
#include "io/timer.h"
|
|
#include "gamesnd/gamesnd.h"
|
|
#include "sound/audiostr.h"
|
|
#include "ship/ship.h"
|
|
#include "object/object.h"
|
|
#include "globalincs/linklist.h"
|
|
#include "playerman/player.h"
|
|
#include "ui/ui.h"
|
|
#include "ui/uidefs.h"
|
|
#include "missionui/missionscreencommon.h"
|
|
#include "graphics/font.h"
|
|
#include "gamehelp/contexthelp.h"
|
|
#include "globalincs/alphacolors.h"
|
|
#include "weapon/weapon.h"
|
|
#include "iff_defs/iff_defs.h"
|
|
#include "parse/parselo.h"
|
|
|
|
|
|
static int Key_sets[MAX_KEYED_TARGETS] = {
|
|
KEY_F5,
|
|
KEY_F6,
|
|
KEY_F7,
|
|
KEY_F8,
|
|
KEY_F9,
|
|
KEY_F10,
|
|
KEY_F11,
|
|
KEY_F12
|
|
};
|
|
|
|
/////////////////////////////
|
|
|
|
static int Hotkey_bits[MAX_SHIPS]; // bitfield indicating which hotkeys are used by each ship
|
|
|
|
static int Hotkey_sets_saved; // have we saved the sets for this mission
|
|
|
|
static int Mission_hotkey_save_timestamp; // timestamp used to tell us when we can save
|
|
#define HOTKEY_SAVE_TIME 15000 // save sets this number of milliseconds into the mission
|
|
|
|
typedef struct {
|
|
int setnum;
|
|
char name[NAME_LENGTH];
|
|
} HK_save_info;
|
|
|
|
HK_save_info Hotkey_saved_info[MAX_HOTKEY_TARGET_ITEMS];
|
|
int Num_hotkeys_saved;
|
|
|
|
|
|
static char *Hotkey_background_fname[GR_NUM_RESOLUTIONS] = {
|
|
"Hotkeys", // GR_640
|
|
"2_Hotkeys" // GR_1024
|
|
};
|
|
|
|
static char *Hotkey_mask_fname[GR_NUM_RESOLUTIONS] = {
|
|
"Hotkeys-M", // GR_640
|
|
"2_Hotkeys-M" // GR_1024
|
|
};
|
|
|
|
//#define GROUP_LIST_X 40
|
|
//#define GROUP_LIST_W 160
|
|
|
|
// #define ICON_LIST_X 219
|
|
// #define ICON_LIST_W 8
|
|
|
|
// #define ICON_LIST_X 280
|
|
// #define ICON_LIST_W 8
|
|
|
|
//#define SHIP_LIST_X 242
|
|
//#define SHIP_LIST_X2 259
|
|
//#define SHIP_LIST_W 341
|
|
//#define SHIP_LIST_W2 324
|
|
|
|
// #define SHIP_LIST_X 302
|
|
// #define SHIP_LIST_X2 319
|
|
// #define SHIP_LIST_W 281
|
|
// #define SHIP_LIST_W2 264
|
|
|
|
// #define LIST_Y 70
|
|
// #define LIST_H 280
|
|
|
|
/*
|
|
#define HOTKEY_X 575
|
|
#define HOTKEY_Y 41
|
|
*/
|
|
|
|
#define HOTKEY_LINE_HEADING 1
|
|
#define HOTKEY_LINE_WING 2
|
|
#define HOTKEY_LINE_SHIP 3
|
|
#define HOTKEY_LINE_SUBSHIP 4 // ship that is in a wing
|
|
|
|
#define WING_FLAG 0x80000
|
|
|
|
#define MAX_LINES 200
|
|
#define NUM_BUTTONS 10
|
|
#define LIST_BUTTONS_MAX 50
|
|
|
|
#define SCROLL_UP_BUTTON 0
|
|
#define SCROLL_DOWN_BUTTON 1
|
|
#define CANCEL_BUTTON 2
|
|
#define CLEAR_BUTTON 3
|
|
#define RESET_BUTTON 4
|
|
#define ADD_HOTKEY_BUTTON 5
|
|
#define REMOVE_HOTKEY_BUTTON 6
|
|
#define HELP_BUTTON 7
|
|
#define OPTIONS_BUTTON 8
|
|
#define ACCEPT_BUTTON 9
|
|
|
|
// coords for entire ship box
|
|
static int Hotkey_list_coords[GR_NUM_RESOLUTIONS][4] = {
|
|
{
|
|
// GR_640
|
|
29, // x
|
|
22, // y
|
|
502, // w
|
|
315 // h
|
|
},
|
|
{
|
|
// GR_1024
|
|
47, // x
|
|
35, // y
|
|
802, // w
|
|
505 // h
|
|
}
|
|
};
|
|
|
|
// coords for big "F9" thing in the corner
|
|
static int Hotkey_function_name_coords[GR_NUM_RESOLUTIONS][4] = {
|
|
{
|
|
// GR_640
|
|
570, // x
|
|
14, // y
|
|
59, // w
|
|
22 // h
|
|
},
|
|
{
|
|
// GR_1024
|
|
912, // x
|
|
22, // y
|
|
94, // w
|
|
36 // h
|
|
}
|
|
};
|
|
|
|
/*
|
|
#define FIELD_LEFT_EDGE 0
|
|
#define FIELD_F5 1
|
|
#define FIELD_F6 2
|
|
#define FIELD_F7 3
|
|
#define FIELD_F8 4
|
|
#define FIELD_F9 5
|
|
#define FIELD_F10 6
|
|
#define FIELD_F11 7
|
|
#define FIELD_F12 8
|
|
#define FIELD_ICON 9
|
|
#define FIELD_RIGHT_EDGE 10
|
|
// x coords of unseen field boundaries ( | field1 | field2 | ... | )
|
|
// entried will all be centered in fields except FIELD_SHIP which will be left justified
|
|
// an edge is named by the field on its left
|
|
static int Hotkey_field_edge[GR_NUM_RESOLUTIONS][11] = {
|
|
{
|
|
29, 56, 83, 110, 137, 164, 191, 218, 245, 280, 531
|
|
},
|
|
{
|
|
47, 91, 135, 179, 223, 267, 311, 355, 399, 448, 849
|
|
}
|
|
}
|
|
*/
|
|
|
|
static int Hotkey_function_field_width[GR_NUM_RESOLUTIONS] = {
|
|
27, // GR_640
|
|
44 // GR_1024
|
|
};
|
|
static int Hotkey_wing_icon_x[GR_NUM_RESOLUTIONS] = {
|
|
246, // GR_640
|
|
400 // GR_1024
|
|
};
|
|
static int Hotkey_ship_x[GR_NUM_RESOLUTIONS] = {
|
|
280, // GR_640
|
|
448 // GR_1024
|
|
};
|
|
|
|
struct hotkey_buttons {
|
|
char *filename;
|
|
int x, y;
|
|
int hotspot;
|
|
UI_BUTTON button; // because we have a class inside this struct, we need the constructor below..
|
|
|
|
hotkey_buttons(char *name, int x1, int y1, int h) : filename(name), x(x1), y(y1), hotspot(h) {}
|
|
};
|
|
|
|
// button definitions
|
|
static hotkey_buttons Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
|
|
//XSTR:OFF
|
|
{
|
|
// GR_640
|
|
hotkey_buttons("HKB_00", 1, 94, 0),
|
|
hotkey_buttons("HKB_01", 1, 133, 1),
|
|
hotkey_buttons("HKB_02", 15, 342, 2),
|
|
hotkey_buttons("HKB_03", 84, 342, 3),
|
|
hotkey_buttons("HKB_04", 161, 342, 4),
|
|
hotkey_buttons("HKB_05", 539, 5, 5),
|
|
hotkey_buttons("HKB_06", 539, 44, 6),
|
|
hotkey_buttons("HKB_07", 539, 431, 7),
|
|
hotkey_buttons("HKB_08", 539, 455, 8),
|
|
hotkey_buttons("HKB_09", 575, 432, 9)
|
|
},
|
|
{
|
|
// GR_1024
|
|
hotkey_buttons("2_HKB_00", 2, 150, 0),
|
|
hotkey_buttons("2_HKB_01", 2, 213, 1),
|
|
hotkey_buttons("2_HKB_02", 24, 548, 2),
|
|
hotkey_buttons("2_HKB_03", 135, 548, 3),
|
|
hotkey_buttons("2_HKB_04", 258, 548, 4),
|
|
hotkey_buttons("2_HKB_05", 862, 8, 5),
|
|
hotkey_buttons("2_HKB_06", 862, 71, 6),
|
|
hotkey_buttons("2_HKB_07", 863, 690, 7),
|
|
hotkey_buttons("2_HKB_08", 862, 728, 8),
|
|
hotkey_buttons("2_HKB_09", 920, 692, 9)
|
|
}
|
|
//XSTR:ON
|
|
};
|
|
|
|
#define HOTKEY_NUM_TEXT 6
|
|
static UI_XSTR Hotkey_text[GR_NUM_RESOLUTIONS][HOTKEY_NUM_TEXT] = {
|
|
{
|
|
// GR_640
|
|
{ "Cancel", 1516, 7, 392, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_640][CANCEL_BUTTON].button },
|
|
{ "Clear", 1517, 85, 392, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_640][CLEAR_BUTTON].button },
|
|
{ "Reset", 1518, 159, 392, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_640][RESET_BUTTON].button },
|
|
{ "Help", 1519, 500, 440, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_640][HELP_BUTTON].button },
|
|
{ "Options", 1520, 479, 464, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_640][OPTIONS_BUTTON].button },
|
|
{ "Accept", 1521, 573, 413, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_640][ACCEPT_BUTTON].button }
|
|
},
|
|
{
|
|
// GR_1024
|
|
{ "Cancel", 1516, 30, 629, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_1024][CANCEL_BUTTON].button },
|
|
{ "Clear", 1517, 151, 629, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_1024][CLEAR_BUTTON].button },
|
|
{ "Reset", 1518, 269, 629, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_1024][RESET_BUTTON].button },
|
|
{ "Help", 1519, 800, 704, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_1024][HELP_BUTTON].button },
|
|
{ "Options", 1520, 797, 743, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_1024][OPTIONS_BUTTON].button },
|
|
{ "Accept", 1521, 902, 661, UI_XSTR_COLOR_GREEN, -1, &Buttons[GR_1024][ACCEPT_BUTTON].button }
|
|
}
|
|
};
|
|
|
|
|
|
|
|
static struct {
|
|
const char *label;
|
|
int type;
|
|
int index;
|
|
int y; // Y coordinate of line
|
|
} Hotkey_lines[MAX_LINES];
|
|
|
|
static int Cur_hotkey = 0;
|
|
static int Scroll_offset;
|
|
static int Num_lines;
|
|
static int Selected_line;
|
|
static int Background_bitmap;
|
|
static int Wing_bmp;
|
|
static UI_WINDOW Ui_window;
|
|
static UI_BUTTON List_buttons[LIST_BUTTONS_MAX]; // buttons for each line of text in list
|
|
//static UI_BUTTON List_region;
|
|
|
|
int Hotkey_overlay_id;
|
|
|
|
//////////////////////
|
|
|
|
|
|
// function used in a couple of places to get the actual hotkey set number from a key value.
|
|
// not trivial since our current keysets (F5 - F12) do not have sequential keycodes
|
|
int mission_hotkey_get_set_num( int k )
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_KEYED_TARGETS; i++ ) {
|
|
if ( Key_sets[i] == k ) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
Int3(); // get allender
|
|
return 0;
|
|
}
|
|
|
|
// function to maybe restore some hotkeys during the first N seconds of the mission
|
|
void mission_hotkey_maybe_restore()
|
|
{
|
|
int i, index;
|
|
|
|
for ( i = 0; i < Num_hotkeys_saved; i++ ) {
|
|
// don't process something that has no set
|
|
if ( Hotkey_saved_info[i].setnum == -1 )
|
|
continue;
|
|
|
|
// the ship is present, add it to the given set.
|
|
index = ship_name_lookup(Hotkey_saved_info[i].name);
|
|
if ( index != -1 ) {
|
|
hud_target_hotkey_add_remove( Hotkey_saved_info[i].setnum, &Objects[Ships[index].objnum], HOTKEY_USER_ADDED );
|
|
Hotkey_saved_info[i].setnum = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// mission_hotkey_set_defaults()
|
|
//
|
|
// Set up the hotkey lists for the player based on the mission designer
|
|
// defaults.
|
|
//
|
|
void mission_hotkey_set_defaults()
|
|
{
|
|
int i,j;
|
|
wing *wp;
|
|
ship *sp;
|
|
object *A;
|
|
|
|
for ( i = 0; i < MAX_KEYED_TARGETS; i++ ) {
|
|
hud_target_hotkey_clear(i);
|
|
}
|
|
|
|
// set the variable letting us know that we should save the hotkey sets
|
|
Hotkey_sets_saved = 0;
|
|
Mission_hotkey_save_timestamp = timestamp(HOTKEY_SAVE_TIME);
|
|
|
|
// if we have hotkeys saved from the previous run of this mission, then simply keep the cleared
|
|
// sets, and let the restore code take care of it! This works because this function is currently
|
|
// only called from one place -- after the mission loads.
|
|
if ( Num_hotkeys_saved > 0 ) {
|
|
mission_hotkey_maybe_restore();
|
|
return;
|
|
}
|
|
|
|
// Check for ships with a hotkey assigned
|
|
obj_merge_created_list();
|
|
for ( A = GET_FIRST(&obj_used_list); A !=END_OF_LIST(&obj_used_list); A = GET_NEXT(A) ) {
|
|
|
|
if ( (A == &obj_used_list) || (A->type != OBJ_SHIP) || ((Game_mode & GM_NORMAL) && (A == Player_obj)) ) {
|
|
continue;
|
|
}
|
|
|
|
Assert(A->instance >= 0 && A->instance < MAX_SHIPS);
|
|
sp = &Ships[A->instance];
|
|
|
|
if ( sp->hotkey == -1 )
|
|
continue;
|
|
|
|
// if the hotkey is the last hotkey in the list, then don't add it either since this hotkey is a special
|
|
// marker to indicate that this ship should remain invisible in the hotkey screen until after mission
|
|
// starts
|
|
if ( sp->hotkey == MAX_KEYED_TARGETS )
|
|
continue;
|
|
|
|
Assert(sp->objnum >= 0);
|
|
hud_target_hotkey_add_remove( sp->hotkey, &Objects[sp->objnum], HOTKEY_MISSION_FILE_ADDED );
|
|
}
|
|
|
|
// Check for wings with a hotkey assigned
|
|
for ( i = 0; i < Num_wings; i++ ) {
|
|
wp = &Wings[i];
|
|
|
|
if ( wp->hotkey == -1 )
|
|
continue;
|
|
|
|
// like ships, skip this wing if the hotkey is the last hotkey item
|
|
if ( wp->hotkey == MAX_KEYED_TARGETS )
|
|
continue;
|
|
|
|
for ( j = 0; j < wp->current_count; j++ ) {
|
|
if ( wp->ship_index[j] == -1 )
|
|
continue;
|
|
|
|
sp = &Ships[wp->ship_index[j]];
|
|
hud_target_hotkey_add_remove( wp->hotkey, &Objects[sp->objnum], HOTKEY_MISSION_FILE_ADDED );
|
|
}
|
|
}
|
|
}
|
|
|
|
// function to reset the saved hotkeys -- called when a new mission is loaded
|
|
void mission_hotkey_reset_saved()
|
|
{
|
|
Num_hotkeys_saved = 0;
|
|
}
|
|
|
|
// next function called when we might want to save the hotkey sets for the player. We will save the hotkey
|
|
// sets N seconds into the mission
|
|
void mission_hotkey_maybe_save_sets()
|
|
{
|
|
int i;
|
|
htarget_list *hitem, *plist;
|
|
HK_save_info *hkp;
|
|
|
|
if ( !timestamp_elapsed(Mission_hotkey_save_timestamp) ) {
|
|
mission_hotkey_maybe_restore();
|
|
return;
|
|
}
|
|
|
|
// no processing if we have saved them.
|
|
if ( Hotkey_sets_saved )
|
|
return;
|
|
|
|
for ( i = 0; i < MAX_HOTKEY_TARGET_ITEMS; i++ )
|
|
Hotkey_saved_info[i].setnum = -1;
|
|
|
|
Num_hotkeys_saved = 0;
|
|
hkp = &(Hotkey_saved_info[0]);
|
|
|
|
for ( i = 0; i < MAX_KEYED_TARGETS; i++ ) {
|
|
|
|
// get the list. do nothing if list is empty
|
|
plist = &(Player->keyed_targets[i]);
|
|
if ( EMPTY(plist) )
|
|
continue;
|
|
|
|
for ( hitem = GET_FIRST(plist); hitem != END_OF_LIST(plist); hitem = GET_NEXT(hitem) ) {
|
|
Assert( Num_hotkeys_saved < MAX_HOTKEY_TARGET_ITEMS );
|
|
hkp->setnum = i;
|
|
strcpy_s( hkp->name, Ships[hitem->objp->instance].ship_name );
|
|
hkp++;
|
|
Num_hotkeys_saved++;
|
|
}
|
|
}
|
|
|
|
Hotkey_sets_saved = 1;
|
|
}
|
|
|
|
// function which gets called from MissionParse to maybe add a ship or wing to a hotkey set.
|
|
// this intermediate function is needed so that we don't blast over possibly saved hotkey sets
|
|
void mission_hotkey_mf_add( int set, int objnum, int how_to_add )
|
|
{
|
|
// if we are restoring hotkeys, and the timer hasn't elapsed, then return and let the
|
|
// hotkey restoration code deal with it
|
|
if ( Num_hotkeys_saved && !timestamp_elapsed(Mission_hotkey_save_timestamp) )
|
|
return;
|
|
|
|
// we can add it to the set
|
|
hud_target_hotkey_add_remove( set, &Objects[objnum], how_to_add );
|
|
}
|
|
|
|
void mission_hotkey_validate()
|
|
{
|
|
htarget_list *hitem, *plist;
|
|
object *A;
|
|
int obj_valid, i;
|
|
|
|
for ( i = 0; i < MAX_KEYED_TARGETS; i++ ) {
|
|
plist = &(Players[Player_num].keyed_targets[i]);
|
|
if ( EMPTY( plist ) ) // no items in list, then do nothing
|
|
continue;
|
|
|
|
hitem = GET_FIRST(plist);
|
|
while ( hitem != END_OF_LIST(plist) ) {
|
|
|
|
// ensure this object is still valid and in the obj_used_list
|
|
obj_valid = FALSE;
|
|
for ( A = GET_FIRST(&obj_used_list); A !=END_OF_LIST(&obj_used_list); A = GET_NEXT(A) ) {
|
|
if ( A->signature == hitem->objp->signature ) {
|
|
obj_valid = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if ( obj_valid == FALSE ) {
|
|
htarget_list *temp;
|
|
|
|
temp = GET_NEXT(hitem);
|
|
list_remove( plist, hitem );
|
|
list_append( &htarget_free_list, hitem );
|
|
hitem->objp = NULL;
|
|
hitem = temp;
|
|
continue;
|
|
}
|
|
hitem = GET_NEXT( hitem );
|
|
} // end while
|
|
} // end for
|
|
}
|
|
|
|
|
|
// get the Hotkey_bits of a whole wing (bits must be set in all ships of wing for a hotkey bit to be set)
|
|
int get_wing_hotkeys(int n)
|
|
{
|
|
int i, total = 0xffffffff;
|
|
|
|
Assert((n >= 0) && (n < Num_wings));
|
|
for (i=0; i<Wings[n].current_count; i++) {
|
|
int ship_index;
|
|
|
|
// don't count the player ship for the total -- you cannot assign the player since bad things
|
|
// can happen on the hud.
|
|
ship_index = Wings[n].ship_index[i];
|
|
if ( &Ships[ship_index] == Player_ship )
|
|
continue;
|
|
|
|
total &= Hotkey_bits[Wings[n].ship_index[i]];
|
|
}
|
|
|
|
return total;
|
|
}
|
|
|
|
// add a line of hotkey smuck to end of list
|
|
int hotkey_line_add(const char *text, int type, int index, int y)
|
|
{
|
|
if (Num_lines >= MAX_LINES)
|
|
return 0;
|
|
|
|
Hotkey_lines[Num_lines].label = text;
|
|
Hotkey_lines[Num_lines].type = type;
|
|
Hotkey_lines[Num_lines].index = index;
|
|
Hotkey_lines[Num_lines].y = y;
|
|
return Num_lines++;
|
|
}
|
|
|
|
// insert a line of hotkey smuck before line 'n'.
|
|
int hotkey_line_insert(int n, char *text, int type, int index)
|
|
{
|
|
int z;
|
|
|
|
if (Num_lines >= MAX_LINES)
|
|
return 0;
|
|
|
|
z = Num_lines++;
|
|
while (z > n) {
|
|
Hotkey_lines[z] = Hotkey_lines[z - 1];
|
|
z--;
|
|
}
|
|
|
|
Hotkey_lines[z].label = text;
|
|
Hotkey_lines[z].type = type;
|
|
Hotkey_lines[z].index = index;
|
|
return z;
|
|
}
|
|
|
|
// insert a line of hotkey smuck somewhere between 'start' and end of list such that it is
|
|
// sorted by name
|
|
int hotkey_line_add_sorted(char *text, int type, int index, int start)
|
|
{
|
|
int z;
|
|
|
|
if (Num_lines >= MAX_LINES)
|
|
return -1;
|
|
|
|
z = Num_lines - 1;
|
|
while ((z >= start) && ((Hotkey_lines[z].type == HOTKEY_LINE_SUBSHIP) || (stricmp(text, Hotkey_lines[z].label) < 0)))
|
|
z--;
|
|
|
|
z++;
|
|
while ((z < Num_lines) && (Hotkey_lines[z].type == HOTKEY_LINE_SUBSHIP))
|
|
z++;
|
|
|
|
return hotkey_line_insert(z, text, type, index);
|
|
}
|
|
|
|
int hotkey_build_team_listing(int enemy_team_mask, int y, bool list_enemies)
|
|
{
|
|
ship_obj *so;
|
|
const char *str = NULL;
|
|
int i, j, s, z, start, team_mask;
|
|
int font_height = gr_get_font_height();
|
|
|
|
if (list_enemies)
|
|
{
|
|
str = XSTR( "Enemy ships", 403);
|
|
team_mask = enemy_team_mask;
|
|
}
|
|
else
|
|
{
|
|
str = XSTR( "Friendly ships", 402);
|
|
team_mask = ~enemy_team_mask;
|
|
}
|
|
|
|
for (i=0; i<MAX_SHIPS; i++)
|
|
if (iff_matches_mask(Ships[i].team, team_mask))
|
|
break;
|
|
|
|
if (i >= MAX_SHIPS)
|
|
return y;
|
|
|
|
hotkey_line_add(str, HOTKEY_LINE_HEADING, 0, y);
|
|
y += 2;
|
|
|
|
start = Num_lines;
|
|
|
|
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
|
|
int shipnum;
|
|
|
|
// don't process non-ships, or the player ship
|
|
if ( (Game_mode & GM_NORMAL) && (so->objnum == OBJ_INDEX(Player_obj)) )
|
|
continue;
|
|
|
|
shipnum = Objects[so->objnum].instance;
|
|
|
|
// filter out cargo containers, navbouys, etc, and non-ships
|
|
if ( Ship_info[Ships[shipnum].ship_info_index].class_type < 0 || !(Ship_types[Ship_info[Ships[shipnum].ship_info_index].class_type].hud_bools & STI_HUD_HOTKEY_ON_LIST ))
|
|
continue;
|
|
|
|
// don't process ships invisible to sensors, dying or departing
|
|
if ( Ships[shipnum].flags & (SF_HIDDEN_FROM_SENSORS|SF_DYING|SF_DEPARTING) )
|
|
continue;
|
|
|
|
// if a ship's hotkey is the last hotkey on the list, then maybe make the hotkey -1 if
|
|
// we are now in mission. Otherwise, skip this ship
|
|
if ( Ships[shipnum].hotkey == MAX_KEYED_TARGETS ) {
|
|
if ( !(Game_mode & GM_IN_MISSION) )
|
|
continue; // skip to next ship
|
|
Ships[shipnum].hotkey = -1;
|
|
}
|
|
|
|
// be sure this ship isn't in a wing, and that the teams match
|
|
if ( iff_matches_mask(Ships[shipnum].team, team_mask) && (Ships[shipnum].wingnum < 0) ) {
|
|
hotkey_line_add_sorted(Ships[shipnum].ship_name, HOTKEY_LINE_SHIP, shipnum, start);
|
|
}
|
|
}
|
|
|
|
for (i=0; i<Num_wings; i++) {
|
|
if (Wings[i].current_count && (Wings[i].ship_index[Wings[i].special_ship] >= 0) && iff_matches_mask(Ships[Wings[i].ship_index[Wings[i].special_ship]].team, team_mask)) {
|
|
// special check for the player's wing. If he's in a wing, and the only guy left, don't
|
|
// do anything
|
|
if ( (Player_ship->wingnum == i) && (Wings[i].current_count == 1) )
|
|
continue;
|
|
|
|
// if a ship's hotkey is the last hotkey on the list, then maybe make the hotkey -1 if
|
|
// we are now in mission. Otherwise, skip this ship
|
|
if ( Wings[i].hotkey == MAX_KEYED_TARGETS ) {
|
|
if ( !(Game_mode & GM_IN_MISSION) )
|
|
continue; // skip to next ship
|
|
Wings[i].hotkey = -1;
|
|
}
|
|
|
|
// don't add any wing data whose ships are hidden from sensors
|
|
for ( j = 0; j < Wings[i].current_count; j++ ) {
|
|
if ( Ships[Wings[i].ship_index[j]].flags & SF_HIDDEN_FROM_SENSORS )
|
|
break;
|
|
}
|
|
// if we didn't reach the end of the list, don't display the wing
|
|
if ( j < Wings[i].current_count )
|
|
continue;
|
|
|
|
z = hotkey_line_add_sorted(Wings[i].name, HOTKEY_LINE_WING, i, start);
|
|
if (Wings[i].flags & WF_EXPANDED) {
|
|
for (j=0; j<Wings[i].current_count; j++) {
|
|
s = Wings[i].ship_index[j];
|
|
z = hotkey_line_insert(z + 1, Ships[s].ship_name, HOTKEY_LINE_SUBSHIP, s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i=start; i<Num_lines; i++) {
|
|
if (Hotkey_lines[i].type == HOTKEY_LINE_SUBSHIP)
|
|
y += font_height;
|
|
else
|
|
y += font_height + 2;
|
|
|
|
Hotkey_lines[i].y = y;
|
|
}
|
|
|
|
y += font_height + 8;
|
|
return y;
|
|
}
|
|
|
|
void hotkey_build_listing()
|
|
{
|
|
int y, enemy_team_mask;
|
|
|
|
Num_lines = y = 0;
|
|
|
|
enemy_team_mask = iff_get_attackee_mask(Player_ship->team);
|
|
|
|
y = hotkey_build_team_listing(enemy_team_mask, y, false);
|
|
y = hotkey_build_team_listing(enemy_team_mask, y, true);
|
|
}
|
|
|
|
int hotkey_line_query_visible(int n)
|
|
{
|
|
int y;
|
|
|
|
if ((n < 0) || (n >= Num_lines))
|
|
return 0;
|
|
|
|
y = Hotkey_lines[n].y - Hotkey_lines[Scroll_offset].y;
|
|
if ((y < 0) || (y + gr_get_font_height() > Hotkey_list_coords[gr_screen.res][3]))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void hotkey_scroll_screen_up()
|
|
{
|
|
if (Scroll_offset) {
|
|
Scroll_offset--;
|
|
Assert(Selected_line > Scroll_offset);
|
|
while (!hotkey_line_query_visible(Selected_line) || (Hotkey_lines[Selected_line].type == HOTKEY_LINE_HEADING))
|
|
Selected_line--;
|
|
|
|
gamesnd_play_iface(SND_SCROLL);
|
|
|
|
} else
|
|
gamesnd_play_iface(SND_GENERAL_FAIL);
|
|
}
|
|
|
|
void hotkey_scroll_line_up()
|
|
{
|
|
if (Selected_line > 1) {
|
|
Selected_line--;
|
|
while (Hotkey_lines[Selected_line].type == HOTKEY_LINE_HEADING)
|
|
Selected_line--;
|
|
|
|
if (Selected_line < Scroll_offset)
|
|
Scroll_offset = Selected_line;
|
|
|
|
gamesnd_play_iface(SND_SCROLL);
|
|
|
|
} else
|
|
gamesnd_play_iface(SND_GENERAL_FAIL);
|
|
}
|
|
|
|
void hotkey_scroll_screen_down()
|
|
{
|
|
if (Hotkey_lines[Num_lines - 1].y + gr_get_font_height() > Hotkey_lines[Scroll_offset].y + Hotkey_list_coords[gr_screen.res][3]) {
|
|
Scroll_offset++;
|
|
while (!hotkey_line_query_visible(Selected_line) || (Hotkey_lines[Selected_line].type == HOTKEY_LINE_HEADING)) {
|
|
Selected_line++;
|
|
Assert(Selected_line < Num_lines);
|
|
}
|
|
|
|
gamesnd_play_iface(SND_SCROLL);
|
|
|
|
} else
|
|
gamesnd_play_iface(SND_GENERAL_FAIL);
|
|
}
|
|
|
|
void hotkey_scroll_line_down()
|
|
{
|
|
if (Selected_line < Num_lines - 1) {
|
|
Selected_line++;
|
|
while (Hotkey_lines[Selected_line].type == HOTKEY_LINE_HEADING)
|
|
Selected_line++;
|
|
|
|
Assert(Selected_line > Scroll_offset);
|
|
while (!hotkey_line_query_visible(Selected_line))
|
|
Scroll_offset++;
|
|
|
|
gamesnd_play_iface(SND_SCROLL);
|
|
|
|
} else
|
|
gamesnd_play_iface(SND_GENERAL_FAIL);
|
|
}
|
|
|
|
void expand_wing()
|
|
{
|
|
int i, z;
|
|
|
|
if (Hotkey_lines[Selected_line].type == HOTKEY_LINE_WING) {
|
|
i = Hotkey_lines[Selected_line].index;
|
|
Wings[i].flags ^= WF_EXPANDED;
|
|
hotkey_build_listing();
|
|
for (z=0; z<Num_lines; z++)
|
|
if ((Hotkey_lines[z].type == HOTKEY_LINE_WING) && (Hotkey_lines[z].index == i)) {
|
|
Selected_line = z;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void reset_hotkeys()
|
|
{
|
|
int i;
|
|
htarget_list *hitem, *plist;
|
|
|
|
for (i=0; i<MAX_SHIPS; i++)
|
|
Hotkey_bits[i] = 0;
|
|
|
|
for ( i=0; i<MAX_KEYED_TARGETS; i++ ) {
|
|
plist = &(Players[Player_num].keyed_targets[i]);
|
|
if ( EMPTY(plist) ) // no items in list, then do nothing
|
|
continue;
|
|
|
|
for ( hitem = GET_FIRST(plist); hitem != END_OF_LIST(plist); hitem = GET_NEXT(hitem) ) {
|
|
Assert(hitem->objp->type == OBJ_SHIP);
|
|
Hotkey_bits[hitem->objp->instance] |= (1 << i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void clear_hotkeys()
|
|
{
|
|
int i, b, z;
|
|
|
|
z = Hotkey_lines[Selected_line].type;
|
|
if (z == HOTKEY_LINE_WING) {
|
|
z = Hotkey_lines[Selected_line].index;
|
|
b = ~get_wing_hotkeys(z);
|
|
for (i=0; i<Wings[z].current_count; i++)
|
|
Hotkey_bits[Wings[z].ship_index[i]] &= b;
|
|
|
|
} else if ((z == HOTKEY_LINE_SHIP) || (z == HOTKEY_LINE_SUBSHIP)) {
|
|
Hotkey_bits[Hotkey_lines[Selected_line].index] = 0;
|
|
}
|
|
}
|
|
|
|
void save_hotkeys()
|
|
{
|
|
ship_obj *so;
|
|
int i;
|
|
|
|
for (i=0; i<MAX_KEYED_TARGETS; i++) {
|
|
hud_target_hotkey_clear(i);
|
|
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
|
|
if ( Hotkey_bits[Objects[so->objnum].instance] & (1 << i) ) {
|
|
hud_target_hotkey_add_remove(i, &Objects[so->objnum], HOTKEY_USER_ADDED );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void add_hotkey(int hotkey)
|
|
{
|
|
int i, z;
|
|
|
|
z = Hotkey_lines[Selected_line].type;
|
|
if (z == HOTKEY_LINE_WING) {
|
|
z = Hotkey_lines[Selected_line].index;
|
|
for (i=0; i<Wings[z].current_count; i++)
|
|
Hotkey_bits[Wings[z].ship_index[i]] |= (1 << hotkey);
|
|
|
|
} else if ((z == HOTKEY_LINE_SHIP) || (z == HOTKEY_LINE_SUBSHIP)) {
|
|
Hotkey_bits[Hotkey_lines[Selected_line].index] |= (1 << hotkey);
|
|
}
|
|
}
|
|
|
|
void remove_hotkey()
|
|
{
|
|
int i, z;
|
|
|
|
z = Hotkey_lines[Selected_line].type;
|
|
if (z == HOTKEY_LINE_WING) {
|
|
z = Hotkey_lines[Selected_line].index;
|
|
for (i=0; i<Wings[z].current_count; i++)
|
|
Hotkey_bits[Wings[z].ship_index[i]] &= ~(1 << Cur_hotkey);
|
|
|
|
} else if ((z == HOTKEY_LINE_SHIP) || (z == HOTKEY_LINE_SUBSHIP)) {
|
|
Hotkey_bits[Hotkey_lines[Selected_line].index] &= ~(1 << Cur_hotkey);
|
|
}
|
|
}
|
|
|
|
void hotkey_button_pressed(int n)
|
|
{
|
|
switch (n) {
|
|
case SCROLL_UP_BUTTON:
|
|
hotkey_scroll_screen_up();
|
|
break;
|
|
|
|
case SCROLL_DOWN_BUTTON:
|
|
hotkey_scroll_screen_down();
|
|
break;
|
|
|
|
case ADD_HOTKEY_BUTTON:
|
|
add_hotkey(Cur_hotkey);
|
|
gamesnd_play_iface(SND_USER_SELECT);
|
|
break;
|
|
|
|
case REMOVE_HOTKEY_BUTTON:
|
|
remove_hotkey();
|
|
gamesnd_play_iface(SND_USER_SELECT);
|
|
break;
|
|
|
|
case ACCEPT_BUTTON:
|
|
save_hotkeys();
|
|
// fall through to CANCEL_BUTTON
|
|
|
|
case CANCEL_BUTTON:
|
|
mission_hotkey_exit();
|
|
gamesnd_play_iface(SND_USER_SELECT);
|
|
break;
|
|
|
|
case HELP_BUTTON:
|
|
launch_context_help();
|
|
gamesnd_play_iface(SND_HELP_PRESSED);
|
|
break;
|
|
|
|
case OPTIONS_BUTTON:
|
|
gameseq_post_event(GS_EVENT_OPTIONS_MENU);
|
|
gamesnd_play_iface(SND_USER_SELECT);
|
|
break;
|
|
|
|
case CLEAR_BUTTON:
|
|
clear_hotkeys();
|
|
gamesnd_play_iface(SND_USER_SELECT);
|
|
break;
|
|
|
|
case RESET_BUTTON:
|
|
reset_hotkeys();
|
|
gamesnd_play_iface(SND_USER_SELECT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// mission_hotkey_init()
|
|
//
|
|
// Initialize the hotkey assignment screen system. Called when GS_STATE_HOTKEY_SCREEN
|
|
// is entered.
|
|
//
|
|
void mission_hotkey_init()
|
|
{
|
|
int i;
|
|
hotkey_buttons *b;
|
|
|
|
// pause all weapon sounds
|
|
weapon_pause_sounds();
|
|
|
|
// pause all game music
|
|
audiostream_pause_all();
|
|
|
|
reset_hotkeys();
|
|
common_set_interface_palette(); // set the interface palette
|
|
Ui_window.create(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled, 0);
|
|
Ui_window.set_mask_bmap(Hotkey_mask_fname[gr_screen.res]);
|
|
|
|
for (i=0; i<NUM_BUTTONS; i++) {
|
|
b = &Buttons[gr_screen.res][i];
|
|
|
|
b->button.create(&Ui_window, "", b->x, b->y, 60, 30, i < 2 ? 1 : 0, 1);
|
|
// set up callback for when a mouse first goes over a button
|
|
b->button.set_highlight_action(common_play_highlight_sound);
|
|
b->button.set_bmaps(b->filename);
|
|
b->button.link_hotspot(b->hotspot);
|
|
}
|
|
|
|
// add all xstr text
|
|
for(i=0; i<HOTKEY_NUM_TEXT; i++) {
|
|
Ui_window.add_XSTR(&Hotkey_text[gr_screen.res][i]);
|
|
}
|
|
|
|
for (i=0; i<LIST_BUTTONS_MAX; i++) {
|
|
List_buttons[i].create(&Ui_window, "", 0, 0, 60, 30, (i < 2), 1);
|
|
List_buttons[i].hide();
|
|
List_buttons[i].disable();
|
|
}
|
|
|
|
// set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
|
|
Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP);
|
|
Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
|
|
|
|
// ensure help overlay is off
|
|
Hotkey_overlay_id = help_overlay_get_index(HOTKEY_OVERLAY);
|
|
help_overlay_set_state(Hotkey_overlay_id,gr_screen.res,0);
|
|
|
|
// load in relevant bitmaps
|
|
Background_bitmap = bm_load(Hotkey_background_fname[gr_screen.res]);
|
|
if (Background_bitmap < 0) {
|
|
// bitmap didnt load -- this is bad
|
|
Int3();
|
|
}
|
|
Wing_bmp = bm_load("WingDesignator");
|
|
if (Wing_bmp < 0) {
|
|
// bitmap didnt load -- this is bad
|
|
Int3();
|
|
}
|
|
|
|
Scroll_offset = 0;
|
|
Selected_line = 1;
|
|
hotkey_build_listing();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// mission_hotkey_close()
|
|
//
|
|
// Cleanup the hotkey assignment screen system. Called when GS_STATE_HOTKEY_SCREEN
|
|
// is left.
|
|
//
|
|
void mission_hotkey_close()
|
|
{
|
|
if (Background_bitmap)
|
|
bm_release(Background_bitmap);
|
|
if (Wing_bmp >= 0)
|
|
bm_release(Wing_bmp);
|
|
|
|
// unpause all weapon sounds
|
|
weapon_unpause_sounds();
|
|
|
|
// unpause all game music
|
|
audiostream_unpause_all();
|
|
|
|
Ui_window.destroy();
|
|
common_free_interface_palette(); // restore game palette
|
|
game_flush();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// mission_hotkey_do_frame()
|
|
//
|
|
// Called once per frame to process user input for the Hotkey Assignment Screen
|
|
//
|
|
void mission_hotkey_do_frame(float frametime)
|
|
{
|
|
char buf[256];
|
|
int i, k, w, h, y, z, line, hotkeys;
|
|
int font_height = gr_get_font_height();
|
|
int select_tease_line = -1; // line mouse is down on, but won't be selected until button released
|
|
color circle_color;
|
|
|
|
if ( help_overlay_active(Hotkey_overlay_id) ) {
|
|
Buttons[gr_screen.res][HELP_BUTTON].button.reset_status();
|
|
Ui_window.set_ignore_gadgets(1);
|
|
}
|
|
|
|
k = Ui_window.process() & ~KEY_DEBUGGED;
|
|
|
|
if ( (k > 0) || B1_JUST_RELEASED ) {
|
|
if ( help_overlay_active(Hotkey_overlay_id) ) {
|
|
help_overlay_set_state(Hotkey_overlay_id, gr_screen.res, 0);
|
|
Ui_window.set_ignore_gadgets(0);
|
|
k = 0;
|
|
}
|
|
}
|
|
|
|
if ( !help_overlay_active(Hotkey_overlay_id) ) {
|
|
Ui_window.set_ignore_gadgets(0);
|
|
}
|
|
|
|
switch (k) {
|
|
case KEY_DOWN: // scroll list down
|
|
hotkey_scroll_line_down();
|
|
break;
|
|
|
|
case KEY_UP: // scroll list up
|
|
hotkey_scroll_line_up();
|
|
break;
|
|
|
|
case KEY_PAGEDOWN: // scroll list down
|
|
hotkey_scroll_screen_down();
|
|
break;
|
|
|
|
case KEY_PAGEUP: // scroll list up
|
|
hotkey_scroll_screen_up();
|
|
break;
|
|
|
|
case KEY_CTRLED | KEY_ENTER:
|
|
save_hotkeys();
|
|
// fall through to next state -- allender changed this behavior since ESC should always cancel, no?
|
|
|
|
case KEY_ESC:
|
|
mission_hotkey_exit();
|
|
break;
|
|
|
|
case KEY_TAB:
|
|
case KEY_ENTER:
|
|
case KEY_PADENTER:
|
|
expand_wing();
|
|
break;
|
|
|
|
case KEY_EQUAL:
|
|
case KEY_PADPLUS:
|
|
add_hotkey(Cur_hotkey);
|
|
break;
|
|
|
|
case KEY_MINUS:
|
|
case KEY_PADMINUS:
|
|
remove_hotkey();
|
|
break;
|
|
|
|
case KEY_F2:
|
|
gameseq_post_event(GS_EVENT_OPTIONS_MENU);
|
|
break;
|
|
|
|
case KEY_CTRLED | KEY_R:
|
|
reset_hotkeys();
|
|
break;
|
|
|
|
case KEY_CTRLED | KEY_C:
|
|
clear_hotkeys();
|
|
break;
|
|
} // end switch
|
|
|
|
// ?
|
|
for (i=0; i<MAX_KEYED_TARGETS; i++) {
|
|
if (k == Key_sets[i])
|
|
Cur_hotkey = i;
|
|
|
|
if (k == (Key_sets[i] | KEY_SHIFTED))
|
|
add_hotkey(i);
|
|
}
|
|
|
|
// handle pressed buttons
|
|
for (i=0; i<NUM_BUTTONS; i++) {
|
|
if (Buttons[gr_screen.res][i].button.pressed()) {
|
|
hotkey_button_pressed(i);
|
|
break; // only need to handle 1 button @ a time
|
|
}
|
|
}
|
|
|
|
for (i=0; i<LIST_BUTTONS_MAX; i++) {
|
|
// check for tease line
|
|
if (List_buttons[i].button_down()) {
|
|
select_tease_line = i + Scroll_offset;
|
|
}
|
|
|
|
// check for selected list item
|
|
if (List_buttons[i].pressed()) {
|
|
Selected_line = i + Scroll_offset;
|
|
List_buttons[i].get_mouse_pos(&z, NULL);
|
|
z += Hotkey_list_coords[gr_screen.res][0]; // adjust to full screen space
|
|
if ((z >= Hotkey_wing_icon_x[gr_screen.res]) && (z < (Hotkey_wing_icon_x[gr_screen.res]) + Hotkey_function_field_width[gr_screen.res])) {
|
|
expand_wing();
|
|
}
|
|
}
|
|
|
|
if (List_buttons[i].double_clicked()) {
|
|
Selected_line = i + Scroll_offset;
|
|
hotkeys = -1;
|
|
switch (Hotkey_lines[Selected_line].type) {
|
|
case HOTKEY_LINE_WING:
|
|
hotkeys = get_wing_hotkeys(Hotkey_lines[Selected_line].index);
|
|
break;
|
|
|
|
case HOTKEY_LINE_SHIP:
|
|
case HOTKEY_LINE_SUBSHIP:
|
|
hotkeys = Hotkey_bits[Hotkey_lines[Selected_line].index];
|
|
break;
|
|
}
|
|
|
|
if (hotkeys != -1) {
|
|
if (hotkeys & (1 << Cur_hotkey))
|
|
remove_hotkey();
|
|
else
|
|
add_hotkey(Cur_hotkey);
|
|
}
|
|
}
|
|
}
|
|
|
|
GR_MAYBE_CLEAR_RES(Background_bitmap);
|
|
if (Background_bitmap >= 0) {
|
|
gr_set_bitmap(Background_bitmap);
|
|
gr_bitmap(0, 0, GR_RESIZE_MENU);
|
|
|
|
} else
|
|
gr_clear();
|
|
|
|
Ui_window.draw();
|
|
gr_init_color(&circle_color, 160, 160, 0);
|
|
|
|
// draw the big "F10" in the little box
|
|
gr_set_font(FONT2);
|
|
gr_set_color_fast(&Color_text_normal);
|
|
strcpy_s(buf, Scan_code_text[Key_sets[Cur_hotkey]]);
|
|
gr_get_string_size(&w, &h, buf);
|
|
gr_printf_menu(Hotkey_function_name_coords[gr_screen.res][0] + (Hotkey_function_name_coords[gr_screen.res][2] - w) / 2, Hotkey_function_name_coords[gr_screen.res][1], buf);
|
|
|
|
gr_set_font(FONT1);
|
|
line = Scroll_offset;
|
|
while (hotkey_line_query_visible(line)) {
|
|
z = Hotkey_lines[line].index;
|
|
y = Hotkey_list_coords[gr_screen.res][1] + Hotkey_lines[line].y - Hotkey_lines[Scroll_offset].y;
|
|
hotkeys = 0;
|
|
switch (Hotkey_lines[line].type) {
|
|
case HOTKEY_LINE_HEADING:
|
|
gr_set_color_fast(&Color_text_heading);
|
|
|
|
gr_get_string_size(&w, &h, Hotkey_lines[line].label);
|
|
i = y + h / 2 - 1;
|
|
gr_line(Hotkey_list_coords[gr_screen.res][0], i, Hotkey_ship_x[gr_screen.res] - 2, i, GR_RESIZE_MENU);
|
|
gr_line(Hotkey_ship_x[gr_screen.res] + w + 1, i, Hotkey_list_coords[gr_screen.res][0] + Hotkey_list_coords[gr_screen.res][2], i, GR_RESIZE_MENU);
|
|
break;
|
|
|
|
case HOTKEY_LINE_WING:
|
|
gr_set_bitmap(Wing_bmp);
|
|
bm_get_info(Wing_bmp, NULL, &h, NULL);
|
|
i = y + font_height / 2 - h / 2 - 1;
|
|
gr_bitmap(Hotkey_wing_icon_x[gr_screen.res], i, GR_RESIZE_MENU);
|
|
|
|
// i = y + font_height / 2 - 1;
|
|
// gr_set_color_fast(&circle_color);
|
|
// gr_circle(ICON_LIST_X + 4, i, 5, GR_RESIZE_MENU);
|
|
|
|
// gr_set_color_fast(&Color_bright);
|
|
// gr_line(ICON_LIST_X, i, ICON_LIST_X + 2, i, GR_RESIZE_MENU);
|
|
// gr_line(ICON_LIST_X + 4, i - 4, ICON_LIST_X + 4, i - 2, GR_RESIZE_MENU);
|
|
// gr_line(ICON_LIST_X + 6, i, ICON_LIST_X + 8, i, GR_RESIZE_MENU);
|
|
// gr_line(ICON_LIST_X + 4, i + 2, ICON_LIST_X + 4, i + 4, GR_RESIZE_MENU);
|
|
|
|
hotkeys = get_wing_hotkeys(Hotkey_lines[line].index);
|
|
break;
|
|
|
|
case HOTKEY_LINE_SHIP:
|
|
case HOTKEY_LINE_SUBSHIP:
|
|
hotkeys = Hotkey_bits[Hotkey_lines[line].index];
|
|
break;
|
|
|
|
default:
|
|
Int3();
|
|
}
|
|
|
|
if (Hotkey_lines[line].type != HOTKEY_LINE_HEADING) {
|
|
Assert( (line - Scroll_offset) < LIST_BUTTONS_MAX );
|
|
List_buttons[line - Scroll_offset].update_dimensions(Hotkey_list_coords[gr_screen.res][0], y, Hotkey_list_coords[gr_screen.res][0] + Hotkey_list_coords[gr_screen.res][2] - Hotkey_list_coords[gr_screen.res][0], font_height);
|
|
List_buttons[line - Scroll_offset].enable();
|
|
if (hotkeys & (1 << Cur_hotkey)) {
|
|
gr_set_color_fast(&Color_text_active);
|
|
|
|
} else {
|
|
if (line == Selected_line)
|
|
gr_set_color_fast(&Color_text_selected);
|
|
else if (line == select_tease_line)
|
|
gr_set_color_fast(&Color_text_subselected);
|
|
else
|
|
gr_set_color_fast(&Color_text_normal);
|
|
}
|
|
|
|
} else {
|
|
Assert( (line - Scroll_offset) < LIST_BUTTONS_MAX );
|
|
List_buttons[line - Scroll_offset].disable();
|
|
}
|
|
|
|
// print active hotkeys associated for this line
|
|
if (hotkeys) {
|
|
for (i=0; i<MAX_KEYED_TARGETS; i++) {
|
|
if (hotkeys & (1 << i)) {
|
|
gr_printf_menu(Hotkey_list_coords[gr_screen.res][0] + Hotkey_function_field_width[gr_screen.res]*i, y, Scan_code_text[Key_sets[i]]);
|
|
}
|
|
}
|
|
/*
|
|
*buf = 0;
|
|
for (i=0; i<MAX_KEYED_TARGETS; i++) {
|
|
if (hotkeys & (1 << i)) {
|
|
strcat_s(buf, Scan_code_text[Key_sets[i]]);
|
|
strcat_s(buf, ", ");
|
|
}
|
|
}
|
|
|
|
Assert(strlen(buf) > 1);
|
|
buf[strlen(buf) - 2] = 0; // lose the ", " on the end
|
|
|
|
gr_force_fit_string(buf, 255, GROUP_LIST_W);
|
|
gr_printf_menu(GROUP_LIST_X, y, buf);*/
|
|
}
|
|
|
|
// draw ship/wing name
|
|
strcpy_s(buf, Hotkey_lines[line].label);
|
|
end_string_at_first_hash_symbol(buf);
|
|
if (Hotkey_lines[line].type == HOTKEY_LINE_SUBSHIP) {
|
|
// indent
|
|
gr_force_fit_string(buf, 255, Hotkey_list_coords[gr_screen.res][0] + Hotkey_list_coords[gr_screen.res][2] - (Hotkey_ship_x[gr_screen.res]+20));
|
|
gr_printf_menu(Hotkey_ship_x[gr_screen.res]+20, y, buf);
|
|
} else {
|
|
gr_force_fit_string(buf, 255, Hotkey_list_coords[gr_screen.res][0] + Hotkey_list_coords[gr_screen.res][2] - Hotkey_ship_x[gr_screen.res]);
|
|
gr_printf_menu(Hotkey_ship_x[gr_screen.res], y, buf);
|
|
}
|
|
|
|
line++;
|
|
}
|
|
|
|
i = line - Scroll_offset;
|
|
while (i < LIST_BUTTONS_MAX)
|
|
List_buttons[i++].disable();
|
|
|
|
// blit help overlay if active
|
|
help_overlay_maybe_blit(Hotkey_overlay_id, gr_screen.res);
|
|
|
|
gr_flip();
|
|
}
|
|
|
|
void mission_hotkey_exit()
|
|
{
|
|
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
|
}
|