/* Emacs style mode select -*- C++ -*- *----------------------------------------------------------------------------- * * * PrBoom: a Doom port merged with LxDoom and LSDLDoom * based on BOOM, a modified and improved DOOM engine * Copyright (C) 1999 by * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman * Copyright (C) 1999-2000 by * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze * Copyright 2005, 2006 by * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * DESCRIPTION: Heads-up displays * *----------------------------------------------------------------------------- */ // killough 5/3/98: remove unnecessary headers #include "doomstat.h" #include "hu_stuff.h" #include "hu_lib.h" #include "hu_tracers.h" #include "st_stuff.h" /* jff 2/16/98 need loc of status bar */ #include "s_sound.h" #include "dstrings.h" #include "sounds.h" #include "d_deh.h" /* Ty 03/27/98 - externalization of mapnamesx arrays */ #include "g_game.h" #include "r_main.h" #include "p_inter.h" #include "sc_man.h" #include "lprintf.h" #include "e6y.h" //e6y // global heads up display controls int hud_displayed; //jff 2/23/98 turns heads-up display on/off int hud_num; // // Locally used constants, shortcuts. // // Ty 03/28/98 - // These four shortcuts modifed to reflect char ** of mapnamesx[] // e6y: why sizeof(mapnamest)/sizeof(mapnamest[0]) does not work? #define HU_TITLE (*mapnames[(gameepisode-1)*9+gamemap-1]) #define HU_TITLE2 (gamemap <= 32 ? *mapnames2[gamemap-1] : "") #define HU_TITLEP (gamemap <= 32 ? *mapnamesp[gamemap-1] : "") #define HU_TITLET (gamemap <= 32 ? *mapnamest[gamemap-1] : "") #define HU_TITLEX 0 //jff 2/16/98 change 167 to ST_Y-1 // CPhipps - changed to ST_TY // proff - changed to 200-ST_HEIGHT for stretching #define HU_TITLEY ((200-ST_HEIGHT) - 1 - hu_font[0].height) //jff 2/16/98 add coord text widget coordinates // proff - changed to SCREENWIDTH to 320 for stretching #define HU_COORDX (320 - 13*hu_font2['A'-HU_FONTSTART].width) //jff 3/3/98 split coord widget into three lines in upper right of screen #define HU_COORDXYZ_Y (1 * hu_font['A'-HU_FONTSTART].height + 1) #define HU_COORDX_Y (0 + 0*hu_font['A'-HU_FONTSTART].height + HU_COORDXYZ_Y) #define HU_COORDY_Y (1 + 1*hu_font['A'-HU_FONTSTART].height + HU_COORDXYZ_Y) #define HU_COORDZ_Y (2 + 2*hu_font['A'-HU_FONTSTART].height + HU_COORDXYZ_Y) #define HU_MAP_STAT_X (0) #define HU_MAP_STAT_Y (1 * hu_font['A'-HU_FONTSTART].height + 1) #define HU_MAP_MONSTERS_Y (0 + 0*hu_font['A'-HU_FONTSTART].height + HU_MAP_STAT_Y) #define HU_MAP_SECRETS_Y (1 + 1*hu_font['A'-HU_FONTSTART].height + HU_MAP_STAT_Y) #define HU_MAP_ITEMS_Y (2 + 2*hu_font['A'-HU_FONTSTART].height + HU_MAP_STAT_Y) #define HU_MAP_TIME_Y (4 + 4*hu_font['A'-HU_FONTSTART].height + HU_MAP_STAT_Y) #define HU_MAP_TOTALTIME_Y (5 + 5*hu_font['A'-HU_FONTSTART].height + HU_MAP_STAT_Y) //jff 2/16/98 add ammo, health, armor widgets, 2/22/98 less gap #define HU_GAPY 8 #define HU_INPUTX HU_MSGX #define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(hu_font[0].height) +1) #define HU_TRACERX (2) #define HU_TRACERY (hu_font['A'-HU_FONTSTART].height) #define key_alt KEYD_RALT #define key_shift KEYD_RSHIFT const char* chat_macros[] = // Ty 03/27/98 - *not* externalized // CPhipps - const char* { HUSTR_CHATMACRO0, HUSTR_CHATMACRO1, HUSTR_CHATMACRO2, HUSTR_CHATMACRO3, HUSTR_CHATMACRO4, HUSTR_CHATMACRO5, HUSTR_CHATMACRO6, HUSTR_CHATMACRO7, HUSTR_CHATMACRO8, HUSTR_CHATMACRO9 }; const char* player_names[] = // Ty 03/27/98 - *not* externalized // CPhipps - const char* { HUSTR_PLRGREEN, HUSTR_PLRINDIGO, HUSTR_PLRBROWN, HUSTR_PLRRED }; //jff 3/17/98 translate player colmap to text color ranges int plyrcoltran[MAXPLAYERS]={CR_GREEN,CR_GRAY,CR_BROWN,CR_RED}; char chat_char; // remove later. static player_t* plr; // font sets patchnum_t hu_font[HU_FONTSIZE]; patchnum_t hu_font2[HU_FONTSIZE]; patchnum_t hu_fontk[HU_FONTSIZE];//jff 3/7/98 added for graphic key indicators patchnum_t hu_msgbg[9]; //jff 2/26/98 add patches for message background patchnum_t hu_font_hud[HU_FONTSIZE]; // widgets static hu_textline_t w_title; static hu_stext_t w_message; static hu_itext_t w_chat; static hu_itext_t w_inputbuffer[MAXPLAYERS]; static hu_textline_t w_coordx; //jff 2/16/98 new coord widget for automap static hu_textline_t w_coordy; //jff 3/3/98 split coord widgets automap static hu_textline_t w_coordz; //jff 3/3/98 split coord widgets automap static hu_textline_t w_ammo; //jff 2/16/98 new ammo widget for hud static hu_textline_t w_health; //jff 2/16/98 new health widget for hud static hu_textline_t w_armor; //jff 2/16/98 new armor widget for hud static hu_textline_t w_weapon; //jff 2/16/98 new weapon widget for hud static hu_textline_t w_keys; //jff 2/16/98 new keys widget for hud static hu_textline_t w_gkeys; //jff 3/7/98 graphic keys widget for hud static hu_textline_t w_monsec; //jff 2/16/98 new kill/secret widget for hud static hu_mtext_t w_rtext; //jff 2/26/98 text message refresh widget static hu_textline_t w_map_monsters; //e6y monsters widget for automap static hu_textline_t w_map_secrets; //e6y secrets widgets automap static hu_textline_t w_map_items; //e6y items widgets automap static hu_textline_t w_map_time; //e6y level time widgets automap static hu_textline_t w_map_totaltime; //e6y total time widgets automap static hu_textline_t w_health_big; static hu_textline_t w_medict_icon_big; static hu_textline_t w_medict_icon_small; static hu_textline_t w_medict_icon_custom; static hu_textline_t w_armor_big; static hu_textline_t w_armor_icon_big; static hu_textline_t w_armor_icon_small; static hu_textline_t w_armor_icon_custom; static hu_textline_t w_medict_percent; static hu_textline_t w_armor_percent; static hu_textline_t w_ammo_big; static hu_textline_t w_ammo_icon; static hu_textline_t w_keys_icon; static dboolean always_off = false; static char chat_dest[MAXPLAYERS]; dboolean chat_on; static dboolean message_on; static dboolean message_list; //2/26/98 enable showing list of messages dboolean message_dontfuckwithme; static dboolean message_nottobefuckedwith; static int message_counter; extern int showMessages; static dboolean headsupactive = false; //jff 2/16/98 hud supported automap colors added int hudcolor_titl; // color range of automap level title int hudcolor_xyco; // color range of new coords on automap int hudcolor_mapstat_title; int hudcolor_mapstat_value; int hudcolor_mapstat_time; //jff 2/16/98 hud text colors, controls added int hudcolor_mesg; // color range of scrolling messages int hudcolor_chat; // color range of chat lines int hud_msg_lines; // number of message lines in window //jff 2/26/98 hud text colors, controls added int hudcolor_list; // list of messages color int hud_list_bgon; // enable for solid window background for message list //jff 2/16/98 initialization strings for ammo, health, armor widgets static char hud_coordstrx[32]; static char hud_coordstry[32]; static char hud_coordstrz[32]; static char hud_ammostr[80]; static char hud_healthstr[80]; static char hud_armorstr[80]; static char hud_weapstr[80]; static char hud_keysstr[80]; static char hud_gkeysstr[80]; //jff 3/7/98 add support for graphic key display static char hud_monsecstr[80]; // // Builtin map names. // The actual names can be found in DStrings.h. // // Ty 03/27/98 - externalized map name arrays - now in d_deh.c // and converted to arrays of pointers to char * // See modified HUTITLEx macros extern char **mapnames[]; extern char **mapnames2[]; extern char **mapnamesp[]; extern char **mapnamest[]; extern int map_point_coordinates; extern int map_level_stat; // key tables // jff 5/10/98 french support removed, // as it was not being used and couldn't be easily tested // const char* shiftxform; const char english_shiftxform[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, ' ', '!', '"', '#', '$', '%', '&', '"', // shift-' '(', ')', '*', '+', '<', // shift-, '_', // shift-- '>', // shift-. '?', // shift-/ ')', // shift-0 '!', // shift-1 '@', // shift-2 '#', // shift-3 '$', // shift-4 '%', // shift-5 '^', // shift-6 '&', // shift-7 '*', // shift-8 '(', // shift-9 ':', ':', // shift-; '<', '+', // shift-= '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', // shift-[ '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK ']', // shift-] '"', '_', '\'', // shift-` 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', 127 }; // // HU_Init() // // Initialize the heads-up display, text that overwrites the primary display // // Passed nothing, returns nothing // void HU_Init(void) { int i; int j; char buffer[9]; shiftxform = english_shiftxform; // load the heads-up font j = HU_FONTSTART; for (i=0;i122) { sprintf(buffer, "STBR%.3d",j); R_SetPatchNum(&hu_font2[i], buffer); R_SetPatchNum(&hu_font[i], buffer); } else hu_font[i] = hu_font[0]; //jff 2/16/98 account for gap } // CPhipps - load patches for message background for (i=0; i<9; i++) { sprintf(buffer, "BOX%c%c", "UCL"[i/3], "LCR"[i%3]); R_SetPatchNum(&hu_msgbg[i], buffer); } // CPhipps - load patches for keys and double keys for (i=0; i<6; i++) { sprintf(buffer, "STKEYS%d", i); R_SetPatchNum(&hu_fontk[i], buffer); } R_SetSpriteByIndex(&hu_font_hud[4], SPR_MEDI); R_SetSpriteByIndex(&hu_font_hud[5], SPR_ARM1); R_SetSpriteByIndex(&hu_font_hud[6], SPR_ARM1); R_SetSpriteByIndex(&hu_font_hud[7], SPR_ARM2); R_SetSpriteByIndex(&hu_font_hud[8], SPR_STIM); R_SetSpriteByName(&hu_font_hud[9], "BON2A0"); R_SetSpriteByName(&hu_font_hud[10], "BON2B0"); R_SetSpriteByName(&hu_font_hud[11], "BON2D0"); R_SetPatchNum(&hu_font_hud[12], "STTPRCNT"); R_SetPatchNum(&hu_font_hud[13], "STTPRCNT"); R_SetPatchByName(&hu_font_hud[30], "HUDMED"); R_SetPatchByName(&hu_font_hud[31], "HUDARM1"); R_SetPatchByName(&hu_font_hud[32], "HUDARM1"); R_SetPatchByName(&hu_font_hud[33], "HUDARM2"); R_SetSpriteByName(&hu_font_hud[40], "CLIPA0"); R_SetSpriteByName(&hu_font_hud[41], "SHELA0"); R_SetSpriteByName(&hu_font_hud[42], "CELLA0"); R_SetSpriteByName(&hu_font_hud[43], "ROCKA0"); } // // HU_Stop() // // Make the heads-up displays inactive // // Passed nothing, returns nothing // static void HU_Stop(void) { headsupactive = false; } // // HU_Start(void) // // Create and initialize the heads-up widgets, software machines to // maintain, update, and display information over the primary display // // This routine must be called after any change to the heads up configuration // in order for the changes to take effect in the actual displays // // Passed nothing, returns nothing // void HU_Start(void) { int i; const char* s; /* cph - const */ if (headsupactive) // stop before starting HU_Stop(); plr = &players[displayplayer]; // killough 3/7/98 message_on = false; message_dontfuckwithme = false; message_nottobefuckedwith = false; chat_on = false; // create the message widget // messages to player in upper-left of screen HUlib_initSText ( &w_message, HU_MSGX, HU_MSGY, HU_MSGHEIGHT, hu_font, HU_FONTSTART, hudcolor_mesg, VPT_ALIGN_LEFT_TOP, &message_on ); //jff 2/16/98 added some HUD widgets // create the map title widget - map title display in lower left of automap HUlib_initTextLine ( &w_title, HU_TITLEX, HU_TITLEY, hu_font, HU_FONTSTART, hudcolor_titl, VPT_ALIGN_LEFT_BOTTOM ); // create the hud health widget // bargraph and number for amount of health, // lower left or upper right of screen HUlib_initTextLine ( &w_health, 0, 0, hu_font2, HU_FONTSTART, CR_GREEN, VPT_NONE ); HUlib_initTextLine ( &w_health_big, 0, 0, hu_font_hud, HU_FONTSTART, CR_RED, VPT_NONE ); HUlib_initTextLine ( &w_medict_icon_big, 0, 0, hu_font_hud, HU_FONTSTART, CR_RED, VPT_NONE ); HUlib_initTextLine ( &w_medict_icon_small, 0, 0, hu_font_hud, HU_FONTSTART, CR_RED, VPT_NONE ); HUlib_initTextLine ( &w_medict_icon_custom, 0, 0, hu_font_hud, HU_FONTSTART, CR_RED, VPT_NONE ); // create the hud armor widget // bargraph and number for amount of armor, // lower left or upper right of screen HUlib_initTextLine ( &w_armor, 0, 0, hu_font2, HU_FONTSTART, CR_GREEN, VPT_NONE ); HUlib_initTextLine ( &w_armor_big, 0, 0, hu_font_hud, HU_FONTSTART, CR_RED, VPT_NONE ); HUlib_initTextLine ( &w_armor_icon_big, 0, 0, hu_font_hud, HU_FONTSTART, CR_RED, VPT_NONE ); HUlib_initTextLine ( &w_armor_icon_small, 0, 0, hu_font_hud, HU_FONTSTART, CR_RED, VPT_NONE ); HUlib_initTextLine ( &w_armor_icon_custom, 0, 0, hu_font_hud, HU_FONTSTART, CR_RED, VPT_NONE ); // create the hud ammo widget // bargraph and number for amount of ammo for current weapon, // lower left or lower right of screen HUlib_initTextLine ( &w_ammo, 0, 0, hu_font2, HU_FONTSTART, CR_GOLD, VPT_NONE ); // create the hud weapons widget // list of numbers of weapons possessed // lower left or lower right of screen HUlib_initTextLine ( &w_weapon, 0, 0, hu_font2, HU_FONTSTART, CR_GRAY, VPT_NONE ); // create the hud keys widget // display of key letters possessed // lower left of screen HUlib_initTextLine ( &w_keys, 0, 0, hu_font2, HU_FONTSTART, CR_GRAY, VPT_NONE ); // create the hud graphic keys widget // display of key graphics possessed // lower left of screen HUlib_initTextLine ( &w_gkeys, 0, 0, hu_fontk, HU_FONTSTART, CR_RED, VPT_NONE ); // create the hud monster/secret widget // totals and current values for kills, items, secrets // lower left of screen HUlib_initTextLine ( &w_monsec, 0, 0, hu_font2, HU_FONTSTART, CR_GRAY, VPT_NONE ); HUlib_initTextLine ( &w_medict_percent, 0, 0, hu_font_hud, HU_FONTSTART, CR_GRAY, VPT_NONE ); HUlib_initTextLine ( &w_armor_percent, 0, 0, hu_font_hud, HU_FONTSTART, CR_GRAY, VPT_NONE ); HUlib_initTextLine ( &w_ammo_big, 0, 0, hu_font_hud, HU_FONTSTART, CR_RED, VPT_NONE ); HUlib_initTextLine ( &w_ammo_icon, 0, 0, hu_font_hud, HU_FONTSTART, CR_RED, VPT_NONE ); HUlib_initTextLine ( &w_keys_icon, 0, 0, hu_fontk, HU_FONTSTART, CR_RED, VPT_NONE ); // create the hud text refresh widget // scrolling display of last hud_msg_lines messages received if (hud_msg_lines>HU_MAXMESSAGES) hud_msg_lines=HU_MAXMESSAGES; //jff 4/21/98 if setup has disabled message list while active, turn it off message_list = hud_msg_lines > 1; //jff 8/8/98 initialize both ways //jff 2/26/98 add the text refresh widget initialization HUlib_initMText ( &w_rtext, 0, 0, 320, // SCREENWIDTH, (hud_msg_lines+2)*HU_REFRESHSPACING, hu_font, HU_FONTSTART, hudcolor_list, hu_msgbg, VPT_ALIGN_LEFT_TOP, &message_list ); // initialize the automap's level title widget // e6y: stop SEGV here when gamemap is not initialized if (gamestate == GS_LEVEL && gamemap > 0) /* cph - stop SEGV here when not in level */ switch (gamemode) { case shareware: case registered: case retail: s = HU_TITLE; break; case commercial: default: // Ty 08/27/98 - modified to check mission for TNT/Plutonia s = (gamemission==pack_tnt) ? HU_TITLET : (gamemission==pack_plut) ? HU_TITLEP : HU_TITLE2; break; } else s = ""; while (*s) HUlib_addCharToTextLine(&w_title, *(s++)); // create the automaps coordinate widget // jff 3/3/98 split coord widget into three lines: x,y,z // jff 2/16/98 added HUlib_initTextLine ( &w_coordx, HU_COORDX, HU_COORDX_Y, hu_font, HU_FONTSTART, hudcolor_xyco, VPT_ALIGN_RIGHT_TOP ); HUlib_initTextLine ( &w_coordy, HU_COORDX, HU_COORDY_Y, hu_font, HU_FONTSTART, hudcolor_xyco, VPT_ALIGN_RIGHT_TOP ); HUlib_initTextLine ( &w_coordz, HU_COORDX, HU_COORDZ_Y, hu_font, HU_FONTSTART, hudcolor_xyco, VPT_ALIGN_RIGHT_TOP ); //e6y HUlib_initTextLine ( &w_map_monsters, HU_MAP_STAT_X, HU_MAP_MONSTERS_Y, hu_font, HU_FONTSTART, hudcolor_mapstat_title, VPT_ALIGN_LEFT_TOP ); HUlib_initTextLine ( &w_map_secrets, HU_MAP_STAT_X, HU_MAP_SECRETS_Y, hu_font, HU_FONTSTART, hudcolor_mapstat_title, VPT_ALIGN_LEFT_TOP ); HUlib_initTextLine ( &w_map_items, HU_MAP_STAT_X, HU_MAP_ITEMS_Y, hu_font, HU_FONTSTART, hudcolor_mapstat_title, VPT_ALIGN_LEFT_TOP ); HUlib_initTextLine ( &w_map_time, HU_MAP_STAT_X, HU_MAP_TIME_Y, hu_font, HU_FONTSTART, hudcolor_mapstat_time, VPT_ALIGN_LEFT_TOP ); HUlib_initTextLine ( &w_map_totaltime, HU_MAP_STAT_X, HU_MAP_TOTALTIME_Y, hu_font, HU_FONTSTART, hudcolor_mapstat_time, VPT_ALIGN_LEFT_TOP ); HUlib_initTextLine ( &w_hudadd, 0, 0, hu_font2, HU_FONTSTART, CR_GRAY, VPT_NONE ); HUlib_initTextLine ( &w_centermsg, HU_CENTERMSGX, HU_CENTERMSGY, hu_font, HU_FONTSTART, hudcolor_titl, VPT_STRETCH ); HUlib_initTextLine ( &w_precache, 16, 186, hu_font, HU_FONTSTART, CR_RED, VPT_ALIGN_LEFT_BOTTOM ); strcpy(hud_add,""); s = hud_add; while (*s) HUlib_addCharToTextLine(&w_hudadd, *(s++)); for(i = 0; i < NUMTRACES; i++) { HUlib_initTextLine( &w_traces[i], HU_TRACERX, HU_TRACERY+i*HU_GAPY, hu_font2, HU_FONTSTART, CR_GRAY, VPT_ALIGN_LEFT_BOTTOM ); strcpy(traces[i].hudstr, ""); s = traces[i].hudstr; while (*s) HUlib_addCharToTextLine(&w_traces[i], *(s++)); HUlib_drawTextLine(&w_traces[i], false); } //jff 2/16/98 initialize ammo widget strcpy(hud_ammostr,"AMM "); //jff 2/16/98 initialize health widget strcpy(hud_healthstr,"HEL "); //jff 2/16/98 initialize armor widget strcpy(hud_armorstr,"ARM "); //jff 2/17/98 initialize weapons widget strcpy(hud_weapstr,"WEA "); //jff 2/17/98 initialize keys widget //jff 3/17/98 show frags in deathmatch mode strcpy(hud_keysstr,(deathmatch ? "FRG " : "KEY ")); //jff 2/17/98 initialize graphic keys widget strcpy(hud_gkeysstr," "); //jff 2/17/98 initialize kills/items/secret widget strcpy(hud_monsecstr,"STS "); // create the chat widget HUlib_initIText ( &w_chat, HU_INPUTX, HU_INPUTY, hu_font, HU_FONTSTART, hudcolor_chat, VPT_NONE, &chat_on ); // create the inputbuffer widgets, one per player for (i=0 ; i 0) { hud_num = (hud_num + 1) % huds_count; // cycle hud_active } } typedef void (*HU_widget_build_func)(void); typedef void (*HU_widget_draw_func)(void); typedef struct hud_cfg_item_s { char name[80]; int x; int y; } hud_cfg_item_t; typedef struct hud_widget_s { hu_textline_t *hu_textline; int x; int y; enum patch_translation_e flags; HU_widget_build_func build; HU_widget_draw_func draw; const char *name; } hud_widget_t; typedef struct hud_widgets_list_s { int count; hud_widget_t *items; } hud_widgets_list_t; int huds_count; hud_widgets_list_t *huds; hud_widgets_list_t *hud_current; void HU_widget_build_ammo(void); void HU_widget_draw_ammo(void); void HU_widget_build_weapon(void); void HU_widget_draw_weapon(void); void HU_widget_build_keys(void); void HU_widget_draw_keys(void); void HU_widget_build_monsec(void); void HU_widget_draw_monsec(void); void HU_widget_build_health(void); void HU_widget_draw_health(void); void HU_widget_build_armor(void); void HU_widget_draw_armor(void); void HU_widget_build_hudadd(void); void HU_widget_draw_hudadd(void); void HU_widget_build_health_big(void); void HU_widget_draw_health_big(void); void HU_widget_build_armor_big(void); void HU_widget_draw_armor_big(void); void HU_widget_build_medict_icon_big(void); void HU_widget_draw_medict_icon_big(void); void HU_widget_build_armor_icon_big(void); void HU_widget_draw_armor_icon_big(void); void HU_widget_build_medict_icon_small(void); void HU_widget_draw_medict_icon_small(void); void HU_widget_build_armor_icon_small(void); void HU_widget_draw_armor_icon_small(void); void HU_widget_build_medict_icon_custom(void); void HU_widget_draw_medict_icon_custom(void); void HU_widget_build_armor_icon_custom(void); void HU_widget_draw_armor_icon_custom(void); void HU_widget_build_medict_percent(void); void HU_widget_draw_medict_percent(void); void HU_widget_build_armor_percent(void); void HU_widget_draw_armor_percent(void); void HU_widget_build_ammo_big(void); void HU_widget_draw_ammo_big(void); void HU_widget_build_ammo_icon(void); void HU_widget_draw_ammo_icon(void); void HU_widget_build_gkeys(void); void HU_widget_draw_gkeys(void); static hud_widget_t hud_name_widget[] = { {&w_ammo, 0, 0, 0, HU_widget_build_ammo, HU_widget_draw_ammo, "ammo"}, {&w_weapon, 0, 0, 0, HU_widget_build_weapon, HU_widget_draw_weapon, "weapon"}, {&w_keys, 0, 0, 0, HU_widget_build_keys, HU_widget_draw_keys, "keys"}, {&w_monsec, 0, 0, 0, HU_widget_build_monsec, HU_widget_draw_monsec, "monsec"}, {&w_health, 0, 0, 0, HU_widget_build_health, HU_widget_draw_health, "health"}, {&w_armor, 0, 0, 0, HU_widget_build_armor, HU_widget_draw_armor, "armor"}, {&w_hudadd, 0, 0, 0, HU_widget_build_hudadd, HU_widget_draw_hudadd, "hudadd"}, {&w_keys_icon, 0, 0, 0, HU_widget_build_gkeys, HU_widget_draw_gkeys, "gkeys"}, {&w_traces[0], 0, 0, 0, NULL, NULL, "tracers"}, {&w_health_big, 0, 0, VPT_NOOFFSET, HU_widget_build_health_big, HU_widget_draw_health_big, "health_big"}, {&w_armor_big, 0, 0, VPT_NOOFFSET, HU_widget_build_armor_big, HU_widget_draw_armor_big, "armor_big"}, {&w_medict_icon_big, 0, 0, VPT_NOOFFSET, HU_widget_build_medict_icon_big, HU_widget_draw_medict_icon_big, "medict_icon_big"}, {&w_armor_icon_big, 0, 0, VPT_NOOFFSET, HU_widget_build_armor_icon_big, HU_widget_draw_armor_icon_big, "armor_icon_big"}, {&w_medict_icon_small, 0, 0, VPT_NOOFFSET, HU_widget_build_medict_icon_small, HU_widget_draw_medict_icon_small, "medict_icon_small"}, {&w_armor_icon_small, 0, 0, VPT_NOOFFSET, HU_widget_build_armor_icon_small, HU_widget_draw_armor_icon_small, "armor_icon_small"}, {&w_medict_icon_custom, 0, 0, VPT_NOOFFSET, HU_widget_build_medict_icon_custom, HU_widget_draw_medict_icon_custom, "medict_icon_custom"}, {&w_armor_icon_custom, 0, 0, VPT_NOOFFSET, HU_widget_build_armor_icon_custom, HU_widget_draw_armor_icon_custom, "armor_icon_custom"}, {&w_medict_percent, 0, 0, VPT_NOOFFSET, HU_widget_build_medict_percent, HU_widget_draw_medict_percent, "medict_percent"}, {&w_armor_percent, 0, 0, VPT_NOOFFSET, HU_widget_build_armor_percent, HU_widget_draw_armor_percent, "armor_percent"}, {&w_ammo_big, 0, 0, VPT_NOOFFSET, HU_widget_build_ammo_big, HU_widget_draw_ammo_big, "ammo_big"}, {&w_ammo_big, 0, 0, VPT_NOOFFSET, HU_widget_build_ammo_big, HU_widget_draw_ammo_big, "ammo_big"}, {&w_ammo_icon, 0, 0, VPT_NOOFFSET, HU_widget_build_ammo_icon, HU_widget_draw_ammo_icon, "ammo_icon"}, {&w_ammo_icon, 0, 0, VPT_NOOFFSET, HU_widget_build_ammo_icon, HU_widget_draw_ammo_icon, "ammo_icon"}, {NULL, 0, 0, 0, NULL, NULL, NULL} }; void HU_LoadHUDDefs(void) { static int init = 0; int lump, i, params_count; hud_cfg_item_t cfg_item; hud_widgets_list_t *list = NULL; char st[200]; if (init) return; init = true; huds_count = 0; huds = NULL; lump = (W_CheckNumForName)("-PRBHUD-", ns_prboom); if (lump != -1) { SC_OpenLumpByNum(lump); // Get actor class name. while (SC_GetString()) { // declaration of hud if (SC_Compare("hud")) { // skip everything after "hud" signature while (SC_Check()) SC_GetString(); // setup new hud huds_count++; huds = realloc(huds, huds_count * sizeof(huds[0])); list = &huds[huds_count - 1]; list->items = NULL; list->count = 0; // definition of hud is below continue; } // keep going until a valid HUD declaration has been found if (huds_count < 1) continue; strncpy(st, sc_String, sizeof(st) - 1); while (SC_Check() && SC_GetString()) { strncat(st, " ", sizeof(st) - 1); strncat(st, sc_String, sizeof(st) - 1); } st[sizeof(st) - 1] = 0; // hud_widget x y params_count = sscanf(st, "%s %d %d", &cfg_item.name[0], &cfg_item.x, &cfg_item.y); if (params_count == 3) { for (i = 0; hud_name_widget[i].name; i++) { if (!strcasecmp(hud_name_widget[i].name, cfg_item.name)) { hud_widget_t *item; list->count++; list->items = realloc(list->items, list->count * sizeof(list->items[0])); item = &list->items[list->count - 1]; item->hu_textline = hud_name_widget[i].hu_textline; item->x = cfg_item.x; item->y = cfg_item.y; if (abs(cfg_item.x) < 160) { item->flags = (abs(cfg_item.y) > 100 ? VPT_ALIGN_LEFT_BOTTOM : VPT_ALIGN_LEFT_TOP); } else { item->flags = (abs(cfg_item.y) > 100 ? VPT_ALIGN_RIGHT_BOTTOM : VPT_ALIGN_RIGHT_TOP); } item->flags |= hud_name_widget[i].flags; item->build = hud_name_widget[i].build; item->draw = hud_name_widget[i].draw; break; } } } } SC_Close(); } } // // HU_MoveHud() // // Move the HUD display from distributed to compact mode or vice-versa // // Passed nothing, returns nothing // //jff 3/9/98 create this externally callable to avoid glitch // when menu scatter's HUD due to delay in change of position // void HU_MoveHud(int force) { static int ohud_num = -1; //jff 3/4/98 move displays around on F5 changing hud_distributed if ((huds_count > 0) && (force || hud_num != ohud_num)) { int i; hud_current = &huds[hud_num % huds_count]; for (i = 0; i < hud_current->count; i++) { hud_current->items[i].hu_textline->x = hud_current->items[i].x; hud_current->items[i].hu_textline->y = hud_current->items[i].y; hud_current->items[i].hu_textline->flags = hud_current->items[i].flags; } ohud_num = hud_num; } } int HU_GetHealthColor(int health, int def) { int result; if (health < health_red) result = CR_RED; else if (health < health_yellow) result = CR_GOLD; else if (health <= health_green) result = CR_GREEN; else result = def; return result; } int HU_GetArmorColor(int armor, int def) { int result; if (armor < armor_red) result = CR_RED; else if (armor < armor_yellow) result = CR_GOLD; else if (armor <= armor_green) result = CR_GREEN; else result = def; return result; } int HU_GetAmmoColor(int ammo, int fullammo) { int result; int ammopct = (100 * ammo) / fullammo; if (ammopct < ammo_red) result = CR_RED; else if (ammopct < ammo_yellow) result = CR_GOLD; else result = CR_GREEN; return result; } void HU_widget_build_ammo(void) { int i; char *s; char ammostr[80]; //jff 3/8/98 allow plenty room for dehacked mods int fullammo = plr->maxammo[weaponinfo[plr->readyweapon].ammo]; // do the hud ammo display // clear the widgets internal line HUlib_clearTextLine(&w_ammo); strcpy(hud_ammostr,"AMM "); if (weaponinfo[plr->readyweapon].ammo == am_noammo || fullammo == 0) { // special case for weapon with no ammo selected - blank bargraph + N/A strcat(hud_ammostr,"\x7f\x7f\x7f\x7f\x7f\x7f\x7f N/A"); w_ammo.cm = CR_GRAY; } else { int ammo = plr->ammo[weaponinfo[plr->readyweapon].ammo]; int ammopct = (100*ammo)/fullammo; int ammobars = ammopct/4; // build the numeric amount init string sprintf(ammostr,"%d/%d",ammo,fullammo); // build the bargraph string // full bargraph chars for (i=4;i<4+ammobars/4;) hud_ammostr[i++] = 123; // plus one last character with 0,1,2,3 bars switch(ammobars%4) { case 0: break; case 1: hud_ammostr[i++] = 126; break; case 2: hud_ammostr[i++] = 125; break; case 3: hud_ammostr[i++] = 124; break; } // pad string with blank bar characters while(i<4+7) hud_ammostr[i++] = 127; hud_ammostr[i] = '\0'; strcat(hud_ammostr,ammostr); // set the display color from the percentage of total ammo held w_ammo.cm = HU_GetAmmoColor(ammo, fullammo); } // transfer the init string to the widget s = hud_ammostr; while (*s) HUlib_addCharToTextLine(&w_ammo, *(s++)); } void HU_widget_draw_ammo(void) { // display the ammo widget every frame HUlib_drawTextLine(&w_ammo, false); } void HU_widget_build_health(void) { int i; char *s; char healthstr[80];//jff int health = plr->health; int healthbars = health>100? 25 : health/4; if (w_health.val != -1 && w_health.val == health) return; w_health.val = health; // clear the widgets internal line HUlib_clearTextLine(&w_health); // build the numeric amount init string sprintf(healthstr,"%3d",health); // build the bargraph string // full bargraph chars for (i=4;i<4+healthbars/4;) hud_healthstr[i++] = 123; // plus one last character with 0,1,2,3 bars switch(healthbars%4) { case 0: break; case 1: hud_healthstr[i++] = 126; break; case 2: hud_healthstr[i++] = 125; break; case 3: hud_healthstr[i++] = 124; break; } // pad string with blank bar characters while(i<4+7) hud_healthstr[i++] = 127; hud_healthstr[i] = '\0'; strcat(hud_healthstr,healthstr); // set the display color from the amount of health posessed w_health.cm = HU_GetHealthColor(health, CR_BLUE); // transfer the init string to the widget s = hud_healthstr; while (*s) HUlib_addCharToTextLine(&w_health, *(s++)); } void HU_widget_draw_health(void) { HUlib_drawTextLine(&w_health, false); } void HU_widget_build_health_big(void) { char *s; char healthstr[80];//jff int health = plr->health; if (w_health_big.val != -1 && w_health_big.val == health) return; w_health_big.val = health; // clear the widgets internal line HUlib_clearTextLine(&w_health_big); // build the numeric amount init string sprintf(healthstr,"%d",health); // set the display color from the amount of health posessed if (!sts_always_red) w_health_big.cm = HU_GetHealthColor(health, CR_BLUE2); // transfer the init string to the widget s = healthstr; while (*s) HUlib_addCharToTextLine(&w_health_big, *(s++)); } void HU_widget_draw_health_big(void) { HUlib_drawTextLine(&w_health_big, false); } void HU_widget_build_medict_icon_big(void) { // transfer the graphic key text to the widget HUlib_clearTextLine(&w_medict_icon_big); HUlib_addCharToTextLine(&w_medict_icon_big, '!' + 0 + 4); } void HU_widget_draw_medict_icon_big(void) { HUlib_drawTextLine(&w_medict_icon_big, false); } void HU_widget_build_medict_icon_small(void) { // transfer the graphic key text to the widget HUlib_clearTextLine(&w_medict_icon_small); HUlib_addCharToTextLine(&w_medict_icon_small, '!' + 0 + 8); } void HU_widget_draw_medict_icon_small(void) { HUlib_drawTextLine(&w_medict_icon_small, false); } void HU_widget_build_medict_icon_custom(void) { // transfer the graphic key text to the widget HUlib_clearTextLine(&w_medict_icon_custom); HUlib_addCharToTextLine(&w_medict_icon_custom, '!' + 0 + 30); } void HU_widget_draw_medict_icon_custom(void) { HUlib_drawTextLine(&w_medict_icon_custom, false); } void HU_widget_build_armor_icon_custom(void) { // transfer the graphic key text to the widget HUlib_clearTextLine(&w_armor_icon_custom); HUlib_addCharToTextLine(&w_armor_icon_custom, (char)('!' + plr->armortype + 1 + 30)); } void HU_widget_draw_armor_icon_custom(void) { HUlib_drawTextLine(&w_armor_icon_custom, false); } void HU_widget_build_armor(void) { int i; char *s; char armorstr[80]; //jff int armor = plr->armorpoints; int armorbars = armor>100? 25 : armor/4; if (w_armor.val != -1 && w_armor.val == armor) return; w_armor.val = armor; // clear the widgets internal line HUlib_clearTextLine(&w_armor); // build the numeric amount init string sprintf(armorstr,"%3d",armor); // build the bargraph string // full bargraph chars for (i=4;i<4+armorbars/4;) hud_armorstr[i++] = 123; // plus one last character with 0,1,2,3 bars switch(armorbars%4) { case 0: break; case 1: hud_armorstr[i++] = 126; break; case 2: hud_armorstr[i++] = 125; break; case 3: hud_armorstr[i++] = 124; break; } // pad string with blank bar characters while(i<4+7) hud_armorstr[i++] = 127; hud_armorstr[i] = '\0'; strcat(hud_armorstr,armorstr); // set the display color from the amount of armor posessed w_armor.cm = HU_GetArmorColor(armor, CR_BLUE); // transfer the init string to the widget s = hud_armorstr; while (*s) HUlib_addCharToTextLine(&w_armor, *(s++)); } void HU_widget_draw_armor(void) { HUlib_drawTextLine(&w_armor, false); } void HU_widget_build_armor_big(void) { char *s; char armorstr[80]; //jff int armor = plr->armorpoints; if (w_armor_big.val != -1 && w_armor_big.val == armor) return; w_armor_big.val = armor; // clear the widgets internal line HUlib_clearTextLine(&w_armor_big); // build the numeric amount init string sprintf(armorstr,"%d",armor); // set the display color from the amount of armor posessed if (!sts_always_red) w_armor_big.cm = HU_GetArmorColor(armor, CR_BLUE2); // transfer the init string to the widget s = armorstr; while (*s) HUlib_addCharToTextLine(&w_armor_big, *(s++)); } void HU_widget_draw_armor_big(void) { HUlib_drawTextLine(&w_armor_big, false); } void HU_widget_build_armor_icon_big(void) { // transfer the graphic key text to the widget HUlib_clearTextLine(&w_armor_icon_big); HUlib_addCharToTextLine(&w_armor_icon_big, (char)('!' + plr->armortype + 1 + 4)); } void HU_widget_draw_armor_icon_big(void) { HUlib_drawTextLine(&w_armor_icon_big, false); } void HU_widget_build_armor_icon_small(void) { // transfer the graphic key text to the widget HUlib_clearTextLine(&w_armor_icon_small); HUlib_addCharToTextLine(&w_armor_icon_small, (char)('!' + plr->armortype + 1 + 8)); } void HU_widget_draw_armor_icon_small(void) { HUlib_drawTextLine(&w_armor_icon_small, false); } void HU_widget_build_weapon(void) { int i; char *s; int w; int ammo,fullammo,ammopct; // clear the widgets internal line HUlib_clearTextLine(&w_weapon); i=4; hud_weapstr[i] = '\0'; //jff 3/7/98 make sure ammo goes away // do each weapon that exists in current gamemode for (w=0;w<=wp_supershotgun;w++) //jff 3/4/98 show fists too, why not? { int ok=1; //jff avoid executing for weapons that do not exist switch (gamemode) { case shareware: if (w>=wp_plasma && w!=wp_chainsaw) ok=0; break; case retail: case registered: if (w>=wp_supershotgun) ok=0; break; default: case commercial: break; } if (!ok) continue; ammo = plr->ammo[weaponinfo[w].ammo]; fullammo = plr->maxammo[weaponinfo[w].ammo]; ammopct=0; // skip weapons not currently posessed if (!plr->weaponowned[w]) continue; ammopct = fullammo? (100*ammo)/fullammo : 100; // display each weapon number in a color related to the ammo for it hud_weapstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths if (weaponinfo[w].ammo==am_noammo) //jff 3/14/98 show berserk on HUD hud_weapstr[i++] = plr->powers[pw_strength]? '0'+CR_GREEN : '0'+CR_GRAY; else if (ammopctcards[k]) continue; hud_gkeysstr[i++] = '!'+k; // key number plus '!' is char for key hud_gkeysstr[i++] = ' '; // spacing hud_gkeysstr[i++] = ' '; } hud_gkeysstr[i]='\0'; } else // not possible in current code, unless deathmatching, { i=4; hud_keysstr[i] = '\0'; //jff 3/7/98 make sure deleted keys go away // if deathmatch, build string showing top four frag counts if (deathmatch) //jff 3/17/98 show frags, not keys, in deathmatch { int top1=-999,top2=-999,top3=-999,top4=-999; int idx1=-1,idx2=-1,idx3=-1,idx4=-1; int fragcount,m; char numbuf[32]; // scan thru players for (k=0;ktop1) { top4=top3; top3=top2; top2 = top1; top1=fragcount; idx4=idx3; idx3=idx2; idx2 = idx1; idx1=k; } else if (fragcount>top2) { top4=top3; top3=top2; top2=fragcount; idx4=idx3; idx3=idx2; idx2=k; } else if (fragcount>top3) { top4=top3; top3=fragcount; idx4=idx3; idx3=k; } else if (fragcount>top4) { top4=fragcount; idx4=k; } } // if the biggest number exists, put it in the init string if (idx1>-1) { sprintf(numbuf,"%5d",top1); // make frag count in player's color via escape code hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths hud_keysstr[i++] = '0'+plyrcoltran[idx1&3]; s = numbuf; while (*s) hud_keysstr[i++] = *(s++); } // if the second biggest number exists, put it in the init string if (idx2>-1) { sprintf(numbuf,"%5d",top2); // make frag count in player's color via escape code hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths hud_keysstr[i++] = '0'+plyrcoltran[idx2&3]; s = numbuf; while (*s) hud_keysstr[i++] = *(s++); } // if the third biggest number exists, put it in the init string if (idx3>-1) { sprintf(numbuf,"%5d",top3); // make frag count in player's color via escape code hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths hud_keysstr[i++] = '0'+plyrcoltran[idx3&3]; s = numbuf; while (*s) hud_keysstr[i++] = *(s++); } // if the fourth biggest number exists, put it in the init string if (idx4>-1) { sprintf(numbuf,"%5d",top4); // make frag count in player's color via escape code hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths hud_keysstr[i++] = '0'+plyrcoltran[idx4&3]; s = numbuf; while (*s) hud_keysstr[i++] = *(s++); } hud_keysstr[i] = '\0'; } //jff 3/17/98 end of deathmatch clause else // build alphabetical key display (not used currently) { // scan the keys for (k=0;k<6;k++) { // skip any not possessed by the displayed player's stats if (!plr->cards[k]) continue; // use color escapes to make text in key's color hud_keysstr[i++] = '\x1b'; //jff 3/26/98 use ESC not '\' for paths switch(k) { case 0: hud_keysstr[i++] = '0'+CR_BLUE; hud_keysstr[i++] = 'B'; hud_keysstr[i++] = 'C'; hud_keysstr[i++] = ' '; break; case 1: hud_keysstr[i++] = '0'+CR_GOLD; hud_keysstr[i++] = 'Y'; hud_keysstr[i++] = 'C'; hud_keysstr[i++] = ' '; break; case 2: hud_keysstr[i++] = '0'+CR_RED; hud_keysstr[i++] = 'R'; hud_keysstr[i++] = 'C'; hud_keysstr[i++] = ' '; break; case 3: hud_keysstr[i++] = '0'+CR_BLUE; hud_keysstr[i++] = 'B'; hud_keysstr[i++] = 'S'; hud_keysstr[i++] = ' '; break; case 4: hud_keysstr[i++] = '0'+CR_GOLD; hud_keysstr[i++] = 'Y'; hud_keysstr[i++] = 'S'; hud_keysstr[i++] = ' '; break; case 5: hud_keysstr[i++] = '0'+CR_RED; hud_keysstr[i++] = 'R'; hud_keysstr[i++] = 'S'; hud_keysstr[i++] = ' '; break; } hud_keysstr[i]='\0'; } } } HUlib_clearTextLine(&w_keys); // clear the widget strings // transfer the built string (frags or key title) to the widget s = hud_keysstr; //jff 3/7/98 display key titles/key text or frags while (*s) HUlib_addCharToTextLine(&w_keys, *(s++)); //jff 3/17/98 show graphic keys in non-DM only if (!deathmatch) //jff 3/7/98 display graphic keys { // clear the widget strings HUlib_clearTextLine(&w_gkeys); // transfer the graphic key text to the widget s = hud_gkeysstr; while (*s) HUlib_addCharToTextLine(&w_gkeys, *(s++)); } w_gkeys.x = w_keys.x + 20; w_gkeys.y = w_keys.y; w_gkeys.flags = w_keys.flags; } void HU_widget_draw_keys(void) { HUlib_drawTextLine(&w_keys, false); if (!deathmatch) { HUlib_drawTextLine(&w_gkeys, false); } } void HU_widget_build_monsec(void) { int i; char *s; //e6y char allkills[200], allsecrets[200]; int playerscount; int fullkillcount, fullitemcount, fullsecretcount; int color, killcolor, itemcolor, secretcolor; // clear the internal widget text buffer HUlib_clearTextLine(&w_monsec); if (!hudadd_smarttotals || deathmatch) { sprintf ( hud_monsecstr, "STS \x1b\x36K \x1b\x33%d \x1b\x36M \x1b\x33%d \x1b\x37I \x1b\x33%d/%d \x1b\x35S \x1b\x33%d/%d", plr->killcount,totallive, plr->itemcount,totalitems, plr->secretcount,totalsecret ); } else { int allkills_len = 0; int allsecrets_len = 0; playerscount = 0; fullkillcount = 0; fullitemcount = 0; fullsecretcount = 0; for (i=0 ; i= 0 && allsecrets_len >=0) { allkills_len += sprintf(&allkills[allkills_len], "\x1b%c+%d", color, players[i].killcount - players[i].resurectedkillcount); allsecrets_len += sprintf(&allsecrets[allsecrets_len], "\x1b%c+%d", color, players[i].secretcount); } } playerscount++; fullkillcount += players[i].killcount - players[i].resurectedkillcount; fullitemcount += players[i].itemcount; fullsecretcount += players[i].secretcount; } } killcolor = (fullkillcount >= totalkills ? 0x37 : 0x35); secretcolor = (fullsecretcount >= totalsecret ? 0x37 : 0x35); itemcolor = (fullitemcount >= totalitems ? 0x37 : 0x35); if (playerscount<2) { sprintf ( hud_monsecstr, "STS \x1b\x36K \x1b%c%d/%d \x1b\x36I \x1b%c%d/%d \x1b\x36S \x1b%c%d/%d", killcolor, fullkillcount,totalkills, itemcolor,plr->itemcount,totalitems, secretcolor, fullsecretcount,totalsecret ); } else { sprintf ( hud_monsecstr, "STS \x1b\x36K %s \x1b%c%d/%d \x1b\x36I \x1b%c%d/%d \x1b\x36S %s \x1b%c%d/%d", allkills,killcolor,fullkillcount,totalkills, itemcolor,plr->itemcount,totalitems, allsecrets,secretcolor,fullsecretcount,totalsecret ); } } // transfer the init string to the widget s = hud_monsecstr; while (*s) HUlib_addCharToTextLine(&w_monsec, *(s++)); } void HU_widget_draw_monsec(void) { HUlib_drawTextLine(&w_monsec, false); } void HU_widget_build_hudadd(void) { char *s; hud_add[0] = 0; if (!hudadd_gamespeed && !hudadd_leveltime) return; if (hudadd_gamespeed) sprintf(hud_add,"\x1b\x32speed \x1b\x33%.2d ", realtic_clock_rate); if ((hudadd_leveltime) || (demoplayback && hudadd_demotime)) { static char demo_len_null[1]={0}; char *demo_len = demoplayback && hudadd_demotime ? demo_len_st : demo_len_null; if (totalleveltimes) sprintf(hud_add+strlen(hud_add),"\x1b\x32time \x1b\x35%d:%02d%s \x1b\x33%d:%05.2f ", (totalleveltimes+leveltime)/35/60, ((totalleveltimes+leveltime)%(60*35))/35, demo_len, leveltime/35/60, (float)(leveltime%(60*35))/35); else sprintf(hud_add+strlen(hud_add),"\x1b\x32time \x1b\x33%d:%05.2f%s ", leveltime/35/60, (float)(leveltime%(60*35))/35, demo_len); } HUlib_clearTextLine(&w_hudadd); s = hud_add; while (*s) HUlib_addCharToTextLine(&w_hudadd, *(s++)); } void HU_widget_draw_hudadd(void) { if (hudadd_gamespeed || hudadd_leveltime) { HUlib_drawTextLine(&w_hudadd, false); } } void HU_widget_build_medict_percent(void) { int health = plr->health; if (w_medict_percent.val != -1 && w_medict_percent.val == health) return; w_medict_percent.val = health; // transfer the graphic key text to the widget HUlib_clearTextLine(&w_medict_percent); if (!sts_always_red) { if (sts_pct_always_gray) w_medict_percent.cm = CR_GRAY; else w_medict_percent.cm = HU_GetHealthColor(health, CR_BLUE2); } HUlib_addCharToTextLine(&w_medict_percent, (char)('!' + 12)); } void HU_widget_draw_medict_percent(void) { HUlib_drawTextLine(&w_medict_percent, false); } void HU_widget_build_armor_percent(void) { int armor = plr->armorpoints; if (w_armor_percent.val != -1 && w_armor_percent.val == armor) return; w_armor_percent.val = armor; // transfer the graphic key text to the widget HUlib_clearTextLine(&w_armor_percent); if (!sts_always_red) { if (sts_pct_always_gray) w_armor_percent.cm = CR_GRAY; else w_armor_percent.cm = HU_GetArmorColor(armor, CR_BLUE2); } HUlib_addCharToTextLine(&w_armor_percent, (char)('!' + 13)); } void HU_widget_draw_armor_percent(void) { HUlib_drawTextLine(&w_armor_percent, false); } void HU_widget_build_ammo_big(void) { char *s; char ammostr[80]; int fullammo = plr->maxammo[weaponinfo[plr->readyweapon].ammo]; // clear the widgets internal line HUlib_clearTextLine(&w_ammo_big); if (weaponinfo[plr->readyweapon].ammo != am_noammo && fullammo != 0) { int ammo = plr->ammo[weaponinfo[plr->readyweapon].ammo]; // build the numeric amount init string sprintf(ammostr, "%d", ammo); // set the display color from the percentage of total ammo held if (!sts_always_red) w_ammo_big.cm = HU_GetAmmoColor(ammo, fullammo); // transfer the init string to the widget s = ammostr; while (*s) HUlib_addCharToTextLine(&w_ammo_big, *(s++)); } } void HU_widget_draw_ammo_big(void) { HUlib_drawTextLine(&w_ammo_big, false); } void HU_widget_build_ammo_icon(void) { int ammo = weaponinfo[plr->readyweapon].ammo; if (w_ammo_icon.val != -1 && w_ammo_icon.val == ammo) return; w_ammo_icon.val = ammo; if (ammo < NUMAMMO) { HUlib_clearTextLine(&w_ammo_icon); HUlib_addCharToTextLine(&w_ammo_icon, (char)('!' + ammo + 40)); } else { HUlib_clearTextLine(&w_ammo_icon); } } void HU_widget_draw_ammo_icon(void) { HUlib_drawTextLine(&w_ammo_icon, false); } void HU_widget_build_gkeys(void) { int i, k; char *s; char gkeysstr[80]; int mask = 0; // build text string whose characters call out graphic keys from fontk i = 0; for (k = 0; k < 6; k++) { // skip keys not possessed if (!plr->cards[k]) continue; gkeysstr[i++] = '!' + k; // key number plus '!' is char for key gkeysstr[i++] = ' '; // spacing gkeysstr[i++] = ' '; mask |= (1 << k); } if (w_keys_icon.val != -1 && w_keys_icon.val == mask) return; w_keys_icon.val = mask; gkeysstr[i] = '\0'; while (((--i) > 0) && (gkeysstr[i] == ' ')) gkeysstr[i] = '\0'; // clear the widget strings HUlib_clearTextLine(&w_keys_icon); // transfer the graphic key text to the widget s = gkeysstr; while (*s) HUlib_addCharToTextLine(&w_keys_icon, *(s++)); } void HU_widget_draw_gkeys(void) { HUlib_drawTextLine(&w_keys_icon, false); } // // HU_Drawer() // // Draw all the pieces of the heads-up display // // Passed nothing, returns nothing // void HU_Drawer(void) { char *s; player_t *plr; //jff 3/4/98 speed update up for slow systems //e6y: speed update for uncapped framerate static dboolean needupdate = false; if (realframe) needupdate = !needupdate; // don't draw anything if there's a fullscreen menu up if (menuactive == mnact_full) return; plr = &players[displayplayer]; // killough 3/7/98 // draw the automap widgets if automap is displayed if (automapmode & am_active) { if (!(automapmode & am_overlay) || (viewheight != SCREENHEIGHT))//!hud_displayed) { // map title HUlib_drawTextLine(&w_title, false); } //jff 2/16/98 output new coord display // x-coord if (map_point_coordinates) { //e6y: speedup if (!realframe) { HUlib_drawTextLine(&w_coordx, false); HUlib_drawTextLine(&w_coordy, false); HUlib_drawTextLine(&w_coordz, false); } else { sprintf(hud_coordstrx,"X: %-5d", (plr->mo->x)>>FRACBITS); HUlib_clearTextLine(&w_coordx); s = hud_coordstrx; while (*s) HUlib_addCharToTextLine(&w_coordx, *(s++)); HUlib_drawTextLine(&w_coordx, false); //jff 3/3/98 split coord display into x,y,z lines // y-coord sprintf(hud_coordstry,"Y: %-5d", (plr->mo->y)>>FRACBITS); HUlib_clearTextLine(&w_coordy); s = hud_coordstry; while (*s) HUlib_addCharToTextLine(&w_coordy, *(s++)); HUlib_drawTextLine(&w_coordy, false); //jff 3/3/98 split coord display into x,y,z lines //jff 2/22/98 added z // z-coord sprintf(hud_coordstrz,"Z: %-5d", (plr->mo->z)>>FRACBITS); HUlib_clearTextLine(&w_coordz); s = hud_coordstrz; while (*s) HUlib_addCharToTextLine(&w_coordz, *(s++)); HUlib_drawTextLine(&w_coordz, false); } } if (map_level_stat) { static char str[32]; int time = leveltime / TICRATE; int ttime = (totalleveltimes + leveltime) / TICRATE; sprintf(str, "Monsters: \x1b%c%d/%d", '0' + hudcolor_mapstat_value, players[consoleplayer].killcount - players[consoleplayer].resurectedkillcount, totalkills); HUlib_clearTextLine(&w_map_monsters); s = str; while (*s) HUlib_addCharToTextLine(&w_map_monsters, *(s++)); HUlib_drawTextLine(&w_map_monsters, false); sprintf(str, "Secrets: \x1b%c%d/%d", '0' + hudcolor_mapstat_value, players[consoleplayer].secretcount, totalsecret); HUlib_clearTextLine(&w_map_secrets); s = str; while (*s) HUlib_addCharToTextLine(&w_map_secrets, *(s++)); HUlib_drawTextLine(&w_map_secrets, false); sprintf(str, "Items: \x1b%c%d/%d", '0' + hudcolor_mapstat_value, players[consoleplayer].itemcount, totalitems); HUlib_clearTextLine(&w_map_items); s = str; while (*s) HUlib_addCharToTextLine(&w_map_items, *(s++)); HUlib_drawTextLine(&w_map_items, false); sprintf(str, "%02d:%02d:%02d", time/3600, (time%3600)/60, time%60); HUlib_clearTextLine(&w_map_time); s = str; while (*s) HUlib_addCharToTextLine(&w_map_time, *(s++)); HUlib_drawTextLine(&w_map_time, false); if (totalleveltimes > 0) { sprintf(str, "%02d:%02d:%02d", ttime/3600, (ttime%3600)/60, ttime%60); HUlib_clearTextLine(&w_map_totaltime); s = str; while (*s) HUlib_addCharToTextLine(&w_map_totaltime, *(s++)); HUlib_drawTextLine(&w_map_totaltime, false); } } } // draw the weapon/health/ammo/armor/kills/keys displays if optioned //jff 2/17/98 allow new hud stuff to be turned off // killough 2/21/98: really allow new hud stuff to be turned off COMPLETELY if ( hud_num > 0 && // hud optioned on hud_displayed && // hud on from fullscreen key viewheight==SCREENHEIGHT && // fullscreen mode is active (!(automapmode & am_active) || // automap is not active (automapmode & am_overlay)) ) { int i; HU_MoveHud(false); // insure HUD display coords are correct if (hud_current) { for (i = 0; i < hud_current->count; i++) { if (hud_current->items[i].build && hud_current->items[i].draw) { if (realframe) { hud_current->items[i].build(); } hud_current->items[i].draw(); } } } //e6y if (traces_present) { int k, num = 0; for(k = 0; k < NUMTRACES; k++) { if (traces[k].count) { if (realframe) { w_traces[num].y = w_traces[0].y - num * 8; if (traces[k].ApplyFunc) traces[k].ApplyFunc(k); HUlib_clearTextLine(&w_traces[num]); s = traces[k].hudstr; while (*s) HUlib_addCharToTextLine(&w_traces[num], *(s++)); if (traces[k].ResetFunc) traces[k].ResetFunc(k); } HUlib_drawTextLine(&w_traces[num], false); num++; } } } } //jff 3/4/98 display last to give priority HU_Erase(); // jff 4/24/98 Erase current lines before drawing current // needed when screen not fullsize //jff 4/21/98 if setup has disabled message list while active, turn it off if (hud_msg_lines<=1) message_list = false; // if the message review not enabled, show the standard message widget if (!message_list) HUlib_drawSText(&w_message); //e6y if (messagecenter_counter) HUlib_drawTextLine(&w_centermsg, false); // if the message review is enabled show the scrolling message review if (hud_msg_lines>1 && message_list) HUlib_drawMText(&w_rtext); // display the interactive buffer for chat entry HUlib_drawIText(&w_chat); } // // HU_Erase() // // Erase hud display lines that can be trashed by small screen display // // Passed nothing, returns nothing // void HU_Erase(void) { // erase the message display or the message review display if (!message_list) HUlib_eraseSText(&w_message); else HUlib_eraseMText(&w_rtext); //e6y if (messagecenter_counter) HUlib_eraseTextLine(&w_centermsg); // erase the interactive text buffer for chat entry HUlib_eraseIText(&w_chat); // erase the automap title HUlib_eraseTextLine(&w_title); } // // HU_Ticker() // // Update the hud displays once per frame // // Passed nothing, returns nothing // static dboolean bsdown; // Is backspace down? static int bscounter; void HU_Ticker(void) { int i, rc; char c; // tick down message counter if message is up if (message_counter && !--message_counter) { message_on = false; message_nottobefuckedwith = false; } if (bsdown && bscounter++ > 9) { HUlib_keyInIText(&w_chat, (unsigned char)key_backspace); bscounter = 8; } // if messages on, or "Messages Off" is being displayed // this allows the notification of turning messages off to be seen if (showMessages || message_dontfuckwithme) { // display message if necessary if ((plr->message && !message_nottobefuckedwith) || (plr->message && message_dontfuckwithme)) { //post the message to the message widget HUlib_addMessageToSText(&w_message, 0, plr->message); //jff 2/26/98 add message to refresh text widget too HUlib_addMessageToMText(&w_rtext, 0, plr->message); // clear the message to avoid posting multiple times plr->message = 0; // note a message is displayed message_on = true; // start the message persistence counter message_counter = HU_MSGTIMEOUT; // transfer "Messages Off" exception to the "being displayed" variable message_nottobefuckedwith = message_dontfuckwithme; // clear the flag that "Messages Off" is being posted message_dontfuckwithme = 0; } } //e6y if (messagecenter_counter) messagecenter_counter--; if (/*showMessages && */plr->centermessage) { const char *s = plr->centermessage; HUlib_clearTextLine(&w_centermsg); while (*s) { HUlib_addCharToTextLine(&w_centermsg, *(s++)); } HUlib_setTextXCenter(&w_centermsg); plr->centermessage = NULL; messagecenter_counter = HU_MSGCENTERTIMEOUT; S_StartSound(NULL, sfx_secret); } // check for incoming chat characters if (netgame) { for (i=0; i= 'a' && c <= 'z') c = (char) shiftxform[(unsigned char) c]; rc = HUlib_keyInIText(&w_inputbuffer[i], c); if (rc && c == KEYD_ENTER) { if (w_inputbuffer[i].l.len && (chat_dest[i] == consoleplayer+1 || chat_dest[i] == HU_BROADCAST)) { HUlib_addMessageToSText(&w_message, player_names[i], w_inputbuffer[i].l.l); message_nottobefuckedwith = true; message_on = true; message_counter = HU_MSGTIMEOUT; if ( gamemode == commercial ) S_StartSound(0, sfx_radio); else S_StartSound(0, sfx_tink); } HUlib_resetIText(&w_inputbuffer[i]); } } players[i].cmd.chatchar = 0; } } } } #define QUEUESIZE 128 static char chatchars[QUEUESIZE]; static int head = 0; static int tail = 0; // // HU_queueChatChar() // // Add an incoming character to the circular chat queue // // Passed the character to queue, returns nothing // static void HU_queueChatChar(char c) { if (((head + 1) & (QUEUESIZE-1)) == tail) { plr->message = HUSTR_MSGU; } else { chatchars[head] = c; head = (head + 1) & (QUEUESIZE-1); } } // // HU_dequeueChatChar() // // Remove the earliest added character from the circular chat queue // // Passed nothing, returns the character dequeued // char HU_dequeueChatChar(void) { char c; if (head != tail) { c = chatchars[tail]; tail = (tail + 1) & (QUEUESIZE-1); } else { c = 0; } return c; } // // HU_Responder() // // Responds to input events that affect the heads up displays // // Passed the event to respond to, returns true if the event was handled // dboolean HU_Responder(event_t *ev) { static char lastmessage[HU_MAXLINELENGTH+1]; const char* macromessage; // CPhipps - const char* dboolean eatkey = false; static dboolean shiftdown = false; static dboolean altdown = false; unsigned char c; int i; int numplayers; static int num_nobrainers = 0; numplayers = 0; for (i=0 ; idata1 == key_shift) { shiftdown = ev->type == ev_keydown; return false; } else if (ev->data1 == key_alt) { altdown = ev->type == ev_keydown; return false; } else if (ev->data1 == key_backspace) { bsdown = ev->type == ev_keydown; bscounter = 0; } if (ev->type != ev_keydown) return false; if (!chat_on) { if (ev->data1 == key_enter) // phares { #ifndef INSTRUMENTED // never turn on message review if INSTRUMENTED defined if (hud_msg_lines>1) // it posts multi-line messages that will trash { if (message_list) HU_Erase(); //jff 4/28/98 erase behind messages message_list = !message_list; //jff 2/26/98 toggle list of messages } #endif if (!message_list) // if not message list, refresh message { message_on = true; message_counter = HU_MSGTIMEOUT; } eatkey = true; }//jff 2/26/98 no chat if message review is displayed // killough 10/02/98: no chat if demo playback // no chat in -solo-net mode else if (!demoplayback && !message_list && netgame && numplayers > 1) { if (ev->data1 == key_chat) { eatkey = chat_on = true; HUlib_resetIText(&w_chat); HU_queueChatChar(HU_BROADCAST); } else if (numplayers > 2) { for (i=0; idata1 == destination_keys[i]) { if (playeringame[i] && i!=consoleplayer) { eatkey = chat_on = true; HUlib_resetIText(&w_chat); HU_queueChatChar((char)(i+1)); break; } else if (i == consoleplayer) { num_nobrainers++; if (num_nobrainers < 3) plr->message = HUSTR_TALKTOSELF1; else if (num_nobrainers < 6) plr->message = HUSTR_TALKTOSELF2; else if (num_nobrainers < 9) plr->message = HUSTR_TALKTOSELF3; else if (num_nobrainers < 32) plr->message = HUSTR_TALKTOSELF4; else plr->message = HUSTR_TALKTOSELF5; } } } } } }//jff 2/26/98 no chat functions if message review is displayed else if (!message_list) { c = ev->data1; // send a macro if (altdown) { c = c - '0'; if (c > 9) return false; macromessage = chat_macros[c]; // kill last message with a '\n' HU_queueChatChar((char)key_enter); // DEBUG!!! // phares // send the macro message while (*macromessage) HU_queueChatChar(*macromessage++); HU_queueChatChar((char)key_enter); // phares // leave chat mode and notify that it was sent chat_on = false; strcpy(lastmessage, chat_macros[c]); plr->message = lastmessage; eatkey = true; } else { if (shiftdown || (c >= 'a' && c <= 'z')) c = shiftxform[c]; eatkey = HUlib_keyInIText(&w_chat, c); if (eatkey) HU_queueChatChar(c); if (c == key_enter) // phares { chat_on = false; if (w_chat.l.len) { strcpy(lastmessage, w_chat.l.l); plr->message = lastmessage; } } else if (c == key_escape) // phares chat_on = false; } } return eatkey; }