1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1997, 2005 - 3D Realms Entertainment
4 
5 This file is part of Shadow Warrior version 1.2
6 
7 Shadow Warrior is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 
22 Original Source: 1997 - Frank Maddin and Jim Norwood
23 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24 */
25 //-------------------------------------------------------------------------
26 
27 #undef MAIN
28 #include "build.h"
29 
30 #include "keys.h"
31 #include "names2.h"
32 #include "panel.h"
33 #include "game.h"
34 #include "pal.h"
35 #include "text.h"
36 #include "colormap.h"
37 #include "player.h"
38 
39 //#define SAVE_EXTERN
40 //#include "_save.h"
41 //#undef SAVE_EXTERN
42 
43 extern short NormalVisibility;
44 
45 // indexed by gs.BorderNum   130,172
46 short InventoryBarXpos[] = {110, 110, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80};
47 short InventoryBarYpos[] = {172, 172, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130};
48 
49 VOID PlayerUpdateInventory(PLAYERp pp, short InventoryNum);
50 void SpawnInventoryBar(PLAYERp pp);
51 VOID InventoryBarUpdatePosition(PLAYERp pp);
52 VOID InvBorderRefresh(PLAYERp pp);
53 VOID InventoryUse(PLAYERp pp);
54 VOID InventoryStop(PLAYERp pp, short InventoryNum);
55 VOID KillInventoryBar(PLAYERp pp);
56 VOID PlayerUpdateInventoryPercent(PLAYERp pp);
57 VOID PlayerUpdateInventoryPic(PLAYERp pp);
58 VOID PlayerUpdateInventoryState(PLAYERp pp);
59 
60 
61 //#define INVENTORY_ICON_WIDTH  32
62 #define INVENTORY_ICON_WIDTH  28
63 
64 VOID UseInventoryRepairKit(PLAYERp pp);
65 VOID UseInventoryMedkit(PLAYERp pp);
66 VOID UseInventoryRepairKit(PLAYERp pp);
67 VOID UseInventoryCloak(PLAYERp pp);
68 VOID UseInventoryEnvironSuit(PLAYERp pp);
69 VOID UseInventoryNightVision(PLAYERp pp);
70 VOID UseInventoryChemBomb(PLAYERp pp);
71 VOID UseInventoryFlashBomb(PLAYERp pp);
72 VOID UseInventoryCaltrops(PLAYERp pp);
73 
74 VOID StopInventoryRepairKit(PLAYERp pp, short);
75 VOID StopInventoryMedkit(PLAYERp pp, short);
76 VOID StopInventoryRepairKit(PLAYERp pp, short);
77 VOID StopInventoryCloak(PLAYERp pp, short);
78 VOID StopInventoryEnvironSuit(PLAYERp pp, short);
79 VOID StopInventoryNightVision(PLAYERp pp, short);
80 
81 extern PANEL_STATE ps_PanelEnvironSuit[];
82 extern PANEL_STATE ps_PanelCloak[];
83 extern PANEL_STATE ps_PanelMedkit[];
84 extern PANEL_STATE ps_PanelRepairKit[];
85 extern PANEL_STATE ps_PanelSelectionBox[];
86 extern PANEL_STATE ps_PanelNightVision[];
87 extern PANEL_STATE ps_PanelChemBomb[];
88 extern PANEL_STATE ps_PanelFlashBomb[];
89 extern PANEL_STATE ps_PanelCaltrops[];
90 
91 
92 INVENTORY_DATA InventoryData[MAX_INVENTORY+1] =
93     {
94     {"PORTABLE MEDKIT",  UseInventoryMedkit,      NULL,                 ps_PanelMedkit,        0,   1, (1<<16),     0},
95     {"REPAIR KIT",       NULL,                    NULL,                 ps_PanelRepairKit,     100, 1, (1<<16),     INVF_AUTO_USE},
96     {"SMOKE BOMB",       UseInventoryCloak,       StopInventoryCloak,   ps_PanelCloak,         4,   1, (1<<16),     INVF_TIMED},
97     {"NIGHT VISION",     UseInventoryNightVision, StopInventoryNightVision, ps_PanelNightVision,3,  1, (1<<16),     INVF_TIMED},
98     {"GAS BOMB",         UseInventoryChemBomb,    NULL,                 ps_PanelChemBomb,      0,   1, (1<<16),     INVF_COUNT},
99     {"FLASH BOMB",       UseInventoryFlashBomb,   NULL,                 ps_PanelFlashBomb,     0,   2, (1<<16),     INVF_COUNT},
100     {"CALTROPS",         UseInventoryCaltrops,    NULL,                 ps_PanelCaltrops,      0,   3, (1<<16),     INVF_COUNT},
101     {NULL, NULL, NULL, NULL, 0, 0, 0, 0}
102     };
103 
104 VOID PanelInvTestSuicide(PANEL_SPRITEp psp);
105 
UpdateMiniBar(PLAYERp pp)106 VOID UpdateMiniBar(PLAYERp pp)
107     {
108     USERp u = User[pp->PlayerSprite];
109     short i;
110     int x,y;
111     BOOL found;
112     INVENTORY_DATAp id;
113     extern BOOL PanelUpdateMode;
114 
115     #define MINI_BAR_Y 174
116 
117     #define MINI_BAR_HEALTH_BOX_PIC 2437
118     #define MINI_BAR_AMMO_BOX_PIC 2437
119     #define MINI_BAR_INVENTORY_BOX_PIC 2438
120 
121     #define MINI_BAR_HEALTH_BOX_X 4
122     #define MINI_BAR_AMMO_BOX_X 32
123     #define MINI_BAR_INVENTORY_BOX_X 64
124     #define MINI_BAR_INVENTORY_BOX_Y MINI_BAR_Y
125 
126     if (!PanelUpdateMode)
127         return;
128 
129     if (gs.BorderNum != BORDER_MINI_BAR)
130         return;
131 
132     x = MINI_BAR_HEALTH_BOX_X;
133     y = 200 - 26;
134 
135     rotatesprite(x << 16, y << 16, (1 << 16), 0,
136         MINI_BAR_HEALTH_BOX_PIC, 0, 0,
137         ROTATE_SPRITE_SCREEN_CLIP | ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
138 
139     x = MINI_BAR_HEALTH_BOX_X+3;
140     DisplayMiniBarNumber(pp, x, y+5, u->Health);
141 
142     if (u->WeaponNum != WPN_SWORD && u->WeaponNum != WPN_FIST)
143         {
144         x = MINI_BAR_AMMO_BOX_X;
145 
146         rotatesprite(x << 16, y << 16, (1 << 16), 0,
147             MINI_BAR_AMMO_BOX_PIC, 0, 0,
148             ROTATE_SPRITE_SCREEN_CLIP | ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
149 
150         x = MINI_BAR_AMMO_BOX_X+3;
151         DisplayMiniBarNumber(pp, x, y+5, pp->WpnAmmo[u->WeaponNum]);
152         }
153 
154     if (!pp->InventoryAmount[pp->InventoryNum])
155         return;
156 
157     // Inventory Box
158     x = MINI_BAR_INVENTORY_BOX_X;
159 
160     rotatesprite(x << 16, y << 16, (1 << 16), 0,
161         MINI_BAR_INVENTORY_BOX_PIC, 0, 0,
162         ROTATE_SPRITE_SCREEN_CLIP | ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
163 
164     id = &InventoryData[pp->InventoryNum];
165 
166     // Inventory pic
167     x = MINI_BAR_INVENTORY_BOX_X + 2;
168     y += 2;
169 
170     rotatesprite(x << 16, y << 16, (1 << 16), 0,
171         id->State->picndx, 0, 0,
172         ROTATE_SPRITE_SCREEN_CLIP | ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
173 
174     // will update the AUTO and % inventory values
175     PlayerUpdateInventory(pp, pp->InventoryNum);
176     }
177 
178 
179 VOID
PanelInvTestSuicide(PANEL_SPRITEp psp)180 PanelInvTestSuicide(PANEL_SPRITEp psp)
181     {
182     if (TEST(psp->flags, PANF_SUICIDE))
183         {
184         pKillSprite(psp);
185         }
186     }
187 
188 PANEL_SPRITEp
SpawnInventoryIcon(PLAYERp pp,short InventoryNum)189 SpawnInventoryIcon(PLAYERp pp, short InventoryNum)
190     {
191     PANEL_SPRITEp psp;
192     short x,y;
193 
194     // check invalid value
195     ASSERT(InventoryNum < MAX_INVENTORY);
196 
197     // check to see if its already spawned
198     if (pp->InventorySprite[InventoryNum])
199         return(NULL);
200 
201     // check for Icon panel state
202     if (!InventoryData[InventoryNum].State)
203         return(NULL);
204 
205     x = InventoryBarXpos[gs.BorderNum] + (InventoryNum*INVENTORY_ICON_WIDTH);
206     y = InventoryBarYpos[gs.BorderNum];
207     psp = pSpawnSprite(pp, InventoryData[InventoryNum].State, PRI_FRONT, x, y);
208     pp->InventorySprite[InventoryNum] = psp;
209 
210     psp->x1 = 0;
211     psp->y1 = 0;
212     psp->x2 = xdim - 1;
213     psp->y2 = ydim - 1;
214     psp->scale = InventoryData[InventoryNum].Scale;
215     SET(psp->flags, PANF_STATUS_AREA | PANF_SCREEN_CLIP);
216 
217     return(psp);
218     }
219 
220 VOID
KillPanelInv(PLAYERp pp,short InventoryNum)221 KillPanelInv(PLAYERp pp, short InventoryNum)
222     {
223     ASSERT(pp->InventorySprite[InventoryNum]);
224     ASSERT(InventoryNum < MAX_INVENTORY);
225 
226     pp->InventoryTics[InventoryNum] = 0;
227     SET(pp->InventorySprite[InventoryNum]->flags, PANF_SUICIDE);
228     pp->InventorySprite[InventoryNum] = NULL;
229     }
230 
231 VOID
KillPlayerIcon(PLAYERp UNUSED (pp),PANEL_SPRITEp * pspp)232 KillPlayerIcon(PLAYERp UNUSED(pp), PANEL_SPRITEp *pspp)
233     {
234     SET((*pspp)->flags, PANF_SUICIDE);
235     (*pspp) = NULL;
236     }
237 
238 VOID
KillAllPanelInv(PLAYERp pp)239 KillAllPanelInv(PLAYERp pp)
240     {
241     short i;
242 
243     for (i = 0; i < MAX_INVENTORY; i++)
244         {
245         if (!pp->InventorySprite[i])
246             continue;
247 
248         pp->InventoryTics[i] = 0;
249         SET(pp->InventorySprite[i]->flags, PANF_SUICIDE);
250         pp->InventorySprite[i]->numpages = 0;
251         pp->InventorySprite[i] = NULL;
252         }
253     }
254 
255 PANEL_SPRITEp
SpawnIcon(PLAYERp pp,PANEL_STATEp state)256 SpawnIcon(PLAYERp pp, PANEL_STATEp state)
257     {
258     PANEL_SPRITEp psp;
259     short i;
260 
261     psp = pSpawnSprite(pp, state, PRI_FRONT, 0, 0);
262 
263     psp->x1 = 0;
264     psp->y1 = 0;
265     psp->x2 = xdim - 1;
266     psp->y2 = ydim - 1;
267     SET(psp->flags, PANF_STATUS_AREA | PANF_SCREEN_CLIP);
268     return(psp);
269     }
270 
271 //////////////////////////////////////////////////////////////////////
272 //
273 // MEDKIT
274 //
275 //////////////////////////////////////////////////////////////////////
276 
AutoPickInventory(PLAYERp pp)277 VOID AutoPickInventory(PLAYERp pp)
278     {
279     int i;
280 
281     // auto pick only if run out of currently selected one
282 
283     if (pp->InventoryAmount[pp->InventoryNum] <= 0)
284         {
285         for (i = 0; i < MAX_INVENTORY; i++)
286             {
287             if (i == INVENTORY_REPAIR_KIT)
288                 continue;
289 
290             if (pp->InventoryAmount[i])
291                 {
292                 pp->InventoryNum = i;
293                 return;
294                 }
295             }
296 
297         // only take this if there is nothing else
298         if (pp->InventoryAmount[INVENTORY_REPAIR_KIT])
299             pp->InventoryNum = INVENTORY_REPAIR_KIT;
300         }
301     }
302 
303 VOID
UseInventoryMedkit(PLAYERp pp)304 UseInventoryMedkit(PLAYERp pp)
305     {
306     USERp u = User[pp->PlayerSprite];
307     short diff;
308     short inv = INVENTORY_MEDKIT;
309     short amt;
310 
311 
312     if (!pp->InventoryAmount[inv])
313         return;
314 
315     diff = 100 - u->Health;
316     if (diff <= 0)
317         return;
318 
319     if(diff > pp->InventoryPercent[inv]) // If not enough to get to 100, use what's left
320         amt = pp->InventoryPercent[inv];
321     else
322         amt = diff;
323 
324     PlayerUpdateHealth(pp, amt);
325 
326     pp->InventoryPercent[inv] -= diff;
327     if (pp->InventoryPercent[inv] < 0)
328         {
329         pp->InventoryPercent[inv] = 0;
330         pp->InventoryAmount[inv]--;
331         }
332 
333     AutoPickInventory(pp);
334 
335     //percent
336     PlayerUpdateInventory(pp, pp->InventoryNum);
337 
338     if(pp == Player+myconnectindex)
339         {
340         if (amt >= 30)
341             PlayerSound(DIGI_GETMEDKIT,&pp->posx,&pp->posy,&pp->posz,v3df_follow|v3df_dontpan,pp);
342         else
343             PlayerSound(DIGI_AHH,&pp->posx,&pp->posy,&pp->posz,v3df_follow|v3df_dontpan,pp);
344         }
345     }
346 
347 //////////////////////////////////////////////////////////////////////
348 //
349 // CHEMICAL WARFARE CANISTERS
350 //
351 //////////////////////////////////////////////////////////////////////
352 VOID
UseInventoryChemBomb(PLAYERp pp)353 UseInventoryChemBomb(PLAYERp pp)
354     {
355     USERp u = User[pp->PlayerSprite];
356     short diff;
357     short inv = INVENTORY_CHEMBOMB;
358 
359     if (!pp->InventoryAmount[inv])
360         return;
361 
362     PlayerInitChemBomb(pp); // Throw a chemical bomb out there
363 
364     pp->InventoryPercent[inv] = 0;
365     if (--pp->InventoryAmount[inv] < 0)
366         pp->InventoryAmount[inv] = 0;
367 
368     AutoPickInventory(pp);
369 
370     PlayerUpdateInventory(pp, pp->InventoryNum);
371     }
372 
373 //////////////////////////////////////////////////////////////////////
374 //
375 // FLASH BOMBS
376 //
377 //////////////////////////////////////////////////////////////////////
378 VOID
UseInventoryFlashBomb(PLAYERp pp)379 UseInventoryFlashBomb(PLAYERp pp)
380     {
381     USERp u = User[pp->PlayerSprite];
382     short diff;
383     short inv = INVENTORY_FLASHBOMB;
384 
385     if (!pp->InventoryAmount[inv])
386         return;
387 
388     PlayerInitFlashBomb(pp);
389 
390     pp->InventoryPercent[inv] = 0;
391     if (--pp->InventoryAmount[inv] < 0)
392         pp->InventoryAmount[inv] = 0;
393 
394     AutoPickInventory(pp);
395 
396     PlayerUpdateInventory(pp, pp->InventoryNum);
397     }
398 
399 //////////////////////////////////////////////////////////////////////
400 //
401 // CALTROPS
402 //
403 //////////////////////////////////////////////////////////////////////
404 VOID
UseInventoryCaltrops(PLAYERp pp)405 UseInventoryCaltrops(PLAYERp pp)
406     {
407     USERp u = User[pp->PlayerSprite];
408     short diff;
409     short inv = INVENTORY_CALTROPS;
410 
411     if (!pp->InventoryAmount[inv])
412         return;
413 
414     PlayerInitCaltrops(pp);
415 
416     pp->InventoryPercent[inv] = 0;
417     if (--pp->InventoryAmount[inv] < 0)
418         pp->InventoryAmount[inv] = 0;
419 
420     AutoPickInventory(pp);
421 
422     PlayerUpdateInventory(pp, pp->InventoryNum);
423     }
424 
425 //////////////////////////////////////////////////////////////////////
426 //
427 // REPAIR KIT
428 //
429 //////////////////////////////////////////////////////////////////////
430 
431 VOID
UseInventoryRepairKit(PLAYERp pp)432 UseInventoryRepairKit(PLAYERp pp)
433     {
434     SPRITEp sp = pp->SpriteP;
435     short inv = INVENTORY_REPAIR_KIT;
436 
437     //PlaySound(DIGI_TOOLBOX, &pp->posx, &pp->posy, &pp->posz, v3df_none);
438     if(pp == Player + myconnectindex)
439         {
440         if(STD_RANDOM_RANGE(1000) > 500)
441             PlayerSound(DIGI_NOREPAIRMAN,&pp->posx,&pp->posy,&pp->posz,v3df_follow|v3df_dontpan,pp);
442         else
443             PlayerSound(DIGI_NOREPAIRMAN2,&pp->posx,&pp->posy,&pp->posz,v3df_follow|v3df_dontpan,pp);
444         }
445 
446     pp->InventoryPercent[inv] = 0;
447     pp->InventoryAmount[inv] = 0;
448 
449     AutoPickInventory(pp);
450 
451     //percent
452     PlayerUpdateInventory(pp, pp->InventoryNum);
453     }
454 
455 //////////////////////////////////////////////////////////////////////
456 //
457 // CLOAK
458 //
459 //////////////////////////////////////////////////////////////////////
460 
461 VOID
UseInventoryCloak(PLAYERp pp)462 UseInventoryCloak(PLAYERp pp)
463     {
464     SPRITEp sp = pp->SpriteP;
465 
466     if (pp->InventoryActive[pp->InventoryNum])
467         {
468 //        StopInventoryCloak(pp, pp->InventoryNum);
469         return;
470         }
471 
472     pp->InventoryActive[pp->InventoryNum] = TRUE;
473 
474     AutoPickInventory(pp);
475 
476     // on/off
477     PlayerUpdateInventory(pp, pp->InventoryNum);
478 
479     SET(sp->cstat, CSTAT_SPRITE_TRANSLUCENT);
480     sp->shade = 100;
481 
482     PlaySound(DIGI_GASPOP, &pp->posx, &pp->posy, &pp->posz, v3df_none);
483     //if(RANDOM_RANGE(1000) > 950)
484     if(pp == Player+myconnectindex)
485         PlayerSound(DIGI_IAMSHADOW,&pp->posx,&pp->posy,&pp->posz,v3df_follow|v3df_dontpan,pp);
486     }
487 
488 VOID
StopInventoryCloak(PLAYERp pp,short InventoryNum)489 StopInventoryCloak(PLAYERp pp, short InventoryNum)
490     {
491     SPRITEp sp = pp->SpriteP;
492 
493     pp->InventoryActive[InventoryNum] = FALSE;
494 
495     if (pp->InventoryPercent[InventoryNum] <= 0)
496         {
497         pp->InventoryPercent[InventoryNum] = 0;
498         if (--pp->InventoryAmount[InventoryNum] < 0)
499             pp->InventoryAmount[InventoryNum] = 0;
500         }
501 
502     // on/off
503     PlayerUpdateInventory(pp, InventoryNum);
504 
505     RESET(sp->cstat, CSTAT_SPRITE_TRANSLUCENT);
506     sp->shade = 0;
507 
508     PlaySound(DIGI_GASPOP, &pp->posx, &pp->posy, &pp->posz, v3df_none);
509     }
510 
511 //////////////////////////////////////////////////////////////////////
512 //
513 // ENVIRONMENT SUIT
514 //
515 //////////////////////////////////////////////////////////////////////
516 #if 0
517 VOID
518 UseInventoryEnvironSuit(PLAYERp pp)
519     {
520     SPRITEp sp = pp->SpriteP;
521     short inv = INVENTORY_ENVIRON_SUIT;
522 
523     // only activate if you have one
524     if (pp->InventoryAmount[inv])
525         {
526         pp->InventoryActive[inv] = TRUE;
527         // on/off
528         PlayerUpdateInventory(pp, inv);
529         }
530     }
531 
532 VOID
533 StopInventoryEnvironSuit(PLAYERp pp, short InventoryNum)
534     {
535     SPRITEp sp = pp->SpriteP;
536     short inv = INVENTORY_ENVIRON_SUIT;
537 
538     pp->InventoryActive[InventoryNum] = FALSE;
539 
540     if (pp->InventoryPercent[InventoryNum] <= 0)
541         {
542         pp->InventoryPercent[InventoryNum] = 0;
543         if (--pp->InventoryAmount[InventoryNum] < 0)
544             pp->InventoryAmount[InventoryNum] = 0;
545         }
546 
547     // on/off
548     PlayerUpdateInventory(pp, InventoryNum);
549 
550     PlaySound(DIGI_SWCLOAKUNCLOAK, &pp->posx, &pp->posy, &pp->posz, v3df_none);
551     }
552 #endif
553 
554 //////////////////////////////////////////////////////////////////////
555 //
556 // NIGHT VISION
557 //
558 //////////////////////////////////////////////////////////////////////
559 
560 static char sectorfloorpals[MAXSECTORS], sectorceilingpals[MAXSECTORS], wallpals[MAXWALLS];
561 
562 #if 0
563 VOID
564 DoPlayerNightVisionPalette(PLAYERp pp)
565     {
566     extern char DefaultPalette[];
567     short i;
568 
569     if (pp->InventoryActive[INVENTORY_NIGHT_VISION] && (pp - Player == screenpeek))
570         {
571         if (NightVision)
572             return;                     // Already using night vision, don't
573                                         // bother.
574         visibility = 0;
575         for (i = 0; i < numsectors; i++)
576             {
577             sectorfloorpals[i] = sector[i].floorpal;
578             sectorceilingpals[i] = sector[i].ceilingpal;
579             sector[i].floorpal = PALETTE_GREEN_LIGHTING;
580             sector[i].ceilingpal = PALETTE_GREEN_LIGHTING;
581             }
582         for (i = 0; i < numwalls; i++)
583             {
584             wallpals[i] = wall[i].pal;
585             wall[i].pal = PALETTE_GREEN_LIGHTING;
586             }
587 
588 
589         NightVision = TRUE;
590         COVERsetbrightness(4, (char *) &palette_data[0][0]);
591         }
592     else
593         {
594         visibility = NormalVisibility;
595         for (i = 0; i < numsectors; i++)
596             {
597             sector[i].floorpal = sectorfloorpals[i];
598             sector[i].ceilingpal = sectorceilingpals[i];
599             }
600         for (i = 0; i < numwalls; i++)
601             {
602             wall[i].pal = wallpals[i];
603             }
604         DoPlayerDivePalette(pp);  // Check again to see if its a water palette
605         NightVision = FALSE;
606         COVERsetbrightness(gs.Brightness, (char *) &palette_data[0][0]);
607         }
608     }
609 #endif
610 
611 VOID
DoPlayerNightVisionPalette(PLAYERp pp)612 DoPlayerNightVisionPalette(PLAYERp pp)
613     {
614     extern char DefaultPalette[];
615 
616     if (pp != Player + screenpeek) return;
617 
618     if (pp->InventoryActive[INVENTORY_NIGHT_VISION])
619         {
620 //        if (pp->NightVision && pp->StartColor == 148)
621 //            return;
622         SetFadeAmt(pp,-1005,148); // Night vision green tint
623         pp->NightVision = TRUE;
624         } else
625         {
626         // Put it all back to normal
627         if(pp->StartColor == 148)
628             {
629             memcpy(pp->temp_pal, palette_data, sizeof(palette_data));
630             memcpy(palookup[PALETTE_DEFAULT], DefaultPalette, 256 * 32);
631             pp->FadeAmt = 0;
632 #if USE_POLYMOST && USE_OPENGL
633             if (getrendermode() >= 3)
634                 {
635                 setpalettefade(0,0,0,0);
636                 }
637             else
638 #endif
639                 {
640                 COVERsetbrightness(gs.Brightness, &palette_data[0][0]);
641                 }
642             }
643             pp->NightVision = FALSE;
644         }
645     }
646 
647 VOID
UseInventoryNightVision(PLAYERp pp)648 UseInventoryNightVision(PLAYERp pp)
649     {
650     SPRITEp sp = pp->SpriteP;
651     #define NIGHT_INVENTORY_TIME 30
652 
653     if (pp->InventoryActive[pp->InventoryNum])
654         {
655         StopInventoryNightVision(pp, pp->InventoryNum);
656         return;
657         }
658 
659     pp->InventoryActive[pp->InventoryNum] = TRUE;
660 
661     // on/off
662     PlayerUpdateInventory(pp, pp->InventoryNum);
663 
664     DoPlayerNightVisionPalette(pp);
665     PlaySound(DIGI_NIGHTON, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan|v3df_follow);
666     }
667 
668 VOID
StopInventoryNightVision(PLAYERp pp,short InventoryNum)669 StopInventoryNightVision(PLAYERp pp, short InventoryNum)
670     {
671     SPRITEp sp = pp->SpriteP;
672 
673     pp->InventoryActive[InventoryNum] = FALSE;
674 
675     if (pp->InventoryPercent[InventoryNum] <= 0)
676         {
677         pp->InventoryPercent[InventoryNum] = 0;
678         if (--pp->InventoryAmount[InventoryNum] < 0)
679             pp->InventoryAmount[InventoryNum] = 0;
680         }
681 
682     AutoPickInventory(pp);
683 
684     // on/off
685     PlayerUpdateInventory(pp, pp->InventoryNum);
686 
687     DoPlayerNightVisionPalette(pp);
688     DoPlayerDivePalette(pp);
689     PlaySound(DIGI_NIGHTOFF, &pp->posx, &pp->posy, &pp->posz, v3df_dontpan|v3df_follow);
690     }
691 
692 //////////////////////////////////////////////////////////////////////
693 //
694 // INVENTORY KEYS
695 //
696 //////////////////////////////////////////////////////////////////////
697 
InventoryKeys(PLAYERp pp)698 VOID InventoryKeys(PLAYERp pp)
699     {
700     short inv_hotkey;
701 
702     // scroll SPELLs left
703     if (TEST_SYNC_KEY(pp, SK_INV_LEFT))
704         {
705         if (FLAG_KEY_PRESSED(pp, SK_INV_LEFT))
706             {
707             FLAG_KEY_RELEASE(pp, SK_INV_LEFT);
708             SpawnInventoryBar(pp);
709             PlayerUpdateInventory(pp, pp->InventoryNum - 1);
710             PutStringInfo(pp, InventoryData[pp->InventoryNum].Name);
711             InventoryBarUpdatePosition(pp);
712             InvBorderRefresh(pp);
713             }
714         }
715     else
716         {
717         FLAG_KEY_RESET(pp, SK_INV_LEFT);
718         }
719 
720     // scroll SPELLs right
721     if (TEST_SYNC_KEY(pp, SK_INV_RIGHT))
722         {
723         if (FLAG_KEY_PRESSED(pp, SK_INV_RIGHT))
724             {
725             FLAG_KEY_RELEASE(pp, SK_INV_RIGHT);
726             SpawnInventoryBar(pp);
727             PlayerUpdateInventory(pp, pp->InventoryNum + 1);
728             PutStringInfo(pp, InventoryData[pp->InventoryNum].Name);
729             InventoryBarUpdatePosition(pp);
730             InvBorderRefresh(pp);
731             }
732         }
733     else
734         {
735         FLAG_KEY_RESET(pp, SK_INV_RIGHT);
736         }
737 
738     if (TEST_SYNC_KEY(pp, SK_INV_USE))
739         {
740         if (FLAG_KEY_PRESSED(pp, SK_INV_USE))
741             {
742             FLAG_KEY_RELEASE(pp, SK_INV_USE);
743 
744             if (InventoryData[pp->InventoryNum].Init)
745                 {
746                 if (pp->InventoryAmount[pp->InventoryNum])
747                     {
748                     InventoryUse(pp);
749                     }
750                 else
751                     {
752                     sprintf(ds,"No %s",InventoryData[pp->InventoryNum].Name);
753                     PutStringInfo(pp,ds); // DONT have message
754                     }
755                 }
756             }
757         }
758     else
759         {
760         FLAG_KEY_RESET(pp, SK_INV_USE);
761         }
762 
763     // get hotkey number out of input bits
764     inv_hotkey = TEST(pp->input.bits, SK_INV_HOTKEY_MASK) >> SK_INV_HOTKEY_BIT0;
765 
766     if (inv_hotkey)
767         {
768         if (FLAG_KEY_PRESSED(pp, SK_INV_HOTKEY_BIT0))
769             {
770             FLAG_KEY_RELEASE(pp, SK_INV_HOTKEY_BIT0);
771 
772             inv_hotkey -= 1;
773 
774             ////DSPRINTF(ds,"inv_hotkey %d",inv_hotkey);
775             //MONO_PRINT(ds);
776 
777             // switches you to this inventory item
778             //PlayerUpdateInventory(pp, inv_hotkey);
779             pp->InventoryNum = inv_hotkey;
780 
781             if (InventoryData[pp->InventoryNum].Init && !TEST(pp->Flags, PF_CLIMBING))
782                 {
783                 if (pp->InventoryAmount[pp->InventoryNum])
784                     {
785                     InventoryUse(pp);
786                     }
787                 #if 0
788                 else
789                     {
790                     sprintf(ds,"No %s",InventoryData[pp->InventoryNum].Name);
791                     PutStringInfo(pp,ds); // DONT have message
792                     }
793                 #endif
794                 }
795 
796             //PlayerUpdateInventory(pp, pp->InventoryNum);
797             }
798         }
799     else
800         {
801         FLAG_KEY_RESET(pp, SK_INV_HOTKEY_BIT0);
802         }
803     }
804 
InvBorderRefresh(PLAYERp pp)805 VOID InvBorderRefresh(PLAYERp pp)
806     {
807     int x,y;
808 
809     if (pp != Player + myconnectindex)
810         return;
811 
812     x = InventoryBarXpos[gs.BorderNum];
813     y = InventoryBarYpos[gs.BorderNum];
814 
815     SetRedrawScreen(pp);
816     //BorderRefreshClip(pp, x-5, y-5, x + (MAX_INVENTORY * INVENTORY_ICON_WIDTH), y + 24);
817     }
818 
InventoryTimer(PLAYERp pp)819 VOID InventoryTimer(PLAYERp pp)
820     {
821     // called every time through loop
822     short inv = 0;
823     INVENTORY_DATAp id;
824 
825     // if bar is up
826     if (pp->InventoryBarTics)
827         {
828         InventoryBarUpdatePosition(pp);
829 
830         pp->InventoryBarTics -= synctics;
831         // if bar time has elapsed
832         if (pp->InventoryBarTics <= 0)
833             {
834             // get rid of the bar
835             KillInventoryBar(pp);
836             // don't update bar anymore
837             pp->InventoryBarTics = 0;
838 
839             InvBorderRefresh(pp);
840             //BorderRefresh(pp);
841             }
842         }
843 
844     for (id = InventoryData; id->Name; id++, inv++)
845         {
846         // if timed and active
847         if (TEST(id->Flags, INVF_TIMED) && pp->InventoryActive[inv])
848             {
849             // dec tics
850             pp->InventoryTics[inv] -= synctics;
851             if (pp->InventoryTics[inv] <= 0)
852                 {
853                 // take off a percentage
854                 pp->InventoryPercent[inv] -= id->DecPerSec;
855                 if (pp->InventoryPercent[inv] <= 0)
856                     {
857                     // ALL USED UP
858                     pp->InventoryPercent[inv] = 0;
859                     InventoryStop(pp, inv);
860                     pp->InventoryActive[inv] = FALSE;
861                     }
862                 else
863                     {
864                     // reset 1 sec tic clock
865                     pp->InventoryTics[inv] = SEC(1);
866                     }
867 
868                 //PlayerUpdateInventoryPercent(pp);
869                 PlayerUpdateInventory(pp, pp->InventoryNum);
870                 }
871             }
872         else
873         // the idea behind this is that the USE function will get called
874         // every time the player is in an AUTO_USE situation.
875         // This code will decrement the timer and set the Item to InActive
876         // EVERY SINGLE TIME.  Relies on the USE function getting called!
877         if (TEST(id->Flags, INVF_AUTO_USE) && pp->InventoryActive[inv])
878             {
879             pp->InventoryTics[inv] -= synctics;
880             if (pp->InventoryTics[inv] <= 0)
881                 {
882                 // take off a percentage
883                 pp->InventoryPercent[inv] -= id->DecPerSec;
884                 if (pp->InventoryPercent[inv] <= 0)
885                     {
886                     // ALL USED UP
887                     pp->InventoryPercent[inv] = 0;
888                     // should get rid if Amount - stop it for good
889                     InventoryStop(pp, inv);
890                     }
891                 else
892                     {
893                     // reset 1 sec tic clock
894                     pp->InventoryTics[inv] = SEC(1);
895                     // set to InActive EVERY TIME THROUGH THE LOOP!
896                     pp->InventoryActive[inv] = FALSE;
897                     }
898 
899                 //PlayerUpdateInventoryPercent(pp);
900                 PlayerUpdateInventory(pp, pp->InventoryNum);
901                 }
902             }
903         }
904     }
905 
906 //////////////////////////////////////////////////////////////////////
907 //
908 // INVENTORY BAR
909 //
910 //////////////////////////////////////////////////////////////////////
911 
SpawnInventoryBar(PLAYERp pp)912 VOID SpawnInventoryBar(PLAYERp pp)
913     {
914     short inv = 0;
915     INVENTORY_DATAp id;
916     PANEL_SPRITEp psp;
917 
918 
919     // its already up
920     if (pp->InventoryBarTics)
921         {
922         pp->InventoryBarTics = SEC(2);
923         return;
924         }
925 
926     pp->InventorySelectionBox = SpawnIcon(pp, ps_PanelSelectionBox);
927 
928     for (id = InventoryData; id->Name; id++, inv++)
929         {
930         psp = SpawnInventoryIcon(pp, inv);
931 
932         if (!pp->InventoryAmount[inv])
933             {
934             //SET(psp->flags, PANF_TRANSLUCENT);
935             //SET(psp->flags, PANF_TRANS_FLIP);
936             psp->shade = 100; //Darken it
937             }
938         }
939 
940     pp->InventoryBarTics = SEC(2);
941     }
942 
KillInventoryBar(PLAYERp pp)943 VOID KillInventoryBar(PLAYERp pp)
944     {
945     KillAllPanelInv(pp);
946     KillPlayerIcon(pp, &pp->InventorySelectionBox);
947     }
948 
949 // In case the BorderNum changes - move the postions
InventoryBarUpdatePosition(PLAYERp pp)950 VOID InventoryBarUpdatePosition(PLAYERp pp)
951     {
952     short inv = 0;
953     short x,y;
954     INVENTORY_DATAp id;
955 
956     x = InventoryBarXpos[gs.BorderNum] + (pp->InventoryNum * INVENTORY_ICON_WIDTH);
957     y = InventoryBarYpos[gs.BorderNum];
958 
959     pp->InventorySelectionBox->x = x - 5;
960     pp->InventorySelectionBox->y = y - 5;
961 
962     for (id = InventoryData; id->Name; id++, inv++)
963         {
964         x = InventoryBarXpos[gs.BorderNum] + (inv * INVENTORY_ICON_WIDTH);
965         y = InventoryBarYpos[gs.BorderNum];
966 
967         pp->InventorySprite[inv]->x = x;
968         pp->InventorySprite[inv]->y = y;
969         }
970 
971     }
972 
InventoryUse(PLAYERp pp)973 VOID InventoryUse(PLAYERp pp)
974     {
975     INVENTORY_DATAp id = &InventoryData[pp->InventoryNum];
976 
977     if (id->Init)
978         (*id->Init)(pp);
979     }
980 
InventoryStop(PLAYERp pp,short InventoryNum)981 VOID InventoryStop(PLAYERp pp, short InventoryNum)
982     {
983     INVENTORY_DATAp id = &InventoryData[InventoryNum];
984 
985     if (id->Stop)
986         (*id->Stop)(pp, InventoryNum);
987     }
988 
989 /////////////////////////////////////////////////////////////////
990 //
991 // Inventory Console Area
992 //
993 /////////////////////////////////////////////////////////////////
994 
995 #define INVENTORY_BOX_X 231
996 #define INVENTORY_BOX_Y (176-8)
997 #define INVENTORY_BOX_ERASE 2403
998 
999 short InventoryBoxX;
1000 short InventoryBoxY;
1001 short InventoryXoff;
1002 short InventoryYoff;
1003 VOID (*InventoryDisplayString)(PLAYERp, short, short, short, const char *);
1004 
1005 #define INVENTORY_PIC_XOFF 1
1006 #define INVENTORY_PIC_YOFF 1
1007 
1008 #define INVENTORY_PERCENT_XOFF 19
1009 #define INVENTORY_PERCENT_YOFF 13
1010 
1011 #define INVENTORY_STATE_XOFF 19
1012 #define INVENTORY_STATE_YOFF 1
1013 
1014 VOID
PlayerUpdateInventory(PLAYERp pp,short InventoryNum)1015 PlayerUpdateInventory(PLAYERp pp, short InventoryNum)
1016     {
1017     USERp u = User[pp->PlayerSprite];
1018     short w,h;
1019     PANEL_SPRITEp psp;
1020 
1021     // Check for items that need to go translucent from use
1022     if (pp->InventoryBarTics)
1023         {
1024         short inv = 0;
1025         INVENTORY_DATAp id;
1026 
1027         // Go translucent if used
1028         for (id = InventoryData; id->Name; id++, inv++)
1029             {
1030             psp = pp->InventorySprite[inv];
1031             if (!pp->InventoryAmount[inv])
1032                 {
1033                 //SET(psp->flags, PANF_TRANSLUCENT);
1034                 //SET(psp->flags, PANF_TRANS_FLIP);
1035                 psp->shade = 100; // Darken it
1036                 }
1037             else
1038                 {
1039                 //RESET(psp->flags, PANF_TRANSLUCENT);
1040                 //RESET(psp->flags, PANF_TRANS_FLIP);
1041                 psp->shade = 0;
1042                 }
1043             }
1044         }
1045 
1046     pp->InventoryNum = InventoryNum;
1047 
1048     if (pp->InventoryNum < 0)
1049         pp->InventoryNum = MAX_INVENTORY-1;
1050 
1051     if (pp->InventoryNum >= MAX_INVENTORY)
1052         pp->InventoryNum = 0;
1053 
1054     if (pp - Player != screenpeek)
1055         return;
1056 
1057     if (gs.BorderNum == BORDER_MINI_BAR)
1058         {
1059         InventoryBoxX = MINI_BAR_INVENTORY_BOX_X;
1060         InventoryBoxY = MINI_BAR_INVENTORY_BOX_Y;
1061 
1062         InventoryXoff = 1;
1063         InventoryYoff = 1;
1064 
1065         InventoryDisplayString = DisplayMiniBarSmString;
1066         }
1067     else
1068         {
1069         if (gs.BorderNum < BORDER_BAR)
1070             return;
1071 
1072         InventoryBoxX = INVENTORY_BOX_X;
1073         InventoryBoxY = INVENTORY_BOX_Y;
1074 
1075         InventoryXoff = 0;
1076         InventoryYoff = 0;
1077 
1078         InventoryDisplayString = DisplaySmString;
1079 
1080         // erase old info
1081         psp = pSpawnFullScreenSprite(pp, INVENTORY_BOX_ERASE, PRI_MID, INVENTORY_BOX_X, INVENTORY_BOX_Y);
1082         SET(psp->flags, PANF_SCALE_BOTTOM);
1083 
1084         // put pic
1085         if (pp->InventoryAmount[pp->InventoryNum])
1086             PlayerUpdateInventoryPic(pp);
1087         }
1088 
1089     if (pp->InventoryAmount[pp->InventoryNum])
1090         {
1091         // Auto/On/Off
1092         PlayerUpdateInventoryState(pp);
1093         // Percent count/Item count
1094         PlayerUpdateInventoryPercent(pp);
1095         }
1096     }
1097 
1098 VOID
PlayerUpdateInventoryPercent(PLAYERp pp)1099 PlayerUpdateInventoryPercent(PLAYERp pp)
1100     {
1101     USERp u = User[pp->PlayerSprite];
1102     short x,y;
1103     INVENTORY_DATAp id = &InventoryData[pp->InventoryNum];
1104 
1105     x = InventoryBoxX + INVENTORY_PERCENT_XOFF + InventoryXoff;
1106     y = InventoryBoxY + INVENTORY_PERCENT_YOFF + InventoryYoff;
1107 
1108     if (TEST(id->Flags, INVF_COUNT))
1109         {
1110         sprintf(ds,"%d", pp->InventoryAmount[pp->InventoryNum]);
1111         InventoryDisplayString(pp, x, y, 0, ds);
1112         }
1113         else
1114         {
1115         sprintf(ds,"%d%c", pp->InventoryPercent[pp->InventoryNum],'%');
1116         InventoryDisplayString(pp, x, y, 0, ds);
1117         }
1118     }
1119 
1120 VOID
PlayerUpdateInventoryPic(PLAYERp pp)1121 PlayerUpdateInventoryPic(PLAYERp pp)
1122     {
1123     USERp u = User[pp->PlayerSprite];
1124     PANEL_SPRITEp psp;
1125     short pic;
1126     short x,y;
1127     INVENTORY_DATAp id = &InventoryData[pp->InventoryNum];
1128 
1129     x = InventoryBoxX + INVENTORY_PIC_XOFF + InventoryXoff;
1130     y = InventoryBoxY + INVENTORY_PIC_YOFF + InventoryYoff;
1131 
1132     pic = id->State->picndx;
1133 
1134     psp = pSpawnFullScreenSprite(pp, pic, PRI_FRONT_MAX, x, y);
1135     SET(psp->flags, PANF_SCALE_BOTTOM);
1136 
1137     psp->scale = id->Scale;
1138     }
1139 
1140 VOID
PlayerUpdateInventoryState(PLAYERp pp)1141 PlayerUpdateInventoryState(PLAYERp pp)
1142     {
1143     USERp u = User[pp->PlayerSprite];
1144     short x,y;
1145     INVENTORY_DATAp id = &InventoryData[pp->InventoryNum];
1146 
1147     x = InventoryBoxX + INVENTORY_STATE_XOFF + InventoryXoff;
1148     y = InventoryBoxY + INVENTORY_STATE_YOFF + InventoryYoff;
1149 
1150     if (TEST(id->Flags, INVF_AUTO_USE))
1151         {
1152         sprintf(ds,"%s", "AUTO");
1153         InventoryDisplayString(pp, x, y, 0, ds);
1154         }
1155     else
1156     if (TEST(id->Flags, INVF_TIMED))
1157         {
1158         sprintf(ds,"%s", pp->InventoryActive[pp->InventoryNum] ? "ON" : "OFF");
1159         InventoryDisplayString(pp, x, y, 0, ds);
1160         }
1161     }
1162