m_cheat.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. /* Emacs style mode select -*- C++ -*-
  2. *-----------------------------------------------------------------------------
  3. *
  4. *
  5. * PrBoom: a Doom port merged with LxDoom and LSDLDoom
  6. * based on BOOM, a modified and improved DOOM engine
  7. * Copyright (C) 1999 by
  8. * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
  9. * Copyright (C) 1999-2002 by
  10. * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
  11. * Copyright 2005, 2006 by
  12. * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License
  16. * as published by the Free Software Foundation; either version 2
  17. * of the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  27. * 02111-1307, USA.
  28. *
  29. * DESCRIPTION:
  30. * Cheat sequence checking.
  31. *
  32. *-----------------------------------------------------------------------------*/
  33. #include "doomstat.h"
  34. #include "g_game.h"
  35. #include "r_data.h"
  36. #include "p_inter.h"
  37. #include "p_tick.h"
  38. #include "m_cheat.h"
  39. #include "m_argv.h"
  40. #include "s_sound.h"
  41. #include "sounds.h"
  42. #include "dstrings.h"
  43. #include "r_main.h"
  44. #include "p_map.h"
  45. #include "d_deh.h" // Ty 03/27/98 - externalized strings
  46. /* cph 2006/07/23 - needs direct access to thinkercap */
  47. #include "p_tick.h"
  48. #define plyr (players+consoleplayer) /* the console player */
  49. //-----------------------------------------------------------------------------
  50. //
  51. // CHEAT SEQUENCE PACKAGE
  52. //
  53. //-----------------------------------------------------------------------------
  54. static void cheat_mus();
  55. static void cheat_choppers();
  56. static void cheat_god();
  57. static void cheat_fa();
  58. static void cheat_k();
  59. static void cheat_kfa();
  60. static void cheat_noclip();
  61. static void cheat_pw();
  62. static void cheat_behold();
  63. static void cheat_clev();
  64. static void cheat_mypos();
  65. static void cheat_rate();
  66. static void cheat_comp();
  67. static void cheat_friction();
  68. static void cheat_pushers();
  69. static void cheat_tnttran();
  70. static void cheat_massacre();
  71. static void cheat_ddt();
  72. static void cheat_hom();
  73. static void cheat_fast();
  74. static void cheat_tntkey();
  75. static void cheat_tntkeyx();
  76. static void cheat_tntkeyxx();
  77. static void cheat_tntweap();
  78. static void cheat_tntweapx();
  79. static void cheat_tntammo();
  80. static void cheat_tntammox();
  81. static void cheat_smart();
  82. static void cheat_pitch();
  83. static void cheat_megaarmour();
  84. static void cheat_health();
  85. //-----------------------------------------------------------------------------
  86. //
  87. // List of cheat codes, functions, and special argument indicators.
  88. //
  89. // The first argument is the cheat code.
  90. //
  91. // The second argument is its DEH name, or NULL if it's not supported by -deh.
  92. //
  93. // The third argument is a combination of the bitmasks:
  94. // {always, not_dm, not_coop, not_net, not_menu, not_demo, not_deh},
  95. // which excludes the cheat during certain modes of play.
  96. //
  97. // The fourth argument is the handler function.
  98. //
  99. // The fifth argument is passed to the handler function if it's non-negative;
  100. // if negative, then its negative indicates the number of extra characters
  101. // expected after the cheat code, which are passed to the handler function
  102. // via a pointer to a buffer (after folding any letters to lowercase).
  103. //
  104. //-----------------------------------------------------------------------------
  105. struct cheat_s cheat[] = {
  106. {"idmus", "Change music", always,
  107. cheat_mus, -2, 0, 0 },
  108. {"idchoppers", "Chainsaw", not_net | not_demo,
  109. cheat_choppers, 0, 0, 0 },
  110. {"iddqd", "God mode", not_net | not_demo,
  111. cheat_god, 0, 0, 0 },
  112. #if 0
  113. {"idk", NULL, not_net | not_demo | not_deh,
  114. cheat_k }, // The most controversial cheat code in Doom history!!!
  115. #endif
  116. {"idkfa", "Ammo & Keys", not_net | not_demo,
  117. cheat_kfa, 0, 0, 0 },
  118. {"idfa", "Ammo", not_net | not_demo,
  119. cheat_fa, 0, 0, 0 },
  120. {"idspispopd", "No Clipping 1", not_net | not_demo,
  121. cheat_noclip, 0, 0, 0 },
  122. {"idclip", "No Clipping 2", not_net | not_demo,
  123. cheat_noclip, 0, 0, 0 },
  124. {"idbeholdh", "Invincibility", not_net | not_demo,
  125. cheat_health, 0, 0, 0 },
  126. {"idbeholdm", "Invincibility", not_net | not_demo,
  127. cheat_megaarmour, 0, 0, 0 },
  128. {"idbeholdv", "Invincibility", not_net | not_demo,
  129. cheat_pw, pw_invulnerability, 0, 0 },
  130. {"idbeholds", "Berserk", not_net | not_demo,
  131. cheat_pw, pw_strength, 0, 0 },
  132. {"idbeholdi", "Invisibility", not_net | not_demo,
  133. cheat_pw, pw_invisibility, 0, 0 },
  134. {"idbeholdr", "Radiation Suit", not_net | not_demo,
  135. cheat_pw, pw_ironfeet, 0, 0 },
  136. {"idbeholda", "Auto-map", not_dm,
  137. cheat_pw, pw_allmap, 0, 0 },
  138. {"idbeholdl", "Lite-Amp Goggles", not_dm,
  139. cheat_pw, pw_infrared, 0, 0 },
  140. {"idbehold", "BEHOLD menu", not_dm,
  141. cheat_behold, 0, 0, 0 },
  142. {"idclev", "Level Warp", not_net | not_demo | not_menu,
  143. cheat_clev, -2, 0, 0},
  144. {"idmypos", "Player Position", not_dm,
  145. cheat_mypos, 0, 0, 0 },
  146. {"idrate", "Frame rate", 0,
  147. cheat_rate, 0, 0, 0 },
  148. {"tntcomp", NULL, not_net | not_demo,
  149. cheat_comp, 0, 0, 0 }, // phares
  150. {"tntem", NULL, not_net | not_demo,
  151. cheat_massacre, 0, 0, 0 }, // jff 2/01/98 kill all monsters
  152. {"iddt", "Map cheat", not_dm,
  153. cheat_ddt, 0, 0, 0 }, // killough 2/07/98: moved from am_map.c
  154. {"tnthom", NULL, always,
  155. cheat_hom, 0, 0, 0 }, // killough 2/07/98: HOM autodetector
  156. {"tntkey", NULL, not_net | not_demo,
  157. cheat_tntkey, 0, 0, 0 }, // killough 2/16/98: generalized key cheats
  158. {"tntkeyr", NULL, not_net | not_demo,
  159. cheat_tntkeyx, 0, 0, 0 },
  160. {"tntkeyy", NULL, not_net | not_demo,
  161. cheat_tntkeyx, 0, 0, 0 },
  162. {"tntkeyb", NULL, not_net | not_demo,
  163. cheat_tntkeyx, 0, 0, 0 },
  164. {"tntkeyrc", NULL, not_net | not_demo,
  165. cheat_tntkeyxx, it_redcard, 0, 0 },
  166. {"tntkeyyc", NULL, not_net | not_demo,
  167. cheat_tntkeyxx, it_yellowcard, 0, 0 },
  168. {"tntkeybc", NULL, not_net | not_demo,
  169. cheat_tntkeyxx, it_bluecard, 0, 0 },
  170. {"tntkeyrs", NULL, not_net | not_demo,
  171. cheat_tntkeyxx, it_redskull, 0, 0 },
  172. {"tntkeyys", NULL, not_net | not_demo,
  173. cheat_tntkeyxx, it_yellowskull, 0, 0 },
  174. {"tntkeybs", NULL, not_net | not_demo,
  175. cheat_tntkeyxx, it_blueskull, 0, 0 }, // killough 2/16/98: end generalized keys
  176. {"tntka", NULL, not_net | not_demo,
  177. cheat_k, 0, 0, 0 }, // Ty 04/11/98 - Added TNTKA
  178. {"tntweap", NULL, not_net | not_demo,
  179. cheat_tntweap, 0, 0, 0 }, // killough 2/16/98: generalized weapon cheats
  180. {"tntweap", NULL, not_net | not_demo,
  181. cheat_tntweapx, -1, 0, 0},
  182. {"tntammo", NULL, not_net | not_demo,
  183. cheat_tntammo, 0, 0, 0 },
  184. {"tntammo", NULL, not_net | not_demo,
  185. cheat_tntammox, -1, 0, 0}, // killough 2/16/98: end generalized weapons
  186. {"tnttran", NULL, always,
  187. cheat_tnttran, 0, 0, 0 }, // invoke translucency // phares
  188. {"tntsmart", NULL, not_net | not_demo,
  189. cheat_smart, 0, 0, 0}, // killough 2/21/98: smart monster toggle
  190. {"tntpitch", NULL, always,
  191. cheat_pitch, 0, 0, 0}, // killough 2/21/98: pitched sound toggle
  192. // killough 2/21/98: reduce RSI injury by adding simpler alias sequences:
  193. {"tntran", NULL, always,
  194. cheat_tnttran, 0, 0, 0 }, // killough 2/21/98: same as tnttran
  195. {"tntamo", NULL, not_net | not_demo,
  196. cheat_tntammo, 0, 0, 0 }, // killough 2/21/98: same as tntammo
  197. {"tntamo", NULL, not_net | not_demo,
  198. cheat_tntammox, -1, 0, 0}, // killough 2/21/98: same as tntammo
  199. {"tntfast", NULL, not_net | not_demo,
  200. cheat_fast, 0, 0, 0 }, // killough 3/6/98: -fast toggle
  201. {"tntice", NULL, not_net | not_demo,
  202. cheat_friction, 0, 0, 0 }, // phares 3/10/98: toggle variable friction effects
  203. {"tntpush", NULL, not_net | not_demo,
  204. cheat_pushers, 0, 0, 0 }, // phares 3/10/98: toggle pushers
  205. {NULL, NULL, 0, NULL, 0, 0, 0} // end-of-list marker
  206. };
  207. //-----------------------------------------------------------------------------
  208. static void cheat_mus(buf)
  209. char buf[3];
  210. {
  211. int musnum;
  212. //jff 3/20/98 note: this cheat allowed in netgame/demorecord
  213. //jff 3/17/98 avoid musnum being negative and crashing
  214. if (!isdigit(buf[0]) || !isdigit(buf[1]))
  215. return;
  216. plyr->message = s_STSTR_MUS; // Ty 03/27/98 - externalized
  217. if (gamemode == commercial)
  218. {
  219. musnum = mus_runnin + (buf[0]-'0')*10 + buf[1]-'0' - 1;
  220. //jff 4/11/98 prevent IDMUS00 in DOOMII and IDMUS36 or greater
  221. if (musnum < mus_runnin || ((buf[0]-'0')*10 + buf[1]-'0') > 35)
  222. plyr->message = s_STSTR_NOMUS; // Ty 03/27/98 - externalized
  223. else
  224. {
  225. S_ChangeMusic(musnum, 1);
  226. idmusnum = musnum; //jff 3/17/98 remember idmus number for restore
  227. }
  228. }
  229. else
  230. {
  231. musnum = mus_e1m1 + (buf[0]-'1')*9 + (buf[1]-'1');
  232. //jff 4/11/98 prevent IDMUS0x IDMUSx0 in DOOMI and greater than introa
  233. if (buf[0] < '1' || buf[1] < '1' || ((buf[0]-'1')*9 + buf[1]-'1') > 31)
  234. plyr->message = s_STSTR_NOMUS; // Ty 03/27/98 - externalized
  235. else
  236. {
  237. S_ChangeMusic(musnum, 1);
  238. idmusnum = musnum; //jff 3/17/98 remember idmus number for restore
  239. }
  240. }
  241. }
  242. // 'choppers' invulnerability & chainsaw
  243. static void cheat_choppers()
  244. {
  245. plyr->weaponowned[wp_chainsaw] = true;
  246. plyr->powers[pw_invulnerability] = true;
  247. plyr->message = s_STSTR_CHOPPERS; // Ty 03/27/98 - externalized
  248. }
  249. static void cheat_god()
  250. { // 'dqd' cheat for toggleable god mode
  251. plyr->cheats ^= CF_GODMODE;
  252. if (plyr->cheats & CF_GODMODE)
  253. {
  254. if (plyr->mo)
  255. plyr->mo->health = god_health; // Ty 03/09/98 - deh
  256. plyr->health = god_health;
  257. plyr->message = s_STSTR_DQDON; // Ty 03/27/98 - externalized
  258. }
  259. else
  260. plyr->message = s_STSTR_DQDOFF; // Ty 03/27/98 - externalized
  261. }
  262. // CPhipps - new health and armour cheat codes
  263. static void cheat_health()
  264. {
  265. if (!(plyr->cheats & CF_GODMODE)) {
  266. if (plyr->mo)
  267. plyr->mo->health = mega_health;
  268. plyr->health = mega_health;
  269. plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized
  270. }
  271. }
  272. static void cheat_megaarmour()
  273. {
  274. plyr->armorpoints = idfa_armor; // Ty 03/09/98 - deh
  275. plyr->armortype = idfa_armor_class; // Ty 03/09/98 - deh
  276. plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized
  277. }
  278. static void cheat_fa()
  279. {
  280. int i;
  281. if (!plyr->backpack)
  282. {
  283. for (i=0 ; i<NUMAMMO ; i++)
  284. plyr->maxammo[i] *= 2;
  285. plyr->backpack = true;
  286. }
  287. plyr->armorpoints = idfa_armor; // Ty 03/09/98 - deh
  288. plyr->armortype = idfa_armor_class; // Ty 03/09/98 - deh
  289. // You can't own weapons that aren't in the game // phares 02/27/98
  290. for (i=0;i<NUMWEAPONS;i++)
  291. if (!(((i == wp_plasma || i == wp_bfg) && gamemode == shareware) ||
  292. (i == wp_supershotgun && gamemode != commercial)))
  293. plyr->weaponowned[i] = true;
  294. for (i=0;i<NUMAMMO;i++)
  295. if (i!=am_cell || gamemode!=shareware)
  296. plyr->ammo[i] = plyr->maxammo[i];
  297. plyr->message = s_STSTR_FAADDED;
  298. }
  299. static void cheat_k()
  300. {
  301. int i;
  302. for (i=0;i<NUMCARDS;i++)
  303. if (!plyr->cards[i]) // only print message if at least one key added
  304. { // however, caller may overwrite message anyway
  305. plyr->cards[i] = true;
  306. plyr->message = "Keys Added";
  307. }
  308. }
  309. static void cheat_kfa()
  310. {
  311. cheat_k();
  312. cheat_fa();
  313. plyr->message = STSTR_KFAADDED;
  314. }
  315. static void cheat_noclip()
  316. {
  317. // Simplified, accepting both "noclip" and "idspispopd".
  318. // no clipping mode cheat
  319. plyr->message = (plyr->cheats ^= CF_NOCLIP) & CF_NOCLIP ?
  320. s_STSTR_NCON : s_STSTR_NCOFF; // Ty 03/27/98 - externalized
  321. }
  322. // 'behold?' power-up cheats (modified for infinite duration -- killough)
  323. static void cheat_pw(int pw)
  324. {
  325. if (plyr->powers[pw])
  326. plyr->powers[pw] = pw!=pw_strength && pw!=pw_allmap; // killough
  327. else
  328. {
  329. P_GivePower(plyr, pw);
  330. if (pw != pw_strength)
  331. plyr->powers[pw] = -1; // infinite duration -- killough
  332. }
  333. plyr->message = s_STSTR_BEHOLDX; // Ty 03/27/98 - externalized
  334. }
  335. // 'behold' power-up menu
  336. static void cheat_behold()
  337. {
  338. plyr->message = s_STSTR_BEHOLD; // Ty 03/27/98 - externalized
  339. }
  340. // 'clev' change-level cheat
  341. static void cheat_clev(char buf[3])
  342. {
  343. int epsd, map;
  344. if (gamemode == commercial)
  345. {
  346. epsd = 1; //jff was 0, but espd is 1-based
  347. map = (buf[0] - '0')*10 + buf[1] - '0';
  348. }
  349. else
  350. {
  351. epsd = buf[0] - '0';
  352. map = buf[1] - '0';
  353. }
  354. // Catch invalid maps.
  355. if (epsd < 1 || map < 1 || // Ohmygod - this is not going to work.
  356. (gamemode == retail && (epsd > 4 || map > 9 )) ||
  357. (gamemode == registered && (epsd > 3 || map > 9 )) ||
  358. (gamemode == shareware && (epsd > 1 || map > 9 )) ||
  359. (gamemode == commercial && (epsd > 1 || map > 32 )) ) //jff no 33 and 34
  360. return; //8/14/98 allowed
  361. // So be it.
  362. idmusnum = -1; //jff 3/17/98 revert to normal level music on IDCLEV
  363. plyr->message = s_STSTR_CLEV; // Ty 03/27/98 - externalized
  364. G_DeferedInitNew(gameskill, epsd, map);
  365. }
  366. // 'mypos' for player position
  367. // killough 2/7/98: simplified using dprintf and made output more user-friendly
  368. static void cheat_mypos()
  369. {
  370. doom_printf("Position (%d,%d,%d)\tAngle %-.0f",
  371. players[consoleplayer].mo->x >> FRACBITS,
  372. players[consoleplayer].mo->y >> FRACBITS,
  373. players[consoleplayer].mo->z >> FRACBITS,
  374. players[consoleplayer].mo->angle * (90.0/ANG90));
  375. }
  376. // cph - cheat to toggle frame rate/rendering stats display
  377. static void cheat_rate()
  378. {
  379. rendering_stats ^= 1;
  380. }
  381. // compatibility cheat
  382. static void cheat_comp()
  383. {
  384. // CPhipps - modified for new compatibility system
  385. compatibility_level++; compatibility_level %= MAX_COMPATIBILITY_LEVEL;
  386. // must call G_Compatibility after changing compatibility_level
  387. // (fixes sf bug number 1558738)
  388. G_Compatibility();
  389. doom_printf("New compatibility level:\n%s",
  390. comp_lev_str[compatibility_level]);
  391. }
  392. // variable friction cheat
  393. static void cheat_friction()
  394. {
  395. plyr->message = // Ty 03/27/98 - *not* externalized
  396. (variable_friction = !variable_friction) ? "Variable Friction enabled" :
  397. "Variable Friction disabled";
  398. }
  399. // Pusher cheat
  400. // phares 3/10/98
  401. static void cheat_pushers()
  402. {
  403. plyr->message = // Ty 03/27/98 - *not* externalized
  404. (allow_pushers = !allow_pushers) ? "Pushers enabled" : "Pushers disabled";
  405. }
  406. // translucency cheat
  407. static void cheat_tnttran()
  408. {
  409. plyr->message = // Ty 03/27/98 - *not* externalized
  410. (general_translucency = !general_translucency) ? "Translucency enabled" :
  411. "Translucency disabled";
  412. // killough 3/1/98, 4/11/98: cache translucency map on a demand basis
  413. if (general_translucency && !main_tranmap)
  414. R_InitTranMap(0);
  415. }
  416. static void cheat_massacre() // jff 2/01/98 kill all monsters
  417. {
  418. // jff 02/01/98 'em' cheat - kill all monsters
  419. // partially taken from Chi's .46 port
  420. //
  421. // killough 2/7/98: cleaned up code and changed to use dprintf;
  422. // fixed lost soul bug (LSs left behind when PEs are killed)
  423. int killcount=0;
  424. thinker_t *currentthinker = NULL;
  425. extern void A_PainDie(mobj_t *);
  426. // killough 7/20/98: kill friendly monsters only if no others to kill
  427. uint_64_t mask = MF_FRIEND;
  428. P_MapStart();
  429. do
  430. while ((currentthinker = P_NextThinker(currentthinker,th_all)) != NULL)
  431. if (currentthinker->function == P_MobjThinker &&
  432. !(((mobj_t *) currentthinker)->flags & mask) && // killough 7/20/98
  433. (((mobj_t *) currentthinker)->flags & MF_COUNTKILL ||
  434. ((mobj_t *) currentthinker)->type == MT_SKULL))
  435. { // killough 3/6/98: kill even if PE is dead
  436. if (((mobj_t *) currentthinker)->health > 0)
  437. {
  438. killcount++;
  439. P_DamageMobj((mobj_t *)currentthinker, NULL, NULL, 10000);
  440. }
  441. if (((mobj_t *) currentthinker)->type == MT_PAIN)
  442. {
  443. A_PainDie((mobj_t *) currentthinker); // killough 2/8/98
  444. P_SetMobjState ((mobj_t *) currentthinker, S_PAIN_DIE6);
  445. }
  446. }
  447. while (!killcount && mask ? mask=0, 1 : 0); // killough 7/20/98
  448. P_MapEnd();
  449. // killough 3/22/98: make more intelligent about plural
  450. // Ty 03/27/98 - string(s) *not* externalized
  451. doom_printf("%d Monster%s Killed", killcount, killcount==1 ? "" : "s");
  452. }
  453. // killough 2/7/98: move iddt cheat from am_map.c to here
  454. // killough 3/26/98: emulate Doom better
  455. static void cheat_ddt()
  456. {
  457. extern int ddt_cheating;
  458. if (automapmode & am_active)
  459. ddt_cheating = (ddt_cheating+1) % 3;
  460. }
  461. // killough 2/7/98: HOM autodetection
  462. static void cheat_hom()
  463. {
  464. extern int autodetect_hom; // Ty 03/27/98 - *not* externalized
  465. plyr->message = (autodetect_hom = !autodetect_hom) ? "HOM Detection On" :
  466. "HOM Detection Off";
  467. }
  468. // killough 3/6/98: -fast parameter toggle
  469. static void cheat_fast()
  470. {
  471. plyr->message = (fastparm = !fastparm) ? "Fast Monsters On" :
  472. "Fast Monsters Off"; // Ty 03/27/98 - *not* externalized
  473. G_SetFastParms(fastparm); // killough 4/10/98: set -fast parameter correctly
  474. }
  475. // killough 2/16/98: keycard/skullkey cheat functions
  476. static void cheat_tntkey()
  477. {
  478. plyr->message = "Red, Yellow, Blue"; // Ty 03/27/98 - *not* externalized
  479. }
  480. static void cheat_tntkeyx()
  481. {
  482. plyr->message = "Card, Skull"; // Ty 03/27/98 - *not* externalized
  483. }
  484. static void cheat_tntkeyxx(int key)
  485. {
  486. plyr->message = (plyr->cards[key] = !plyr->cards[key]) ?
  487. "Key Added" : "Key Removed"; // Ty 03/27/98 - *not* externalized
  488. }
  489. // killough 2/16/98: generalized weapon cheats
  490. static void cheat_tntweap()
  491. { // Ty 03/27/98 - *not* externalized
  492. plyr->message = gamemode==commercial ? // killough 2/28/98
  493. "Weapon number 1-9" : "Weapon number 1-8";
  494. }
  495. static void cheat_tntweapx(buf)
  496. char buf[3];
  497. {
  498. int w = *buf - '1';
  499. if ((w==wp_supershotgun && gamemode!=commercial) || // killough 2/28/98
  500. ((w==wp_bfg || w==wp_plasma) && gamemode==shareware))
  501. return;
  502. if (w==wp_fist) // make '1' apply beserker strength toggle
  503. cheat_pw(pw_strength);
  504. else
  505. if (w >= 0 && w < NUMWEAPONS) {
  506. if ((plyr->weaponowned[w] = !plyr->weaponowned[w]))
  507. plyr->message = "Weapon Added"; // Ty 03/27/98 - *not* externalized
  508. else
  509. {
  510. plyr->message = "Weapon Removed"; // Ty 03/27/98 - *not* externalized
  511. if (w==plyr->readyweapon) // maybe switch if weapon removed
  512. plyr->pendingweapon = P_SwitchWeapon(plyr);
  513. }
  514. }
  515. }
  516. // killough 2/16/98: generalized ammo cheats
  517. static void cheat_tntammo()
  518. {
  519. plyr->message = "Ammo 1-4, Backpack"; // Ty 03/27/98 - *not* externalized
  520. }
  521. static void cheat_tntammox(buf)
  522. char buf[1];
  523. {
  524. int a = *buf - '1';
  525. if (*buf == 'b') // Ty 03/27/98 - strings *not* externalized
  526. if ((plyr->backpack = !plyr->backpack))
  527. for (plyr->message = "Backpack Added", a=0 ; a<NUMAMMO ; a++)
  528. plyr->maxammo[a] <<= 1;
  529. else
  530. for (plyr->message = "Backpack Removed", a=0 ; a<NUMAMMO ; a++)
  531. {
  532. if (plyr->ammo[a] > (plyr->maxammo[a] >>= 1))
  533. plyr->ammo[a] = plyr->maxammo[a];
  534. }
  535. else
  536. if (a>=0 && a<NUMAMMO) // Ty 03/27/98 - *not* externalized
  537. { // killough 5/5/98: switch plasma and rockets for now -- KLUDGE
  538. a = a==am_cell ? am_misl : a==am_misl ? am_cell : a; // HACK
  539. plyr->message = (plyr->ammo[a] = !plyr->ammo[a]) ?
  540. plyr->ammo[a] = plyr->maxammo[a], "Ammo Added" : "Ammo Removed";
  541. }
  542. }
  543. static void cheat_smart()
  544. {
  545. plyr->message = (monsters_remember = !monsters_remember) ?
  546. "Smart Monsters Enabled" : "Smart Monsters Disabled";
  547. }
  548. static void cheat_pitch()
  549. {
  550. plyr->message=(pitched_sounds = !pitched_sounds) ? "Pitch Effects Enabled" :
  551. "Pitch Effects Disabled";
  552. }
  553. //-----------------------------------------------------------------------------
  554. // 2/7/98: Cheat detection rewritten by Lee Killough, to avoid
  555. // scrambling and to use a more general table-driven approach.
  556. //-----------------------------------------------------------------------------
  557. #define CHEAT_ARGS_MAX 8 /* Maximum number of args at end of cheats */
  558. boolean M_FindCheats(int key)
  559. {
  560. static uint_64_t sr;
  561. static char argbuf[CHEAT_ARGS_MAX+1], *arg;
  562. static int init, argsleft, cht;
  563. int i, ret, matchedbefore;
  564. // If we are expecting arguments to a cheat
  565. // (e.g. idclev), put them in the arg buffer
  566. if (argsleft)
  567. {
  568. *arg++ = tolower(key); // store key in arg buffer
  569. if (!--argsleft) // if last key in arg list,
  570. cheat[cht].func(argbuf); // process the arg buffer
  571. return 1; // affirmative response
  572. }
  573. key = tolower(key) - 'a';
  574. if (key < 0 || key >= 32) // ignore most non-alpha cheat letters
  575. {
  576. sr = 0; // clear shift register
  577. return 0;
  578. }
  579. if (!init) // initialize aux entries of table
  580. {
  581. init = 1;
  582. for (i=0;cheat[i].cheat;i++)
  583. {
  584. uint_64_t c=0, m=0;
  585. const char *p;
  586. for (p=cheat[i].cheat; *p; p++)
  587. {
  588. unsigned keynum = tolower(*p)-'a'; // convert to 0-31
  589. if (keynum >= 32) // ignore most non-alpha cheat letters
  590. continue;
  591. c = (c<<5) + keynum; // shift key into code
  592. m = (m<<5) + 31; // shift 1's into mask
  593. }
  594. cheat[i].code = c; // code for this cheat key
  595. cheat[i].mask = m; // mask for this cheat key
  596. }
  597. }
  598. sr = (sr<<5) + key; // shift this key into shift register
  599. for (matchedbefore = ret = i = 0; cheat[i].cheat; i++)
  600. if ((sr & cheat[i].mask) == cheat[i].code && // if match found
  601. !(cheat[i].when & not_dm && deathmatch) && // and if cheat allowed
  602. !(cheat[i].when & not_coop && netgame && !deathmatch) &&
  603. !(cheat[i].when & not_demo && (demorecording || demoplayback)) &&
  604. !(cheat[i].when & not_menu && menuactive) &&
  605. !(cheat[i].when & not_deh && M_CheckParm("-deh"))) {
  606. if (cheat[i].arg < 0) // if additional args are required
  607. {
  608. cht = i; // remember this cheat code
  609. arg = argbuf; // point to start of arg buffer
  610. argsleft = -cheat[i].arg; // number of args expected
  611. ret = 1; // responder has eaten key
  612. }
  613. else
  614. if (!matchedbefore) // allow only one cheat at a time
  615. {
  616. matchedbefore = ret = 1; // responder has eaten key
  617. cheat[i].func(cheat[i].arg); // call cheat handler
  618. }
  619. }
  620. return ret;
  621. }