summaryrefslogtreecommitdiffstats
path: root/src/gui.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-03 23:51:02 +0100
committersalmonik <salmonik@tuta.io>2026-11-03 23:51:02 +0100
commit95b5be2299b332917ae63c45252cb9744a3460cd (patch)
tree1da6d89d8ddf9f724368738a4969f8dd308cbcce /src/gui.cpp
parentAI: treat scripted NPCs as neutral; Lamarr neutral (diff)
downloadhl2h-95b5be2299b332917ae63c45252cb9744a3460cd.tar.gz
hl2h-95b5be2299b332917ae63c45252cb9744a3460cd.zip
World: add skybox changer
New Visuals -> Skybox card with a runtime sv_skyname override using the same mechanism as the stock skybox_swapper entity. The choice list is the HL2 skybox set extracted from the game VPKs. The map's own sky is captured from loaded materials (SkyBox group, parsing skybox/<name>... face names) before the first override, so turning the feature off or picking "Map default" restores it; a level change restores it implicitly. Sky changes invalidate the world tint so new sky materials are tinted as well. GUI: add a CK_CHOICE control (value box with < / > zones).
Diffstat (limited to '')
-rw-r--r--src/gui.cpp66
1 files changed, 63 insertions, 3 deletions
diff --git a/src/gui.cpp b/src/gui.cpp
index aa47868..5fb8fa7 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -183,7 +183,8 @@ enum CtrlKind {
183 CK_SECTION, 183 CK_SECTION,
184 CK_INFO, 184 CK_INFO,
185 CK_BUTTON, 185 CK_BUTTON,
186 CK_COLOR 186 CK_COLOR,
187 CK_CHOICE
187}; 188};
188 189
189enum CtrlAction { ACT_NONE = 0, ACT_RELOAD, ACT_RESET }; 190enum CtrlAction { ACT_NONE = 0, ACT_RELOAD, ACT_RESET };
@@ -195,6 +196,8 @@ struct Ctrl {
195 bool *bval; // CK_TOGGLE 196 bool *bval; // CK_TOGGLE
196 int *ival; // CK_SLIDER 197 int *ival; // CK_SLIDER
197 int *rgb; // CK_COLOR: three ints, 0..255 198 int *rgb; // CK_COLOR: three ints, 0..255
199 const char *const *opts; // CK_CHOICE: option labels
200 int nopts;
198 int min, max; 201 int min, max;
199 int action; // CK_BUTTON 202 int action; // CK_BUTTON
200 bool zero_unlimited; // slider: value 0 displays as "All" 203 bool zero_unlimited; // slider: value 0 displays as "All"
@@ -253,6 +256,8 @@ static void add_ctrl(int card, int kind, const char *label, const char *desc,
253 c.action = action; 256 c.action = action;
254 c.zero_unlimited = false; 257 c.zero_unlimited = false;
255 c.rgb = nullptr; 258 c.rgb = nullptr;
259 c.opts = nullptr;
260 c.nopts = 0;
256 c.hue = 0.0f; 261 c.hue = 0.0f;
257 c.sat = 0.0f; 262 c.sat = 0.0f;
258 c.val = 1.0f; 263 c.val = 1.0f;
@@ -282,11 +287,19 @@ static void add_color(int card, const char *label, const char *desc,
282 add_ctrl(card, CK_COLOR, label, desc, 0, 255, nullptr, nullptr, ACT_NONE); 287 add_ctrl(card, CK_COLOR, label, desc, 0, 255, nullptr, nullptr, ACT_NONE);
283 g_ctrls[i].rgb = rgb; 288 g_ctrls[i].rgb = rgb;
284} 289}
290static void add_choice(int card, const char *label, const char *desc,
291 const char *const *opts, int nopts, int *value) {
292 int i = g_nctrl;
293 add_ctrl(card, CK_CHOICE, label, desc, 0, nopts > 0 ? nopts - 1 : 0,
294 nullptr, value, ACT_NONE);
295 g_ctrls[i].opts = opts;
296 g_ctrls[i].nopts = nopts;
297}
285 298
286static int ctrl_val(const Ctrl &c) { 299static int ctrl_val(const Ctrl &c) {
287 if (c.kind == CK_TOGGLE && c.bval) 300 if (c.kind == CK_TOGGLE && c.bval)
288 return *c.bval ? 1 : 0; 301 return *c.bval ? 1 : 0;
289 if (c.kind == CK_SLIDER && c.ival) 302 if ((c.kind == CK_SLIDER || c.kind == CK_CHOICE) && c.ival)
290 return *c.ival; 303 return *c.ival;
291 return 0; 304 return 0;
292} 305}
@@ -294,7 +307,7 @@ static void ctrl_set(Ctrl &c, int v) {
294 if (c.kind == CK_TOGGLE && c.bval) { 307 if (c.kind == CK_TOGGLE && c.bval) {
295 *c.bval = v != 0; 308 *c.bval = v != 0;
296 config_save(); 309 config_save();
297 } else if (c.kind == CK_SLIDER && c.ival) { 310 } else if ((c.kind == CK_SLIDER || c.kind == CK_CHOICE) && c.ival) {
298 if (v < c.min) v = c.min; 311 if (v < c.min) v = c.min;
299 if (v > c.max) v = c.max; 312 if (v > c.max) v = c.max;
300 if (*c.ival != v) { 313 if (*c.ival != v) {
@@ -420,6 +433,13 @@ static void build_cards() {
420 add_toggle(fog, "Remove fog", 433 add_toggle(fog, "Remove fog",
421 "Disable fog entirely instead of recolouring it.", &g_fog_disable); 434 "Disable fog entirely instead of recolouring it.", &g_fog_disable);
422 435
436 int sky = add_card(2, &g_skybox, "Skybox",
437 "Swap the skybox at runtime through sv_skyname. The "
438 "map's own sky comes back on level change.",
439 true);
440 add_choice(sky, "Sky", "Pick a skybox from the HL2 set.", skybox_options(),
441 skybox_option_count(), &g_skybox_choice);
442
423 int spread = add_card(3, &g_spread, "Spread control", 443 int spread = add_card(3, &g_spread, "Spread control",
424 "Choose a server shot seed that tightens the cone.", 444 "Choose a server shot seed that tightens the cone.",
425 true); 445 true);
@@ -835,6 +855,8 @@ static int header_h(const Card &c) {
835static int label_max_w(const Ctrl &c) { 855static int label_max_w(const Ctrl &c) {
836 if (c.kind == CK_SLIDER) 856 if (c.kind == CK_SLIDER)
837 return S(214.0f); 857 return S(214.0f);
858 if (c.kind == CK_CHOICE)
859 return card_content_w() - S(16.0f) - S(250.0f);
838 return card_content_w() - S(16.0f) - S(110.0f); 860 return card_content_w() - S(16.0f) - S(110.0f);
839} 861}
840 862
@@ -1409,6 +1431,25 @@ static void handle_mouse_click() {
1409 } 1431 }
1410 return; 1432 return;
1411 } 1433 }
1434 if (ct.kind == CK_CHOICE) {
1435 int base = label_row_h(ct);
1436 Rect box{cr.x + cr.w - S(238.0f),
1437 by + (base - S(24.0f)) / 2, S(222.0f), S(24.0f)};
1438 if (box.has(mx, my)) {
1439 int v = ctrl_val(ct);
1440 if (mx < box.x + S(36.0f))
1441 v--;
1442 else if (mx >= box.x + box.w - S(36.0f))
1443 v++;
1444 if (v < 0) v = 0;
1445 if (ct.nopts > 0 && v >= ct.nopts) v = ct.nopts - 1;
1446 if (v != ctrl_val(ct)) {
1447 *ct.ival = v;
1448 config_save();
1449 }
1450 }
1451 return;
1452 }
1412 if (ct.kind == CK_BUTTON) { 1453 if (ct.kind == CK_BUTTON) {
1413 int bw = button_w(ct.label); 1454 int bw = button_w(ct.label);
1414 Rect b{cr.x + cr.w - S(16.0f) - bw, 1455 Rect b{cr.x + cr.w - S(16.0f) - bw,
@@ -1799,6 +1840,25 @@ static void draw_card(const Rect &clip, int index, int y) {
1799 outline(sw, picker_open_for(ct) ? C_ACCENT : C_BORDER, &clip); 1840 outline(sw, picker_open_for(ct) ? C_ACCENT : C_BORDER, &clip);
1800 if (picker_open_for(ct)) 1841 if (picker_open_for(ct))
1801 draw_picker(clip, cr, ct, by); 1842 draw_picker(clip, cr, ct, by);
1843 } else if (ct.kind == CK_CHOICE) {
1844 int v = ctrl_val(ct);
1845 const char *name = (ct.opts && v >= 0 && v < ct.nopts)
1846 ? ct.opts[v]
1847 : "?";
1848 Rect box{cr.x + cr.w - S(238.0f),
1849 by + (base_h - S(24.0f)) / 2, S(222.0f), S(24.0f)};
1850 fill(box, Col{45, 50, 60, 255}, &clip);
1851 outline(box, C_BORDER, &clip);
1852 int ty = box.y + (box.h - g_body_h) / 2;
1853 text_in(clip, box.x + S(8.0f), ty, "<", g_font_body, g_body_h, 0,
1854 C_DIM);
1855 text_in(clip, box.x + box.w - S(16.0f), ty, ">", g_font_body, g_body_h,
1856 0, C_DIM);
1857 int w = text_w(name, g_body_h);
1858 int tx = box.x + (box.w - w) / 2;
1859 if (tx < box.x + S(24.0f))
1860 tx = box.x + S(24.0f);
1861 text_in(clip, tx, ty, name, g_font_body, g_body_h, 0, C_TEXT);
1802 } 1862 }
1803 } 1863 }
1804 by += rh; 1864 by += rh;