st_stuff.cpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "Precompiled.h"
  21. #include "globaldata.h"
  22. #include <stdio.h>
  23. #include "i_system.h"
  24. #include "i_video.h"
  25. #include "z_zone.h"
  26. #include "m_random.h"
  27. #include "w_wad.h"
  28. #include "doomdef.h"
  29. #include "g_game.h"
  30. #include "st_stuff.h"
  31. #include "st_lib.h"
  32. #include "r_local.h"
  33. #include "p_local.h"
  34. #include "p_inter.h"
  35. #include "am_map.h"
  36. #include "m_cheat.h"
  37. #include "s_sound.h"
  38. // Needs access to LFB.
  39. #include "v_video.h"
  40. // State.
  41. #include "doomstat.h"
  42. // Data.
  43. #include "dstrings.h"
  44. #include "sounds.h"
  45. //
  46. // STATUS BAR DATA
  47. //
  48. // Palette indices.
  49. // For damage/bonus red-/gold-shifts
  50. // Radiation suit, green shift.
  51. // N/256*100% probability
  52. // that the normal face state will change
  53. // For Responder
  54. // Location of status bar
  55. // Should be set to patch width
  56. // for tall numbers later on
  57. // Number of status ::g->faces.
  58. // Location and size of statistics,
  59. // justified according to widget type.
  60. // Problem is, within which space? STbar? Screen?
  61. // Note: this could be read in by a lump.
  62. // Problem is, is the stuff rendered
  63. // into a buffer,
  64. // or into the frame buffer?
  65. // AMMO number pos.
  66. // HEALTH number pos.
  67. // Weapon pos.
  68. // Frags pos.
  69. // ARMOR number pos.
  70. // Key icon positions.
  71. // Ammunition counter.
  72. // Indicate maximum ammunition.
  73. // Only needed because backpack exists.
  74. // pistol
  75. // shotgun
  76. // chain gun
  77. // missile launcher
  78. // plasma gun
  79. // bfg
  80. // WPNS title
  81. // DETH title
  82. //Incoming messages window location
  83. //UNUSED
  84. // #define ST_MSGTEXTX (::g->viewwindowx)
  85. // #define ST_MSGTEXTY (::g->viewwindowy+::g->viewheight-18)
  86. // Dimensions given in characters.
  87. // Or shall I say, in lines?
  88. // Width, in characters again.
  89. // Height, in ::g->lines.
  90. // main player in game
  91. // ST_Start() has just been called
  92. // used to execute ST_Init() only once
  93. // lump number for PLAYPAL
  94. // used for timing
  95. // used for making messages go away
  96. // used when in chat
  97. // States for the intermission
  98. // whether in automap or first-person
  99. // whether left-side main status bar is active
  100. // whether status bar chat is active
  101. // value of ::g->st_chat before message popped up
  102. // whether chat window has the cursor on
  103. // !::g->deathmatch
  104. // !::g->deathmatch && ::g->st_statusbaron
  105. // !::g->deathmatch
  106. // main bar left
  107. // 0-9, tall numbers
  108. // tall % sign
  109. // 0-9, short, yellow (,different!) numbers
  110. // 3 key-cards, 3 skulls
  111. // face status patches
  112. // face background
  113. // main bar right
  114. // weapon ownership patches
  115. // ready-weapon widget
  116. // in ::g->deathmatch only, summary of frags stats
  117. // health widget
  118. // ::g->arms background
  119. // weapon ownership widgets
  120. // face status widget
  121. // keycard widgets
  122. // armor widget
  123. // ammo widgets
  124. // max ammo widgets
  125. // number of frags so far in ::g->deathmatch
  126. // used to use appopriately pained face
  127. // used for evil grin
  128. // count until face changes
  129. // current face index, used by ::g->w_faces
  130. // holds key-type for each key box on bar
  131. // a random number per tick
  132. // Massive bunches of cheat shit
  133. // to keep it from being easy to figure them out.
  134. // Yeah, right...
  135. const unsigned char cheat_mus_seq[] =
  136. {
  137. 0xb2, 0x26, 0xb6, 0xae, 0xea, 1, 0, 0, 0xff
  138. };
  139. const unsigned char cheat_choppers_seq[] =
  140. {
  141. 0xb2, 0x26, 0xe2, 0x32, 0xf6, 0x2a, 0x2a, 0xa6, 0x6a, 0xea, 0xff // id...
  142. };
  143. const unsigned char cheat_god_seq[] =
  144. {
  145. 0xb2, 0x26, 0x26, 0xaa, 0x26, 0xff // iddqd
  146. };
  147. const unsigned char cheat_ammo_seq[] =
  148. {
  149. 0xb2, 0x26, 0xf2, 0x66, 0xa2, 0xff // idkfa
  150. };
  151. const unsigned char cheat_ammonokey_seq[] =
  152. {
  153. 0xb2, 0x26, 0x66, 0xa2, 0xff // idfa
  154. };
  155. // Smashing Pumpkins Into Samml Piles Of Putried Debris.
  156. const unsigned char cheat_noclip_seq[] =
  157. {
  158. 0xb2, 0x26, 0xea, 0x2a, 0xb2, // idspispopd
  159. 0xea, 0x2a, 0xf6, 0x2a, 0x26, 0xff
  160. };
  161. //
  162. const unsigned char cheat_commercial_noclip_seq[] =
  163. {
  164. 0xb2, 0x26, 0xe2, 0x36, 0xb2, 0x2a, 0xff // idclip
  165. };
  166. const unsigned char cheat_powerup_seq[7][10] =
  167. {
  168. { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x6e, 0xff }, // beholdv
  169. { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xea, 0xff }, // beholds
  170. { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xb2, 0xff }, // beholdi
  171. { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x6a, 0xff }, // beholdr
  172. { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xa2, 0xff }, // beholda
  173. { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x36, 0xff }, // beholdl
  174. { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xff } // behold
  175. };
  176. const unsigned char cheat_clev_seq[] =
  177. {
  178. 0xb2, 0x26, 0xe2, 0x36, 0xa6, 0x6e, 1, 0, 0, 0xff // idclev
  179. };
  180. // my position cheat
  181. const unsigned char cheat_mypos_seq[] =
  182. {
  183. 0xb2, 0x26, 0xb6, 0xba, 0x2a, 0xf6, 0xea, 0xff // idmypos
  184. };
  185. // Now what?
  186. cheatseq_t cheat_mus = cheatseq_t( cheat_mus_seq, 0 );
  187. cheatseq_t cheat_god = cheatseq_t( cheat_god_seq, 0 );
  188. cheatseq_t cheat_ammo = cheatseq_t( cheat_ammo_seq, 0 );
  189. cheatseq_t cheat_ammonokey = cheatseq_t( cheat_ammonokey_seq, 0 );
  190. cheatseq_t cheat_noclip = cheatseq_t( cheat_noclip_seq, 0 );
  191. cheatseq_t cheat_commercial_noclip = cheatseq_t( cheat_commercial_noclip_seq, 0 );
  192. // ALAN
  193. // DISABLED cheatseq_t( cheat_powerup_seq[0], 0 ), cheatseq_t( cheat_powerup_seq[1], 0 ),
  194. // cheatseq_t( cheat_powerup_seq[2], 0 ),
  195. // DISABLED cheatseq_t( cheat_powerup_seq[3], 0 ),
  196. // cheatseq_t( cheat_powerup_seq[4], 0 ),cheatseq_t( cheat_powerup_seq[5], 0 ),cheatseq_t( cheat_powerup_seq[6], 0 ) };
  197. cheatseq_t cheat_choppers = cheatseq_t( cheat_choppers_seq, 0 );
  198. cheatseq_t cheat_clev = cheatseq_t( cheat_clev_seq, 0 );
  199. cheatseq_t cheat_mypos = cheatseq_t( cheat_mypos_seq, 0 );
  200. //
  201. const extern char* mapnames[];
  202. //
  203. // STATUS BAR CODE
  204. //
  205. void ST_Stop(void);
  206. void ST_refreshBackground(void)
  207. {
  208. if (::g->st_statusbaron)
  209. {
  210. V_DrawPatch(ST_X, 0, BG, ::g->sbar);
  211. if (::g->netgame)
  212. V_DrawPatch(ST_FX, 0, BG, ::g->faceback);
  213. V_CopyRect(ST_X, 0, BG, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y, FG);
  214. }
  215. }
  216. // Respond to keyboard input ::g->events,
  217. // intercept cheats.
  218. qboolean
  219. ST_Responder (event_t* ev)
  220. {
  221. int i;
  222. // Filter automap on/off.
  223. if (ev->type == ev_keyup
  224. && ((ev->data1 & 0xffff0000) == AM_MSGHEADER))
  225. {
  226. switch(ev->data1)
  227. {
  228. case AM_MSGENTERED:
  229. ::g->st_gamestate = AutomapState;
  230. ::g->st_firsttime = true;
  231. break;
  232. case AM_MSGEXITED:
  233. // I_PrintfE( "AM exited\n");
  234. ::g->st_gamestate = FirstPersonState;
  235. break;
  236. }
  237. }
  238. // if a user keypress...
  239. else if (ev->type == ev_keydown)
  240. {
  241. if (!::g->netgame)
  242. {
  243. // b. - enabled for more debug fun.
  244. // if (::g->gameskill != sk_nightmare) {
  245. // 'dqd' cheat for toggleable god mode
  246. if (cht_CheckCheat(&cheat_god, ev->data1))
  247. {
  248. ::g->plyr->cheats ^= CF_GODMODE;
  249. if (::g->plyr->cheats & CF_GODMODE)
  250. {
  251. if (::g->plyr->mo)
  252. ::g->plyr->mo->health = 100;
  253. ::g->plyr->health = 100;
  254. ::g->plyr->message = STSTR_DQDON;
  255. }
  256. else
  257. ::g->plyr->message = STSTR_DQDOFF;
  258. }
  259. // 'fa' cheat for killer fucking arsenal
  260. else if (cht_CheckCheat(&cheat_ammonokey, ev->data1))
  261. {
  262. ::g->plyr->armorpoints = 200;
  263. ::g->plyr->armortype = 2;
  264. for (i=0;i<NUMWEAPONS;i++)
  265. ::g->plyr->weaponowned[i] = true;
  266. for (i=0;i<NUMAMMO;i++)
  267. ::g->plyr->ammo[i] = ::g->plyr->maxammo[i];
  268. ::g->plyr->message = STSTR_FAADDED;
  269. }
  270. // 'kfa' cheat for key full ammo
  271. else if (cht_CheckCheat(&cheat_ammo, ev->data1))
  272. {
  273. ::g->plyr->armorpoints = 200;
  274. ::g->plyr->armortype = 2;
  275. for (i=0;i<NUMWEAPONS;i++)
  276. ::g->plyr->weaponowned[i] = true;
  277. for (i=0;i<NUMAMMO;i++)
  278. ::g->plyr->ammo[i] = ::g->plyr->maxammo[i];
  279. for (i=0;i<NUMCARDS;i++)
  280. ::g->plyr->cards[i] = true;
  281. ::g->plyr->message = STSTR_KFAADDED;
  282. }
  283. // 'mus' cheat for changing music
  284. else if (cht_CheckCheat(&cheat_mus, ev->data1))
  285. {
  286. char buf[3];
  287. int musnum;
  288. ::g->plyr->message = STSTR_MUS;
  289. cht_GetParam(&cheat_mus, buf);
  290. if (::g->gamemode == commercial)
  291. {
  292. musnum = mus_runnin + (buf[0]-'0')*10 + buf[1]-'0' - 1;
  293. if (((buf[0]-'0')*10 + buf[1]-'0') > 35)
  294. ::g->plyr->message = STSTR_NOMUS;
  295. else
  296. S_ChangeMusic(musnum, 1);
  297. }
  298. else
  299. {
  300. musnum = mus_e1m1 + (buf[0]-'1')*9 + (buf[1]-'1');
  301. if (((buf[0]-'1')*9 + buf[1]-'1') > 31)
  302. ::g->plyr->message = STSTR_NOMUS;
  303. else
  304. S_ChangeMusic(musnum, 1);
  305. }
  306. }
  307. // Simplified, accepting both "noclip" and "idspispopd".
  308. // no clipping mode cheat
  309. else if ( cht_CheckCheat(&cheat_noclip, ev->data1)
  310. || cht_CheckCheat(&cheat_commercial_noclip,ev->data1) )
  311. {
  312. ::g->plyr->cheats ^= CF_NOCLIP;
  313. if (::g->plyr->cheats & CF_NOCLIP)
  314. ::g->plyr->message = STSTR_NCON;
  315. else
  316. ::g->plyr->message = STSTR_NCOFF;
  317. }
  318. // 'behold?' power-up cheats
  319. for (i=0;i<6;i++)
  320. {
  321. if (cht_CheckCheat(&::g->cheat_powerup[i], ev->data1))
  322. {
  323. if (!::g->plyr->powers[i])
  324. P_GivePower( ::g->plyr, i);
  325. else if (i!=pw_strength)
  326. ::g->plyr->powers[i] = 1;
  327. else
  328. ::g->plyr->powers[i] = 0;
  329. ::g->plyr->message = STSTR_BEHOLDX;
  330. }
  331. }
  332. // 'behold' power-up menu
  333. if (cht_CheckCheat(&::g->cheat_powerup[6], ev->data1))
  334. {
  335. ::g->plyr->message = STSTR_BEHOLD;
  336. }
  337. // 'choppers' invulnerability & chainsaw
  338. else if (cht_CheckCheat(&cheat_choppers, ev->data1))
  339. {
  340. ::g->plyr->weaponowned[wp_chainsaw] = true;
  341. ::g->plyr->powers[pw_invulnerability] = true;
  342. ::g->plyr->message = STSTR_CHOPPERS;
  343. }
  344. // 'mypos' for player position
  345. else if (cht_CheckCheat(&cheat_mypos, ev->data1))
  346. {
  347. static char buf[ST_MSGWIDTH];
  348. sprintf(buf, "ang=0x%x;x,y=(0x%x,0x%x)",
  349. ::g->players[::g->consoleplayer].mo->angle,
  350. ::g->players[::g->consoleplayer].mo->x,
  351. ::g->players[::g->consoleplayer].mo->y);
  352. ::g->plyr->message = buf;
  353. }
  354. }
  355. // 'clev' change-level cheat
  356. // ALAN NETWORKING
  357. if (false) // cht_CheckCheat(&cheat_clev, ev->data1))
  358. {
  359. char buf[3];
  360. int epsd;
  361. int map;
  362. cht_GetParam(&cheat_clev, buf);
  363. if (::g->gamemode == commercial)
  364. {
  365. epsd = 0;
  366. map = (buf[0] - '0')*10 + buf[1] - '0';
  367. }
  368. else
  369. {
  370. epsd = buf[0] - '0';
  371. map = buf[1] - '0';
  372. }
  373. // Catch invalid maps.
  374. if (epsd < 1)
  375. return false;
  376. if (map < 1)
  377. return false;
  378. // Ohmygod - this is not going to work.
  379. if ((::g->gamemode == retail)
  380. && ((epsd > 4) || (map > 9)))
  381. return false;
  382. if ((::g->gamemode == registered)
  383. && ((epsd > 3) || (map > 9)))
  384. return false;
  385. if ((::g->gamemode == shareware)
  386. && ((epsd > 1) || (map > 9)))
  387. return false;
  388. if ((::g->gamemode == commercial)
  389. && (( epsd > 1) || (map > 34)))
  390. return false;
  391. // So be it.
  392. ::g->plyr->message = STSTR_CLEV;
  393. G_DeferedInitNew(::g->gameskill, epsd, map);
  394. }
  395. }
  396. return false;
  397. }
  398. int ST_calcPainOffset(void)
  399. {
  400. int health;
  401. health = ::g->plyr->health > 100 ? 100 : ::g->plyr->health;
  402. if (health != ::g->oldhealth)
  403. {
  404. ::g->lastcalc = ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101);
  405. ::g->oldhealth = health;
  406. }
  407. return ::g->lastcalc;
  408. }
  409. //
  410. // This is a not-very-pretty routine which handles
  411. // the face states and their timing.
  412. // the precedence of expressions is:
  413. // dead > evil grin > turned head > straight ahead
  414. //
  415. void ST_updateFaceWidget(void)
  416. {
  417. int i;
  418. angle_t badguyangle;
  419. angle_t diffang;
  420. qboolean doevilgrin;
  421. if (::g->priority < 10)
  422. {
  423. // dead
  424. if (!::g->plyr->health)
  425. {
  426. ::g->priority = 9;
  427. ::g->st_faceindex = ST_DEADFACE;
  428. ::g->st_facecount = 1;
  429. }
  430. }
  431. if (::g->priority < 9)
  432. {
  433. if (::g->plyr->bonuscount)
  434. {
  435. // picking up bonus
  436. doevilgrin = false;
  437. for (i=0;i<NUMWEAPONS;i++)
  438. {
  439. if (::g->oldweaponsowned[i] != ::g->plyr->weaponowned[i])
  440. {
  441. doevilgrin = true;
  442. ::g->oldweaponsowned[i] = ::g->plyr->weaponowned[i];
  443. }
  444. }
  445. if (doevilgrin)
  446. {
  447. // evil grin if just picked up weapon
  448. ::g->priority = 8;
  449. ::g->st_facecount = ST_EVILGRINCOUNT;
  450. ::g->st_faceindex = ST_calcPainOffset() + ST_EVILGRINOFFSET;
  451. }
  452. }
  453. }
  454. if (::g->priority < 8)
  455. {
  456. if (::g->plyr->damagecount
  457. && ::g->plyr->attacker
  458. && ::g->plyr->attacker != ::g->plyr->mo)
  459. {
  460. // being attacked
  461. ::g->priority = 7;
  462. if (::g->plyr->health - ::g->st_oldhealth > ST_MUCHPAIN)
  463. {
  464. ::g->st_facecount = ST_TURNCOUNT;
  465. ::g->st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET;
  466. }
  467. else
  468. {
  469. badguyangle = R_PointToAngle2(::g->plyr->mo->x,
  470. ::g->plyr->mo->y,
  471. ::g->plyr->attacker->x,
  472. ::g->plyr->attacker->y);
  473. if (badguyangle > ::g->plyr->mo->angle)
  474. {
  475. // whether right or left
  476. diffang = badguyangle - ::g->plyr->mo->angle;
  477. i = diffang > ANG180;
  478. }
  479. else
  480. {
  481. // whether left or right
  482. diffang = ::g->plyr->mo->angle - badguyangle;
  483. i = diffang <= ANG180;
  484. } // confusing, aint it?
  485. ::g->st_facecount = ST_TURNCOUNT;
  486. ::g->st_faceindex = ST_calcPainOffset();
  487. if (diffang < ANG45)
  488. {
  489. // head-on
  490. ::g->st_faceindex += ST_RAMPAGEOFFSET;
  491. }
  492. else if (i)
  493. {
  494. // turn face right
  495. ::g->st_faceindex += ST_TURNOFFSET;
  496. }
  497. else
  498. {
  499. // turn face left
  500. ::g->st_faceindex += ST_TURNOFFSET+1;
  501. }
  502. }
  503. }
  504. }
  505. if (::g->priority < 7)
  506. {
  507. // getting hurt because of your own damn stupidity
  508. if (::g->plyr->damagecount)
  509. {
  510. if (::g->plyr->health - ::g->st_oldhealth > ST_MUCHPAIN)
  511. {
  512. ::g->priority = 7;
  513. ::g->st_facecount = ST_TURNCOUNT;
  514. ::g->st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET;
  515. }
  516. else
  517. {
  518. ::g->priority = 6;
  519. ::g->st_facecount = ST_TURNCOUNT;
  520. ::g->st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET;
  521. }
  522. }
  523. }
  524. if (::g->priority < 6)
  525. {
  526. // rapid firing
  527. if (::g->plyr->attackdown)
  528. {
  529. if (::g->lastattackdown==-1)
  530. ::g->lastattackdown = ST_RAMPAGEDELAY;
  531. else if (!--::g->lastattackdown)
  532. {
  533. ::g->priority = 5;
  534. ::g->st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET;
  535. ::g->st_facecount = 1;
  536. ::g->lastattackdown = 1;
  537. }
  538. }
  539. else
  540. ::g->lastattackdown = -1;
  541. }
  542. if (::g->priority < 5)
  543. {
  544. // invulnerability
  545. if ((::g->plyr->cheats & CF_GODMODE)
  546. || ::g->plyr->powers[pw_invulnerability])
  547. {
  548. ::g->priority = 4;
  549. ::g->st_faceindex = ST_GODFACE;
  550. ::g->st_facecount = 1;
  551. }
  552. }
  553. // look left or look right if the facecount has timed out
  554. if (!::g->st_facecount)
  555. {
  556. ::g->st_faceindex = ST_calcPainOffset() + (::g->st_randomnumber % 3);
  557. ::g->st_facecount = ST_STRAIGHTFACECOUNT;
  558. ::g->priority = 0;
  559. }
  560. ::g->st_facecount--;
  561. }
  562. void ST_updateWidgets(void)
  563. {
  564. int i;
  565. // must redirect the pointer if the ready weapon has changed.
  566. // if (::g->w_ready.data != ::g->plyr->readyweapon)
  567. // {
  568. if (weaponinfo[::g->plyr->readyweapon].ammo == am_noammo)
  569. ::g->w_ready.num = &::g->largeammo;
  570. else
  571. ::g->w_ready.num = &::g->plyr->ammo[weaponinfo[::g->plyr->readyweapon].ammo];
  572. //{
  573. // static int tic=0;
  574. // static int dir=-1;
  575. // if (!(tic&15))
  576. // ::g->plyr->ammo[weaponinfo[::g->plyr->readyweapon].ammo]+=dir;
  577. // if (::g->plyr->ammo[weaponinfo[::g->plyr->readyweapon].ammo] == -100)
  578. // dir = 1;
  579. // tic++;
  580. // }
  581. ::g->w_ready.data = ::g->plyr->readyweapon;
  582. // if (*::g->w_ready.on)
  583. // STlib_updateNum(&::g->w_ready, true);
  584. // refresh weapon change
  585. // }
  586. // update keycard multiple widgets
  587. for (i=0;i<3;i++)
  588. {
  589. ::g->keyboxes[i] = ::g->plyr->cards[i] ? i : -1;
  590. if (::g->plyr->cards[i+3])
  591. ::g->keyboxes[i] = i+3;
  592. }
  593. // refresh everything if this is him coming back to life
  594. ST_updateFaceWidget();
  595. // used by the ::g->w_armsbg widget
  596. ::g->st_notdeathmatch = !::g->deathmatch;
  597. // used by ::g->w_arms[] widgets
  598. ::g->st_armson = ::g->st_statusbaron && !::g->deathmatch;
  599. // used by ::g->w_frags widget
  600. ::g->st_fragson = ::g->deathmatch && ::g->st_statusbaron;
  601. ::g->st_fragscount = 0;
  602. for (i=0 ; i<MAXPLAYERS ; i++)
  603. {
  604. if (i != ::g->consoleplayer)
  605. ::g->st_fragscount += ::g->plyr->frags[i];
  606. else
  607. ::g->st_fragscount -= ::g->plyr->frags[i];
  608. }
  609. // get rid of chat window if up because of message
  610. if (!--::g->st_msgcounter)
  611. ::g->st_chat = ::g->st_oldchat;
  612. }
  613. void ST_Ticker (void)
  614. {
  615. ::g->st_clock++;
  616. ::g->st_randomnumber = M_Random();
  617. ST_updateWidgets();
  618. ::g->st_oldhealth = ::g->plyr->health;
  619. }
  620. void ST_doPaletteStuff(void)
  621. {
  622. int palette;
  623. byte* pal;
  624. int cnt;
  625. int bzc;
  626. cnt = ::g->plyr->damagecount;
  627. if (::g->plyr->powers[pw_strength])
  628. {
  629. // slowly fade the berzerk out
  630. bzc = 12 - (::g->plyr->powers[pw_strength]>>6);
  631. if (bzc > cnt)
  632. cnt = bzc;
  633. }
  634. if (cnt)
  635. {
  636. palette = (cnt+7)>>3;
  637. if (palette >= NUMREDPALS)
  638. palette = NUMREDPALS-1;
  639. palette += STARTREDPALS;
  640. }
  641. else if (::g->plyr->bonuscount)
  642. {
  643. palette = (::g->plyr->bonuscount+7)>>3;
  644. if (palette >= NUMBONUSPALS)
  645. palette = NUMBONUSPALS-1;
  646. palette += STARTBONUSPALS;
  647. }
  648. else if ( ::g->plyr->powers[pw_ironfeet] > 4*32
  649. || ::g->plyr->powers[pw_ironfeet]&8)
  650. palette = RADIATIONPAL;
  651. else
  652. palette = 0;
  653. if (palette != ::g->st_palette)
  654. {
  655. ::g->st_palette = palette;
  656. pal = (byte *) W_CacheLumpNum (::g->lu_palette, PU_CACHE_SHARED)+palette*768;
  657. I_SetPalette (pal);
  658. }
  659. }
  660. void ST_drawWidgets(qboolean refresh)
  661. {
  662. int i;
  663. ::g->st_notdeathmatch = !::g->deathmatch;
  664. // used by ::g->w_arms[] widgets
  665. ::g->st_armson = ::g->st_statusbaron && !::g->deathmatch;
  666. // used by ::g->w_frags widget
  667. ::g->st_fragson = ::g->deathmatch && ::g->st_statusbaron;
  668. STlib_updateNum(&::g->w_ready, refresh);
  669. for (i=0;i<4;i++)
  670. {
  671. STlib_updateNum(&::g->w_ammo[i], refresh);
  672. STlib_updateNum(&::g->w_maxammo[i], refresh);
  673. }
  674. STlib_updatePercent(&::g->w_health, refresh);
  675. STlib_updatePercent(&::g->w_armor, refresh);
  676. STlib_updateBinIcon(&::g->w_armsbg, refresh);
  677. for (i=0;i<6;i++)
  678. STlib_updateMultIcon(&::g->w_arms[i], refresh);
  679. STlib_updateMultIcon(&::g->w_faces, refresh);
  680. for (i=0;i<3;i++)
  681. STlib_updateMultIcon(&::g->w_keyboxes[i], refresh);
  682. STlib_updateNum(&::g->w_frags, refresh);
  683. }
  684. void ST_doRefresh(void)
  685. {
  686. ::g->st_firsttime = false;
  687. // draw status bar background to off-screen buff
  688. ST_refreshBackground();
  689. // and refresh all widgets
  690. ST_drawWidgets(true);
  691. }
  692. void ST_diffDraw(void)
  693. {
  694. // update all widgets
  695. ST_drawWidgets(false);
  696. }
  697. void ST_Drawer (qboolean fullscreen, qboolean refresh)
  698. {
  699. ::g->st_statusbaron = (!fullscreen) || ::g->automapactive;
  700. ::g->st_firsttime = ::g->st_firsttime || refresh;
  701. // Do red-/gold-shifts from damage/items
  702. ST_doPaletteStuff();
  703. // If just after ST_Start(), refresh all
  704. if (::g->st_firsttime) ST_doRefresh();
  705. // Otherwise, update as little as possible
  706. else ST_diffDraw();
  707. }
  708. void ST_loadGraphics(void)
  709. {
  710. static bool ST_HasBeenCalled = false;
  711. // if (ST_HasBeenCalled == true)
  712. // return;
  713. ST_HasBeenCalled = true;
  714. int i;
  715. int j;
  716. int facenum;
  717. char namebuf[9];
  718. // Load the numbers, tall and short
  719. for (i=0;i<10;i++)
  720. {
  721. sprintf(namebuf, "STTNUM%d", i);
  722. ::g->tallnum[i] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC_SHARED);
  723. sprintf(namebuf, "STYSNUM%d", i);
  724. ::g->shortnum[i] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC_SHARED);
  725. }
  726. // Load percent key.
  727. //Note: why not load STMINUS here, too?
  728. ::g->tallpercent = (patch_t *) W_CacheLumpName("STTPRCNT", PU_STATIC_SHARED);
  729. // key cards
  730. for (i=0;i<NUMCARDS;i++)
  731. {
  732. sprintf(namebuf, "STKEYS%d", i);
  733. ::g->keys[i] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC_SHARED);
  734. }
  735. // ::g->arms background
  736. ::g->armsbg = (patch_t *) W_CacheLumpName("STARMS", PU_STATIC_SHARED);
  737. // ::g->arms ownership widgets
  738. for (i=0;i<6;i++)
  739. {
  740. sprintf(namebuf, "STGNUM%d", i+2);
  741. // gray #
  742. ::g->arms[i][0] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC_SHARED);
  743. // yellow #
  744. ::g->arms[i][1] = ::g->shortnum[i+2];
  745. }
  746. // face backgrounds for different color ::g->players
  747. sprintf(namebuf, "STFB%d", ::g->consoleplayer);
  748. ::g->faceback = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC_SHARED);
  749. // status bar background bits
  750. ::g->sbar = (patch_t *) W_CacheLumpName("STBAR", PU_STATIC_SHARED);
  751. // face states
  752. facenum = 0;
  753. for (i=0;i<ST_NUMPAINFACES;i++)
  754. {
  755. for (j=0;j<ST_NUMSTRAIGHTFACES;j++)
  756. {
  757. sprintf(namebuf, "STFST%d%d", i, j);
  758. ::g->faces[facenum++] = (patch_t*)W_CacheLumpName(namebuf, PU_STATIC_SHARED);
  759. }
  760. sprintf(namebuf, "STFTR%d0", i); // turn right
  761. ::g->faces[facenum++] = (patch_t*)W_CacheLumpName(namebuf, PU_STATIC_SHARED);
  762. sprintf(namebuf, "STFTL%d0", i); // turn left
  763. ::g->faces[facenum++] = (patch_t*)W_CacheLumpName(namebuf, PU_STATIC_SHARED);
  764. sprintf(namebuf, "STFOUCH%d", i); // ouch!
  765. ::g->faces[facenum++] = (patch_t*)W_CacheLumpName(namebuf, PU_STATIC_SHARED);
  766. sprintf(namebuf, "STFEVL%d", i); // evil grin ;)
  767. ::g->faces[facenum++] = (patch_t*)W_CacheLumpName(namebuf, PU_STATIC_SHARED);
  768. sprintf(namebuf, "STFKILL%d", i); // pissed off
  769. ::g->faces[facenum++] = (patch_t*)W_CacheLumpName(namebuf, PU_STATIC_SHARED);
  770. }
  771. ::g->faces[facenum++] = (patch_t*)W_CacheLumpName("STFGOD0", PU_STATIC_SHARED);
  772. ::g->faces[facenum++] = (patch_t*)W_CacheLumpName("STFDEAD0", PU_STATIC_SHARED);
  773. }
  774. void ST_loadData(void)
  775. {
  776. ::g->lu_palette = W_GetNumForName ("PLAYPAL");
  777. ST_loadGraphics();
  778. }
  779. void ST_unloadGraphics(void)
  780. {
  781. // These things are always reloaded... so just don't bother to clean them up!
  782. }
  783. void ST_unloadData(void)
  784. {
  785. ST_unloadGraphics();
  786. }
  787. void ST_initData(void)
  788. {
  789. int i;
  790. ::g->st_firsttime = true;
  791. ::g->plyr = &::g->players[::g->consoleplayer];
  792. ::g->st_clock = 0;
  793. ::g->st_chatstate = StartChatState;
  794. ::g->st_gamestate = FirstPersonState;
  795. ::g->st_statusbaron = true;
  796. ::g->st_oldchat = ::g->st_chat = false;
  797. ::g->st_cursoron = false;
  798. ::g->st_faceindex = 0;
  799. ::g->st_palette = -1;
  800. ::g->st_oldhealth = -1;
  801. for (i=0;i<NUMWEAPONS;i++)
  802. ::g->oldweaponsowned[i] = ::g->plyr->weaponowned[i];
  803. for (i=0;i<3;i++)
  804. ::g->keyboxes[i] = -1;
  805. STlib_init();
  806. }
  807. void ST_createWidgets(void)
  808. {
  809. int i;
  810. // ready weapon ammo
  811. STlib_initNum(&::g->w_ready,
  812. ST_AMMOX,
  813. ST_AMMOY,
  814. ::g->tallnum,
  815. &::g->plyr->ammo[weaponinfo[::g->plyr->readyweapon].ammo],
  816. &::g->st_statusbaron,
  817. ST_AMMOWIDTH );
  818. // the last weapon type
  819. ::g->w_ready.data = ::g->plyr->readyweapon;
  820. // health percentage
  821. STlib_initPercent(&::g->w_health,
  822. ST_HEALTHX,
  823. ST_HEALTHY,
  824. ::g->tallnum,
  825. &::g->plyr->health,
  826. &::g->st_statusbaron,
  827. ::g->tallpercent);
  828. // ::g->arms background
  829. STlib_initBinIcon(&::g->w_armsbg,
  830. ST_ARMSBGX,
  831. ST_ARMSBGY,
  832. ::g->armsbg,
  833. &::g->st_notdeathmatch,
  834. &::g->st_statusbaron);
  835. // weapons owned
  836. for(i=0;i<6;i++)
  837. {
  838. STlib_initMultIcon(&::g->w_arms[i],
  839. ST_ARMSX+(i%3)*ST_ARMSXSPACE,
  840. ST_ARMSY+(i/3)*ST_ARMSYSPACE,
  841. ::g->arms[i], (int *) &::g->plyr->weaponowned[i+1],
  842. &::g->st_armson);
  843. }
  844. // frags sum
  845. STlib_initNum(&::g->w_frags,
  846. ST_FRAGSX,
  847. ST_FRAGSY,
  848. ::g->tallnum,
  849. &::g->st_fragscount,
  850. &::g->st_fragson,
  851. ST_FRAGSWIDTH);
  852. // ::g->faces
  853. STlib_initMultIcon(&::g->w_faces,
  854. ST_FACESX,
  855. ST_FACESY,
  856. ::g->faces,
  857. &::g->st_faceindex,
  858. &::g->st_statusbaron);
  859. // armor percentage - should be colored later
  860. STlib_initPercent(&::g->w_armor,
  861. ST_ARMORX,
  862. ST_ARMORY,
  863. ::g->tallnum,
  864. &::g->plyr->armorpoints,
  865. &::g->st_statusbaron, ::g->tallpercent);
  866. // ::g->keyboxes 0-2
  867. STlib_initMultIcon(&::g->w_keyboxes[0],
  868. ST_KEY0X,
  869. ST_KEY0Y,
  870. ::g->keys,
  871. &::g->keyboxes[0],
  872. &::g->st_statusbaron);
  873. STlib_initMultIcon(&::g->w_keyboxes[1],
  874. ST_KEY1X,
  875. ST_KEY1Y,
  876. ::g->keys,
  877. &::g->keyboxes[1],
  878. &::g->st_statusbaron);
  879. STlib_initMultIcon(&::g->w_keyboxes[2],
  880. ST_KEY2X,
  881. ST_KEY2Y,
  882. ::g->keys,
  883. &::g->keyboxes[2],
  884. &::g->st_statusbaron);
  885. // ammo count (all four kinds)
  886. STlib_initNum(&::g->w_ammo[0],
  887. ST_AMMO0X,
  888. ST_AMMO0Y,
  889. ::g->shortnum,
  890. &::g->plyr->ammo[0],
  891. &::g->st_statusbaron,
  892. ST_AMMO0WIDTH);
  893. STlib_initNum(&::g->w_ammo[1],
  894. ST_AMMO1X,
  895. ST_AMMO1Y,
  896. ::g->shortnum,
  897. &::g->plyr->ammo[1],
  898. &::g->st_statusbaron,
  899. ST_AMMO1WIDTH);
  900. STlib_initNum(&::g->w_ammo[2],
  901. ST_AMMO2X,
  902. ST_AMMO2Y,
  903. ::g->shortnum,
  904. &::g->plyr->ammo[2],
  905. &::g->st_statusbaron,
  906. ST_AMMO2WIDTH);
  907. STlib_initNum(&::g->w_ammo[3],
  908. ST_AMMO3X,
  909. ST_AMMO3Y,
  910. ::g->shortnum,
  911. &::g->plyr->ammo[3],
  912. &::g->st_statusbaron,
  913. ST_AMMO3WIDTH);
  914. // max ammo count (all four kinds)
  915. STlib_initNum(&::g->w_maxammo[0],
  916. ST_MAXAMMO0X,
  917. ST_MAXAMMO0Y,
  918. ::g->shortnum,
  919. &::g->plyr->maxammo[0],
  920. &::g->st_statusbaron,
  921. ST_MAXAMMO0WIDTH);
  922. STlib_initNum(&::g->w_maxammo[1],
  923. ST_MAXAMMO1X,
  924. ST_MAXAMMO1Y,
  925. ::g->shortnum,
  926. &::g->plyr->maxammo[1],
  927. &::g->st_statusbaron,
  928. ST_MAXAMMO1WIDTH);
  929. STlib_initNum(&::g->w_maxammo[2],
  930. ST_MAXAMMO2X,
  931. ST_MAXAMMO2Y,
  932. ::g->shortnum,
  933. &::g->plyr->maxammo[2],
  934. &::g->st_statusbaron,
  935. ST_MAXAMMO2WIDTH);
  936. STlib_initNum(&::g->w_maxammo[3],
  937. ST_MAXAMMO3X,
  938. ST_MAXAMMO3Y,
  939. ::g->shortnum,
  940. &::g->plyr->maxammo[3],
  941. &::g->st_statusbaron,
  942. ST_MAXAMMO3WIDTH);
  943. }
  944. void ST_Start (void)
  945. {
  946. if (!::g->st_stopped)
  947. ST_Stop();
  948. ST_initData();
  949. ST_createWidgets();
  950. ::g->st_stopped = false;
  951. }
  952. void ST_Stop (void)
  953. {
  954. if (::g->st_stopped)
  955. return;
  956. I_SetPalette ((byte*)W_CacheLumpNum ((int)::g->lu_palette, PU_CACHE_SHARED));
  957. ::g->st_stopped = true;
  958. }
  959. void ST_Init (void)
  960. {
  961. ::g->veryfirsttime = 0;
  962. ST_loadData();
  963. ::g->screens[4] = (byte *) DoomLib::Z_Malloc( SCREENWIDTH * SCREENHEIGHT /*ST_WIDTH*ST_HEIGHT*/, PU_STATIC, 0);
  964. memset( ::g->screens[4], 0, SCREENWIDTH * SCREENHEIGHT );
  965. }
  966. CONSOLE_COMMAND_SHIP( idqd, "cheat for toggleable god mode", 0 ) {
  967. int oldPlayer = DoomLib::GetPlayer();
  968. DoomLib::SetPlayer( 0 );
  969. if ( ::g == NULL ) {
  970. return;
  971. }
  972. if (::g->gamestate != GS_LEVEL) {
  973. return;
  974. }
  975. ::g->plyr->cheats ^= CF_GODMODE;
  976. if (::g->plyr->cheats & CF_GODMODE)
  977. {
  978. if (::g->plyr->mo)
  979. ::g->plyr->mo->health = 100;
  980. ::g->plyr->health = 100;
  981. ::g->plyr->message = STSTR_DQDON;
  982. }
  983. else
  984. ::g->plyr->message = STSTR_DQDOFF;
  985. DoomLib::SetPlayer( oldPlayer );
  986. }
  987. CONSOLE_COMMAND_SHIP( idfa, "cheat for killer fucking arsenal", 0 ) {
  988. int oldPlayer = DoomLib::GetPlayer();
  989. DoomLib::SetPlayer( 0 );
  990. if ( ::g == NULL ) {
  991. return;
  992. }
  993. if (::g->gamestate != GS_LEVEL) {
  994. return;
  995. }
  996. int i = 0;
  997. ::g->plyr->armorpoints = 200;
  998. ::g->plyr->armortype = 2;
  999. for (i=0;i<NUMWEAPONS;i++)
  1000. ::g->plyr->weaponowned[i] = true;
  1001. for (i=0;i<NUMAMMO;i++)
  1002. ::g->plyr->ammo[i] = ::g->plyr->maxammo[i];
  1003. ::g->plyr->message = STSTR_FAADDED;
  1004. DoomLib::SetPlayer( oldPlayer );
  1005. }
  1006. CONSOLE_COMMAND_SHIP( idkfa, "cheat for key full ammo", 0 ) {
  1007. int oldPlayer = DoomLib::GetPlayer();
  1008. DoomLib::SetPlayer( 0 );
  1009. if ( ::g == NULL ) {
  1010. return;
  1011. }
  1012. if (::g->gamestate != GS_LEVEL) {
  1013. return;
  1014. }
  1015. int i = 0;
  1016. ::g->plyr->armorpoints = 200;
  1017. ::g->plyr->armortype = 2;
  1018. for (i=0;i<NUMWEAPONS;i++)
  1019. ::g->plyr->weaponowned[i] = true;
  1020. for (i=0;i<NUMAMMO;i++)
  1021. ::g->plyr->ammo[i] = ::g->plyr->maxammo[i];
  1022. for (i=0;i<NUMCARDS;i++)
  1023. ::g->plyr->cards[i] = true;
  1024. ::g->plyr->message = STSTR_KFAADDED;
  1025. DoomLib::SetPlayer( oldPlayer );
  1026. }
  1027. CONSOLE_COMMAND_SHIP( idclip, "cheat for no clip", 0 ) {
  1028. int oldPlayer = DoomLib::GetPlayer();
  1029. DoomLib::SetPlayer( 0 );
  1030. if ( ::g == NULL ) {
  1031. return;
  1032. }
  1033. if (::g->gamestate != GS_LEVEL) {
  1034. return;
  1035. }
  1036. ::g->plyr->cheats ^= CF_NOCLIP;
  1037. if (::g->plyr->cheats & CF_NOCLIP)
  1038. ::g->plyr->message = STSTR_NCON;
  1039. else
  1040. ::g->plyr->message = STSTR_NCOFF;
  1041. DoomLib::SetPlayer( oldPlayer );
  1042. }
  1043. CONSOLE_COMMAND_SHIP( idmypos, "for player position", 0 ) {
  1044. int oldPlayer = DoomLib::GetPlayer();
  1045. DoomLib::SetPlayer( 0 );
  1046. if ( ::g == NULL ) {
  1047. return;
  1048. }
  1049. if (::g->gamestate != GS_LEVEL) {
  1050. return;
  1051. }
  1052. static char buf[ST_MSGWIDTH];
  1053. sprintf(buf, "ang=0x%x;x,y=(0x%x,0x%x)",
  1054. ::g->players[::g->consoleplayer].mo->angle,
  1055. ::g->players[::g->consoleplayer].mo->x,
  1056. ::g->players[::g->consoleplayer].mo->y);
  1057. ::g->plyr->message = buf;
  1058. DoomLib::SetPlayer( oldPlayer );
  1059. }
  1060. CONSOLE_COMMAND_SHIP( idclev, "warp to next level", 0 ) {
  1061. int oldPlayer = DoomLib::GetPlayer();
  1062. DoomLib::SetPlayer( 0 );
  1063. if ( ::g == NULL ) {
  1064. return;
  1065. }
  1066. if (::g->gamestate != GS_LEVEL) {
  1067. return;
  1068. }
  1069. int epsd;
  1070. int map;
  1071. if (::g->gamemode == commercial)
  1072. {
  1073. if( args.Argc() > 1 ) {
  1074. epsd = 1;
  1075. map = atoi( args.Argv( 1 ) );
  1076. } else {
  1077. idLib::Printf( "idclev takes map as first argument \n" );
  1078. return;
  1079. }
  1080. if( map > 32 ) {
  1081. map = 1;
  1082. }
  1083. }
  1084. else
  1085. {
  1086. if( args.Argc() > 2 ) {
  1087. epsd = atoi( args.Argv( 1 ) );
  1088. map = atoi( args.Argv( 2 ) );
  1089. } else {
  1090. idLib::Printf( "idclev takes episode and map as first two arguments \n" );
  1091. return;
  1092. }
  1093. }
  1094. // Catch invalid maps.
  1095. if (epsd < 1)
  1096. return;
  1097. if (map < 1)
  1098. return;
  1099. // Ohmygod - this is not going to work.
  1100. if ((::g->gamemode == retail)
  1101. && ((epsd > 4) || (map > 9)))
  1102. return;
  1103. if ((::g->gamemode == registered)
  1104. && ((epsd > 3) || (map > 9)))
  1105. return;
  1106. if ((::g->gamemode == shareware)
  1107. && ((epsd > 1) || (map > 9)))
  1108. return;
  1109. if ((::g->gamemode == commercial)
  1110. && (( epsd > 1) || (map > 34)))
  1111. return;
  1112. // So be it.
  1113. ::g->plyr->message = STSTR_CLEV;
  1114. G_DeferedInitNew(::g->gameskill, epsd, map);
  1115. DoomLib::SetPlayer( oldPlayer );
  1116. }