1 
2 /* P_inter.c */
3 
4 #include "doomdef.h"
5 #include "p_local.h"
6 #include "soundst.h"
7 
8 #define BONUSADD 6
9 
10 int WeaponValue[] =
11 {
12   1,		/* staff */
13   3,		/* goldwand */
14   4,		/* crossbow */
15   5,		/* blaster */
16   6,		/* skullrod */
17   7,		/* phoenixrod */
18   8,		/* mace */
19   2,		/* gauntlets */
20   0		/* beak */
21 };
22 
23 int maxammo[NUMAMMO] =
24 {
25   100,	        /* gold wand */
26   50,	        /* crossbow */
27   200,	        /* blaster */
28   200,	        /* skull rod */
29   20,	        /* phoenix rod */
30   150	        /* mace */
31 };
32 
33 static int GetWeaponAmmo[NUMWEAPONS] =
34 {
35   0,		/* staff */
36   25,		/* gold wand */
37   10,		/* crossbow */
38   30,		/* blaster */
39   50,		/* skull rod */
40   2,		/* phoenix rod */
41   50,		/* mace */
42   0,		/* gauntlets */
43   0		/* beak */
44 };
45 
46 static weapontype_t GetAmmoChange[] =
47 {
48   wp_goldwand,
49   wp_crossbow,
50   wp_blaster,
51   wp_skullrod,
52   wp_phoenixrod,
53   wp_mace
54 };
55 
56 /*
57   static boolean GetAmmoChangePL1[NUMWEAPONS][NUMAMMO] =
58   {
59   // staff
60   {wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace},
61   // gold wand
62   {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace},
63   // crossbow
64   {-1, -1, wp_blaster, wp_skullrod, -1, -1},
65   // blaster
66   {-1, -1, -1, -1, -1, -1},
67   // skull rod
68   {-1, -1, -1, -1, -1, -1},
69   // phoenix rod
70   {-1, -1, -1, -1, -1, -1},
71   // mace
72   {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, -1},
73   // gauntlets
74   {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, wp_mace}
75   };
76 */
77 
78 /*
79   static boolean GetAmmoChangePL2[NUMWEAPONS][NUMAMMO] =
80   {
81   // staff
82   {wp_goldwand, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod,
83   wp_mace},
84   // gold wand
85   {-1, wp_crossbow, wp_blaster, wp_skullrod, wp_phoenixrod, wp_mace},
86   // crossbow
87   {-1, -1, wp_blaster, wp_skullrod, wp_phoenixrod, -1},
88   // blaster
89   {-1, -1, -1, wp_skullrod, wp_phoenixrod, -1},
90   // skull rod
91   {-1, -1, -1, -1, -1, -1},
92   // phoenix rod
93   {-1, -1, -1, -1, -1, -1},
94   // mace
95   {-1, wp_crossbow, wp_blaster, wp_skullrod, -1, -1},
96   // gauntlets
97   {-1, -1, -1, wp_skullrod, wp_phoenixrod, wp_mace}
98   };
99 */
100 
101 
102 /*
103   //--------------------------------------------------------------------------
104   //
105   // PROC P_SetMessage
106   //
107   //--------------------------------------------------------------------------
108 */
109 boolean ultimatemsg;
110 
P_SetMessage(player_t * player,char * message,boolean ultmsg)111 void P_SetMessage(player_t *player, char *message, boolean ultmsg)
112 {
113   extern boolean messageson;
114 
115   if((ultimatemsg || !messageson) && !ultmsg)
116     {
117       return;
118     }
119   player->message = message;
120   player->messageTics = MESSAGETICS;
121   BorderTopRefresh = true;
122   if(ultmsg)
123     {
124       ultimatemsg = true;
125     }
126 }
127 
128 
129 /*
130   //--------------------------------------------------------------------------
131   //
132   // FUNC P_GiveAmmo
133   //
134   // Returns true if the player accepted the ammo, false if it was
135   // refused (player has maxammo[ammo]).
136   //
137   //--------------------------------------------------------------------------
138 */
P_GiveAmmo(player_t * player,ammotype_t ammo,int count)139 boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int count)
140 {
141   int prevAmmo;
142   /*   weapontype_t changeWeapon;   */
143 
144   if(ammo == am_noammo)
145     {
146       return(false);
147     }
148   if(ammo < 0 || ammo > NUMAMMO)
149     {
150       I_Error("P_GiveAmmo: bad type %i", ammo);
151     }
152   if(player->ammo[ammo] == player->maxammo[ammo])
153     {
154       return(false);
155     }
156   if(gameskill == sk_baby || gameskill == sk_nightmare)
157     { /* extra ammo in baby mode and nightmare mode */
158       count += count>>1;
159     }
160   prevAmmo = player->ammo[ammo];
161 
162   player->ammo[ammo] += count;
163   if(player->ammo[ammo] > player->maxammo[ammo])
164     {
165       player->ammo[ammo] = player->maxammo[ammo];
166     }
167   if(prevAmmo)
168     {
169       /*
170        * Don't attempt to change weapons if the player already had
171        * ammo of the type just given
172        */
173       return(true);
174     }
175   if(player->readyweapon == wp_staff
176      || player->readyweapon == wp_gauntlets)
177     {
178       if(player->weaponowned[GetAmmoChange[ammo]])
179 	{
180 	  player->pendingweapon = GetAmmoChange[ammo];
181 	}
182     }
183   /*
184     if(player->powers[pw_weaponlevel2])
185     {
186     changeWeapon = GetAmmoChangePL2[player->readyweapon][ammo];
187     }
188     else
189     {
190     changeWeapon = GetAmmoChangePL1[player->readyweapon][ammo];
191     }
192     if(changeWeapon != -1)
193     {
194     if(player->weaponowned[changeWeapon])
195     {
196     player->pendingweapon = changeWeapon;
197     }
198     }
199   */
200   return(true);
201 }
202 
203 
204 /*
205   //--------------------------------------------------------------------------
206   //
207   // FUNC P_GiveWeapon
208   //
209   // Returns true if the weapon or its ammo was accepted.
210   //
211   //--------------------------------------------------------------------------
212 */
P_GiveWeapon(player_t * player,weapontype_t weapon)213 boolean P_GiveWeapon(player_t *player, weapontype_t weapon)
214 {
215   boolean gaveAmmo;
216   boolean gaveWeapon;
217 
218   if(netgame && !deathmatch)
219     { /* Cooperative net-game */
220       if(player->weaponowned[weapon])
221 	{
222 	  return(false);
223 	}
224       player->bonuscount += BONUSADD;
225       player->weaponowned[weapon] = true;
226       P_GiveAmmo(player, wpnlev1info[weapon].ammo,
227 		 GetWeaponAmmo[weapon]);
228       player->pendingweapon = weapon;
229       if(player == &players[consoleplayer])
230 	{
231 	  S_StartSound(NULL, sfx_wpnup);
232 	}
233       return(false);
234     }
235   gaveAmmo = P_GiveAmmo(player, wpnlev1info[weapon].ammo,
236 			GetWeaponAmmo[weapon]);
237   if(player->weaponowned[weapon])
238     {
239       gaveWeapon = false;
240     }
241   else
242     {
243       gaveWeapon = true;
244       player->weaponowned[weapon] = true;
245       if(WeaponValue[weapon] > WeaponValue[player->readyweapon])
246 	{ /* Only switch to more powerful weapons */
247 	  player->pendingweapon = weapon;
248 	}
249     }
250   return(gaveWeapon || gaveAmmo);
251 }
252 
253 
254 /*
255   //---------------------------------------------------------------------------
256   //
257   // FUNC P_GiveBody
258   //
259   // Returns false if the body isn't needed at all.
260   //
261   //---------------------------------------------------------------------------
262 */
P_GiveBody(player_t * player,int num)263 boolean P_GiveBody(player_t *player, int num)
264 {
265   int max;
266 
267   max = MAXHEALTH;
268   if(player->chickenTics)
269     {
270       max = MAXCHICKENHEALTH;
271     }
272   if(player->health >= max)
273     {
274       return(false);
275     }
276   player->health += num;
277   if(player->health > max)
278     {
279       player->health = max;
280     }
281   player->mo->health = player->health;
282   return(true);
283 }
284 
285 
286 /*
287   //---------------------------------------------------------------------------
288   //
289   // FUNC P_GiveArmor
290   //
291   // Returns false if the armor is worse than the current armor.
292   //
293   //---------------------------------------------------------------------------
294 */
P_GiveArmor(player_t * player,int armortype)295 boolean P_GiveArmor(player_t *player, int armortype)
296 {
297   int hits;
298 
299   hits = armortype*100;
300   if(player->armorpoints >= hits)
301     {
302       return(false);
303     }
304   player->armortype = armortype;
305   player->armorpoints = hits;
306   return(true);
307 }
308 
309 
310 /*
311   //---------------------------------------------------------------------------
312   //
313   // PROC P_GiveKey
314   //
315   //---------------------------------------------------------------------------
316 */
P_GiveKey(player_t * player,keytype_t key)317 void P_GiveKey(player_t *player, keytype_t key)
318 {
319   extern int playerkeys;
320   extern vertex_t KeyPoints[];
321 
322   if(player->keys[key])
323     {
324       return;
325     }
326   if(player == &players[consoleplayer])
327     {
328       playerkeys |= 1<<key;
329       KeyPoints[key].x = 0;
330       KeyPoints[key].y = 0;
331     }
332   player->bonuscount = BONUSADD;
333   player->keys[key] = true;
334 }
335 
336 
337 /*
338   //---------------------------------------------------------------------------
339   //
340   // FUNC P_GivePower
341   //
342   // Returns true if power accepted.
343   //
344   //---------------------------------------------------------------------------
345 */
P_GivePower(player_t * player,powertype_t power)346 boolean P_GivePower(player_t *player, powertype_t power)
347 {
348   if(power == pw_invulnerability)
349     {
350       if(player->powers[power] > BLINKTHRESHOLD)
351 	{ /* Already have it */
352 	  return(false);
353 	}
354       player->powers[power] = INVULNTICS;
355       return(true);
356     }
357   if(power == pw_weaponlevel2)
358     {
359       if(player->powers[power] > BLINKTHRESHOLD)
360 	{ /* Already have it */
361 	  return(false);
362 	}
363       player->powers[power] = WPNLEV2TICS;
364       return(true);
365     }
366   if(power == pw_invisibility)
367     {
368       if(player->powers[power] > BLINKTHRESHOLD)
369 	{ /* Already have it */
370 	  return(false);
371 	}
372       player->powers[power] = INVISTICS;
373       player->mo->flags |= MF_SHADOW;
374       return(true);
375     }
376   if(power == pw_flight)
377     {
378       if(player->powers[power] > BLINKTHRESHOLD)
379 	{ /* Already have it */
380 	  return(false);
381 	}
382       player->powers[power] = FLIGHTTICS;
383       player->mo->flags2 |= MF2_FLY;
384       player->mo->flags |= MF_NOGRAVITY;
385       if(player->mo->z <= player->mo->floorz)
386 	{
387 	  player->flyheight = 10; /* thrust the player in the air a bit */
388 	}
389       return(true);
390     }
391   if(power == pw_infrared)
392     {
393       if(player->powers[power] > BLINKTHRESHOLD)
394 	{ /* Already have it */
395 	  return(false);
396 	}
397       player->powers[power] = INFRATICS;
398       return(true);
399     }
400   /*
401     if(power == pw_ironfeet)
402     {
403     player->powers[power] = IRONTICS;
404     return(true);
405     }
406     if(power == pw_strength)
407     {
408     P_GiveBody(player, 100);
409     player->powers[power] = 1;
410     return(true);
411     }
412   */
413   if(player->powers[power])
414     {
415       return(false); /* already got it */
416     }
417   player->powers[power] = 1;
418   return(true);
419 }
420 
421 
422 /*
423   //---------------------------------------------------------------------------
424   //
425   // FUNC P_GiveArtifact
426   //
427   // Returns true if artifact accepted.
428   //
429   //---------------------------------------------------------------------------
430 */
P_GiveArtifact(player_t * player,artitype_t arti,mobj_t * mo)431 boolean P_GiveArtifact(player_t *player, artitype_t arti, mobj_t *mo)
432 {
433   int i;
434 
435   i = 0;
436   while(player->inventory[i].type != arti && i < player->inventorySlotNum)
437     {
438       i++;
439     }
440   if(i == player->inventorySlotNum)
441     {
442       player->inventory[i].count = 1;
443       player->inventory[i].type = arti;
444       player->inventorySlotNum++;
445     }
446   else
447     {
448       if(player->inventory[i].count >= 16)
449 	{ /* Player already has 16 of this item */
450 	  return(false);
451 	}
452       player->inventory[i].count++;
453     }
454   if(player->artifactCount == 0)
455     {
456       player->readyArtifact = arti;
457     }
458   player->artifactCount++;
459   if(mo && (mo->flags&MF_COUNTITEM))
460     {
461       player->itemcount++;
462     }
463   return(true);
464 }
465 
466 
467 /*
468   //---------------------------------------------------------------------------
469   //
470   // PROC P_SetDormantArtifact
471   //
472   // Removes the MF_SPECIAL flag, and initiates the artifact pickup
473   // animation.
474   //
475   //---------------------------------------------------------------------------
476 */
P_SetDormantArtifact(mobj_t * arti)477 void P_SetDormantArtifact(mobj_t *arti)
478 {
479   arti->flags &= ~MF_SPECIAL;
480   if(
481      (deathmatch && (arti->type != MT_ARTIINVULNERABILITY)
482       && (arti->type != MT_ARTIINVISIBILITY))
483      || (respawnartifacts) )
484     {
485       P_SetMobjState(arti, S_DORMANTARTI1);
486     }
487   else
488     { /* Don't respawn */
489       P_SetMobjState(arti, S_DEADARTI1);
490     }
491   S_StartSound(arti, sfx_artiup);
492 }
493 
494 
495 /*
496   //---------------------------------------------------------------------------
497   //
498   // PROC A_RestoreArtifact
499   //
500   //---------------------------------------------------------------------------
501 */
A_RestoreArtifact(mobj_t * arti)502 void A_RestoreArtifact(mobj_t *arti)
503 {
504   arti->flags |= MF_SPECIAL;
505   P_SetMobjState(arti, arti->info->spawnstate);
506   S_StartSound(arti, sfx_respawn);
507 }
508 
509 
510 /*
511   //----------------------------------------------------------------------------
512   //
513   // PROC P_HideSpecialThing
514   //
515   //----------------------------------------------------------------------------
516 */
P_HideSpecialThing(mobj_t * thing)517 void P_HideSpecialThing(mobj_t *thing)
518 {
519   thing->flags &= ~MF_SPECIAL;
520   thing->flags2 |= MF2_DONTDRAW;
521   P_SetMobjState(thing, S_HIDESPECIAL1);
522 }
523 
524 
525 /*
526   //---------------------------------------------------------------------------
527   //
528   // PROC A_RestoreSpecialThing1
529   //
530   // Make a special thing visible again.
531   //
532   //---------------------------------------------------------------------------
533 */
A_RestoreSpecialThing1(mobj_t * thing)534 void A_RestoreSpecialThing1(mobj_t *thing)
535 {
536   if(thing->type == MT_WMACE)
537     { /* Do random mace placement */
538       P_RepositionMace(thing);
539     }
540   thing->flags2 &= ~MF2_DONTDRAW;
541   S_StartSound(thing, sfx_respawn);
542 }
543 
544 
545 /*
546   //---------------------------------------------------------------------------
547   //
548   // PROC A_RestoreSpecialThing2
549   //
550   //---------------------------------------------------------------------------
551 */
A_RestoreSpecialThing2(mobj_t * thing)552 void A_RestoreSpecialThing2(mobj_t *thing)
553 {
554   thing->flags |= MF_SPECIAL;
555   P_SetMobjState(thing, thing->info->spawnstate);
556 }
557 
558 
559 /*
560   //---------------------------------------------------------------------------
561   //
562   // PROC P_TouchSpecialThing
563   //
564   //---------------------------------------------------------------------------
565 */
P_TouchSpecialThing(mobj_t * special,mobj_t * toucher)566 void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher)
567 {
568   int i;
569   player_t *player;
570   fixed_t delta;
571   int sound;
572   boolean respawn;
573 
574   delta = special->z-toucher->z;
575   if(delta > toucher->height || delta < -32*FRACUNIT)
576     { /* Out of reach */
577       return;
578     }
579   if(toucher->health <= 0)
580     { /* Toucher is dead */
581       return;
582     }
583   sound = sfx_itemup;
584   player = toucher->player;
585   respawn = true;
586   switch(special->sprite)
587     {
588       /* Items */
589     case SPR_PTN1: /* Item_HealingPotion */
590       if(!P_GiveBody(player, 10))
591 	{
592 	  return;
593 	}
594       P_SetMessage(player, TXT_ITEMHEALTH, false);
595       break;
596     case SPR_SHLD: /* Item_Shield1 */
597       if(!P_GiveArmor(player, 1))
598 	{
599 	  return;
600 	}
601       P_SetMessage(player, TXT_ITEMSHIELD1, false);
602       break;
603     case SPR_SHD2: /* Item_Shield2 */
604       if(!P_GiveArmor(player, 2))
605 	{
606 	  return;
607 	}
608       P_SetMessage(player, TXT_ITEMSHIELD2, false);
609       break;
610     case SPR_BAGH: /* Item_BagOfHolding */
611       if(!player->backpack)
612 	{
613 	  for(i = 0; i < NUMAMMO; i++)
614 	    {
615 	      player->maxammo[i] *= 2;
616 	    }
617 	  player->backpack = true;
618 	}
619       P_GiveAmmo(player, am_goldwand, AMMO_GWND_WIMPY);
620       P_GiveAmmo(player, am_blaster, AMMO_BLSR_WIMPY);
621       P_GiveAmmo(player, am_crossbow, AMMO_CBOW_WIMPY);
622       P_GiveAmmo(player, am_skullrod, AMMO_SKRD_WIMPY);
623       P_GiveAmmo(player, am_phoenixrod, AMMO_PHRD_WIMPY);
624       P_SetMessage(player, TXT_ITEMBAGOFHOLDING, false);
625       break;
626     case SPR_SPMP: /* Item_SuperMap */
627       if(!P_GivePower(player, pw_allmap))
628 	{
629 	  return;
630 	}
631       P_SetMessage(player, TXT_ITEMSUPERMAP, false);
632       break;
633 
634       /* Keys */
635     case SPR_BKYY: /* Key_Blue */
636       if(!player->keys[key_blue])
637 	{
638 	  P_SetMessage(player, TXT_GOTBLUEKEY, false);
639 	}
640       P_GiveKey(player, key_blue);
641       sound = sfx_keyup;
642       if(!netgame)
643 	{
644 	  break;
645 	}
646       return;
647     case SPR_CKYY: /* Key_Yellow */
648       if(!player->keys[key_yellow])
649 	{
650 	  P_SetMessage(player, TXT_GOTYELLOWKEY, false);
651 	}
652       sound = sfx_keyup;
653       P_GiveKey(player, key_yellow);
654       if(!netgame)
655 	{
656 	  break;
657 	}
658       return;
659     case SPR_AKYY: /* Key_Green */
660       if(!player->keys[key_green])
661 	{
662 	  P_SetMessage(player, TXT_GOTGREENKEY, false);
663 	}
664       sound = sfx_keyup;
665       P_GiveKey(player, key_green);
666       if(!netgame)
667 	{
668 	  break;
669 	}
670       return;
671 
672       /* Artifacts */
673     case SPR_PTN2: /* Arti_HealingPotion */
674       if(P_GiveArtifact(player, arti_health, special))
675 	{
676 	  P_SetMessage(player, TXT_ARTIHEALTH, false);
677 	  P_SetDormantArtifact(special);
678 	}
679       return;
680     case SPR_SOAR: /* Arti_Fly */
681       if(P_GiveArtifact(player, arti_fly, special))
682 	{
683 	  P_SetMessage(player, TXT_ARTIFLY, false);
684 	  P_SetDormantArtifact(special);
685 	}
686       return;
687     case SPR_INVU: /* Arti_Invulnerability */
688       if(P_GiveArtifact(player, arti_invulnerability, special))
689 	{
690 	  P_SetMessage(player, TXT_ARTIINVULNERABILITY, false);
691 	  P_SetDormantArtifact(special);
692 	}
693       return;
694     case SPR_PWBK: /* Arti_TomeOfPower */
695       if(P_GiveArtifact(player, arti_tomeofpower, special))
696 	{
697 	  P_SetMessage(player, TXT_ARTITOMEOFPOWER, false);
698 	  P_SetDormantArtifact(special);
699 	}
700       return;
701     case SPR_INVS: /* Arti_Invisibility */
702       if(P_GiveArtifact(player, arti_invisibility, special))
703 	{
704 	  P_SetMessage(player, TXT_ARTIINVISIBILITY, false);
705 	  P_SetDormantArtifact(special);
706 	}
707       return;
708     case SPR_EGGC: /* Arti_Egg */
709       if(P_GiveArtifact(player, arti_egg, special))
710 	{
711 	  P_SetMessage(player, TXT_ARTIEGG, false);
712 	  P_SetDormantArtifact(special);
713 	}
714       return;
715     case SPR_SPHL: /* Arti_SuperHealth */
716       if(P_GiveArtifact(player, arti_superhealth, special))
717 	{
718 	  P_SetMessage(player, TXT_ARTISUPERHEALTH, false);
719 	  P_SetDormantArtifact(special);
720 	}
721       return;
722     case SPR_TRCH: /* Arti_Torch */
723       if(P_GiveArtifact(player, arti_torch, special))
724 	{
725 	  P_SetMessage(player, TXT_ARTITORCH, false);
726 	  P_SetDormantArtifact(special);
727 	}
728       return;
729     case SPR_FBMB: /* Arti_FireBomb */
730       if(P_GiveArtifact(player, arti_firebomb, special))
731 	{
732 	  P_SetMessage(player, TXT_ARTIFIREBOMB, false);
733 	  P_SetDormantArtifact(special);
734 	}
735       return;
736     case SPR_ATLP: /* Arti_Teleport */
737       if(P_GiveArtifact(player, arti_teleport, special))
738 	{
739 	  P_SetMessage(player, TXT_ARTITELEPORT, false);
740 	  P_SetDormantArtifact(special);
741 	}
742       return;
743 
744       /* Ammo */
745     case SPR_AMG1: /* Ammo_GoldWandWimpy */
746       if(!P_GiveAmmo(player, am_goldwand, special->health))
747 	{
748 	  return;
749 	}
750       P_SetMessage(player, TXT_AMMOGOLDWAND1, false);
751       break;
752     case SPR_AMG2: /* Ammo_GoldWandHefty */
753       if(!P_GiveAmmo(player, am_goldwand, special->health))
754 	{
755 	  return;
756 	}
757       P_SetMessage(player, TXT_AMMOGOLDWAND2, false);
758       break;
759     case SPR_AMM1: /* Ammo_MaceWimpy */
760       if(!P_GiveAmmo(player, am_mace, special->health))
761 	{
762 	  return;
763 	}
764       P_SetMessage(player, TXT_AMMOMACE1, false);
765       break;
766     case SPR_AMM2: /* Ammo_MaceHefty */
767       if(!P_GiveAmmo(player, am_mace, special->health))
768 	{
769 	  return;
770 	}
771       P_SetMessage(player, TXT_AMMOMACE2, false);
772       break;
773     case SPR_AMC1: /* Ammo_CrossbowWimpy */
774       if(!P_GiveAmmo(player, am_crossbow, special->health))
775 	{
776 	  return;
777 	}
778       P_SetMessage(player, TXT_AMMOCROSSBOW1, false);
779       break;
780     case SPR_AMC2: /* Ammo_CrossbowHefty */
781       if(!P_GiveAmmo(player, am_crossbow, special->health))
782 	{
783 	  return;
784 	}
785       P_SetMessage(player, TXT_AMMOCROSSBOW2, false);
786       break;
787     case SPR_AMB1: /* Ammo_BlasterWimpy */
788       if(!P_GiveAmmo(player, am_blaster, special->health))
789 	{
790 	  return;
791 	}
792       P_SetMessage(player, TXT_AMMOBLASTER1, false);
793       break;
794     case SPR_AMB2: /* Ammo_BlasterHefty */
795       if(!P_GiveAmmo(player, am_blaster, special->health))
796 	{
797 	  return;
798 	}
799       P_SetMessage(player, TXT_AMMOBLASTER2, false);
800       break;
801     case SPR_AMS1: /* Ammo_SkullRodWimpy */
802       if(!P_GiveAmmo(player, am_skullrod, special->health))
803 	{
804 	  return;
805 	}
806       P_SetMessage(player, TXT_AMMOSKULLROD1, false);
807       break;
808     case SPR_AMS2: /* Ammo_SkullRodHefty */
809       if(!P_GiveAmmo(player, am_skullrod, special->health))
810 	{
811 	  return;
812 	}
813       P_SetMessage(player, TXT_AMMOSKULLROD2, false);
814       break;
815     case SPR_AMP1: /* Ammo_PhoenixRodWimpy */
816       if(!P_GiveAmmo(player, am_phoenixrod, special->health))
817 	{
818 	  return;
819 	}
820       P_SetMessage(player, TXT_AMMOPHOENIXROD1, false);
821       break;
822     case SPR_AMP2: /* Ammo_PhoenixRodHefty */
823       if(!P_GiveAmmo(player, am_phoenixrod, special->health))
824 	{
825 	  return;
826 	}
827       P_SetMessage(player, TXT_AMMOPHOENIXROD2, false);
828       break;
829 
830       /* Weapons */
831     case SPR_WMCE: /* Weapon_Mace */
832       if(!P_GiveWeapon(player, wp_mace))
833 	{
834 	  return;
835 	}
836       P_SetMessage(player, TXT_WPNMACE, false);
837       sound = sfx_wpnup;
838       break;
839     case SPR_WBOW: /* Weapon_Crossbow */
840       if(!P_GiveWeapon(player, wp_crossbow))
841 	{
842 	  return;
843 	}
844       P_SetMessage(player, TXT_WPNCROSSBOW, false);
845       sound = sfx_wpnup;
846       break;
847     case SPR_WBLS: /* Weapon_Blaster */
848       if(!P_GiveWeapon(player, wp_blaster))
849 	{
850 	  return;
851 	}
852       P_SetMessage(player, TXT_WPNBLASTER, false);
853       sound = sfx_wpnup;
854       break;
855     case SPR_WSKL: /* Weapon_SkullRod */
856       if(!P_GiveWeapon(player, wp_skullrod))
857 	{
858 	  return;
859 	}
860       P_SetMessage(player, TXT_WPNSKULLROD, false);
861       sound = sfx_wpnup;
862       break;
863     case SPR_WPHX: /* Weapon_PhoenixRod */
864       if(!P_GiveWeapon(player, wp_phoenixrod))
865 	{
866 	  return;
867 	}
868       P_SetMessage(player, TXT_WPNPHOENIXROD, false);
869       sound = sfx_wpnup;
870       break;
871     case SPR_WGNT: /* Weapon_Gauntlets */
872       if(!P_GiveWeapon(player, wp_gauntlets))
873 	{
874 	  return;
875 	}
876       P_SetMessage(player, TXT_WPNGAUNTLETS, false);
877       sound = sfx_wpnup;
878       break;
879     default:
880       I_Error("P_SpecialThing: Unknown gettable thing");
881     }
882   if(special->flags&MF_COUNTITEM)
883     {
884       player->itemcount++;
885     }
886   if(deathmatch && respawn && !(special->flags&MF_DROPPED))
887     {
888       P_HideSpecialThing(special);
889     }
890   else
891     {
892       P_RemoveMobj(special);
893     }
894   player->bonuscount += BONUSADD;
895   if(player == &players[consoleplayer])
896     {
897       S_StartSound(NULL, sound);
898       SB_PaletteFlash();
899     }
900 }
901 
902 
903 /*
904   //---------------------------------------------------------------------------
905   //
906   // PROC P_KillMobj
907   //
908   //---------------------------------------------------------------------------
909 */
P_KillMobj(mobj_t * source,mobj_t * target)910 void P_KillMobj(mobj_t *source, mobj_t *target)
911 {
912   target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_NOGRAVITY);
913   target->flags |= MF_CORPSE|MF_DROPOFF;
914   target->flags2 &= ~MF2_PASSMOBJ;
915   target->height >>= 2;
916   if(source && source->player)
917     {
918       if(target->flags&MF_COUNTKILL)
919 	{ /* Count for intermission */
920 	  source->player->killcount++;
921 	}
922       if(target->player)
923 	{ /* Frag stuff */
924 	  if(target == source)
925 	    { /* Self-frag */
926 	      target->player->frags[target->player-players]--;
927 	    }
928 	  else
929 	    {
930 	      source->player->frags[target->player-players]++;
931 	      if(source->player == &players[consoleplayer])
932 		{
933 		  S_StartSound(NULL, sfx_gfrag);
934 		}
935 	      if(source->player->chickenTics)
936 		{ /* Make a super chicken */
937 		  P_GivePower(source->player, pw_weaponlevel2);
938 		}
939 	    }
940 	}
941     }
942   else if(!netgame && (target->flags&MF_COUNTKILL))
943     { /* Count all monster deaths */
944       players[0].killcount++;
945     }
946   if(target->player)
947     {
948       if(!source)
949 	{ /* Self-frag */
950 	  target->player->frags[target->player-players]--;
951 	}
952       target->flags &= ~MF_SOLID;
953       target->flags2 &= ~MF2_FLY;
954       target->player->powers[pw_flight] = 0;
955       target->player->powers[pw_weaponlevel2] = 0;
956       target->player->playerstate = PST_DEAD;
957       P_DropWeapon(target->player);
958       if(target->flags2&MF2_FIREDAMAGE)
959 	{ /* Player flame death */
960 	  P_SetMobjState(target, S_PLAY_FDTH1);
961 	  /*   S_StartSound(target, sfx_hedat1); // Burn sound   */
962 	  return;
963 	}
964     }
965   if(target->health < -(target->info->spawnhealth>>1)
966      && target->info->xdeathstate)
967     { /* Extreme death */
968       P_SetMobjState(target, target->info->xdeathstate);
969     }
970   else
971     { /* Normal death */
972       P_SetMobjState(target, target->info->deathstate);
973     }
974   target->tics -= P_Random()&3;
975   /*	I_StartSound(&actor->r, actor->info->deathsound); */
976 }
977 
978 
979 /*
980   //---------------------------------------------------------------------------
981   //
982   // FUNC P_MinotaurSlam
983   //
984   //---------------------------------------------------------------------------
985 */
P_MinotaurSlam(mobj_t * source,mobj_t * target)986 void P_MinotaurSlam(mobj_t *source, mobj_t *target)
987 {
988   angle_t angle;
989   fixed_t thrust;
990 
991   angle = R_PointToAngle2(source->x, source->y, target->x, target->y);
992   angle >>= ANGLETOFINESHIFT;
993   thrust = 16*FRACUNIT+(P_Random()<<10);
994   target->momx += FixedMul(thrust, finecosine[angle]);
995   target->momy += FixedMul(thrust, finesine[angle]);
996   P_DamageMobj(target, NULL, NULL, HITDICE(6));
997   if(target->player)
998     {
999       target->reactiontime = 14+(P_Random()&7);
1000     }
1001 }
1002 
1003 
1004 /*
1005   //---------------------------------------------------------------------------
1006   //
1007   // FUNC P_TouchWhirlwind
1008   //
1009   //---------------------------------------------------------------------------
1010 */
P_TouchWhirlwind(mobj_t * target)1011 void P_TouchWhirlwind(mobj_t *target)
1012 {
1013   int randVal;
1014 
1015   target->angle += (P_Random()-P_Random())<<20;
1016   target->momx += (P_Random()-P_Random())<<10;
1017   target->momy += (P_Random()-P_Random())<<10;
1018   if(leveltime&16 && !(target->flags2&MF2_BOSS))
1019     {
1020       randVal = P_Random();
1021       if(randVal > 160)
1022 	{
1023 	  randVal = 160;
1024 	}
1025       target->momz += randVal<<10;
1026       if(target->momz > 12*FRACUNIT)
1027 	{
1028 	  target->momz = 12*FRACUNIT;
1029 	}
1030     }
1031   if(!(leveltime&7))
1032     {
1033       P_DamageMobj(target, NULL, NULL, 3);
1034     }
1035 }
1036 
1037 
1038 /*
1039   //---------------------------------------------------------------------------
1040   //
1041   // FUNC P_ChickenMorphPlayer
1042   //
1043   // Returns true if the player gets turned into a chicken.
1044   //
1045   //---------------------------------------------------------------------------
1046 */
P_ChickenMorphPlayer(player_t * player)1047 boolean P_ChickenMorphPlayer(player_t *player)
1048 {
1049   mobj_t *pmo;
1050   mobj_t *fog;
1051   mobj_t *chicken;
1052   fixed_t x;
1053   fixed_t y;
1054   fixed_t z;
1055   angle_t angle;
1056   int oldFlags2;
1057 
1058   if(player->chickenTics)
1059     {
1060       if((player->chickenTics < CHICKENTICS-TICSPERSEC)
1061 	 && !player->powers[pw_weaponlevel2])
1062 	{ /* Make a super chicken */
1063 	  P_GivePower(player, pw_weaponlevel2);
1064 	}
1065       return(false);
1066     }
1067   if(player->powers[pw_invulnerability])
1068     { /* Immune when invulnerable */
1069       return(false);
1070     }
1071   pmo = player->mo;
1072   x = pmo->x;
1073   y = pmo->y;
1074   z = pmo->z;
1075   angle = pmo->angle;
1076   oldFlags2 = pmo->flags2;
1077   P_SetMobjState(pmo, S_FREETARGMOBJ);
1078   fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
1079   S_StartSound(fog, sfx_telept);
1080   chicken = P_SpawnMobj(x, y, z, MT_CHICPLAYER);
1081   chicken->special1 = player->readyweapon;
1082   chicken->angle = angle;
1083   chicken->player = player;
1084   player->health = chicken->health = MAXCHICKENHEALTH;
1085   player->mo = chicken;
1086   player->armorpoints = player->armortype = 0;
1087   player->powers[pw_invisibility] = 0;
1088   player->powers[pw_weaponlevel2] = 0;
1089   if(oldFlags2&MF2_FLY)
1090     {
1091       chicken->flags2 |= MF2_FLY;
1092     }
1093   player->chickenTics = CHICKENTICS;
1094   P_ActivateBeak(player);
1095   return(true);
1096 }
1097 
1098 
1099 /*
1100   //---------------------------------------------------------------------------
1101   //
1102   // FUNC P_ChickenMorph
1103   //
1104   //---------------------------------------------------------------------------
1105 */
P_ChickenMorph(mobj_t * actor)1106 boolean P_ChickenMorph(mobj_t *actor)
1107 {
1108   mobj_t *fog;
1109   mobj_t *chicken;
1110   mobj_t *target;
1111   mobjtype_t moType;
1112   fixed_t x;
1113   fixed_t y;
1114   fixed_t z;
1115   angle_t angle;
1116   int ghost;
1117 
1118   if(actor->player)
1119     {
1120       return(false);
1121     }
1122   moType = actor->type;
1123   switch(moType)
1124     {
1125     case MT_POD:
1126     case MT_CHICKEN:
1127     case MT_HEAD:
1128     case MT_MINOTAUR:
1129     case MT_SORCERER1:
1130     case MT_SORCERER2:
1131       return(false);
1132     default:
1133       break;
1134     }
1135   x = actor->x;
1136   y = actor->y;
1137   z = actor->z;
1138   angle = actor->angle;
1139   ghost = actor->flags&MF_SHADOW;
1140   target = actor->target;
1141   P_SetMobjState(actor, S_FREETARGMOBJ);
1142   fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
1143   S_StartSound(fog, sfx_telept);
1144   chicken = P_SpawnMobj(x, y, z, MT_CHICKEN);
1145   chicken->special2 = moType;
1146   chicken->special1 = CHICKENTICS+P_Random();
1147   chicken->flags |= ghost;
1148   chicken->target = target;
1149   chicken->angle = angle;
1150   return(true);
1151 }
1152 
1153 
1154 /*
1155   //---------------------------------------------------------------------------
1156   //
1157   // FUNC P_AutoUseChaosDevice
1158   //
1159   //---------------------------------------------------------------------------
1160 */
P_AutoUseChaosDevice(player_t * player)1161 boolean P_AutoUseChaosDevice(player_t *player)
1162 {
1163   int i;
1164 
1165   for(i = 0; i < player->inventorySlotNum; i++)
1166     {
1167       if(player->inventory[i].type == arti_teleport)
1168 	{
1169 	  P_PlayerUseArtifact(player, arti_teleport);
1170 	  player->health = player->mo->health = (player->health+1)/2;
1171 	  return(true);
1172 	}
1173     }
1174   return(false);
1175 }
1176 
1177 
1178 /*
1179   //---------------------------------------------------------------------------
1180   //
1181   // PROC P_AutoUseHealth
1182   //
1183   //---------------------------------------------------------------------------
1184 */
P_AutoUseHealth(player_t * player,int saveHealth)1185 void P_AutoUseHealth(player_t *player, int saveHealth)
1186 {
1187   int i;
1188   int count;
1189   int normalCount;
1190   /* changed from int normalSlot */
1191   int normalSlot=0;
1192   int superCount;
1193   /* changed from int superSlot */
1194   int superSlot=0;
1195 
1196   normalCount = superCount = 0;
1197   for(i = 0; i < player->inventorySlotNum; i++)
1198     {
1199       if(player->inventory[i].type == arti_health)
1200 	{
1201 	  normalSlot = i;
1202 	  normalCount = player->inventory[i].count;
1203 	}
1204       else if(player->inventory[i].type == arti_superhealth)
1205 	{
1206 	  superSlot = i;
1207 	  superCount = player->inventory[i].count;
1208 	}
1209     }
1210   if((gameskill == sk_baby) && (normalCount*25 >= saveHealth))
1211     { /* Use quartz flasks */
1212       count = (saveHealth+24)/25;
1213       for(i = 0; i < count; i++)
1214 	{
1215 	  player->health += 25;
1216 	  P_PlayerRemoveArtifact(player, normalSlot);
1217 	}
1218     }
1219   else if(superCount*100 >= saveHealth)
1220     { /* Use mystic urns */
1221       count = (saveHealth+99)/100;
1222       for(i = 0; i < count; i++)
1223 	{
1224 	  player->health += 100;
1225 	  P_PlayerRemoveArtifact(player, superSlot);
1226 	}
1227     }
1228   else if((gameskill == sk_baby)
1229 	  && (superCount*100+normalCount*25 >= saveHealth))
1230     { /* Use mystic urns and quartz flasks */
1231       count = (saveHealth+24)/25;
1232       saveHealth -= count*25;
1233       for(i = 0; i < count; i++)
1234 	{
1235 	  player->health += 25;
1236 	  P_PlayerRemoveArtifact(player, normalSlot);
1237 	}
1238       count = (saveHealth+99)/100;
1239       for(i = 0; i < count; i++)
1240 	{
1241 	  player->health += 100;
1242 	  P_PlayerRemoveArtifact(player, normalSlot);
1243 	}
1244     }
1245   player->mo->health = player->health;
1246 }
1247 
1248 /*
1249   =================
1250   =
1251   = P_DamageMobj
1252   =
1253   = Damages both enemies and players
1254   = inflictor is the thing that caused the damage
1255   = 		creature or missile, can be NULL (slime, etc)
1256   = source is the thing to target after taking damage
1257   =		creature or NULL
1258   = Source and inflictor are the same for melee attacks
1259   = source can be null for barrel explosions and other environmental stuff
1260   ==================
1261 */
1262 
P_DamageMobj(mobj_t * target,mobj_t * inflictor,mobj_t * source,int damage)1263 void P_DamageMobj
1264 (
1265  mobj_t *target,
1266  mobj_t *inflictor,
1267  mobj_t *source,
1268  int	damage
1269  )
1270 {
1271   unsigned ang;
1272   int saved;
1273   player_t *player;
1274   fixed_t thrust;
1275   int temp;
1276 
1277   if(!(target->flags&MF_SHOOTABLE))
1278     {
1279       /* Shouldn't happen */
1280       return;
1281     }
1282   if(target->health <= 0)
1283     {
1284       return;
1285     }
1286   if(target->flags&MF_SKULLFLY)
1287     {
1288       if(target->type == MT_MINOTAUR)
1289 	{ /* Minotaur is invulnerable during charge attack */
1290 	  return;
1291 	}
1292       target->momx = target->momy = target->momz = 0;
1293     }
1294   player = target->player;
1295   if(player && gameskill == sk_baby)
1296     {
1297       /* Take half damage in trainer mode */
1298       damage >>= 1;
1299     }
1300   /* Special damage types */
1301   if(inflictor)
1302     {
1303       switch(inflictor->type)
1304 	{
1305 	case MT_EGGFX:
1306 	  if(player)
1307 	    {
1308 	      P_ChickenMorphPlayer(player);
1309 	    }
1310 	  else
1311 	    {
1312 	      P_ChickenMorph(target);
1313 	    }
1314 	  return; /* Always return */
1315 	case MT_WHIRLWIND:
1316 	  P_TouchWhirlwind(target);
1317 	  return;
1318 	case MT_MINOTAUR:
1319 	  if(inflictor->flags&MF_SKULLFLY)
1320 	    { /* Slam only when in charge mode */
1321 	      P_MinotaurSlam(inflictor, target);
1322 	      return;
1323 	    }
1324 	  break;
1325 	case MT_MACEFX4: /* Death ball */
1326 	  if((target->flags2&MF2_BOSS) || target->type == MT_HEAD)
1327 	    { /* Don't allow cheap boss kills */
1328 	      break;
1329 	    }
1330 	  else if(target->player)
1331 	    { /* Player specific checks */
1332 	      if(target->player->powers[pw_invulnerability])
1333 		{ /* Can't hurt invulnerable players */
1334 		  break;
1335 		}
1336 	      if(P_AutoUseChaosDevice(target->player))
1337 		{ /* Player was saved using chaos device */
1338 		  return;
1339 		}
1340 	    }
1341 	  damage = 10000; /* Something's gonna die */
1342 	  break;
1343 	case MT_PHOENIXFX2: /* Flame thrower */
1344 	  if(target->player && P_Random() < 128)
1345 	    { /* Freeze player for a bit */
1346 	      target->reactiontime += 4;
1347 	    }
1348 	  break;
1349 	case MT_RAINPLR1: /* Rain missiles */
1350 	case MT_RAINPLR2:
1351 	case MT_RAINPLR3:
1352 	case MT_RAINPLR4:
1353 	  if(target->flags2&MF2_BOSS)
1354 	    { /* Decrease damage for bosses */
1355 	      damage = (P_Random()&7)+1;
1356 	    }
1357 	  break;
1358 	case MT_HORNRODFX2:
1359 	case MT_PHOENIXFX1:
1360 	  if(target->type == MT_SORCERER2 && P_Random() < 96)
1361 	    { /* D'Sparil teleports away */
1362 	      P_DSparilTeleport(target);
1363 	      return;
1364 	    }
1365 	  break;
1366 	case MT_BLASTERFX1:
1367 	case MT_RIPPER:
1368 	  if(target->type == MT_HEAD)
1369 	    { /* Less damage to Ironlich bosses */
1370 	      damage = P_Random()&1;
1371 	      if(!damage)
1372 		{
1373 		  return;
1374 		}
1375 	    }
1376 	  break;
1377 	default:
1378 	  break;
1379 	}
1380     }
1381   /* Push the target unless source is using the gauntlets */
1382   if(inflictor && (!source || !source->player
1383 		   || source->player->readyweapon != wp_gauntlets)
1384      && !(inflictor->flags2&MF2_NODMGTHRUST))
1385     {
1386       ang = R_PointToAngle2(inflictor->x, inflictor->y,
1387 			    target->x, target->y);
1388       /*   thrust = damage*(FRACUNIT>>3)*100/target->info->mass;   */
1389       thrust = damage*(FRACUNIT>>3)*150/target->info->mass;
1390       /* make fall forwards sometimes */
1391       if((damage < 40) && (damage > target->health)
1392 	 && (target->z-inflictor->z > 64*FRACUNIT) && (P_Random()&1))
1393 	{
1394 	  ang += ANG180;
1395 	  thrust *= 4;
1396 	}
1397       ang >>= ANGLETOFINESHIFT;
1398       if(source && source->player && (source == inflictor)
1399 	 && source->player->powers[pw_weaponlevel2]
1400 	 && source->player->readyweapon == wp_staff)
1401 	{
1402 	  /* Staff power level 2 */
1403 	  target->momx += FixedMul(10*FRACUNIT, finecosine[ang]);
1404 	  target->momy += FixedMul(10*FRACUNIT, finesine[ang]);
1405 	  if(!(target->flags&MF_NOGRAVITY))
1406 	    {
1407 	      target->momz += 5*FRACUNIT;
1408 	    }
1409 	}
1410       else
1411 	{
1412 	  target->momx += FixedMul(thrust, finecosine[ang]);
1413 	  target->momy += FixedMul(thrust, finesine[ang]);
1414 	}
1415     }
1416 
1417   /*
1418    * player specific
1419    */
1420   if(player)
1421     {
1422       /*
1423 	// end of game hell hack
1424 	//if(target->subsector->sector->special == 11
1425 	//	&& damage >= target->health)
1426 	//{
1427 	//	damage = target->health - 1;
1428 	//}
1429       */
1430 
1431       if(damage < 1000 && ((player->cheats&CF_GODMODE)
1432 			   || player->powers[pw_invulnerability]))
1433 	{
1434 	  return;
1435 	}
1436       if(player->armortype)
1437 	{
1438 	  if(player->armortype == 1)
1439 	    {
1440 	      saved = damage>>1;
1441 	    }
1442 	  else
1443 	    {
1444 	      saved = (damage>>1)+(damage>>2);
1445 	    }
1446 	  if(player->armorpoints <= saved)
1447 	    {
1448 				/* armor is used up */
1449 	      saved = player->armorpoints;
1450 	      player->armortype = 0;
1451 	    }
1452 	  player->armorpoints -= saved;
1453 	  damage -= saved;
1454 	}
1455       if(damage >= player->health
1456 	 && ((gameskill == sk_baby) || deathmatch)
1457 	 && !player->chickenTics)
1458 	{ /* Try to use some inventory health */
1459 	  P_AutoUseHealth(player, damage-player->health+1);
1460 	}
1461       player->health -= damage; /* mirror mobj health here for Dave */
1462       if(player->health < 0)
1463 	{
1464 	  player->health = 0;
1465 	}
1466       player->attacker = source;
1467       player->damagecount += damage; /* add damage after armor / invuln */
1468       if(player->damagecount > 100)
1469 	{
1470 	  player->damagecount = 100; /* teleport stomp does 10k points... */
1471 	}
1472       temp = damage < 100 ? damage : 100;
1473       if(player == &players[consoleplayer])
1474 	{
1475 	  /* MR ! */
1476 	  /* I_Tactile(40, 10, 40+temp*2); */
1477 	  SB_PaletteFlash();
1478 	}
1479     }
1480 
1481   /*
1482    * do the damage
1483    */
1484   target->health -= damage;
1485   if(target->health <= 0)
1486     { /* Death */
1487       target->special1 = damage;
1488       if(target->type == MT_POD && source && source->type != MT_POD)
1489 	{ /* Make sure players get frags for chain-reaction kills */
1490 	  target->target = source;
1491 	}
1492       if(player && inflictor && !player->chickenTics)
1493 	{ /* Check for flame death */
1494 	  if((inflictor->flags2&MF2_FIREDAMAGE)
1495 	     || ((inflictor->type == MT_PHOENIXFX1)
1496 		 && (target->health > -50) && (damage > 25)))
1497 	    {
1498 	      target->flags2 |= MF2_FIREDAMAGE;
1499 	    }
1500 	}
1501       P_KillMobj(source, target);
1502       return;
1503     }
1504   if((P_Random() < target->info->painchance)
1505      && !(target->flags&MF_SKULLFLY))
1506     {
1507       target->flags |= MF_JUSTHIT; /* fight back! */
1508       P_SetMobjState(target, target->info->painstate);
1509     }
1510   target->reactiontime = 0; /* we're awake now... */
1511   if(!target->threshold && source && !(source->flags2&MF2_BOSS)
1512      && !(target->type == MT_SORCERER2 && source->type == MT_WIZARD))
1513     {
1514       /*
1515        * Target actor is not intent on another actor,
1516        * so make him chase after source
1517        */
1518       target->target = source;
1519       target->threshold = BASETHRESHOLD;
1520       if(target->state == &states[target->info->spawnstate]
1521 	 && target->info->seestate != S_NULL)
1522 	{
1523 	  P_SetMobjState(target, target->info->seestate);
1524 	}
1525     }
1526 }
1527 
1528 
1529