mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 04:49:39 -10:00
1328 lines
35 KiB
C++
1328 lines
35 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 "freespace.h"
|
|
#include "gamehelp/contexthelp.h"
|
|
#include "gamesequence/gamesequence.h"
|
|
#include "gamesnd/gamesnd.h"
|
|
#include "globalincs/alphacolors.h"
|
|
#include "globalincs/linklist.h"
|
|
#include "globalincs/pstypes.h"
|
|
#include "graphics/font.h"
|
|
#include "iff_defs/iff_defs.h"
|
|
#include "io/key.h"
|
|
#include "io/timer.h"
|
|
#include "mission/missionhotkey.h"
|
|
#include "missionui/missionscreencommon.h"
|
|
#include "object/object.h"
|
|
#include "parse/parselo.h"
|
|
#include "playerman/player.h"
|
|
#include "ship/ship.h"
|
|
#include "sound/audiostr.h"
|
|
#include "ui/ui.h"
|
|
#include "ui/uidefs.h"
|
|
#include "weapon/weapon.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 const char *Hotkey_background_fname[GR_NUM_RESOLUTIONS] = {
|
|
"Hotkeys", // GR_640
|
|
"2_Hotkeys" // GR_1024
|
|
};
|
|
|
|
static const 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 {
|
|
const 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(const 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 {
|
|
SCP_string 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;
|
|
bool found_player_hotkey;
|
|
|
|
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;
|
|
|
|
found_player_hotkey = false;
|
|
for ( hitem = GET_FIRST(plist); hitem != END_OF_LIST(plist); hitem = GET_NEXT(hitem) )
|
|
if (hitem->how_added == HOTKEY_USER_ADDED)
|
|
found_player_hotkey = true;
|
|
|
|
if (!found_player_hotkey)
|
|
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, const 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(const 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.c_str()) < 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();
|
|
IFF_hotkey_team hotkey_team;
|
|
|
|
if (list_enemies)
|
|
{
|
|
str = XSTR( "Enemy ships", 403);
|
|
team_mask = enemy_team_mask;
|
|
hotkey_team = IFF_hotkey_team::Hostile;
|
|
}
|
|
else
|
|
{
|
|
str = XSTR( "Friendly ships", 402);
|
|
team_mask = ~enemy_team_mask;
|
|
hotkey_team = IFF_hotkey_team::Friendly;
|
|
}
|
|
|
|
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) ) {
|
|
bool add_it;
|
|
|
|
// don't process non-ships, or the player ship
|
|
if ( (Game_mode & GM_NORMAL) && (so->objnum == OBJ_INDEX(Player_obj)) )
|
|
continue;
|
|
|
|
int shipnum = Objects[so->objnum].instance;
|
|
ship *shipp = &Ships[shipnum];
|
|
|
|
// filter out ships in wings
|
|
if ( shipp->wingnum >= 0 )
|
|
continue;
|
|
|
|
// filter out cargo containers, navbouys, etc, and non-ships
|
|
if ( Ship_info[shipp->ship_info_index].class_type < 0 || !(Ship_types[Ship_info[shipp->ship_info_index].class_type].flags[Ship::Type_Info_Flags::Hotkey_on_list]) )
|
|
continue;
|
|
|
|
// don't process ships invisible to sensors, dying or departing
|
|
if ( shipp->flags[Ship::Ship_Flags::Hidden_from_sensors] || shipp->is_dying_or_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 ( shipp->hotkey == MAX_KEYED_TARGETS ) {
|
|
if ( !(Game_mode & GM_IN_MISSION) )
|
|
continue; // skip to next ship
|
|
shipp->hotkey = -1;
|
|
}
|
|
|
|
// check IFF override and team mask
|
|
if (Iff_info[shipp->team].hotkey_team == IFF_hotkey_team::Default) {
|
|
add_it = iff_matches_mask(shipp->team, team_mask);
|
|
} else {
|
|
add_it = (Iff_info[shipp->team].hotkey_team == hotkey_team);
|
|
}
|
|
|
|
// add it if the teams match or if the IFF says to
|
|
if (add_it) {
|
|
hotkey_line_add_sorted(shipp->get_display_name(), HOTKEY_LINE_SHIP, shipnum, start);
|
|
}
|
|
}
|
|
|
|
for (i=0; i<Num_wings; i++) {
|
|
bool add_it;
|
|
char wing_name[NAME_LENGTH];
|
|
|
|
// the wing has to be valid
|
|
if (Wings[i].current_count && Wings[i].ship_index[Wings[i].special_ship] >= 0) {
|
|
ship *shipp = &Ships[Wings[i].ship_index[Wings[i].special_ship]];
|
|
|
|
// check IFF override and team mask
|
|
if (Iff_info[shipp->team].hotkey_team == IFF_hotkey_team::Default) {
|
|
add_it = iff_matches_mask(shipp->team, team_mask);
|
|
} else {
|
|
add_it = (Iff_info[shipp->team].hotkey_team == hotkey_team);
|
|
}
|
|
} else {
|
|
add_it = false;
|
|
}
|
|
|
|
// add it if the teams match or if the IFF says to
|
|
if (add_it) {
|
|
// 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[Ship::Ship_Flags::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;
|
|
|
|
strcpy_s(wing_name, Wings[i].name);
|
|
end_string_at_first_hash_symbol(wing_name);
|
|
|
|
z = hotkey_line_add_sorted(wing_name, HOTKEY_LINE_WING, i, start);
|
|
if (Wings[i].flags[Ship::Wing_Flags::Expanded]) {
|
|
for (j=0; j<Wings[i].current_count; j++) {
|
|
s = Wings[i].ship_index[j];
|
|
if (!Ships[s].is_dying_or_departing()) {
|
|
z = hotkey_line_insert(z + 1, Ships[s].get_display_name(), HOTKEY_LINE_SUBSHIP, s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// see if we actually added any lines
|
|
if (start == Num_lines) {
|
|
// roll back the heading, then return as if nothing happened
|
|
Num_lines--;
|
|
return y - 2;
|
|
}
|
|
|
|
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(InterfaceSounds::SCROLL);
|
|
|
|
} else
|
|
gamesnd_play_iface(InterfaceSounds::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(InterfaceSounds::SCROLL);
|
|
|
|
} else
|
|
gamesnd_play_iface(InterfaceSounds::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(InterfaceSounds::SCROLL);
|
|
|
|
} else
|
|
gamesnd_play_iface(InterfaceSounds::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(InterfaceSounds::SCROLL);
|
|
|
|
} else
|
|
gamesnd_play_iface(InterfaceSounds::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.toggle(Ship::Wing_Flags::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(InterfaceSounds::USER_SELECT);
|
|
break;
|
|
|
|
case REMOVE_HOTKEY_BUTTON:
|
|
remove_hotkey();
|
|
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
|
break;
|
|
|
|
case ACCEPT_BUTTON:
|
|
save_hotkeys();
|
|
// fall through to CANCEL_BUTTON
|
|
FALLTHROUGH;
|
|
|
|
case CANCEL_BUTTON:
|
|
mission_hotkey_exit();
|
|
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
|
break;
|
|
|
|
case HELP_BUTTON:
|
|
launch_context_help();
|
|
gamesnd_play_iface(InterfaceSounds::HELP_PRESSED);
|
|
break;
|
|
|
|
case OPTIONS_BUTTON:
|
|
gameseq_post_event(GS_EVENT_OPTIONS_MENU);
|
|
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
|
break;
|
|
|
|
case CLEAR_BUTTON:
|
|
clear_hotkeys();
|
|
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
|
break;
|
|
|
|
case RESET_BUTTON:
|
|
reset_hotkeys();
|
|
gamesnd_play_iface(InterfaceSounds::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?
|
|
FALLTHROUGH;
|
|
|
|
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
|
|
font::set_font(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], "%s", buf);
|
|
|
|
font::set_font(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.c_str());
|
|
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, "%s", 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
|
|
|
|
font::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.c_str());
|
|
if (Hotkey_lines[line].type == HOTKEY_LINE_SUBSHIP) {
|
|
// indent
|
|
font::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, "%s", buf);
|
|
} else {
|
|
font::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, "%s", 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);
|
|
}
|