diff --git a/src/client/cmds.qc b/src/client/cmds.qc index 446ffcf..cb4384c 100644 --- a/src/client/cmds.qc +++ b/src/client/cmds.qc @@ -25,10 +25,10 @@ ClientGame_ConsoleCommand(void) //TAGGG - is that ok? case "+speedcustom": - pSeatLocal->iInputSpeed = TRUE; + pSeatLocal->m_iInputSpeed = TRUE; break; case "-speedcustom": - pSeatLocal->iInputSpeed = FALSE; + pSeatLocal->m_iInputSpeed = FALSE; break; //TAGGG - NEW ONES @@ -85,12 +85,12 @@ ClientGame_ConsoleCommand(void) */ case "motd": if(getplayerkeyvalue( player_localnum, "*spec" ) != "0"){ - VGUI_ChangeScreen(VGUI_SCREEN::MOTD); + UI_ChangeScreen(UI_SCREEN::MOTD); } break; case "buy": //If we're in spectator mode we can do this - // no-screen check, not necessary probably: pSeatLocal->fVGUI_Display == VGUI_SCREEN::NONE && + // no-screen check, not necessary probably: pSeatLocal->m_flUI_Display == UI_SCREEN::NONE && pl = (player)pSeat->m_ePlayer; printfline("CMD: BUY COMMAND RECEIVED! Should I react? %s (1=yes) : %d", getplayerkeyvalue( player_localnum, "*spec" ), pl.iState); @@ -99,7 +99,7 @@ ClientGame_ConsoleCommand(void) //if(getplayerkeyvalue( player_localnum, "*spec" ) != "0"){ if(pl.iState != PLAYER_STATE::SPAWNED){ //we can show it! - VGUI_ChangeScreen(VGUI_SCREEN::BUYSIDEMENU); + UI_ChangeScreen(UI_SCREEN::BUYMENU); } break; diff --git a/src/client/game_event.qc b/src/client/game_event.qc index 8fac1e0..630ea81 100644 --- a/src/client/game_event.qc +++ b/src/client/game_event.qc @@ -26,8 +26,8 @@ ClientGame_EventParse(float fHeader) // ! // Any need for a m_ePlayer classname check here? - // I think none apply for being an authentic "spectator", most don't for being a buymenu spectator - // (player with that is not PLAYER_STATE::SPAWNED) + // I think none apply for being an authentic "spectator", most don't for being a + // buymenu spectator (player with that is not PLAYER_STATE::SPAWNED) switch(fHeader){ case EV_OBITUARY: @@ -162,7 +162,7 @@ ClientGame_EventParse(float fHeader) deployConfig(); // Just in case. - VGUI_ChangeScreen(VGUI_SCREEN::NONE); + UI_ChangeScreen(UI_SCREEN::NONE); // so that any choice of weapon, same as before or even nothing, will still // let client/view.qc do the whole viewmodel routine again @@ -178,9 +178,6 @@ ClientGame_EventParse(float fHeader) case EVENT_TS::PLAYER_DEATH: EV_PlayerDeath(); break; - //case EVENT_TS::PLAY_INSERT_SHELL_SND: - // EV_TS_PlayInsertShellSound(pl); - // break; case EVENT_TS::EFFECT_EXPLOSION: vecOrigin[0] = readcoord(); vecOrigin[1] = readcoord(); diff --git a/src/client/hud.qc b/src/client/hud.qc index 12902f1..9e800c8 100644 --- a/src/client/hud.qc +++ b/src/client/hud.qc @@ -83,9 +83,7 @@ HUD_Draw(void) } ////////////////////////////////////////////////////////////// - GameClient_PlayerInputRaw(); - - //TAGGG - NEw + //TAGGG - new ////////////////////////////////////////////////////////////// drawTimer(); drawPlayerStats(); @@ -94,8 +92,9 @@ HUD_Draw(void) ////////////////////////////////////////////////////////////// - // TEST! Just for nuclide, doesn't matter what m_iHUDWeaponSelected is exactly, - // just 0 or non-zero has significance in it. + // Just for nuclide, doesn't matter what m_iHUDWeaponSelected is exactly, + // just 0 or non-zero has significance in it for denying game-related inputs + // in Nuclide, which is all we need. pSeat->m_iHUDWeaponSelected = (pl.weaponSelectHighlightID != -1); @@ -123,21 +122,11 @@ HUD_Draw(void) pSeat->m_iHUDWeaponSelected = 0; - // is this necessary? With or without the if-then too. - /* - if(g_vguiWidgetCount > 0){ - GameClient_SpectatorInputRaw(); - } - */ - drawTimer(); - //TAGGG - Moved over! Is it wise for this to go here? // Links to drawing the MoTD and buymenu when appropriate - //TAGGG - CRITICAL. "self" is a spectator, not a player!! - // Send over the above "spec" instead too! - CSQC_VGUI_Draw(pl); + UI_Draw(pl); }// pl.iState check diff --git a/src/client/init.qc b/src/client/init.qc index 57ed5cc..b814b71 100644 --- a/src/client/init.qc +++ b/src/client/init.qc @@ -104,7 +104,7 @@ ClientGame_Init(float apilevel, string enginename, float engineversion) // using the new VGUI approach. // That also includes mentions of fonts in ts/src/client/vgui.qc - // Also see ts/src/client/vgui.qc where CSQC_VGUI_Draw checks to see if the screen + // Also see ts/src/client/vgui.qc where UI_Draw checks to see if the screen // size has been changed or this is the first time drawing (some FONTs having ID -1). // In either case, they're loaded and sized per screen height over there. FONT_ARIAL = -1; //specify me at draw startup instead, if this is safe. @@ -136,7 +136,7 @@ ClientGame_Init(float apilevel, string enginename, float engineversion) drawfont = FONT_CON; ////////////////////////////////////////////////////////////////// - CSQC_VGUI_Init(); + UI_Init(); } diff --git a/src/client/input.h b/src/client/input.h deleted file mode 100644 index 1ac2836..0000000 --- a/src/client/input.h +++ /dev/null @@ -1,4 +0,0 @@ - - -void GameClient_SpectatorInputRaw(void) -void GameClient_PlayerInputRaw(void); \ No newline at end of file diff --git a/src/client/input.qc b/src/client/input.qc deleted file mode 100644 index 7a9a525..0000000 --- a/src/client/input.qc +++ /dev/null @@ -1,204 +0,0 @@ - -// NEW FILE. - -// RECENT: This file is pending deletion, if the "GamePlayerSpawn" message call in -// ts/src/shared/input.qc is good enough. -// That would mean GameClient_SpectatorInputRaw, nor any pSeatLocal vars only it uses, -// would no longer be necessary. -// Just want to be sure first with some more tests, no getting locked out of spawning. -// GameClient_PlayerInputRaw is tiny and hud.qc can do what it does instead. - -// The "DISABLED" area further down is worth seeing if supporting right click to close -// an open weapon select immediately without applying any selection is a good idea though. - - // ----------------------------- - - - -// WARNING: Do not get this file mixed up with /src/shared/input.qc, that one is -// only called when the player is spawned (collision, seen by others, etc.). -// This is for checking to see if the user performed some action that does not need -// to be checked by the server, such as INPUT_BUTTON0 (primary fire) while not in any -// VGUI choice (blank screen) to send a message to the server to swawn the player. -// This is reached through draw-calls (root of the calls is method CSQC_UpdateView). -// It works. - -// ALSO, this is called continually to check for user-provided input, it is not only -// called when user input is detected. Be aware of that. - - -// Also, this version is for while in spectator. See further down for the "for-player" -// version. -void -GameClient_SpectatorInputRaw(void) -{ - // If in spectator with nothing open (no MoTD, no buyside menu), - // go ahead and spawn ingame. - - if(pSeatLocal->fVGUI_Display == VGUI_SCREEN::NONE && pSeatLocal->m_flPrevVGUI != VGUI_SCREEN::NONE){ - // Current display is NONE, yet the previous wasn't (Recent change to NONE)? - // Set that. - pSeatLocal->m_bNeedPrimaryRelease = TRUE; - pSeatLocal->m_flReleaseTime = time + 0.15f; - } - - pSeatLocal->m_flPrevVGUI = pSeatLocal->fVGUI_Display; - - // OKAY. So little issue. - // Modern Nuclide does not offer a way to read "input_buttons" in the usual places - // (CSQC_Input_Frame), can they be re-gathered? - - // COPIED FROM src/client/predict.qc, for scraping through - // all queued input frames for sending (or not yet verified to have - // been received by the server. I think?). - // Or use the one at clientcommandframe only. Hmm. - - // quote from fteextensions.qc: - // The sequence number range used for prediction should normally be - // servercommandframe < sequence <= clientcommandframe. - - //printf("WHAT are the client/server comm frames? %d %d\n", clientcommandframe, servercommandframe); - //for (int i = pl.sequence + 1; i <= clientcommandframe; i++) { - - /* - bool wasButtonPushedThisFrame = FALSE; - for (int i = servercommandframe+1; i <= clientcommandframe; i++) { - float flSuccess = getinputstate(i); - if (flSuccess == FALSE) { - continue; - } - - //if (i==clientcommandframe){ - // CSQC_Input_Frame(); - //} - - if (input_timelength == 0) { - break; - } - - if((input_buttons & INPUT_BUTTON0) != 0){ - //printfline("IM here man %d\n", (input_buttons & INPUT_BUTTON0) != 0); - // any frame says I got pushed? Treat it as such. - wasButtonPushedThisFrame = TRUE; - } - - //input_sequence = i; - } - */ - - float flSuccess = getinputstate(clientcommandframe); - if (flSuccess) { - //printf("BUT HOW? %d - %d\n", (pSeatLocal->m_bNeedPrimaryRelease), (( input_buttons & INPUT_BUTTON0)!=0) ); - - // IDEA: could we just do this? - /* - if(pSeatLocal->m_bNeedPrimaryRelease){ - if(!wasButtonPushedThisFrame)){ - pSeatLocal->m_bNeedPrimaryRelease = FALSE; - } - } - */ - // INSTEAD OF THIS - /////////////////////////////////////////////////////// - if(pSeatLocal->m_bNeedPrimaryRelease){ - // yay. - if(!(input_buttons & INPUT_BUTTON0)){ - // not pushed? Check it - if(time >= pSeatLocal->m_flReleaseTime){ - // okay! Not touched for enough time. - pSeatLocal->m_bNeedPrimaryRelease = FALSE; - } - }else{ - // Touched? Oh. - pSeatLocal->m_flReleaseTime = time + 0.15f; - } - } - /////////////////////////////////////////////////////// - - player pl = (player)pSeat->m_ePlayer; - - // primary fire? - if(!pSeatLocal->m_bNeedPrimaryRelease && (input_buttons & INPUT_BUTTON0) ){ - - if( - pSeatLocal->fVGUI_Display == VGUI_SCREEN::NONE && - //getplayerkeyvalue(player_localnum, "*spec") != "0" - pl.iState != PLAYER_STATE::SPAWNED - ){ - // && getstati(STAT_RULE_ALLOW_SPAWN)) - // just send the intention we want to spawn, the server will see if a delay is needed. - // And only work if we're not in some other screen AND not spawned. Clicking to spawn while ingame (die) would be irritating. - - // Check is no longer needed, only the spectator would have reached this method to begin with. - //if( stof(getplayerkeyvalue(player_localnum, "*team")) == TEAM_SPECTATOR) - - //TAGGG - TODO - should some minimum cooldown before respawning be enforced, - // and the countdown shows up if the user clicks too soon since a respawn? - // Print this if the client suspects that will be the case, or let spawn-delay - // be some serverstat that is known here at all times. - //CSQC_Parse_CenterPrint("Spawning soon...\n"); - - sendevent( "GamePlayerSpawn", ""); - - VGUI_ChangeScreen(VGUI_SCREEN::NONE); - - // probably unnecessary? - EV_TS_resetViewModel(); - - } - } - } - -}//GameClient_SpectatorInputRaw - - -// While a player. -void -GameClient_PlayerInputRaw(void) -{ - player pl = (player)pSeat->m_ePlayer; - // weapon select extra. - if(pl == NULL){ - return; - } - - // This was removed? Legacy VGUI - // If we are inside a VGUI, don't let the client do stuff outside - if (pl.iState != PLAYER_STATE::SPAWNED && pSeatLocal->fVGUI_Display != VGUI_SCREEN::NONE){ - pSeat->m_flInputBlockTime = time + 0.2; - } - - - // No need to check for calling TS_HUD_DrawWeaponSelect_CheckClick or - // HUD_DrawWeaponSelect_Trigger here, Nuclide calls the latter which works - // fine. - - - // CRITICAL. - // DISABLED. - // This is trying to close weaponselect on detecting a right-click, but it - // has issues. - // Idea is, this needs to *absorb* the right-click, and stop it from reaching - // the rest of the client and server to work with weapons, like a change-ironsight - // order. - // This might stop the client weapon logic from seeing the right click, but not - // the server. - // It appears there is no way to stop that without the FTE built-in event method - // CSQC_Input_Frame (defined by Nuclide) letting the gamemod block right-click - // inputs per some condition, like weapon-select being up. - /* - if(pSeat->m_iInputAttack2){ //input_buttons & INPUT_BUTTON3){ - if(HUD_CloseWeaponSelect(TRUE)){ - pSeat->m_flInputBlockTime = time + 0.2; - input_impulse = 0; - input_buttons = 0; - pSeat->m_iInputAttack2 = FALSE; - }else{ - //pSeat->m_iInputAttack2 = TRUE; - } - } - */ - -}//GameClient_PlayerInputRaw - - diff --git a/src/client/progs.src b/src/client/progs.src index 8de1734..b4fe659 100644 --- a/src/client/progs.src +++ b/src/client/progs.src @@ -32,13 +32,12 @@ defs.h clientinfo.h seatlocal.h -input.h //TAGGG - NEW precache.h -vgui.h +ui.h ui_eventgrabber.h -vgui_buysidemenu.h +ui_buymenu.h hud_weaponselect.h inventory_logic_draw.h view.h @@ -59,12 +58,10 @@ hud.h ../shared/inventory_logic.qc //TAGGG - NEW -input.qc vguiobjects.qc vgui_motd.qc -vgui_buysidemenu.qc -//vgui_spectator.c ???? -vgui.qc +ui_buymenu.qc +ui.qc hud_crosshair.qc hud_scope.qc diff --git a/src/client/seatlocal.h b/src/client/seatlocal.h index 99e9d35..95279dd 100644 --- a/src/client/seatlocal.h +++ b/src/client/seatlocal.h @@ -23,16 +23,13 @@ struct int m_iHUDWeaponSelected; float m_flHUDWeaponSelectTime; - float m_flPrevVGUI; - BOOL m_bNeedPrimaryRelease; - float m_flReleaseTime; //TAGGG - assuming this is a fine place to put this // It's the slower movement from holding shift down. - int iInputSpeed; + int m_iInputSpeed; // Keeping for now, remove later - float fVGUI_Display; + float m_flUI_Display; // CRITICAL: // Should these be per pSeat instead? Unsure if that makes sense. diff --git a/src/client/seatlocal.qc b/src/client/seatlocal.qc index 2485b86..4310cce 100644 --- a/src/client/seatlocal.qc +++ b/src/client/seatlocal.qc @@ -5,9 +5,8 @@ void pSeatLocal_init(void) { - pSeatLocal->m_flPrevVGUI = VGUI_SCREEN::NONE; - pSeatLocal->m_bNeedPrimaryRelease = FALSE; - pSeatLocal->m_flReleaseTime = 0; + pSeatLocal->m_flUI_Display = UI_SCREEN::NONE; + pSeatLocal->m_inputKeyTapped = 0; pSeatLocal->m_inputKeyDown = 0; diff --git a/src/client/vgui.h b/src/client/ui.h similarity index 84% rename from src/client/vgui.h rename to src/client/ui.h index bca313c..3045d1f 100644 --- a/src/client/vgui.h +++ b/src/client/ui.h @@ -1,47 +1,47 @@ - - -#define VGUI_WINDOW_BGCOLOR '0.0 0.0 0.0' -#define VGUI_WINDOW_FGCOLOR '1.0 0.5 0.0' -#define VGUI_WINDOW_BGALPHA 0.76 -#define VGUI_WINDOW_FGALPHA 1.0 - -vector vVGUIWindowPos; -vector vVGUIWindowSiz; - -string sMOTDString[25]; -string sMapString[35]; - -var string sMOTD_total; - -class player; - - -// Keep in synch with the vguiMenus array of vgui.c -enum VGUI_SCREEN{ - NONE = 0, - MOTD, - BUYSIDEMENU -}; - -typedef struct { - string sTitle; - // Whether to do a VGUI_Window call to draw a window. - // Not very customizable for now, intended only for the MoTD, but adapts to different screen sizes. - // Could have other settings added later, or even be handled per screen's draw call too for completely re-doing - BOOLEAN fDrawMainWindowAuto; - - // Custom draw script for a particular screen choice - //TAGGG - now accepts how much to change the font size (and adjust other things) by. - // Also accepts the player for getting other info from. - void(player arg_player, vector vPos, vector vWindowSiz, float fFontSizeMulti ) vDraw; - // What to do the moment the screen is changed to this. - void(void) vOnInit; -} vguiwindow_t; - - - -void CSQC_VGUI_Init(void); -float CSQC_VGUI_Draw( player arg_player); -void VGUI_ChangeScreen(VGUI_SCREEN fNewScreenID); - - + + +#define VGUI_WINDOW_BGCOLOR '0.0 0.0 0.0' +#define VGUI_WINDOW_FGCOLOR '1.0 0.5 0.0' +#define VGUI_WINDOW_BGALPHA 0.76 +#define VGUI_WINDOW_FGALPHA 1.0 + +vector vVGUIWindowPos; +vector vVGUIWindowSiz; + +string sMOTDString[25]; +string sMapString[35]; + +var string sMOTD_total; + +class player; + + +// Keep in synch with the vguiMenus array of vgui.c +enum UI_SCREEN{ + NONE = 0, + MOTD, + BUYMENU +}; + +typedef struct { + string sTitle; + // Whether to do a VGUI_Window call to draw a window. + // Not very customizable for now, intended only for the MoTD, but adapts to different screen sizes. + // Could have other settings added later, or even be handled per screen's draw call too for completely re-doing + BOOLEAN fDrawMainWindowAuto; + + // Custom draw script for a particular screen choice + //TAGGG - now accepts how much to change the font size (and adjust other things) by. + // Also accepts the player for getting other info from. + void(player arg_player, vector vPos, vector vWindowSiz, float fFontSizeMulti ) vDraw; + // What to do the moment the screen is changed to this. + void(void) vOnInit; +} vguiwindow_t; + + + +void UI_Init(void); +float UI_Draw( player arg_player); +void UI_ChangeScreen(UI_SCREEN fNewScreenID); + + diff --git a/src/client/vgui.qc b/src/client/ui.qc similarity index 90% rename from src/client/vgui.qc rename to src/client/ui.qc index 2456ab3..b6fef21 100644 --- a/src/client/vgui.qc +++ b/src/client/ui.qc @@ -26,25 +26,25 @@ // be set in an init method instead. -// Keep in synch with vgui.h's VGUI_SCREEN enum choices, besides the NONE choice. +// Keep in synch with vgui.h's UI_SCREEN enum choices, besides the NONE choice. // That isn't represented, not even by a dummy. var vguiwindow_t vguiMenus[] = { //{ _("VGUI_TITLE_MOTD"), VGUI_MessageOfTheDay }, { "", TRUE, VGUI_MessageOfTheDay, NULL }, - { "", FALSE, VGUI_BuySideMenu_Update, VGUI_BuySideMenu_OnInit} + { "", FALSE, UI_BuyMenu_Update, UI_BuyMenu_OnInit} }; //var float nextPrintoutTime = -1; void -VGUI_ChangeScreen(VGUI_SCREEN arg_NewScreenID) +UI_ChangeScreen(UI_SCREEN arg_NewScreenID) { - pSeatLocal->fVGUI_Display = (float)arg_NewScreenID; + pSeatLocal->m_flUI_Display = (float)arg_NewScreenID; - printfline("VGUI_ChangeScreen:: arg_NewScreenID? %d", arg_NewScreenID); + printfline("UI_ChangeScreen:: arg_NewScreenID? %d", arg_NewScreenID); - if(arg_NewScreenID <= VGUI_SCREEN::NONE){ + if(arg_NewScreenID <= UI_SCREEN::NONE){ // If at NONE or below, also do nothing. This has no "vOnInit" behavior. // Besides obligatory cleanup if we choose (which may as well be done right here) // And turn the cursor lock off. @@ -75,16 +75,16 @@ VGUI_ChangeScreen(VGUI_SCREEN arg_NewScreenID) /* ================= -CSQC_VGUI_Draw +UI_Draw This is the entry point for FreeTS's (cloned from FreeCS) own "VGUI" implementation Run every frame ================= */ float -CSQC_VGUI_Draw( player arg_player) +UI_Draw(player arg_player) { - if ( pSeatLocal->fVGUI_Display == VGUI_SCREEN::NONE ) { + if ( pSeatLocal->m_flUI_Display == UI_SCREEN::NONE ) { setcursormode( FALSE ); return FALSE; } @@ -160,19 +160,19 @@ CSQC_VGUI_Draw( player arg_player) vVGUIWindowSiz[1] = window_height_y; // draw the window only if this screen says to. - if(vguiMenus[ pSeatLocal->fVGUI_Display - 1 ].fDrawMainWindowAuto){ - VGUI_Window( vVGUIWindowPos, vVGUIWindowSiz, vguiMenus[ pSeatLocal->fVGUI_Display - 1 ].sTitle, [fontSizeMulti*32,fontSizeMulti*32] ); + if(vguiMenus[ pSeatLocal->m_flUI_Display - 1 ].fDrawMainWindowAuto){ + VGUI_Window( vVGUIWindowPos, vVGUIWindowSiz, vguiMenus[ pSeatLocal->m_flUI_Display - 1 ].sTitle, [fontSizeMulti*32,fontSizeMulti*32] ); } // Display the contents of whatever we have selected - vguiMenus[ pSeatLocal->fVGUI_Display - 1 ].vDraw( arg_player, vVGUIWindowPos, vVGUIWindowSiz, fontSizeMulti ); + vguiMenus[ pSeatLocal->m_flUI_Display - 1 ].vDraw( arg_player, vVGUIWindowPos, vVGUIWindowSiz, fontSizeMulti ); return TRUE; } /* ================= -CSQC_VGUI_Init +UI_Init Initialize all there is ================= @@ -181,7 +181,7 @@ Initialize all there is // ALSO - this means once for the entire client, so handle all pSeat choices // individually as it does. void -CSQC_VGUI_Init(void) +UI_Init(void) { string sTemp; int iMOTDLength; @@ -238,14 +238,14 @@ CSQC_VGUI_Init(void) for (s = 0; s < g_seats.length; s++){ pSeat = &g_seats[s]; pSeatLocal = &g_seatslocal[s]; - VGUI_ChangeScreen(VGUI_SCREEN::MOTD); + 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]; - VGUI_ChangeScreen(VGUI_SCREEN::NONE); + UI_ChangeScreen(UI_SCREEN::NONE); } } } diff --git a/src/client/ui_buymenu.h b/src/client/ui_buymenu.h new file mode 100644 index 0000000..c2d2207 --- /dev/null +++ b/src/client/ui_buymenu.h @@ -0,0 +1,3 @@ + +extern var BOOL UI_BuyMenu_InitDone; +void UI_BuyMenu_onInputEvent(void); diff --git a/src/client/vgui_buysidemenu.qc b/src/client/ui_buymenu.qc similarity index 69% rename from src/client/vgui_buysidemenu.qc rename to src/client/ui_buymenu.qc index 688c3af..5d594e8 100644 --- a/src/client/vgui_buysidemenu.qc +++ b/src/client/ui_buymenu.qc @@ -1,1596 +1,1596 @@ -/*** -* -* Copyright (c) 2016-2019 Marco 'eukara' Hladik. All rights reserved. -* -* See the file LICENSE attached with the sources for usage details. -* -****/ - -#define LABEL_OFFSET_X 1 -#define LABEL_OFFSET_Y 3 - -#define BUTTON_TYPEID_BASIC 0 -#define BUTTON_TYPEID_WEAPON 1 - - - - -#define INITIALIZE_BASICBUTTON(arg_varName, arg_sName, arg_sHotkeyDisplay, arg_clr, arg_vOnClick_Custom) buysidemenu_btn_##arg_varName = spawn(CBuySideMenu_BasicButton);\ - flDeterminedHotkey = determineHotkeyFromChar(arg_sHotkeyDisplay);\ - buysidemenu_btn_##arg_varName.setThisPointer(&buysidemenu_btn_##arg_varName);\ - buysidemenu_btn_##arg_varName.create(sprintf("%s %s", arg_sHotkeyDisplay, arg_sName), flDeterminedHotkey, arg_clr, arg_vOnClick_Custom);\ - buysidemenu_addbuttonToTotal(&buysidemenu_btn_##arg_varName); - - -#define INITIALIZE_WEAPONBUTTON(arg_varName, arg_sHotkeyDisplay, arg_clr, arg_vOnClick_Custom, arg_parentName) buysidemenu_btn_Buy_##arg_varName = spawn(CBuySideMenu_WeaponButton);\ - flDeterminedHotkey = determineHotkeyFromChar(arg_sHotkeyDisplay);\ - buysidemenu_btn_Buy_##arg_varName.setThisPointer(&buysidemenu_btn_Buy_##arg_varName);\ - tempWeapRef = *ary_weaponData[WEAPON_ID::##arg_varName];\ - buysidemenu_btn_Buy_##arg_varName.create_WeaponButton(sprintf("%s %s", arg_sHotkeyDisplay, tempWeapRef.sDisplayName), flDeterminedHotkey, arg_clr, arg_vOnClick_Custom, tempWeapRef.sIconFilePath, tempWeapRef.iPrice, tempWeapRef.iSlots, tempWeapRef.iBitsUpgrade & ~tempWeapRef.iBitsUpgradeAuto);\ - buysidemenu_addbuttonToTotal(&buysidemenu_btn_Buy_##arg_varName);\ - buysidemenu_btn_Buy_##arg_varName.iWeaponPurchaseID = WEAPON_ID::##arg_varName;\ - buysidemenu_addbutton(&buysidemenu_btn_Buy_##arg_parentName, &buysidemenu_btn_Buy_##arg_varName); - - - -// prototype'd class -class CBuySideMenu_BasicButton; - - -// set to TRUE if this screen has ever been brought up before. -var BOOL VGUI_BuySideMenu_InitDone = FALSE; - -var int iWeaponTempID = -1; - -//What upgrades has the player purchased for the currently open weapon in the buy menu? -var int iBitsUpgradeTemp = BITS_WEAPONOPT_NONE; -//How much does the weapon's upgrades (does not consider ammo if necessary) cost? -var int iExtraPriceTemp = 0; -var int iExtraSlotsTemp = 0; -var int iPurchaseCountTemp = 1; - -var int iHoveredButtonIndex = -1; -var int iActiveLayer = 0; - - -class CBuySideMenu_BasicButton; -class CBuySideMenu_WeaponButton; -class CBuySideMenu_WeaponButton; -class CBuySideMenu_RemoveWeaponButton; - -void buysidemenu_cancelConfigAndClose(void); -void refreshButtons(void); -void setupRemoveButtonList(void); -void buysidemenu_btn_removeButton_clicked(CBuySideMenu_BasicButton* arg_this); -void buysidemenu_btn_RemoveItem_clicked(CBuySideMenu_BasicButton* arg_this); - - -void buysidemenu_backOneLayer(void); -void buysidemenu_btn_Back_updateText(void); -void buysidemenu_btn_Back_clicked(CBuySideMenu_BasicButton* arg_this); - -void(CBuySideMenu_BasicButton* arg_someButton) setActiveLayerButton; - -float determineHotkeyFromChar(string arg_sHotkeyDisplay); - - - -//Each button ever created must be added to this list. Can be one automatically... -//struct's don't have constructors though. Call for this at startup I suppose. -var CBuySideMenu_BasicButton* ary_btnTotal[128]; -var int ary_btnTotal_softLength = 0; - -var CBuySideMenu_BasicButton* ary_layerButtonChoice[16]; //16 layers max. Not that nearly this many should be used. -//var int ary_layerButtonChoiceIndex[16i]; //alternative approach. - -//Any buttons in the first layer must be recorded here. -var CBuySideMenu_BasicButton* ary_layerFirstButton[16]; -var int ary_layerFirstButton_softLength = 0; - - -// One button expected for each weapon in ary_myWeapons of the tempconfig at most. -// (so up to "ary_myWeapons_length" in count). -CBuySideMenu_RemoveWeaponButton ary_btn_removeButton[ary_myWeapons_length]; - - - -var CBuySideMenu_BasicButton buysidemenu_btn_WeaponOpt_Buy; -var CBuySideMenu_BasicButton buysidemenu_btn_WeaponOpt_Silencer; -var CBuySideMenu_BasicButton buysidemenu_btn_WeaponOpt_Lasersight; -var CBuySideMenu_BasicButton buysidemenu_btn_WeaponOpt_Flashlight; -var CBuySideMenu_BasicButton buysidemenu_btn_WeaponOpt_Scope; -var CBuySideMenu_BasicButton buysidemenu_btn_WeaponOpt_Akimbo; -var CBuySideMenu_BasicButton buysidemenu_btn_WeaponOpt_FullLoad; - - - - -// SPECIAL BUTTON - draw this wherever appropriate for the active layer. Its text is also different -// if the 1st layer is active (drawn to that one). Says "Cancel" there, but if on any deeper layer it reads "Go Back". -var CBuySideMenu_BasicButton buysidemenu_btn_Back; -// var CBuySideMenu_BasicButton buysidemenu_btn_Back = {0, "0 Cancel", 0,0, 48, NULL, {}, 0, NULL}; - -var CBuySideMenu_BasicButton buysidemenu_btn_Recentconfig; -var CBuySideMenu_BasicButton buysidemenu_btn_Buy; -var CBuySideMenu_BasicButton buysidemenu_btn_RemoveItem; -var CBuySideMenu_BasicButton buysidemenu_btn_ResetConfig; -var CBuySideMenu_BasicButton buysidemenu_btn_SaveConfig; -var CBuySideMenu_BasicButton buysidemenu_btn_LoadConfig; -var CBuySideMenu_BasicButton buysidemenu_btn_BuyRandom; - -var CBuySideMenu_BasicButton buysidemenu_btn_Buy_Handguns; -var CBuySideMenu_BasicButton buysidemenu_btn_Buy_SMGs; -var CBuySideMenu_BasicButton buysidemenu_btn_Buy_Rifles; -var CBuySideMenu_BasicButton buysidemenu_btn_Buy_Shotguns; -var CBuySideMenu_BasicButton buysidemenu_btn_Buy_SpecialPurpose; - -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_GLOCK18; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_SOCOMMK23; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_DESERTEAGLE; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_FIVESEVEN; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_BERETTA; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_AKIMBOCOLTS; - -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_GLOCK20; - -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_RUGERMK1; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_RAGINGBULL; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_CONTENDERG2; - - -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_MINIUZI; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_MP5SD; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_MP5K; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_STEYRTMP; - -// called the MP7PDW ingame? ts_fgd refers to it as "HK Pdw" though -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_HKPDW; - -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_MAC10; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_UMP; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_SKORPION; - -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_M4A1; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_AK47; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_STEYRAUG; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_M16A4; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_BARRETTM82; - -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_BENELLIM3; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_USAS12; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_SPAS12; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_MOSSBERG500; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_SAWEDOFF; - -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_M61GRENADE; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_COMBATKNIFE; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_M60; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_KATANA; -var CBuySideMenu_WeaponButton buysidemenu_btn_Buy_SEALKNIFE; - - - - -// Notice that the buttons do not have location/size information. They are -// drawn wherever as needed, checks for clicks need that supplied to know where -// to check. -class CBuySideMenu_BasicButton{ - - // yes. really. - CBuySideMenu_BasicButton* _this; - - int iType; // is this a BasicButton or a WeaponButton? - BOOL bActive; // Effectively hides this from all logic. As in, don't skip the space this would occupy. Pretend like this button didn't exit. - // Refreshed at a new layer / going back one. - - int iGlobalIndex; - string sName; - - // -1 is the signal for "no hotkey". Numbers actually start at 48 for 0 (49 for 1... or 48+1 for clarity). - float flHotkey; - - vector clr; // stored; natural color. - vector clr_render; // for actual use. - - // Array of buttons that are shown when I'm clicked on. Many buttons use this. - // The "0 Cancel" back button will be drawn if applicaple (for the active (deepest layer open) if it's not the first layer). - // struct CBuySideMenu_BasicButton* ary_btn[16i]; - int ary_btn_index[16]; - int ary_btn_softLength; - - - // Special behavior for this button (optional). Good for buttons that will interact - // with something in the game like adding a weapon or adding an accessory (Silencer) to an existing one. - - //virtual void(CBuySideMenu_BasicButton* arg_this) vOnClick_Custom = NULL; - int* vOnClick_Custom; - //virtual void(CBuySideMenu_BasicButton* arg_this) vOnShow_Custom = NULL; - int* vOnShow_Custom; - - void(void) CBuySideMenu_BasicButton; - - virtual void(CBuySideMenu_BasicButton* arg_this) setThisPointer; - - virtual void(string arg_sName, float arg_flHotkey, vector arg_clr, void(CBuySideMenu_BasicButton* arg_this)* arg_vOnClick_Custom ) create; - - virtual void(vector arg_suggestedDrawPos, int arg_iLayer, int arg_iButtonRow, BOOL arg_fIsSelected) vOnRender_Base; - virtual void(void) vOnClick_Base; - - - virtual void(void) vOnShow_Base; - - // This is set separately from any "create" methods or constructors since it is rarely used. - // If set, this method will run anytime this button is shown. This lets it do a quick calculation - // to see if the player can afford an upgrade as it is displayed. - - -}; - - -class CBuySideMenu_WeaponButton : CBuySideMenu_BasicButton{ - - // What weapon (by ID) will I purchase (or try to) when bought? - // Parameter limit used up - have to set this separtely. Ugh. - // We're remaking buttons to use structs instead of classes later so this isn't too - // bad of a patch for now. - int iWeaponPurchaseID; - - string sWeaponImagePath; - int iWeaponPrice; - int iWeaponSlots; - int iBitsWeaponOpt; //Can the player buy... a scope? lazer sight? flash light? akimbo? etc. - - - void(void) CBuySideMenu_WeaponButton; - - // after arg_clr: int arg_ary_btn_index[16] - virtual void(string arg_sName, float arg_flHotkey, vector arg_clr, void(CBuySideMenu_BasicButton* arg_this)* arg_vOnClick_Custom, string arg_sWeaponImagePath, int arg_iWeaponPrice, int arg_iWeaponSlots, int arg_iBitsWeaponOpt ) create_WeaponButton; - - virtual void(vector arg_suggestedDrawPos, int arg_iLayer, int arg_iButtonRow, BOOL arg_fIsSelected) vOnRender_Base; - virtual void(void) vOnClick_Base; - - - virtual void(void) vOnShow_Base; - //virtual void(CBuySideMenu_BasicButton* arg_this) vOnShow_Custom = NULL; - -}; - - -// Very slightly modified form of CBuySideMenu_BasicButton that just includes -// an extra var for storing what part of the config to remove if clicked on. -// As in, the 3rd button will remove the 2nd index (...ary_myWeapons[2]) from the player's -// temp config. -class CBuySideMenu_RemoveWeaponButton : CBuySideMenu_BasicButton{ - // What element of the config do I remove if I am picked? - int linkedConfigIndex; - - void(void) CBuySideMenu_RemoveWeaponButton; -}; - - -void -CBuySideMenu_RemoveWeaponButton::CBuySideMenu_RemoveWeaponButton(void) -{ - -} - - -BOOL -checkBuySideMenuButtonClicked( - CBuySideMenu_BasicButton* arg_someBtn, vector vPosition, - vector vSize -) -{ - CBuySideMenu_BasicButton deref = *arg_someBtn; - - // Check for the button's hotkey. - if(deref.flHotkey != -1 && pSeatLocal->m_inputKeyDown == deref.flHotkey){ - (*arg_someBtn).vOnClick_Base(); - pSeatLocal->m_inputKeyDown = 0; - return TRUE; - } - - if ( pSeatLocal->m_inputMouseClicked == TRUE ) { - if(VGUI_CheckMouse( vPosition, vSize )){ - // What button is being hovered over? - iHoveredButtonIndex = deref.iGlobalIndex; - - (*arg_someBtn).vOnClick_Base(); - - pSeatLocal->m_inputMouseClicked = FALSE; - return TRUE; - } - } - - return FALSE; -}// checkBuySideMenuButtonClicked - - - -// Called by ui_eventgrabber on detecting input from a keypress or mouse. -// TODO - still a little sloppy to check for both the recently pressed key -// matching the hotkey and a mouse-click for coords when each event can only be -// either of these things, not both. -// But that would mean cloning this method with the only difference being -// checkBuySideMenuButtonClicked for "checkBuySideMenuButtonHotKey" insetad, -// and Clicked loses the hotkey check. -void BuySideMenu_onInputEvent(void){ - if(!VGUI_BuySideMenu_InitDone){ - // Not allowed yet! - return; - } - - vector vButtonPos = [video_mins[0] + 5, video_mins[1] + video_res[1]/2, 0]; - vector vBtnPos = [0,0,0]; - int currentLayerSelectedIndex; - int btnToRender_index_global; - CBuySideMenu_BasicButton someThing; - CBuySideMenu_BasicButton previousLayerButton; - BOOL fIsSelected; - - if(iActiveLayer == 0){ - vBtnPos.x = (int)vButtonPos.x; //default pos. - vBtnPos.y = (int)vButtonPos.y; - - - for(int i2 = 0i; i2 < ary_layerFirstButton_softLength; i2++){ - CBuySideMenu_BasicButton tempButton = *ary_layerFirstButton[i2]; - - checkBuySideMenuButtonClicked(ary_layerFirstButton[i2], vBtnPos, vButtonSizStandard); - vBtnPos.y += (vButtonSizStandard.y + 1); - } - - }else{ - vBtnPos.x = (int)vButtonPos.x + (vButtonSizStandard.x + 1) * iActiveLayer; - vBtnPos.y = (int)vButtonPos.y; - // All other layers only render buttons that the previous layer (selected button there) tells them to. - - previousLayerButton = *ary_layerButtonChoice[iActiveLayer - 1i]; - - - for(int i2 = 0i; i2 < previousLayerButton.ary_btn_softLength; i2 = i2+1i){ - - // CONCLUSION... maybe. - // So much as this local var, "btnCheck", being set to a dereferenced ary_btnTotal element, - // and this btnCheck being used in checkBuySideMenubuttonClicked instead of just that ary_btnTotal element (a pointer already) - // is enough to trigger this odd error, where the next frame (or if this for loop gets so much as an extra iteration - // that resets btnCheck... test with the "if(theThingHappened)continue;" bit above moved to after these lines below too... - // Anyways, this makes the difference between whether the real thing the ary_btnTotal element links to stays - // consistent between at least loop iterations or not even those. Staying consistent between frames is definitely out. - // When this method ends, or really this scope (?), that thing the ary_btnTotal element is pointing at blanks out. - - btnToRender_index_global = previousLayerButton.ary_btn_index[i2]; - - CBuySideMenu_BasicButton tempButton2 = *ary_btnTotal[btnToRender_index_global]; - if(tempButton2.bActive == FALSE){ - // let the next button be tried instead. - continue; - } - - // NOT THIS WAY (causes the odd problem): - //if(checkBuySideMenuButtonClicked(&btnCheck, vBtnPos, vButtonSizStandard)){ - if(checkBuySideMenuButtonClicked(ary_btnTotal[btnToRender_index_global], vBtnPos, vButtonSizStandard)){ - // nothing special happens if so, checkBuySideMenuButtonClicked handles this fine. - } - - vBtnPos.y += (vButtonSizStandard.y + 1); - }// for i2 in this layer's buttons. - } - - // Check the "0. Cancel" button. - checkBuySideMenuButtonClicked(&buysidemenu_btn_Back, vBtnPos, vButtonSizStandard); - vBtnPos.y += (vButtonSizStandard.y + 1); -}// BuySideMenu_onInputEvent - - - -// For "_this" button, add "arg_other" to its list of buttons (ary_btn) to be shown when this button -// is clicked. -// Also, so much as adding a button to another's list will bump the other button's "iLayer" by 1 -// past the button it's being linked to. -// So NEVER add one button to two different layers, or at least set the layer manually to be correct -// (and match between the two parents, which should be parentButton+1). -// "iLayer" will be handled naturally just fine otherwise. -void -buysidemenu_addbutton(CBuySideMenu_BasicButton* _this, CBuySideMenu_BasicButton* arg_other) -{ - - CBuySideMenu_BasicButton _this_deref = *_this; - CBuySideMenu_BasicButton arg_other_deref = *arg_other; - - if(_this_deref.ary_btn_softLength < 16i){ - //proceed. - int nextButtonSlot = _this_deref.ary_btn_softLength; - - //I am the number "i" child of the parent. Useful for telling what button from the previous layer - //was selected. - - //_this.ary_btn[nextButtonSlot] = arg_other; - _this_deref.ary_btn_index[nextButtonSlot] = arg_other_deref.iGlobalIndex; - - _this_deref.ary_btn_softLength += 1i; //increase the number of buttons I link to by 1. - // arg_other_deref.iLayer = _this_deref.iLayer + 1i; //This "other" button is one layer deeper - // than the parent. - - } - -}//buysidemenu_addbutton - - - -void -buysidemenu_addbuttonToTotal(CBuySideMenu_BasicButton* _this) -{ - - if(ary_btnTotal_softLength >= ary_btnTotal.length){ - //ERROR! - print(sprintf("!!! CLIENT ERROR. Button max of %i reached, button not added! Report this!\n", ary_btnTotal.length) ); - return; - } - - CBuySideMenu_BasicButton _this_deref = *_this; - - //localcmd(sprintf("echo addButtonToTotal: IM %s AND MY ID IS %i\n", _this.sName, ary_btnTotal_softLength)); - - _this_deref.iGlobalIndex = ary_btnTotal_softLength; - ary_btnTotal[ary_btnTotal_softLength] = _this; - ary_btnTotal_softLength = ary_btnTotal_softLength + 1i; - -}//buysidemenu_addbutton - -void -buysidemenu_addbuttonToFirstLayer(CBuySideMenu_BasicButton* _this) -{ - - if(ary_layerFirstButton_softLength >= ary_layerFirstButton.length){ - //ERROR! - print(sprintf("!!! CLIENT ERROR. First layer button max of %i reached, button not added! Report this!\n", ary_layerFirstButton.length) ); - return; - } - - ary_layerFirstButton[ary_layerFirstButton_softLength] = _this; - ary_layerFirstButton_softLength = ary_layerFirstButton_softLength + 1i; - -}//buysidemenu_addbuttonToFirstLayer - - - -//!!! SEND THE iGlobalIndex. -// Method that actually draws the button. -// Made separate from button's onRender methods so that this can be called with a different color conveniently -// (red for "can't afford this" at a glance) -void -drawBuyButton( - int arg_iGlobalIndex, string arg_text, vector arg_suggestedDrawPos, int arg_iLayer, - int arg_iButtonRow, BOOL arg_fIsSelected, vector arg_clr -) -{ - vector arg_buttonPos = arg_suggestedDrawPos; - - float arg_opac; - if(arg_fIsSelected || arg_iLayer == iActiveLayer){ - arg_opac = 0.96; - }else{ - arg_opac = 0.71; - } - - vector vLabelPos; - BOOL mouseHovered = FALSE; - - // Draw the button label - vLabelPos[0] = arg_buttonPos[0] + LABEL_OFFSET_X; - vLabelPos[1] = arg_buttonPos[1] + LABEL_OFFSET_Y; - - if(arg_iGlobalIndex == iHoveredButtonIndex){ - //This button is the chosen one!!! - mouseHovered = TRUE; - } - - /* - // NO BORDERS FOR THE WICKED. - // last two parameters were these constants before: vVGUIColor, VGUI_WINDOW_FGALPHA - //Now the draw stuff. - drawfill( vPosition, [vSize[0], 1], '255 0 0', 1.0 ); - drawfill( [vPosition[0], vPosition[1] + vSize[1] - 1], [vSize[0], 1], '255 0 0', 1.0 ); - drawfill( vPosition, [1, vSize[1]], '255 0 0', 1.0 ); - drawfill( [vPosition[0] + vSize[0] - 1, vPosition[1]], [1, vSize[1]], '255 0 0', 1.0 ); - */ - - //iActiveLayer == iLayer && - if(mouseHovered){ - // Draw the background - drawfill( arg_buttonPos, vButtonSizStandard, arg_clr * 0.93f, arg_opac - 0.60f, DRAWFLAG_NORMAL ); - - Gfx_Text( vLabelPos, arg_text, vButtonFontSize, arg_clr * 0.98f, (1.0f-(1.0f - arg_opac)*0.88) - 0.02f, DRAWFLAG_NORMAL, FONT_ARIAL_STD ); - //return TRUE; - }else{ - // Draw the background - drawfill( arg_buttonPos, vButtonSizStandard, arg_clr * 0.86, arg_opac - 0.70f, DRAWFLAG_NORMAL ); - - Gfx_Text( vLabelPos, arg_text, vButtonFontSize, arg_clr * 0.94f, (1.0f-(1.0f - arg_opac)*0.88) - 0.06f, DRAWFLAG_NORMAL, FONT_ARIAL_STD ); - } - -}// drawBuyButton - - - -void -setActiveLayerButton(CBuySideMenu_BasicButton* arg_someButton) -{ - ary_layerButtonChoice[iActiveLayer] = arg_someButton; -} - -void -CBuySideMenu_BasicButton::CBuySideMenu_BasicButton(void) -{ - iType = BUTTON_TYPEID_BASIC; - bActive = TRUE; - vOnClick_Custom = NULL; - vOnShow_Custom = NULL; -} -void -CBuySideMenu_BasicButton::setThisPointer(CBuySideMenu_BasicButton* arg_this) -{ - _this = arg_this; -} -void -CBuySideMenu_BasicButton::create(string arg_sName, float arg_flHotkey, vector arg_clr, void(CBuySideMenu_BasicButton* arg_this)* arg_vOnClick_Custom ) -{ - sName = arg_sName; - - flHotkey = arg_flHotkey; - clr = arg_clr; - clr_render = arg_clr; //good default. - - vOnClick_Custom = arg_vOnClick_Custom; //(int*)&arg_vOnClick_Custom; - vOnShow_Custom = NULL; -}//create - - -void -CBuySideMenu_BasicButton::vOnRender_Base -( - vector arg_suggestedDrawPos, int arg_iLayer, int arg_iButtonRow, BOOL arg_fIsSelected -) -{ - drawBuyButton(this.iGlobalIndex, this.sName, arg_suggestedDrawPos, arg_iLayer, arg_iButtonRow, arg_fIsSelected, this.clr_render); -}//vOnRender_Base - - - -void -CBuySideMenu_BasicButton::vOnShow_Base(void) -{ - - if(vOnShow_Custom != NULL){ - void(CBuySideMenu_BasicButton* arg_this)* tempRef = vOnShow_Custom; - (*tempRef)(_this); - //vOnShow_Custom(_this); - } - -}// vOnShow_Base - - -// When this button is clicked, what does it do? -void -CBuySideMenu_BasicButton::vOnClick_Base(void) -{ - - // basic button behavior. Only if our array has a non-zero length. - // Buttons of zero length don't unwrap into new buttons and can do something special, - // like go up a layer instead ("cancel"), something about configs, or buy a - // weapon/accessory. - if( ary_btn_softLength != 0i){ - - // "this"... is not already a pointer??! WHAT HERESY BEFALLS MY EYES?!!! - // nah just kidding, makes sense for QuakeC. - // setActiveLayerButton(&this); - ary_layerButtonChoice[iActiveLayer] = _this; - - // "warning F307: type mismatch: CBuySideMenu_BasicButton * _this to - // CBuySideMenu_BasicButton *[ary_layerButtonChoice]" - // ...????? happens if using CBuySideMenu_BasicButton pointers (*) in _this above - // and the array "ary_layerButtonChoice". - iActiveLayer = iActiveLayer + 1i; - - // Also: go through each button that I'm going to show and set its "bAtive" to TRUE - // (all buttons like weapon upgrades are visible - // unless purchased in that showing of the weapon). And call each one's "vOnShow" - // since there may be some logic such as - // coloring the text red if the player can't afford that upgrade or weapon (in the - // case of entire weapons by name buttons too). - for(int i = 0; i < ary_btn_softLength; i++){ - int nextButtonIndex = ary_btn_index[i]; - CBuySideMenu_BasicButton someButton = *ary_btnTotal[nextButtonIndex]; - if(someButton.iType == BUTTON_TYPEID_WEAPON){ - CBuySideMenu_WeaponButton someButto = *((CBuySideMenu_WeaponButton*)ary_btnTotal[nextButtonIndex]); - someButto.bActive = TRUE; - someButto.vOnShow_Base(); - }else{ - someButton.bActive = TRUE; - someButton.vOnShow_Base(); - } - } - - }// button length check - - if(vOnClick_Custom != NULL){ - // If we have a custom click method, do it. - void(CBuySideMenu_BasicButton* arg_this)* tempRef = vOnClick_Custom; - (*tempRef)(_this); - //vOnClick_Custom(_this); - } - - //Regardless, most buttons are bound to change the current layer and - //possibly what the Cancel/Go Back button says (one of those two). - buysidemenu_btn_Back_updateText(); - -}//vOnClick_Base - - -void -CBuySideMenu_WeaponButton::CBuySideMenu_WeaponButton(void) -{ - // is chaining constructors ok here? No need! Done implicitly. - bActive = TRUE; - iWeaponPurchaseID = -1; //default -} -void -CBuySideMenu_WeaponButton::create_WeaponButton -( - string arg_sName, float arg_flHotkey, vector arg_clr, - void(CBuySideMenu_BasicButton* arg_this)* arg_vOnClick_Custom, - string arg_sWeaponImagePath, int arg_iWeaponPrice, int arg_iWeaponSlots, - int arg_iBitsWeaponOpt -) -{ - - //defaults. - //_this_deref.iLayer = 0i; - ary_btn_softLength = 0i; - - - sName = arg_sName; - - flHotkey = arg_flHotkey; - clr = arg_clr; - clr_render = arg_clr; //good default. - - vOnClick_Custom = arg_vOnClick_Custom; //(int*)&arg_vOnClick_Custom; - vOnShow_Custom = NULL; //paranoia? - - // Why do we add "_0.tga" to a .spr reference for the draw to work? - // The world may never know. - sWeaponImagePath = sprintf("%s_0.tga", arg_sWeaponImagePath); - - iWeaponPrice = arg_iWeaponPrice; - iWeaponSlots = arg_iWeaponSlots; - - iBitsWeaponOpt = arg_iBitsWeaponOpt; - - //Use that flag to determine what butttons to give me. - - iType = BUTTON_TYPEID_WEAPON; - - //Only add subbuttons (buy, upgrades, etc.) if this lacks the INSTANT option. - if( !(iBitsWeaponOpt & BITS_WEAPONOPT_INSTANT)){ - - //Every weapon has at least a "Buy" button. - buysidemenu_addbutton(_this, &buysidemenu_btn_WeaponOpt_Buy); - - if(iBitsWeaponOpt & BITS_WEAPONOPT_SILENCER){ - buysidemenu_addbutton(_this, &buysidemenu_btn_WeaponOpt_Silencer); - } - if(iBitsWeaponOpt & BITS_WEAPONOPT_LASERSIGHT){ - buysidemenu_addbutton(_this, &buysidemenu_btn_WeaponOpt_Lasersight); - } - if(iBitsWeaponOpt & BITS_WEAPONOPT_FLASHLIGHT){ - buysidemenu_addbutton(_this, &buysidemenu_btn_WeaponOpt_Flashlight); - } - if(iBitsWeaponOpt & BITS_WEAPONOPT_SCOPE){ - buysidemenu_addbutton(_this, &buysidemenu_btn_WeaponOpt_Scope); - } - if(iBitsWeaponOpt & BITS_WEAPONOPT_AKIMBO){ - buysidemenu_addbutton(_this, &buysidemenu_btn_WeaponOpt_Akimbo); - } - if(iBitsWeaponOpt & BITS_WEAPONOPT_FULLLOAD){ - buysidemenu_addbutton(_this, &buysidemenu_btn_WeaponOpt_FullLoad); - } - }//BITS_WEAPONOPT_INSTANT check - -}//create_WeaponButton - - -void -CBuySideMenu_WeaponButton::vOnRender_Base -( - vector arg_suggestedDrawPos, int arg_iLayer, int arg_iButtonRow, - BOOL arg_fIsSelected -) -{ - CBuySideMenu_BasicButton::vOnRender_Base( - arg_suggestedDrawPos, arg_iLayer, arg_iButtonRow, arg_fIsSelected - ); //call the parent's. - - // I want to draw my sWeaponImagePath above myself. - if(arg_fIsSelected && !(iBitsWeaponOpt & BITS_WEAPONOPT_INSTANT) ){ - - vector arg_buttonPos = [ - video_mins[0] + 5 + - arg_iLayer * (vButtonSizStandard.x + 1), video_mins[1] + video_res[1]/2 + arg_iButtonRow * (vButtonSizStandard.y + 1) - ]; - - float arg_opac; - if(arg_fIsSelected || arg_iLayer == iActiveLayer){ - arg_opac = 0.96; - }else{ - arg_opac = 0.71; - } - - vector textDrawOrigin = [arg_suggestedDrawPos.x + LABEL_OFFSET_X + 128, (video_res[1]/2) + LABEL_OFFSET_Y - (48 + 1)]; - - // NOTICE - draw on top of all buttons on this row unconditionally. Don't use arg_suggestedDrawPos.y - drawsubpic([arg_buttonPos.x, (video_res[1]/2) - (48 + 1)], [128,48], sWeaponImagePath, [0,0], [128/128,48/48], clrPaleBlue, 0.96, DRAWFLAG_ADDITIVE); - - string drawString1 = sprintf("%i Credits", iWeaponPrice); - string drawString2 = sprintf("%i Slots", iWeaponSlots); - - drawfill( [arg_buttonPos.x, (video_res[1]/2) - (48 + 1)], [256-1, 48], this.clr * 0.93f, arg_opac - 0.60f, DRAWFLAG_NORMAL ); - - Gfx_Text( textDrawOrigin, drawString1, vButtonFontSize, this.clr * 0.98f, (1.0f-(1.0f - arg_opac)*0.88) - 0.02f, DRAWFLAG_NORMAL, FONT_ARIAL_STD ); - Gfx_Text( [textDrawOrigin.x, textDrawOrigin.y + (vButtonSizStandard.y+1) ], drawString2, vButtonFontSize, this.clr * 0.98f, (1.0f-(1.0f - arg_opac)*0.88) - 0.02f, DRAWFLAG_NORMAL, FONT_ARIAL_STD ); - - } -}//vOnRender_Base - - -// convenient way to reset these globals for keeping track of a purchase in progress. -// Leaving the buy screen or getting out of a weapon should reset them. -void -VGUI_BuySideMenu_ResetTempVariables(void) -{ - iWeaponTempID = -1; - iBitsUpgradeTemp = BITS_WEAPONOPT_NONE; - iExtraPriceTemp = 0; - iExtraSlotsTemp = 0; - iPurchaseCountTemp = 1; -}// VGUI_BuySideMenu_ResetTempVariables - - -void -CBuySideMenu_WeaponButton::vOnShow_Base(void) -{ - CBuySideMenu_BasicButton::vOnShow_Base(); - // See if this weapon can be afforded. - if(canBuyWeapon(iWeaponPurchaseID, 0, 0, 1)){ - clr_render = clr; - }else{ - // same, but draw it red to show we can't afford it at a glance. - clr_render = clrRed; - } -}//vOnShow_Base - -void -CBuySideMenu_WeaponButton::vOnClick_Base(void) -{ - weapondata_basic_t weaponRef; - // Just one thing. Let's reset this to be safe (new weapon opened for seeing - // upgrade choices) - VGUI_BuySideMenu_ResetTempVariables(); - // and, thie tempCost starts at the value of this weapon as stated. - if(iWeaponPurchaseID == -1){ - return; - } - weaponRef = (*ary_weaponData[iWeaponPurchaseID]); - if(!(iBitsWeaponOpt & BITS_WEAPONOPT_INSTANT)){ - // normal behavior. - iWeaponTempID = iWeaponPurchaseID; - CBuySideMenu_BasicButton::vOnClick_Base(); - }else{ - // has the instant flag? that's it, apply it if we can. - if(canBuyWeapon(iWeaponPurchaseID, 0, 0, 1) ){ - BOOL addSuccess = attemptAddWeaponToConfig(iWeaponPurchaseID, BITS_WEAPONOPT_NONE, 1); - if(addSuccess){ - //and then go back. - buysidemenu_backOneLayer(); - buysidemenu_btn_Back_updateText(); - } - } - } -}//vOnClick_Base - - -void -buysidemenu_btn_Back_clicked(CBuySideMenu_BasicButton* arg_this) -{ - iWeaponTempID = -1; - if(iActiveLayer == 0i){ - // This is a request to close the buy menu. - // TODO. Support that. - buysidemenu_cancelConfigAndClose(); - }else{ - buysidemenu_backOneLayer(); - } -}//buysidemenu_btn_Back_clicked - - -void -buysidemenu_backOneLayer(void) -{ - // In any other layer, this reduces iActiveLayer by 1 to stop drawing the latest - // layer of buttons. And makes the previous layer accessible again. - - // The button on the previous layer is unselected. No button on the current - // active layer can be selected technically; selecting a button does so for that - // layer and then advances the active layer. - ary_layerButtonChoice[iActiveLayer - 1] = NULL; - - iActiveLayer = iActiveLayer - 1i; //drop a layer. -}//buysidemenu_backOneLayer - - -void -buysidemenu_btn_Back_updateText(void) -{ - if(iActiveLayer == 0i){ - // I will exit the buy menu if hit again. - buysidemenu_btn_Back.sName = "0 Cancel"; - }else{ - // Still going to say, "Go Back". - buysidemenu_btn_Back.sName = "0 Go Back"; - } -}//buysidemenu_btn_Back_updateText - - -// This is for the "Buy" option of any weapon/item in the buy menu, as in within its own -// details. -void -buysidemenu_btn_Buy_Weapon_clicked(CBuySideMenu_BasicButton* arg_this) -{ - if(iWeaponTempID != -1){ - // but how do we get the player from here... oh that actually still works. - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp, iExtraSlotsTemp, iPurchaseCountTemp)){ - BOOL addResult = attemptAddWeaponToConfig(iWeaponTempID, iBitsUpgradeTemp, iPurchaseCountTemp); - if(addResult){ - // went ok. back out of this. - buysidemenu_backOneLayer(); - buysidemenu_backOneLayer(); - } - } - refreshButtons(); - } -}//buysidemenu_btn_Buy_Weapon_clicked - - -void -setupRemoveButtonList(void) -{ - for(int i = 0; i < ary_myWeapons_length; i++){ - ary_btn_removeButton[i] = spawn(CBuySideMenu_RemoveWeaponButton); - - // basic init without the ".create" call. That gives the button its actual properties, - // which will change as things are deleted or the "Remove Items" button is returned to. - ary_btn_removeButton[i].setThisPointer(&ary_btn_removeButton[i]); - buysidemenu_addbuttonToTotal(&ary_btn_removeButton[i]); - buysidemenu_addbutton(&buysidemenu_btn_RemoveItem, &ary_btn_removeButton[i]); - } -}// setupRemoveButtonList - - -void -buysidemenu_btn_removeButton_clicked(CBuySideMenu_BasicButton* arg_this) -{ - CBuySideMenu_RemoveWeaponButton removeWeaponButtonRef = *( (CBuySideMenu_RemoveWeaponButton*)arg_this ); - removeWeaponFromConfig(removeWeaponButtonRef.linkedConfigIndex); - //and refresh this area. - buysidemenu_btn_RemoveItem_clicked(&buysidemenu_btn_RemoveItem); -} - - -void -buysidemenu_btn_RemoveItem_clicked(CBuySideMenu_BasicButton* arg_this) -{ - int i; - // FIRST, set each "ary_myWeapons_length" to be invisible. - // Don't get rendered / be clickable unless actually linked to a weapon in the - // player's inventory. - // (well this config really) - for(i = 0; i < ary_myWeapons_length; i++){ - ary_btn_removeButton[i].bActive = FALSE; - } - - // Get the list of all items in the player's inventory. - // Make one button active / set up to delete that item when clicked. - for(i = 0; i < pSeatLocal->m_clientinfo.weaponconfig_temp.ary_myWeapons_softMax; i++){ - weaponconfig_weapon_t* thisWeapo = &pSeatLocal->m_clientinfo.weaponconfig_temp.ary_myWeapons[i]; - - weapondata_basic_t* basicPointer = (weapondata_basic_t*) ary_weaponData[thisWeapo->weaponID]; - weapondata_basic_t basicRef = *(basicPointer); - - string buttonDisplayText; - int hotKeyCode; - if(i < 9) - { - //for i choices 0 through 8, use "i+1" to give 1-9. - buttonDisplayText = sprintf("%i: %s", (i+1i), basicRef.sDisplayName); - hotKeyCode = 48+(i+1); // '0' + (i+1) - } - else if(i < 9+26) - { - //now pick letters of the alphabet for the rest. - //uhhh. I don't know how to work with characters as a type or with ASCII values, so - //we'll just use this array of letters in the alphabet. - buttonDisplayText = sprintf("%s: %s", chr2str((float)i+65), basicRef.sDisplayName); - hotKeyCode = 97+(i-9); // 'a' + (i-9) - }else{ - // surpass that range? Not possible! - // In case it somehow is, refuse to generate any more remove buttons. - return; - } - - //INITIALIZE_BASICBUTTON(ary_btn_removeButton[i], "7 Buy Random", 48+7,clrGreen, NULL) - ary_btn_removeButton[i].create(buttonDisplayText, hotKeyCode, clrPaleBlue, &buysidemenu_btn_removeButton_clicked); - ary_btn_removeButton[i].bActive = TRUE; - - //CBuySideMenu_RemoveWeaponButton removeWeaponButtonRef2 = (CBuySideMenu_RemoveWeaponButton)ary_btn_removeButton[i]; - //removeWeaponButtonRef2.linkedConfigIndex = i; - ary_btn_removeButton[i].linkedConfigIndex = i; - - - }// for everything in the player's inventory - -}// buysidemenu_btn_RemoveItem_clicked - - - -// Take all buttons and call their "vOnShow". See what we can and can't afford -// (color red when we can't). vOnShow should handle this appropriately per button. -void -refreshButtons(void) -{ - int i; - int i2; - CBuySideMenu_BasicButton previousLayerButton; - CBuySideMenu_BasicButton tempButton; - - for(i = 0; i <= iActiveLayer; i++){ - if(i == 0){ - //CBuySideMenu_BasicButton tempButton = *ary_layerFirstButton[i2]; - for(i2 = 0; i2 < ary_layerFirstButton_softLength; i2++){ - tempButton = *ary_layerFirstButton[i2]; - tempButton.vOnShow_Base(); - }// for i2 in ary_layerFirstButton - - }else{ - previousLayerButton = *ary_layerButtonChoice[i - 1i]; - - for(i2 = 0i; i2 < previousLayerButton.ary_btn_softLength; i2 = i2+1i){ - //btnToRender = &previousLayerButton.ary_btn[i2]; - int btnToRender_index_global = previousLayerButton.ary_btn_index[i2]; - tempButton = *ary_btnTotal[btnToRender_index_global]; - tempButton.vOnShow_Base(); - } - } - } - -}//refreshButtons - - - - -// NOTICE - assumes "Cancel" was clicked. Reverts "temp" config to the "current" -// config (one last saved / applied). -void -buysidemenu_cancelConfigAndClose(void) -{ - //other way around. Copy what's at the current to the temp (forgetting any purchase changes). - - weaponconfig_data_t* tempWeaponConfig = &pSeatLocal->m_clientinfo.weaponconfig_temp; - weaponconfig_data_t* currentWeaponConfig = &pSeatLocal->m_clientinfo.weaponconfig_current; - - //copyConfig(pSeatLocal->m_clientinfo.weaponconfig_temp, pSeatLocal->m_clientinfo.weaponconfig_current); - copyConfig(tempWeaponConfig, currentWeaponConfig); - - - if(boughtAnything){ - CSQC_Parse_CenterPrint("Buy Order Canceled.\n"); - } - - VGUI_ChangeScreen(VGUI_SCREEN::NONE); -}//buysidemenu_cancelConfigAndClose - -// This is the "1 Use New Config" choice in the 1st layer. Applies the config (copies weaponconfig_temp to weapconfig_current). -// the "_current" one is read at spawn to give the player their loadout. -void -buysidemenu_btn_UseNewConfig_clicked(CBuySideMenu_BasicButton* arg_this) -{ - //weaponconfig_data_t - - weaponconfig_data_t* tempWeaponConfig = &pSeatLocal->m_clientinfo.weaponconfig_temp; - weaponconfig_data_t* currentWeaponConfig = &pSeatLocal->m_clientinfo.weaponconfig_current; - - //Player wants to apply everything from the currentConfig to tempConfig. - copyConfig(currentWeaponConfig, tempWeaponConfig); - - // TODO - check to see whether the config we just used was empty or not, to affect this message... - CSQC_Parse_CenterPrint("Using new config.\n"); - - VGUI_ChangeScreen(VGUI_SCREEN::NONE); -}//buysidemenu_btn_UseNewConfig_clicked - - -void -buysidemenu_btn_Buy_onShow(CBuySideMenu_BasicButton* arg_this) -{ - CBuySideMenu_BasicButton thisTemp = *arg_this; - - // uhhh. Why did I do this again? Clarity? - int arg_extraPrice = 0; - int arg_extraSlots = 0; - - int finalExtraPrice = iExtraPriceTemp + arg_extraPrice; - int finalExtraSlots = arg_extraSlots; - - weapondata_basic_t weaponRef = *( (weapondata_basic_t*) ary_weaponData[iWeaponTempID]); - - if(canBuyWeapon(iWeaponTempID, finalExtraPrice, finalExtraSlots, 1)){ - thisTemp.clr_render = thisTemp.clr; - }else{ - thisTemp.clr_render = clrRed; - } -} - - -void -buysidemenu_btn_Silencer_onShow(CBuySideMenu_BasicButton* arg_this) -{ - CBuySideMenu_BasicButton thisTemp = *arg_this; - // See if this buyopt's additional cost can be afforded. - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_SILENCER_COST, 0, 1)){ - thisTemp.clr_render = thisTemp.clr; - }else{ - thisTemp.clr_render = clrRed; - } -} - -void -buysidemenu_btn_Lasersight_onShow(CBuySideMenu_BasicButton* arg_this) -{ - CBuySideMenu_BasicButton thisTemp = *arg_this; - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_LASERSIGHT_COST, 0, 1)){ - thisTemp.clr_render = thisTemp.clr; - }else{ - thisTemp.clr_render = clrRed; - } -} - -void -buysidemenu_btn_Flashlight_onShow(CBuySideMenu_BasicButton* arg_this) -{ - CBuySideMenu_BasicButton thisTemp = *arg_this; - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_FLASHLIGHT_COST, 0, 1)){ - thisTemp.clr_render = thisTemp.clr; - }else{ - thisTemp.clr_render = clrRed; - } -} - -void -buysidemenu_btn_Scope_onShow(CBuySideMenu_BasicButton* arg_this) -{ - CBuySideMenu_BasicButton thisTemp = *arg_this; - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_SCOPE_COST, 0, 1)){ - thisTemp.clr_render = thisTemp.clr; - }else{ - thisTemp.clr_render = clrRed; - } -} - -void -buysidemenu_btn_Akimbo_onShow(CBuySideMenu_BasicButton* arg_this) -{ - CBuySideMenu_BasicButton thisTemp = *arg_this; - - //Can we afford one more copy of this weapon? - weapondata_basic_t weaponRef = (*ary_weaponData[iWeaponTempID]); - - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + weaponRef.iPrice, iExtraSlotsTemp + weaponRef.iSlots, iPurchaseCountTemp)){ - thisTemp.clr_render = thisTemp.clr; - }else{ - thisTemp.clr_render = clrRed; - } -} - -void -buysidemenu_btn_FullLoad_onShow(CBuySideMenu_BasicButton* arg_this) -{ - CBuySideMenu_BasicButton thisTemp = *arg_this; - //I'm not copying and pasting this stuff all over the place. - int buyCount = fullLoadCountToBuy(iWeaponTempID); - if(buyCount >= 0){ - weapondata_basic_t weaponRef = (*ary_weaponData[iWeaponTempID]); - - int testPrice = (buyCount) * weaponRef.iPrice; - int testSlots = (buyCount) * weaponRef.iSlots; - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + testPrice, iExtraSlotsTemp + testSlots, iPurchaseCountTemp)){ - thisTemp.clr_render = thisTemp.clr; - }else{ - thisTemp.clr_render = clrRed; - } - - }else{ - //assume there is nothing else to buy? - thisTemp.clr_render = thisTemp.clr; - } -}//buysidemenu_btn_FullLoad_clicked - - -void -buysidemenu_btn_Silencer_clicked(CBuySideMenu_BasicButton* arg_this) -{ - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_SILENCER_COST, iExtraSlotsTemp, iPurchaseCountTemp)){ - CBuySideMenu_BasicButton thisTemp = *arg_this; - //allow it and hide this button. - iBitsUpgradeTemp |= BITS_WEAPONOPT_SILENCER; - iExtraPriceTemp += WEAPONOPT_SILENCER_COST; - thisTemp.bActive = FALSE; - refreshButtons(); - } -} - -void -buysidemenu_btn_Lasersight_clicked(CBuySideMenu_BasicButton* arg_this) -{ - - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_LASERSIGHT_COST, iExtraSlotsTemp, iPurchaseCountTemp)){ - CBuySideMenu_BasicButton thisTemp = *arg_this; - //allow it and hide this button. - iBitsUpgradeTemp |= BITS_WEAPONOPT_LASERSIGHT; - iExtraPriceTemp += WEAPONOPT_LASERSIGHT_COST; - thisTemp.bActive = FALSE; - refreshButtons(); - } -} - -void -buysidemenu_btn_Flashlight_clicked(CBuySideMenu_BasicButton* arg_this) -{ - - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_FLASHLIGHT_COST, iExtraSlotsTemp, iPurchaseCountTemp)){ - CBuySideMenu_BasicButton thisTemp = *arg_this; - // allow it and hide this button. - iBitsUpgradeTemp |= BITS_WEAPONOPT_FLASHLIGHT; - iExtraPriceTemp += WEAPONOPT_FLASHLIGHT_COST; - thisTemp.bActive = FALSE; - refreshButtons(); - } -} - -void -buysidemenu_btn_Scope_clicked(CBuySideMenu_BasicButton* arg_this) -{ - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_SCOPE_COST, iExtraSlotsTemp, iPurchaseCountTemp)){ - CBuySideMenu_BasicButton thisTemp = *arg_this; - // allow it and hide this button. - iBitsUpgradeTemp |= BITS_WEAPONOPT_SCOPE; - iExtraPriceTemp += WEAPONOPT_SCOPE_COST; - thisTemp.bActive = FALSE; - refreshButtons(); - } -} -void -buysidemenu_btn_Akimbo_clicked(CBuySideMenu_BasicButton* arg_this) -{ - // Can we afford one more copy of this weapon? - weapondata_basic_t weaponRef = (*ary_weaponData[iWeaponTempID]); - - if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + weaponRef.iPrice, iExtraSlotsTemp + weaponRef.iSlots, iPurchaseCountTemp)){ - CBuySideMenu_BasicButton thisTemp = *arg_this; - // allow it and hide this button. - iBitsUpgradeTemp |= BITS_WEAPONOPT_AKIMBO; - iExtraPriceTemp += weaponRef.iPrice; - iExtraSlotsTemp += weaponRef.iSlots; - thisTemp.bActive = FALSE; - refreshButtons(); - } -} - -// NOTICE -// Buying 'full load', even if we can't afford to fill this throwable to the max, -// still works if we can afford at least one more. -// This method checks to see the least that can be afforded between price, slots, -// and max count allowed for this weapon type, and uses that + closes the picked -// weapon in the buymenu if a purchase is made. -// "Full Load" is for throwables only. Counting grenades as that type too. -void -buysidemenu_btn_FullLoad_clicked(CBuySideMenu_BasicButton* arg_this) -{ - // I'm not copying and pasting this stuff all over the place. - int buyCount = fullLoadCountToBuy(iWeaponTempID); - - if(buyCount >= 0){ - CBuySideMenu_BasicButton thisTemp; - weapondata_basic_t weaponRef = (*ary_weaponData[iWeaponTempID]); - - int testPrice = (buyCount) * weaponRef.iPrice; - int testSlots = (buyCount) * weaponRef.iSlots; - - int finalExtraPrice = iExtraPriceTemp + testPrice; - int finalExtraSlots = iExtraSlotsTemp + testSlots; - - if(canBuyWeapon(iWeaponTempID, finalExtraPrice, finalExtraSlots, iPurchaseCountTemp)){ - thisTemp = *arg_this; - // allow it and hide this button. - iBitsUpgradeTemp |= BITS_WEAPONOPT_FULLLOAD; - iExtraPriceTemp += testPrice; - iExtraSlotsTemp += testSlots; - thisTemp.bActive = FALSE; - - // Go ahead and buy this now. - buysidemenu_btn_Buy_Weapon_clicked((CBuySideMenu_BasicButton*)&buysidemenu_btn_WeaponOpt_Buy); - - refreshButtons(); - }else{ - // Couldn't afford the full load? - // How many throwables can I buy, given slot and (possible) money constraints? - int iSlotsAvailable = RULE_SLOTS_ALLOWED - (CONFIG_PLAYER_TOTALSLOTS + iExtraSlotsTemp); - int iMoneyAvailable; - if(RULE_MONEY_ALLOWED){ - iMoneyAvailable = CONFIG_PLAYER_MONEY - (CONFIG_PLAYER_TOTALCOST + iExtraPriceTemp); - }else{ - // signal that money is not something to worry about - iMoneyAvailable = -1; - } - - int numberAfforded = determineThrowableBuyCount(iWeaponTempID, iSlotsAvailable, iMoneyAvailable); - - if(numberAfforded > 0){ - //do something! - thisTemp = *arg_this; - //iBitsUpgradeTemp |= BITS_WEAPONOPT_FULLLOAD; - iPurchaseCountTemp = numberAfforded; - // no need for extra price/slot stuff! We'll make that from that - // altered 'iPurchaseCountTemp'. - // That is ever rarely anything besides '1'. Except for this case of - // course. - thisTemp.bActive = FALSE; - buysidemenu_btn_Buy_Weapon_clicked( (CBuySideMenu_BasicButton*) &buysidemenu_btn_WeaponOpt_Buy); - - refreshButtons(); - } - } - - } -}//buysidemenu_btn_FullLoad_clicked - - -void -VGUI_BuySideMenu_OnInit(void) -{ - // for macros below. - float flDeterminedHotkey; - - //safety. - VGUI_BuySideMenu_ResetTempVariables(); - - //haven't yet. - boughtAnything = FALSE; - - if(VGUI_BuySideMenu_InitDone == FALSE){ - //looks like we need to do this. proceed. - }else{ - //nevermind. - //Keep in mind some stuff (what's above) can run on any init call, even subsequent ones (re-opening the buy menu), since we might want to default some stuff - //like what was selected, temp buyopts clicked, etc. - return; - } - - iActiveLayer = 0i; - ary_btnTotal_softLength = 0i; - ary_layerFirstButton_softLength = 0i; - - // just in case? - for(int i = 0i; i < ary_layerButtonChoice.length; i+=1i){ - ary_layerButtonChoice[i] = NULL; - } - - - // buysidemenu_btn_Back = spawn(CBuySideMenu_BasicButton); - // if the 1st layer is active (drawn to that one). Says "Cancel" there, but if on any deeper layer it reads "Go Back". - //buysidemenu_btn_Back.create("0 Cancel", 48, NULL, buysidemenu_btn_Back_clicked); - - INITIALIZE_BASICBUTTON(Back, "Cancel", "0", clrPaleBluePurple, &buysidemenu_btn_Back_clicked) - - - //INITIALIZE_BASICBUTTON(Buy, "2 Buy", 48+2, NULL, 0, NULL) - INITIALIZE_BASICBUTTON(Recentconfig, "Use New Config", "1", clrGreen, &buysidemenu_btn_UseNewConfig_clicked) - INITIALIZE_BASICBUTTON(Buy, "Buy", "2", clrPaleBlue, NULL) - INITIALIZE_BASICBUTTON(RemoveItem, "Remove Item", "3", clrPaleBlue, &buysidemenu_btn_RemoveItem_clicked) - INITIALIZE_BASICBUTTON(ResetConfig, "Reset Config", "4", clrPaleBlue, NULL) - INITIALIZE_BASICBUTTON(SaveConfig, "Save Config", "5", clrPaleBlue, NULL) - INITIALIZE_BASICBUTTON(LoadConfig, "Load Config", "6", clrPaleBlue, NULL) - INITIALIZE_BASICBUTTON(BuyRandom, "Buy Random", "7", clrGreen, NULL) - INITIALIZE_BASICBUTTON(Buy_Handguns, "Handguns", "1", clrPaleBlue, NULL) - INITIALIZE_BASICBUTTON(Buy_SMGs, "SMGs", "2", clrPaleBlue, NULL) - INITIALIZE_BASICBUTTON(Buy_Rifles, "Rifles", "3", clrPaleBlue, NULL) - INITIALIZE_BASICBUTTON(Buy_Shotguns, "Shotguns", "4", clrPaleBlue, NULL) - INITIALIZE_BASICBUTTON(Buy_SpecialPurpose, "Special Purpose", "5", clrPaleBlue, NULL) - - - // !!! INITIALIZE THE WEAPON-UPGRADE BUTTONS BEFORE THE WEAPONS THEMSELVES. Or else these will be missing at that point. - INITIALIZE_BASICBUTTON(WeaponOpt_Buy, "Buy", "1", clrGreen, &buysidemenu_btn_Buy_Weapon_clicked) - INITIALIZE_BASICBUTTON(WeaponOpt_Silencer, sprintf("Silencer %i", WEAPONOPT_SILENCER_COST), "2", clrPaleBlue, &buysidemenu_btn_Silencer_clicked) - INITIALIZE_BASICBUTTON(WeaponOpt_Lasersight, sprintf("Lasersight %i", WEAPONOPT_LASERSIGHT_COST), "3", clrPaleBlue, &buysidemenu_btn_Lasersight_clicked) - INITIALIZE_BASICBUTTON(WeaponOpt_Flashlight, sprintf("Flashlight %i", WEAPONOPT_FLASHLIGHT_COST), "4", clrPaleBlue, &buysidemenu_btn_Flashlight_clicked) - INITIALIZE_BASICBUTTON(WeaponOpt_Scope, sprintf("Scope %i", WEAPONOPT_SCOPE_COST), "5", clrPaleBlue, &buysidemenu_btn_Scope_clicked) - - // Yes, Akimbo and FullLoad use the same hotkey (number 6). They never appear on the same weapon, - // since Akimbo is only meant for some guns, and FullLoad is only meant for some melee weapons. - // TODO? And if these two were to support flexible prices (show what it costs for the currently selected weapon... akimbo & fullLoad can't be fixed to - // one constant for all weapons), their display text + prices would have to be shown as they're shown to the user. - INITIALIZE_BASICBUTTON(WeaponOpt_Akimbo, "Akimbo", "6", clrPaleBlue, &buysidemenu_btn_Akimbo_clicked) - INITIALIZE_BASICBUTTON(WeaponOpt_FullLoad, "FullLoad", "6", clrGreen, &buysidemenu_btn_FullLoad_clicked) - - buysidemenu_btn_WeaponOpt_Buy.vOnShow_Custom = &buysidemenu_btn_Buy_onShow; - - buysidemenu_btn_WeaponOpt_Silencer.vOnShow_Custom = &buysidemenu_btn_Silencer_onShow; - buysidemenu_btn_WeaponOpt_Lasersight.vOnShow_Custom = &buysidemenu_btn_Lasersight_onShow; - buysidemenu_btn_WeaponOpt_Flashlight.vOnShow_Custom = &buysidemenu_btn_Flashlight_onShow; - buysidemenu_btn_WeaponOpt_Scope.vOnShow_Custom = &buysidemenu_btn_Scope_onShow; - buysidemenu_btn_WeaponOpt_Akimbo.vOnShow_Custom = &buysidemenu_btn_Akimbo_onShow; - buysidemenu_btn_WeaponOpt_FullLoad.vOnShow_Custom = &buysidemenu_btn_FullLoad_onShow; - - - // TODO - ONGOING. As more weapons are entered, use this new condensed way - // to hook up to their info instead of using the hardcoded specifics below. - // Any other references to the button may be deleted thereafter. - - // This variable is expected for the _ADV version to work or else it would need to - // declare a new temp each time, just keep it around. - weapondata_basic_t tempWeapRef; - - - INITIALIZE_WEAPONBUTTON(GLOCK18, "1", clrPaleBlue, NULL, Handguns) - INITIALIZE_WEAPONBUTTON(SOCOMMK23, "2", clrPaleBlue, NULL, Handguns) - INITIALIZE_WEAPONBUTTON(DESERTEAGLE, "3", clrPaleBlue, NULL, Handguns) - INITIALIZE_WEAPONBUTTON(FIVESEVEN, "4", clrPaleBlue, NULL, Handguns) - INITIALIZE_WEAPONBUTTON(BERETTA, "5", clrPaleBlue, NULL, Handguns) - INITIALIZE_WEAPONBUTTON(AKIMBOCOLTS, "6", clrPaleBlue, NULL, Handguns) - INITIALIZE_WEAPONBUTTON(GLOCK20, "7", clrPaleBlue, NULL, Handguns) - INITIALIZE_WEAPONBUTTON(RUGERMK1, "8", clrPaleBlue, NULL, Handguns) - INITIALIZE_WEAPONBUTTON(RAGINGBULL, "9", clrPaleBlue, NULL, Handguns) - INITIALIZE_WEAPONBUTTON(CONTENDERG2, "A", clrPaleBlue, NULL, Handguns) - - - INITIALIZE_WEAPONBUTTON(MINIUZI, "1", clrPaleBlue, NULL, SMGs) - INITIALIZE_WEAPONBUTTON(MP5SD, "2", clrPaleBlue, NULL, SMGs) - INITIALIZE_WEAPONBUTTON(MP5K, "3", clrPaleBlue, NULL, SMGs) - - INITIALIZE_WEAPONBUTTON(STEYRTMP, "4", clrPaleBlue, NULL, SMGs) - INITIALIZE_WEAPONBUTTON(HKPDW, "5", clrPaleBlue, NULL, SMGs) - INITIALIZE_WEAPONBUTTON(UMP, "6", clrPaleBlue, NULL, SMGs) - - INITIALIZE_WEAPONBUTTON(SKORPION, "7", clrPaleBlue, NULL, SMGs) - INITIALIZE_WEAPONBUTTON(MAC10, "8", clrPaleBlue, NULL, SMGs) - - - INITIALIZE_WEAPONBUTTON(M4A1, "1", clrPaleBlue, NULL, Rifles) - INITIALIZE_WEAPONBUTTON(AK47, "2", clrPaleBlue, NULL, Rifles) - INITIALIZE_WEAPONBUTTON(STEYRAUG, "3", clrPaleBlue, NULL, Rifles) - INITIALIZE_WEAPONBUTTON(M16A4, "4", clrPaleBlue, NULL, Rifles) - INITIALIZE_WEAPONBUTTON(BARRETTM82, "5", clrPaleBlue, NULL, Rifles) - - - INITIALIZE_WEAPONBUTTON(BENELLIM3, "1", clrPaleBlue, NULL, Shotguns) - INITIALIZE_WEAPONBUTTON(USAS12, "2", clrPaleBlue, NULL, Shotguns) - INITIALIZE_WEAPONBUTTON(SPAS12, "3", clrPaleBlue, NULL, Shotguns) - INITIALIZE_WEAPONBUTTON(MOSSBERG500, "4", clrPaleBlue, NULL, Shotguns) - INITIALIZE_WEAPONBUTTON(SAWEDOFF, "5", clrPaleBlue, NULL, Shotguns) - - - // LATER - make purchaseable only if the gamemode is team/scenario. (mercs vs specialists) - INITIALIZE_WEAPONBUTTON(M61GRENADE, "1", clrPaleBlue, NULL, SpecialPurpose) - - INITIALIZE_WEAPONBUTTON(COMBATKNIFE, "2", clrPaleBlue, NULL, SpecialPurpose) - INITIALIZE_WEAPONBUTTON(M60, "3", clrPaleBlue, NULL, SpecialPurpose) - INITIALIZE_WEAPONBUTTON(KATANA, "4", clrPaleBlue, NULL, SpecialPurpose) - INITIALIZE_WEAPONBUTTON(SEALKNIFE, "5", clrPaleBlue, NULL, SpecialPurpose) - - //TODO - set these up. items are simpler than weapons and have no default behavior. - // in fact the kevlar just puts armor on the player at spawn, stealthshoes may as well - // be a "yes/no" toggle on the player. - // Last parameter is the cost instead of the buy category, since we don't have - // any weapondata to get the cost from. - // ...we still need the category too though. - //INITIALIZE_ITEMBUTTON_ADV(KEVLAR, "1", 48+1, clrPaleBlue, NULL, PlayerAccessory, 1900); - //INITIALIZE_ITEMBUTTON_ADV(STEALTHSHOES, "2", 48+2, clrPaleBlue, NULL, PlayerAccessory, 700); - - buysidemenu_btn_Back_updateText(); //just in case. - - buysidemenu_addbuttonToFirstLayer(&buysidemenu_btn_Recentconfig); - buysidemenu_addbuttonToFirstLayer(&buysidemenu_btn_Buy); - buysidemenu_addbuttonToFirstLayer(&buysidemenu_btn_RemoveItem); - buysidemenu_addbuttonToFirstLayer(&buysidemenu_btn_ResetConfig); - buysidemenu_addbuttonToFirstLayer(&buysidemenu_btn_SaveConfig); - buysidemenu_addbuttonToFirstLayer(&buysidemenu_btn_LoadConfig); - buysidemenu_addbuttonToFirstLayer(&buysidemenu_btn_BuyRandom); - - buysidemenu_addbutton(&buysidemenu_btn_Buy, &buysidemenu_btn_Buy_Handguns); - buysidemenu_addbutton(&buysidemenu_btn_Buy, &buysidemenu_btn_Buy_SMGs); - buysidemenu_addbutton(&buysidemenu_btn_Buy, &buysidemenu_btn_Buy_Rifles); - buysidemenu_addbutton(&buysidemenu_btn_Buy, &buysidemenu_btn_Buy_Shotguns); - buysidemenu_addbutton(&buysidemenu_btn_Buy, &buysidemenu_btn_Buy_SpecialPurpose); - - - setupRemoveButtonList(); - - // don't do this init process again. - VGUI_BuySideMenu_InitDone = TRUE; - -}// VGUI_BuySideMenu_OnInit - - - -//var float lastPrintoutTime = 0.0f; - -void -VGUI_BuySideMenu_Update(player arg_player, vector vPos, vector vWindowSiz, float fFontSizeMulti) -{ - // If we leave spectator view (spawned and walking/aiming), disallow the buy menu. - // (could also check for "player.iState == PLAYER_STATE::SPAWNED" ) - if(getplayerkeyvalue(player_localnum, "*spec") == "0"){ - - VGUI_ChangeScreen(VGUI_SCREEN::NONE); - return; - } - - // Reset this. If the mouse is hovering over something we'll find out. - iHoveredButtonIndex = -1; - - int currentLayerSelectedIndex; - int btnToRender_index_global; - CBuySideMenu_BasicButton someThing; - CBuySideMenu_BasicButton previousLayerButton; - BOOL fIsSelected; - - // VGUI_Text( sprintf("%s - %s", "Free Specialists", serverkey("hostname") ), vPos + '16 64 0', '12 12', FONT_CON ); - - - // Checks for clicks be done separately - // Only check for buttons from the active layer. - - vector vButtonPos = [video_mins[0] + 5, video_mins[1] + video_res[1]/2, 0]; - vector vBtnPos = [0,0,0]; - - /* - if(time >= lastPrintoutTime){ - lastPrintoutTime = time + 2.0f; - - // anything routine? - } - */ - - BuySideMenu_onInputEvent(); - - drawPlayerInventory(TRUE); - - for(int i = 0i; i <= iActiveLayer; i = i + 1i){ - //Adjust these as needed. These also show where to draw the "0 Cancel" button - //for the active layer (after the most recent button; below). - //vector vBtnPos; - vBtnPos.z = 0; - if(i == 0){ - - if(ary_layerButtonChoice[i] == NULL){ - currentLayerSelectedIndex = -1; - }else{ - someThing = *ary_layerButtonChoice[i]; - currentLayerSelectedIndex = someThing.iGlobalIndex; - } - - vBtnPos.x = (int)vButtonPos.x; //default pos. - vBtnPos.y = (int)vButtonPos.y; - - for(int i2 = 0i; i2 < ary_layerFirstButton_softLength; i2++){ - CBuySideMenu_BasicButton tempButton = *ary_layerFirstButton[i2]; - fIsSelected = (tempButton.iGlobalIndex == currentLayerSelectedIndex); - - (*ary_layerFirstButton[i2]).vOnRender_Base(vBtnPos, i, i2, fIsSelected); - - vBtnPos.y += (vButtonSizStandard.y + 1); - - } - - }else{ - vBtnPos.x = (int)vButtonPos.x + (vButtonSizStandard.x + 1) * i; //slide the X-pos however far given this layer. - vBtnPos.y = (int)vButtonPos.y; - // All other layers only render buttons that the previous layer (selected button there) tells them to. - - previousLayerButton = *ary_layerButtonChoice[i - 1i]; - - if(ary_layerButtonChoice[i] == NULL){ - currentLayerSelectedIndex = -1; - }else{ - someThing = *ary_layerButtonChoice[i]; - currentLayerSelectedIndex = someThing.iGlobalIndex; - } - - for(int i2 = 0i; i2 < previousLayerButton.ary_btn_softLength; i2 = i2+1i){ - btnToRender_index_global = previousLayerButton.ary_btn_index[i2]; - - CBuySideMenu_BasicButton tempButton2_aaa = *ary_btnTotal[btnToRender_index_global]; - - //NOTICE - we can only check for bActive in the active layer. Any others must show - // all buttons yet. - if(i == iActiveLayer && tempButton2_aaa.bActive == FALSE){ - //skip showing this one. - continue; - } - - fIsSelected = (btnToRender_index_global == currentLayerSelectedIndex); - - (*ary_btnTotal[btnToRender_index_global]).vOnRender_Base(vBtnPos, i, i2, fIsSelected); - vBtnPos.y += (vButtonSizStandard.y + 1); - - }// for i2 in this layer's buttons. - } - - if(i == iActiveLayer){ - int backButtonRow; - // Draw the "0. Cancel" button. Special purpose. - // buysidemenu_renderButton(&buysidemenu_btn_Back, vBtnPos, 0.86); - - // Whatever the size of the latest layer is. Since that index itself wasn't used (minus 1 is the most recently used index; - // we're putting a button AFTER that one). - if(iActiveLayer > 0){ - previousLayerButton = *ary_layerButtonChoice[iActiveLayer - 1i]; - backButtonRow = previousLayerButton.ary_btn_softLength; - }else{ - backButtonRow = ary_layerFirstButton_softLength; - } - - buysidemenu_btn_Back.vOnRender_Base(vBtnPos, i, backButtonRow, fIsSelected); - vBtnPos.y += (vButtonSizStandard.y + 1); - } - - - }// for(i from 0 to iActiveLayer, inclusive) - - - // TEST! - // DRAWFLAG_ADDITIVE? NORMAL? Which one? - //drawsubpic([25,25], [128,48], "sprites/weapons/glock18.spr_0.tga", [0,0], [128/128,48/48], [1,1,1], 1, DRAWFLAG_ADDITIVE); - //drawsubpic([16,128], [11,16], "sprites/numbers.spr_0.tga", [1/112,0], [11/112,16/16], [1,1,1], 1, DRAWFLAG_ADDITIVE); - //drawsubpic([16,128], [127*0.1,16], "sprites/numbers.spr_0.tga", [0.5,0], [0.1,16/16], [1,1,1], 1, DRAWFLAG_ADDITIVE); - - drawPlayerInventory_TopBar(-1, TRUE); - -}//VGUI_BuySideMenu_Update - - -// Given a single-character string, like "3" or "A", determine the keycode that -// should be tied to it. For uppercase characters, force the lowercase one, as the -// user is certainly pushing that one. -float determineHotkeyFromChar(string arg_sHotkeyDisplay){ - if(strlen(arg_sHotkeyDisplay) != 0){ - float charCode = str2chr(arg_sHotkeyDisplay, 0); - if(charCode >= 48 && charCode <= 48+9){ - // numeric? Straightforward - return charCode; - }else if(charCode >= 65 && charCode <= 65+25){ - // uppercase? Convert to lowercase for charCode. - return charCode + 32; - }else if(charCode >= 97 && charCode <= 97+25){ - // lowercase? Leave it as it is - return charCode; - }else{ - // ??? - return -1; - } - }else{ - // blank string given? - return -1; - } -} - - +/*** +* +* Copyright (c) 2016-2019 Marco 'eukara' Hladik. All rights reserved. +* +* See the file LICENSE attached with the sources for usage details. +* +****/ + +#define LABEL_OFFSET_X 1 +#define LABEL_OFFSET_Y 3 + +#define BUTTON_TYPEID_BASIC 0 +#define BUTTON_TYPEID_WEAPON 1 + + + + +#define INITIALIZE_BASICBUTTON(arg_varName, arg_sName, arg_sHotkeyDisplay, arg_clr, arg_vOnClick_Custom) buymenu_btn_##arg_varName = spawn(CBuyMenu_BasicButton);\ + flDeterminedHotkey = determineHotkeyFromChar(arg_sHotkeyDisplay);\ + buymenu_btn_##arg_varName.setThisPointer(&buymenu_btn_##arg_varName);\ + buymenu_btn_##arg_varName.create(sprintf("%s %s", arg_sHotkeyDisplay, arg_sName), flDeterminedHotkey, arg_clr, arg_vOnClick_Custom);\ + buymenu_addbuttonToTotal(&buymenu_btn_##arg_varName); + + +#define INITIALIZE_WEAPONBUTTON(arg_varName, arg_sHotkeyDisplay, arg_clr, arg_vOnClick_Custom, arg_parentName) buymenu_btn_Buy_##arg_varName = spawn(CBuyMenu_WeaponButton);\ + flDeterminedHotkey = determineHotkeyFromChar(arg_sHotkeyDisplay);\ + buymenu_btn_Buy_##arg_varName.setThisPointer(&buymenu_btn_Buy_##arg_varName);\ + tempWeapRef = *ary_weaponData[WEAPON_ID::##arg_varName];\ + buymenu_btn_Buy_##arg_varName.create_WeaponButton(sprintf("%s %s", arg_sHotkeyDisplay, tempWeapRef.sDisplayName), flDeterminedHotkey, arg_clr, arg_vOnClick_Custom, tempWeapRef.sIconFilePath, tempWeapRef.iPrice, tempWeapRef.iSlots, tempWeapRef.iBitsUpgrade & ~tempWeapRef.iBitsUpgradeAuto);\ + buymenu_addbuttonToTotal(&buymenu_btn_Buy_##arg_varName);\ + buymenu_btn_Buy_##arg_varName.iWeaponPurchaseID = WEAPON_ID::##arg_varName;\ + buymenu_addbutton(&buymenu_btn_Buy_##arg_parentName, &buymenu_btn_Buy_##arg_varName); + + + +// prototype'd class +class CBuyMenu_BasicButton; + + +// set to TRUE if this screen has ever been brought up before. +var BOOL UI_BuyMenu_InitDone = FALSE; + +var int iWeaponTempID = -1; + +//What upgrades has the player purchased for the currently open weapon in the buy menu? +var int iBitsUpgradeTemp = BITS_WEAPONOPT_NONE; +//How much does the weapon's upgrades (does not consider ammo if necessary) cost? +var int iExtraPriceTemp = 0; +var int iExtraSlotsTemp = 0; +var int iPurchaseCountTemp = 1; + +var int iHoveredButtonIndex = -1; +var int iActiveLayer = 0; + + +class CBuyMenu_BasicButton; +class CBuyMenu_WeaponButton; +class CBuyMenu_WeaponButton; +class CBuyMenu_RemoveWeaponButton; + +void buymenu_cancelConfigAndClose(void); +void refreshButtons(void); +void setupRemoveButtonList(void); +void buymenu_btn_removeButton_clicked(CBuyMenu_BasicButton* arg_this); +void buymenu_btn_RemoveItem_clicked(CBuyMenu_BasicButton* arg_this); + + +void buymenu_backOneLayer(void); +void buymenu_btn_Back_updateText(void); +void buymenu_btn_Back_clicked(CBuyMenu_BasicButton* arg_this); + +void(CBuyMenu_BasicButton* arg_someButton) setActiveLayerButton; + +float determineHotkeyFromChar(string arg_sHotkeyDisplay); + + + +//Each button ever created must be added to this list. Can be one automatically... +//struct's don't have constructors though. Call for this at startup I suppose. +var CBuyMenu_BasicButton* ary_btnTotal[128]; +var int ary_btnTotal_softLength = 0; + +var CBuyMenu_BasicButton* ary_layerButtonChoice[16]; //16 layers max. Not that nearly this many should be used. +//var int ary_layerButtonChoiceIndex[16i]; //alternative approach. + +//Any buttons in the first layer must be recorded here. +var CBuyMenu_BasicButton* ary_layerFirstButton[16]; +var int ary_layerFirstButton_softLength = 0; + + +// One button expected for each weapon in ary_myWeapons of the tempconfig at most. +// (so up to "ary_myWeapons_length" in count). +CBuyMenu_RemoveWeaponButton ary_btn_removeButton[ary_myWeapons_length]; + + + +var CBuyMenu_BasicButton buymenu_btn_WeaponOpt_Buy; +var CBuyMenu_BasicButton buymenu_btn_WeaponOpt_Silencer; +var CBuyMenu_BasicButton buymenu_btn_WeaponOpt_Lasersight; +var CBuyMenu_BasicButton buymenu_btn_WeaponOpt_Flashlight; +var CBuyMenu_BasicButton buymenu_btn_WeaponOpt_Scope; +var CBuyMenu_BasicButton buymenu_btn_WeaponOpt_Akimbo; +var CBuyMenu_BasicButton buymenu_btn_WeaponOpt_FullLoad; + + + + +// SPECIAL BUTTON - draw this wherever appropriate for the active layer. Its text is also different +// if the 1st layer is active (drawn to that one). Says "Cancel" there, but if on any deeper layer it reads "Go Back". +var CBuyMenu_BasicButton buymenu_btn_Back; +// var CBuyMenu_BasicButton buymenu_btn_Back = {0, "0 Cancel", 0,0, 48, NULL, {}, 0, NULL}; + +var CBuyMenu_BasicButton buymenu_btn_Recentconfig; +var CBuyMenu_BasicButton buymenu_btn_Buy; +var CBuyMenu_BasicButton buymenu_btn_RemoveItem; +var CBuyMenu_BasicButton buymenu_btn_ResetConfig; +var CBuyMenu_BasicButton buymenu_btn_SaveConfig; +var CBuyMenu_BasicButton buymenu_btn_LoadConfig; +var CBuyMenu_BasicButton buymenu_btn_BuyRandom; + +var CBuyMenu_BasicButton buymenu_btn_Buy_Handguns; +var CBuyMenu_BasicButton buymenu_btn_Buy_SMGs; +var CBuyMenu_BasicButton buymenu_btn_Buy_Rifles; +var CBuyMenu_BasicButton buymenu_btn_Buy_Shotguns; +var CBuyMenu_BasicButton buymenu_btn_Buy_SpecialPurpose; + +var CBuyMenu_WeaponButton buymenu_btn_Buy_GLOCK18; +var CBuyMenu_WeaponButton buymenu_btn_Buy_SOCOMMK23; +var CBuyMenu_WeaponButton buymenu_btn_Buy_DESERTEAGLE; +var CBuyMenu_WeaponButton buymenu_btn_Buy_FIVESEVEN; +var CBuyMenu_WeaponButton buymenu_btn_Buy_BERETTA; +var CBuyMenu_WeaponButton buymenu_btn_Buy_AKIMBOCOLTS; + +var CBuyMenu_WeaponButton buymenu_btn_Buy_GLOCK20; + +var CBuyMenu_WeaponButton buymenu_btn_Buy_RUGERMK1; +var CBuyMenu_WeaponButton buymenu_btn_Buy_RAGINGBULL; +var CBuyMenu_WeaponButton buymenu_btn_Buy_CONTENDERG2; + + +var CBuyMenu_WeaponButton buymenu_btn_Buy_MINIUZI; +var CBuyMenu_WeaponButton buymenu_btn_Buy_MP5SD; +var CBuyMenu_WeaponButton buymenu_btn_Buy_MP5K; +var CBuyMenu_WeaponButton buymenu_btn_Buy_STEYRTMP; + +// called the MP7PDW ingame? ts_fgd refers to it as "HK Pdw" though +var CBuyMenu_WeaponButton buymenu_btn_Buy_HKPDW; + +var CBuyMenu_WeaponButton buymenu_btn_Buy_MAC10; +var CBuyMenu_WeaponButton buymenu_btn_Buy_UMP; +var CBuyMenu_WeaponButton buymenu_btn_Buy_SKORPION; + +var CBuyMenu_WeaponButton buymenu_btn_Buy_M4A1; +var CBuyMenu_WeaponButton buymenu_btn_Buy_AK47; +var CBuyMenu_WeaponButton buymenu_btn_Buy_STEYRAUG; +var CBuyMenu_WeaponButton buymenu_btn_Buy_M16A4; +var CBuyMenu_WeaponButton buymenu_btn_Buy_BARRETTM82; + +var CBuyMenu_WeaponButton buymenu_btn_Buy_BENELLIM3; +var CBuyMenu_WeaponButton buymenu_btn_Buy_USAS12; +var CBuyMenu_WeaponButton buymenu_btn_Buy_SPAS12; +var CBuyMenu_WeaponButton buymenu_btn_Buy_MOSSBERG500; +var CBuyMenu_WeaponButton buymenu_btn_Buy_SAWEDOFF; + +var CBuyMenu_WeaponButton buymenu_btn_Buy_M61GRENADE; +var CBuyMenu_WeaponButton buymenu_btn_Buy_COMBATKNIFE; +var CBuyMenu_WeaponButton buymenu_btn_Buy_M60; +var CBuyMenu_WeaponButton buymenu_btn_Buy_KATANA; +var CBuyMenu_WeaponButton buymenu_btn_Buy_SEALKNIFE; + + + + +// Notice that the buttons do not have location/size information. They are +// drawn wherever as needed, checks for clicks need that supplied to know where +// to check. +class CBuyMenu_BasicButton{ + + // yes. really. + CBuyMenu_BasicButton* _this; + + int iType; // is this a BasicButton or a WeaponButton? + BOOL bActive; // Effectively hides this from all logic. As in, don't skip the space this would occupy. Pretend like this button didn't exit. + // Refreshed at a new layer / going back one. + + int iGlobalIndex; + string sName; + + // -1 is the signal for "no hotkey". Numbers actually start at 48 for 0 (49 for 1... or 48+1 for clarity). + float flHotkey; + + vector clr; // stored; natural color. + vector clr_render; // for actual use. + + // Array of buttons that are shown when I'm clicked on. Many buttons use this. + // The "0 Cancel" back button will be drawn if applicaple (for the active (deepest layer open) if it's not the first layer). + // struct CBuyMenu_BasicButton* ary_btn[16i]; + int ary_btn_index[16]; + int ary_btn_softLength; + + + // Special behavior for this button (optional). Good for buttons that will interact + // with something in the game like adding a weapon or adding an accessory (Silencer) to an existing one. + + //virtual void(CBuyMenu_BasicButton* arg_this) vOnClick_Custom = NULL; + int* vOnClick_Custom; + //virtual void(CBuyMenu_BasicButton* arg_this) vOnShow_Custom = NULL; + int* vOnShow_Custom; + + void(void) CBuyMenu_BasicButton; + + virtual void(CBuyMenu_BasicButton* arg_this) setThisPointer; + + virtual void(string arg_sName, float arg_flHotkey, vector arg_clr, void(CBuyMenu_BasicButton* arg_this)* arg_vOnClick_Custom ) create; + + virtual void(vector arg_suggestedDrawPos, int arg_iLayer, int arg_iButtonRow, BOOL arg_fIsSelected) vOnRender_Base; + virtual void(void) vOnClick_Base; + + + virtual void(void) vOnShow_Base; + + // This is set separately from any "create" methods or constructors since it is rarely used. + // If set, this method will run anytime this button is shown. This lets it do a quick calculation + // to see if the player can afford an upgrade as it is displayed. + + +}; + + +class CBuyMenu_WeaponButton : CBuyMenu_BasicButton{ + + // What weapon (by ID) will I purchase (or try to) when bought? + // Parameter limit used up - have to set this separtely. Ugh. + // We're remaking buttons to use structs instead of classes later so this isn't too + // bad of a patch for now. + int iWeaponPurchaseID; + + string sWeaponImagePath; + int iWeaponPrice; + int iWeaponSlots; + int iBitsWeaponOpt; //Can the player buy... a scope? lazer sight? flash light? akimbo? etc. + + + void(void) CBuyMenu_WeaponButton; + + // after arg_clr: int arg_ary_btn_index[16] + virtual void(string arg_sName, float arg_flHotkey, vector arg_clr, void(CBuyMenu_BasicButton* arg_this)* arg_vOnClick_Custom, string arg_sWeaponImagePath, int arg_iWeaponPrice, int arg_iWeaponSlots, int arg_iBitsWeaponOpt ) create_WeaponButton; + + virtual void(vector arg_suggestedDrawPos, int arg_iLayer, int arg_iButtonRow, BOOL arg_fIsSelected) vOnRender_Base; + virtual void(void) vOnClick_Base; + + + virtual void(void) vOnShow_Base; + //virtual void(CBuyMenu_BasicButton* arg_this) vOnShow_Custom = NULL; + +}; + + +// Very slightly modified form of CBuyMenu_BasicButton that just includes +// an extra var for storing what part of the config to remove if clicked on. +// As in, the 3rd button will remove the 2nd index (...ary_myWeapons[2]) from the player's +// temp config. +class CBuyMenu_RemoveWeaponButton : CBuyMenu_BasicButton{ + // What element of the config do I remove if I am picked? + int linkedConfigIndex; + + void(void) CBuyMenu_RemoveWeaponButton; +}; + + +void +CBuyMenu_RemoveWeaponButton::CBuyMenu_RemoveWeaponButton(void) +{ + +} + + +BOOL +checkBuyMenuButtonClicked( + CBuyMenu_BasicButton* arg_someBtn, vector vPosition, + vector vSize +) +{ + CBuyMenu_BasicButton deref = *arg_someBtn; + + // Check for the button's hotkey. + if(deref.flHotkey != -1 && pSeatLocal->m_inputKeyDown == deref.flHotkey){ + (*arg_someBtn).vOnClick_Base(); + pSeatLocal->m_inputKeyDown = 0; + return TRUE; + } + + if ( pSeatLocal->m_inputMouseClicked == TRUE ) { + if(VGUI_CheckMouse( vPosition, vSize )){ + // What button is being hovered over? + iHoveredButtonIndex = deref.iGlobalIndex; + + (*arg_someBtn).vOnClick_Base(); + + pSeatLocal->m_inputMouseClicked = FALSE; + return TRUE; + } + } + + return FALSE; +}// checkBuyMenuButtonClicked + + + +// Called by ui_eventgrabber on detecting input from a keypress or mouse. +// TODO - still a little sloppy to check for both the recently pressed key +// matching the hotkey and a mouse-click for coords when each event can only be +// either of these things, not both. +// But that would mean cloning this method with the only difference being +// checkBuyMenuButtonClicked for "checkBuyMenuButtonHotKey" insetad, +// and Clicked loses the hotkey check. +void UI_BuyMenu_onInputEvent(void){ + if(!UI_BuyMenu_InitDone){ + // Not allowed yet! + return; + } + + vector vButtonPos = [video_mins[0] + 5, video_mins[1] + video_res[1]/2, 0]; + vector vBtnPos = [0,0,0]; + int currentLayerSelectedIndex; + int btnToRender_index_global; + CBuyMenu_BasicButton someThing; + CBuyMenu_BasicButton previousLayerButton; + BOOL fIsSelected; + + if(iActiveLayer == 0){ + vBtnPos.x = (int)vButtonPos.x; //default pos. + vBtnPos.y = (int)vButtonPos.y; + + + for(int i2 = 0i; i2 < ary_layerFirstButton_softLength; i2++){ + CBuyMenu_BasicButton tempButton = *ary_layerFirstButton[i2]; + + checkBuyMenuButtonClicked(ary_layerFirstButton[i2], vBtnPos, vButtonSizStandard); + vBtnPos.y += (vButtonSizStandard.y + 1); + } + + }else{ + vBtnPos.x = (int)vButtonPos.x + (vButtonSizStandard.x + 1) * iActiveLayer; + vBtnPos.y = (int)vButtonPos.y; + // All other layers only render buttons that the previous layer (selected button there) tells them to. + + previousLayerButton = *ary_layerButtonChoice[iActiveLayer - 1i]; + + + for(int i2 = 0i; i2 < previousLayerButton.ary_btn_softLength; i2 = i2+1i){ + + // CONCLUSION... maybe. + // So much as this local var, "btnCheck", being set to a dereferenced ary_btnTotal element, + // and this btnCheck being used in checkBuyMenubuttonClicked instead of just that ary_btnTotal element (a pointer already) + // is enough to trigger this odd error, where the next frame (or if this for loop gets so much as an extra iteration + // that resets btnCheck... test with the "if(theThingHappened)continue;" bit above moved to after these lines below too... + // Anyways, this makes the difference between whether the real thing the ary_btnTotal element links to stays + // consistent between at least loop iterations or not even those. Staying consistent between frames is definitely out. + // When this method ends, or really this scope (?), that thing the ary_btnTotal element is pointing at blanks out. + + btnToRender_index_global = previousLayerButton.ary_btn_index[i2]; + + CBuyMenu_BasicButton tempButton2 = *ary_btnTotal[btnToRender_index_global]; + if(tempButton2.bActive == FALSE){ + // let the next button be tried instead. + continue; + } + + // NOT THIS WAY (causes the odd problem): + //if(checkBuyMenuButtonClicked(&btnCheck, vBtnPos, vButtonSizStandard)){ + if(checkBuyMenuButtonClicked(ary_btnTotal[btnToRender_index_global], vBtnPos, vButtonSizStandard)){ + // nothing special happens if so, checkBuyMenuButtonClicked handles this fine. + } + + vBtnPos.y += (vButtonSizStandard.y + 1); + }// for i2 in this layer's buttons. + } + + // Check the "0. Cancel" button. + checkBuyMenuButtonClicked(&buymenu_btn_Back, vBtnPos, vButtonSizStandard); + vBtnPos.y += (vButtonSizStandard.y + 1); +}// UI_BuyMenu_onInputEvent + + + +// For "_this" button, add "arg_other" to its list of buttons (ary_btn) to be shown when this button +// is clicked. +// Also, so much as adding a button to another's list will bump the other button's "iLayer" by 1 +// past the button it's being linked to. +// So NEVER add one button to two different layers, or at least set the layer manually to be correct +// (and match between the two parents, which should be parentButton+1). +// "iLayer" will be handled naturally just fine otherwise. +void +buymenu_addbutton(CBuyMenu_BasicButton* _this, CBuyMenu_BasicButton* arg_other) +{ + + CBuyMenu_BasicButton _this_deref = *_this; + CBuyMenu_BasicButton arg_other_deref = *arg_other; + + if(_this_deref.ary_btn_softLength < 16i){ + //proceed. + int nextButtonSlot = _this_deref.ary_btn_softLength; + + //I am the number "i" child of the parent. Useful for telling what button from the previous layer + //was selected. + + //_this.ary_btn[nextButtonSlot] = arg_other; + _this_deref.ary_btn_index[nextButtonSlot] = arg_other_deref.iGlobalIndex; + + _this_deref.ary_btn_softLength += 1i; //increase the number of buttons I link to by 1. + // arg_other_deref.iLayer = _this_deref.iLayer + 1i; //This "other" button is one layer deeper + // than the parent. + + } + +}//buymenu_addbutton + + + +void +buymenu_addbuttonToTotal(CBuyMenu_BasicButton* _this) +{ + + if(ary_btnTotal_softLength >= ary_btnTotal.length){ + //ERROR! + print(sprintf("!!! CLIENT ERROR. Button max of %i reached, button not added! Report this!\n", ary_btnTotal.length) ); + return; + } + + CBuyMenu_BasicButton _this_deref = *_this; + + //localcmd(sprintf("echo addButtonToTotal: IM %s AND MY ID IS %i\n", _this.sName, ary_btnTotal_softLength)); + + _this_deref.iGlobalIndex = ary_btnTotal_softLength; + ary_btnTotal[ary_btnTotal_softLength] = _this; + ary_btnTotal_softLength = ary_btnTotal_softLength + 1i; + +}//buymenu_addbutton + +void +buymenu_addbuttonToFirstLayer(CBuyMenu_BasicButton* _this) +{ + + if(ary_layerFirstButton_softLength >= ary_layerFirstButton.length){ + //ERROR! + print(sprintf("!!! CLIENT ERROR. First layer button max of %i reached, button not added! Report this!\n", ary_layerFirstButton.length) ); + return; + } + + ary_layerFirstButton[ary_layerFirstButton_softLength] = _this; + ary_layerFirstButton_softLength = ary_layerFirstButton_softLength + 1i; + +}//buymenu_addbuttonToFirstLayer + + + +//!!! SEND THE iGlobalIndex. +// Method that actually draws the button. +// Made separate from button's onRender methods so that this can be called with a different color conveniently +// (red for "can't afford this" at a glance) +void +drawBuyButton( + int arg_iGlobalIndex, string arg_text, vector arg_suggestedDrawPos, int arg_iLayer, + int arg_iButtonRow, BOOL arg_fIsSelected, vector arg_clr +) +{ + vector arg_buttonPos = arg_suggestedDrawPos; + + float arg_opac; + if(arg_fIsSelected || arg_iLayer == iActiveLayer){ + arg_opac = 0.96; + }else{ + arg_opac = 0.71; + } + + vector vLabelPos; + BOOL mouseHovered = FALSE; + + // Draw the button label + vLabelPos[0] = arg_buttonPos[0] + LABEL_OFFSET_X; + vLabelPos[1] = arg_buttonPos[1] + LABEL_OFFSET_Y; + + if(arg_iGlobalIndex == iHoveredButtonIndex){ + //This button is the chosen one!!! + mouseHovered = TRUE; + } + + /* + // NO BORDERS FOR THE WICKED. + // last two parameters were these constants before: vVGUIColor, VGUI_WINDOW_FGALPHA + //Now the draw stuff. + drawfill( vPosition, [vSize[0], 1], '255 0 0', 1.0 ); + drawfill( [vPosition[0], vPosition[1] + vSize[1] - 1], [vSize[0], 1], '255 0 0', 1.0 ); + drawfill( vPosition, [1, vSize[1]], '255 0 0', 1.0 ); + drawfill( [vPosition[0] + vSize[0] - 1, vPosition[1]], [1, vSize[1]], '255 0 0', 1.0 ); + */ + + //iActiveLayer == iLayer && + if(mouseHovered){ + // Draw the background + drawfill( arg_buttonPos, vButtonSizStandard, arg_clr * 0.93f, arg_opac - 0.60f, DRAWFLAG_NORMAL ); + + Gfx_Text( vLabelPos, arg_text, vButtonFontSize, arg_clr * 0.98f, (1.0f-(1.0f - arg_opac)*0.88) - 0.02f, DRAWFLAG_NORMAL, FONT_ARIAL_STD ); + //return TRUE; + }else{ + // Draw the background + drawfill( arg_buttonPos, vButtonSizStandard, arg_clr * 0.86, arg_opac - 0.70f, DRAWFLAG_NORMAL ); + + Gfx_Text( vLabelPos, arg_text, vButtonFontSize, arg_clr * 0.94f, (1.0f-(1.0f - arg_opac)*0.88) - 0.06f, DRAWFLAG_NORMAL, FONT_ARIAL_STD ); + } + +}// drawBuyButton + + + +void +setActiveLayerButton(CBuyMenu_BasicButton* arg_someButton) +{ + ary_layerButtonChoice[iActiveLayer] = arg_someButton; +} + +void +CBuyMenu_BasicButton::CBuyMenu_BasicButton(void) +{ + iType = BUTTON_TYPEID_BASIC; + bActive = TRUE; + vOnClick_Custom = NULL; + vOnShow_Custom = NULL; +} +void +CBuyMenu_BasicButton::setThisPointer(CBuyMenu_BasicButton* arg_this) +{ + _this = arg_this; +} +void +CBuyMenu_BasicButton::create(string arg_sName, float arg_flHotkey, vector arg_clr, void(CBuyMenu_BasicButton* arg_this)* arg_vOnClick_Custom ) +{ + sName = arg_sName; + + flHotkey = arg_flHotkey; + clr = arg_clr; + clr_render = arg_clr; //good default. + + vOnClick_Custom = arg_vOnClick_Custom; //(int*)&arg_vOnClick_Custom; + vOnShow_Custom = NULL; +}//create + + +void +CBuyMenu_BasicButton::vOnRender_Base +( + vector arg_suggestedDrawPos, int arg_iLayer, int arg_iButtonRow, BOOL arg_fIsSelected +) +{ + drawBuyButton(this.iGlobalIndex, this.sName, arg_suggestedDrawPos, arg_iLayer, arg_iButtonRow, arg_fIsSelected, this.clr_render); +}//vOnRender_Base + + + +void +CBuyMenu_BasicButton::vOnShow_Base(void) +{ + + if(vOnShow_Custom != NULL){ + void(CBuyMenu_BasicButton* arg_this)* tempRef = vOnShow_Custom; + (*tempRef)(_this); + //vOnShow_Custom(_this); + } + +}// vOnShow_Base + + +// When this button is clicked, what does it do? +void +CBuyMenu_BasicButton::vOnClick_Base(void) +{ + + // basic button behavior. Only if our array has a non-zero length. + // Buttons of zero length don't unwrap into new buttons and can do something special, + // like go up a layer instead ("cancel"), something about configs, or buy a + // weapon/accessory. + if( ary_btn_softLength != 0i){ + + // "this"... is not already a pointer??! WHAT HERESY BEFALLS MY EYES?!!! + // nah just kidding, makes sense for QuakeC. + // setActiveLayerButton(&this); + ary_layerButtonChoice[iActiveLayer] = _this; + + // "warning F307: type mismatch: CBuyMenu_BasicButton * _this to + // CBuyMenu_BasicButton *[ary_layerButtonChoice]" + // ...????? happens if using CBuyMenu_BasicButton pointers (*) in _this above + // and the array "ary_layerButtonChoice". + iActiveLayer = iActiveLayer + 1i; + + // Also: go through each button that I'm going to show and set its "bAtive" to TRUE + // (all buttons like weapon upgrades are visible + // unless purchased in that showing of the weapon). And call each one's "vOnShow" + // since there may be some logic such as + // coloring the text red if the player can't afford that upgrade or weapon (in the + // case of entire weapons by name buttons too). + for(int i = 0; i < ary_btn_softLength; i++){ + int nextButtonIndex = ary_btn_index[i]; + CBuyMenu_BasicButton someButton = *ary_btnTotal[nextButtonIndex]; + if(someButton.iType == BUTTON_TYPEID_WEAPON){ + CBuyMenu_WeaponButton someButto = *((CBuyMenu_WeaponButton*)ary_btnTotal[nextButtonIndex]); + someButto.bActive = TRUE; + someButto.vOnShow_Base(); + }else{ + someButton.bActive = TRUE; + someButton.vOnShow_Base(); + } + } + + }// button length check + + if(vOnClick_Custom != NULL){ + // If we have a custom click method, do it. + void(CBuyMenu_BasicButton* arg_this)* tempRef = vOnClick_Custom; + (*tempRef)(_this); + //vOnClick_Custom(_this); + } + + //Regardless, most buttons are bound to change the current layer and + //possibly what the Cancel/Go Back button says (one of those two). + buymenu_btn_Back_updateText(); + +}//vOnClick_Base + + +void +CBuyMenu_WeaponButton::CBuyMenu_WeaponButton(void) +{ + // is chaining constructors ok here? No need! Done implicitly. + bActive = TRUE; + iWeaponPurchaseID = -1; //default +} +void +CBuyMenu_WeaponButton::create_WeaponButton +( + string arg_sName, float arg_flHotkey, vector arg_clr, + void(CBuyMenu_BasicButton* arg_this)* arg_vOnClick_Custom, + string arg_sWeaponImagePath, int arg_iWeaponPrice, int arg_iWeaponSlots, + int arg_iBitsWeaponOpt +) +{ + + //defaults. + //_this_deref.iLayer = 0i; + ary_btn_softLength = 0i; + + + sName = arg_sName; + + flHotkey = arg_flHotkey; + clr = arg_clr; + clr_render = arg_clr; //good default. + + vOnClick_Custom = arg_vOnClick_Custom; //(int*)&arg_vOnClick_Custom; + vOnShow_Custom = NULL; //paranoia? + + // Why do we add "_0.tga" to a .spr reference for the draw to work? + // The world may never know. + sWeaponImagePath = sprintf("%s_0.tga", arg_sWeaponImagePath); + + iWeaponPrice = arg_iWeaponPrice; + iWeaponSlots = arg_iWeaponSlots; + + iBitsWeaponOpt = arg_iBitsWeaponOpt; + + //Use that flag to determine what butttons to give me. + + iType = BUTTON_TYPEID_WEAPON; + + //Only add subbuttons (buy, upgrades, etc.) if this lacks the INSTANT option. + if( !(iBitsWeaponOpt & BITS_WEAPONOPT_INSTANT)){ + + //Every weapon has at least a "Buy" button. + buymenu_addbutton(_this, &buymenu_btn_WeaponOpt_Buy); + + if(iBitsWeaponOpt & BITS_WEAPONOPT_SILENCER){ + buymenu_addbutton(_this, &buymenu_btn_WeaponOpt_Silencer); + } + if(iBitsWeaponOpt & BITS_WEAPONOPT_LASERSIGHT){ + buymenu_addbutton(_this, &buymenu_btn_WeaponOpt_Lasersight); + } + if(iBitsWeaponOpt & BITS_WEAPONOPT_FLASHLIGHT){ + buymenu_addbutton(_this, &buymenu_btn_WeaponOpt_Flashlight); + } + if(iBitsWeaponOpt & BITS_WEAPONOPT_SCOPE){ + buymenu_addbutton(_this, &buymenu_btn_WeaponOpt_Scope); + } + if(iBitsWeaponOpt & BITS_WEAPONOPT_AKIMBO){ + buymenu_addbutton(_this, &buymenu_btn_WeaponOpt_Akimbo); + } + if(iBitsWeaponOpt & BITS_WEAPONOPT_FULLLOAD){ + buymenu_addbutton(_this, &buymenu_btn_WeaponOpt_FullLoad); + } + }//BITS_WEAPONOPT_INSTANT check + +}//create_WeaponButton + + +void +CBuyMenu_WeaponButton::vOnRender_Base +( + vector arg_suggestedDrawPos, int arg_iLayer, int arg_iButtonRow, + BOOL arg_fIsSelected +) +{ + CBuyMenu_BasicButton::vOnRender_Base( + arg_suggestedDrawPos, arg_iLayer, arg_iButtonRow, arg_fIsSelected + ); //call the parent's. + + // I want to draw my sWeaponImagePath above myself. + if(arg_fIsSelected && !(iBitsWeaponOpt & BITS_WEAPONOPT_INSTANT) ){ + + vector arg_buttonPos = [ + video_mins[0] + 5 + + arg_iLayer * (vButtonSizStandard.x + 1), video_mins[1] + video_res[1]/2 + arg_iButtonRow * (vButtonSizStandard.y + 1) + ]; + + float arg_opac; + if(arg_fIsSelected || arg_iLayer == iActiveLayer){ + arg_opac = 0.96; + }else{ + arg_opac = 0.71; + } + + vector textDrawOrigin = [arg_suggestedDrawPos.x + LABEL_OFFSET_X + 128, (video_res[1]/2) + LABEL_OFFSET_Y - (48 + 1)]; + + // NOTICE - draw on top of all buttons on this row unconditionally. Don't use arg_suggestedDrawPos.y + drawsubpic([arg_buttonPos.x, (video_res[1]/2) - (48 + 1)], [128,48], sWeaponImagePath, [0,0], [128/128,48/48], clrPaleBlue, 0.96, DRAWFLAG_ADDITIVE); + + string drawString1 = sprintf("%i Credits", iWeaponPrice); + string drawString2 = sprintf("%i Slots", iWeaponSlots); + + drawfill( [arg_buttonPos.x, (video_res[1]/2) - (48 + 1)], [256-1, 48], this.clr * 0.93f, arg_opac - 0.60f, DRAWFLAG_NORMAL ); + + Gfx_Text( textDrawOrigin, drawString1, vButtonFontSize, this.clr * 0.98f, (1.0f-(1.0f - arg_opac)*0.88) - 0.02f, DRAWFLAG_NORMAL, FONT_ARIAL_STD ); + Gfx_Text( [textDrawOrigin.x, textDrawOrigin.y + (vButtonSizStandard.y+1) ], drawString2, vButtonFontSize, this.clr * 0.98f, (1.0f-(1.0f - arg_opac)*0.88) - 0.02f, DRAWFLAG_NORMAL, FONT_ARIAL_STD ); + + } +}//vOnRender_Base + + +// convenient way to reset these globals for keeping track of a purchase in progress. +// Leaving the buy screen or getting out of a weapon should reset them. +void +UI_BuyMenu_ResetTempVariables(void) +{ + iWeaponTempID = -1; + iBitsUpgradeTemp = BITS_WEAPONOPT_NONE; + iExtraPriceTemp = 0; + iExtraSlotsTemp = 0; + iPurchaseCountTemp = 1; +}// UI_BuyMenu_ResetTempVariables + + +void +CBuyMenu_WeaponButton::vOnShow_Base(void) +{ + CBuyMenu_BasicButton::vOnShow_Base(); + // See if this weapon can be afforded. + if(canBuyWeapon(iWeaponPurchaseID, 0, 0, 1)){ + clr_render = clr; + }else{ + // same, but draw it red to show we can't afford it at a glance. + clr_render = clrRed; + } +}//vOnShow_Base + +void +CBuyMenu_WeaponButton::vOnClick_Base(void) +{ + weapondata_basic_t weaponRef; + // Just one thing. Let's reset this to be safe (new weapon opened for seeing + // upgrade choices) + UI_BuyMenu_ResetTempVariables(); + // and, thie tempCost starts at the value of this weapon as stated. + if(iWeaponPurchaseID == -1){ + return; + } + weaponRef = (*ary_weaponData[iWeaponPurchaseID]); + if(!(iBitsWeaponOpt & BITS_WEAPONOPT_INSTANT)){ + // normal behavior. + iWeaponTempID = iWeaponPurchaseID; + CBuyMenu_BasicButton::vOnClick_Base(); + }else{ + // has the instant flag? that's it, apply it if we can. + if(canBuyWeapon(iWeaponPurchaseID, 0, 0, 1) ){ + BOOL addSuccess = attemptAddWeaponToConfig(iWeaponPurchaseID, BITS_WEAPONOPT_NONE, 1); + if(addSuccess){ + //and then go back. + buymenu_backOneLayer(); + buymenu_btn_Back_updateText(); + } + } + } +}//vOnClick_Base + + +void +buymenu_btn_Back_clicked(CBuyMenu_BasicButton* arg_this) +{ + iWeaponTempID = -1; + if(iActiveLayer == 0i){ + // This is a request to close the buy menu. + // TODO. Support that. + buymenu_cancelConfigAndClose(); + }else{ + buymenu_backOneLayer(); + } +}//buymenu_btn_Back_clicked + + +void +buymenu_backOneLayer(void) +{ + // In any other layer, this reduces iActiveLayer by 1 to stop drawing the latest + // layer of buttons. And makes the previous layer accessible again. + + // The button on the previous layer is unselected. No button on the current + // active layer can be selected technically; selecting a button does so for that + // layer and then advances the active layer. + ary_layerButtonChoice[iActiveLayer - 1] = NULL; + + iActiveLayer = iActiveLayer - 1i; //drop a layer. +}//buymenu_backOneLayer + + +void +buymenu_btn_Back_updateText(void) +{ + if(iActiveLayer == 0i){ + // I will exit the buy menu if hit again. + buymenu_btn_Back.sName = "0 Cancel"; + }else{ + // Still going to say, "Go Back". + buymenu_btn_Back.sName = "0 Go Back"; + } +}//buymenu_btn_Back_updateText + + +// This is for the "Buy" option of any weapon/item in the buy menu, as in within its own +// details. +void +buymenu_btn_Buy_Weapon_clicked(CBuyMenu_BasicButton* arg_this) +{ + if(iWeaponTempID != -1){ + // but how do we get the player from here... oh that actually still works. + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp, iExtraSlotsTemp, iPurchaseCountTemp)){ + BOOL addResult = attemptAddWeaponToConfig(iWeaponTempID, iBitsUpgradeTemp, iPurchaseCountTemp); + if(addResult){ + // went ok. back out of this. + buymenu_backOneLayer(); + buymenu_backOneLayer(); + } + } + refreshButtons(); + } +}//buymenu_btn_Buy_Weapon_clicked + + +void +setupRemoveButtonList(void) +{ + for(int i = 0; i < ary_myWeapons_length; i++){ + ary_btn_removeButton[i] = spawn(CBuyMenu_RemoveWeaponButton); + + // basic init without the ".create" call. That gives the button its actual properties, + // which will change as things are deleted or the "Remove Items" button is returned to. + ary_btn_removeButton[i].setThisPointer(&ary_btn_removeButton[i]); + buymenu_addbuttonToTotal(&ary_btn_removeButton[i]); + buymenu_addbutton(&buymenu_btn_RemoveItem, &ary_btn_removeButton[i]); + } +}// setupRemoveButtonList + + +void +buymenu_btn_removeButton_clicked(CBuyMenu_BasicButton* arg_this) +{ + CBuyMenu_RemoveWeaponButton removeWeaponButtonRef = *( (CBuyMenu_RemoveWeaponButton*)arg_this ); + removeWeaponFromConfig(removeWeaponButtonRef.linkedConfigIndex); + //and refresh this area. + buymenu_btn_RemoveItem_clicked(&buymenu_btn_RemoveItem); +} + + +void +buymenu_btn_RemoveItem_clicked(CBuyMenu_BasicButton* arg_this) +{ + int i; + // FIRST, set each "ary_myWeapons_length" to be invisible. + // Don't get rendered / be clickable unless actually linked to a weapon in the + // player's inventory. + // (well this config really) + for(i = 0; i < ary_myWeapons_length; i++){ + ary_btn_removeButton[i].bActive = FALSE; + } + + // Get the list of all items in the player's inventory. + // Make one button active / set up to delete that item when clicked. + for(i = 0; i < pSeatLocal->m_clientinfo.weaponconfig_temp.ary_myWeapons_softMax; i++){ + weaponconfig_weapon_t* thisWeapo = &pSeatLocal->m_clientinfo.weaponconfig_temp.ary_myWeapons[i]; + + weapondata_basic_t* basicPointer = (weapondata_basic_t*) ary_weaponData[thisWeapo->weaponID]; + weapondata_basic_t basicRef = *(basicPointer); + + string buttonDisplayText; + int hotKeyCode; + if(i < 9) + { + //for i choices 0 through 8, use "i+1" to give 1-9. + buttonDisplayText = sprintf("%i: %s", (i+1i), basicRef.sDisplayName); + hotKeyCode = 48+(i+1); // '0' + (i+1) + } + else if(i < 9+26) + { + //now pick letters of the alphabet for the rest. + //uhhh. I don't know how to work with characters as a type or with ASCII values, so + //we'll just use this array of letters in the alphabet. + buttonDisplayText = sprintf("%s: %s", chr2str((float)i+65), basicRef.sDisplayName); + hotKeyCode = 97+(i-9); // 'a' + (i-9) + }else{ + // surpass that range? Not possible! + // In case it somehow is, refuse to generate any more remove buttons. + return; + } + + //INITIALIZE_BASICBUTTON(ary_btn_removeButton[i], "7 Buy Random", 48+7,clrGreen, NULL) + ary_btn_removeButton[i].create(buttonDisplayText, hotKeyCode, clrPaleBlue, &buymenu_btn_removeButton_clicked); + ary_btn_removeButton[i].bActive = TRUE; + + //CBuyMenu_RemoveWeaponButton removeWeaponButtonRef2 = (CBuyMenu_RemoveWeaponButton)ary_btn_removeButton[i]; + //removeWeaponButtonRef2.linkedConfigIndex = i; + ary_btn_removeButton[i].linkedConfigIndex = i; + + + }// for everything in the player's inventory + +}// buymenu_btn_RemoveItem_clicked + + + +// Take all buttons and call their "vOnShow". See what we can and can't afford +// (color red when we can't). vOnShow should handle this appropriately per button. +void +refreshButtons(void) +{ + int i; + int i2; + CBuyMenu_BasicButton previousLayerButton; + CBuyMenu_BasicButton tempButton; + + for(i = 0; i <= iActiveLayer; i++){ + if(i == 0){ + //CBuyMenu_BasicButton tempButton = *ary_layerFirstButton[i2]; + for(i2 = 0; i2 < ary_layerFirstButton_softLength; i2++){ + tempButton = *ary_layerFirstButton[i2]; + tempButton.vOnShow_Base(); + }// for i2 in ary_layerFirstButton + + }else{ + previousLayerButton = *ary_layerButtonChoice[i - 1i]; + + for(i2 = 0i; i2 < previousLayerButton.ary_btn_softLength; i2 = i2+1i){ + //btnToRender = &previousLayerButton.ary_btn[i2]; + int btnToRender_index_global = previousLayerButton.ary_btn_index[i2]; + tempButton = *ary_btnTotal[btnToRender_index_global]; + tempButton.vOnShow_Base(); + } + } + } + +}//refreshButtons + + + + +// NOTICE - assumes "Cancel" was clicked. Reverts "temp" config to the "current" +// config (one last saved / applied). +void +buymenu_cancelConfigAndClose(void) +{ + //other way around. Copy what's at the current to the temp (forgetting any purchase changes). + + weaponconfig_data_t* tempWeaponConfig = &pSeatLocal->m_clientinfo.weaponconfig_temp; + weaponconfig_data_t* currentWeaponConfig = &pSeatLocal->m_clientinfo.weaponconfig_current; + + //copyConfig(pSeatLocal->m_clientinfo.weaponconfig_temp, pSeatLocal->m_clientinfo.weaponconfig_current); + copyConfig(tempWeaponConfig, currentWeaponConfig); + + + if(boughtAnything){ + CSQC_Parse_CenterPrint("Buy Order Canceled.\n"); + } + + UI_ChangeScreen(UI_SCREEN::NONE); +}//buymenu_cancelConfigAndClose + +// This is the "1 Use New Config" choice in the 1st layer. Applies the config (copies weaponconfig_temp to weapconfig_current). +// the "_current" one is read at spawn to give the player their loadout. +void +buymenu_btn_UseNewConfig_clicked(CBuyMenu_BasicButton* arg_this) +{ + //weaponconfig_data_t + + weaponconfig_data_t* tempWeaponConfig = &pSeatLocal->m_clientinfo.weaponconfig_temp; + weaponconfig_data_t* currentWeaponConfig = &pSeatLocal->m_clientinfo.weaponconfig_current; + + //Player wants to apply everything from the currentConfig to tempConfig. + copyConfig(currentWeaponConfig, tempWeaponConfig); + + // TODO - check to see whether the config we just used was empty or not, to affect this message... + CSQC_Parse_CenterPrint("Using new config.\n"); + + UI_ChangeScreen(UI_SCREEN::NONE); +}//buymenu_btn_UseNewConfig_clicked + + +void +buymenu_btn_Buy_onShow(CBuyMenu_BasicButton* arg_this) +{ + CBuyMenu_BasicButton thisTemp = *arg_this; + + // uhhh. Why did I do this again? Clarity? + int arg_extraPrice = 0; + int arg_extraSlots = 0; + + int finalExtraPrice = iExtraPriceTemp + arg_extraPrice; + int finalExtraSlots = arg_extraSlots; + + weapondata_basic_t weaponRef = *( (weapondata_basic_t*) ary_weaponData[iWeaponTempID]); + + if(canBuyWeapon(iWeaponTempID, finalExtraPrice, finalExtraSlots, 1)){ + thisTemp.clr_render = thisTemp.clr; + }else{ + thisTemp.clr_render = clrRed; + } +} + + +void +buymenu_btn_Silencer_onShow(CBuyMenu_BasicButton* arg_this) +{ + CBuyMenu_BasicButton thisTemp = *arg_this; + // See if this buyopt's additional cost can be afforded. + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_SILENCER_COST, 0, 1)){ + thisTemp.clr_render = thisTemp.clr; + }else{ + thisTemp.clr_render = clrRed; + } +} + +void +buymenu_btn_Lasersight_onShow(CBuyMenu_BasicButton* arg_this) +{ + CBuyMenu_BasicButton thisTemp = *arg_this; + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_LASERSIGHT_COST, 0, 1)){ + thisTemp.clr_render = thisTemp.clr; + }else{ + thisTemp.clr_render = clrRed; + } +} + +void +buymenu_btn_Flashlight_onShow(CBuyMenu_BasicButton* arg_this) +{ + CBuyMenu_BasicButton thisTemp = *arg_this; + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_FLASHLIGHT_COST, 0, 1)){ + thisTemp.clr_render = thisTemp.clr; + }else{ + thisTemp.clr_render = clrRed; + } +} + +void +buymenu_btn_Scope_onShow(CBuyMenu_BasicButton* arg_this) +{ + CBuyMenu_BasicButton thisTemp = *arg_this; + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_SCOPE_COST, 0, 1)){ + thisTemp.clr_render = thisTemp.clr; + }else{ + thisTemp.clr_render = clrRed; + } +} + +void +buymenu_btn_Akimbo_onShow(CBuyMenu_BasicButton* arg_this) +{ + CBuyMenu_BasicButton thisTemp = *arg_this; + + //Can we afford one more copy of this weapon? + weapondata_basic_t weaponRef = (*ary_weaponData[iWeaponTempID]); + + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + weaponRef.iPrice, iExtraSlotsTemp + weaponRef.iSlots, iPurchaseCountTemp)){ + thisTemp.clr_render = thisTemp.clr; + }else{ + thisTemp.clr_render = clrRed; + } +} + +void +buymenu_btn_FullLoad_onShow(CBuyMenu_BasicButton* arg_this) +{ + CBuyMenu_BasicButton thisTemp = *arg_this; + //I'm not copying and pasting this stuff all over the place. + int buyCount = fullLoadCountToBuy(iWeaponTempID); + if(buyCount >= 0){ + weapondata_basic_t weaponRef = (*ary_weaponData[iWeaponTempID]); + + int testPrice = (buyCount) * weaponRef.iPrice; + int testSlots = (buyCount) * weaponRef.iSlots; + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + testPrice, iExtraSlotsTemp + testSlots, iPurchaseCountTemp)){ + thisTemp.clr_render = thisTemp.clr; + }else{ + thisTemp.clr_render = clrRed; + } + + }else{ + //assume there is nothing else to buy? + thisTemp.clr_render = thisTemp.clr; + } +}//buymenu_btn_FullLoad_clicked + + +void +buymenu_btn_Silencer_clicked(CBuyMenu_BasicButton* arg_this) +{ + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_SILENCER_COST, iExtraSlotsTemp, iPurchaseCountTemp)){ + CBuyMenu_BasicButton thisTemp = *arg_this; + //allow it and hide this button. + iBitsUpgradeTemp |= BITS_WEAPONOPT_SILENCER; + iExtraPriceTemp += WEAPONOPT_SILENCER_COST; + thisTemp.bActive = FALSE; + refreshButtons(); + } +} + +void +buymenu_btn_Lasersight_clicked(CBuyMenu_BasicButton* arg_this) +{ + + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_LASERSIGHT_COST, iExtraSlotsTemp, iPurchaseCountTemp)){ + CBuyMenu_BasicButton thisTemp = *arg_this; + //allow it and hide this button. + iBitsUpgradeTemp |= BITS_WEAPONOPT_LASERSIGHT; + iExtraPriceTemp += WEAPONOPT_LASERSIGHT_COST; + thisTemp.bActive = FALSE; + refreshButtons(); + } +} + +void +buymenu_btn_Flashlight_clicked(CBuyMenu_BasicButton* arg_this) +{ + + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_FLASHLIGHT_COST, iExtraSlotsTemp, iPurchaseCountTemp)){ + CBuyMenu_BasicButton thisTemp = *arg_this; + // allow it and hide this button. + iBitsUpgradeTemp |= BITS_WEAPONOPT_FLASHLIGHT; + iExtraPriceTemp += WEAPONOPT_FLASHLIGHT_COST; + thisTemp.bActive = FALSE; + refreshButtons(); + } +} + +void +buymenu_btn_Scope_clicked(CBuyMenu_BasicButton* arg_this) +{ + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + WEAPONOPT_SCOPE_COST, iExtraSlotsTemp, iPurchaseCountTemp)){ + CBuyMenu_BasicButton thisTemp = *arg_this; + // allow it and hide this button. + iBitsUpgradeTemp |= BITS_WEAPONOPT_SCOPE; + iExtraPriceTemp += WEAPONOPT_SCOPE_COST; + thisTemp.bActive = FALSE; + refreshButtons(); + } +} +void +buymenu_btn_Akimbo_clicked(CBuyMenu_BasicButton* arg_this) +{ + // Can we afford one more copy of this weapon? + weapondata_basic_t weaponRef = (*ary_weaponData[iWeaponTempID]); + + if(canBuyWeapon(iWeaponTempID, iExtraPriceTemp + weaponRef.iPrice, iExtraSlotsTemp + weaponRef.iSlots, iPurchaseCountTemp)){ + CBuyMenu_BasicButton thisTemp = *arg_this; + // allow it and hide this button. + iBitsUpgradeTemp |= BITS_WEAPONOPT_AKIMBO; + iExtraPriceTemp += weaponRef.iPrice; + iExtraSlotsTemp += weaponRef.iSlots; + thisTemp.bActive = FALSE; + refreshButtons(); + } +} + +// NOTICE +// Buying 'full load', even if we can't afford to fill this throwable to the max, +// still works if we can afford at least one more. +// This method checks to see the least that can be afforded between price, slots, +// and max count allowed for this weapon type, and uses that + closes the picked +// weapon in the buymenu if a purchase is made. +// "Full Load" is for throwables only. Counting grenades as that type too. +void +buymenu_btn_FullLoad_clicked(CBuyMenu_BasicButton* arg_this) +{ + // I'm not copying and pasting this stuff all over the place. + int buyCount = fullLoadCountToBuy(iWeaponTempID); + + if(buyCount >= 0){ + CBuyMenu_BasicButton thisTemp; + weapondata_basic_t weaponRef = (*ary_weaponData[iWeaponTempID]); + + int testPrice = (buyCount) * weaponRef.iPrice; + int testSlots = (buyCount) * weaponRef.iSlots; + + int finalExtraPrice = iExtraPriceTemp + testPrice; + int finalExtraSlots = iExtraSlotsTemp + testSlots; + + if(canBuyWeapon(iWeaponTempID, finalExtraPrice, finalExtraSlots, iPurchaseCountTemp)){ + thisTemp = *arg_this; + // allow it and hide this button. + iBitsUpgradeTemp |= BITS_WEAPONOPT_FULLLOAD; + iExtraPriceTemp += testPrice; + iExtraSlotsTemp += testSlots; + thisTemp.bActive = FALSE; + + // Go ahead and buy this now. + buymenu_btn_Buy_Weapon_clicked((CBuyMenu_BasicButton*)&buymenu_btn_WeaponOpt_Buy); + + refreshButtons(); + }else{ + // Couldn't afford the full load? + // How many throwables can I buy, given slot and (possible) money constraints? + int iSlotsAvailable = RULE_SLOTS_ALLOWED - (CONFIG_PLAYER_TOTALSLOTS + iExtraSlotsTemp); + int iMoneyAvailable; + if(RULE_MONEY_ALLOWED){ + iMoneyAvailable = CONFIG_PLAYER_MONEY - (CONFIG_PLAYER_TOTALCOST + iExtraPriceTemp); + }else{ + // signal that money is not something to worry about + iMoneyAvailable = -1; + } + + int numberAfforded = determineThrowableBuyCount(iWeaponTempID, iSlotsAvailable, iMoneyAvailable); + + if(numberAfforded > 0){ + //do something! + thisTemp = *arg_this; + //iBitsUpgradeTemp |= BITS_WEAPONOPT_FULLLOAD; + iPurchaseCountTemp = numberAfforded; + // no need for extra price/slot stuff! We'll make that from that + // altered 'iPurchaseCountTemp'. + // That is ever rarely anything besides '1'. Except for this case of + // course. + thisTemp.bActive = FALSE; + buymenu_btn_Buy_Weapon_clicked( (CBuyMenu_BasicButton*) &buymenu_btn_WeaponOpt_Buy); + + refreshButtons(); + } + } + + } +}//buymenu_btn_FullLoad_clicked + + +void +UI_BuyMenu_OnInit(void) +{ + // for macros below. + float flDeterminedHotkey; + + //safety. + UI_BuyMenu_ResetTempVariables(); + + //haven't yet. + boughtAnything = FALSE; + + if(UI_BuyMenu_InitDone == FALSE){ + //looks like we need to do this. proceed. + }else{ + //nevermind. + //Keep in mind some stuff (what's above) can run on any init call, even subsequent ones (re-opening the buy menu), since we might want to default some stuff + //like what was selected, temp buyopts clicked, etc. + return; + } + + iActiveLayer = 0i; + ary_btnTotal_softLength = 0i; + ary_layerFirstButton_softLength = 0i; + + // just in case? + for(int i = 0i; i < ary_layerButtonChoice.length; i+=1i){ + ary_layerButtonChoice[i] = NULL; + } + + + // buymenu_btn_Back = spawn(CBuyMenu_BasicButton); + // if the 1st layer is active (drawn to that one). Says "Cancel" there, but if on any deeper layer it reads "Go Back". + //buymenu_btn_Back.create("0 Cancel", 48, NULL, buymenu_btn_Back_clicked); + + INITIALIZE_BASICBUTTON(Back, "Cancel", "0", clrPaleBluePurple, &buymenu_btn_Back_clicked) + + + //INITIALIZE_BASICBUTTON(Buy, "2 Buy", 48+2, NULL, 0, NULL) + INITIALIZE_BASICBUTTON(Recentconfig, "Use New Config", "1", clrGreen, &buymenu_btn_UseNewConfig_clicked) + INITIALIZE_BASICBUTTON(Buy, "Buy", "2", clrPaleBlue, NULL) + INITIALIZE_BASICBUTTON(RemoveItem, "Remove Item", "3", clrPaleBlue, &buymenu_btn_RemoveItem_clicked) + INITIALIZE_BASICBUTTON(ResetConfig, "Reset Config", "4", clrPaleBlue, NULL) + INITIALIZE_BASICBUTTON(SaveConfig, "Save Config", "5", clrPaleBlue, NULL) + INITIALIZE_BASICBUTTON(LoadConfig, "Load Config", "6", clrPaleBlue, NULL) + INITIALIZE_BASICBUTTON(BuyRandom, "Buy Random", "7", clrGreen, NULL) + INITIALIZE_BASICBUTTON(Buy_Handguns, "Handguns", "1", clrPaleBlue, NULL) + INITIALIZE_BASICBUTTON(Buy_SMGs, "SMGs", "2", clrPaleBlue, NULL) + INITIALIZE_BASICBUTTON(Buy_Rifles, "Rifles", "3", clrPaleBlue, NULL) + INITIALIZE_BASICBUTTON(Buy_Shotguns, "Shotguns", "4", clrPaleBlue, NULL) + INITIALIZE_BASICBUTTON(Buy_SpecialPurpose, "Special Purpose", "5", clrPaleBlue, NULL) + + + // !!! INITIALIZE THE WEAPON-UPGRADE BUTTONS BEFORE THE WEAPONS THEMSELVES. Or else these will be missing at that point. + INITIALIZE_BASICBUTTON(WeaponOpt_Buy, "Buy", "1", clrGreen, &buymenu_btn_Buy_Weapon_clicked) + INITIALIZE_BASICBUTTON(WeaponOpt_Silencer, sprintf("Silencer %i", WEAPONOPT_SILENCER_COST), "2", clrPaleBlue, &buymenu_btn_Silencer_clicked) + INITIALIZE_BASICBUTTON(WeaponOpt_Lasersight, sprintf("Lasersight %i", WEAPONOPT_LASERSIGHT_COST), "3", clrPaleBlue, &buymenu_btn_Lasersight_clicked) + INITIALIZE_BASICBUTTON(WeaponOpt_Flashlight, sprintf("Flashlight %i", WEAPONOPT_FLASHLIGHT_COST), "4", clrPaleBlue, &buymenu_btn_Flashlight_clicked) + INITIALIZE_BASICBUTTON(WeaponOpt_Scope, sprintf("Scope %i", WEAPONOPT_SCOPE_COST), "5", clrPaleBlue, &buymenu_btn_Scope_clicked) + + // Yes, Akimbo and FullLoad use the same hotkey (number 6). They never appear on the same weapon, + // since Akimbo is only meant for some guns, and FullLoad is only meant for some melee weapons. + // TODO? And if these two were to support flexible prices (show what it costs for the currently selected weapon... akimbo & fullLoad can't be fixed to + // one constant for all weapons), their display text + prices would have to be shown as they're shown to the user. + INITIALIZE_BASICBUTTON(WeaponOpt_Akimbo, "Akimbo", "6", clrPaleBlue, &buymenu_btn_Akimbo_clicked) + INITIALIZE_BASICBUTTON(WeaponOpt_FullLoad, "FullLoad", "6", clrGreen, &buymenu_btn_FullLoad_clicked) + + buymenu_btn_WeaponOpt_Buy.vOnShow_Custom = &buymenu_btn_Buy_onShow; + + buymenu_btn_WeaponOpt_Silencer.vOnShow_Custom = &buymenu_btn_Silencer_onShow; + buymenu_btn_WeaponOpt_Lasersight.vOnShow_Custom = &buymenu_btn_Lasersight_onShow; + buymenu_btn_WeaponOpt_Flashlight.vOnShow_Custom = &buymenu_btn_Flashlight_onShow; + buymenu_btn_WeaponOpt_Scope.vOnShow_Custom = &buymenu_btn_Scope_onShow; + buymenu_btn_WeaponOpt_Akimbo.vOnShow_Custom = &buymenu_btn_Akimbo_onShow; + buymenu_btn_WeaponOpt_FullLoad.vOnShow_Custom = &buymenu_btn_FullLoad_onShow; + + + // TODO - ONGOING. As more weapons are entered, use this new condensed way + // to hook up to their info instead of using the hardcoded specifics below. + // Any other references to the button may be deleted thereafter. + + // This variable is expected for the _ADV version to work or else it would need to + // declare a new temp each time, just keep it around. + weapondata_basic_t tempWeapRef; + + + INITIALIZE_WEAPONBUTTON(GLOCK18, "1", clrPaleBlue, NULL, Handguns) + INITIALIZE_WEAPONBUTTON(SOCOMMK23, "2", clrPaleBlue, NULL, Handguns) + INITIALIZE_WEAPONBUTTON(DESERTEAGLE, "3", clrPaleBlue, NULL, Handguns) + INITIALIZE_WEAPONBUTTON(FIVESEVEN, "4", clrPaleBlue, NULL, Handguns) + INITIALIZE_WEAPONBUTTON(BERETTA, "5", clrPaleBlue, NULL, Handguns) + INITIALIZE_WEAPONBUTTON(AKIMBOCOLTS, "6", clrPaleBlue, NULL, Handguns) + INITIALIZE_WEAPONBUTTON(GLOCK20, "7", clrPaleBlue, NULL, Handguns) + INITIALIZE_WEAPONBUTTON(RUGERMK1, "8", clrPaleBlue, NULL, Handguns) + INITIALIZE_WEAPONBUTTON(RAGINGBULL, "9", clrPaleBlue, NULL, Handguns) + INITIALIZE_WEAPONBUTTON(CONTENDERG2, "A", clrPaleBlue, NULL, Handguns) + + + INITIALIZE_WEAPONBUTTON(MINIUZI, "1", clrPaleBlue, NULL, SMGs) + INITIALIZE_WEAPONBUTTON(MP5SD, "2", clrPaleBlue, NULL, SMGs) + INITIALIZE_WEAPONBUTTON(MP5K, "3", clrPaleBlue, NULL, SMGs) + + INITIALIZE_WEAPONBUTTON(STEYRTMP, "4", clrPaleBlue, NULL, SMGs) + INITIALIZE_WEAPONBUTTON(HKPDW, "5", clrPaleBlue, NULL, SMGs) + INITIALIZE_WEAPONBUTTON(UMP, "6", clrPaleBlue, NULL, SMGs) + + INITIALIZE_WEAPONBUTTON(SKORPION, "7", clrPaleBlue, NULL, SMGs) + INITIALIZE_WEAPONBUTTON(MAC10, "8", clrPaleBlue, NULL, SMGs) + + + INITIALIZE_WEAPONBUTTON(M4A1, "1", clrPaleBlue, NULL, Rifles) + INITIALIZE_WEAPONBUTTON(AK47, "2", clrPaleBlue, NULL, Rifles) + INITIALIZE_WEAPONBUTTON(STEYRAUG, "3", clrPaleBlue, NULL, Rifles) + INITIALIZE_WEAPONBUTTON(M16A4, "4", clrPaleBlue, NULL, Rifles) + INITIALIZE_WEAPONBUTTON(BARRETTM82, "5", clrPaleBlue, NULL, Rifles) + + + INITIALIZE_WEAPONBUTTON(BENELLIM3, "1", clrPaleBlue, NULL, Shotguns) + INITIALIZE_WEAPONBUTTON(USAS12, "2", clrPaleBlue, NULL, Shotguns) + INITIALIZE_WEAPONBUTTON(SPAS12, "3", clrPaleBlue, NULL, Shotguns) + INITIALIZE_WEAPONBUTTON(MOSSBERG500, "4", clrPaleBlue, NULL, Shotguns) + INITIALIZE_WEAPONBUTTON(SAWEDOFF, "5", clrPaleBlue, NULL, Shotguns) + + + // LATER - make purchaseable only if the gamemode is team/scenario. (mercs vs specialists) + INITIALIZE_WEAPONBUTTON(M61GRENADE, "1", clrPaleBlue, NULL, SpecialPurpose) + + INITIALIZE_WEAPONBUTTON(COMBATKNIFE, "2", clrPaleBlue, NULL, SpecialPurpose) + INITIALIZE_WEAPONBUTTON(M60, "3", clrPaleBlue, NULL, SpecialPurpose) + INITIALIZE_WEAPONBUTTON(KATANA, "4", clrPaleBlue, NULL, SpecialPurpose) + INITIALIZE_WEAPONBUTTON(SEALKNIFE, "5", clrPaleBlue, NULL, SpecialPurpose) + + //TODO - set these up. items are simpler than weapons and have no default behavior. + // in fact the kevlar just puts armor on the player at spawn, stealthshoes may as well + // be a "yes/no" toggle on the player. + // Last parameter is the cost instead of the buy category, since we don't have + // any weapondata to get the cost from. + // ...we still need the category too though. + //INITIALIZE_ITEMBUTTON_ADV(KEVLAR, "1", 48+1, clrPaleBlue, NULL, PlayerAccessory, 1900); + //INITIALIZE_ITEMBUTTON_ADV(STEALTHSHOES, "2", 48+2, clrPaleBlue, NULL, PlayerAccessory, 700); + + buymenu_btn_Back_updateText(); //just in case. + + buymenu_addbuttonToFirstLayer(&buymenu_btn_Recentconfig); + buymenu_addbuttonToFirstLayer(&buymenu_btn_Buy); + buymenu_addbuttonToFirstLayer(&buymenu_btn_RemoveItem); + buymenu_addbuttonToFirstLayer(&buymenu_btn_ResetConfig); + buymenu_addbuttonToFirstLayer(&buymenu_btn_SaveConfig); + buymenu_addbuttonToFirstLayer(&buymenu_btn_LoadConfig); + buymenu_addbuttonToFirstLayer(&buymenu_btn_BuyRandom); + + buymenu_addbutton(&buymenu_btn_Buy, &buymenu_btn_Buy_Handguns); + buymenu_addbutton(&buymenu_btn_Buy, &buymenu_btn_Buy_SMGs); + buymenu_addbutton(&buymenu_btn_Buy, &buymenu_btn_Buy_Rifles); + buymenu_addbutton(&buymenu_btn_Buy, &buymenu_btn_Buy_Shotguns); + buymenu_addbutton(&buymenu_btn_Buy, &buymenu_btn_Buy_SpecialPurpose); + + + setupRemoveButtonList(); + + // don't do this init process again. + UI_BuyMenu_InitDone = TRUE; + +}// UI_BuyMenu_OnInit + + + +//var float lastPrintoutTime = 0.0f; + +void +UI_BuyMenu_Update(player arg_player, vector vPos, vector vWindowSiz, float fFontSizeMulti) +{ + // If we leave spectator view (spawned and walking/aiming), disallow the buy menu. + // (could also check for "player.iState == PLAYER_STATE::SPAWNED" ) + if(getplayerkeyvalue(player_localnum, "*spec") == "0"){ + + UI_ChangeScreen(UI_SCREEN::NONE); + return; + } + + // Reset this. If the mouse is hovering over something we'll find out. + iHoveredButtonIndex = -1; + + int currentLayerSelectedIndex; + int btnToRender_index_global; + CBuyMenu_BasicButton someThing; + CBuyMenu_BasicButton previousLayerButton; + BOOL fIsSelected; + + // VGUI_Text( sprintf("%s - %s", "Free Specialists", serverkey("hostname") ), vPos + '16 64 0', '12 12', FONT_CON ); + + + // Checks for clicks be done separately + // Only check for buttons from the active layer. + + vector vButtonPos = [video_mins[0] + 5, video_mins[1] + video_res[1]/2, 0]; + vector vBtnPos = [0,0,0]; + + /* + if(time >= lastPrintoutTime){ + lastPrintoutTime = time + 2.0f; + + // anything routine? + } + */ + + //UI_BuyMenu_onInputEvent(); + + drawPlayerInventory(TRUE); + + for(int i = 0i; i <= iActiveLayer; i = i + 1i){ + //Adjust these as needed. These also show where to draw the "0 Cancel" button + //for the active layer (after the most recent button; below). + //vector vBtnPos; + vBtnPos.z = 0; + if(i == 0){ + + if(ary_layerButtonChoice[i] == NULL){ + currentLayerSelectedIndex = -1; + }else{ + someThing = *ary_layerButtonChoice[i]; + currentLayerSelectedIndex = someThing.iGlobalIndex; + } + + vBtnPos.x = (int)vButtonPos.x; //default pos. + vBtnPos.y = (int)vButtonPos.y; + + for(int i2 = 0i; i2 < ary_layerFirstButton_softLength; i2++){ + CBuyMenu_BasicButton tempButton = *ary_layerFirstButton[i2]; + fIsSelected = (tempButton.iGlobalIndex == currentLayerSelectedIndex); + + (*ary_layerFirstButton[i2]).vOnRender_Base(vBtnPos, i, i2, fIsSelected); + + vBtnPos.y += (vButtonSizStandard.y + 1); + + } + + }else{ + vBtnPos.x = (int)vButtonPos.x + (vButtonSizStandard.x + 1) * i; //slide the X-pos however far given this layer. + vBtnPos.y = (int)vButtonPos.y; + // All other layers only render buttons that the previous layer (selected button there) tells them to. + + previousLayerButton = *ary_layerButtonChoice[i - 1i]; + + if(ary_layerButtonChoice[i] == NULL){ + currentLayerSelectedIndex = -1; + }else{ + someThing = *ary_layerButtonChoice[i]; + currentLayerSelectedIndex = someThing.iGlobalIndex; + } + + for(int i2 = 0i; i2 < previousLayerButton.ary_btn_softLength; i2 = i2+1i){ + btnToRender_index_global = previousLayerButton.ary_btn_index[i2]; + + CBuyMenu_BasicButton tempButton2_aaa = *ary_btnTotal[btnToRender_index_global]; + + //NOTICE - we can only check for bActive in the active layer. Any others must show + // all buttons yet. + if(i == iActiveLayer && tempButton2_aaa.bActive == FALSE){ + //skip showing this one. + continue; + } + + fIsSelected = (btnToRender_index_global == currentLayerSelectedIndex); + + (*ary_btnTotal[btnToRender_index_global]).vOnRender_Base(vBtnPos, i, i2, fIsSelected); + vBtnPos.y += (vButtonSizStandard.y + 1); + + }// for i2 in this layer's buttons. + } + + if(i == iActiveLayer){ + int backButtonRow; + // Draw the "0. Cancel" button. Special purpose. + // buymenu_renderButton(&buymenu_btn_Back, vBtnPos, 0.86); + + // Whatever the size of the latest layer is. Since that index itself wasn't used (minus 1 is the most recently used index; + // we're putting a button AFTER that one). + if(iActiveLayer > 0){ + previousLayerButton = *ary_layerButtonChoice[iActiveLayer - 1i]; + backButtonRow = previousLayerButton.ary_btn_softLength; + }else{ + backButtonRow = ary_layerFirstButton_softLength; + } + + buymenu_btn_Back.vOnRender_Base(vBtnPos, i, backButtonRow, fIsSelected); + vBtnPos.y += (vButtonSizStandard.y + 1); + } + + + }// for(i from 0 to iActiveLayer, inclusive) + + + // TEST! + // DRAWFLAG_ADDITIVE? NORMAL? Which one? + //drawsubpic([25,25], [128,48], "sprites/weapons/glock18.spr_0.tga", [0,0], [128/128,48/48], [1,1,1], 1, DRAWFLAG_ADDITIVE); + //drawsubpic([16,128], [11,16], "sprites/numbers.spr_0.tga", [1/112,0], [11/112,16/16], [1,1,1], 1, DRAWFLAG_ADDITIVE); + //drawsubpic([16,128], [127*0.1,16], "sprites/numbers.spr_0.tga", [0.5,0], [0.1,16/16], [1,1,1], 1, DRAWFLAG_ADDITIVE); + + drawPlayerInventory_TopBar(-1, TRUE); + +}//UI_BuyMenu_Update + + +// Given a single-character string, like "3" or "A", determine the keycode that +// should be tied to it. For uppercase characters, force the lowercase one, as the +// user is certainly pushing that one. +float determineHotkeyFromChar(string arg_sHotkeyDisplay){ + if(strlen(arg_sHotkeyDisplay) != 0){ + float charCode = str2chr(arg_sHotkeyDisplay, 0); + if(charCode >= 48 && charCode <= 48+9){ + // numeric? Straightforward + return charCode; + }else if(charCode >= 65 && charCode <= 65+25){ + // uppercase? Convert to lowercase for charCode. + return charCode + 32; + }else if(charCode >= 97 && charCode <= 97+25){ + // lowercase? Leave it as it is + return charCode; + }else{ + // ??? + return -1; + } + }else{ + // blank string given? + return -1; + } +} + + diff --git a/src/client/ui_eventgrabber.qc b/src/client/ui_eventgrabber.qc index ea1692b..f671676 100644 --- a/src/client/ui_eventgrabber.qc +++ b/src/client/ui_eventgrabber.qc @@ -9,12 +9,9 @@ // Simple UIWidget to absorb mouse-click and key-press events while in -// the MoTD or the buysidemenu screens. +// the MoTD or the buymenu screens. // Do not give me child elements! Behavior for handling children removed. -// assuming these are provided elsewhere, works for now. -extern var BOOL VGUI_BuySideMenu_InitDone; -void BuySideMenu_onInputEvent(void); class CUIEventGrabber:CUIWidget @@ -52,8 +49,8 @@ CUIEventGrabber::Input(float flEVType, float flKey, float flChar, float flDevID) // TODO TODO TODO! Check for mouse-clicks (K_MOUSE1) and key presses by separate methods? // Checking for keypresses on a mouse-click or for mouse-coords on a keypress on every // single button (even a mouse, yes/no check every time) is unnecessary. - if(pSeatLocal->fVGUI_Display == BUYSIDEMENU){ - BuySideMenu_onInputEvent(); + if(pSeatLocal->m_flUI_Display == UI_SCREEN::BUYMENU){ + UI_BuyMenu_onInputEvent(); } break; diff --git a/src/client/vgui_buysidemenu.h b/src/client/vgui_buysidemenu.h deleted file mode 100644 index d3f5a12..0000000 --- a/src/client/vgui_buysidemenu.h +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/client/vgui_motd.qc b/src/client/vgui_motd.qc index 8aa6a56..4d9cc8c 100644 --- a/src/client/vgui_motd.qc +++ b/src/client/vgui_motd.qc @@ -63,8 +63,8 @@ Colors_RGB8_to_HEX(vector color) void VGUI_MessageOfTheDay(player arg_player, vector vPos, vector vWindowSiz, float fFontSizeMulti ) { static void MessageOfTheDay_ButtonOK( void ) { - printfline("HEY ButtonOK got CLICKED!!!"); - VGUI_ChangeScreen(VGUI_SCREEN::BUYSIDEMENU); + printfline("HEY ButtonOK got CLICKED"); + UI_ChangeScreen(UI_SCREEN::BUYMENU); } //TAGGG - start from this location instead. diff --git a/src/client/vguiobjects.qc b/src/client/vguiobjects.qc index 9275098..0253f2c 100644 --- a/src/client/vguiobjects.qc +++ b/src/client/vguiobjects.qc @@ -108,7 +108,7 @@ Draws a button, returns whether or not a mouse is hovering over it (for inherita ==================== */ -//*** NOTE! Buysidemenu buttons don't use this! Only the MoTD close button, at least so far. +//*** NOTE! BuyMenu buttons don't use this! Only the MoTD close button, at least so far. float VGUI_Button( string sLabel, void() vFunction, vector vPosition, vector vSize) { vector vLabelPos; @@ -125,7 +125,7 @@ float VGUI_Button( string sLabel, void() vFunction, vector vPosition, vector vSi if ( VGUI_CheckMouse( vPosition, vSize ) ) { - //pSeatLocal->fVGUI_Display + //pSeatLocal->m_flUI_Display if (pSeatLocal->m_inputMouseClicked == TRUE) { vFunction(); diff --git a/src/server/init.qc b/src/server/init.qc index a1127b4..dee1556 100644 --- a/src/server/init.qc +++ b/src/server/init.qc @@ -192,7 +192,7 @@ Game_Worldspawn(void) // The message of the day. // This saves the contents of the MoTD text file (path given by CVar motdfile) to a series of // serverinfo entries named motdline0, 1, 2, ... for reading back in client/vgui.c from the server - // at client-connect time (CSQC_VGUI_Init) to go in the MoTD window whenever needed. + // at client-connect time (UI_Init) to go in the MoTD window whenever needed. localcmd(sprintf("echo [MOTD] Loading %s.\n", autocvar_motdfile)); filestream fmMOTD = fopen(autocvar_motdfile, FILE_READ); if (fmMOTD >= 0) { diff --git a/src/shared/event_custom.h b/src/shared/event_custom.h index 413a939..b752485 100644 --- a/src/shared/event_custom.h +++ b/src/shared/event_custom.h @@ -24,14 +24,6 @@ void CSEv_TS_playerEquippedWeapon_ii(int newWeaponEquipped, BOOL useAkimbo); -#ifdef SERVER -void TS_PlayInsertShellSound(player pl); -#else -void TS_PlayInsertShellSound(player pl); -void EV_TS_PlayInsertShellSound(player pl); -#endif - - #ifdef SERVER void TS_resetViewModel(player pl); #else diff --git a/src/shared/event_custom.qc b/src/shared/event_custom.qc index 7968611..001ac18 100644 --- a/src/shared/event_custom.qc +++ b/src/shared/event_custom.qc @@ -235,35 +235,6 @@ CSEv_TS_playerEquippedWeapon_ii(int newWeaponEquipped, BOOL useAkimbo){ -#ifdef SERVER -// Send a request to change the animation of the viewmodel directly. -void -TS_PlayInsertShellSound(player pl){ - /* - WriteByte( MSG_MULTICAST, SVC_CGAMEPACKET ); - WriteByte( MSG_MULTICAST, EVENT_TS::PLAY_INSERT_SHELL_SND ); - msg_entity = pl; - multicast( [0,0,0], MULTICAST_ONE ); - */ -} - -#else -void -TS_PlayInsertShellSound(player pl){ - EV_TS_PlayInsertShellSound(pl); -} -//CLIENTSIDE. now what do I do over here? -void -EV_TS_PlayInsertShellSound(player pl){ - //TODO - lower attenuation maybe? - // Nevermind, this is a client-only sound for now anyway. - localsound("weapons/insert-shell.wav", CHAN_AUTO, 1.0f); -} -#endif - - - - // The server may want to tell the client to reset its viewmodel. // DUMMIED - nevermind that for now, assuming the logic is called from server/client // individually like a lot of weapon's logic. @@ -334,19 +305,22 @@ EV_TS_resetPlayer(player pl, BOOL resetInventory){ #ifdef CLIENT // Called by the GameRules, PlayerDeath, for the client to do something as soon as // possible. +// WHOOPS. All vars since have been dummied or changes here are ineffective, +// keeping the event in case it has some use later. void EV_PlayerDeath(void){ printfline("EV_PlayerDeath"); + // Require a tiny amount of time and a mouse release before a respawn, so that // dying with the mouse held down isn't enough to trigger a respawn request. - pSeatLocal->m_bNeedPrimaryRelease = TRUE; - pSeatLocal->m_flReleaseTime = time + 0.15; + //pSeatLocal->m_bNeedPrimaryRelease = TRUE; + //pSeatLocal->m_flReleaseTime = time + 0.15; // Unfortunately not as effective as it may look. // On the player using "kill" in console, a CSQC_Parse_Damage call happens shortly // after this PlayerDeath one, somehow. Stopping damage-drawing on the "*dead" key // being 1 works. - pSeat->m_flDamageAlpha = 0; + //pSeat->m_flDamageAlpha = 0; } #endif diff --git a/src/shared/input.qc b/src/shared/input.qc index b4d49b9..5167408 100644 --- a/src/shared/input.qc +++ b/src/shared/input.qc @@ -36,12 +36,11 @@ Game_Input(void) // If not, grab pSeat->m_ePlayer instead! player pl = (player)self; - if(pl.iState != PLAYER_STATE::SPAWNED){ // not ingame (fake spectator)? Do another check instead: spawning. #ifdef CLIENT if((input_buttons & INPUT_BUTTON0) && !(pl.gflags & GF_SEMI_TOGGLED) ){ - if(pSeatLocal->fVGUI_Display == VGUI_SCREEN::NONE && pl.iState != PLAYER_STATE::SPAWNED){ + if(pSeatLocal->m_flUI_Display == UI_SCREEN::NONE && pl.iState != PLAYER_STATE::SPAWNED){ sendevent( "GamePlayerSpawn", ""); } } @@ -52,14 +51,57 @@ Game_Input(void) pl.gflags &= ~GF_SEMI_TOGGLED; } #endif + // client or server, don't pay attention to the rest of this file if not spawned return; } +#ifdef CLIENT + else{ + // not spawned? Some notes on possible things to involve, all dummied for now + + + // This was removed? Legacy VGUI + // If we are inside a UI, don't let the client do stuff outside + // (looks like this is no longer necessary) + /* + if (pl.iState != PLAYER_STATE::SPAWNED && pSeatLocal->m_flUI_Display != UI_SCREEN::NONE){ + pSeat->m_flInputBlockTime = time + 0.2; + } + */ + + // No need to check for calling TS_HUD_DrawWeaponSelect_CheckClick or + // HUD_DrawWeaponSelect_Trigger here, Nuclide calls the latter which works + // fine. + + // CRITICAL. + // DISABLED. + // This is trying to close weaponselect on detecting a right-click, but it + // has issues. + // Idea is, this needs to *absorb* the right-click, and stop it from reaching + // the rest of the client and server to work with weapons, like a change-ironsight + // order. + // This might stop the client weapon logic from seeing the right click, but not + // the server. + // It appears there is no way to stop that without the FTE built-in event method + // CSQC_Input_Frame (defined by Nuclide) letting the gamemod block right-click + // inputs per some condition, like weapon-select being up. + /* + if(pSeat->m_iInputAttack2){ //input_buttons & INPUT_BUTTON3){ + if(HUD_CloseWeaponSelect(TRUE)){ + pSeat->m_flInputBlockTime = time + 0.2; + input_impulse = 0; + input_buttons = 0; + pSeat->m_iInputAttack2 = FALSE; + }else{ + //pSeat->m_iInputAttack2 = TRUE; + } + } + */ + }// pi.iState checks +#endif // Must be ingame to reach beyond here - - //TAGGG - good place for this? Cloned from w_attack_next as a separate counter // for akimbo firing to use. // This method, Game_Input, is called by Nuclide's pmove.qc in the same place @@ -139,8 +181,18 @@ Game_Input(void) #endif - - + // !!! + // An override for this to go in CSQC_Input_Frame would be very nice I think, + // unless there is some other way that I'm missing. + /* + if (pSeatLocal->m_iInputSpeed == TRUE) { + //input_buttons |= INPUT_BUTTON9; + input_buttons |= INPUT_BUTTON7; + //self.flags |= FL_SNEAK; + }else{ + //self.flags &= ~FL_SNEAK; + } + */ // TS way, weapon thinks happen alongside checking inputs diff --git a/src/shared/pmove.qc b/src/shared/pmove.qc index 6846077..eb4ab59 100644 --- a/src/shared/pmove.qc +++ b/src/shared/pmove.qc @@ -301,9 +301,9 @@ player::Physics_MaxSpeed(void) return targetSpeed; } - //FL_CROUCHING + // Sneak? if (input_buttons & INPUT_BUTTON7) { - //sneak forgets slot limits. + // sneak forgets slot limits. targetSpeed *= 0.38; }else{ // speed factor of 0 means 55% speed. diff --git a/src/shared/sound_pitched.qc b/src/shared/sound_pitched.qc index 27d91fd..739092c 100644 --- a/src/shared/sound_pitched.qc +++ b/src/shared/sound_pitched.qc @@ -118,43 +118,43 @@ const string sfx_pitched_s[] = "weapons/beretta/fire.wav", "weapons/beretta/fire-sil.wav", "weapons/contender/fire.wav", - "weapons/deagle/fire-sil.wav", "weapons/deagle/fire.wav", - "weapons/fnh/fnh-fire-sil.wav", + "weapons/deagle/fire-sil.wav", "weapons/fnh/fnh-fire.wav", - "weapons/glock/glock-fire-sil.wav", + "weapons/fnh/fnh-fire-sil.wav", "weapons/glock/glock-fire.wav", - "weapons/glock22/glock22-fire-sil.wav", + "weapons/glock/glock-fire-sil.wav", "weapons/glock22/glock22-fire.wav", - "weapons/pdw/fire-sil.wav", + "weapons/glock22/glock22-fire-sil.wav", "weapons/pdw/fire.wav", + "weapons/pdw/fire-sil.wav", "weapons/katana/miss.wav", "weapons/katana/miss1.wav", - "weapons/m4/m4-fire-sil.wav", "weapons/m4/m4-fire.wav", + "weapons/m4/m4-fire-sil.wav", "weapons/m16/fire.wav", "weapons/m60/m60-fire.wav", - "weapons/mac10/mac10-fire-sil.wav", "weapons/mac10/mac10-fire.wav", - "weapons/uzi/uzi-fire-sil.wav", + "weapons/mac10/mac10-fire-sil.wav", "weapons/uzi/uzi-fire.wav", + "weapons/uzi/uzi-fire-sil.wav", "weapons/mossberg/fire.wav", - "weapons/mp5k/mp5k-fire-sil.wav", "weapons/mp5k/mp5k-fire.wav", + "weapons/mp5k/mp5k-fire-sil.wav", "weapons/mp5sd/mp5sd-fire.wav", "weapons/bull/fire01.wav", "weapons/ruger/fire.wav", "weapons/sawedoff/fire.wav", "weapons/skorpion/fire.wav", - "weapons/mk23/mk23-fire-sil.wav", "weapons/mk23/mk23-fire.wav", + "weapons/mk23/mk23-fire-sil.wav", "weapons/spas12/spas12-fire.wav", - "weapons/aug/aug-fire-sil.wav", "weapons/aug/aug-fire.wav", - "weapons/tmp/fire-sil.wav", + "weapons/aug/aug-fire-sil.wav", "weapons/tmp/fire.wav", - "weapons/ump/ump-fire-sil.wav", + "weapons/tmp/fire-sil.wav", "weapons/ump/ump-fire.wav", + "weapons/ump/ump-fire-sil.wav", "weapons/usas/usas-fire.wav", "explo/explode.wav", "explo/explode1.wav", diff --git a/src/shared/weapons.qc b/src/shared/weapons.qc index e0e7e06..dca3765 100644 --- a/src/shared/weapons.qc +++ b/src/shared/weapons.qc @@ -531,7 +531,6 @@ weapon_shotgun_onThink_reloadLogic(player pl, weapondata_gun_t* basePRef, weapon if(pl.shotgunAddAmmoSoundTime != -1 && pl.w_attack_next <= pl.shotgunAddAmmoSoundTime){ - //TS_PlayInsertShellSound(pl); //TS_Weapons_PlaySoundChannelDirect(pl, "weapons/insert-shell.wav", CHAN_AUTO); // TODO: if you want other players to hear this, the server should play it for all players diff --git a/src/shared/weapons/weapon_glock18.qc b/src/shared/weapons/weapon_glock18.qc index 0b13c63..cd4bc9d 100644 --- a/src/shared/weapons/weapon_glock18.qc +++ b/src/shared/weapons/weapon_glock18.qc @@ -225,7 +225,7 @@ w_glock18_hud(void) } -// NOPE! Handled by the buysidemenu, could make this give the instructions for drawing the +// NOPE! Handled by the BuyMenu, could make this give the instructions for drawing the // button with the icon if really wanted void w_glock18_hudpic(int selected, vector pos, float a) diff --git a/src/shared/weapons/weapon_karate.qc b/src/shared/weapons/weapon_karate.qc index 9594061..4ccb446 100644 --- a/src/shared/weapons/weapon_karate.qc +++ b/src/shared/weapons/weapon_karate.qc @@ -62,7 +62,6 @@ weapondata_basic_t weapon_karate = - void w_karate_precache(void) { diff --git a/src/shared/weapons/weapon_katana.qc b/src/shared/weapons/weapon_katana.qc index 60e43a8..b7fec44 100644 --- a/src/shared/weapons/weapon_katana.qc +++ b/src/shared/weapons/weapon_katana.qc @@ -53,9 +53,6 @@ weapondata_melee_t weapon_katana = - - - void w_katana_precache(void) {