You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

418 lines
13KB

  1. /* ---------------------------------------------------------------------------|
  2. *
  3. * Distributed under the CC0 public domain license.
  4. * By Alison G. Watson. Attribution is encouraged, though not required.
  5. * See licenses/cc0.txt for more information.
  6. *
  7. * ---------------------------------------------------------------------------|
  8. *
  9. * Settings configuration UI.
  10. *
  11. * ---------------------------------------------------------------------------|
  12. */
  13. #include "common.h"
  14. #include "p_player.h"
  15. #include "w_world.h"
  16. /* Types ------------------------------------------------------------------- */
  17. enum {
  18. _left = 2,
  19. _rght = 280,
  20. };
  21. enum {
  22. lxh_max = 10,
  23. lxb_max = 13,
  24. };
  25. /* all members are ordered by how many types use them */
  26. struct setting {
  27. /* used by all */
  28. script void (*cb)(struct set_parm const *sp);
  29. /* used by any with text */
  30. cstr text;
  31. /* used by any with a variable */
  32. union {
  33. script bool (*b)(struct set_parm const *sp, bool *v);
  34. script i32 (*i)(struct set_parm const *sp, i32 *v);
  35. script k32 (*k)(struct set_parm const *sp, k32 *v);
  36. } cb_g;
  37. script bool (*cb_e)(struct setting const *st, struct player *p);
  38. /* used by any with a scalar */
  39. union {
  40. struct {i32 min, max;} i;
  41. struct {k32 min, max;} k;
  42. } bnd;
  43. cstr suff;
  44. /* used in special cases */
  45. u32 fill;
  46. i32 pclass;
  47. };
  48. struct set_parm {
  49. struct player *p;
  50. struct gui_state *g;
  51. i32 x, y;
  52. struct setting const *st;
  53. };
  54. /* Static Functions -------------------------------------------------------- */
  55. #define SG_clBody(type, name, suff) \
  56. script static \
  57. type SG_cl##name(struct set_parm const *sp, type *v) { \
  58. str cvar = l_strcpy2(CVAR, sp->st->text); \
  59. if(v) {sp->p->set##suff(cvar, *v); return *v;} \
  60. else {return sp->p->get##suff(cvar);} \
  61. }
  62. #define SG_svBody(type, name, suff) \
  63. script static \
  64. type SG_sv##name(struct set_parm const *sp, type *v) { \
  65. str cvar = l_strcpy2(CVAR, sp->st->text); \
  66. if(v) {ACS_Set##suff(cvar, *v); return *v;} \
  67. else {return ACS_Get##suff(cvar);} \
  68. }
  69. SG_clBody(bool, Boole, CVarI)
  70. SG_clBody(i32, Integ, CVarI)
  71. SG_clBody(k32, Fixed, CVarK)
  72. SG_svBody(bool, Boole, CVar)
  73. SG_svBody(i32, Integ, CVar)
  74. SG_svBody(k32, Fixed, CVarFixed)
  75. script static
  76. bool SG_autoBuy(struct set_parm const *sp, bool *v) {
  77. i32 which = sp->st->text[strlen(sp->st->text) - 1] - '1';
  78. if(v) {tog_bit(sp->p->autobuy, which); P_Data_Save(sp->p);}
  79. return get_bit(sp->p->autobuy, which);
  80. }
  81. script static
  82. bool SG_doneIntro(struct set_parm const *sp, bool *v) {
  83. if(v) {sp->p->done_intro ^= sp->p->pclass; P_Data_Save(sp->p);}
  84. return sp->p->done_intro & sp->p->pclass;
  85. }
  86. script static
  87. bool SE_server(struct setting const *st, struct player *p) {
  88. return p->num == 0;
  89. }
  90. script static
  91. void S_empty(struct set_parm const *sp) {
  92. }
  93. script static
  94. void S_label(struct set_parm const *sp) {
  95. char buf[64]; lstrcpy2(buf, LANG, sp->st->text);
  96. PrintTextChS(LC(buf));
  97. PrintText(s_smallfnt, sp->g->defcr,
  98. sp->g->ox + _left,1, sp->g->oy + sp->y,1);
  99. }
  100. script static
  101. void S_boole(struct set_parm const *sp) {
  102. bool v = sp->st->cb_g.b(sp, nil);
  103. S_label(sp);
  104. if(G_Button_HId(sp->g, sp->y, v ? LC(LANG "ON") : LC(LANG "OFF"),
  105. _rght - gui_p.btnlist.w, sp->y, Pre(btnlist),
  106. .fill = {&CBIState(sp->g)->settingsfill, sp->st->fill})) {
  107. v = !v;
  108. sp->st->cb_g.b(sp, &v);
  109. }
  110. }
  111. script static
  112. void S_integ(struct set_parm const *sp) {
  113. char suff[32]; lstrcpy2(suff, LANG "st_suff_", sp->st->suff);
  114. i32 diff, v = sp->st->cb_g.i(sp, nil);
  115. S_label(sp);
  116. if((diff = G_Slider_HId(sp->g, sp->y, _rght - gui_p.slddef.w, sp->y,
  117. sp->st->bnd.i.min, sp->st->bnd.i.max, v, true,
  118. .suf = LC(suff)))) {
  119. v += diff;
  120. sp->st->cb_g.i(sp, &v);
  121. }
  122. }
  123. script static
  124. void S_fixed(struct set_parm const *sp) {
  125. char suff[32]; lstrcpy2(suff, LANG "st_suff_", sp->st->suff);
  126. k32 diff, v = sp->st->cb_g.k(sp, nil);
  127. S_label(sp);
  128. if((diff = G_Slider_HId(sp->g, sp->y, _rght - gui_p.slddef.w, sp->y,
  129. sp->st->bnd.k.min, sp->st->bnd.k.max, v,
  130. .suf = LC(suff)))) {
  131. v = (i32)((v + diff) * 100) / 100.0k;
  132. sp->st->cb_g.k(sp, &v);
  133. }
  134. }
  135. script static
  136. void S_enume(struct set_parm const *sp) {
  137. i32 v = sp->st->cb_g.i(sp, nil);
  138. i32 min = sp->st->bnd.i.min;
  139. i32 max = sp->st->bnd.i.max - 1;
  140. i32 btw = gui_p.btnnexts.w;
  141. S_label(sp);
  142. if(G_Button_HId(sp->g, sp->y, .x = _rght - btw * 2, sp->y, v <= min,
  143. Pre(btnprevs))) {
  144. v--;
  145. sp->st->cb_g.i(sp, &v);
  146. }
  147. if(G_Button_HId(sp->g, sp->y, .x = _rght - btw, sp->y, v >= max,
  148. Pre(btnnexts))) {
  149. v++;
  150. sp->st->cb_g.i(sp, &v);
  151. }
  152. i32 cr = !strcmp(sp->st->suff, "color") ? Draw_GetCr(v) : sp->g->defcr;
  153. if(v < min || v > max)
  154. PrintTextChS(LC(LANG "st_name_unknown"));
  155. else
  156. PrintTextChS(LanguageC(LANG "st_name_%s_%i", sp->st->suff, v));
  157. PrintText(s_smallfnt, cr,
  158. sp->g->ox + _rght - btw * 2 - 1,2,
  159. sp->g->oy + sp->y,1);
  160. }
  161. static
  162. bool S_isEnabled(struct setting const *st, struct player *p) {
  163. return
  164. (!st->cb_e || st->cb_e(st, p)) &&
  165. (!st->pclass || p->pclass & st->pclass);
  166. }
  167. /* Static Objects ---------------------------------------------------------- */
  168. #define S_bndi(min, max) .bnd = {.i = {min, max}}
  169. #define S_bndk(min, max) .bnd = {.k = {min, max}}
  170. #define S_color S_bndi('a', 'z' + _gcr_max), "color"
  171. #define S_clBoole .cb_g = {.b = SG_clBoole}
  172. #define S_clInteg .cb_g = {.i = SG_clInteg}
  173. #define S_clFixed .cb_g = {.k = SG_clFixed}
  174. #define S_svEnabl .cb_e = SE_server
  175. #define S_svBoole S_svEnabl, .cb_g = {.b = SG_svBoole}
  176. #define S_svInteg S_svEnabl, .cb_g = {.i = SG_svInteg}
  177. #define S_svFixed S_svEnabl, .cb_g = {.k = SG_svFixed}
  178. struct setting const st_gui[] = {
  179. {S_enume, "gui_cursor", S_clInteg, S_bndi(0, gui_curs_max), "cursor"},
  180. {S_enume, "gui_defcr", S_clInteg, S_color},
  181. {S_enume, "gui_theme", S_clInteg, S_bndi(0, cbi_theme_max), "theme"},
  182. {S_fixed, "gui_xmul", S_clFixed, S_bndk(0.1, 2.0), "mult"},
  183. {S_fixed, "gui_ymul", S_clFixed, S_bndk(0.1, 2.0), "mult"},
  184. {S_integ, "gui_buyfiller", S_clInteg, S_bndi(0, 70), "tick"},
  185. {S_empty},
  186. {S_enume, "gui_jpfont", S_clInteg, S_bndi(0, font_num), "jpfont"},
  187. {S_empty},
  188. {S_label, "st_labl_jp_1"},
  189. {S_label, "st_labl_jp_2"},
  190. {S_label, "st_labl_jp_3"},
  191. };
  192. struct setting const st_hud[] = {
  193. {S_boole, "hud_showarmorind", S_clBoole},
  194. {S_boole, "hud_showdamage", S_clBoole},
  195. {S_boole, "hud_showlvl", S_clBoole},
  196. {S_boole, "hud_showscore", S_clBoole},
  197. {S_boole, "hud_showweapons", S_clBoole},
  198. {S_enume, "hud_expbar", S_clInteg, S_bndi(0, lxb_max), "expbar"},
  199. {S_empty},
  200. {S_boole, "xhair_enable", S_clBoole},
  201. {S_boole, "xhair_enablejuicer", S_clBoole},
  202. {S_enume, "xhair_style", S_clInteg, S_bndi(0, lxh_max), "xhair"},
  203. {S_empty},
  204. {S_integ, "xhair_r", S_clInteg, S_bndi(0, 255), "byte"},
  205. {S_integ, "xhair_g", S_clInteg, S_bndi(0, 255), "byte"},
  206. {S_integ, "xhair_b", S_clInteg, S_bndi(0, 255), "byte"},
  207. {S_empty},
  208. {S_integ, "scanner_xoffs", S_clInteg, S_bndi(-160, 160), "pxls"},
  209. {S_integ, "scanner_yoffs", S_clInteg, S_bndi(-160, 160), "pxls"},
  210. {S_empty},
  211. {S_boole, "scanner_altfont", S_clBoole},
  212. {S_boole, "scanner_bar", S_clBoole},
  213. {S_boole, "scanner_slide", S_clBoole},
  214. {S_enume, "scanner_color", S_clInteg, S_color},
  215. };
  216. struct setting const st_itm[] = {
  217. {S_boole, "player_altinvuln", S_clBoole},
  218. {S_boole, "player_brightweps", S_svBoole},
  219. {S_boole, "player_noitemfx", S_svBoole},
  220. {S_boole, "player_scoresound", S_clBoole},
  221. {S_boole, "player_teleshop", S_clBoole},
  222. {S_boole, "sv_nobossdrop", S_svBoole},
  223. {S_boole, "sv_nofullammo", S_svBoole},
  224. {S_boole, "sv_noscoreammo", S_svBoole},
  225. {S_boole, "sv_wepdrop", S_svBoole},
  226. };
  227. struct setting const st_lit[] = {
  228. {S_integ, "light_battery", S_clInteg, S_bndi(0, 60), "secs"},
  229. {S_integ, "light_regen", S_clInteg, S_bndi(1, 10), "mult"},
  230. {S_empty},
  231. {S_integ, "light_r", S_clInteg, S_bndi(0, 255), "byte"},
  232. {S_integ, "light_g", S_clInteg, S_bndi(0, 255), "byte"},
  233. {S_integ, "light_b", S_clInteg, S_bndi(0, 255), "byte"},
  234. {S_empty},
  235. {S_integ, "light_radius", S_clInteg, S_bndi(100, 1000), "unit"},
  236. };
  237. struct setting const st_log[] = {
  238. {S_boole, "hud_logfromtop", S_clBoole},
  239. {S_boole, "hud_showlog", S_clBoole},
  240. {S_boole, "player_ammolog", S_clBoole},
  241. {S_boole, "player_scorelog", S_clBoole},
  242. {S_boole, "player_stupidpickups", S_clBoole},
  243. {S_fixed, "hud_logsize", S_clFixed, S_bndk(0.2, 1.0), "mult"},
  244. };
  245. struct setting const st_pgm[] = {
  246. {S_boole, "sv_postgame", S_svBoole, .fill = 35 * 5},
  247. {S_empty},
  248. {S_label, "st_labl_postgame_1"},
  249. {S_label, "st_labl_postgame_2"},
  250. {S_label, "st_labl_postgame_3"},
  251. {S_label, "st_labl_postgame_4"},
  252. };
  253. struct setting const st_ply[] = {
  254. {S_boole, "st_autobuy_1", .cb_g = {.b = SG_autoBuy}},
  255. {S_boole, "st_autobuy_2", .cb_g = {.b = SG_autoBuy}},
  256. {S_boole, "st_autobuy_3", .cb_g = {.b = SG_autoBuy}},
  257. {S_boole, "st_autobuy_4", .cb_g = {.b = SG_autoBuy}},
  258. {S_boole, "sv_revenge", S_svBoole},
  259. {S_integ, "sv_minhealth", S_svInteg, S_bndi(0, 200), "perc"},
  260. {S_enume, "player_lvsys", S_svInteg, S_bndi(0, atsys_max), "lvsys"},
  261. {S_empty},
  262. {S_boole, "player_damagebob", S_clBoole},
  263. {S_fixed, "player_damagebobmul", S_clFixed, S_bndk(0.0, 1.0), "mult"},
  264. {S_empty},
  265. {S_boole, "player_invertmouse", S_clBoole},
  266. {S_boole, "player_resultssound", S_clBoole},
  267. {S_boole, "st_done_intro", .cb_g = {.b = SG_doneIntro}},
  268. {S_fixed, "player_footstepvol", S_clFixed, S_bndk(0.0, 1.0), "mult"},
  269. {S_fixed, "player_viewtilt", S_clFixed, S_bndk(0.0, 1.0), "mult"},
  270. {S_empty},
  271. {S_boole, "player_bosstexts", S_clBoole},
  272. {S_empty},
  273. {S_label, "st_labl_boss_1"},
  274. {S_label, "st_labl_boss_2"},
  275. {S_label, "st_labl_boss_3"},
  276. };
  277. struct setting const st_wep[] = {
  278. {S_boole, "weapons_magicselanims", S_clBoole, .pclass = pC},
  279. {S_empty, .pclass = pC},
  280. {S_boole, "weapons_fastlazshot", S_svBoole, .pclass = pM},
  281. {S_boole, "weapons_rainbowlaser", S_svBoole, .pclass = pM},
  282. {S_boole, "weapons_reducedsg", S_clBoole, .pclass = pM},
  283. {S_boole, "weapons_riflemodeclear", S_clBoole, .pclass = pM},
  284. {S_boole, "weapons_riflescope", S_clBoole, .pclass = pM},
  285. {S_empty, .pclass = pM},
  286. {S_boole, "weapons_casingfadeout", S_svBoole},
  287. {S_boole, "weapons_casings", S_svBoole},
  288. {S_boole, "weapons_magdrops", S_svBoole},
  289. {S_boole, "weapons_magfadeout", S_svBoole},
  290. {S_boole, "weapons_nofirebob", S_svBoole},
  291. {S_boole, "weapons_reloadempty", S_svBoole},
  292. {S_boole, "weapons_slot3ammo", S_clBoole},
  293. {S_fixed, "weapons_alpha", S_clFixed, S_bndk(0.0, 1.0), "mult"},
  294. {S_fixed, "weapons_recoil", S_clFixed, S_bndk(0.0, 1.0), "mult"},
  295. {S_fixed, "weapons_reloadbob", S_clFixed, S_bndk(0.0, 1.0), "mult"},
  296. {S_fixed, "weapons_ricochetvol", S_svFixed, S_bndk(0.0, 1.0), "mult"},
  297. {S_fixed, "weapons_scopealpha", S_clFixed, S_bndk(0.0, 1.0), "mult"},
  298. {S_fixed, "weapons_zoomfactor", S_clFixed, S_bndk(1.0, 10.0), "mult"},
  299. };
  300. struct setting const st_wld[] = {
  301. {S_boole, "player_rainshader", S_clBoole},
  302. {S_boole, "sv_lessparticles", S_svBoole},
  303. {S_boole, "sv_nobosses", S_svBoole},
  304. {S_boole, "sv_rain", S_svBoole},
  305. {S_boole, "sv_sky", S_svBoole},
  306. {S_fixed, "sv_scoremul", S_svFixed, S_bndk(0.0, 10.0), "mult"},
  307. {S_integ, "sv_autosave", S_svInteg, S_bndi(0, 30), "minu"},
  308. {S_integ, "sv_difficulty", S_svInteg, S_bndi(1, 100), "perc"},
  309. };
  310. struct {
  311. cstr nam;
  312. struct setting const *set;
  313. size_t num;
  314. } const settings[] = {
  315. #define Typ(name) {LANG "st_labl_" #name, st_##name, countof(st_##name)}
  316. Typ(gui),
  317. Typ(hud),
  318. Typ(itm),
  319. Typ(lit),
  320. Typ(log),
  321. Typ(pgm),
  322. Typ(ply),
  323. Typ(wep),
  324. Typ(wld),
  325. #undef Typ
  326. };
  327. /* Extern Functions -------------------------------------------------------- */
  328. void P_CBI_TabSettings(struct gui_state *g, struct player *p) {
  329. i32 set_num = 0;
  330. char tn[countof(settings)][20];
  331. for(i32 i = 0; i < countof(settings); i++)
  332. LanguageVC(tn[i], settings[i].nam);
  333. i32 yp = G_Tabs(g, &CBIState(g)->settingstab, tn, countof(tn), 13, 13, 1);
  334. yp *= gui_p.btntab.h;
  335. struct setting const *set = settings[CBIState(g)->settingstab].set;
  336. size_t num = settings[CBIState(g)->settingstab].num;
  337. for(i32 i = 0; i < num; i++)
  338. if(S_isEnabled(&set[i], p))
  339. set_num++;
  340. G_ScrBeg(g, &CBIState(g)->settingscr, 15, 30 + yp, _rght, 192 - yp,
  341. set_num * 10);
  342. struct set_parm sp = {p, g, 0, 0};
  343. for(i32 i = 0; i < num; i++) {
  344. sp.st = &set[i];
  345. if(S_isEnabled(sp.st, p)) {
  346. if(!G_ScrOcc(g, &CBIState(g)->settingscr, sp.y, 10))
  347. sp.st->cb(&sp);
  348. sp.y += 10;
  349. }
  350. }
  351. G_ScrEnd(g, &CBIState(g)->settingscr);
  352. }
  353. /* EOF */