435 lines
12 KiB
Plaintext
435 lines
12 KiB
Plaintext
/***
|
|
*
|
|
* Copyright (c) 2016-2019 Marco 'eukara' Hladik. All rights reserved.
|
|
*
|
|
* See the file LICENSE attached with the sources for usage details.
|
|
*
|
|
****/
|
|
|
|
// Menus with their window titles and draw functions
|
|
|
|
//TAGGG
|
|
// also public now so that the first MOTD element can have its sTitle modified by game
|
|
// logic. It's a bit more than just one language key now.
|
|
// And why did the array indeces have a number like this: "[11]"? Looks to adjust fine
|
|
// to having no number and doing the count itself.
|
|
// where does "VGUI_TITLE_MODT" or the text it produces ("Message of the day") ever occur
|
|
// in game files or script?
|
|
// ANSWERED: it comes from the language file. See one of the files near the compiled
|
|
// .dat file
|
|
// (typically in the game's data.pk3dir fodlder) like so:
|
|
// csprogs.dat.en.po
|
|
// The identifier and value for that language will show up.
|
|
// In this case, VGUI_TITLE_MODT won't be used. This new way mimicks the original The
|
|
// Specialists initial screen a little more.
|
|
|
|
|
|
|
|
//font_s FONT_ARIAL_TITLE_EX;
|
|
|
|
|
|
// Keep in synch with ui.h's UI_SCREEN enum choices, besides the NONE choice.
|
|
// That isn't represented, not even by a dummy.
|
|
var ui_screen_t ary_UI_Screen[] = {
|
|
{
|
|
FALSE,
|
|
TRUE,
|
|
UI_MOTD_Init,
|
|
UI_MOTD_Show,
|
|
UI_MOTD_Hide,
|
|
UI_MOTD_Draw,
|
|
UI_MOTD_OnMouseClick,
|
|
UI_MOTD_OnKeyDown
|
|
},
|
|
{
|
|
FALSE,
|
|
FALSE,
|
|
UI_BuyMenu_Init,
|
|
UI_BuyMenu_Show,
|
|
UI_BuyMenu_Hide,
|
|
UI_BuyMenu_Draw,
|
|
UI_BuyMenu_OnMouseClick,
|
|
UI_BuyMenu_OnKeyDown
|
|
}
|
|
|
|
};
|
|
|
|
//var float nextPrintoutTime = -1;
|
|
|
|
|
|
// Actually sees if funInit should be called (first time going to that screen),
|
|
// also calls funShow.
|
|
void
|
|
UI_InitCheck(void){
|
|
if(
|
|
!ary_UI_Screen[pSeatLocal->m_flUI_Display-1].bInitializedYet &&
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].funInit != NULL
|
|
){
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].funInit();
|
|
}
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].bInitializedYet = TRUE;
|
|
if(
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].funShow != NULL
|
|
){
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].funShow();
|
|
}
|
|
g_UI_queueInit = FALSE;
|
|
}
|
|
|
|
void
|
|
UI_ChangeScreen(UI_SCREEN arg_NewScreenID)
|
|
{
|
|
g_UI_queueInit = FALSE;
|
|
|
|
if(
|
|
pSeatLocal->m_flUI_Display != UI_SCREEN::NONE &&
|
|
arg_NewScreenID != pSeatLocal->m_flUI_Display
|
|
){
|
|
// First, check the existing m_flUI_Display. If valid, call funHide for it
|
|
// (does not apply to setting the screen to the same choice)
|
|
if(
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].funHide != NULL
|
|
){
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].funHide();
|
|
}
|
|
}
|
|
|
|
pSeatLocal->m_flUI_Display = (float)arg_NewScreenID;
|
|
|
|
printfline("UI_ChangeScreen:: arg_NewScreenID? %d", arg_NewScreenID);
|
|
|
|
if(arg_NewScreenID == UI_SCREEN::NONE){
|
|
// If at NONE or below, also do nothing. This has no "funInit" behavior.
|
|
// Besides obligatory cleanup if we choose (which may as well be done right here)
|
|
// And turn the cursor lock off.
|
|
setcursormode(FALSE, "gfx/cursor", [0,0,0], 1.0f);
|
|
// And don't let Nuclide's src/client/entry.qc try to re-lock the mouse!
|
|
printfline("TURN SCREEN OFF.");
|
|
gFun_UI_EventGrabber_Hide();
|
|
|
|
// Don't allow the same click to spawn the player, likely not intentional.
|
|
// Unless we want to deviate from original TS and let buymenu-closing orders
|
|
// count as spawn requests.
|
|
// Questionably effective but better than nothing maybe.
|
|
player pl = (player)pSeat->m_ePlayer;
|
|
pl.gflags |= GF_SEMI_TOGGLED;
|
|
pSeatLocal->flBlockSpawnTime = time + 0.20;
|
|
return;
|
|
}
|
|
|
|
// If this screen has a funInit, do it!
|
|
// This is done for the new screen once as soon as it becomes the active one.
|
|
// Also, turn the cursor lock on, clearly this needs user input.
|
|
// src/client/entry.qc already has this check too for having any UI widget, but
|
|
// it takes one mouse-movement for it to kick-in, which causes one slight nudge of the
|
|
// camera before the cursor appears. Not terrible, but calling for the lock this early
|
|
// ensures that doesn't get a chance to happen.
|
|
setcursormode(TRUE, "gfx/cursor", [0,0,0], 1.0f);
|
|
// And let the event grabber be shown so that entry.qc doesn't try to undo the mouse lock.
|
|
gFun_UI_EventGrabber_Show();
|
|
|
|
if(video_res[0] == 0){
|
|
// haven't set the screen resolution vars yet?
|
|
// STOP: handle this as soon as possible.
|
|
g_UI_queueInit = TRUE;
|
|
return;
|
|
}
|
|
|
|
UI_InitCheck();
|
|
|
|
}
|
|
|
|
|
|
void
|
|
UI_Init(void)
|
|
{
|
|
string sTemp;
|
|
int iMOTDLength;
|
|
int i;
|
|
int s;
|
|
|
|
filestream fmMapDescr;
|
|
|
|
// First load the MESSAGE OF THE DAY from the sever
|
|
//sMOTD_total = serverkey("motd_total");
|
|
|
|
sMOTD_total = "";
|
|
|
|
iMOTDLength = stof( serverkey( "motdlength" ) );
|
|
for (i = 0; i < iMOTDLength; i++ ) {
|
|
sMOTDString[ i ] = serverkey( sprintf( "motdline%i", i ) );
|
|
|
|
if ( sMOTDString[ i ] == "/" ) {
|
|
sMOTD_total = strcat(sMOTD_total, "\n" );
|
|
}else{
|
|
sMOTD_total = strcat(sMOTD_total, sprintf("%s\n", sMOTDString[ i ]) );
|
|
}
|
|
}
|
|
// color it
|
|
// NOPE! Let this be handled elsewhere in case of a different color choice!
|
|
//sMOTD_total = strcat("^xFA0", sMOTD_total);
|
|
|
|
|
|
// Now load the MAP DESCRIPTION
|
|
// TAGGG
|
|
// Do we have any use for this though? Check original TS, the "Select Team"
|
|
// screen does (press enter to close or after closing the MoTD, probably)
|
|
|
|
sMapString_total = "";
|
|
|
|
//printfline("MAPNAME READS: %s", mapname);
|
|
// TODO! If the mapname ends in .bsp, remove that portion, that causes
|
|
// the appended ".txt" to work wrongly, "mymap.bsp.txt" instead of "mymap.txt"
|
|
|
|
fmMapDescr = fopen( sprintf( "maps/%s.txt", mapname ), FILE_READ );
|
|
if ( fmMapDescr != -1 ) {
|
|
for (i = 0; i < 35; i++ ) {
|
|
sTemp = fgets( fmMapDescr );
|
|
if not ( sTemp ) {
|
|
break;
|
|
}
|
|
sMapString[ i ] = sTemp;
|
|
|
|
/*
|
|
if (sMapString[ i ] == "/" ) {
|
|
sMapString_total = strcat(sMOTD_total, "\n" );
|
|
}else{
|
|
sMapString_total = strcat(sMapString_total, sprintf("%s\n", sMapString[ i ]) );
|
|
}
|
|
*/
|
|
sMapString_total = strcat(sMapString_total, sprintf("%s\n", sMapString[ i ]) );
|
|
|
|
}
|
|
fclose( fmMapDescr );
|
|
}
|
|
|
|
//printfline("MAP DESCRIPTOR?");
|
|
//printfline("%s", sMapString_total);
|
|
|
|
|
|
gFun_UI_EventGrabber_Initialize();
|
|
|
|
////////////////////////////////////////////////////
|
|
// FOR NOW, a lazy way of init for all seats.
|
|
// Apply to all seats, not worrying about what numclientseats is because this is tiny.
|
|
if (serverkeyfloat("slots") != 1) {
|
|
// We start on the MOTD, always
|
|
for (s = 0; s < g_seats.length; s++){
|
|
pSeat = &g_seats[s];
|
|
pSeatLocal = &g_seatslocal[s];
|
|
UI_ChangeScreen(UI_SCREEN::MOTD);
|
|
}
|
|
}else{
|
|
// make all pSeats start at the NONE screen instead
|
|
for (s = 0; s < g_seats.length; s++){
|
|
pSeat = &g_seats[s];
|
|
pSeatLocal = &g_seatslocal[s];
|
|
UI_ChangeScreen(UI_SCREEN::NONE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// big ugly method
|
|
void
|
|
UI_determineDrawGlobals(void){
|
|
|
|
float fontSizeMulti;
|
|
|
|
// How much space to add to the left and right of the drawn windows (x) and to the top and
|
|
// bottom (y).
|
|
// That does mean each removes twice its value of the drawn window in that dimension.
|
|
// ex: a window_pad_x of 60 will actually remove 120 from the drawn window. 60 from the
|
|
// left, 60 from the right.
|
|
float window_pad_x = video_res[0] * 0.175;
|
|
float window_pad_y = video_res[1] * 0.166;
|
|
float window_width_x = video_res[0] - window_pad_x*2;
|
|
float window_height_y = video_res[1] - window_pad_y*2;
|
|
|
|
|
|
// If the height is over 800, stay at full size. It only gets smaller as the height
|
|
// decreases.
|
|
if(video_res[1] >= 800){
|
|
fontSizeMulti = 1 * 1.0; //REMOVE 1.8 later!!!;
|
|
}else{
|
|
//scale it to fit the screen size.
|
|
//fontSizeMulti = 0.2 + 0.001 * video_res[1];
|
|
//fontSizeMulti = 0.234 + 0.0007 * video_res[1];
|
|
fontSizeMulti = 0.1429 + 0.001 * 1.0 * video_res[1];
|
|
|
|
|
|
}// screen height check
|
|
|
|
//
|
|
if(FONT_ARIAL == -1 || g_videoResPrev != video_res){
|
|
//Give it a font based on this screen size.
|
|
|
|
//g_videoResPrev = video_res;
|
|
g_videoResPrev[0] = video_res[0];
|
|
g_videoResPrev[1] = video_res[1];
|
|
|
|
//FONT_ARIAL = loadfont( "label", "arial", "32", -1 );
|
|
float font_arial_size = (fontSizeMulti * 24);
|
|
float font_arial_title_size = (fontSizeMulti * 32);
|
|
string str_font_arial_size = ftos(font_arial_size);
|
|
string str_font_arial_title_size = ftos(font_arial_title_size);
|
|
|
|
|
|
FONT_ARIAL = loadfont( "game", "arial", str_font_arial_size, -1 );
|
|
FONT_ARIAL_TITLE = loadfont( "game", "arial", str_font_arial_title_size, -1 );
|
|
|
|
|
|
// NEW!!!
|
|
// TODO - use Font_Load to properly fill these fields from some kind of
|
|
// font script file most likely, see examples in other codebaes.
|
|
//Font_Load("folder/some_file.ext", &FONT_ARIAL_TITLE_TEST);
|
|
|
|
// This works, but not completely. Want some things to have differnet fonts,
|
|
// like the _title and normal variants of FONT_ARIAL above.
|
|
/*
|
|
Font_Load_Easy("arial", (int)font_arial_title_size, FONT_ARIAL_TITLE_EX);
|
|
g_fntDefault = FONT_ARIAL_TITLE_EX;
|
|
*/
|
|
|
|
|
|
|
|
//print( sprintf("CHANGE height:%i fontm:%.2f fontref:%i match:(%i, %i) totalmatch:%i\n", (int)video_res[1], fontSizeMulti, (int)FONT_ARIAL, (int)(g_videoResPrev[0]==video_res[0]), (int)(g_videoResPrev[1]==video_res[1]), (int)(g_videoResPrev==video_res)) );
|
|
}
|
|
|
|
//little demo.
|
|
/*
|
|
if(nextPrintoutTime == -1 || (time >= nextPrintoutTime) ){
|
|
nextPrintoutTime = time + 2;
|
|
print( sprintf("timed printout. height:%i fontm:%.2f fontref:%i match:(%i, %i) totalmatch:%i\n", (int)video_res[1], fontSizeMulti, (int)FONT_ARIAL, (int)(g_videoResPrev[0]==video_res[0]), (int)(g_videoResPrev[1]==video_res[1]), (int)(g_videoResPrev==video_res)) );
|
|
}
|
|
*/
|
|
|
|
// Oh, there is a Nuclide-provided CVar called 'vgui_color'.
|
|
// Keep this as it is?
|
|
g_UI_Color = autocvar_vgui_color * ( 1 / 255 );
|
|
|
|
// Align the window to the center
|
|
g_UI_WindowPos = video_mins;
|
|
g_UI_WindowPos[0] += window_pad_x;
|
|
g_UI_WindowPos[1] += window_pad_y;
|
|
|
|
g_UI_WindowSize[0] = window_width_x;
|
|
g_UI_WindowSize[1] = window_height_y;
|
|
|
|
g_fontSizeMulti = fontSizeMulti;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
UI_Draw(void)
|
|
{
|
|
if(pSeatLocal->m_flUI_Display == UI_SCREEN::NONE ){
|
|
// Not effective for the new version of game executable fteglqw64.exe?
|
|
// Well that's just dandy
|
|
// (this is supposed to let clicking after closing the buy menu without moving the
|
|
// mouse mouse work).
|
|
setcursormode(FALSE, "gfx/cursor", [0,0,0], 1.0f);
|
|
return;
|
|
}
|
|
|
|
if(g_UI_queueInit){
|
|
// do it then!
|
|
UI_InitCheck();
|
|
}
|
|
|
|
if(!ary_UI_Screen[pSeatLocal->m_flUI_Display-1].bInitializedYet){
|
|
// no drawing uninitialized UI. Is this even possible?
|
|
return;
|
|
}
|
|
|
|
UI_determineDrawGlobals();
|
|
//printfline("UI SIZE B! %.1f %.1f", g_UI_WindowSize[0], g_UI_WindowSize[1]);
|
|
|
|
#ifndef MOTD_NEW_VGUI
|
|
// draw the window only if this screen says to.
|
|
if(ary_UI_Screen[pSeatLocal->m_flUI_Display-1].fDrawMainWindowAuto){
|
|
VGUI_Window( g_UI_WindowPos, g_UI_WindowSize, [g_fontSizeMulti*32,g_fontSizeMulti*32] );
|
|
}
|
|
#endif
|
|
|
|
|
|
// Display the contents of whatever we have selected
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].funDraw();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
UI_MouseClick(void)
|
|
{
|
|
if(pSeatLocal->m_flUI_Display != UI_SCREEN::NONE){
|
|
if(
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].bInitializedYet &&
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].funOnMouseClick != NULL
|
|
){
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].funOnMouseClick();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
UI_KeyDown(void)
|
|
{
|
|
if(pSeatLocal->m_flUI_Display != UI_SCREEN::NONE){
|
|
if(
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].bInitializedYet &&
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].funOnKeyDown != NULL)
|
|
{
|
|
ary_UI_Screen[pSeatLocal->m_flUI_Display-1].funOnKeyDown();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
====================
|
|
UI_CheckMouse
|
|
|
|
Returns whether or not our mouse cursor hovers over a region
|
|
====================
|
|
*/
|
|
BOOL
|
|
UI_CheckMouse(vector vPos, vector vReg)
|
|
{
|
|
vector vSMins, vSMaxs;
|
|
|
|
vSMins = vPos;
|
|
vSMaxs = vPos;
|
|
vSMins[0] = vPos[0];
|
|
vSMaxs[1] = vPos[1] - 1;
|
|
|
|
vSMaxs[0] = vPos[0] + vReg[0];
|
|
vSMaxs[1] = vPos[1] + vReg[1];
|
|
|
|
if ( mouse_pos[0] >= vSMins[0] && mouse_pos[0] <= vSMaxs[0] ) {
|
|
if (mouse_pos[1] >= vSMins[1] && mouse_pos[1] <= vSMaxs[1] ) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
// convenience method for now. Based off of Nuclide's src/vgui Font_Load method,
|
|
// uses its font_s type
|
|
void
|
|
Font_Load_Easy(string strFontPath, int iFontScale, font_s &fntNew)
|
|
{
|
|
fntNew.iScale = iFontScale;
|
|
fntNew.vecColor = [1,1,1];
|
|
fntNew.flAlpha = 1.0f;
|
|
fntNew.iFlags = 0;
|
|
fntNew.iID = (int)loadfont("", strFontPath, ftos((float)fntNew.iScale), -1, 0, 0);
|
|
}
|