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