]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/doom/st_stuff.c
change /dev/kbd to return multiple messages per read
[plan9front.git] / sys / src / games / doom / st_stuff.c
1 // Emacs style mode select   -*- C++ -*- 
2 //-----------------------------------------------------------------------------
3 //
4 // $Id:$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
11 //
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
16 //
17 // $Log:$
18 //
19 // DESCRIPTION:
20 //      Status bar code.
21 //      Does the face/direction indicator animatin.
22 //      Does palette indicators as well (red pain/berserk, bright pickup)
23 //
24 //-----------------------------------------------------------------------------
25
26 static const char
27 rcsid[] = "$Id: st_stuff.c,v 1.6 1997/02/03 22:45:13 b1 Exp $";
28
29 #include "i_system.h"
30 #include "i_video.h"
31 #include "z_zone.h"
32 #include "m_random.h"
33 #include "w_wad.h"
34
35 #include "doomdef.h"
36
37 #include "g_game.h"
38
39 #include "st_stuff.h"
40 #include "st_lib.h"
41 #include "r_local.h"
42
43 #include "p_local.h"
44 #include "p_inter.h"
45
46 #include "am_map.h"
47 #include "m_cheat.h"
48
49 #include "s_sound.h"
50
51 // Needs access to LFB.
52 #include "v_video.h"
53
54 // State.
55 #include "doomstat.h"
56
57 // Data.
58 #include "dstrings.h"
59 #include "sounds.h"
60
61 //
62 // STATUS BAR DATA
63 //
64
65
66 // Palette indices.
67 // For damage/bonus red-/gold-shifts
68 #define STARTREDPALS            1
69 #define STARTBONUSPALS          9
70 #define NUMREDPALS                      8
71 #define NUMBONUSPALS            4
72 // Radiation suit, green shift.
73 #define RADIATIONPAL            13
74
75 // N/256*100% probability
76 //  that the normal face state will change
77 #define ST_FACEPROBABILITY              96
78
79 // For Responder
80 #define ST_TOGGLECHAT           KEY_ENTER
81
82 // Location of status bar
83 #define ST_X                            0
84 #define ST_X2                           104
85
86 #define ST_FX                   143
87 #define ST_FY                   169
88
89 // Should be set to patch width
90 //  for tall numbers later on
91 #define ST_TALLNUMWIDTH         (tallnum[0]->width)
92
93 // Number of status faces.
94 #define ST_NUMPAINFACES         5
95 #define ST_NUMSTRAIGHTFACES     3
96 #define ST_NUMTURNFACES         2
97 #define ST_NUMSPECIALFACES              3
98
99 #define ST_FACESTRIDE \
100           (ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES)
101
102 #define ST_NUMEXTRAFACES                2
103
104 #define ST_NUMFACES \
105           (ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES)
106
107 #define ST_TURNOFFSET           (ST_NUMSTRAIGHTFACES)
108 #define ST_OUCHOFFSET           (ST_TURNOFFSET + ST_NUMTURNFACES)
109 #define ST_EVILGRINOFFSET               (ST_OUCHOFFSET + 1)
110 #define ST_RAMPAGEOFFSET                (ST_EVILGRINOFFSET + 1)
111 #define ST_GODFACE                      (ST_NUMPAINFACES*ST_FACESTRIDE)
112 #define ST_DEADFACE                     (ST_GODFACE+1)
113
114 #define ST_FACESX                       143
115 #define ST_FACESY                       168
116
117 #define ST_EVILGRINCOUNT                (2*TICRATE)
118 #define ST_STRAIGHTFACECOUNT    (TICRATE/2)
119 #define ST_TURNCOUNT            (1*TICRATE)
120 #define ST_OUCHCOUNT            (1*TICRATE)
121 #define ST_RAMPAGEDELAY         (2*TICRATE)
122
123 #define ST_MUCHPAIN                     20
124
125
126 // Location and size of statistics,
127 //  justified according to widget type.
128 // Problem is, within which space? STbar? Screen?
129 // Note: this could be read in by a lump.
130 //       Problem is, is the stuff rendered
131 //       into a buffer,
132 //       or into the frame buffer?
133
134 // AMMO number pos.
135 #define ST_AMMOWIDTH            3       
136 #define ST_AMMOX                        44
137 #define ST_AMMOY                        171
138
139 // HEALTH number pos.
140 #define ST_HEALTHWIDTH          3       
141 #define ST_HEALTHX                      90
142 #define ST_HEALTHY                      171
143
144 // Weapon pos.
145 #define ST_ARMSX                        111
146 #define ST_ARMSY                        172
147 #define ST_ARMSBGX                      104
148 #define ST_ARMSBGY                      168
149 #define ST_ARMSXSPACE           12
150 #define ST_ARMSYSPACE           10
151
152 // Frags pos.
153 #define ST_FRAGSX                       138
154 #define ST_FRAGSY                       171     
155 #define ST_FRAGSWIDTH           2
156
157 // ARMOR number pos.
158 #define ST_ARMORWIDTH           3
159 #define ST_ARMORX                       221
160 #define ST_ARMORY                       171
161
162 // Key icon positions.
163 #define ST_KEY0WIDTH            8
164 #define ST_KEY0HEIGHT           5
165 #define ST_KEY0X                        239
166 #define ST_KEY0Y                        171
167 #define ST_KEY1WIDTH            ST_KEY0WIDTH
168 #define ST_KEY1X                        239
169 #define ST_KEY1Y                        181
170 #define ST_KEY2WIDTH            ST_KEY0WIDTH
171 #define ST_KEY2X                        239
172 #define ST_KEY2Y                        191
173
174 // Ammunition counter.
175 #define ST_AMMO0WIDTH           3
176 #define ST_AMMO0HEIGHT          6
177 #define ST_AMMO0X                       288
178 #define ST_AMMO0Y                       173
179 #define ST_AMMO1WIDTH           ST_AMMO0WIDTH
180 #define ST_AMMO1X                       288
181 #define ST_AMMO1Y                       179
182 #define ST_AMMO2WIDTH           ST_AMMO0WIDTH
183 #define ST_AMMO2X                       288
184 #define ST_AMMO2Y                       191
185 #define ST_AMMO3WIDTH           ST_AMMO0WIDTH
186 #define ST_AMMO3X                       288
187 #define ST_AMMO3Y                       185
188
189 // Indicate maximum ammunition.
190 // Only needed because backpack exists.
191 #define ST_MAXAMMO0WIDTH                3
192 #define ST_MAXAMMO0HEIGHT               5
193 #define ST_MAXAMMO0X            314
194 #define ST_MAXAMMO0Y            173
195 #define ST_MAXAMMO1WIDTH                ST_MAXAMMO0WIDTH
196 #define ST_MAXAMMO1X            314
197 #define ST_MAXAMMO1Y            179
198 #define ST_MAXAMMO2WIDTH                ST_MAXAMMO0WIDTH
199 #define ST_MAXAMMO2X            314
200 #define ST_MAXAMMO2Y            191
201 #define ST_MAXAMMO3WIDTH                ST_MAXAMMO0WIDTH
202 #define ST_MAXAMMO3X            314
203 #define ST_MAXAMMO3Y            185
204
205 // pistol
206 #define ST_WEAPON0X                     110 
207 #define ST_WEAPON0Y                     172
208
209 // shotgun
210 #define ST_WEAPON1X                     122 
211 #define ST_WEAPON1Y                     172
212
213 // chain gun
214 #define ST_WEAPON2X                     134 
215 #define ST_WEAPON2Y                     172
216
217 // missile launcher
218 #define ST_WEAPON3X                     110 
219 #define ST_WEAPON3Y                     181
220
221 // plasma gun
222 #define ST_WEAPON4X                     122 
223 #define ST_WEAPON4Y                     181
224
225  // bfg
226 #define ST_WEAPON5X                     134
227 #define ST_WEAPON5Y                     181
228
229 // WPNS title
230 #define ST_WPNSX                        109 
231 #define ST_WPNSY                        191
232
233  // DETH title
234 #define ST_DETHX                        109
235 #define ST_DETHY                        191
236
237 //Incoming messages window location
238 //UNUSED
239 // #define ST_MSGTEXTX     (viewwindowx)
240 // #define ST_MSGTEXTY     (viewwindowy+viewheight-18)
241 #define ST_MSGTEXTX                     0
242 #define ST_MSGTEXTY                     0
243 // Dimensions given in characters.
244 #define ST_MSGWIDTH                     52
245 // Or shall I say, in lines?
246 #define ST_MSGHEIGHT            1
247
248 #define ST_OUTTEXTX                     0
249 #define ST_OUTTEXTY                     6
250
251 // Width, in characters again.
252 #define ST_OUTWIDTH                     52 
253  // Height, in lines. 
254 #define ST_OUTHEIGHT            1
255
256 #define ST_MAPWIDTH     \
257     (strlen(mapnames[(gameepisode-1)*9+(gamemap-1)]))
258
259 #define ST_MAPTITLEX \
260     (SCREENWIDTH - ST_MAPWIDTH * ST_CHATFONTWIDTH)
261
262 #define ST_MAPTITLEY            0
263 #define ST_MAPHEIGHT            1
264
265             
266 // main player in game
267 static player_t*        plyr; 
268
269 // ST_Start() has just been called
270 static boolean          st_firsttime;
271
272 // used to execute ST_Init() only once
273 static int              veryfirsttime = 1;
274
275 // lump number for PLAYPAL
276 static int              lu_palette;
277
278 // used for timing
279 static unsigned int     st_clock;
280
281 // used for making messages go away
282 static int              st_msgcounter=0;
283
284 // used when in chat 
285 static st_chatstateenum_t       st_chatstate;
286
287 // whether in automap or first-person
288 static st_stateenum_t   st_gamestate;
289
290 // whether left-side main status bar is active
291 static boolean          st_statusbaron;
292
293 // whether status bar chat is active
294 static boolean          st_chat;
295
296 // value of st_chat before message popped up
297 static boolean          st_oldchat;
298
299 // whether chat window has the cursor on
300 static boolean          st_cursoron;
301
302 // !deathmatch
303 static boolean          st_notdeathmatch; 
304
305 // !deathmatch && st_statusbaron
306 static boolean          st_armson;
307
308 // !deathmatch
309 static boolean          st_fragson; 
310
311 // main bar left
312 static patch_t*         sbar;
313
314 // 0-9, tall numbers
315 static patch_t*         tallnum[10];
316
317 // tall % sign
318 static patch_t*         tallpercent;
319
320 // 0-9, short, yellow (,different!) numbers
321 static patch_t*         shortnum[10];
322
323 // 3 key-cards, 3 skulls
324 static patch_t*         keys[NUMCARDS]; 
325
326 // face status patches
327 static patch_t*         faces[ST_NUMFACES];
328
329 // face background
330 static patch_t*         faceback;
331
332  // main bar right
333 static patch_t*         armsbg;
334
335 // weapon ownership patches
336 static patch_t*         arms[6][2]; 
337
338 // ready-weapon widget
339 static st_number_t      w_ready;
340
341  // in deathmatch only, summary of frags stats
342 static st_number_t      w_frags;
343
344 // health widget
345 static st_percent_t     w_health;
346
347 // arms background
348 static st_binicon_t     w_armsbg; 
349
350
351 // weapon ownership widgets
352 static st_multicon_t    w_arms[6];
353
354 // face status widget
355 static st_multicon_t    w_faces; 
356
357 // keycard widgets
358 static st_multicon_t    w_keyboxes[3];
359
360 // armor widget
361 static st_percent_t     w_armor;
362
363 // ammo widgets
364 static st_number_t      w_ammo[4];
365
366 // max ammo widgets
367 static st_number_t      w_maxammo[4]; 
368
369
370
371  // number of frags so far in deathmatch
372 static int      st_fragscount;
373
374 // used to use appopriately pained face
375 static int      st_oldhealth = -1;
376
377 // used for evil grin
378 static boolean  oldweaponsowned[NUMWEAPONS]; 
379
380  // count until face changes
381 static int      st_facecount = 0;
382
383 // current face index, used by w_faces
384 static int      st_faceindex = 0;
385
386 // holds key-type for each key box on bar
387 static int      keyboxes[3]; 
388
389 // a random number per tick
390 static int      st_randomnumber;  
391
392
393
394 // Massive bunches of cheat shit
395 //  to keep it from being easy to figure them out.
396 // Yeah, right...
397 unsigned char   cheat_mus_seq[] =
398 {
399     0xb2, 0x26, 0xb6, 0xae, 0xea, 1, 0, 0, 0xff
400 };
401
402 unsigned char   cheat_choppers_seq[] =
403 {
404     0xb2, 0x26, 0xe2, 0x32, 0xf6, 0x2a, 0x2a, 0xa6, 0x6a, 0xea, 0xff // id...
405 };
406
407 unsigned char   cheat_god_seq[] =
408 {
409     0xb2, 0x26, 0x26, 0xaa, 0x26, 0xff  // iddqd
410 };
411
412 unsigned char   cheat_ammo_seq[] =
413 {
414     0xb2, 0x26, 0xf2, 0x66, 0xa2, 0xff  // idkfa
415 };
416
417 unsigned char   cheat_ammonokey_seq[] =
418 {
419     0xb2, 0x26, 0x66, 0xa2, 0xff        // idfa
420 };
421
422
423 // Smashing Pumpkins Into Samml Piles Of Putried Debris. 
424 unsigned char   cheat_noclip_seq[] =
425 {
426     0xb2, 0x26, 0xea, 0x2a, 0xb2,       // idspispopd
427     0xea, 0x2a, 0xf6, 0x2a, 0x26, 0xff
428 };
429
430 //
431 unsigned char   cheat_commercial_noclip_seq[] =
432 {
433     0xb2, 0x26, 0xe2, 0x36, 0xb2, 0x2a, 0xff    // idclip
434 }; 
435
436
437
438 unsigned char   cheat_powerup_seq[7][10] =
439 {
440     { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x6e, 0xff },     // beholdv
441     { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xea, 0xff },     // beholds
442     { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xb2, 0xff },     // beholdi
443     { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x6a, 0xff },     // beholdr
444     { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xa2, 0xff },     // beholda
445     { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0x36, 0xff },     // beholdl
446     { 0xb2, 0x26, 0x62, 0xa6, 0x32, 0xf6, 0x36, 0x26, 0xff }            // behold
447 };
448
449
450 unsigned char   cheat_clev_seq[] =
451 {
452     0xb2, 0x26,  0xe2, 0x36, 0xa6, 0x6e, 1, 0, 0, 0xff  // idclev
453 };
454
455
456 // my position cheat
457 unsigned char   cheat_mypos_seq[] =
458 {
459     0xb2, 0x26, 0xb6, 0xba, 0x2a, 0xf6, 0xea, 0xff      // idmypos
460 }; 
461
462
463 // Now what?
464 cheatseq_t      cheat_mus = { cheat_mus_seq, 0 };
465 cheatseq_t      cheat_god = { cheat_god_seq, 0 };
466 cheatseq_t      cheat_ammo = { cheat_ammo_seq, 0 };
467 cheatseq_t      cheat_ammonokey = { cheat_ammonokey_seq, 0 };
468 cheatseq_t      cheat_noclip = { cheat_noclip_seq, 0 };
469 cheatseq_t      cheat_commercial_noclip = { cheat_commercial_noclip_seq, 0 };
470
471 cheatseq_t      cheat_powerup[7] =
472 {
473     { cheat_powerup_seq[0], 0 },
474     { cheat_powerup_seq[1], 0 },
475     { cheat_powerup_seq[2], 0 },
476     { cheat_powerup_seq[3], 0 },
477     { cheat_powerup_seq[4], 0 },
478     { cheat_powerup_seq[5], 0 },
479     { cheat_powerup_seq[6], 0 }
480 };
481
482 cheatseq_t      cheat_choppers = { cheat_choppers_seq, 0 };
483 cheatseq_t      cheat_clev = { cheat_clev_seq, 0 };
484 cheatseq_t      cheat_mypos = { cheat_mypos_seq, 0 };
485
486
487 // 
488 extern char*    mapnames[];
489
490
491 //
492 // STATUS BAR CODE
493 //
494 void ST_Stop(void);
495
496 void ST_refreshBackground(void)
497 {
498
499     if (st_statusbaron)
500     {
501         V_DrawPatch(ST_X, 0, BG, sbar);
502
503         if (netgame)
504             V_DrawPatch(ST_FX, 0, BG, faceback);
505
506         V_CopyRect(ST_X, 0, BG, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y, FG);
507     }
508
509 }
510
511
512 // Respond to keyboard input events,
513 //  intercept cheats.
514 boolean
515 ST_Responder (event_t* ev)
516 {
517   int           i;
518     
519   // Filter automap on/off.
520   if (ev->type == ev_keyup
521       && ((ev->data1 & 0xffff0000) == AM_MSGHEADER))
522   {
523     switch(ev->data1)
524     {
525       case AM_MSGENTERED:
526         st_gamestate = AutomapState;
527         st_firsttime = true;
528         break;
529         
530       case AM_MSGEXITED:
531         //      fprintf(stderr, "AM exited\n");
532         st_gamestate = FirstPersonState;
533         break;
534     }
535   }
536
537   // if a user keypress...
538   else if (ev->type == ev_keydown)
539   {
540     if (!netgame)
541     {
542       // b. - enabled for more debug fun.
543       // if (gameskill != sk_nightmare) {
544       
545       // 'dqd' cheat for toggleable god mode
546       if (cht_CheckCheat(&cheat_god, ev->data1))
547       {
548         plyr->cheats ^= CF_GODMODE;
549         if (plyr->cheats & CF_GODMODE)
550         {
551           if (plyr->mo)
552             plyr->mo->health = 100;
553           
554           plyr->health = 100;
555           plyr->message = STSTR_DQDON;
556         }
557         else 
558           plyr->message = STSTR_DQDOFF;
559       }
560       // 'fa' cheat for killer fucking arsenal
561       else if (cht_CheckCheat(&cheat_ammonokey, ev->data1))
562       {
563         plyr->armorpoints = 200;
564         plyr->armortype = 2;
565         
566         for (i=0;i<NUMWEAPONS;i++)
567           plyr->weaponowned[i] = true;
568         
569         for (i=0;i<NUMAMMO;i++)
570           plyr->ammo[i] = plyr->maxammo[i];
571         
572         plyr->message = STSTR_FAADDED;
573       }
574       // 'kfa' cheat for key full ammo
575       else if (cht_CheckCheat(&cheat_ammo, ev->data1))
576       {
577         plyr->armorpoints = 200;
578         plyr->armortype = 2;
579         
580         for (i=0;i<NUMWEAPONS;i++)
581           plyr->weaponowned[i] = true;
582         
583         for (i=0;i<NUMAMMO;i++)
584           plyr->ammo[i] = plyr->maxammo[i];
585         
586         for (i=0;i<NUMCARDS;i++)
587           plyr->cards[i] = true;
588         
589         plyr->message = STSTR_KFAADDED;
590       }
591       // 'mus' cheat for changing music
592       else if (cht_CheckCheat(&cheat_mus, ev->data1))
593       {
594         
595         char    buf[3];
596         int             musnum;
597         
598         plyr->message = STSTR_MUS;
599         cht_GetParam(&cheat_mus, buf);
600         
601         if (gamemode == commercial)
602         {
603           musnum = mus_runnin + (buf[0]-'0')*10 + buf[1]-'0' - 1;
604           
605           if (((buf[0]-'0')*10 + buf[1]-'0') > 35)
606             plyr->message = STSTR_NOMUS;
607           else
608             S_ChangeMusic(musnum, 1);
609         }
610         else
611         {
612           musnum = mus_e1m1 + (buf[0]-'1')*9 + (buf[1]-'1');
613           
614           if (((buf[0]-'1')*9 + buf[1]-'1') > 31)
615             plyr->message = STSTR_NOMUS;
616           else
617             S_ChangeMusic(musnum, 1);
618         }
619       }
620       // Simplified, accepting both "noclip" and "idspispopd".
621       // no clipping mode cheat
622       else if ( cht_CheckCheat(&cheat_noclip, ev->data1) 
623                 || cht_CheckCheat(&cheat_commercial_noclip,ev->data1) )
624       { 
625         plyr->cheats ^= CF_NOCLIP;
626         
627         if (plyr->cheats & CF_NOCLIP)
628           plyr->message = STSTR_NCON;
629         else
630           plyr->message = STSTR_NCOFF;
631       }
632       // 'behold?' power-up cheats
633       for (i=0;i<6;i++)
634       {
635         if (cht_CheckCheat(&cheat_powerup[i], ev->data1))
636         {
637           if (!plyr->powers[i])
638             P_GivePower( plyr, i);
639           else if (i!=pw_strength)
640             plyr->powers[i] = 1;
641           else
642             plyr->powers[i] = 0;
643           
644           plyr->message = STSTR_BEHOLDX;
645         }
646       }
647       
648       // 'behold' power-up menu
649       if (cht_CheckCheat(&cheat_powerup[6], ev->data1))
650       {
651         plyr->message = STSTR_BEHOLD;
652       }
653       // 'choppers' invulnerability & chainsaw
654       else if (cht_CheckCheat(&cheat_choppers, ev->data1))
655       {
656         plyr->weaponowned[wp_chainsaw] = true;
657         plyr->powers[pw_invulnerability] = true;
658         plyr->message = STSTR_CHOPPERS;
659       }
660       // 'mypos' for player position
661       else if (cht_CheckCheat(&cheat_mypos, ev->data1))
662       {
663         static char     buf[ST_MSGWIDTH];
664         sprintf(buf, "ang=0x%x;x,y=(0x%x,0x%x)",
665                 players[consoleplayer].mo->angle,
666                 players[consoleplayer].mo->x,
667                 players[consoleplayer].mo->y);
668         plyr->message = buf;
669       }
670     }
671     
672     // 'clev' change-level cheat
673     if (cht_CheckCheat(&cheat_clev, ev->data1))
674     {
675       char              buf[3];
676       int               epsd;
677       int               map;
678       
679       cht_GetParam(&cheat_clev, buf);
680       
681       if (gamemode == commercial)
682       {
683         epsd = 1;
684         map = (buf[0] - '0')*10 + buf[1] - '0';
685       }
686       else
687       {
688         epsd = buf[0] - '0';
689         map = buf[1] - '0';
690       }
691
692       // Catch invalid maps.
693       if (epsd < 1)
694         return false;
695
696       if (map < 1)
697         return false;
698       
699       // Ohmygod - this is not going to work.
700       if ((gamemode == retail)
701           && ((epsd > 4) || (map > 9)))
702         return false;
703
704       if ((gamemode == registered)
705           && ((epsd > 3) || (map > 9)))
706         return false;
707
708       if ((gamemode == shareware)
709           && ((epsd > 1) || (map > 9)))
710         return false;
711
712       if ((gamemode == commercial)
713         && (( epsd > 1) || (map > 34)))
714         return false;
715
716       // So be it.
717       plyr->message = STSTR_CLEV;
718       G_DeferedInitNew(gameskill, epsd, map);
719     }    
720   }
721   return false;
722 }
723
724
725
726 int ST_calcPainOffset(void)
727 {
728     int         health;
729     static int  lastcalc;
730     static int  oldhealth = -1;
731     
732     health = plyr->health > 100 ? 100 : plyr->health;
733
734     if (health != oldhealth)
735     {
736         lastcalc = ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101);
737         oldhealth = health;
738     }
739     return lastcalc;
740 }
741
742
743 //
744 // This is a not-very-pretty routine which handles
745 //  the face states and their timing.
746 // the precedence of expressions is:
747 //  dead > evil grin > turned head > straight ahead
748 //
749 void ST_updateFaceWidget(void)
750 {
751     int         i;
752     angle_t     badguyangle;
753     angle_t     diffang;
754     static int  lastattackdown = -1;
755     static int  priority = 0;
756     boolean     doevilgrin;
757
758     if (priority < 10)
759     {
760         // dead
761         if (!plyr->health)
762         {
763             priority = 9;
764             st_faceindex = ST_DEADFACE;
765             st_facecount = 1;
766         }
767     }
768
769     if (priority < 9)
770     {
771         if (plyr->bonuscount)
772         {
773             // picking up bonus
774             doevilgrin = false;
775
776             for (i=0;i<NUMWEAPONS;i++)
777             {
778                 if (oldweaponsowned[i] != plyr->weaponowned[i])
779                 {
780                     doevilgrin = true;
781                     oldweaponsowned[i] = plyr->weaponowned[i];
782                 }
783             }
784             if (doevilgrin) 
785             {
786                 // evil grin if just picked up weapon
787                 priority = 8;
788                 st_facecount = ST_EVILGRINCOUNT;
789                 st_faceindex = ST_calcPainOffset() + ST_EVILGRINOFFSET;
790             }
791         }
792
793     }
794   
795     if (priority < 8)
796     {
797         if (plyr->damagecount
798             && plyr->attacker
799             && plyr->attacker != plyr->mo)
800         {
801             // being attacked
802             priority = 7;
803             
804             if (st_oldhealth - plyr->health > ST_MUCHPAIN)
805             {
806                 st_facecount = ST_TURNCOUNT;
807                 st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET;
808             }
809             else
810             {
811                 badguyangle = R_PointToAngle2(plyr->mo->x,
812                                               plyr->mo->y,
813                                               plyr->attacker->x,
814                                               plyr->attacker->y);
815                 
816                 if (badguyangle > plyr->mo->angle)
817                 {
818                     // whether right or left
819                     diffang = badguyangle - plyr->mo->angle;
820                     i = diffang > ANG180; 
821                 }
822                 else
823                 {
824                     // whether left or right
825                     diffang = plyr->mo->angle - badguyangle;
826                     i = diffang <= ANG180; 
827                 } // confusing, aint it?
828
829                 
830                 st_facecount = ST_TURNCOUNT;
831                 st_faceindex = ST_calcPainOffset();
832                 
833                 if (diffang < ANG45)
834                 {
835                     // head-on    
836                     st_faceindex += ST_RAMPAGEOFFSET;
837                 }
838                 else if (i)
839                 {
840                     // turn face right
841                     st_faceindex += ST_TURNOFFSET;
842                 }
843                 else
844                 {
845                     // turn face left
846                     st_faceindex += ST_TURNOFFSET+1;
847                 }
848             }
849         }
850     }
851   
852     if (priority < 7)
853     {
854         // getting hurt because of your own damn stupidity
855         if (plyr->damagecount)
856         {
857             if (st_oldhealth - plyr->health > ST_MUCHPAIN)
858             {
859                 priority = 7;
860                 st_facecount = ST_TURNCOUNT;
861                 st_faceindex = ST_calcPainOffset() + ST_OUCHOFFSET;
862             }
863             else
864             {
865                 priority = 6;
866                 st_facecount = ST_TURNCOUNT;
867                 st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET;
868             }
869
870         }
871
872     }
873   
874     if (priority < 6)
875     {
876         // rapid firing
877         if (plyr->attackdown)
878         {
879             if (lastattackdown==-1)
880                 lastattackdown = ST_RAMPAGEDELAY;
881             else if (!--lastattackdown)
882             {
883                 priority = 5;
884                 st_faceindex = ST_calcPainOffset() + ST_RAMPAGEOFFSET;
885                 st_facecount = 1;
886                 lastattackdown = 1;
887             }
888         }
889         else
890             lastattackdown = -1;
891
892     }
893   
894     if (priority < 5)
895     {
896         // invulnerability
897         if ((plyr->cheats & CF_GODMODE)
898             || plyr->powers[pw_invulnerability])
899         {
900             priority = 4;
901
902             st_faceindex = ST_GODFACE;
903             st_facecount = 1;
904
905         }
906
907     }
908
909     // look left or look right if the facecount has timed out
910     if (!st_facecount)
911     {
912         st_faceindex = ST_calcPainOffset() + (st_randomnumber % 3);
913         st_facecount = ST_STRAIGHTFACECOUNT;
914         priority = 0;
915     }
916
917     st_facecount--;
918
919 }
920
921 void ST_updateWidgets(void)
922 {
923     static int  largeammo = 1994; // means "n/a"
924     int         i;
925
926     // must redirect the pointer if the ready weapon has changed.
927     //  if (w_ready.data != plyr->readyweapon)
928     //  {
929     if (weaponinfo[plyr->readyweapon].ammo == am_noammo)
930         w_ready.num = &largeammo;
931     else
932         w_ready.num = &plyr->ammo[weaponinfo[plyr->readyweapon].ammo];
933     //{
934     // static int tic=0;
935     // static int dir=-1;
936     // if (!(tic&15))
937     //   plyr->ammo[weaponinfo[plyr->readyweapon].ammo]+=dir;
938     // if (plyr->ammo[weaponinfo[plyr->readyweapon].ammo] == -100)
939     //   dir = 1;
940     // tic++;
941     // }
942     w_ready.data = plyr->readyweapon;
943
944     // if (*w_ready.on)
945     //  STlib_updateNum(&w_ready, true);
946     // refresh weapon change
947     //  }
948
949     // update keycard multiple widgets
950     for (i=0;i<3;i++)
951     {
952         keyboxes[i] = plyr->cards[i] ? i : -1;
953
954         if (plyr->cards[i+3])
955             keyboxes[i] = i+3;
956     }
957
958     // refresh everything if this is him coming back to life
959     ST_updateFaceWidget();
960
961     // used by the w_armsbg widget
962     st_notdeathmatch = !deathmatch;
963     
964     // used by w_arms[] widgets
965     st_armson = st_statusbaron && !deathmatch; 
966
967     // used by w_frags widget
968     st_fragson = deathmatch && st_statusbaron; 
969     st_fragscount = 0;
970
971     for (i=0 ; i<MAXPLAYERS ; i++)
972     {
973         if (i != consoleplayer)
974             st_fragscount += plyr->frags[i];
975         else
976             st_fragscount -= plyr->frags[i];
977     }
978
979     // get rid of chat window if up because of message
980     if (!--st_msgcounter)
981         st_chat = st_oldchat;
982
983 }
984
985 void ST_Ticker (void)
986 {
987
988     st_clock++;
989     st_randomnumber = M_Random();
990     ST_updateWidgets();
991     st_oldhealth = plyr->health;
992
993 }
994
995 static int st_palette = 0;
996
997 void ST_doPaletteStuff(void)
998 {
999
1000     int         palette;
1001     byte*       pal;
1002     int         cnt;
1003     int         bzc;
1004
1005     cnt = plyr->damagecount;
1006
1007     if (plyr->powers[pw_strength])
1008     {
1009         // slowly fade the berzerk out
1010         bzc = 12 - (plyr->powers[pw_strength]>>6);
1011
1012         if (bzc > cnt)
1013             cnt = bzc;
1014     }
1015         
1016     if (cnt)
1017     {
1018         palette = (cnt+7)>>3;
1019         
1020         if (palette >= NUMREDPALS)
1021             palette = NUMREDPALS-1;
1022
1023         palette += STARTREDPALS;
1024     }
1025
1026     else if (plyr->bonuscount)
1027     {
1028         palette = (plyr->bonuscount+7)>>3;
1029
1030         if (palette >= NUMBONUSPALS)
1031             palette = NUMBONUSPALS-1;
1032
1033         palette += STARTBONUSPALS;
1034     }
1035
1036     else if ( plyr->powers[pw_ironfeet] > 4*32
1037               || plyr->powers[pw_ironfeet]&8)
1038         palette = RADIATIONPAL;
1039     else
1040         palette = 0;
1041
1042     if (palette != st_palette)
1043     {
1044         st_palette = palette;
1045         pal = (byte *) W_CacheLumpNum (lu_palette, PU_CACHE)+palette*768;
1046         I_SetPalette (pal);
1047     }
1048
1049 }
1050
1051 void ST_drawWidgets(boolean refresh)
1052 {
1053     int         i;
1054
1055     // used by w_arms[] widgets
1056     st_armson = st_statusbaron && !deathmatch;
1057
1058     // used by w_frags widget
1059     st_fragson = deathmatch && st_statusbaron; 
1060
1061     STlib_updateNum(&w_ready, refresh);
1062
1063     for (i=0;i<4;i++)
1064     {
1065         STlib_updateNum(&w_ammo[i], refresh);
1066         STlib_updateNum(&w_maxammo[i], refresh);
1067     }
1068
1069     STlib_updatePercent(&w_health, refresh);
1070     STlib_updatePercent(&w_armor, refresh);
1071
1072     STlib_updateBinIcon(&w_armsbg, refresh);
1073
1074     for (i=0;i<6;i++)
1075         STlib_updateMultIcon(&w_arms[i], refresh);
1076
1077     STlib_updateMultIcon(&w_faces, refresh);
1078
1079     for (i=0;i<3;i++)
1080         STlib_updateMultIcon(&w_keyboxes[i], refresh);
1081
1082     STlib_updateNum(&w_frags, refresh);
1083
1084 }
1085
1086 void ST_doRefresh(void)
1087 {
1088
1089     st_firsttime = false;
1090
1091     // draw status bar background to off-screen buff
1092     ST_refreshBackground();
1093
1094     // and refresh all widgets
1095     ST_drawWidgets(true);
1096
1097 }
1098
1099 void ST_diffDraw(void)
1100 {
1101     // update all widgets
1102     ST_drawWidgets(false);
1103 }
1104
1105 void ST_Drawer (boolean fullscreen, boolean refresh)
1106 {
1107   
1108     st_statusbaron = (!fullscreen) || automapactive;
1109     st_firsttime = st_firsttime || refresh;
1110
1111     // Do red-/gold-shifts from damage/items
1112     ST_doPaletteStuff();
1113
1114     // If just after ST_Start(), refresh all
1115     if (st_firsttime) ST_doRefresh();
1116     // Otherwise, update as little as possible
1117     else ST_diffDraw();
1118
1119 }
1120
1121 void ST_loadGraphics(void)
1122 {
1123
1124     int         i;
1125     int         j;
1126     int         facenum;
1127     
1128     char        namebuf[9];
1129
1130     // Load the numbers, tall and short
1131     for (i=0;i<10;i++)
1132     {
1133         sprintf(namebuf, "STTNUM%d", i);
1134         tallnum[i] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC);
1135
1136         sprintf(namebuf, "STYSNUM%d", i);
1137         shortnum[i] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC);
1138     }
1139
1140     // Load percent key.
1141     //Note: why not load STMINUS here, too?
1142     tallpercent = (patch_t *) W_CacheLumpName("STTPRCNT", PU_STATIC);
1143
1144     // key cards
1145     for (i=0;i<NUMCARDS;i++)
1146     {
1147         sprintf(namebuf, "STKEYS%d", i);
1148         keys[i] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC);
1149     }
1150
1151     // arms background
1152     armsbg = (patch_t *) W_CacheLumpName("STARMS", PU_STATIC);
1153
1154     // arms ownership widgets
1155     for (i=0;i<6;i++)
1156     {
1157         sprintf(namebuf, "STGNUM%d", i+2);
1158
1159         // gray #
1160         arms[i][0] = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC);
1161
1162         // yellow #
1163         arms[i][1] = shortnum[i+2]; 
1164     }
1165
1166     // face backgrounds for different color players
1167     sprintf(namebuf, "STFB%d", consoleplayer);
1168     faceback = (patch_t *) W_CacheLumpName(namebuf, PU_STATIC);
1169
1170     // status bar background bits
1171     sbar = (patch_t *) W_CacheLumpName("STBAR", PU_STATIC);
1172
1173     // face states
1174     facenum = 0;
1175     for (i=0;i<ST_NUMPAINFACES;i++)
1176     {
1177         for (j=0;j<ST_NUMSTRAIGHTFACES;j++)
1178         {
1179             sprintf(namebuf, "STFST%d%d", i, j);
1180             faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
1181         }
1182         sprintf(namebuf, "STFTR%d0", i);        // turn right
1183         faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
1184         sprintf(namebuf, "STFTL%d0", i);        // turn left
1185         faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
1186         sprintf(namebuf, "STFOUCH%d", i);       // ouch!
1187         faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
1188         sprintf(namebuf, "STFEVL%d", i);        // evil grin ;)
1189         faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
1190         sprintf(namebuf, "STFKILL%d", i);       // pissed off
1191         faces[facenum++] = W_CacheLumpName(namebuf, PU_STATIC);
1192     }
1193     faces[facenum++] = W_CacheLumpName("STFGOD0", PU_STATIC);
1194     faces[facenum  ] = W_CacheLumpName("STFDEAD0", PU_STATIC);
1195
1196 }
1197
1198 void ST_loadData(void)
1199 {
1200     lu_palette = W_GetNumForName ("PLAYPAL");
1201     ST_loadGraphics();
1202 }
1203
1204 void ST_unloadGraphics(void)
1205 {
1206
1207     int i;
1208
1209     // unload the numbers, tall and short
1210     for (i=0;i<10;i++)
1211     {
1212         Z_ChangeTag(tallnum[i], PU_CACHE);
1213         Z_ChangeTag(shortnum[i], PU_CACHE);
1214     }
1215     // unload tall percent
1216     Z_ChangeTag(tallpercent, PU_CACHE); 
1217
1218     // unload arms background
1219     Z_ChangeTag(armsbg, PU_CACHE); 
1220
1221     // unload gray #'s
1222     for (i=0;i<6;i++)
1223         Z_ChangeTag(arms[i][0], PU_CACHE);
1224     
1225     // unload the key cards
1226     for (i=0;i<NUMCARDS;i++)
1227         Z_ChangeTag(keys[i], PU_CACHE);
1228
1229     Z_ChangeTag(sbar, PU_CACHE);
1230     Z_ChangeTag(faceback, PU_CACHE);
1231
1232     for (i=0;i<ST_NUMFACES;i++)
1233         Z_ChangeTag(faces[i], PU_CACHE);
1234
1235     // Note: nobody ain't seen no unloading
1236     //   of stminus yet. Dude.
1237     
1238
1239 }
1240
1241 void ST_unloadData(void)
1242 {
1243     ST_unloadGraphics();
1244 }
1245
1246 void ST_initData(void)
1247 {
1248
1249     int         i;
1250
1251     st_firsttime = true;
1252     plyr = &players[consoleplayer];
1253
1254     st_clock = 0;
1255     st_chatstate = StartChatState;
1256     st_gamestate = FirstPersonState;
1257
1258     st_statusbaron = true;
1259     st_oldchat = st_chat = false;
1260     st_cursoron = false;
1261
1262     st_faceindex = 0;
1263     st_palette = -1;
1264
1265     st_oldhealth = -1;
1266
1267     for (i=0;i<NUMWEAPONS;i++)
1268         oldweaponsowned[i] = plyr->weaponowned[i];
1269
1270     for (i=0;i<3;i++)
1271         keyboxes[i] = -1;
1272
1273     STlib_init();
1274
1275 }
1276
1277
1278
1279 void ST_createWidgets(void)
1280 {
1281
1282     int i;
1283
1284     // ready weapon ammo
1285     STlib_initNum(&w_ready,
1286                   ST_AMMOX,
1287                   ST_AMMOY,
1288                   tallnum,
1289                   &plyr->ammo[weaponinfo[plyr->readyweapon].ammo],
1290                   &st_statusbaron,
1291                   ST_AMMOWIDTH );
1292
1293     // the last weapon type
1294     w_ready.data = plyr->readyweapon; 
1295
1296     // health percentage
1297     STlib_initPercent(&w_health,
1298                       ST_HEALTHX,
1299                       ST_HEALTHY,
1300                       tallnum,
1301                       &plyr->health,
1302                       &st_statusbaron,
1303                       tallpercent);
1304
1305     // arms background
1306     STlib_initBinIcon(&w_armsbg,
1307                       ST_ARMSBGX,
1308                       ST_ARMSBGY,
1309                       armsbg,
1310                       &st_notdeathmatch,
1311                       &st_statusbaron);
1312
1313     // weapons owned
1314     for(i=0;i<6;i++)
1315     {
1316         STlib_initMultIcon(&w_arms[i],
1317                            ST_ARMSX+(i%3)*ST_ARMSXSPACE,
1318                            ST_ARMSY+(i/3)*ST_ARMSYSPACE,
1319                            arms[i], (int *) &plyr->weaponowned[i+1],
1320                            &st_armson);
1321     }
1322
1323     // frags sum
1324     STlib_initNum(&w_frags,
1325                   ST_FRAGSX,
1326                   ST_FRAGSY,
1327                   tallnum,
1328                   &st_fragscount,
1329                   &st_fragson,
1330                   ST_FRAGSWIDTH);
1331
1332     // faces
1333     STlib_initMultIcon(&w_faces,
1334                        ST_FACESX,
1335                        ST_FACESY,
1336                        faces,
1337                        &st_faceindex,
1338                        &st_statusbaron);
1339
1340     // armor percentage - should be colored later
1341     STlib_initPercent(&w_armor,
1342                       ST_ARMORX,
1343                       ST_ARMORY,
1344                       tallnum,
1345                       &plyr->armorpoints,
1346                       &st_statusbaron, tallpercent);
1347
1348     // keyboxes 0-2
1349     STlib_initMultIcon(&w_keyboxes[0],
1350                        ST_KEY0X,
1351                        ST_KEY0Y,
1352                        keys,
1353                        &keyboxes[0],
1354                        &st_statusbaron);
1355     
1356     STlib_initMultIcon(&w_keyboxes[1],
1357                        ST_KEY1X,
1358                        ST_KEY1Y,
1359                        keys,
1360                        &keyboxes[1],
1361                        &st_statusbaron);
1362
1363     STlib_initMultIcon(&w_keyboxes[2],
1364                        ST_KEY2X,
1365                        ST_KEY2Y,
1366                        keys,
1367                        &keyboxes[2],
1368                        &st_statusbaron);
1369
1370     // ammo count (all four kinds)
1371     STlib_initNum(&w_ammo[0],
1372                   ST_AMMO0X,
1373                   ST_AMMO0Y,
1374                   shortnum,
1375                   &plyr->ammo[0],
1376                   &st_statusbaron,
1377                   ST_AMMO0WIDTH);
1378
1379     STlib_initNum(&w_ammo[1],
1380                   ST_AMMO1X,
1381                   ST_AMMO1Y,
1382                   shortnum,
1383                   &plyr->ammo[1],
1384                   &st_statusbaron,
1385                   ST_AMMO1WIDTH);
1386
1387     STlib_initNum(&w_ammo[2],
1388                   ST_AMMO2X,
1389                   ST_AMMO2Y,
1390                   shortnum,
1391                   &plyr->ammo[2],
1392                   &st_statusbaron,
1393                   ST_AMMO2WIDTH);
1394     
1395     STlib_initNum(&w_ammo[3],
1396                   ST_AMMO3X,
1397                   ST_AMMO3Y,
1398                   shortnum,
1399                   &plyr->ammo[3],
1400                   &st_statusbaron,
1401                   ST_AMMO3WIDTH);
1402
1403     // max ammo count (all four kinds)
1404     STlib_initNum(&w_maxammo[0],
1405                   ST_MAXAMMO0X,
1406                   ST_MAXAMMO0Y,
1407                   shortnum,
1408                   &plyr->maxammo[0],
1409                   &st_statusbaron,
1410                   ST_MAXAMMO0WIDTH);
1411
1412     STlib_initNum(&w_maxammo[1],
1413                   ST_MAXAMMO1X,
1414                   ST_MAXAMMO1Y,
1415                   shortnum,
1416                   &plyr->maxammo[1],
1417                   &st_statusbaron,
1418                   ST_MAXAMMO1WIDTH);
1419
1420     STlib_initNum(&w_maxammo[2],
1421                   ST_MAXAMMO2X,
1422                   ST_MAXAMMO2Y,
1423                   shortnum,
1424                   &plyr->maxammo[2],
1425                   &st_statusbaron,
1426                   ST_MAXAMMO2WIDTH);
1427     
1428     STlib_initNum(&w_maxammo[3],
1429                   ST_MAXAMMO3X,
1430                   ST_MAXAMMO3Y,
1431                   shortnum,
1432                   &plyr->maxammo[3],
1433                   &st_statusbaron,
1434                   ST_MAXAMMO3WIDTH);
1435
1436 }
1437
1438 static boolean  st_stopped = true;
1439
1440
1441 void ST_Start (void)
1442 {
1443
1444     if (!st_stopped)
1445         ST_Stop();
1446
1447     ST_initData();
1448     ST_createWidgets();
1449     st_stopped = false;
1450
1451 }
1452
1453 void ST_Stop (void)
1454 {
1455     if (st_stopped)
1456         return;
1457
1458     I_SetPalette (W_CacheLumpNum (lu_palette, PU_CACHE));
1459
1460     st_stopped = true;
1461 }
1462
1463 void ST_Init (void)
1464 {
1465     veryfirsttime = 0;
1466     ST_loadData();
1467     screens[4] = (byte *) Z_Malloc(ST_WIDTH*ST_HEIGHT, PU_STATIC, 0);
1468 }