ref: 0de63fa5e707d4811a67e3f3e81cd7e9349581f2
author: Jacob Moody <[email protected]>
date: Sat Jan 21 20:12:46 EST 2023
initial commit
--- /dev/null
+++ b/a_action.c
@@ -1,0 +1,1321 @@
+
+//**************************************************************************
+//**
+//** a_action.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 584 $
+//** $Date: 2012-02-17 12:01:51 +0200 (Fri, 17 Feb 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern fixed_t FloatBobOffsets[64];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int orbitTableX[256] =
+{
+ 983025, 982725, 981825, 980340, 978255, 975600, 972330, 968490,
+ 964065, 959070, 953475, 947325, 940590, 933300, 925440, 917025,
+ 908055, 898545, 888495, 877905, 866775, 855135, 842985, 830310,
+ 817155, 803490, 789360, 774735, 759660, 744120, 728130, 711690,
+ 694845, 677565, 659880, 641805, 623340, 604500, 585285, 565725,
+ 545820, 525600, 505050, 484200, 463065, 441645, 419955, 398010,
+ 375840, 353430, 330810, 307995, 285000, 261825, 238485, 215010,
+ 191400, 167685, 143865, 119955, 95970, 71940, 47850, 23745,
+ -375, -24495, -48600, -72690, -96720, -120705, -144600, -168420,
+ -192150, -215745, -239220, -262545, -285720, -308715, -331530, -354135,
+ -376530, -398700, -420630, -442320, -463725, -484860, -505695, -526230,
+ -546450, -566340, -585885, -605085, -623925, -642375, -660435, -678105,
+ -695370, -712215, -728625, -744600, -760125, -775200, -789795, -803925,
+ -817575, -830715, -843375, -855510, -867135, -878235, -888810, -898845,
+ -908340, -917295, -925695, -933540, -940815, -947520, -953670, -959235,
+ -964215, -968625, -972450, -975690, -978330, -980400, -981870, -982740,
+ -983025, -982725, -981825, -980340, -978255, -975600, -972330, -968490,
+ -964065, -959070, -953475, -947325, -940590, -933300, -925440, -917025,
+ -908055, -898545, -888495, -877905, -866775, -855135, -842985, -830310,
+ -817155, -803490, -789360, -774735, -759660, -744120, -728130, -711690,
+ -694845, -677565, -659880, -641805, -623340, -604485, -585285, -565725,
+ -545820, -525600, -505050, -484200, -463065, -441645, -419955, -398010,
+ -375840, -353430, -330810, -307995, -285000, -261825, -238485, -215010,
+ -191400, -167685, -143865, -119955, -95970, -71940, -47850, -23745,
+ 375, 24495, 48600, 72690, 96720, 120705, 144600, 168420,
+ 192150, 215745, 239220, 262545, 285720, 308715, 331530, 354135,
+ 376530, 398700, 420630, 442320, 463725, 484860, 505695, 526230,
+ 546450, 566340, 585885, 605085, 623925, 642375, 660435, 678105,
+ 695370, 712215, 728625, 744600, 760125, 775200, 789795, 803925,
+ 817575, 830715, 843375, 855510, 867135, 878235, 888810, 898845,
+ 908340, 917295, 925695, 933540, 940815, 947520, 953670, 959235,
+ 964215, 968625, 972450, 975690, 978330, 980400, 981870, 982740
+};
+
+static int orbitTableY[256] =
+{
+ 375, 24495, 48600, 72690, 96720, 120705, 144600, 168420,
+ 192150, 215745, 239220, 262545, 285720, 308715, 331530, 354135,
+ 376530, 398700, 420630, 442320, 463725, 484860, 505695, 526230,
+ 546450, 566340, 585885, 605085, 623925, 642375, 660435, 678105,
+ 695370, 712215, 728625, 744600, 760125, 775200, 789795, 803925,
+ 817575, 830715, 843375, 855510, 867135, 878235, 888810, 898845,
+ 908340, 917295, 925695, 933540, 940815, 947520, 953670, 959235,
+ 964215, 968625, 972450, 975690, 978330, 980400, 981870, 982740,
+ 983025, 982725, 981825, 980340, 978255, 975600, 972330, 968490,
+ 964065, 959070, 953475, 947325, 940590, 933300, 925440, 917025,
+ 908055, 898545, 888495, 877905, 866775, 855135, 842985, 830310,
+ 817155, 803490, 789360, 774735, 759660, 744120, 728130, 711690,
+ 694845, 677565, 659880, 641805, 623340, 604500, 585285, 565725,
+ 545820, 525600, 505050, 484200, 463065, 441645, 419955, 398010,
+ 375840, 353430, 330810, 307995, 285000, 261825, 238485, 215010,
+ 191400, 167685, 143865, 119955, 95970, 71940, 47850, 23745,
+ -375, -24495, -48600, -72690, -96720, -120705, -144600, -168420,
+ -192150, -215745, -239220, -262545, -285720, -308715, -331530, -354135,
+ -376530, -398700, -420630, -442320, -463725, -484860, -505695, -526230,
+ -546450, -566340, -585885, -605085, -623925, -642375, -660435, -678105,
+ -695370, -712215, -728625, -744600, -760125, -775200, -789795, -803925,
+ -817575, -830715, -843375, -855510, -867135, -878235, -888810, -898845,
+ -908340, -917295, -925695, -933540, -940815, -947520, -953670, -959235,
+ -964215, -968625, -972450, -975690, -978330, -980400, -981870, -982740,
+ -983025, -982725, -981825, -980340, -978255, -975600, -972330, -968490,
+ -964065, -959070, -953475, -947325, -940590, -933300, -925440, -917025,
+ -908055, -898545, -888495, -877905, -866775, -855135, -842985, -830310,
+ -817155, -803490, -789360, -774735, -759660, -744120, -728130, -711690,
+ -694845, -677565, -659880, -641805, -623340, -604485, -585285, -565725,
+ -545820, -525600, -505050, -484200, -463065, -441645, -419955, -398010,
+ -375840, -353430, -330810, -307995, -285000, -261825, -238485, -215010,
+ -191400, -167685, -143865, -119955, -95970, -71940, -47850, -23745
+};
+
+// CODE --------------------------------------------------------------------
+
+//--------------------------------------------------------------------------
+//
+// Environmental Action routines
+//
+//--------------------------------------------------------------------------
+
+//==========================================================================
+//
+// A_DripBlood
+//
+//==========================================================================
+
+/*
+void A_DripBlood(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<11),
+ actor->y+((P_Random()-P_Random())<<11), actor->z, MT_BLOOD);
+ mo->momx = (P_Random()-P_Random())<<10;
+ mo->momy = (P_Random()-P_Random())<<10;
+ mo->flags2 |= MF2_LOGRAV;
+}
+*/
+
+//============================================================================
+//
+// A_PotteryExplode
+//
+//============================================================================
+
+void A_PotteryExplode(mobj_t *actor)
+{
+ mobj_t *mo = NULL;
+ int i;
+
+ for (i = (P_Random()&3)+3; i; i--)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_POTTERYBIT1);
+ P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 5));
+ if (mo)
+ {
+ mo->momz = ((P_Random()&7)+5)*(3*FRACUNIT/4);
+ mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
+ mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
+ }
+ }
+ S_StartSound(mo, SFX_POTTERY_EXPLODE);
+ if (actor->args[0])
+ { // Spawn an item
+ if (!nomonsters ||
+ !(mobjinfo[TranslateThingType[actor->args[0]]].flags & MF_COUNTKILL))
+ { // Only spawn monsters if not -nomonsters
+ P_SpawnMobj(actor->x, actor->y, actor->z,
+ TranslateThingType[actor->args[0]]);
+ }
+ }
+ P_RemoveMobj(actor);
+}
+
+//============================================================================
+//
+// A_PotteryChooseBit
+//
+//============================================================================
+
+void A_PotteryChooseBit(mobj_t *actor)
+{
+ P_SetMobjState(actor, actor->info->deathstate + (P_Random()%5) + 1);
+ actor->tics = 256 + (P_Random()<<1);
+}
+
+//============================================================================
+//
+// A_PotteryCheck
+//
+//============================================================================
+
+void A_PotteryCheck(mobj_t *actor)
+{
+ int i;
+ mobj_t *pmo;
+
+ if (!netgame)
+ {
+ pmo = players[consoleplayer].mo;
+ if (P_CheckSight(actor, pmo) &&
+ abs(R_PointToAngle2(pmo->x, pmo->y, actor->x, actor->y)-pmo->angle) <= ANGLE_45)
+ { // Previous state (pottery bit waiting state)
+ P_SetMobjState(actor, actor->state-&states[0]-1);
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ pmo = players[i].mo;
+ if (P_CheckSight(actor, pmo) &&
+ abs(R_PointToAngle2(pmo->x, pmo->y, actor->x, actor->y)-pmo->angle) <= ANGLE_45)
+ { // Previous state (pottery bit waiting state)
+ P_SetMobjState(actor, actor->state-&states[0]-1);
+ return;
+ }
+ }
+ }
+}
+
+//============================================================================
+//
+// A_CorpseBloodDrip
+//
+//============================================================================
+
+void A_CorpseBloodDrip(mobj_t *actor)
+{
+ if (P_Random() > 128)
+ {
+ return;
+ }
+ P_SpawnMobj(actor->x, actor->y, actor->z+actor->height/2, MT_CORPSEBLOODDRIP);
+}
+
+//============================================================================
+//
+// A_CorpseExplode
+//
+//============================================================================
+
+void A_CorpseExplode(mobj_t *actor)
+{
+ mobj_t *mo;
+ int i;
+
+ for (i = (P_Random()&3)+3; i; i--)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_CORPSEBIT);
+ P_SetMobjState(mo, mo->info->spawnstate + (P_Random()%3));
+ if (mo)
+ {
+ mo->momz = ((P_Random()&7)+5)*(3*FRACUNIT/4);
+ mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
+ mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
+ }
+ }
+ // Spawn a skull
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_CORPSEBIT);
+ P_SetMobjState(mo, S_CORPSEBIT_4);
+ if (mo)
+ {
+ mo->momz = ((P_Random()&7) + 5) * (3*FRACUNIT/4);
+ mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
+ mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
+ S_StartSound(mo, SFX_FIRED_DEATH);
+ }
+ P_RemoveMobj(actor);
+}
+
+//============================================================================
+//
+// A_LeafSpawn
+//
+//============================================================================
+
+void A_LeafSpawn(mobj_t *actor)
+{
+ mobj_t *mo;
+ int i;
+
+ for (i = (P_Random()&3)+1; i; i--)
+ {
+ mo = P_SpawnMobj(actor->x + ((P_Random()-P_Random())<<14),
+ actor->y + ((P_Random()-P_Random())<<14),
+ actor->z + (P_Random()<<14),
+ MT_LEAF1 + (P_Random()&1));
+ if (mo)
+ {
+ P_ThrustMobj(mo, actor->angle, (P_Random()<<9)+3*FRACUNIT);
+ mo->target = actor;
+ mo->special1 = 0;
+ }
+ }
+}
+
+//============================================================================
+//
+// A_LeafThrust
+//
+//============================================================================
+
+void A_LeafThrust(mobj_t *actor)
+{
+ if (P_Random() > 96)
+ {
+ return;
+ }
+ actor->momz += (P_Random()<<9)+FRACUNIT;
+}
+
+//============================================================================
+//
+// A_LeafCheck
+//
+//============================================================================
+
+void A_LeafCheck(mobj_t *actor)
+{
+ actor->special1++;
+ if (actor->special1 >= 20)
+ {
+ P_SetMobjState(actor, S_NULL);
+ return;
+ }
+ if (P_Random() > 64)
+ {
+ if (!actor->momx && !actor->momy)
+ {
+ P_ThrustMobj(actor, actor->target->angle,
+ (P_Random()<<9)+FRACUNIT);
+ }
+ return;
+ }
+ P_SetMobjState(actor, S_LEAF1_8);
+ actor->momz = (P_Random()<<9)+FRACUNIT;
+ P_ThrustMobj(actor, actor->target->angle, (P_Random()<<9)+2*FRACUNIT);
+ actor->flags |= MF_MISSILE;
+}
+
+/*
+#define ORBIT_RADIUS (15*FRACUNIT)
+void GenerateOrbitTable(void)
+{
+ int angle;
+
+ for (angle = 0; angle < 256; angle++)
+ {
+ orbitTableX[angle] = FixedMul(ORBIT_RADIUS, finecosine[angle<<5]);
+ orbitTableY[angle] = FixedMul(ORBIT_RADIUS, finesine[angle<<5]);
+ }
+
+ printf("int orbitTableX[256]=\n{\n");
+ for (angle = 0; angle < 256; angle += 8)
+ {
+ printf("%d, %d, %d, %d, %d, %d, %d, %d,\n",
+ orbitTableX[angle],
+ orbitTableX[angle+1],
+ orbitTableX[angle+2],
+ orbitTableX[angle+3],
+ orbitTableX[angle+4],
+ orbitTableX[angle+5],
+ orbitTableX[angle+6],
+ orbitTableX[angle+7]);
+ }
+ printf("};\n\n");
+
+ printf("int orbitTableY[256]=\n{\n");
+ for (angle = 0; angle < 256; angle += 8)
+ {
+ printf("%d, %d, %d, %d, %d, %d, %d, %d,\n",
+ orbitTableY[angle],
+ orbitTableY[angle+1],
+ orbitTableY[angle+2],
+ orbitTableY[angle+3],
+ orbitTableY[angle+4],
+ orbitTableY[angle+5],
+ orbitTableY[angle+6],
+ orbitTableY[angle+7]);
+ }
+ printf("};\n");
+}
+*/
+
+// New bridge stuff
+// Parent
+// special1 true == removing from world
+//
+// Child
+// target pointer to center mobj
+// args[0] angle of ball
+
+void A_BridgeOrbit(mobj_t *actor)
+{
+ if (actor->target->special1)
+ {
+ P_SetMobjState(actor, S_NULL);
+ }
+ actor->args[0] += 3;
+ actor->x = actor->target->x + orbitTableX[actor->args[0]];
+ actor->y = actor->target->y + orbitTableY[actor->args[0]];
+ actor->z = actor->target->z;
+}
+
+
+void A_BridgeInit(mobj_t *actor)
+{
+ byte startangle;
+ mobj_t *ball1, *ball2, *ball3;
+ fixed_t cx,cy,cz;
+
+// GenerateOrbitTable();
+
+ cx = actor->x;
+ cy = actor->y;
+ cz = actor->z;
+ startangle = P_Random();
+ actor->special1 = 0;
+
+ // Spawn triad into world
+ ball1 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
+ ball1->args[0] = startangle;
+ ball1->target = actor;
+
+ ball2 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
+ ball2->args[0] = (startangle + 85) & 255;
+ ball2->target = actor;
+
+ ball3 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
+ ball3->args[0] = (startangle + 170) & 255;
+ ball3->target = actor;
+
+ A_BridgeOrbit(ball1);
+ A_BridgeOrbit(ball2);
+ A_BridgeOrbit(ball3);
+}
+
+void A_BridgeRemove(mobj_t *actor)
+{
+ actor->special1 = true; // Removing the bridge
+ actor->flags &= ~MF_SOLID;
+ P_SetMobjState(actor, S_FREE_BRIDGE1);
+}
+
+
+//==========================================================================
+//
+// A_GhostOn
+//
+//==========================================================================
+
+/*
+void A_GhostOn(mobj_t *actor)
+{
+ actor->flags |= MF_SHADOW;
+}
+*/
+
+//==========================================================================
+//
+// A_GhostOff
+//
+//==========================================================================
+
+/*
+void A_GhostOff(mobj_t *actor)
+{
+ actor->flags &= ~MF_SHADOW;
+}
+*/
+
+//==========================================================================
+//
+// A_HideThing
+//
+//==========================================================================
+
+void A_HideThing(mobj_t *actor)
+{
+ actor->flags2 |= MF2_DONTDRAW;
+}
+
+//==========================================================================
+//
+// A_UnHideThing
+//
+//==========================================================================
+
+void A_UnHideThing(mobj_t *actor)
+{
+ actor->flags2 &= ~MF2_DONTDRAW;
+}
+
+//==========================================================================
+//
+// A_SetShootable
+//
+//==========================================================================
+
+void A_SetShootable(mobj_t *actor)
+{
+ actor->flags2 &= ~MF2_NONSHOOTABLE;
+ actor->flags |= MF_SHOOTABLE;
+}
+
+//==========================================================================
+//
+// A_UnSetShootable
+//
+//==========================================================================
+
+void A_UnSetShootable(mobj_t *actor)
+{
+ actor->flags2 |= MF2_NONSHOOTABLE;
+ actor->flags &= ~MF_SHOOTABLE;
+}
+
+//==========================================================================
+//
+// A_SetAltShadow
+//
+//==========================================================================
+
+void A_SetAltShadow(mobj_t *actor)
+{
+ actor->flags &= ~MF_SHADOW;
+ actor->flags |= MF_ALTSHADOW;
+}
+
+//==========================================================================
+//
+// A_UnSetAltShadow
+//
+//==========================================================================
+
+/*
+void A_UnSetAltShadow(mobj_t *actor)
+{
+ actor->flags &= ~MF_ALTSHADOW;
+}
+*/
+
+//--------------------------------------------------------------------------
+//
+// Sound Action Routines
+//
+//--------------------------------------------------------------------------
+
+//==========================================================================
+//
+// A_ContMobjSound
+//
+//==========================================================================
+
+void A_ContMobjSound(mobj_t *actor)
+{
+ switch (actor->type)
+ {
+ case MT_SERPENTFX:
+ S_StartSound(actor, SFX_SERPENTFX_CONTINUOUS);
+ break;
+ case MT_HAMMER_MISSILE:
+ S_StartSound(actor, SFX_FIGHTER_HAMMER_CONTINUOUS);
+ break;
+ case MT_QUAKE_FOCUS:
+ S_StartSound(actor, SFX_EARTHQUAKE);
+ break;
+ default:
+ break;
+ }
+}
+
+//==========================================================================
+//
+// PROC A_ESound
+//
+//==========================================================================
+
+void A_ESound(mobj_t *mo)
+{
+ int sound;
+
+ switch (mo->type)
+ {
+ case MT_SOUNDWIND:
+ sound = SFX_WIND;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ S_StartSound(mo, sound);
+}
+
+
+//==========================================================================
+// Summon Minotaur -- see p_enemy for variable descriptions
+//==========================================================================
+
+void A_Summon(mobj_t *actor)
+{
+ mobj_t *mo;
+ mobj_t *master;
+ int summontime;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_MINOTAUR);
+ if (mo)
+ {
+ if (P_TestMobjLocation(mo) == false || !actor->special1)
+ { // Didn't fit - change back to artifact
+ P_SetMobjState(mo, S_NULL);
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SUMMONMAULATOR);
+ if (mo)
+ mo->flags2 |= MF2_DROPPED;
+ return;
+ }
+
+ /* record the time in little endian format */
+ summontime = LONG(leveltime);
+ memcpy((void *)mo->args, &summontime, sizeof(int));
+ master = (mobj_t *)actor->special1;
+ if (master->flags & MF_CORPSE)
+ { // Master dead
+ mo->special1 = 0; // No master
+ }
+ else
+ {
+ mo->special1 = actor->special1; // Pointer to master (mobj_t *)
+ P_GivePower(master->player, pw_minotaur);
+ }
+
+ // Make smoke puff
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKE);
+ S_StartSound(actor, SFX_MAULATOR_ACTIVE);
+ }
+}
+
+
+//==========================================================================
+// Fog Variables:
+//
+// args[0] Speed (0..10) of fog
+// args[1] Angle of spread (0..128)
+// args[2] Frequency of spawn (1..10)
+// args[3] Lifetime countdown
+// args[4] Boolean: fog moving?
+// special1 Internal: Counter for spawn frequency
+// special2 Internal: Index into floatbob table
+//
+//==========================================================================
+
+void A_FogSpawn(mobj_t *actor)
+{
+ mobj_t *mo = NULL;
+ angle_t delta;
+
+ if (actor->special1-- > 0)
+ return;
+
+ actor->special1 = actor->args[2]; // Reset frequency count
+
+ switch (P_Random() % 3)
+ {
+ case 0:
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHS);
+ break;
+ case 1:
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHM);
+ break;
+ case 2:
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHL);
+ break;
+ }
+
+ if (mo)
+ {
+ delta = actor->args[1];
+ if (delta == 0)
+ delta = 1;
+ mo->angle = actor->angle + (((P_Random()%delta)-(delta>>1))<<24);
+ mo->target = actor;
+ if (actor->args[0] < 1)
+ actor->args[0] = 1;
+ mo->args[0] = (P_Random() % (actor->args[0])) + 1; // Random speed
+ mo->args[3] = actor->args[3]; // Set lifetime
+ mo->args[4] = 1; // Set to moving
+ mo->special2 = P_Random() & 63;
+ }
+}
+
+
+void A_FogMove(mobj_t *actor)
+{
+ int speed = actor->args[0]<<FRACBITS;
+ angle_t angle;
+ int weaveindex;
+
+ if (!(actor->args[4]))
+ return;
+
+ if (actor->args[3]-- <= 0)
+ {
+ P_SetMobjStateNF(actor, actor->info->deathstate);
+ return;
+ }
+
+ if ((actor->args[3] % 4) == 0)
+ {
+ weaveindex = actor->special2;
+ actor->z += FloatBobOffsets[weaveindex]>>1;
+ actor->special2 = (weaveindex + 1) & 63;
+ }
+
+ angle = actor->angle>>ANGLETOFINESHIFT;
+ actor->momx = FixedMul(speed, finecosine[angle]);
+ actor->momy = FixedMul(speed, finesine[angle]);
+}
+
+//===========================================================================
+//
+// A_PoisonBagInit
+//
+//===========================================================================
+
+void A_PoisonBagInit(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z+28*FRACUNIT, MT_POISONCLOUD);
+ if (!mo)
+ {
+ return;
+ }
+ mo->momx = 1; // missile objects must move to impact other objects
+ mo->special1 = 24 + (P_Random() & 7);
+ mo->special2 = 0;
+ mo->target = actor->target;
+ mo->radius = 20 * FRACUNIT;
+ mo->height = 30 * FRACUNIT;
+ mo->flags &= ~MF_NOCLIP;
+}
+
+//===========================================================================
+//
+// A_PoisonBagCheck
+//
+//===========================================================================
+
+void A_PoisonBagCheck(mobj_t *actor)
+{
+ if (!--actor->special1)
+ {
+ P_SetMobjState(actor, S_POISONCLOUD_X1);
+ }
+ else
+ {
+ return;
+ }
+}
+
+//===========================================================================
+//
+// A_PoisonBagDamage
+//
+//===========================================================================
+
+void A_PoisonBagDamage(mobj_t *actor)
+{
+ int bobIndex;
+
+ extern void A_Explode(mobj_t *actor);
+
+ A_Explode(actor);
+
+ bobIndex = actor->special2;
+ actor->z += FloatBobOffsets[bobIndex]>>4;
+ actor->special2 = (bobIndex + 1) & 63;
+}
+
+//===========================================================================
+//
+// A_PoisonShroom
+//
+//===========================================================================
+
+void A_PoisonShroom(mobj_t *actor)
+{
+ actor->tics = 128+(P_Random()<<1);
+}
+
+//===========================================================================
+//
+// A_CheckThrowBomb
+//
+//===========================================================================
+
+void A_CheckThrowBomb(mobj_t *actor)
+{
+ if (abs(actor->momx) < 1.5*FRACUNIT && abs(actor->momy) < 1.5*FRACUNIT
+ && actor->momz < 2*FRACUNIT
+ && actor->state == &states[S_THROWINGBOMB6])
+ {
+ P_SetMobjState(actor, S_THROWINGBOMB7);
+ actor->z = actor->floorz;
+ actor->momz = 0;
+ actor->flags2 &= ~MF2_FLOORBOUNCE;
+ actor->flags &= ~MF_MISSILE;
+ }
+ if (!--actor->health)
+ {
+ P_SetMobjState(actor, actor->info->deathstate);
+ }
+}
+
+//===========================================================================
+// Quake variables
+//
+// args[0] Intensity on richter scale (2..9)
+// args[1] Duration in tics
+// args[2] Radius for damage
+// args[3] Radius for tremor
+// args[4] TID of map thing for focus of quake
+//
+//===========================================================================
+
+//===========================================================================
+//
+// A_LocalQuake
+//
+//===========================================================================
+
+boolean A_LocalQuake(byte *args, mobj_t *actor)
+{
+ mobj_t *focus, *target;
+ int lastfound = 0;
+ int success = false;
+
+ (void)actor; // suppress warning
+
+ // Find all quake foci
+ do
+ {
+ target = P_FindMobjFromTID(args[4], &lastfound);
+ if (target)
+ {
+ focus = P_SpawnMobj(target->x,
+ target->y,
+ target->z, MT_QUAKE_FOCUS);
+ if (focus)
+ {
+ focus->args[0] = args[0];
+ focus->args[1] = args[1]>>1; // decremented every 2 tics
+ focus->args[2] = args[2];
+ focus->args[3] = args[3];
+ focus->args[4] = args[4];
+ success = true;
+ }
+ }
+ } while (target != NULL);
+
+ return success;
+}
+
+
+//===========================================================================
+//
+// A_Quake
+//
+//===========================================================================
+int localQuakeHappening[MAXPLAYERS];
+
+void A_Quake(mobj_t *actor)
+{
+ angle_t an;
+ player_t *player;
+ mobj_t *victim;
+ int richters = actor->args[0];
+ int playnum;
+ fixed_t dist;
+
+ if (actor->args[1]-- > 0)
+ {
+ for (playnum = 0; playnum < MAXPLAYERS; playnum++)
+ {
+ player = &players[playnum];
+ if (!playeringame[playnum])
+ continue;
+
+ victim = player->mo;
+ dist = P_AproxDistance(actor->x - victim->x,
+ actor->y - victim->y) >> (FRACBITS+6);
+ // Tested in tile units (64 pixels)
+ if (dist < actor->args[3]) // In tremor radius
+ {
+ localQuakeHappening[playnum] = richters;
+ }
+ // Check if in damage radius
+ if ((dist < actor->args[2]) &&
+ (victim->z <= victim->floorz))
+ {
+ if (P_Random() < 50)
+ {
+ P_DamageMobj(victim, NULL, NULL, HITDICE(1));
+ }
+ // Thrust player around
+ an = victim->angle + ANGLE_1*P_Random();
+ P_ThrustMobj(victim,an,richters<<(FRACBITS-1));
+ }
+ }
+ }
+ else
+ {
+ for (playnum = 0; playnum < MAXPLAYERS; playnum++)
+ {
+ localQuakeHappening[playnum] = false;
+ }
+ P_SetMobjState(actor, S_NULL);
+ }
+}
+
+
+//===========================================================================
+//
+// Teleport other stuff
+//
+//===========================================================================
+
+#define TELEPORT_LIFE 1
+
+void A_TeloSpawnA(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX2);
+ if (mo)
+ {
+ mo->special1 = TELEPORT_LIFE; // Lifetime countdown
+ mo->angle = actor->angle;
+ mo->target = actor->target;
+ mo->momx = actor->momx>>1;
+ mo->momy = actor->momy>>1;
+ mo->momz = actor->momz>>1;
+ }
+}
+
+void A_TeloSpawnB(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX3);
+ if (mo)
+ {
+ mo->special1 = TELEPORT_LIFE; // Lifetime countdown
+ mo->angle = actor->angle;
+ mo->target = actor->target;
+ mo->momx = actor->momx>>1;
+ mo->momy = actor->momy>>1;
+ mo->momz = actor->momz>>1;
+ }
+}
+
+void A_TeloSpawnC(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX4);
+ if (mo)
+ {
+ mo->special1 = TELEPORT_LIFE; // Lifetime countdown
+ mo->angle = actor->angle;
+ mo->target = actor->target;
+ mo->momx = actor->momx>>1;
+ mo->momy = actor->momy>>1;
+ mo->momz = actor->momz>>1;
+ }
+}
+
+void A_TeloSpawnD(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX5);
+ if (mo)
+ {
+ mo->special1 = TELEPORT_LIFE; // Lifetime countdown
+ mo->angle = actor->angle;
+ mo->target = actor->target;
+ mo->momx = actor->momx>>1;
+ mo->momy = actor->momy>>1;
+ mo->momz = actor->momz>>1;
+ }
+}
+
+void A_CheckTeleRing(mobj_t *actor)
+{
+ if (actor->special1-- <= 0)
+ {
+ P_SetMobjState(actor, actor->info->deathstate);
+ }
+}
+
+
+// Dirt stuff
+
+void P_SpawnDirt(mobj_t *actor, fixed_t radius)
+{
+ fixed_t x,y,z;
+ int dtype = 0;
+ mobj_t *mo;
+ angle_t angle;
+
+ angle = P_Random()<<5; // <<24 >>19
+ x = actor->x + FixedMul(radius,finecosine[angle]);
+ y = actor->y + FixedMul(radius,finesine[angle]);
+// x = actor->x + ((P_Random()-P_Random())%radius)<<FRACBITS;
+// y = actor->y + ((P_Random()-P_Random()<<FRACBITS)%radius);
+ z = actor->z + (P_Random()<<9) + FRACUNIT;
+ switch (P_Random() % 6)
+ {
+ case 0:
+ dtype = MT_DIRT1;
+ break;
+ case 1:
+ dtype = MT_DIRT2;
+ break;
+ case 2:
+ dtype = MT_DIRT3;
+ break;
+ case 3:
+ dtype = MT_DIRT4;
+ break;
+ case 4:
+ dtype = MT_DIRT5;
+ break;
+ case 5:
+ dtype = MT_DIRT6;
+ break;
+ }
+ mo = P_SpawnMobj(x, y, z, dtype);
+ if (mo)
+ {
+ mo->momz = P_Random()<<10;
+ }
+}
+
+
+//===========================================================================
+//
+// Thrust floor stuff
+//
+// Thrust Spike Variables
+// special1 pointer to dirt clump mobj
+// special2 speed of raise
+// args[0] 0 = lowered, 1 = raised
+// args[1] 0 = normal, 1 = bloody
+//===========================================================================
+
+void A_ThrustInitUp(mobj_t *actor)
+{
+ actor->special2 = 5; // Raise speed
+ actor->args[0] = 1; // Mark as up
+ actor->floorclip = 0;
+ actor->flags = MF_SOLID;
+ actor->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP;
+ actor->special1 = 0L;
+}
+
+void A_ThrustInitDn(mobj_t *actor)
+{
+ mobj_t *mo;
+ actor->special2 = 5; // Raise speed
+ actor->args[0] = 0; // Mark as down
+ actor->floorclip = actor->info->height;
+ actor->flags = 0;
+ actor->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP|MF2_DONTDRAW;
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_DIRTCLUMP);
+ actor->special1 = (intptr_t)mo;
+}
+
+void A_ThrustRaise(mobj_t *actor)
+{
+ if (A_RaiseMobj(actor))
+ { // Reached it's target height
+ actor->args[0] = 1;
+ if (actor->args[1])
+ P_SetMobjStateNF(actor, S_BTHRUSTINIT2_1);
+ else
+ P_SetMobjStateNF(actor, S_THRUSTINIT2_1);
+ }
+
+ // Lose the dirt clump
+ if ((actor->floorclip < actor->height) && actor->special1)
+ {
+ P_RemoveMobj((mobj_t *)actor->special1);
+ actor->special1 = 0;
+ }
+
+ // Spawn some dirt
+ if (P_Random() < 40)
+ P_SpawnDirt(actor, actor->radius);
+ actor->special2++; // Increase raise speed
+}
+
+void A_ThrustLower(mobj_t *actor)
+{
+ if (A_SinkMobj(actor))
+ {
+ actor->args[0] = 0;
+ if (actor->args[1])
+ P_SetMobjStateNF(actor, S_BTHRUSTINIT1_1);
+ else
+ P_SetMobjStateNF(actor, S_THRUSTINIT1_1);
+ }
+}
+
+void A_ThrustBlock(mobj_t *actor)
+{
+ actor->flags |= MF_SOLID;
+}
+
+void A_ThrustImpale(mobj_t *actor)
+{
+ // Impale all shootables in radius
+ PIT_ThrustSpike(actor);
+}
+
+//===========================================================================
+//
+// A_SoAExplode - Suit of Armor Explode
+//
+//===========================================================================
+
+void A_SoAExplode(mobj_t *actor)
+{
+ mobj_t *mo;
+ int i;
+
+ for (i = 0; i < 10; i++)
+ {
+ mo = P_SpawnMobj(actor->x+((P_Random()-128)<<12),
+ actor->y + ((P_Random()-128)<<12),
+ actor->z + (P_Random()*actor->height/256), MT_ZARMORCHUNK);
+ P_SetMobjState(mo, mo->info->spawnstate + i);
+ if (mo)
+ {
+ mo->momz = ((P_Random()&7)+5)*FRACUNIT;
+ mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
+ mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
+ }
+ }
+ if (actor->args[0])
+ { // Spawn an item
+ if (!nomonsters ||
+ !(mobjinfo[TranslateThingType[actor->args[0]]].flags & MF_COUNTKILL))
+ { // Only spawn monsters if not -nomonsters
+ P_SpawnMobj(actor->x, actor->y, actor->z,
+ TranslateThingType[actor->args[0]]);
+ }
+ }
+ S_StartSound(mo, SFX_SUITOFARMOR_BREAK);
+ P_RemoveMobj(actor);
+}
+
+//===========================================================================
+//
+// A_BellReset1
+//
+//===========================================================================
+
+void A_BellReset1(mobj_t *actor)
+{
+ actor->flags |= MF_NOGRAVITY;
+ actor->height <<= 2;
+}
+
+//===========================================================================
+//
+// A_BellReset2
+//
+//===========================================================================
+
+void A_BellReset2(mobj_t *actor)
+{
+ actor->flags |= MF_SHOOTABLE;
+ actor->flags &= ~MF_CORPSE;
+ actor->health = 5;
+}
+
+
+//===========================================================================
+//
+// A_FlameCheck
+//
+//===========================================================================
+
+void A_FlameCheck(mobj_t *actor)
+{
+ if (!actor->args[0]--) // Called every 8 tics
+ {
+ P_SetMobjState(actor, S_NULL);
+ }
+}
+
+
+//===========================================================================
+// Bat Spawner Variables
+// special1 frequency counter
+// special2
+// args[0] frequency of spawn (1=fastest, 10=slowest)
+// args[1] spread angle (0..255)
+// args[2]
+// args[3] duration of bats (in octics)
+// args[4] turn amount per move (in degrees)
+//
+// Bat Variables
+// special2 lifetime counter
+// args[4] turn amount per move (in degrees)
+//===========================================================================
+
+void A_BatSpawnInit(mobj_t *actor)
+{
+ actor->special1 = 0; // Frequency count
+}
+
+void A_BatSpawn(mobj_t *actor)
+{
+ mobj_t *mo;
+ int delta;
+ angle_t angle;
+
+ // Countdown until next spawn
+ if (actor->special1-- > 0)
+ return;
+ actor->special1 = actor->args[0]; // Reset frequency count
+
+ delta = actor->args[1];
+ if (delta == 0)
+ delta = 1;
+ angle = actor->angle + (((P_Random()%delta)-(delta>>1))<<24);
+ mo = P_SpawnMissileAngle(actor, MT_BAT, angle, 0);
+ if (mo)
+ {
+ mo->args[0] = P_Random() & 63; // floatbob index
+ mo->args[4] = actor->args[4]; // turn degrees
+ mo->special2 = actor->args[3]<<3; // Set lifetime
+ mo->target = actor;
+ }
+}
+
+
+void A_BatMove(mobj_t *actor)
+{
+ angle_t newangle;
+ fixed_t speed;
+
+ if (actor->special2 < 0)
+ {
+ P_SetMobjState(actor, actor->info->deathstate);
+ }
+ actor->special2 -= 2; // Called every 2 tics
+
+ if (P_Random() < 128)
+ {
+ newangle = actor->angle + ANGLE_1*actor->args[4];
+ }
+ else
+ {
+ newangle = actor->angle - ANGLE_1*actor->args[4];
+ }
+
+ // Adjust momentum vector to new direction
+ newangle >>= ANGLETOFINESHIFT;
+ speed = FixedMul(actor->info->speed, P_Random()<<10);
+ actor->momx = FixedMul(speed, finecosine[newangle]);
+ actor->momy = FixedMul(speed, finesine[newangle]);
+
+ if (P_Random() < 15)
+ S_StartSound(actor, SFX_BAT_SCREAM);
+
+ // Handle Z movement
+ actor->z = actor->target->z + 2*FloatBobOffsets[actor->args[0]];
+ actor->args[0] = (actor->args[0] + 3) & 63;
+}
+
+//===========================================================================
+//
+// A_TreeDeath
+//
+//===========================================================================
+
+void A_TreeDeath(mobj_t *actor)
+{
+ if (!(actor->flags2 & MF2_FIREDAMAGE))
+ {
+ actor->height <<= 2;
+ actor->flags |= MF_SHOOTABLE;
+ actor->flags &= ~(MF_CORPSE + MF_DROPOFF);
+ actor->health = 35;
+ return;
+ }
+ else
+ {
+ P_SetMobjState(actor, actor->info->meleestate);
+ }
+}
+
+//===========================================================================
+//
+// A_NoGravity
+//
+//===========================================================================
+
+void A_NoGravity(mobj_t *actor)
+{
+ actor->flags |= MF_NOGRAVITY;
+}
+
--- /dev/null
+++ b/am_data.h
@@ -1,0 +1,111 @@
+
+//**************************************************************************
+//**
+//** am_data.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __AMDATA_H__
+#define __AMDATA_H__
+
+/* a line drawing of the player pointing right, starting from the middle. */
+
+#define R ((8 * PLAYERRADIUS) / 7)
+
+mline_t player_arrow[] =
+{
+ { { -R+R/4, 0 }, { 0, 0} }, // center line.
+ { { -R+R/4, R/8 }, { R, 0} }, // blade
+ { { -R+R/4, -R/8 }, { R, 0 } },
+ { { -R+R/4, -R/4 }, { -R+R/4, R/4 } }, // crosspiece
+ { { -R+R/8, -R/4 }, { -R+R/8, R/4 } },
+ { { -R+R/8, -R/4 }, { -R+R/4, -R/4} }, // crosspiece connectors
+ { { -R+R/8, R/4 }, { -R+R/4, R/4} },
+ { { -R-R/4, R/8 }, { -R-R/4, -R/8 } }, // pommel
+ { { -R-R/4, R/8 }, { -R+R/8, R/8 } },
+ { { -R-R/4, -R/8}, { -R+R/8, -R/8 } }
+};
+
+/*
+mline_t keysquare[] =
+{
+ { { 0, 0 }, { R/4, -R/2 } },
+ { { R/4, -R/2 }, { R/2, -R/2 } },
+ { { R/2, -R/2 }, { R/2, R/2 } },
+ { { R/2, R/2 }, { R/4, R/2 } },
+ { { R/4, R/2 }, { 0, 0 } }, // handle part type thing
+ { { 0, 0 }, { -R, 0 } }, // stem
+ { { -R, 0 }, { -R, -R/2 } }, // end lockpick part
+ { { -3*R/4, 0 }, { -3*R/4, -R/4 } }
+};
+*/
+
+/*
+mline_t player_arrow[] =
+{
+ { { -R+R/8, 0 }, { R, 0 } }, // -----
+ { { R, 0 }, { R-R/2, R/4 } }, // ----->
+ { { R, 0 }, { R-R/2, -R/4 } },
+ { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
+ { { -R+R/8, 0 }, { -R-R/8, -R/4 } },
+ { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
+ { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
+};
+*/
+#undef R
+
+#define NUMPLYRLINES (sizeof(player_arrow) / sizeof(mline_t))
+#define NUMKEYSQUARELINES (sizeof(keysquare) / sizeof(mline_t))
+
+/*
+#define R ((8 * PLAYERRADIUS) / 7)
+mline_t cheat_player_arrow[] =
+{
+ { { -R+R/8, 0 }, { R, 0 } }, // -----
+ { { R, 0 }, { R-R/2, R/6 } }, // ----->
+ { { R, 0 }, { R-R/2, -R/6 } },
+ { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
+ { { -R+R/8, 0 }, { -R-R/8, -R/6 } },
+ { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
+ { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
+ { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
+ { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
+ { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
+ { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
+ { { -R/6, -R/6 }, { 0, -R/6 } },
+ { { 0, -R/6 }, { 0, R/4 } },
+ { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
+ { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
+ { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
+};
+#undef R
+#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow) / sizeof(mline_t))
+*/
+
+/*
+#define R (FRACUNIT)
+mline_t triangle_guy[] =
+{
+ { { -.867*R, -.5*R }, { .867*R, -.5*R } },
+ { { .867*R, -.5*R } , { 0, R } },
+ { { 0, R }, { -.867*R, -.5*R } }
+};
+#undef R
+#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy) / sizeof(mline_t))
+*/
+
+#define R (FRACUNIT)
+mline_t thintriangle_guy[] =
+{
+ { { -.5*R, -.7*R }, { R, 0 } },
+ { { R, 0 }, { -.5*R, .7*R } },
+ { { -.5*R, .7*R }, { -.5*R, -.7*R } }
+};
+#undef R
+#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy) / sizeof(mline_t))
+
+#endif /* __AMDATA_H__ */
+
--- /dev/null
+++ b/am_map.c
@@ -1,0 +1,1562 @@
+
+//**************************************************************************
+//**
+//** am_map.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "am_map.h"
+#include "am_data.h"
+
+#ifdef RENDER3D
+#include "ogl_def.h"
+
+#define MTOFX(x) FixedMul((x),scale_mtof)
+
+#define CXMTOFX(x) ((f_x<<16) + MTOFX((x)-m_x))
+#define CYMTOFX(y) ((f_y<<16) + ((f_h<<16) - MTOFX((y)-m_y)))
+
+static int maplumpnum;
+#endif /* RENDER3D */
+
+#define NUMALIAS 3 /* Number of antialiased lines. */
+
+int cheating = 0;
+static int grid = 0;
+
+static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
+
+boolean automapactive = false;
+static int finit_width = SCREENWIDTH;
+static int finit_height = SCREENHEIGHT-SBARHEIGHT-3;
+static int f_x, f_y; // location of window on screen
+static int f_w, f_h; // size of window on screen
+static int lightlev; // used for funky strobing effect
+static int amclock;
+
+static mpoint_t m_paninc; // how far the window pans each tic (map coords)
+static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords)
+static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords)
+
+static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords)
+static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords)
+
+// width/height of window on map (map coords)
+static fixed_t m_w, m_h;
+static fixed_t min_x, min_y; // based on level size
+static fixed_t max_x, max_y; // based on level size
+static fixed_t max_w, max_h; // max_x-min_x, max_y-min_y
+static fixed_t min_w, min_h; // based on player size
+static fixed_t min_scale_mtof; // used to tell when to stop zooming out
+static fixed_t max_scale_mtof; // used to tell when to stop zooming in
+
+// old stuff for recovery later
+static fixed_t old_m_w, old_m_h;
+static fixed_t old_m_x, old_m_y;
+
+// old location used by the Follower routine
+static mpoint_t f_oldloc;
+
+// used by MTOF to scale from map-to-frame-buffer coords
+static fixed_t scale_mtof = INITSCALEMTOF;
+// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
+static fixed_t scale_ftom;
+
+static player_t *plr; // the player represented by an arrow
+static vertex_t oldplr;
+
+static int followplayer = 1; // specifies whether to follow the player around
+
+static char cheat_kills[] = { 'k', 'i', 'l', 'l', 's' };
+static boolean ShowKills = 0;
+static unsigned ShowKillsCount = 0;
+
+extern boolean viewactive;
+
+#ifndef RENDER3D
+static byte antialias[NUMALIAS][8] =
+{
+ { 83, 84, 85, 86, 87, 88, 89, 90 },
+ { 96, 96, 95, 94, 93, 92, 91, 90 },
+ { 107, 108, 109, 110, 111, 112, 89, 90 }
+};
+
+/*
+static byte *aliasmax[NUMALIAS] =
+{
+ &antialias[0][7],
+ &antialias[1][7],
+ &antialias[2][7]
+};
+*/
+
+static byte *maplump; // pointer to the raw data for the automap background.
+
+static byte *fb; // pseudo-frame buffer
+#endif /* RENDER3D */
+
+static short mapystart = 0; // y-value for the start of the map bitmap...used in
+ //the parallax stuff.
+static short mapxstart = 0; //x-value for the bitmap.
+
+// Functions
+
+#ifndef RENDER3D
+static void DrawWuLine (int X0, int Y0, int X1, int Y1, byte *BaseColor,
+ int NumLevels, unsigned short IntensityBits);
+#endif /* RENDER3D */
+
+static void AM_DrawDeathmatchStats(void);
+static void DrawWorldTimer(void);
+
+// Calculates the slope and slope according to the x-axis of a line
+// segment in map coordinates (with the upright y-axis n' all) so
+// that it can be used with the brain-dead drawing stuff.
+
+// Ripped out for Heretic
+/*
+static void AM_getIslope(mline_t *ml, islope_t *is)
+{
+ int dx, dy;
+
+ dy = ml->a.y - ml->b.y;
+ dx = ml->b.x - ml->a.x;
+ if (!dy)
+ is->islp = (dx < 0 ? -H2MAXINT : H2MAXINT);
+ else
+ is->islp = FixedDiv(dx, dy);
+ if (!dx)
+ is->slp = (dy < 0 ? -H2MAXINT : H2MAXINT);
+ else
+ is->slp = FixedDiv(dy, dx);
+}
+*/
+
+static void AM_activateNewScale(void)
+{
+ m_x += m_w/2;
+ m_y += m_h/2;
+ m_w = FTOM(f_w);
+ m_h = FTOM(f_h);
+ m_x -= m_w/2;
+ m_y -= m_h/2;
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+}
+
+static void AM_saveScaleAndLoc(void)
+{
+ old_m_x = m_x;
+ old_m_y = m_y;
+ old_m_w = m_w;
+ old_m_h = m_h;
+}
+
+static void AM_restoreScaleAndLoc(void)
+{
+ m_w = old_m_w;
+ m_h = old_m_h;
+ if (!followplayer)
+ {
+ m_x = old_m_x;
+ m_y = old_m_y;
+ }
+ else
+ {
+ m_x = plr->mo->x - m_w/2;
+ m_y = plr->mo->y - m_h/2;
+ }
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+
+ // Change the scaling multipliers
+ scale_mtof = FixedDiv(f_w<<FRACBITS, m_w);
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+}
+
+static void AM_findMinMaxBoundaries(void)
+{
+ int i;
+ fixed_t a, b;
+
+ min_x = min_y = H2MAXINT;
+ max_x = max_y = -H2MAXINT;
+ for (i = 0; i < numvertexes; i++)
+ {
+ if (vertexes[i].x < min_x)
+ min_x = vertexes[i].x;
+ else if (vertexes[i].x > max_x)
+ max_x = vertexes[i].x;
+ if (vertexes[i].y < min_y)
+ min_y = vertexes[i].y;
+ else if (vertexes[i].y > max_y)
+ max_y = vertexes[i].y;
+ }
+ max_w = max_x - min_x;
+ max_h = max_y - min_y;
+ min_w = 2*PLAYERRADIUS;
+ min_h = 2*PLAYERRADIUS;
+
+ a = FixedDiv(f_w<<FRACBITS, max_w);
+ b = FixedDiv(f_h<<FRACBITS, max_h);
+ min_scale_mtof = a < b ? a : b;
+
+ max_scale_mtof = FixedDiv(f_h<<FRACBITS, 2*PLAYERRADIUS);
+}
+
+static void AM_changeWindowLoc(void)
+{
+ if (m_paninc.x || m_paninc.y)
+ {
+ followplayer = 0;
+ f_oldloc.x = H2MAXINT;
+ }
+
+ m_x += m_paninc.x;
+ m_y += m_paninc.y;
+
+ if (m_x + m_w/2 > max_x)
+ {
+ m_x = max_x - m_w/2;
+ m_paninc.x = 0;
+ }
+ else if (m_x + m_w/2 < min_x)
+ {
+ m_x = min_x - m_w/2;
+ m_paninc.x = 0;
+ }
+ if (m_y + m_h/2 > max_y)
+ {
+ m_y = max_y - m_h/2;
+ m_paninc.y = 0;
+ }
+ else if (m_y + m_h/2 < min_y)
+ {
+ m_y = min_y - m_h/2;
+ m_paninc.y = 0;
+ }
+ /*
+ mapxstart += MTOF(m_paninc.x+FRACUNIT/2);
+ mapystart -= MTOF(m_paninc.y+FRACUNIT/2);
+ if (mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ if (mapxstart < 0)
+ mapxstart += finit_width;
+ if (mapystart >= finit_height)
+ mapystart -= finit_height;
+ if (mapystart < 0)
+ mapystart += finit_height;
+ */
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+}
+
+static void AM_initVariables(void)
+{
+ int pnum;
+
+ automapactive = true;
+#ifndef RENDER3D
+ fb = screen;
+#endif
+
+ f_oldloc.x = H2MAXINT;
+ amclock = 0;
+ lightlev = 0;
+
+ m_paninc.x = m_paninc.y = 0;
+ ftom_zoommul = FRACUNIT;
+ mtof_zoommul = FRACUNIT;
+
+ m_w = FTOM(f_w);
+ m_h = FTOM(f_h);
+
+ // find player to center on initially
+ if (!playeringame[pnum = consoleplayer])
+ {
+ for (pnum = 0; pnum < MAXPLAYERS; pnum++)
+ {
+ if (playeringame[pnum])
+ break;
+ }
+ }
+ plr = &players[pnum];
+ oldplr.x = plr->mo->x;
+ oldplr.y = plr->mo->y;
+ m_x = plr->mo->x - m_w/2;
+ m_y = plr->mo->y - m_h/2;
+ AM_changeWindowLoc();
+
+ // for saving & restoring
+ old_m_x = m_x;
+ old_m_y = m_y;
+ old_m_w = m_w;
+ old_m_h = m_h;
+}
+
+static void AM_loadPics(void)
+{
+#ifdef RENDER3D
+ maplumpnum = W_GetNumForName("AUTOPAGE");
+#else
+ maplump = (byte *) W_CacheLumpName("AUTOPAGE", PU_STATIC);
+#endif
+}
+
+// should be called at the start of every level
+// right now, i figure it out myself
+
+static void AM_LevelInit(void)
+{
+ leveljuststarted = 0;
+
+ f_x = f_y = 0;
+ f_w = finit_width;
+ f_h = finit_height;
+ mapxstart = mapystart = 0;
+
+ AM_findMinMaxBoundaries();
+ scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT));
+ if (scale_mtof > max_scale_mtof)
+ scale_mtof = min_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+}
+
+static boolean stopped = true;
+
+void AM_Stop (void)
+{
+ automapactive = false;
+ stopped = true;
+ BorderNeedRefresh = true;
+}
+
+static void AM_Start (void)
+{
+ static int lastlevel = -1, lastepisode = -1;
+
+ if (!stopped)
+ AM_Stop();
+ stopped = false;
+ if (gamestate != GS_LEVEL)
+ {
+ return; // don't show automap if we aren't in a game!
+ }
+ if (lastlevel != gamemap || lastepisode != gameepisode)
+ {
+ AM_LevelInit();
+ lastlevel = gamemap;
+ lastepisode = gameepisode;
+ }
+ AM_initVariables();
+ AM_loadPics();
+}
+
+// set the window scale to the maximum size
+
+static void AM_minOutWindowScale(void)
+{
+ scale_mtof = min_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+ AM_activateNewScale();
+}
+
+// set the window scale to the minimum size
+
+static void AM_maxOutWindowScale(void)
+{
+ scale_mtof = max_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+ AM_activateNewScale();
+}
+
+boolean AM_Responder (event_t *ev)
+{
+ int rc;
+ static int bigstate = 0;
+
+ rc = false;
+ if (!automapactive)
+ {
+ if (ev->type == ev_keydown && ev->data1 == AM_STARTKEY
+ && gamestate == GS_LEVEL)
+ {
+ AM_Start ();
+ SB_state = -1;
+ viewactive = false;
+ rc = true;
+ }
+ }
+ else if (ev->type == ev_keydown)
+ {
+ rc = true;
+ switch (ev->data1)
+ {
+ case AM_PANRIGHTKEY: // pan right
+ if (!followplayer)
+ m_paninc.x = FTOM(F_PANINC);
+ else
+ rc = false;
+ break;
+ case AM_PANLEFTKEY: // pan left
+ if (!followplayer)
+ m_paninc.x = -FTOM(F_PANINC);
+ else
+ rc = false;
+ break;
+ case AM_PANUPKEY: // pan up
+ if (!followplayer)
+ m_paninc.y = FTOM(F_PANINC);
+ else
+ rc = false;
+ break;
+ case AM_PANDOWNKEY: // pan down
+ if (!followplayer)
+ m_paninc.y = -FTOM(F_PANINC);
+ else
+ rc = false;
+ break;
+ case AM_ZOOMOUTKEY: // zoom out
+ mtof_zoommul = M_ZOOMOUT;
+ ftom_zoommul = M_ZOOMIN;
+ break;
+ case AM_ZOOMINKEY: // zoom in
+ mtof_zoommul = M_ZOOMIN;
+ ftom_zoommul = M_ZOOMOUT;
+ break;
+ case AM_ENDKEY:
+ bigstate = 0;
+ viewactive = true;
+ AM_Stop ();
+ SB_state = -1;
+ break;
+ case AM_GOBIGKEY:
+ bigstate = !bigstate;
+ if (bigstate)
+ {
+ AM_saveScaleAndLoc();
+ AM_minOutWindowScale();
+ }
+ else AM_restoreScaleAndLoc();
+ break;
+ case AM_FOLLOWKEY:
+ followplayer = !followplayer;
+ f_oldloc.x = H2MAXINT;
+ P_SetMessage(plr,
+ followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF, true);
+ break;
+ default:
+ rc = false;
+ }
+
+ if (cheat_kills[ShowKillsCount] == ev->data1 && netgame && deathmatch)
+ {
+ ShowKillsCount++;
+ if (ShowKillsCount == 5)
+ {
+ ShowKillsCount = 0;
+ rc = false;
+ ShowKills ^= 1;
+ }
+ }
+ else
+ {
+ ShowKillsCount = 0;
+ }
+ }
+ else if (ev->type == ev_keyup)
+ {
+ rc = false;
+ switch (ev->data1)
+ {
+ case AM_PANRIGHTKEY:
+ if (!followplayer)
+ m_paninc.x = 0;
+ break;
+ case AM_PANLEFTKEY:
+ if (!followplayer)
+ m_paninc.x = 0;
+ break;
+ case AM_PANUPKEY:
+ if (!followplayer)
+ m_paninc.y = 0;
+ break;
+ case AM_PANDOWNKEY:
+ if (!followplayer)
+ m_paninc.y = 0;
+ break;
+ case AM_ZOOMOUTKEY:
+ case AM_ZOOMINKEY:
+ mtof_zoommul = FRACUNIT;
+ ftom_zoommul = FRACUNIT;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static void AM_changeWindowScale(void)
+{
+ // Change the scaling multipliers
+ scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+
+ if (scale_mtof < min_scale_mtof)
+ AM_minOutWindowScale();
+ else if (scale_mtof > max_scale_mtof)
+ AM_maxOutWindowScale();
+ else
+ AM_activateNewScale();
+}
+
+static void AM_doFollowPlayer(void)
+{
+ if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y)
+ {
+ // m_x = FTOM(MTOF(plr->mo->x - m_w/2));
+ // m_y = FTOM(MTOF(plr->mo->y - m_h/2));
+ // m_x = plr->mo->x - m_w/2;
+ // m_y = plr->mo->y - m_h/2;
+ m_x = FTOM(MTOF(plr->mo->x)) - m_w/2;
+ m_y = FTOM(MTOF(plr->mo->y)) - m_h/2;
+ m_x2 = m_x + m_w;
+ m_y2 = m_y + m_h;
+
+ // do the parallax parchment scrolling.
+ /*
+ dmapx = (MTOF(plr->mo->x)-MTOF(f_oldloc.x)); //fixed point
+ dmapy = (MTOF(f_oldloc.y)-MTOF(plr->mo->y));
+
+ if (f_oldloc.x == H2MAXINT) //to eliminate an error when the user first
+ dmapx = 0; //goes into the automap.
+ mapxstart += dmapx;
+ mapystart += dmapy;
+
+ while (mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ while (mapxstart < 0)
+ mapxstart += finit_width;
+ while (mapystart >= finit_height)
+ mapystart -= finit_height;
+ while (mapystart < 0)
+ mapystart += finit_height;
+ */
+ f_oldloc.x = plr->mo->x;
+ f_oldloc.y = plr->mo->y;
+ }
+}
+
+// Ripped out for Heretic
+/*
+static void AM_updateLightLev(void)
+{
+ static nexttic = 0;
+// static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 };
+ static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
+ static int litelevelscnt = 0;
+
+ // Change light level
+ if (amclock > nexttic)
+ {
+ lightlev = litelevels[litelevelscnt++];
+ if (litelevelscnt == sizeof(litelevels)/sizeof(int))
+ litelevelscnt = 0;
+ nexttic = amclock + 6 - (amclock % 6);
+ }
+}
+*/
+
+void AM_Ticker (void)
+{
+ if (!automapactive)
+ return;
+
+ amclock++;
+
+ if (followplayer)
+ AM_doFollowPlayer();
+
+ // Change the zoom if necessary
+ if (ftom_zoommul != FRACUNIT)
+ AM_changeWindowScale();
+
+ // Change x,y location
+ if (m_paninc.x || m_paninc.y)
+ AM_changeWindowLoc();
+ // Update light level
+ /*
+ AM_updateLightLev();
+ */
+}
+
+static void AM_clearFB(int color)
+{
+#ifdef RENDER3D
+ float scaler;
+ int lump;
+#else
+# if !AM_TRANSPARENT
+ int i, j;
+# endif
+#endif
+
+ if (followplayer)
+ {
+ int dmapx = (MTOF(plr->mo->x) - MTOF(oldplr.x)); //fixed point
+ int dmapy = (MTOF(oldplr.y) - MTOF(plr->mo->y));
+
+ oldplr.x = plr->mo->x;
+ oldplr.y = plr->mo->y;
+ // if (f_oldloc.x == H2MAXINT) //to eliminate an error when the user first
+ // dmapx = 0; //goes into the automap.
+ mapxstart += dmapx>>1;
+ mapystart += dmapy>>1;
+
+ while (mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ while (mapxstart < 0)
+ mapxstart += finit_width;
+ while (mapystart >= finit_height)
+ mapystart -= finit_height;
+ while (mapystart < 0)
+ mapystart += finit_height;
+ }
+ else
+ {
+ mapxstart += (MTOF(m_paninc.x)>>1);
+ mapystart -= (MTOF(m_paninc.y)>>1);
+ if (mapxstart >= finit_width)
+ mapxstart -= finit_width;
+ if (mapxstart < 0)
+ mapxstart += finit_width;
+ if (mapystart >= finit_height)
+ mapystart -= finit_height;
+ if (mapystart < 0)
+ mapystart += finit_height;
+ }
+
+#ifdef RENDER3D
+ OGL_SetColorAndAlpha(1, 1, 1, 1);
+ OGL_SetFlat(W_GetNumForName("F_022")-firstflat);
+ scaler = sbarscale/20.0;
+ OGL_DrawCutRectTiled(0, finit_height+4, 320, 200-finit_height-4, 64, 64,
+ 160-160*scaler+1, finit_height, 320*scaler-2, 200-finit_height);
+
+ lump = W_GetNumForName("bordb");
+ OGL_SetPatch(lump);
+ OGL_DrawCutRectTiled(0, finit_height, 320, 4,
+ lumptexsizes[lump].w, lumptexsizes[lump].h,
+ 160-160*scaler+1, finit_height, 320*scaler-2, 4);
+# if !AM_TRANSPARENT
+ OGL_SetRawImage(maplumpnum, 0); // We only want the left portion.
+ OGL_DrawRectTiled(0, 0, finit_width,
+ /*(sbarscale<20)?200:*/ finit_height, 128, 128);
+# endif
+
+#else /* RENDER3D */
+
+# if !AM_TRANSPARENT
+ // blit the automap background to the screen.
+ j = mapystart*finit_width;
+ for (i = 0; i < SCREENHEIGHT-SBARHEIGHT; i++)
+ {
+ memcpy(screen + i*finit_width, maplump + j + mapxstart, finit_width - mapxstart);
+ memcpy(screen + i*finit_width + finit_width - mapxstart, maplump + j, mapxstart);
+ j += finit_width;
+ if (j >= finit_height*finit_width)
+ j = 0;
+ }
+# endif
+#endif /* !RENDER3D */
+}
+
+
+#ifndef RENDER3D
+/* Wu antialiased line drawer.
+ * (X0,Y0),(X1,Y1) = line to draw
+ * BaseColor = color # of first color in block used for antialiasing, the
+ * 100% intensity version of the drawing color
+ * NumLevels = size of color block, with BaseColor+NumLevels-1 being the
+ * 0% intensity version of the drawing color
+ * IntensityBits = log base 2 of NumLevels; the # of bits used to describe
+ * the intensity of the drawing color. 2**IntensityBits==NumLevels
+ */
+static void PUTDOT(short xx,short yy,byte *cc, byte *cm)
+{
+ static int oldyy;
+ static int oldyyshifted;
+ byte *oldcc = cc;
+
+ if (xx < 32)
+ cc += 7-(xx>>2);
+ else if (xx > (finit_width - 32))
+ cc += 7-((finit_width-xx) >> 2);
+// if (cc == oldcc) //make sure that we don't double fade the corners.
+// {
+ if (yy < 32)
+ cc += 7-(yy>>2);
+ else if (yy > (finit_height - 32))
+ cc += 7-((finit_height-yy) >> 2);
+// }
+ if (cc > cm && cm != NULL)
+ {
+ cc = cm;
+ }
+ else if (cc > oldcc+6) // don't let the color escape from the fade table...
+ {
+ cc = oldcc+6;
+ }
+ if (yy == oldyy+1)
+ {
+ oldyy++;
+ oldyyshifted += 320;
+ }
+ else if (yy == oldyy-1)
+ {
+ oldyy--;
+ oldyyshifted -= 320;
+ }
+ else if (yy != oldyy)
+ {
+ oldyy = yy;
+ oldyyshifted = yy*320;
+ }
+ fb[oldyyshifted+xx] = *(cc);
+// fb[(yy)*f_w+(xx)]=*(cc);
+}
+
+static void DrawWuLine (int X0, int Y0, int X1, int Y1, byte *BaseColor,
+ int NumLevels, unsigned short IntensityBits)
+{
+ unsigned short IntensityShift, ErrorAdj, ErrorAcc;
+ unsigned short ErrorAccTemp, Weighting, WeightingComplementMask;
+ short DeltaX, DeltaY, Temp, XDir;
+
+ /* Make sure the line runs top to bottom */
+ if (Y0 > Y1)
+ {
+ Temp = Y0; Y0 = Y1; Y1 = Temp;
+ Temp = X0; X0 = X1; X1 = Temp;
+ }
+ /* Draw the initial pixel, which is always exactly intersected by
+ the line and so needs no weighting */
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+
+ if ((DeltaX = X1 - X0) >= 0)
+ {
+ XDir = 1;
+ }
+ else
+ {
+ XDir = -1;
+ DeltaX = -DeltaX; /* make DeltaX positive */
+ }
+ /* Special-case horizontal, vertical, and diagonal lines, which
+ require no weighting because they go right through the center of
+ every pixel */
+ if ((DeltaY = Y1 - Y0) == 0)
+ {
+ /* Horizontal line */
+ while (DeltaX-- != 0)
+ {
+ X0 += XDir;
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+ }
+ return;
+ }
+ if (DeltaX == 0)
+ {
+ /* Vertical line */
+ do
+ {
+ Y0++;
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+ } while (--DeltaY != 0);
+ return;
+ }
+ //diagonal line.
+ if (DeltaX == DeltaY)
+ {
+ do
+ {
+ X0 += XDir;
+ Y0++;
+ PUTDOT(X0, Y0, &BaseColor[0], NULL);
+ } while (--DeltaY != 0);
+ return;
+ }
+ /* Line is not horizontal, diagonal, or vertical */
+ ErrorAcc = 0; /* initialize the line error accumulator to 0 */
+ /* # of bits by which to shift ErrorAcc to get intensity level */
+ IntensityShift = 16 - IntensityBits;
+ /* Mask used to flip all bits in an intensity weighting, producing the
+ result (1 - intensity weighting) */
+ WeightingComplementMask = NumLevels - 1;
+ /* Is this an X-major or Y-major line? */
+ if (DeltaY > DeltaX)
+ {
+ /* Y-major line; calculate 16-bit fixed-point fractional part of a
+ pixel that X advances each time Y advances 1 pixel, truncating the
+ result so that we won't overrun the endpoint along the X axis */
+ ErrorAdj = ((unsigned long) DeltaX << 16) / (unsigned long) DeltaY;
+ /* Draw all pixels other than the first and last */
+ while (--DeltaY)
+ {
+ ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
+ ErrorAcc += ErrorAdj; /* calculate error for next pixel */
+ if (ErrorAcc <= ErrorAccTemp)
+ {
+ /* The error accumulator turned over, so advance the X coord */
+ X0 += XDir;
+ }
+ Y0++; /* Y-major, so always advance Y */
+ /* The IntensityBits most significant bits of ErrorAcc give us the
+ intensity weighting for this pixel, and the complement of the
+ weighting for the paired pixel */
+ Weighting = ErrorAcc >> IntensityShift;
+ PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
+ PUTDOT(X0 + XDir, Y0,
+ &BaseColor[(Weighting ^ WeightingComplementMask)], &BaseColor[7]);
+ }
+ /* Draw the final pixel, which is always exactly intersected by the line
+ and so needs no weighting */
+ PUTDOT(X1, Y1, &BaseColor[0], NULL);
+ return;
+ }
+ /* It's an X-major line; calculate 16-bit fixed-point fractional part of a
+ pixel that Y advances each time X advances 1 pixel, truncating the
+ result to avoid overrunning the endpoint along the X axis */
+ ErrorAdj = ((unsigned long) DeltaY << 16) / (unsigned long) DeltaX;
+ /* Draw all pixels other than the first and last */
+ while (--DeltaX)
+ {
+ ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
+ ErrorAcc += ErrorAdj; /* calculate error for next pixel */
+ if (ErrorAcc <= ErrorAccTemp)
+ {
+ /* The error accumulator turned over, so advance the Y coord */
+ Y0++;
+ }
+ X0 += XDir; /* X-major, so always advance X */
+ /* The IntensityBits most significant bits of ErrorAcc give us the
+ intensity weighting for this pixel, and the complement of the
+ weighting for the paired pixel */
+ Weighting = ErrorAcc >> IntensityShift;
+ PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
+ PUTDOT(X0, Y0 + 1,
+ &BaseColor[(Weighting ^ WeightingComplementMask)], &BaseColor[7]);
+ }
+ /* Draw the final pixel, which is always exactly intersected by the line
+ and so needs no weighting */
+ PUTDOT(X1, Y1, &BaseColor[0], NULL);
+}
+
+// Based on Cohen-Sutherland clipping algorithm but with a slightly
+// faster reject and precalculated slopes. If I need the speed, will
+// hash algorithm to the common cases.
+
+static boolean AM_clipMline(mline_t *ml, fline_t *fl)
+{
+ enum { LEFT = 1, RIGHT = 2, BOTTOM = 4, TOP = 8 };
+ register int outcode1 = 0, outcode2 = 0, outside;
+ fpoint_t tmp;
+ int dx, dy;
+
+#define DOOUTCODE(oc, mx, my) \
+ (oc) = 0; \
+ if ((my) < 0) (oc) |= TOP; \
+ else if ((my) >= f_h) (oc) |= BOTTOM; \
+ if ((mx) < 0) (oc) |= LEFT; \
+ else if ((mx) >= f_w) (oc) |= RIGHT
+
+ // do trivial rejects and outcodes
+ if (ml->a.y > m_y2)
+ outcode1 = TOP;
+ else if (ml->a.y < m_y)
+ outcode1 = BOTTOM;
+ if (ml->b.y > m_y2)
+ outcode2 = TOP;
+ else if (ml->b.y < m_y)
+ outcode2 = BOTTOM;
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+
+ if (ml->a.x < m_x)
+ outcode1 |= LEFT;
+ else if (ml->a.x > m_x2)
+ outcode1 |= RIGHT;
+ if (ml->b.x < m_x)
+ outcode2 |= LEFT;
+ else if (ml->b.x > m_x2)
+ outcode2 |= RIGHT;
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+
+ // transform to frame-buffer coordinates.
+ fl->a.x = CXMTOF(ml->a.x);
+ fl->a.y = CYMTOF(ml->a.y);
+ fl->b.x = CXMTOF(ml->b.x);
+ fl->b.y = CYMTOF(ml->b.y);
+ DOOUTCODE(outcode1, fl->a.x, fl->a.y);
+ DOOUTCODE(outcode2, fl->b.x, fl->b.y);
+ if (outcode1 & outcode2)
+ return false;
+
+ while (outcode1 | outcode2)
+ {
+ // may be partially inside box
+ // find an outside point
+ if (outcode1)
+ outside = outcode1;
+ else
+ outside = outcode2;
+ // clip to each side
+ if (outside & TOP)
+ {
+ dy = fl->a.y - fl->b.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
+ tmp.y = 0;
+ }
+ else if (outside & BOTTOM)
+ {
+ dy = fl->a.y - fl->b.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy;
+ tmp.y = f_h-1;
+ }
+ else if (outside & RIGHT)
+ {
+ dy = fl->b.y - fl->a.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx;
+ tmp.x = f_w-1;
+ }
+ else if (outside & LEFT)
+ {
+ dy = fl->b.y - fl->a.y;
+ dx = fl->b.x - fl->a.x;
+ tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
+ tmp.x = 0;
+ }
+ else /* avoid compiler warning */
+ {
+ tmp.x = 0;
+ tmp.y = 0;
+ }
+ if (outside == outcode1)
+ {
+ fl->a = tmp;
+ DOOUTCODE(outcode1, fl->a.x, fl->a.y);
+ }
+ else
+ {
+ fl->b = tmp;
+ DOOUTCODE(outcode2, fl->b.x, fl->b.y);
+ }
+ if (outcode1 & outcode2)
+ return false; // trivially outside
+ }
+
+ return true;
+}
+#undef DOOUTCODE
+
+// Classic Bresenham w/ whatever optimizations I need for speed
+
+static void AM_drawFline(fline_t *fl, int color)
+{
+ register int x, y, dx, dy, sx, sy, ax, ay, d;
+// static int fuck = 0;
+
+ switch (color)
+ {
+ case WALLCOLORS:
+ DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
+ &antialias[0][0], 8, 3);
+ break;
+ case FDWALLCOLORS:
+ DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
+ &antialias[1][0], 8, 3);
+ break;
+ case CDWALLCOLORS:
+ DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
+ &antialias[2][0], 8, 3);
+ break;
+ default:
+ // For debugging only
+ if (fl->a.x < 0 || fl->a.x >= f_w
+ || fl->a.y < 0 || fl->a.y >= f_h
+ || fl->b.x < 0 || fl->b.x >= f_w
+ || fl->b.y < 0 || fl->b.y >= f_h)
+ {
+ // fprintf(stderr, "fuck %d \r", fuck++);
+ return;
+ }
+
+ #define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) //the MACRO!
+
+ dx = fl->b.x - fl->a.x;
+ ax = 2 * (dx<0 ? -dx : dx);
+ sx = dx<0 ? -1 : 1;
+
+ dy = fl->b.y - fl->a.y;
+ ay = 2 * (dy < 0 ? -dy : dy);
+ sy = dy < 0 ? -1 : 1;
+
+ x = fl->a.x;
+ y = fl->a.y;
+
+ if (ax > ay)
+ {
+ d = ay - ax/2;
+ while (1)
+ {
+ DOT(x, y, color);
+ if (x == fl->b.x)
+ return;
+ if (d >= 0)
+ {
+ y += sy;
+ d -= ax;
+ }
+ x += sx;
+ d += ay;
+ }
+ }
+ else
+ {
+ d = ax - ay/2;
+ while (1)
+ {
+ DOT(x, y, color);
+ if (y == fl->b.y)
+ return;
+ if (d >= 0)
+ {
+ x += sx;
+ d -= ay;
+ }
+ y += sy;
+ d += ax;
+ }
+ }
+ }
+}
+
+static void AM_drawMline(mline_t *ml, int color)
+{
+ static fline_t fl;
+
+ if (AM_clipMline(ml, &fl))
+ AM_drawFline(&fl, color); // draws it on frame buffer using fb coords
+}
+#endif /* ! RENDER3D */
+
+#ifdef RENDER3D
+static void AM_drawMline(mline_t *ml, int color)
+{
+ /* bbm: disabled this. doing it more directly below.
+ byte *palette = (byte *) W_CacheLumpName("PLAYPAL", PU_CACHE);
+ byte r = palette[color*3],
+ g = palette[color*3 + 1],
+ b = palette[color*3 + 2];
+
+ OGL_DrawLine(FIX2FLT(CXMTOFX(ml->a.x)), FIX2FLT(CYMTOFX(ml->a.y))/1.2,
+ FIX2FLT(CXMTOFX(ml->b.x)), FIX2FLT(CYMTOFX(ml->b.y))/1.2,
+ r/255.0, g/255.0, b/255.0, 1);
+ */
+ OGL_SetColor(color);
+ // Draw the line. 1.2 is the to-square aspect corrector.
+ glVertex2f(FIX2FLT(CXMTOFX(ml->a.x)), FIX2FLT(CYMTOFX(ml->a.y))/1.2);
+ glVertex2f(FIX2FLT(CXMTOFX(ml->b.x)), FIX2FLT(CYMTOFX(ml->b.y))/1.2);
+}
+#endif /* RENDER3D */
+
+static void AM_drawGrid(int color)
+{
+ fixed_t x, y;
+ fixed_t start, end;
+ mline_t ml;
+
+ // Figure out start of vertical gridlines
+ start = m_x;
+ if ((start-bmaporgx) % (MAPBLOCKUNITS<<FRACBITS))
+ start += (MAPBLOCKUNITS<<FRACBITS) - ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS));
+ end = m_x + m_w;
+
+ // draw vertical gridlines
+ ml.a.y = m_y;
+ ml.b.y = m_y+m_h;
+ for (x = start; x < end; x += (MAPBLOCKUNITS<<FRACBITS))
+ {
+ ml.a.x = x;
+ ml.b.x = x;
+ AM_drawMline(&ml, color);
+ }
+
+ // Figure out start of horizontal gridlines
+ start = m_y;
+ if ((start-bmaporgy) % (MAPBLOCKUNITS<<FRACBITS))
+ start += (MAPBLOCKUNITS<<FRACBITS) - ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS));
+ end = m_y + m_h;
+
+ // draw horizontal gridlines
+ ml.a.x = m_x;
+ ml.b.x = m_x + m_w;
+ for (y = start; y < end; y += (MAPBLOCKUNITS<<FRACBITS))
+ {
+ ml.a.y = y;
+ ml.b.y = y;
+ AM_drawMline(&ml, color);
+ }
+}
+
+static void AM_drawWalls(void)
+{
+ int i;
+
+#ifdef RENDER3D
+ /* bbm: disabled this to draw all lines at once, see AM_Drawer()
+ glDisable(GL_TEXTURE_2D);
+ glLineWidth(2.5);
+ glBegin(GL_LINES); // We'll draw pretty much all of them.
+ */
+ for (i = 0; i < numlines; i++)
+ {
+ if (cheating || (lines[i].flags & ML_MAPPED))
+ {
+ if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
+ continue;
+ if (!lines[i].backsector)
+ {
+ OGL_SetColor(WALLCOLORS);
+ }
+ else
+ {
+ if (lines[i].flags & ML_SECRET) // secret door
+ {
+ if (cheating) //AM_drawMline(&l, 0);
+ OGL_SetColor(0);
+ else
+ OGL_SetColor(WALLCOLORS);
+ }
+ else if (lines[i].special == 13 || lines[i].special == 83)
+ { // Locked door line -- all locked doors are greed
+ OGL_SetColor(GREENKEY);
+ }
+ else if (lines[i].special == 70 || lines[i].special == 71)
+ { // intra-level teleports are blue
+ OGL_SetColor(BLUEKEY);
+ }
+ else if (lines[i].special == 74 || lines[i].special == 75)
+ { // inter-level teleport/game-winning exit -- both are red
+ OGL_SetColor(BLOODRED);
+ }
+ else if (lines[i].backsector->floorheight != lines[i].frontsector->floorheight)
+ { // floor level change
+ OGL_SetColor(FDWALLCOLORS);
+ }
+ else if (lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight)
+ { // ceiling level change
+ OGL_SetColor(CDWALLCOLORS);
+ }
+ else if (cheating)
+ {
+ OGL_SetColor(TSWALLCOLORS);
+ }
+ else
+ continue;
+ }
+ }
+ else if (plr->powers[pw_allmap])
+ {
+ if (!(lines[i].flags & LINE_NEVERSEE))
+ OGL_SetColor(GRAYS+3);
+ else
+ continue;
+ }
+ else
+ continue;
+
+ // Draw the line. 1.2 is the to-square aspect corrector.
+ glVertex2f (FIX2FLT(CXMTOFX(lines[i].v1->x)),
+ FIX2FLT(CYMTOFX(lines[i].v1->y))/1.2);
+ glVertex2f (FIX2FLT(CXMTOFX(lines[i].v2->x)),
+ FIX2FLT(CYMTOFX(lines[i].v2->y))/1.2);
+ }
+ /* bbm .
+ glEnd();
+ glLineWidth(1.0);
+ glEnable(GL_TEXTURE_2D);
+ */
+#else
+ static mline_t l;
+
+ for (i = 0; i < numlines; i++)
+ {
+ l.a.x = lines[i].v1->x;
+ l.a.y = lines[i].v1->y;
+ l.b.x = lines[i].v2->x;
+ l.b.y = lines[i].v2->y;
+ if (cheating || (lines[i].flags & ML_MAPPED))
+ {
+ if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
+ continue;
+ if (!lines[i].backsector)
+ {
+ AM_drawMline(&l, WALLCOLORS+lightlev);
+ }
+ else
+ {
+ if (lines[i].flags & ML_SECRET) // secret door
+ {
+ if (cheating)
+ AM_drawMline(&l, 0);
+ else
+ AM_drawMline(&l, WALLCOLORS+lightlev);
+ }
+ else if (lines[i].special == 13 || lines[i].special == 83)
+ { // Locked door line -- all locked doors are greed
+ AM_drawMline(&l, GREENKEY);
+ }
+ else if (lines[i].special == 70 || lines[i].special == 71)
+ { // intra-level teleports are blue
+ AM_drawMline(&l, BLUEKEY);
+ }
+ else if (lines[i].special == 74 || lines[i].special == 75)
+ { // inter-level teleport/game-winning exit -- both are red
+ AM_drawMline(&l, BLOODRED);
+ }
+ else if (lines[i].backsector->floorheight != lines[i].frontsector->floorheight)
+ { // floor level change
+ AM_drawMline(&l, FDWALLCOLORS + lightlev);
+ }
+ else if (lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight)
+ { // ceiling level change
+ AM_drawMline(&l, CDWALLCOLORS+lightlev);
+ }
+ else if (cheating)
+ {
+ AM_drawMline(&l, TSWALLCOLORS+lightlev);
+ }
+ }
+ }
+ else if (plr->powers[pw_allmap])
+ {
+ if (!(lines[i].flags & LINE_NEVERSEE))
+ AM_drawMline(&l, GRAYS+3);
+ }
+ }
+#endif
+}
+
+static void AM_rotate(fixed_t *x, fixed_t *y, angle_t a)
+{
+ fixed_t tmpx;
+
+ tmpx = FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT]) - FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]);
+ *y = FixedMul(*x,finesine[a>>ANGLETOFINESHIFT]) + FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]);
+ *x = tmpx;
+}
+
+static void AM_drawLineCharacter(mline_t *lineguy, int lineguylines, fixed_t scale,
+ angle_t angle, int color, fixed_t x, fixed_t y)
+{
+ int i;
+ mline_t l;
+
+ for (i = 0; i < lineguylines; i++)
+ {
+ l.a.x = lineguy[i].a.x;
+ l.a.y = lineguy[i].a.y;
+ if (scale)
+ {
+ l.a.x = FixedMul(scale, l.a.x);
+ l.a.y = FixedMul(scale, l.a.y);
+ }
+ if (angle)
+ AM_rotate(&l.a.x, &l.a.y, angle);
+ l.a.x += x;
+ l.a.y += y;
+
+ l.b.x = lineguy[i].b.x;
+ l.b.y = lineguy[i].b.y;
+ if (scale)
+ {
+ l.b.x = FixedMul(scale, l.b.x);
+ l.b.y = FixedMul(scale, l.b.y);
+ }
+ if (angle)
+ AM_rotate(&l.b.x, &l.b.y, angle);
+ l.b.x += x;
+ l.b.y += y;
+
+ AM_drawMline(&l, color);
+ }
+}
+
+static void AM_drawPlayers(void)
+{
+ int i;
+ player_t *p;
+ static int their_colors[] =
+ {
+ AM_PLR1_COLOR,
+ AM_PLR2_COLOR,
+ AM_PLR3_COLOR,
+ AM_PLR4_COLOR,
+ AM_PLR5_COLOR,
+ AM_PLR6_COLOR,
+ AM_PLR7_COLOR,
+ AM_PLR8_COLOR
+ };
+ int their_color = -1;
+ int color;
+
+ if (!netgame)
+ {
+ AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, plr->mo->angle,
+ AM_PLR5_COLOR, plr->mo->x, plr->mo->y);
+ // AM_PLR5_COLOR: Jade. Used to be WHITE, couldn't see it! - S.A.
+ return;
+ }
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ their_color++;
+ p = &players[i];
+ if (deathmatch && !singledemo && p != plr)
+ {
+ continue;
+ }
+ if (!playeringame[i])
+ continue;
+ color = their_colors[their_color];
+ AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle,
+ color, p->mo->x, p->mo->y);
+ }
+}
+
+static void AM_drawThings(int colors, int colorrange)
+{
+ int i;
+ mobj_t *t;
+
+ for (i = 0; i < numsectors; i++)
+ {
+ t = sectors[i].thinglist;
+ while (t)
+ {
+ AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
+ 16<<FRACBITS, t->angle, colors+lightlev, t->x, t->y);
+ t = t->snext;
+ }
+ }
+}
+
+
+#ifdef RENDER3D
+static void AM_OGL_SetupState(void)
+{
+ float ys = screenHeight/200.0;
+
+ // Let's set up a scissor box to clip the map lines and stuff.
+ glPushAttrib(GL_SCISSOR_BIT);
+ glScissor(0, screenHeight-finit_height*ys, screenWidth, finit_height*ys);
+ glEnable(GL_SCISSOR_TEST);
+}
+
+static void AM_OGL_RestoreState(void)
+{
+ glPopAttrib();
+}
+#endif /* RENDER3D */
+
+
+void AM_Drawer (void)
+{
+ if (!automapactive)
+ return;
+
+ UpdateState |= I_FULLSCRN;
+
+#ifdef RENDER3D
+ // Update the height (in case sbarscale has been changed).
+ finit_height = SCREENHEIGHT - SBARHEIGHT * sbarscale / 20;
+ AM_OGL_SetupState();
+#endif
+
+ AM_clearFB(BACKGROUND);
+
+#ifdef RENDER3D
+ /* bbm 3/9/2003: start drawing all lines at once */
+ glDisable(GL_TEXTURE_2D);
+ glLineWidth(1.0);
+ glBegin(GL_LINES);
+#endif
+
+ if (grid)
+ AM_drawGrid(GRIDCOLORS);
+ AM_drawWalls();
+ AM_drawPlayers();
+
+ if (cheating == 2)
+ AM_drawThings(THINGCOLORS, THINGRANGE);
+
+#ifdef RENDER3D
+ /* bbm: finish drawing all lines at once */
+ glEnd();
+ glLineWidth(1.0);
+ glEnable(GL_TEXTURE_2D);
+
+ AM_OGL_RestoreState();
+#endif
+
+ DrawWorldTimer();
+ MN_DrTextA(P_GetMapName(gamemap), 38, 144);
+ if (ShowKills && netgame && deathmatch)
+ {
+ AM_DrawDeathmatchStats();
+ }
+}
+
+//===========================================================================
+//
+// AM_DrawDeathmatchStats
+//
+//===========================================================================
+
+// 8-player note: Proper player color names here, too
+
+static const char *PlayerColorText[MAXPLAYERS_11] =
+{
+ "BLUE:",
+ "RED:",
+ "YELLOW:",
+ "GREEN:",
+ "JADE:",
+ "WHITE:",
+ "HAZEL:",
+ "PURPLE:"
+};
+
+static void AM_DrawDeathmatchStats(void)
+{
+ int i, j, k, m;
+ int fragCount[MAXPLAYERS];
+ int order[MAXPLAYERS];
+ char textBuffer[80];
+ int yPosition;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ fragCount[i] = 0;
+ order[i] = -1;
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ else
+ {
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ if (playeringame[j])
+ {
+ fragCount[i] += players[i].frags[j];
+ }
+ }
+ for (k = 0; k < MAXPLAYERS; k++)
+ {
+ if (order[k] == -1)
+ {
+ order[k] = i;
+ break;
+ }
+ else if (fragCount[i] > fragCount[order[k]])
+ {
+ for (m = MAXPLAYERS-1; m > k; m--)
+ {
+ order[m] = order[m-1];
+ }
+ order[k] = i;
+ break;
+ }
+ }
+ }
+ }
+ yPosition = 15;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[order[i]])
+ {
+ continue;
+ }
+ else
+ {
+ MN_DrTextA(PlayerColorText[order[i]], 8, yPosition);
+ snprintf(textBuffer, sizeof(textBuffer), "%d", fragCount[order[i]]);
+ MN_DrTextA(textBuffer, 80, yPosition);
+ yPosition += 10;
+ }
+ }
+}
+
+//===========================================================================
+//
+// DrawWorldTimer
+//
+//===========================================================================
+
+static void DrawWorldTimer(void)
+{
+ int days;
+ int hours;
+ int minutes;
+ int seconds;
+ int worldTimer;
+ char timeBuffer[15];
+ char dayBuffer[20];
+
+ worldTimer = players[consoleplayer].worldTimer;
+
+ worldTimer /= 35;
+ days = worldTimer/86400;
+ worldTimer -= days*86400;
+ hours = worldTimer/3600;
+ worldTimer -= hours*3600;
+ minutes = worldTimer/60;
+ worldTimer -= minutes*60;
+ seconds = worldTimer;
+
+ snprintf(timeBuffer, sizeof(timeBuffer), "%.2d : %.2d : %.2d", hours, minutes,seconds);
+ MN_DrTextA(timeBuffer, 240, 8);
+
+ if (days)
+ {
+ if (days == 1)
+ {
+ snprintf(dayBuffer, sizeof(dayBuffer), "%.2d DAY", days);
+ }
+ else
+ {
+ snprintf(dayBuffer, sizeof(dayBuffer), "%.2d DAYS", days);
+ }
+ MN_DrTextA(dayBuffer, 240, 20);
+ if (days >= 5)
+ {
+ MN_DrTextA("YOU FREAK!!!", 230, 35);
+ }
+ }
+}
+
--- /dev/null
+++ b/am_map.h
@@ -1,0 +1,131 @@
+
+//**************************************************************************
+//**
+//** am_map.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 440 $
+//** $Date: 2009-05-24 00:08:25 +0300 (Sun, 24 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __AMMAP_H__
+#define __AMMAP_H__
+
+/* For use if I do walls with outsides/insides */
+#define REDS (12 * 8)
+#define REDRANGE 1 /* 16 */
+#define BLUES (256 - 4*16 + 8)
+#define BLUERANGE 1 /* 8 */
+#define GREENS (33 * 8)
+#define GREENRANGE 1 /* 16 */
+#define GRAYS (5 * 8)
+#define GRAYSRANGE 1 /* 16 */
+#define BROWNS (14 * 8)
+#define BROWNRANGE 1 /* 16 */
+#define YELLOWS (10 * 8)
+#define YELLOWRANGE 1
+#define BLACK 0
+#define WHITE (4 * 8)
+#define PARCH (13*8 - 1)
+#define BLOODRED 177
+#define BLUEKEY 157
+#define YELLOWKEY 137
+#define GREENKEY 198
+
+/* Automap colors */
+#define AM_PLR1_COLOR 157 /* Blue */
+#define AM_PLR2_COLOR 177 /* Red */
+#define AM_PLR3_COLOR 137 /* Yellow */
+#define AM_PLR4_COLOR 198 /* Green */
+#define AM_PLR5_COLOR 215 /* Jade */
+#define AM_PLR6_COLOR 32 /* White */
+#define AM_PLR7_COLOR 106 /* Hazel */
+#define AM_PLR8_COLOR 234 /* Purple */
+
+#define BACKGROUND PARCH
+#define YOURCOLORS WHITE
+#define YOURRANGE 0
+#define WALLCOLORS REDS
+#define WALLRANGE REDRANGE
+#define TSWALLCOLORS GRAYS
+#define TSWALLRANGE GRAYSRANGE
+#define FDWALLCOLORS BROWNS
+#define FDWALLRANGE BROWNRANGE
+#define CDWALLCOLORS YELLOWS
+#define CDWALLRANGE YELLOWRANGE
+#define THINGCOLORS GREENS
+#define THINGRANGE GREENRANGE
+#define SECRETWALLCOLORS WALLCOLORS
+#define SECRETWALLRANGE WALLRANGE
+#define GRIDCOLORS (GRAYS + GRAYSRANGE/2)
+#define GRIDRANGE 0
+#define XHAIRCOLORS GRAYS
+
+/* drawing stuff */
+#define FB 0
+
+#define AM_PANDOWNKEY KEY_DOWNARROW
+#define AM_PANUPKEY KEY_UPARROW
+#define AM_PANRIGHTKEY KEY_RIGHTARROW
+#define AM_PANLEFTKEY KEY_LEFTARROW
+
+#define AM_ZOOMINKEY '='
+#define AM_ZOOMOUTKEY '-'
+#define AM_STARTKEY KEY_TAB
+#define AM_ENDKEY KEY_TAB
+#define AM_GOBIGKEY '0'
+#define AM_FOLLOWKEY 'f'
+#define AM_GRIDKEY 'g'
+
+#define AM_NUMMARKPOINTS 10
+
+#define AM_MSGHEADER (('a'<<24) + ('m'<<16))
+#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8))
+#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8))
+
+#define INITSCALEMTOF (.2*FRACUNIT) /* scale on entry */
+
+/* how much the automap moves window per tic in frame-buffer coordinates */
+#define F_PANINC 4 /* moves 140 pixels in 1 second */
+
+/* how much zoom-in per tic */
+#define M_ZOOMIN ((int) (1.02*FRACUNIT)) /* goes to 2x in 1 second */
+
+/* how much zoom-out per tic */
+#define M_ZOOMOUT ((int) (FRACUNIT/1.02)) /* pulls out to 0.5x in 1 second */
+
+/* translates between frame-buffer and map distances */
+#define FTOM(x) FixedMul(((x)<<16),scale_ftom)
+#define MTOF(x) (FixedMul((x),scale_mtof)>>16)
+
+/* translates between frame-buffer and map coordinates */
+#define CXMTOF(x) (f_x + MTOF((x)-m_x))
+#define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y)))
+
+/* the following is crap */
+#define LINE_NEVERSEE ML_DONTDRAW
+
+typedef struct
+{
+ int x, y;
+} fpoint_t;
+
+typedef struct
+{
+ fpoint_t a, b;
+} fline_t;
+
+typedef vertex_t mpoint_t;
+
+typedef struct
+{
+ mpoint_t a, b;
+} mline_t;
+
+typedef struct
+{
+ fixed_t slp, islp;
+} islope_t;
+
+#endif /* __AMMAP_H__ */
+
--- /dev/null
+++ b/audio_plugin.h
@@ -1,0 +1,63 @@
+/* XMMS - Cross-platform multimedia player
+ * Copyright (C) 1998-1999 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef AUDIO_PLUGIN_H
+#define AUDIO_PLUGIN_H
+
+
+typedef enum
+{
+ FMT_U8, FMT_S8, FMT_U16_LE, FMT_U16_BE, FMT_U16_NE, FMT_S16_LE, FMT_S16_BE, FMT_S16_NE
+}
+AFormat;
+
+typedef struct
+{
+ void *handle; /* Filled in by xmms */
+ char *filename; /* Filled in by xmms */
+ const char *description; /* The description that is shown in the preferences box */
+ void (*init) (void);
+ void (*about) (void); /* Show the about box */
+ void (*configure) (void); /* Show the configuration dialog */
+ void (*get_volume) (int *l, int *r);
+ void (*set_volume) (int l, int r); /* Set the volume */
+
+ int (*open_audio) (AFormat fmt, int rate, int nch);
+ /* Open the device, if the device can't handle the given
+ parameters the plugin is responsible for downmixing
+ the data to the right format before outputting it */
+
+ void (*write_audio) (void *ptr, int length);
+ /* The input plugin calls this to write data to the output buffer */
+
+ void (*close_audio) (void); /* No comment... */
+ void (*flush) (int flushtime); /* Flush the buffer and set the plugins internal timers to time */
+ void (*pause) (short paused); /* Pause or unpause the output */
+ int (*buffer_free) (void); /* Return the amount of data that can be written to the buffer,
+ two calls to this without a call to write_audio should make
+ the plugin output audio directly */
+ int (*buffer_playing) (void); /* Returns TRUE if the plugin currently is playing some audio,
+ otherwise return FALSE */
+ int (*output_time) (void); /* Return the current playing time */
+ int (*written_time) (void); /* Return the length of all the data that has been written to
+ the buffer */
+}
+OutputPlugin;
+
+#endif /* AUDIO_PLUGIN_H */
+
--- /dev/null
+++ b/ct_chat.c
@@ -1,0 +1,515 @@
+
+//**************************************************************************
+//**
+//** ct_chat.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 529 $
+//** $Date: 2009-06-10 16:27:26 +0300 (Wed, 10 Jun 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+#ifdef RENDER3D
+#include "ogl_def.h"
+#endif
+
+#define QUEUESIZE 128
+#define MESSAGESIZE 128
+#define MESSAGELEN 265
+
+// 8-player note: Change this stuff (CT_PLR_*, and the key mappings)
+enum
+{
+ CT_PLR_BLUE = 1,
+ CT_PLR_RED,
+ CT_PLR_YELLOW,
+ CT_PLR_GREEN,
+#if (MAXPLAYERS >= MAXPLAYERS_11)
+ CT_PLR_PLAYER5,
+ CT_PLR_PLAYER6,
+ CT_PLR_PLAYER7,
+ CT_PLR_PLAYER8,
+#endif
+ CT_PLR_ALL
+};
+
+#define CT_KEY_BLUE 'b'
+#define CT_KEY_RED 'r'
+#define CT_KEY_YELLOW 'y'
+#define CT_KEY_GREEN 'g'
+#define CT_KEY_PLAYER5 'j' /* Jade */
+#define CT_KEY_PLAYER6 'w' /* White */
+#define CT_KEY_PLAYER7 'h' /* Hazel */
+#define CT_KEY_PLAYER8 'p' /* Purple */
+#define CT_KEY_ALL 't'
+#define CT_ESCAPE 6
+
+// Public data
+
+void CT_Init(void);
+void CT_Drawer(void);
+boolean CT_Responder(event_t *ev);
+void CT_Ticker(void);
+char CT_dequeueChatChar(void);
+
+boolean chatmodeon;
+
+char chat_macros[10][80] =
+{
+ HUSTR_CHATMACRO0,
+ HUSTR_CHATMACRO1,
+ HUSTR_CHATMACRO2,
+ HUSTR_CHATMACRO3,
+ HUSTR_CHATMACRO4,
+ HUSTR_CHATMACRO5,
+ HUSTR_CHATMACRO6,
+ HUSTR_CHATMACRO7,
+ HUSTR_CHATMACRO8,
+ HUSTR_CHATMACRO9
+};
+
+// Private data
+
+static void CT_queueChatChar(char ch);
+static void CT_ClearChatMessage(int player);
+static void CT_AddChar(int player, char c);
+static void CT_BackSpace(int player);
+
+static int head, tail;
+static byte ChatQueue[QUEUESIZE];
+static int chat_dest[MAXPLAYERS];
+static char chat_msg[MAXPLAYERS][MESSAGESIZE];
+static char plr_lastmsg[MAXPLAYERS][MESSAGESIZE+9];
+static int msgptr[MAXPLAYERS];
+static int msglen[MAXPLAYERS];
+
+static int FontABaseLump;
+
+static const char *CT_FromPlrText[MAXPLAYERS_11] =
+{
+ "BLUE: ",
+ "RED: ",
+ "YELLOW: ",
+ "GREEN: ",
+ "JADE: ",
+ "WHITE: ",
+ "HAZEL: ",
+ "PURPLE: "
+};
+
+static boolean altdown, shiftdown;
+
+extern boolean usearti;
+
+
+//===========================================================================
+//
+// CT_Init
+//
+// Initialize chat mode data
+//===========================================================================
+
+void CT_Init(void)
+{
+ int i;
+
+ head = 0; //initialize the queue index
+ tail = 0;
+ chatmodeon = false;
+ memset(ChatQueue, 0, QUEUESIZE);
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ chat_dest[i] = 0;
+ msgptr[i] = 0;
+ memset(plr_lastmsg[i], 0, MESSAGESIZE);
+ memset(chat_msg[i], 0, MESSAGESIZE);
+ }
+ FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+ return;
+}
+
+//===========================================================================
+//
+// CT_Stop
+//
+//===========================================================================
+
+void CT_Stop(void)
+{
+ chatmodeon = false;
+ return;
+}
+
+//===========================================================================
+//
+// CT_Responder
+//
+//===========================================================================
+
+boolean CT_Responder(event_t *ev)
+{
+ const char *macro;
+ int sendtarget;
+
+ if (!netgame)
+ {
+ return false;
+ }
+ if (ev->data1 == KEY_RALT)
+ {
+ altdown = (ev->type == ev_keydown);
+ return false;
+ }
+ if (ev->data1 == KEY_RSHIFT)
+ {
+ shiftdown = (ev->type == ev_keydown);
+ return false;
+ }
+ if (gamestate != GS_LEVEL || ev->type != ev_keydown)
+ {
+ return false;
+ }
+ if (!chatmodeon)
+ {
+ sendtarget = 0;
+ if (ev->data1 == CT_KEY_ALL)
+ {
+ sendtarget = CT_PLR_ALL;
+ }
+ else if (ev->data1 == CT_KEY_GREEN)
+ {
+ sendtarget = CT_PLR_GREEN;
+ }
+ else if (ev->data1 == CT_KEY_YELLOW)
+ {
+ sendtarget = CT_PLR_YELLOW;
+ }
+ else if (ev->data1 == CT_KEY_RED)
+ {
+ sendtarget = CT_PLR_RED;
+ }
+ else if (ev->data1 == CT_KEY_BLUE)
+ {
+ sendtarget = CT_PLR_BLUE;
+ }
+#if (MAXPLAYERS == MAXPLAYERS_11)
+ else if (ev->data1 == CT_KEY_PLAYER5)
+ {
+ sendtarget = CT_PLR_PLAYER5;
+ }
+ else if (ev->data1 == CT_KEY_PLAYER6)
+ {
+ sendtarget = CT_PLR_PLAYER6;
+ }
+ else if (ev->data1 == CT_KEY_PLAYER7)
+ {
+ sendtarget = CT_PLR_PLAYER7;
+ }
+ else if (ev->data1 == CT_KEY_PLAYER8)
+ {
+ sendtarget = CT_PLR_PLAYER8;
+ }
+#endif /* 8-players */
+ if (sendtarget == 0 || (sendtarget != CT_PLR_ALL && !playeringame[sendtarget - 1])
+ || sendtarget == consoleplayer + 1)
+ {
+ return false;
+ }
+ CT_queueChatChar(sendtarget);
+ chatmodeon = true;
+ return true;
+ }
+ else
+ {
+ if (altdown)
+ {
+ if (ev->data1 >= '0' && ev->data1 <= '9')
+ {
+ if (ev->data1 == '0')
+ { // macro 0 comes after macro 9
+ ev->data1 = '9' + 1;
+ }
+ macro = chat_macros[ev->data1-'1'];
+ CT_queueChatChar(KEY_ENTER); //send old message
+ CT_queueChatChar(chat_dest[consoleplayer]); // chose the dest.
+ while (*macro)
+ {
+ CT_queueChatChar(toupper(*macro++));
+ }
+ CT_queueChatChar(KEY_ENTER); //send it off...
+ CT_Stop();
+ return true;
+ }
+ }
+ if (ev->data1 == KEY_ENTER)
+ {
+ CT_queueChatChar(KEY_ENTER);
+ usearti = false;
+ CT_Stop();
+ return true;
+ }
+ else if (ev->data1 == KEY_ESCAPE)
+ {
+ CT_queueChatChar(CT_ESCAPE);
+ CT_Stop();
+ return true;
+ }
+ else if (ev->data1 >= 'a' && ev->data1 <= 'z')
+ {
+ CT_queueChatChar(ev->data1-32);
+ return true;
+ }
+ else if (shiftdown)
+ {
+ if (ev->data1 == '1')
+ {
+ CT_queueChatChar('!');
+ return true;
+ }
+ else if (ev->data1 == '/')
+ {
+ CT_queueChatChar('?');
+ return true;
+ }
+ }
+ if (ev->data1 == ' ' || ev->data1 == ',' || ev->data1 == '.' ||
+ (ev->data1 >= '0' && ev->data1 <= '9') || ev->data1 == '\'' ||
+ ev->data1 == KEY_BACKSPACE || ev->data1 == '-' || ev->data1 == '=')
+ {
+ CT_queueChatChar(ev->data1);
+ return true;
+ }
+ }
+ return false;
+}
+
+//===========================================================================
+//
+// CT_Ticker
+//
+//===========================================================================
+
+void CT_Ticker(void)
+{
+ int i, j;
+ char c;
+ int numplayers;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ if ((c = players[i].cmd.chatchar) != 0)
+ {
+ if (c <= CT_PLR_ALL)
+ {
+ chat_dest[i] = c;
+ continue;
+ }
+ else if (c == CT_ESCAPE)
+ {
+ CT_ClearChatMessage(i);
+ }
+ else if (c == KEY_ENTER)
+ {
+ numplayers = 0;
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ numplayers += playeringame[j];
+ }
+ CT_AddChar(i, 0); // set the end of message character
+ if (numplayers > 2)
+ {
+ strcpy(plr_lastmsg[i], CT_FromPlrText[i]);
+ strcat(plr_lastmsg[i], chat_msg[i]);
+ }
+ else
+ {
+ strcpy(plr_lastmsg[i], chat_msg[i]);
+ }
+ if (i != consoleplayer && (chat_dest[i] == consoleplayer + 1
+ || chat_dest[i] == CT_PLR_ALL) && *chat_msg[i])
+ {
+ P_SetMessage(&players[consoleplayer], plr_lastmsg[i], true);
+ S_StartSound(NULL, SFX_CHAT);
+ }
+ else if (i == consoleplayer && (*chat_msg[i]))
+ {
+ if (numplayers <= 1)
+ {
+ P_SetMessage(&players[consoleplayer],
+ "THERE ARE NO OTHER PLAYERS IN THE GAME!", true);
+ S_StartSound(NULL, SFX_CHAT);
+ }
+ }
+ CT_ClearChatMessage(i);
+ }
+ else if (c == KEY_BACKSPACE)
+ {
+ CT_BackSpace(i);
+ }
+ else
+ {
+ CT_AddChar(i, c);
+ }
+ }
+ }
+ return;
+}
+
+//===========================================================================
+//
+// CT_Drawer
+//
+//===========================================================================
+
+void CT_Drawer(void)
+{
+ int i;
+ int x;
+ patch_t *patch;
+
+ if (chatmodeon)
+ {
+ x = 25;
+ for (i = 0; i < msgptr[consoleplayer]; i++)
+ {
+ if (chat_msg[consoleplayer][i] < 33)
+ {
+ x += 6;
+ }
+ else
+ {
+ patch = (patch_t *) W_CacheLumpNum(FontABaseLump + chat_msg[consoleplayer][i] - 33, PU_CACHE);
+#ifdef RENDER3D
+ OGL_DrawPatch_CS(x, 10, FontABaseLump + chat_msg[consoleplayer][i] - 33);
+#else
+ V_DrawPatch(x, 10, patch);
+#endif
+ x += SHORT(patch->width);
+ }
+ }
+#ifdef RENDER3D
+ OGL_DrawPatch_CS(x, 10, W_GetNumForName("FONTA59"));
+#else
+ patch = (patch_t *) W_CacheLumpName("FONTA59", PU_CACHE);
+ V_DrawPatch(x, 10, patch);
+#endif
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+}
+
+//===========================================================================
+//
+// CT_queueChatChar
+//
+//===========================================================================
+
+static void CT_queueChatChar(char ch)
+{
+ if (((tail + 1) & (QUEUESIZE - 1)) == head)
+ { // the queue is full
+ return;
+ }
+ ChatQueue[tail] = ch;
+ tail = (tail + 1) & (QUEUESIZE - 1);
+}
+
+//===========================================================================
+//
+// CT_dequeueChatChar
+//
+//===========================================================================
+
+char CT_dequeueChatChar(void)
+{
+ byte temp;
+
+ if (head == tail)
+ { // queue is empty
+ return 0;
+ }
+ temp = ChatQueue[head];
+ head = (head + 1) & (QUEUESIZE - 1);
+ return temp;
+}
+
+//===========================================================================
+//
+// CT_AddChar
+//
+//===========================================================================
+
+static void CT_AddChar(int player, char c)
+{
+ patch_t *patch;
+
+ if (msgptr[player] + 1 >= MESSAGESIZE || msglen[player] >= MESSAGELEN)
+ { // full.
+ return;
+ }
+ chat_msg[player][msgptr[player]] = c;
+ msgptr[player]++;
+ if (c < 33)
+ {
+ msglen[player] += 6;
+ }
+ else
+ {
+ patch = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ msglen[player] += SHORT(patch->width);
+ }
+}
+
+//===========================================================================
+//
+// CT_BackSpace
+//
+// Backs up a space, when the user hits (obviously) backspace
+//===========================================================================
+
+static void CT_BackSpace(int player)
+{
+ patch_t *patch;
+ char c;
+
+ if (msgptr[player] == 0)
+ { // message is already blank
+ return;
+ }
+ msgptr[player]--;
+ c = chat_msg[player][msgptr[player]];
+ if (c < 33)
+ {
+ msglen[player] -= 6;
+ }
+ else
+ {
+ patch = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ msglen[player] -= SHORT(patch->width);
+ }
+ chat_msg[player][msgptr[player]] = 0;
+}
+
+//===========================================================================
+//
+// CT_ClearChatMessage
+//
+// Clears out the data for the chat message, but the player's message
+// is still saved in plrmsg.
+//===========================================================================
+
+static void CT_ClearChatMessage(int player)
+{
+ memset(chat_msg[player], 0, MESSAGESIZE);
+ msgptr[player] = 0;
+ msglen[player] = 0;
+}
+
--- /dev/null
+++ b/d_net.c
@@ -1,0 +1,929 @@
+
+//**************************************************************************
+//**
+//** d_net.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 469 $
+//** $Date: 2009-05-26 13:45:39 +0300 (Tue, 26 May 2009) $
+//**
+//** This version has the fixed ticdup code.
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "st_start.h"
+#include "p_local.h"
+
+#define NCMD_EXIT 0x80000000
+#define NCMD_RETRANSMIT 0x40000000
+#define NCMD_SETUP 0x20000000
+#define NCMD_KILL 0x10000000 /* kill game */
+#define NCMD_CHECKSUM 0x0fffffff
+
+
+doomcom_t *doomcom;
+doomdata_t *netbuffer; /* points inside doomcom */
+
+
+/*
+==============================================================================
+
+ NETWORKING
+
+gametic is the tic about to (or currently being) run
+maketic is the tick that hasn't had control made for it yet
+nettics[] has the maketics for all players
+
+a gametic cannot be run until nettics[] > gametic for all players
+
+==============================================================================
+*/
+
+#define RESENDCOUNT 10
+#define PL_DRONE 0x80 /* bit flag in doomdata->player */
+
+ticcmd_t localcmds[BACKUPTICS];
+
+ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
+int nettics[MAXNETNODES];
+
+int maketic;
+int lastnettic, skiptics;
+int ticdup;
+int maxsend; /* BACKUPTICS/(2*ticdup)-1 */
+
+static boolean nodeingame[MAXNETNODES]; /* set false as nodes leave game */
+static boolean remoteresend[MAXNETNODES]; /* set when local needs tics */
+static int resendto[MAXNETNODES]; /* set when remote needs tics */
+static int resendcount[MAXNETNODES];
+
+static int nodeforplayer[MAXPLAYERS];
+
+static boolean reboundpacket;
+static doomdata_t reboundstore;
+
+/* extern functions */
+void H2_ProcessEvents (void);
+void G_BuildTiccmd (ticcmd_t *cmd);
+void H2_DoAdvanceDemo (void);
+
+
+//============================================================================
+
+
+static int NetbufferSize (void)
+{
+ return (int) ((ptrdiff_t)&(((doomdata_t *)0)->cmds[netbuffer->numtics]));
+}
+
+static unsigned int NetbufferChecksum (void)
+{
+ unsigned int c;
+ int i, l;
+
+ c = 0x1234567;
+
+#if defined(NeXT) || defined(NORMALUNIX)
+ return 0; /* byte order problems */
+#endif
+
+ l = NetbufferSize() - (int)((ptrdiff_t)&(((doomdata_t *)0)->retransmitfrom))/4;
+ for (i = 0; i < l; i++)
+ c += ((unsigned int *)&netbuffer->retransmitfrom)[i] * (i + 1);
+
+ return c & NCMD_CHECKSUM;
+}
+
+static int ExpandTics (int low)
+{
+ int delta;
+
+ delta = low - (maketic & 0xff);
+
+ if (delta >= -64 && delta <= 64)
+ return (maketic & ~0xff) + low;
+ if (delta > 64)
+ return (maketic & ~0xff) - 256 + low;
+ if (delta < -64)
+ return (maketic & ~0xff) + 256 + low;
+
+ I_Error ("ExpandTics: strange value %i at maketic %i", low, maketic);
+ return 0;
+}
+
+
+//============================================================================
+
+
+/*
+==============
+=
+= HSendPacket
+=
+==============
+*/
+
+static void HSendPacket (int node, int flags)
+{
+ netbuffer->checksum = NetbufferChecksum () | flags;
+
+ if (!node)
+ {
+ reboundstore = *netbuffer;
+ reboundpacket = true;
+ return;
+ }
+
+ if (demoplayback)
+ return;
+
+ if (!netgame)
+ I_Error ("Tried to transmit to another node");
+
+ doomcom->command = CMD_SEND;
+ doomcom->remotenode = node;
+ doomcom->datalength = NetbufferSize();
+
+ if (debugfile)
+ {
+ int i;
+ int realretrans;
+
+ if (netbuffer->checksum & NCMD_RETRANSMIT)
+ realretrans = ExpandTics (netbuffer->retransmitfrom);
+ else
+ realretrans = -1;
+
+ fprintf (debugfile, "send (%i + %i, R %i) [%i] ",
+ ExpandTics(netbuffer->starttic), netbuffer->numtics,
+ realretrans, doomcom->datalength);
+
+ for (i = 0; i < doomcom->datalength; i++)
+ fprintf (debugfile, "%i ", ((byte *)netbuffer)[i]);
+
+ fprintf (debugfile, "\n");
+ }
+
+ I_NetCmd ();
+}
+
+//==========================================================================
+//
+// NET_SendFrags
+//
+//==========================================================================
+
+void NET_SendFrags(player_t *player)
+{
+ int i;
+ int frags;
+
+ netbuffer->checksum = NetbufferChecksum();
+
+ if (demoplayback)
+ {
+ return;
+ }
+ if (!netgame)
+ {
+ I_Error ("Tried to transmit to another node");
+ }
+
+ frags = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ frags += player->frags[i];
+ }
+ doomcom->command = CMD_FRAG;
+ doomcom->remotenode = frags;
+ doomcom->datalength = NetbufferSize();
+
+ I_NetCmd ();
+}
+
+/*
+==============
+=
+= HGetPacket
+=
+= Returns false if no packet is waiting
+=
+==============
+*/
+
+static boolean HGetPacket (void)
+{
+ if (reboundpacket)
+ {
+ *netbuffer = reboundstore;
+ doomcom->remotenode = 0;
+ reboundpacket = false;
+ return true;
+ }
+
+ if (!netgame)
+ return false;
+ if (demoplayback)
+ return false;
+
+ doomcom->command = CMD_GET;
+ I_NetCmd ();
+ if (doomcom->remotenode == -1)
+ return false;
+
+ if (doomcom->datalength != NetbufferSize())
+ {
+ if (debugfile)
+ fprintf (debugfile, "bad packet length %i\n", doomcom->datalength);
+ return false;
+ }
+
+ if (NetbufferChecksum () != (netbuffer->checksum & NCMD_CHECKSUM))
+ {
+ if (debugfile)
+ fprintf (debugfile, "bad packet checksum\n");
+ return false;
+ }
+
+ if (debugfile)
+ {
+ int realretrans;
+ int i;
+
+ if (netbuffer->checksum & NCMD_SETUP)
+ fprintf (debugfile, "setup packet\n");
+ else
+ {
+ if (netbuffer->checksum & NCMD_RETRANSMIT)
+ realretrans = ExpandTics (netbuffer->retransmitfrom);
+ else
+ realretrans = -1;
+
+ fprintf (debugfile, "get %i = (%i + %i, R %i)[%i] ",
+ doomcom->remotenode, ExpandTics(netbuffer->starttic),
+ netbuffer->numtics, realretrans, doomcom->datalength);
+
+ for (i = 0; i < doomcom->datalength; i++)
+ fprintf (debugfile, "%i ", ((byte *)netbuffer)[i]);
+
+ fprintf (debugfile, "\n");
+ }
+ }
+ return true;
+}
+
+
+/*
+===================
+=
+= GetPackets
+=
+===================
+*/
+
+static char exitmsg[80];
+
+static void GetPackets (void)
+{
+ int netconsole;
+ int netnode;
+ ticcmd_t *src, *dest;
+ int realend;
+ int realstart;
+
+ while (HGetPacket ())
+ {
+ if (netbuffer->checksum & NCMD_SETUP)
+ continue; // extra setup packet
+
+ netconsole = netbuffer->player & ~PL_DRONE;
+ netnode = doomcom->remotenode;
+ //
+ // to save bytes, only the low byte of tic numbers are sent
+ // Figure out what the rest of the bytes are
+ //
+ realstart = ExpandTics (netbuffer->starttic);
+ realend = (realstart + netbuffer->numtics);
+
+ //
+ // check for exiting the game
+ //
+ if (netbuffer->checksum & NCMD_EXIT)
+ {
+ if (!nodeingame[netnode])
+ continue;
+ nodeingame[netnode] = false;
+ playeringame[netconsole] = false;
+ strcpy (exitmsg, "PLAYER 1 LEFT THE GAME");
+ exitmsg[7] += netconsole;
+ P_SetMessage(&players[consoleplayer], exitmsg, true);
+ S_StartSound(NULL, SFX_CHAT);
+ // players[consoleplayer].message = exitmsg;
+ // if (demorecording)
+ // G_CheckDemoStatus ();
+ continue;
+ }
+
+ //
+ // check for a remote game kill
+ //
+ if (netbuffer->checksum & NCMD_KILL)
+ I_Error ("Killed by network driver");
+
+ nodeforplayer[netconsole] = netnode;
+
+ //
+ // check for retransmit request
+ //
+ if (resendcount[netnode] <= 0 && (netbuffer->checksum & NCMD_RETRANSMIT))
+ {
+ resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
+ if (debugfile)
+ fprintf (debugfile, "retransmit from %i\n", resendto[netnode]);
+ resendcount[netnode] = RESENDCOUNT;
+ }
+ else
+ resendcount[netnode]--;
+
+ //
+ // check for out of order / duplicated packet
+ //
+ if (realend == nettics[netnode])
+ continue;
+
+ if (realend < nettics[netnode])
+ {
+ if (debugfile)
+ fprintf (debugfile, "out of order packet (%i + %i)\n", realstart, netbuffer->numtics);
+ continue;
+ }
+
+ //
+ // check for a missed packet
+ //
+ if (realstart > nettics[netnode])
+ {
+ // stop processing until the other system resends the missed tics
+ if (debugfile)
+ fprintf (debugfile, "missed tics from %i (%i - %i)\n", netnode, realstart, nettics[netnode]);
+ remoteresend[netnode] = true;
+ continue;
+ }
+
+ //
+ // update command store from the packet
+ //
+ {
+ int start;
+
+ remoteresend[netnode] = false;
+
+ start = nettics[netnode] - realstart;
+ src = &netbuffer->cmds[start];
+
+ while (nettics[netnode] < realend)
+ {
+ dest = &netcmds[netconsole][nettics[netnode] % BACKUPTICS];
+ nettics[netnode]++;
+ *dest = *src;
+ src++;
+ }
+ }
+ }
+}
+
+/*
+=============
+=
+= NetUpdate
+=
+= Builds ticcmds for console player
+= sends out a packet
+=============
+*/
+
+static int gametime;
+
+void NetUpdate (void)
+{
+ int nowtime;
+ int newtics;
+ int i, j;
+ int realstart;
+ int gameticdiv;
+
+//
+// check time
+//
+ nowtime = I_GetTime()/ticdup;
+ newtics = nowtime - gametime;
+ gametime = nowtime;
+
+ if (newtics <= 0) // nothing new to update
+ goto listen;
+
+ if (skiptics <= newtics)
+ {
+ newtics -= skiptics;
+ skiptics = 0;
+ }
+ else
+ {
+ skiptics -= newtics;
+ newtics = 0;
+ }
+
+ netbuffer->player = consoleplayer;
+
+//
+// build new ticcmds for console player
+//
+ gameticdiv = gametic/ticdup;
+ for (i = 0; i < newtics; i++)
+ {
+ I_StartTic ();
+ H2_ProcessEvents ();
+ if (maketic - gameticdiv >= BACKUPTICS/2 - 1)
+ break; // can't hold any more
+ // printf ("mk:%i ", maketic);
+ G_BuildTiccmd (&localcmds[maketic % BACKUPTICS]);
+ maketic++;
+ }
+
+ if (singletics)
+ return; // singletic update is syncronous
+
+//
+// send the packet to the other nodes
+//
+ for (i = 0; i < doomcom->numnodes; i++)
+ {
+ if (nodeingame[i])
+ {
+ netbuffer->starttic = realstart = resendto[i];
+ netbuffer->numtics = maketic - realstart;
+ if (netbuffer->numtics > BACKUPTICS)
+ I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
+
+ resendto[i] = maketic - doomcom->extratics;
+
+ for (j = 0; j < netbuffer->numtics; j++)
+ netbuffer->cmds[j] = localcmds[(realstart + j) % BACKUPTICS];
+
+ if (remoteresend[i])
+ {
+ netbuffer->retransmitfrom = nettics[i];
+ HSendPacket (i, NCMD_RETRANSMIT);
+ }
+ else
+ {
+ netbuffer->retransmitfrom = 0;
+ HSendPacket (i, 0);
+ }
+ }
+ }
+
+//
+// listen for other packets
+//
+listen:
+
+ GetPackets ();
+}
+
+
+/*
+=====================
+=
+= CheckAbort
+=
+=====================
+*/
+
+static void CheckAbort (void)
+{
+ event_t *ev;
+ int stoptic;
+
+ stoptic = I_GetTime () + 2;
+ while (I_GetTime() < stoptic)
+ I_StartTic ();
+
+ I_StartTic ();
+ while (eventtail != eventhead)
+ {
+ ev = &events[eventtail];
+ if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
+ I_Error ("Network game synchronization aborted.");
+ eventtail = (eventtail + 1) & (MAXEVENTS - 1);
+ }
+}
+
+/*
+=====================
+=
+= D_ArbitrateNetStart
+=
+=====================
+*/
+
+static void D_ArbitrateNetStart (void)
+{
+ int i;
+ boolean gotinfo[MAXNETNODES];
+ boolean gotClass[MAXNETNODES];
+
+ autostart = true;
+
+ memset (gotClass, 0, sizeof(gotClass));
+ memset (gotinfo, 0, sizeof(gotinfo));
+ gotClass[doomcom->consoleplayer] = true;
+
+ do
+ {
+ i = 0;
+
+ CheckAbort();
+ while (HGetPacket())
+ { // Check for any incoming packets
+ if (netbuffer->checksum & NCMD_SETUP && netbuffer->starttic >= 64)
+ {
+ PlayerClasses[netbuffer->player] = netbuffer->starttic & 0x3f;
+ if (!gotClass[netbuffer->player])
+ {
+ gotClass[netbuffer->player] = true;
+ ST_NetProgress();
+ ST_Message("\n");
+ }
+ if (netbuffer->retransmitfrom)
+ { // that node has received info from all other nodes
+ gotinfo[netbuffer->player] = true;
+ }
+ }
+ }
+ // Keep sending out packets containing the console class
+ for (i = 0; i < doomcom->numnodes; i++)
+ {
+ netbuffer->player = doomcom->consoleplayer;
+ netbuffer->starttic = PlayerClasses[doomcom->consoleplayer] + 64;
+ netbuffer->retransmitfrom = gotinfo[doomcom->consoleplayer];
+ netbuffer->numtics = 0;
+ HSendPacket(i, NCMD_SETUP);
+ }
+ for (i = 0; i < doomcom->numnodes; i++)
+ { // Make sure that all nodes have sent class info
+ if (!gotClass[i])
+ {
+ ST_Message(".");
+ break;
+ }
+ }
+ if (i < doomcom->numnodes)
+ {
+ continue;
+ }
+ else
+ { // consoleplayer has received all player classes
+ if (gotinfo[doomcom->consoleplayer])
+ {
+ CheckAbort();
+ }
+ else
+ {
+ gotinfo[doomcom->consoleplayer] = true;
+ ST_Message("All player classes received, ready to proceed\n");
+ ST_NetDone();
+ }
+ }
+ for (i = 0; i < doomcom->numnodes; i++)
+ { // Make sure that all nodes are ready to proceed
+ if (!gotinfo[i])
+ {
+ break;
+ }
+ }
+ } while (i < doomcom->numnodes);
+
+ memset (gotinfo, 0, sizeof(gotinfo));
+
+ if (doomcom->consoleplayer)
+ { // listen for setup info from key player
+ // ST_Message ("listening for network start info...\n");
+ while (1)
+ {
+ CheckAbort ();
+ if (!HGetPacket ())
+ continue;
+ if (netbuffer->checksum & NCMD_SETUP && netbuffer->starttic < 64)
+ {
+ if (netbuffer->player != VERSION)
+ I_Error ("Different HEXEN versions cannot play a net game!");
+ startskill = netbuffer->retransmitfrom & 15;
+ deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6;
+ nomonsters = (netbuffer->retransmitfrom & 0x20) > 0;
+ respawnparm = (netbuffer->retransmitfrom & 0x10) > 0;
+ startmap = netbuffer->starttic & 0x3f;
+ startepisode = 1;
+ return;
+ }
+ }
+ }
+ else
+ { // key player, send the setup info
+ // ST_Message ("sending network start info...\n");
+ do
+ {
+ CheckAbort ();
+ for (i = 0; i < doomcom->numnodes; i++)
+ {
+ netbuffer->retransmitfrom = startskill;
+ if (deathmatch)
+ netbuffer->retransmitfrom |= (deathmatch << 6);
+ if (nomonsters)
+ netbuffer->retransmitfrom |= 0x20;
+ if (respawnparm)
+ netbuffer->retransmitfrom |= 0x10;
+ netbuffer->starttic = startmap & 0x3f;
+ netbuffer->player = VERSION;
+ netbuffer->numtics = 0;
+ HSendPacket (i, NCMD_SETUP);
+ }
+
+#if 1
+ for (i = 10; i && HGetPacket(); --i)
+ {
+ if ((netbuffer->player & 0x7f) < MAXNETNODES)
+ gotinfo[netbuffer->player & 0x7f] = true;
+ }
+#else
+ while (HGetPacket ())
+ {
+ gotinfo[netbuffer->player & 0x7f] = true;
+ }
+#endif
+
+ for (i = 1; i < doomcom->numnodes; i++)
+ {
+ if (!gotinfo[i])
+ break;
+ }
+ } while (i < doomcom->numnodes);
+ }
+}
+
+/*
+===================
+=
+= D_CheckNetGame
+=
+= Works out player numbers among the net participants
+===================
+*/
+
+extern int viewangleoffset;
+
+void D_CheckNetGame (void)
+{
+ int i;
+ int pClass;
+
+ for (i = 0; i < MAXNETNODES; i++)
+ {
+ nodeingame[i] = false;
+ nettics[i] = 0;
+ remoteresend[i] = false; // set when local needs tics
+ resendto[i] = 0; // which tic to start sending
+ }
+
+// I_InitNetwork sets doomcom and netgame
+ I_InitNetwork ();
+ if (doomcom->id != DOOMCOM_ID)
+ I_Error ("Doomcom buffer invalid!");
+ netbuffer = &doomcom->data;
+ consoleplayer = displayplayer = doomcom->consoleplayer;
+ pClass = PCLASS_FIGHTER;
+ if ((i = M_CheckParm("-class")))
+ {
+ pClass = atoi(myargv[i + 1]);
+ if (pClass > PCLASS_MAGE || pClass < PCLASS_FIGHTER)
+ {
+ I_Error("Invalid player class: %d\n", pClass);
+ }
+ ST_Message("\nPlayer Class: %d\n", pClass);
+ }
+ PlayerClasses[consoleplayer] = pClass;
+ if (netgame)
+ D_ArbitrateNetStart ();
+
+// ST_Message ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
+// startskill, deathmatch, startmap, startepisode);
+
+// read values out of doomcom
+ ticdup = doomcom->ticdup;
+ maxsend = BACKUPTICS / (2*ticdup) - 1;
+ if (maxsend < 1)
+ maxsend = 1;
+
+ for (i = 0; i < doomcom->numplayers; i++)
+ playeringame[i] = true;
+ for (i = 0; i < doomcom->numnodes; i++)
+ nodeingame[i] = true;
+
+// ST_Message ("player %i of %i (%i nodes)\n",
+// consoleplayer + 1, doomcom->numplayers, doomcom->numnodes);
+}
+
+/*
+==================
+=
+= D_QuitNetGame
+=
+= Called before quitting to leave a net game without hanging the
+= other players
+=
+==================
+*/
+
+void D_QuitNetGame (void)
+{
+ int i, j;
+
+ if (debugfile)
+ fclose (debugfile);
+
+ if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
+ return;
+
+// send a bunch of packets for security
+ netbuffer->player = consoleplayer;
+ netbuffer->numtics = 0;
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 1; j < doomcom->numnodes; j++)
+ {
+ if (nodeingame[j])
+ HSendPacket (j, NCMD_EXIT);
+ }
+ I_WaitVBL (1);
+ }
+}
+
+
+/*
+===============
+=
+= TryRunTics
+=
+===============
+*/
+
+int frametics[4], frameon;
+int frameskip[4];
+int oldnettics;
+extern boolean advancedemo;
+
+void TryRunTics (void)
+{
+ int i;
+ int lowtic;
+ int entertic;
+ static int oldentertics;
+ int realtics, availabletics;
+ int counts;
+ int numplaying;
+
+//
+// get real tics
+//
+ entertic = I_GetTime () / ticdup;
+ realtics = entertic - oldentertics;
+ oldentertics = entertic;
+
+//
+// get available tics
+//
+ NetUpdate ();
+
+ lowtic = H2MAXINT;
+ numplaying = 0;
+ for (i = 0; i < doomcom->numnodes; i++)
+ {
+ if (nodeingame[i])
+ {
+ numplaying++;
+ if (nettics[i] < lowtic)
+ lowtic = nettics[i];
+ }
+ }
+ availabletics = lowtic - gametic/ticdup;
+
+//
+// decide how many tics to run
+//
+ if (realtics < availabletics - 1)
+ counts = realtics + 1;
+ else if (realtics < availabletics)
+ counts = realtics;
+ else
+ counts = availabletics;
+ if (counts < 1)
+ counts = 1;
+
+ frameon++;
+
+ if (debugfile)
+ fprintf (debugfile, "=======real: %i avail: %i game: %i\n", realtics, availabletics, counts);
+
+ if (!demoplayback)
+ {
+ // ideally nettics[0] should be 1 - 3 tics above lowtic
+ // if we are consistantly slower, speed up time
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ break;
+ }
+ if (consoleplayer == i)
+ {
+ // the key player does not adapt
+ }
+ else
+ {
+ if (nettics[0] <= nettics[nodeforplayer[i]])
+ {
+ gametime--;
+ // printf ("-");
+ }
+ frameskip[frameon & 3] = (oldnettics > nettics[nodeforplayer[i]]);
+ oldnettics = nettics[0];
+ if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
+ {
+ skiptics = 1;
+ // printf ("+");
+ }
+ }
+ }
+
+ //
+ // wait for new tics if needed
+ //
+ while (lowtic < gametic/ticdup + counts)
+ {
+ NetUpdate ();
+ lowtic = H2MAXINT;
+
+ for (i = 0; i < doomcom->numnodes; i++)
+ {
+ if (nodeingame[i] && nettics[i] < lowtic)
+ lowtic = nettics[i];
+ }
+
+ if (lowtic < gametic / ticdup)
+ I_Error ("TryRunTics: lowtic < gametic");
+
+ // don't stay in here forever -- give the menu a chance to work
+ if (I_GetTime() / ticdup - entertic >= 20)
+ {
+ MN_Ticker ();
+ return;
+ }
+ }
+
+//
+// run the count * ticdup dics
+//
+ while (counts--)
+ {
+ for (i = 0; i < ticdup; i++)
+ {
+ if (gametic / ticdup > lowtic)
+ I_Error ("gametic>lowtic");
+ if (advancedemo)
+ H2_DoAdvanceDemo ();
+ MN_Ticker ();
+ G_Ticker ();
+ gametic++;
+ //
+ // modify command for duplicated tics
+ //
+ if (i != ticdup - 1)
+ {
+ ticcmd_t *cmd;
+ int buf;
+ int j;
+
+ buf = (gametic / ticdup) % BACKUPTICS;
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ cmd = &netcmds[j][buf];
+ cmd->chatchar = 0;
+ if (cmd->buttons & BT_SPECIAL)
+ cmd->buttons = 0;
+ }
+ }
+ }
+ NetUpdate (); // check for new console commands
+ }
+}
+
--- /dev/null
+++ b/f_finale.c
@@ -1,0 +1,413 @@
+
+//**************************************************************************
+//**
+//** f_finale.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 458 $
+//** $Date: 2009-05-25 15:35:27 +0300 (Mon, 25 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "soundst.h"
+#include "p_local.h"
+#include "v_compat.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define TEXTSPEED 3
+#define TEXTWAIT 250
+
+#ifdef RENDER3D
+#define V_DrawPatch(x,y,p) OGL_DrawPatch((x),(y),(p))
+#define V_DrawRawScreen(a) OGL_DrawRawScreen((a))
+#endif
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void TextWrite(void);
+static void DrawPic(void);
+
+#ifdef RENDER3D
+static void FadeIn (void);
+static void FadeOut(void);
+#define InitializeFade(x) do {} while (0)
+#define DeInitializeFade() do {} while (0)
+#define FadePic() do {} while (0)
+#else
+#define FadeIn() do {} while (0)
+#define FadeOut() do {} while (0)
+static void InitializeFade(boolean fadeIn);
+static void DeInitializeFade(void);
+static void FadePic(void);
+#endif
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern boolean viewactive;
+
+// PUBLIC DATA DECLARATIONS ------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int FinaleStage;
+static int FinaleCount;
+static int FinaleEndCount;
+static int FinaleLumpNum;
+static int FontABaseLump;
+static const char *FinaleText;
+
+#ifndef RENDER3D
+static fixed_t *Palette;
+static fixed_t *PaletteDelta;
+static byte *RealPalette;
+#endif
+
+// CODE --------------------------------------------------------------------
+
+//===========================================================================
+//
+// F_StartFinale
+//
+//===========================================================================
+
+void F_StartFinale (void)
+{
+ gameaction = ga_nothing;
+ gamestate = GS_FINALE;
+ viewactive = false;
+ automapactive = false;
+ P_ClearMessage(&players[consoleplayer]);
+
+ FinaleStage = 0;
+ FinaleCount = 0;
+ FinaleText = GetFinaleText(0);
+ FinaleEndCount = 70;
+ FinaleLumpNum = W_GetNumForName("FINALE1");
+ FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+ InitializeFade(1);
+#ifdef RENDER3D
+ OGL_SetFilter(0);
+#endif
+// S_ChangeMusic(mus_victor, true);
+ S_StartSongName("hall", false); // don't loop the song
+}
+
+//===========================================================================
+//
+// F_Responder
+//
+//===========================================================================
+
+boolean F_Responder(event_t *event)
+{
+ return false;
+}
+
+//===========================================================================
+//
+// F_Ticker
+//
+//===========================================================================
+
+void F_Ticker (void)
+{
+ FinaleCount++;
+ if (FinaleStage < 5 && FinaleCount >= FinaleEndCount)
+ {
+ FinaleCount = 0;
+ FinaleStage++;
+ switch (FinaleStage)
+ {
+ case 1: // Text 1
+ FinaleEndCount = strlen(FinaleText)*TEXTSPEED + TEXTWAIT;
+ break;
+ case 2: // Pic 2, Text 2
+ FinaleText = GetFinaleText(1);
+ FinaleEndCount = strlen(FinaleText)*TEXTSPEED + TEXTWAIT;
+ FinaleLumpNum = W_GetNumForName("FINALE2");
+ S_StartSongName("orb", false);
+ break;
+ case 3: // Pic 2 -- Fade out
+ FinaleEndCount = 70;
+ DeInitializeFade();
+ InitializeFade(0);
+ break;
+ case 4: // Pic 3 -- Fade in
+ FinaleLumpNum = W_GetNumForName("FINALE3");
+ FinaleEndCount = 71;
+ DeInitializeFade();
+ InitializeFade(1);
+ S_StartSongName("chess", true);
+ break;
+ case 5: // Pic 3 , Text 3
+ FinaleText = GetFinaleText(2);
+ DeInitializeFade();
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+ if (FinaleStage == 0 || FinaleStage == 3 || FinaleStage == 4)
+ {
+ FadePic();
+ }
+}
+
+//===========================================================================
+//
+// TextWrite
+//
+//===========================================================================
+
+static void TextWrite (void)
+{
+ int count;
+ const char *ch;
+ int c;
+ int cx, cy;
+ patch_t *w;
+ int width;
+
+ V_DrawRawScreen((BYTE_REF) WR_CacheLumpNum(FinaleLumpNum, PU_CACHE));
+
+ if (FinaleStage == 5)
+ { // Chess pic, draw the correct character graphic
+ if (netgame)
+ {
+ V_DrawPatch(20, 0, (PATCH_REF)WR_CacheLumpName("chessall", PU_CACHE));
+ }
+#ifdef ASSASSIN
+ else if (PlayerClasses[consoleplayer] == PCLASS_ASS)
+ {
+ V_DrawPatch(60, 0, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("chessa"), PU_CACHE));
+ }
+#endif
+ else if (PlayerClasses[consoleplayer])
+ {
+ V_DrawPatch(60, 0, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("chessc")
+ + PlayerClasses[consoleplayer] - 1, PU_CACHE));
+ }
+ }
+ // Draw the actual text
+ if (FinaleStage == 5)
+ {
+ cy = 135;
+ }
+ else
+ {
+ cy = 5;
+ }
+ cx = 20;
+ ch = FinaleText;
+ count = (FinaleCount - 10) / TEXTSPEED;
+ if (count < 0)
+ {
+ count = 0;
+ }
+ for ( ; count; count--)
+ {
+ c = *ch++;
+ if (!c)
+ {
+ break;
+ }
+ if (c == '\n')
+ {
+ cx = 20;
+ cy += 9;
+ continue;
+ }
+ if (c < 32)
+ {
+ continue;
+ }
+ c = toupper(c);
+ if (c == 32)
+ {
+ cx += 5;
+ continue;
+ }
+ w = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ width = SHORT(w->width);
+ if (cx + width > SCREENWIDTH)
+ {
+ break;
+ }
+#ifdef RENDER3D
+ OGL_DrawPatch_CS(cx, cy, FontABaseLump + c - 33);
+#else
+ V_DrawPatch(cx, cy, w);
+#endif
+ cx += width;
+ }
+}
+
+//===========================================================================
+//
+// InitializeFade
+//
+//===========================================================================
+
+#if !defined(RENDER3D)
+static void InitializeFade(boolean fadeIn)
+{
+ unsigned i;
+
+ Palette = (fixed_t *) Z_Malloc(768*sizeof(fixed_t), PU_STATIC, NULL);
+ PaletteDelta = (fixed_t *) Z_Malloc(768*sizeof(fixed_t), PU_STATIC, NULL);
+ RealPalette = (byte *) Z_Malloc(768*sizeof(byte), PU_STATIC, NULL);
+
+ if (fadeIn)
+ {
+ memset(RealPalette, 0, 768*sizeof(byte));
+ for (i = 0; i < 768; i++)
+ {
+ Palette[i] = 0;
+ PaletteDelta[i] = FixedDiv((*((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE) + i))<<FRACBITS, 70*FRACUNIT);
+ }
+ }
+ else
+ {
+ for (i = 0; i < 768; i++)
+ {
+ RealPalette[i] = *((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE) + i);
+ Palette[i] = RealPalette[i]<<FRACBITS;
+ PaletteDelta[i] = FixedDiv(Palette[i], -70*FRACUNIT);
+ }
+ }
+ I_SetPalette(RealPalette);
+}
+
+//===========================================================================
+//
+// DeInitializeFade
+//
+//===========================================================================
+
+static void DeInitializeFade(void)
+{
+ Z_Free(Palette);
+ Z_Free(PaletteDelta);
+ Z_Free(RealPalette);
+}
+
+//===========================================================================
+//
+// FadePic
+//
+//===========================================================================
+
+static void FadePic(void)
+{
+ unsigned i;
+
+ for (i = 0; i < 768; i++)
+ {
+ Palette[i] += PaletteDelta[i];
+ RealPalette[i] = Palette[i]>>FRACBITS;
+ }
+ I_SetPalette(RealPalette);
+}
+
+#else /* ! RENDER3D */
+
+/* For OpenGL: adapted from the Vavoom project.
+ *
+ * The FinaleCount / FinaleEndCount tick rates seem to work fine
+ * for us here: for FinaleStage 0, 3 and 4, where this code is
+ * used, FinaleEndCount is set to 70 or 71, FinaleCount is reset
+ * to 0 and incremented at every tick, and this gives us about 2
+ * seconds of fade-in/fade-out.
+ */
+static void FadeOut (void)
+{
+ float fade = (float)FinaleCount / (float)FinaleEndCount;
+
+ if (fade < 0.0)
+ fade = 0.0;
+ if (fade > 0.99)
+ fade = 0.99;
+ OGL_ShadeRect(0, 0, 320, 200, fade);
+}
+
+static void FadeIn (void)
+{
+ float fade = 1.0 - (float)FinaleCount / (float)FinaleEndCount;
+
+ if (fade < 0.0)
+ fade = 0.0;
+ if (fade > 0.99)
+ fade = 0.99;
+ OGL_ShadeRect(0, 0, 320, 200, fade);
+}
+#endif /* ! RENDER3D */
+
+//===========================================================================
+//
+// DrawPic
+//
+//===========================================================================
+
+static void DrawPic(void)
+{
+ V_DrawRawScreen((BYTE_REF) WR_CacheLumpNum(FinaleLumpNum, PU_CACHE));
+
+ if (FinaleStage == 4 || FinaleStage == 5)
+ { // Chess pic, draw the correct character graphic
+ if (netgame)
+ {
+ V_DrawPatch(20, 0, (PATCH_REF)WR_CacheLumpName("chessall", PU_CACHE));
+ }
+ else if (PlayerClasses[consoleplayer])
+ {
+ V_DrawPatch(60, 0, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("chessc")
+ + PlayerClasses[consoleplayer] - 1, PU_CACHE));
+ }
+ }
+}
+
+//===========================================================================
+//
+// F_Drawer
+//
+//===========================================================================
+
+void F_Drawer(void)
+{
+ switch (FinaleStage)
+ {
+ case 0: // Fade in initial finale screen
+ DrawPic();
+ FadeIn();
+ break;
+ case 1:
+ case 2:
+ TextWrite();
+ break;
+ case 3: // Fade screen out
+ DrawPic();
+ FadeOut();
+ break;
+ case 4: // Fade in chess screen
+ DrawPic();
+ FadeIn();
+ break;
+ case 5:
+ TextWrite();
+ break;
+ }
+ UpdateState |= I_FULLSCRN;
+}
+
--- /dev/null
+++ b/g_game.c
@@ -1,0 +1,1883 @@
+
+//**************************************************************************
+//**
+//** g_game.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 584 $
+//** $Date: 2012-02-17 12:01:51 +0200 (Fri, 17 Feb 2012) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+#define AM_STARTKEY 9
+
+// External functions
+
+extern void R_InitSky(int map);
+extern void P_PlayerNextArtifact(player_t *player);
+
+// Functions
+
+boolean G_CheckDemoStatus (void);
+static void G_ReadDemoTiccmd (ticcmd_t *cmd);
+static void G_WriteDemoTiccmd (ticcmd_t *cmd);
+
+void G_InitNew (skill_t skill, int episode, int map);
+
+static void G_DoReborn (int playernum);
+
+static void G_DoLoadLevel(void);
+static void G_DoInitNew(void);
+static void G_DoNewGame(void);
+
+void G_DoLoadGame(void);
+static void G_DoPlayDemo(void);
+static void G_DoTeleportNewMap(void);
+static void G_DoCompleted(void);
+static void G_DoWorldDone(void);
+static void G_DoSaveGame(void);
+static void G_DoSingleReborn(void);
+
+void H2_PageTicker(void);
+void H2_AdvanceDemo(void);
+
+extern boolean mn_SuicideConsole;
+
+gameaction_t gameaction;
+gamestate_t gamestate;
+skill_t gameskill;
+int gameepisode;
+int gamemap;
+int prevmap;
+
+boolean paused;
+
+boolean usergame; // ok to save / end game
+
+static boolean sendpause; // send a pause event next tic
+static boolean sendsave; // send a save event next tic
+
+static boolean timingdemo; // if true, exit with report on completion
+static int starttime; // for comparative timing purposes
+
+boolean viewactive;
+
+boolean deathmatch; // only if started as net death
+boolean netgame; // only true if packets are broadcast
+boolean playeringame[MAXPLAYERS];
+player_t players[MAXPLAYERS];
+pclass_t PlayerClasses[MAXPLAYERS];
+
+// Position indicator for cooperative net-play reborn
+int RebornPosition;
+
+int consoleplayer; // player taking events and displaying
+int displayplayer; // view being displayed
+int gametic;
+int levelstarttic; // gametic at level start
+
+boolean demorecording;
+boolean demoplayback;
+boolean singledemo; // quit after playing a demo from cmdline
+static byte *demobuffer, *demo_p;
+static char demoname[MAX_OSPATH];
+
+static short consistancy[MAXPLAYERS][BACKUPTICS];
+
+boolean precache = true; // if true, load all graphics at start
+
+//
+// controls (have defaults)
+//
+int key_right, key_left, key_up, key_down;
+int key_strafeleft, key_straferight, key_jump;
+int key_fire, key_use, key_strafe, key_speed;
+int key_flyup, key_flydown, key_flycenter;
+int key_lookup, key_lookdown, key_lookcenter;
+int key_invleft, key_invright, key_useartifact;
+
+int mouselook;
+int alwaysrun; /* boolean */
+
+int mousebfire;
+int mousebstrafe;
+int mousebforward;
+int mousebjump;
+
+int joybfire;
+int joybstrafe;
+int joybuse;
+int joybspeed;
+int joybjump;
+
+int LeaveMap;
+static int LeavePosition;
+
+//#define MAXPLMOVE 0x32 // Old Heretic Max move
+
+static fixed_t MaxPlayerMove[NUMCLASSES] =
+{
+ 0x3C,
+ 0x32,
+ 0x2D,
+#ifdef ASSASSIN
+ 0x3D,
+#endif
+ 0x31
+};
+
+static fixed_t forwardmove[NUMCLASSES][2] =
+{
+ { 0x1D, 0x3C },
+ { 0x19, 0x32 },
+ { 0x16, 0x2E },
+#ifdef ASSASSIN
+ { 0x17, 0x3D },
+#endif
+ { 0x18, 0x31 }
+};
+
+static fixed_t sidemove[NUMCLASSES][2] =
+{
+ { 0x1B, 0x3B },
+ { 0x18, 0x28 },
+ { 0x15, 0x25 },
+#ifdef ASSASSIN
+ { 0x16, 0x3C },
+#endif
+ { 0x17, 0x27 }
+};
+
+static fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn
+#define SLOWTURNTICS 6
+
+boolean gamekeydown[MAXKEYS];
+static int turnheld; // for accelerative turning
+static int lookheld;
+
+static boolean mousearray[4];
+static boolean *mousebuttons = &mousearray[1]; // allow [-1]
+
+static int mousex, mousey; // mouse values are used once
+static int dclicktime, dclickstate, dclicks;
+static int dclicktime2, dclickstate2, dclicks2;
+
+static int joyxmove, joyymove; // joystick values are repeated
+static boolean joyarray[5];
+static boolean *joybuttons = &joyarray[1]; // allow [-1]
+
+static int loadgameslot;
+static int savegameslot;
+static char savedescription[32];
+
+static int inventoryTics;
+
+boolean usearti = true;
+
+static skill_t TempSkill;
+static int TempEpisode;
+static int TempMap;
+
+//=============================================================================
+
+/*
+====================
+=
+= G_BuildTiccmd
+=
+= Builds a ticcmd from all of the available inputs or reads it from the
+= demo buffer.
+= If recording a demo, write it out
+====================
+*/
+
+extern boolean inventory;
+extern boolean artiskip;
+extern int curpos;
+extern int inv_ptr;
+
+void G_BuildTiccmd (ticcmd_t *cmd)
+{
+ int i;
+ boolean strafe, bstrafe;
+ int speed, tspeed, lspeed;
+ int forward, side;
+ int look, arti;
+ int flyheight;
+ int pClass;
+
+ pClass = players[consoleplayer].playerclass;
+ memset (cmd, 0, sizeof(*cmd));
+
+// cmd->consistancy =
+// consistancy[consoleplayer][(maketic*ticdup)%BACKUPTICS];
+
+ cmd->consistancy =
+ consistancy[consoleplayer][maketic%BACKUPTICS];
+
+//printf ("cons: %i\n",cmd->consistancy);
+ strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
+ speed = gamekeydown[key_speed] || joybuttons[joybspeed] || joybuttons[joybspeed];
+ if (alwaysrun && !demoplayback && !demorecording)
+ speed = !speed;
+ forward = side = look = arti = flyheight = 0;
+
+//
+// use two stage accelerative turning on the keyboard and joystick
+//
+ if (joyxmove < 0 || joyxmove > 0 || gamekeydown[key_right] || gamekeydown[key_left])
+ turnheld += ticdup;
+ else
+ turnheld = 0;
+ if (turnheld < SLOWTURNTICS)
+ tspeed = 2; // slow turn
+ else
+ tspeed = speed;
+
+ if (gamekeydown[key_lookdown] || gamekeydown[key_lookup])
+ {
+ lookheld += ticdup;
+ }
+ else
+ {
+ lookheld = 0;
+ }
+ if (lookheld < SLOWTURNTICS)
+ {
+ lspeed = 1; // 3;
+ }
+ else
+ {
+ lspeed = 2; // 5;
+ }
+
+//
+// let movement keys cancel each other out
+//
+ if (strafe)
+ {
+ if (gamekeydown[key_right])
+ {
+ side += sidemove[pClass][speed];
+ }
+ if (gamekeydown[key_left])
+ {
+ side -= sidemove[pClass][speed];
+ }
+ if (joyxmove > 0)
+ {
+ side += sidemove[pClass][speed];
+ }
+ if (joyxmove < 0)
+ {
+ side -= sidemove[pClass][speed];
+ }
+ }
+ else
+ {
+ if (gamekeydown[key_right])
+ cmd->angleturn -= angleturn[tspeed];
+ if (gamekeydown[key_left])
+ cmd->angleturn += angleturn[tspeed];
+ if (joyxmove > 0)
+ cmd->angleturn -= angleturn[tspeed];
+ if (joyxmove < 0)
+ cmd->angleturn += angleturn[tspeed];
+ }
+
+ if (gamekeydown[key_up])
+ {
+ forward += forwardmove[pClass][speed];
+ }
+ if (gamekeydown[key_down])
+ {
+ forward -= forwardmove[pClass][speed];
+ }
+ if (joyymove < 0)
+ {
+ forward += forwardmove[pClass][speed];
+ }
+ if (joyymove > 0)
+ {
+ forward -= forwardmove[pClass][speed];
+ }
+ if (gamekeydown[key_straferight])
+ {
+ side += sidemove[pClass][speed];
+ }
+ if (gamekeydown[key_strafeleft])
+ {
+ side -= sidemove[pClass][speed];
+ }
+
+ // Look up/down/center keys
+ if (gamekeydown[key_lookup])
+ {
+ look = lspeed;
+ }
+ if (gamekeydown[key_lookdown])
+ {
+ look = -lspeed;
+ }
+ if (gamekeydown[key_lookcenter])
+ {
+ look = TOCENTER;
+ }
+
+ // Fly up/down/drop keys
+ if (gamekeydown[key_flyup])
+ {
+ flyheight = 5; // note that the actual flyheight will be twice this
+ }
+ if (gamekeydown[key_flydown])
+ {
+ flyheight = -5;
+ }
+ if (gamekeydown[key_flycenter])
+ {
+ flyheight = TOCENTER;
+ look = TOCENTER;
+ }
+ // Use artifact key
+ if (gamekeydown[key_useartifact])
+ {
+ if (gamekeydown[key_speed] && artiskip)
+ {
+ if (players[consoleplayer].inventory[inv_ptr].type != arti_none)
+ { // Skip an artifact
+ gamekeydown[key_useartifact] = false;
+ P_PlayerNextArtifact(&players[consoleplayer]);
+ }
+ }
+ else
+ {
+ if (inventory)
+ {
+ players[consoleplayer].readyArtifact =
+ players[consoleplayer].inventory[inv_ptr].type;
+ inventory = false;
+ cmd->arti = 0;
+ usearti = false;
+ }
+ else if (usearti)
+ {
+ cmd->arti |=
+ players[consoleplayer].inventory[inv_ptr].type&AFLAG_MASK;
+ usearti = false;
+ }
+ }
+ }
+ if (gamekeydown[key_jump] || mousebuttons[mousebjump] || joybuttons[joybjump])
+ {
+ cmd->arti |= AFLAG_JUMP;
+ }
+ if (mn_SuicideConsole)
+ {
+ cmd->arti |= AFLAG_SUICIDE;
+ mn_SuicideConsole = false;
+ }
+
+ // Artifact hot keys
+ if (gamekeydown[KEY_BACKSPACE] && !cmd->arti)
+ {
+ gamekeydown[KEY_BACKSPACE] = false; // Use one of each artifact
+ cmd->arti = NUMARTIFACTS;
+ }
+ else if (gamekeydown[KEY_BACKSLASH] && !cmd->arti && (players[consoleplayer].mo->health < MAXHEALTH))
+ {
+ gamekeydown[KEY_BACKSLASH] = false;
+ cmd->arti = arti_health;
+ }
+ else if (gamekeydown[KEY_ZERO] && !cmd->arti)
+ {
+ gamekeydown[KEY_ZERO] = false;
+ cmd->arti = arti_poisonbag;
+ }
+ else if (gamekeydown[KEY_NINE] && !cmd->arti)
+ {
+ gamekeydown[KEY_NINE] = false;
+ cmd->arti = arti_blastradius;
+ }
+ else if (gamekeydown[KEY_EIGHT] && !cmd->arti)
+ {
+ gamekeydown[KEY_EIGHT] = false;
+ cmd->arti = arti_teleport;
+ }
+ else if (gamekeydown[KEY_SEVEN] && !cmd->arti)
+ {
+ gamekeydown[KEY_SEVEN] = false;
+ cmd->arti = arti_teleportother;
+ }
+ else if (gamekeydown[KEY_SIX] && !cmd->arti)
+ {
+ gamekeydown[KEY_SIX] = false;
+ cmd->arti = arti_egg;
+ }
+ else if (gamekeydown[KEY_FIVE] && !cmd->arti && !players[consoleplayer].powers[pw_invulnerability])
+ {
+ gamekeydown[KEY_FIVE] = false;
+ cmd->arti = arti_invulnerability;
+ }
+
+//
+// buttons
+//
+ cmd->chatchar = CT_dequeueChatChar();
+ if (gamekeydown[key_fire] || mousebuttons[mousebfire]
+ || joybuttons[joybfire])
+ cmd->buttons |= BT_ATTACK;
+
+ if (gamekeydown[key_use] || joybuttons[joybuse] )
+ {
+ cmd->buttons |= BT_USE;
+ dclicks = 0; // clear double clicks if hit use button
+ }
+
+ for (i = 0; i < NUMWEAPONS; i++)
+ {
+ if (gamekeydown['1'+i])
+ {
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i<<BT_WEAPONSHIFT;
+ break;
+ }
+ }
+
+//
+// mouse
+//
+#if 0
+ printf ("%d %d %d %d <%d %d>\n",
+ mousebuttons[mousebfire], mousebuttons[mousebforward],
+ mousebuttons[mousebjump], mousebuttons[mousebstrafe],
+ mousex, mousey);
+#endif
+ if (mousebuttons[mousebforward])
+ {
+ forward += forwardmove[pClass][speed];
+ }
+
+//
+// forward double click
+//
+ if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1)
+ {
+ dclickstate = mousebuttons[mousebforward];
+ if (dclickstate)
+ dclicks++;
+ if (dclicks == 2)
+ {
+ cmd->buttons |= BT_USE;
+ dclicks = 0;
+ }
+ else
+ dclicktime = 0;
+ }
+ else
+ {
+ dclicktime += ticdup;
+ if (dclicktime > 20)
+ {
+ dclicks = 0;
+ dclickstate = 0;
+ }
+ }
+
+//
+// strafe double click
+//
+ bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
+ if (bstrafe != dclickstate2 && dclicktime2 > 1)
+ {
+ dclickstate2 = bstrafe;
+ if (dclickstate2)
+ dclicks2++;
+ if (dclicks2 == 2)
+ {
+ cmd->buttons |= BT_USE;
+ dclicks2 = 0;
+ }
+ else
+ dclicktime2 = 0;
+ }
+ else
+ {
+ dclicktime2 += ticdup;
+ if (dclicktime2 > 20)
+ {
+ dclicks2 = 0;
+ dclickstate2 = 0;
+ }
+ }
+ if (strafe)
+ {
+ side += mousex*2;
+ }
+ else
+ {
+ cmd->angleturn -= mousex*0x8;
+ }
+
+ if (demorecording || demoplayback || (mouselook == 0))
+ {
+ forward += mousey;
+ }
+ else if (mousey && !paused) /* mouselook, but not when paused */
+ {
+ /* We'll directly change the viewing pitch of the console player. */
+ float adj = ((mousey*0x4) << 16) / (float) ANGLE_180*180*110.0/85.0;
+ float newlookdir = 0; /* jim initialiser added to prevent warning */
+
+ adj *= 2; /* Speed up the X11 mlook a little. */
+
+ if (mouselook == 1)
+ newlookdir = players[consoleplayer].lookdir + adj;
+ else if (mouselook == 2)
+ newlookdir = players[consoleplayer].lookdir - adj;
+
+ // vertical view angle taken from p_user.c line 249.
+ if (newlookdir > 90)
+ newlookdir = 90;
+ else if (newlookdir < -110)
+ newlookdir = -110;
+
+ players[consoleplayer].lookdir = newlookdir;
+ }
+
+ mousex = mousey = 0;
+
+ if (forward > MaxPlayerMove[pClass])
+ {
+ forward = MaxPlayerMove[pClass];
+ }
+ else if (forward < -MaxPlayerMove[pClass])
+ {
+ forward = -MaxPlayerMove[pClass];
+ }
+ if (side > MaxPlayerMove[pClass])
+ {
+ side = MaxPlayerMove[pClass];
+ }
+ else if (side < -MaxPlayerMove[pClass])
+ {
+ side = -MaxPlayerMove[pClass];
+ }
+ if (players[consoleplayer].powers[pw_speed] && !players[consoleplayer].morphTics)
+ { // Adjust for a player with a speed artifact
+ forward = (3*forward)>>1;
+ side = (3*side)>>1;
+ }
+ cmd->forwardmove += forward;
+ cmd->sidemove += side;
+ if (players[consoleplayer].playerstate == PST_LIVE)
+ {
+ if (look < 0)
+ {
+ look += 16;
+ }
+ cmd->lookfly = look;
+ }
+ if (flyheight < 0)
+ {
+ flyheight += 16;
+ }
+ cmd->lookfly |= flyheight<<4;
+
+//
+// special buttons
+//
+ if (sendpause)
+ {
+ sendpause = false;
+ cmd->buttons = BT_SPECIAL | BTS_PAUSE;
+ }
+ if (sendsave)
+ {
+ sendsave = false;
+ cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<<BTS_SAVESHIFT);
+ }
+}
+
+
+/*
+==============
+=
+= G_DoLoadLevel
+=
+==============
+*/
+
+static void G_DoLoadLevel (void)
+{
+ int i;
+
+ levelstarttic = gametic; // for time calculation
+ gamestate = GS_LEVEL;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i] && players[i].playerstate == PST_DEAD)
+ players[i].playerstate = PST_REBORN;
+ memset (players[i].frags, 0, sizeof(players[i].frags));
+ }
+
+ SN_StopAllSequences();
+ P_SetupLevel (gameepisode, gamemap, 0, gameskill);
+ displayplayer = consoleplayer; // view the guy you are playing
+ starttime = I_GetTime ();
+ gameaction = ga_nothing;
+ Z_CheckHeap ();
+
+//
+// clear cmd building stuff
+//
+ memset (gamekeydown, 0, sizeof(gamekeydown));
+ joyxmove = joyymove = 0;
+ mousex = mousey = 0;
+ sendpause = sendsave = paused = false;
+// memset (mousebuttons, 0, sizeof(mousebuttons));
+// memset (joybuttons, 0, sizeof(joybuttons));
+ memset (joyarray, 0, sizeof(joyarray));
+ memset (mousearray, 0, sizeof(mousearray));
+}
+
+
+/*
+===============================================================================
+=
+= G_Responder
+=
+= get info needed to make ticcmd_ts for the players
+=
+===============================================================================
+*/
+
+boolean G_Responder(event_t *ev)
+{
+ player_t *plr;
+ extern boolean MenuActive;
+
+ plr = &players[consoleplayer];
+ if (ev->type == ev_keyup && ev->data1 == key_useartifact)
+ { // flag to denote that it's okay to use an artifact
+ if (!inventory)
+ {
+ plr->readyArtifact = plr->inventory[inv_ptr].type;
+ }
+ usearti = true;
+ }
+
+ // Check for spy mode player cycle
+ if (gamestate == GS_LEVEL && ev->type == ev_keydown
+ && ev->data1 == KEY_F12 && !deathmatch)
+ { // Cycle the display player
+ do
+ {
+ displayplayer++;
+ if (displayplayer == MAXPLAYERS)
+ {
+ displayplayer = 0;
+ }
+ }
+ while (!playeringame[displayplayer] && displayplayer != consoleplayer);
+
+ return true;
+ }
+
+ if (CT_Responder(ev))
+ { // Chat ate the event
+ return true;
+ }
+ if (gamestate == GS_LEVEL)
+ {
+ if (SB_Responder(ev))
+ { // Status bar ate the event
+ return true;
+ }
+ if (AM_Responder(ev))
+ { // Automap ate the event
+ return true;
+ }
+ }
+
+ switch (ev->type)
+ {
+ case ev_keydown:
+ if (ev->data1 == key_invleft)
+ {
+ inventoryTics = 5*35;
+ if (!inventory)
+ {
+ inventory = true;
+ break;
+ }
+ inv_ptr--;
+ if (inv_ptr < 0)
+ {
+ inv_ptr = 0;
+ }
+ else
+ {
+ curpos--;
+ if (curpos < 0)
+ {
+ curpos = 0;
+ }
+ }
+ return true;
+ }
+ if (ev->data1 == key_invright)
+ {
+ inventoryTics = 5*35;
+ if (!inventory)
+ {
+ inventory = true;
+ break;
+ }
+ inv_ptr++;
+ if (inv_ptr >= plr->inventorySlotNum)
+ {
+ inv_ptr--;
+ if (inv_ptr < 0)
+ inv_ptr = 0;
+ }
+ else
+ {
+ curpos++;
+ if (curpos > 6)
+ {
+ curpos = 6;
+ }
+ }
+ return true;
+ }
+ if (ev->data1 == KEY_PAUSE)
+ {
+ if (!MenuActive && gamestate != GS_FINALE)
+ sendpause = true;
+ return true;
+ }
+ if (ev->data1 < MAXKEYS)
+ {
+ gamekeydown[ev->data1] = true;
+ }
+ return true; // eat key down events
+
+ case ev_keyup:
+ if (ev->data1 < MAXKEYS)
+ {
+ gamekeydown[ev->data1] = false;
+ }
+ return false; // always let key up events filter down
+
+ case ev_mouse:
+ mousebuttons[0] = ev->data1 & 1;
+ mousebuttons[1] = ev->data1 & 2;
+ mousebuttons[2] = ev->data1 & 4;
+ mousex = ev->data2 * (mouseSensitivity + 5) / 10;
+ mousey = ev->data3 * (mouseSensitivity + 5) / 10;
+ return true; // eat events
+
+ case ev_joystick:
+ joybuttons[0] = ev->data1 & 1;
+ joybuttons[1] = ev->data1 & 2;
+ joybuttons[2] = ev->data1 & 4;
+ joybuttons[3] = ev->data1 & 8;
+ joyxmove = ev->data2;
+ joyymove = ev->data3;
+ return true; // eat events
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+//==========================================================================
+//
+// G_Ticker
+//
+//==========================================================================
+
+void G_Ticker(void)
+{
+ int i, buf;
+ ticcmd_t *cmd = NULL;
+
+//
+// do player reborns if needed
+//
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i] && players[i].playerstate == PST_REBORN)
+ G_DoReborn (i);
+ }
+
+//
+// do things to change the game state
+//
+ while (gameaction != ga_nothing)
+ {
+ switch (gameaction)
+ {
+ case ga_loadlevel:
+ G_DoLoadLevel();
+ break;
+ case ga_initnew:
+ G_DoInitNew();
+ break;
+ case ga_newgame:
+ G_DoNewGame();
+ break;
+ case ga_loadgame:
+ Draw_LoadIcon();
+ G_DoLoadGame();
+ break;
+ case ga_savegame:
+ Draw_SaveIcon();
+ G_DoSaveGame();
+ break;
+ case ga_singlereborn:
+ G_DoSingleReborn();
+ break;
+ case ga_playdemo:
+ G_DoPlayDemo();
+ break;
+ case ga_screenshot:
+ M_ScreenShot();
+ gameaction = ga_nothing;
+ break;
+ case ga_leavemap:
+ Draw_TeleportIcon();
+ G_DoTeleportNewMap();
+ break;
+ case ga_completed:
+ G_DoCompleted();
+ break;
+ case ga_worlddone:
+ G_DoWorldDone();
+ break;
+ case ga_victory:
+ F_StartFinale();
+ break;
+ default:
+ break;
+ }
+ }
+
+//
+// get commands, check consistancy, and build new consistancy check
+//
+ //buf = gametic % BACKUPTICS;
+ buf = (gametic / ticdup) % BACKUPTICS;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ cmd = &players[i].cmd;
+
+ memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t));
+
+ if (demoplayback)
+ G_ReadDemoTiccmd (cmd);
+ if (demorecording)
+ G_WriteDemoTiccmd (cmd);
+
+ if (netgame && !(gametic%ticdup))
+ {
+ if (gametic > BACKUPTICS && consistancy[i][buf] != cmd->consistancy)
+ {
+ I_Error ("consistency failure (%i should be %i)",cmd->consistancy, consistancy[i][buf]);
+ }
+ if (players[i].mo)
+ consistancy[i][buf] = players[i].mo->x;
+ else
+ consistancy[i][buf] = rndindex;
+ }
+ }
+ }
+
+//
+// check for special buttons
+//
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ if (players[i].cmd.buttons & BT_SPECIAL)
+ {
+ switch (players[i].cmd.buttons & BT_SPECIALMASK)
+ {
+ case BTS_PAUSE:
+ paused ^= 1;
+ if (paused)
+ {
+ S_PauseSound();
+ }
+ else
+ {
+ S_ResumeSound();
+ }
+ break;
+
+ case BTS_SAVEGAME:
+ if (!savedescription[0])
+ {
+ if (netgame)
+ {
+ strcpy (savedescription, "NET GAME");
+ }
+ else
+ {
+ strcpy(savedescription, "SAVE GAME");
+ }
+ }
+ savegameslot =
+ (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
+ gameaction = ga_savegame;
+ break;
+ }
+ }
+ }
+ }
+
+// turn inventory off after a certain amount of time
+ if (inventory && !(--inventoryTics))
+ {
+ players[consoleplayer].readyArtifact =
+ players[consoleplayer].inventory[inv_ptr].type;
+ inventory = false;
+ cmd->arti = 0;
+ }
+
+//
+// do main actions
+//
+ switch (gamestate)
+ {
+ case GS_LEVEL:
+ P_Ticker ();
+ SB_Ticker ();
+ AM_Ticker ();
+ CT_Ticker();
+ break;
+ case GS_INTERMISSION:
+ IN_Ticker ();
+ break;
+ case GS_FINALE:
+ F_Ticker();
+ break;
+ case GS_DEMOSCREEN:
+ H2_PageTicker ();
+ break;
+ }
+}
+
+
+/*
+==============================================================================
+
+ PLAYER STRUCTURE FUNCTIONS
+
+also see P_SpawnPlayer in P_Things
+==============================================================================
+*/
+
+//==========================================================================
+//
+// G_PlayerExitMap
+//
+// Called when the player leaves a map.
+//
+//==========================================================================
+
+void G_PlayerExitMap(int playerNumber)
+{
+ int i;
+ player_t *player;
+ int flightPower;
+
+ player = &players[playerNumber];
+
+// if (deathmatch)
+// {
+// // Strip all but one of each type of artifact
+// for (i = 0; i < player->inventorySlotNum; i++)
+// {
+// player->inventory[i].count = 1;
+// }
+// player->artifactCount = player->inventorySlotNum;
+// }
+// else
+
+ // Strip all current powers (retain flight)
+ flightPower = player->powers[pw_flight];
+ memset(player->powers, 0, sizeof(player->powers));
+ player->powers[pw_flight] = flightPower;
+
+ if (deathmatch)
+ {
+ player->powers[pw_flight] = 0;
+ }
+ else
+ {
+ if (P_GetMapCluster(gamemap) != P_GetMapCluster(LeaveMap))
+ { // Entering new cluster
+ // Strip all keys
+ player->keys = 0;
+
+ // Strip flight artifact
+ for (i = 0; i < 25; i++)
+ {
+ player->powers[pw_flight] = 0;
+ P_PlayerUseArtifact(player, arti_fly);
+ }
+ player->powers[pw_flight] = 0;
+ }
+ }
+
+ if (player->morphTics)
+ {
+ player->readyweapon = player->mo->special1; // Restore weapon
+ player->morphTics = 0;
+ }
+ player->messageTics = 0;
+ player->lookdir = 0;
+ player->mo->flags &= ~MF_SHADOW; // Remove invisibility
+ player->extralight = 0; // Remove weapon flashes
+ player->fixedcolormap = 0; // Remove torch
+ player->damagecount = 0; // No palette changes
+ player->bonuscount = 0;
+ player->poisoncount = 0;
+ if (player == &players[consoleplayer])
+ {
+ SB_state = -1; // refresh the status bar
+ viewangleoffset = 0;
+ }
+}
+
+//==========================================================================
+//
+// G_PlayerReborn
+//
+// Called after a player dies. Almost everything is cleared and
+// initialized.
+//
+//==========================================================================
+
+void G_PlayerReborn(int player)
+{
+ player_t *p;
+ int frags[MAXPLAYERS];
+ int killcount, itemcount, secretcount;
+ unsigned int worldTimer;
+
+ memcpy(frags, players[player].frags, sizeof(frags));
+ killcount = players[player].killcount;
+ itemcount = players[player].itemcount;
+ secretcount = players[player].secretcount;
+ worldTimer = players[player].worldTimer;
+
+ p = &players[player];
+ memset(p, 0, sizeof(*p));
+
+ memcpy(players[player].frags, frags, sizeof(players[player].frags));
+ players[player].killcount = killcount;
+ players[player].itemcount = itemcount;
+ players[player].secretcount = secretcount;
+ players[player].worldTimer = worldTimer;
+ players[player].playerclass = PlayerClasses[player];
+
+ p->usedown = p->attackdown = true; // don't do anything immediately
+ p->playerstate = PST_LIVE;
+ p->health = MAXHEALTH;
+ p->readyweapon = p->pendingweapon = WP_FIRST;
+ p->weaponowned[WP_FIRST] = true;
+ p->messageTics = 0;
+ p->lookdir = 0;
+ localQuakeHappening[player] = false;
+ if (p == &players[consoleplayer])
+ {
+ SB_state = -1; // refresh the status bar
+ inv_ptr = 0; // reset the inventory pointer
+ curpos = 0;
+ viewangleoffset = 0;
+ }
+}
+
+/*
+====================
+=
+= G_CheckSpot
+=
+= Returns false if the player cannot be respawned at the given mapthing_t spot
+= because something is occupying it
+====================
+*/
+
+void P_SpawnPlayer (mapthing_t *mthing);
+
+boolean G_CheckSpot (int playernum, mapthing_t *mthing)
+{
+ fixed_t x, y;
+ subsector_t *ss;
+ unsigned int an;
+ mobj_t *mo;
+
+ x = mthing->x << FRACBITS;
+ y = mthing->y << FRACBITS;
+
+ players[playernum].mo->flags2 &= ~MF2_PASSMOBJ;
+ if (! P_CheckPosition(players[playernum].mo, x, y))
+ {
+ players[playernum].mo->flags2 |= MF2_PASSMOBJ;
+ return false;
+ }
+ players[playernum].mo->flags2 |= MF2_PASSMOBJ;
+
+// spawn a teleport fog
+ ss = R_PointInSubsector (x, y);
+ an = (ANG45 * (mthing->angle / 45)) >> ANGLETOFINESHIFT;
+
+ mo = P_SpawnMobj (x + 20*finecosine[an], y + 20*finesine[an],
+ ss->sector->floorheight + TELEFOGHEIGHT, MT_TFOG);
+
+ if (players[consoleplayer].viewz != 1)
+ S_StartSound (mo, SFX_TELEPORT); // don't start sound on first frame
+
+ return true;
+}
+
+/*
+====================
+=
+= G_DeathMatchSpawnPlayer
+=
+= Spawns a player at one of the random death match spots
+= called at level load and each death
+====================
+*/
+
+void G_DeathMatchSpawnPlayer (int playernum)
+{
+ int i, j;
+ int selections;
+
+ selections = deathmatch_p - deathmatchstarts;
+
+ // This check has been moved to p_setup.c:P_LoadThings()
+ //if (selections < 8)
+ // I_Error ("Only %i deathmatch spots, 8 required", selections);
+
+ for (j = 0; j < 20; j++)
+ {
+ i = P_Random() % selections;
+ if (G_CheckSpot (playernum, &deathmatchstarts[i]))
+ {
+ deathmatchstarts[i].type = playernum + 1;
+ P_SpawnPlayer (&deathmatchstarts[i]);
+ return;
+ }
+ }
+
+// no good spot, so the player will probably get stuck
+ P_SpawnPlayer (&playerstarts[0][playernum]);
+}
+
+//==========================================================================
+//
+// G_DoReborn
+//
+//==========================================================================
+
+static void G_DoReborn(int playernum)
+{
+ int i;
+ boolean oldWeaponowned[NUMWEAPONS];
+ int oldKeys;
+ int oldPieces;
+ boolean foundSpot;
+ int bestWeapon;
+
+ if (G_CheckDemoStatus())
+ {
+ return;
+ }
+ if (!netgame)
+ {
+ if (SV_RebornSlotAvailable())
+ { // Use the reborn code if the slot is available
+ gameaction = ga_singlereborn;
+ }
+ else
+ { // Start a new game if there's no reborn info
+ gameaction = ga_newgame;
+ }
+ }
+ else
+ { // Net-game
+ players[playernum].mo->player = NULL; // Dissassociate the corpse
+
+ if (deathmatch)
+ { // Spawn at random spot if in death match
+ G_DeathMatchSpawnPlayer(playernum);
+ return;
+ }
+
+ // Cooperative net-play, retain keys and weapons
+ oldKeys = players[playernum].keys;
+ oldPieces = players[playernum].pieces;
+ for (i = 0; i < NUMWEAPONS; i++)
+ {
+ oldWeaponowned[i] = players[playernum].weaponowned[i];
+ }
+
+ foundSpot = false;
+ if (G_CheckSpot(playernum, &playerstarts[RebornPosition][playernum]))
+ { // Appropriate player start spot is open
+ P_SpawnPlayer(&playerstarts[RebornPosition][playernum]);
+ foundSpot = true;
+ }
+ else
+ {
+ // Try to spawn at one of the other player start spots
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (G_CheckSpot(playernum, &playerstarts[RebornPosition][i]))
+ { // Found an open start spot
+ // Fake as other player
+ playerstarts[RebornPosition][i].type = playernum + 1;
+ P_SpawnPlayer(&playerstarts[RebornPosition][i]);
+
+ // Restore proper player type
+ playerstarts[RebornPosition][i].type = i + 1;
+
+ foundSpot = true;
+ break;
+ }
+ }
+ }
+
+ if (foundSpot == false)
+ { // Player's going to be inside something
+ P_SpawnPlayer(&playerstarts[RebornPosition][playernum]);
+ }
+
+ // Restore keys and weapons
+ players[playernum].keys = oldKeys;
+ players[playernum].pieces = oldPieces;
+ for (bestWeapon = 0, i = 0; i < NUMWEAPONS; i++)
+ {
+ if (oldWeaponowned[i])
+ {
+ bestWeapon = i;
+ players[playernum].weaponowned[i] = true;
+ }
+ }
+ players[playernum].mana[MANA_1] = 25;
+ players[playernum].mana[MANA_2] = 25;
+ if (bestWeapon)
+ { // Bring up the best weapon
+ players[playernum].pendingweapon = bestWeapon;
+ }
+ }
+}
+
+
+void G_ScreenShot (void)
+{
+ gameaction = ga_screenshot;
+}
+
+
+//==========================================================================
+//
+// G_StartNewInit
+//
+//==========================================================================
+
+void G_StartNewInit(void)
+{
+ SV_InitBaseSlot();
+ SV_ClearRebornSlot();
+ P_ACSInitNewGame();
+ // Default the player start spot group to 0
+ RebornPosition = 0;
+}
+
+//==========================================================================
+//
+// G_StartNewGame
+//
+//==========================================================================
+
+void G_StartNewGame(skill_t skill)
+{
+ int realMap;
+
+ G_StartNewInit();
+ realMap = P_TranslateMap(1);
+ if (realMap == -1)
+ {
+ realMap = 1;
+ }
+ G_InitNew(TempSkill, 1, realMap);
+}
+
+//==========================================================================
+//
+// G_TeleportNewMap
+//
+// Only called by the warp cheat code. Works just like normal map to map
+// teleporting, but doesn't do any interlude stuff.
+//
+//==========================================================================
+
+void G_TeleportNewMap(int map, int position)
+{
+ gameaction = ga_leavemap;
+ LeaveMap = map;
+ LeavePosition = position;
+}
+
+//==========================================================================
+//
+// G_DoTeleportNewMap
+//
+//==========================================================================
+
+static void G_DoTeleportNewMap(void)
+{
+ SV_MapTeleport(LeaveMap, LeavePosition);
+ gamestate = GS_LEVEL;
+ gameaction = ga_nothing;
+ RebornPosition = LeavePosition;
+}
+
+/*
+boolean secretexit;
+void G_ExitLevel (void)
+{
+ secretexit = false;
+ gameaction = ga_completed;
+}
+void G_SecretExitLevel (void)
+{
+ secretexit = true;
+ gameaction = ga_completed;
+}
+*/
+
+//==========================================================================
+//
+// G_Completed
+//
+// Starts intermission routine, which is used only during hub exits,
+// and DeathMatch games.
+//==========================================================================
+
+void G_Completed(int map, int position)
+{
+ if (shareware && map > 4)
+ {
+ // Not possible in the 4-level demo.
+ P_SetMessage(&players[consoleplayer], "ACCESS DENIED -- DEMO", true);
+ return;
+ }
+
+ gameaction = ga_completed;
+ LeaveMap = map;
+ LeavePosition = position;
+}
+
+static void G_DoCompleted(void)
+{
+ int i;
+
+ gameaction = ga_nothing;
+ if (G_CheckDemoStatus())
+ {
+ return;
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ G_PlayerExitMap(i);
+ }
+ }
+ if (LeaveMap == -1 && LeavePosition == -1)
+ {
+ gameaction = ga_victory;
+ return;
+ }
+ else
+ {
+ gamestate = GS_INTERMISSION;
+ IN_Start();
+ }
+
+ /*
+ int i;
+ static int afterSecret[3] = { 7, 5, 5 };
+
+ gameaction = ga_nothing;
+ if (G_CheckDemoStatus())
+ {
+ return;
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ G_PlayerFinishLevel(i);
+ }
+ }
+ prevmap = gamemap;
+ if (secretexit == true)
+ {
+ gamemap = 9;
+ }
+ else if (gamemap == 9)
+ { // Finished secret level
+ gamemap = afterSecret[gameepisode - 1];
+ }
+ else if (gamemap == 8)
+ {
+ gameaction = ga_victory;
+ return;
+ }
+ else
+ {
+ gamemap++;
+ }
+ gamestate = GS_INTERMISSION;
+ IN_Start();
+ */
+}
+
+//============================================================================
+//
+// G_WorldDone
+//
+//============================================================================
+
+void G_WorldDone(void)
+{
+ gameaction = ga_worlddone;
+}
+
+//============================================================================
+//
+// G_DoWorldDone
+//
+//============================================================================
+
+static void G_DoWorldDone(void)
+{
+ gamestate = GS_LEVEL;
+ G_DoLoadLevel();
+ gameaction = ga_nothing;
+ viewactive = true;
+}
+
+//==========================================================================
+//
+// G_DoSingleReborn
+//
+// Called by G_Ticker based on gameaction. Loads a game from the reborn
+// save slot.
+//
+//==========================================================================
+
+static void G_DoSingleReborn(void)
+{
+ gameaction = ga_nothing;
+ SV_LoadGame(SV_GetRebornSlot());
+ SB_SetClassData();
+}
+
+//==========================================================================
+//
+// G_LoadGame
+//
+// Can be called by the startup code or the menu task.
+//
+//==========================================================================
+
+void G_LoadGame(int slot)
+{
+ loadgameslot = slot;
+ gameaction = ga_loadgame;
+}
+
+//==========================================================================
+//
+// G_DoLoadGame
+//
+// Called by G_Ticker based on gameaction.
+//
+//==========================================================================
+
+void G_DoLoadGame(void)
+{
+ gameaction = ga_nothing;
+ SV_LoadGame(loadgameslot);
+ if (!netgame)
+ { // Copy the base slot to the reborn slot
+ SV_UpdateRebornSlot();
+ }
+ SB_SetClassData();
+}
+
+//==========================================================================
+//
+// G_SaveGame
+//
+// Called by the menu task. <description> is a 24 byte text string.
+//
+//==========================================================================
+
+void G_SaveGame(int slot, const char *description)
+{
+ savegameslot = slot;
+ strcpy(savedescription, description);
+ sendsave = true;
+}
+
+//==========================================================================
+//
+// G_DoSaveGame
+//
+// Called by G_Ticker based on gameaction.
+//
+//==========================================================================
+
+static void G_DoSaveGame(void)
+{
+ SV_SaveGame(savegameslot, savedescription);
+ gameaction = ga_nothing;
+ savedescription[0] = 0;
+ P_SetMessage(&players[consoleplayer], TXT_GAMESAVED, true);
+}
+
+//==========================================================================
+//
+// G_DeferredNewGame
+//
+//==========================================================================
+
+void G_DeferredNewGame(skill_t skill)
+{
+ TempSkill = skill;
+ gameaction = ga_newgame;
+}
+
+//==========================================================================
+//
+// G_DoNewGame
+//
+//==========================================================================
+
+static void G_DoNewGame(void)
+{
+ G_StartNewGame(TempSkill);
+ gameaction = ga_nothing;
+}
+
+/*
+====================
+=
+= G_InitNew
+=
+= Can be called by the startup code or the menu task
+= consoleplayer, displayplayer, playeringame[] should be set
+====================
+*/
+
+void G_DeferedInitNew(skill_t skill, int episode, int map)
+{
+ TempSkill = skill;
+ TempEpisode = episode;
+ TempMap = map;
+ gameaction = ga_initnew;
+}
+
+static void G_DoInitNew(void)
+{
+ SV_InitBaseSlot();
+ G_InitNew(TempSkill, TempEpisode, TempMap);
+ gameaction = ga_nothing;
+}
+
+void G_InitNew(skill_t skill, int episode, int map)
+{
+ int i;
+
+ if (paused)
+ {
+ paused = false;
+ S_ResumeSound();
+ }
+ if (skill < sk_baby)
+ {
+ skill = sk_baby;
+ }
+ if (skill > sk_nightmare)
+ {
+ skill = sk_nightmare;
+ }
+ if (map < 1)
+ {
+ map = 1;
+ }
+ if (map > 99)
+ {
+ map = 99;
+ }
+ M_ClearRandom();
+ // Force players to be initialized upon first level load
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ players[i].playerstate = PST_REBORN;
+ players[i].worldTimer = 0;
+ }
+
+ // Set up a bunch of globals
+ usergame = true; // will be set false if a demo
+ paused = false;
+ demorecording = false;
+ demoplayback = false;
+ viewactive = true;
+ gameepisode = episode;
+ gamemap = map;
+ gameskill = skill;
+ BorderNeedRefresh = true;
+
+ // Initialize the sky
+ R_InitSky(map);
+
+ // Give one null ticcmd_t
+ //gametic = 0;
+ //maketic = 1;
+ //for (i = 0; i < MAXPLAYERS; i++)
+ // nettics[i] = 1; // one null event for this gametic
+ //memset (localcmds, 0, sizeof(localcmds));
+ //memset (netcmds, 0, sizeof(netcmds));
+
+ G_DoLoadLevel();
+}
+
+/*
+===============================================================================
+
+ DEMO RECORDING
+
+===============================================================================
+*/
+
+#define DEMOMARKER 0x80
+
+static void G_ReadDemoTiccmd (ticcmd_t *cmd)
+{
+ if (*demo_p == DEMOMARKER)
+ { // end of demo data stream
+ G_CheckDemoStatus ();
+ return;
+ }
+ cmd->forwardmove = ((signed char)*demo_p++);
+ cmd->sidemove = ((signed char)*demo_p++);
+ cmd->angleturn = ((unsigned char)*demo_p++)<<8;
+ cmd->buttons = (unsigned char)*demo_p++;
+ cmd->lookfly = (unsigned char)*demo_p++;
+ cmd->arti = (unsigned char)*demo_p++;
+}
+
+static void G_WriteDemoTiccmd (ticcmd_t *cmd)
+{
+ if (gamekeydown['q']) // press q to end demo recording
+ G_CheckDemoStatus ();
+ *demo_p++ = (byte) cmd->forwardmove;
+ *demo_p++ = (byte) cmd->sidemove;
+ *demo_p++ = cmd->angleturn>>8;
+ *demo_p++ = cmd->buttons;
+ *demo_p++ = cmd->lookfly;
+ *demo_p++ = cmd->arti;
+ demo_p -= 6;
+ G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same
+}
+
+
+/*
+===================
+=
+= G_RecordDemo
+=
+===================
+*/
+
+void G_RecordDemo (skill_t skill, int numplayers, int episode, int map, const char *name)
+{
+ int i;
+
+ G_InitNew (skill, episode, map);
+ usergame = false;
+ snprintf (demoname, sizeof(demoname), "%s%s.lmp", basePath, name);
+ demobuffer = demo_p = (byte *) Z_Malloc (0x20000, PU_STATIC, NULL);
+ *demo_p++ = skill;
+ *demo_p++ = episode;
+ *demo_p++ = map;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+#if (MAXPLAYERS > MAXPLAYERS_10)
+ /* 8-player support is added to Hexen starting
+ * with version 1.1. If using 1.0 wad files,
+ * don't write player data > 4 to the demo...
+ * See also G_DoPlayDemo() below.
+ * FIXME: What if the player count is > 4 ???
+ */
+ if (oldwad_10 && i >= MAXPLAYERS_10)
+ break;
+#endif
+ *demo_p++ = playeringame[i];
+ *demo_p++ = PlayerClasses[i];
+ }
+ demorecording = true;
+}
+
+
+/*
+===================
+=
+= G_PlayDemo
+=
+===================
+*/
+
+static const char *defdemoname;
+
+void G_DeferedPlayDemo (const char *name)
+{
+ defdemoname = name;
+ gameaction = ga_playdemo;
+}
+
+static void G_DoPlayDemo (void)
+{
+ skill_t skill;
+ int i, episode, map;
+
+ gameaction = ga_nothing;
+ demobuffer = demo_p = (byte *) W_CacheLumpName (defdemoname, PU_STATIC);
+ skill = *demo_p++;
+ episode = *demo_p++;
+ map = *demo_p++;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+#if (MAXPLAYERS > MAXPLAYERS_10)
+ /* here is the tricky part: the demos in the
+ * version 1.0 wad files are for MAXPLAYERS 4,
+ * not 8. the check that I added below is not
+ * accurate, though, because the demo may be
+ * recorded using MAXPLAYERS == 8, ie. it may
+ * not be from the wad file..
+ * See also G_RecordDemo() above.
+ */
+ if (oldwad_10 && i >= MAXPLAYERS_10)
+ {
+ playeringame[i] = 0;
+ PlayerClasses[i] = 0;
+ continue;
+ }
+#endif
+ playeringame[i] = *demo_p++;
+ PlayerClasses[i] = *demo_p++;
+ }
+
+ // Initialize world info, etc.
+ G_StartNewInit();
+
+ precache = false; // don't spend a lot of time in loadlevel
+ G_InitNew (skill, episode, map);
+ precache = true;
+ usergame = false;
+ demoplayback = true;
+}
+
+
+/*
+===================
+=
+= G_TimeDemo
+=
+===================
+*/
+
+void G_TimeDemo (const char *name)
+{
+ skill_t skill;
+ int episode, map;
+
+ demobuffer = demo_p = (byte *) W_CacheLumpName (name, PU_STATIC);
+ skill = *demo_p++;
+ episode = *demo_p++;
+ map = *demo_p++;
+ G_InitNew (skill, episode, map);
+ usergame = false;
+ demoplayback = true;
+ timingdemo = true;
+ singletics = true;
+}
+
+
+/*
+===================
+=
+= G_CheckDemoStatus
+=
+= Called after a death or level completion to allow demos to be cleaned up
+= Returns true if a new demo loop action will take place
+===================
+*/
+
+boolean G_CheckDemoStatus (void)
+{
+ int endtime;
+
+ if (timingdemo)
+ {
+ endtime = I_GetTime ();
+ I_Error ("timed %i gametics in %i realtics", gametic,
+ endtime - starttime);
+ }
+
+ if (demoplayback)
+ {
+ if (singledemo)
+ I_Quit ();
+
+ Z_ChangeTag (demobuffer, PU_CACHE);
+ demoplayback = false;
+ H2_AdvanceDemo();
+ return true;
+ }
+
+ if (demorecording)
+ {
+ *demo_p++ = DEMOMARKER;
+ M_WriteFile (demoname, demobuffer, demo_p - demobuffer);
+ Z_Free (demobuffer);
+ demorecording = false;
+ I_Error ("Recorded demo: %s", demoname);
+ }
+
+ return false;
+}
+
--- /dev/null
+++ b/h2_main.c
@@ -1,0 +1,964 @@
+
+//**************************************************************************
+//**
+//** h2_main.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 586 $
+//** $Date: 2012-08-31 21:51:13 +0300 (Fri, 31 Aug 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+#include "v_compat.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAXWADFILES 20
+
+#ifdef RENDER3D
+#define V_DrawPatch(x,y,p) OGL_DrawPatch((x),(y),(p))
+#define V_DrawRawScreen(a) OGL_DrawRawScreen((a))
+#endif
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct
+{
+ const char *name;
+ void (*func)(const char **args, int tag);
+ int requiredArgs;
+ int tag;
+} execOpt_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void R_ExecuteSetViewSize(void);
+void D_CheckNetGame(void);
+void G_BuildTiccmd(ticcmd_t *cmd);
+void F_Drawer(void);
+boolean F_Responder(event_t *ev);
+void I_StartupKeyboard(void);
+void I_StartupJoystick(void);
+void I_ShutdownKeyboard(void);
+void S_InitScript(void);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+void H2_ProcessEvents(void);
+void H2_DoAdvanceDemo(void);
+void H2_AdvanceDemo(void);
+void H2_StartTitle(void);
+void H2_PageTicker(void);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void DrawMessage(void);
+static void PageDrawer(void);
+static void HandleArgs(void);
+static void CheckRecordFrom(void);
+static void AddWADFile(const char *file);
+static void DrawAndBlit(void);
+static void ExecOptionFILE(const char **args, int tag);
+static void ExecOptionSCRIPTS(const char **args, int tag);
+static void ExecOptionDEVMAPS(const char **args, int tag);
+static void ExecOptionSKILL(const char **args, int tag);
+static void ExecOptionPLAYDEMO(const char **args, int tag);
+static void ExecOptionMAXZONE(const char **args, int tag);
+static void WarpCheck(void);
+
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern boolean MenuActive;
+extern boolean askforquit;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+const char *basePath = DUMMY_BASEPATH;
+boolean DevMaps; // true = Map development mode
+const char *DevMapsDir = ""; // development maps directory
+boolean shareware; // true if only episode 1 present
+boolean oldwad_10; // true if version 1.0 wad files
+boolean mac_hexen; // true if Macintosh version wad
+boolean nomonsters; // checkparm of -nomonsters
+boolean respawnparm; // checkparm of -respawn
+boolean randomclass; // checkparm of -randclass
+boolean debugmode; // checkparm of -debug
+boolean ravpic; // checkparm of -ravpic
+boolean cmdfrag; // true if a CMD_FRAG packet should be sent out
+boolean singletics; // debug flag to cancel adaptiveness
+boolean artiskip; // whether shift-enter skips an artifact
+int maxzone = 0x800000; // Maximum allocated for zone heap (8meg default)
+skill_t startskill;
+int startepisode;
+int startmap;
+boolean autostart;
+boolean advancedemo;
+FILE *debugfile;
+event_t events[MAXEVENTS];
+int eventhead;
+int eventtail;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int WarpMap;
+static int demosequence;
+static int pagetic;
+static const char *pagename;
+
+static const char *wadfiles[MAXWADFILES + 1] =
+{
+ "hexen.wad",
+#ifdef ASSASSIN
+ "assassin.wad",
+#endif
+ NULL /* the last entry MUST be NULL */
+};
+static execOpt_t ExecOptions[] =
+{
+ { "-file", ExecOptionFILE, 1, 0 },
+ { "-scripts", ExecOptionSCRIPTS, 1, 0 },
+ { "-devmaps", ExecOptionDEVMAPS, 1, 0 },
+ { "-skill", ExecOptionSKILL, 1, 0 },
+ { "-playdemo", ExecOptionPLAYDEMO, 1, 0 },
+ { "-timedemo", ExecOptionPLAYDEMO, 1, 0 },
+ { "-maxzone", ExecOptionMAXZONE, 1, 0 },
+ { NULL, NULL, 0, 0 } // Terminator
+};
+
+// CODE --------------------------------------------------------------------
+
+#if !(defined(__DOS__) || defined(__WATCOMC__) || defined(__DJGPP__) || defined(_WIN32) || defined(_WIN64))
+char *strlwr (char *str)
+{
+ char *c;
+ c = str;
+ while (*c)
+ {
+ *c = tolower(*c);
+ c++;
+ }
+ return str;
+}
+
+char *strupr (char *str)
+{
+ char *c;
+ c = str;
+ while (*c)
+ {
+ *c = toupper(*c);
+ c++;
+ }
+ return str;
+}
+
+int filelength(int handle)
+{
+ Dir *d;
+ int length;
+
+ d = dirfstat(handle);
+ if (d == nil)
+ {
+ I_Error("Error fstating");
+ }
+ length = d->length;
+ free(d);
+ return length;
+}
+#endif
+
+//==========================================================================
+//
+// H2_Main
+//
+//==========================================================================
+void InitMapMusicInfo(void);
+
+void H2_Main(void)
+{
+ int p;
+
+ M_FindResponseFile();
+ setbuf(stdout, NULL);
+ startepisode = 1;
+ autostart = false;
+ startskill = sk_medium;
+ startmap = 1;
+
+ HandleArgs();
+
+ // Initialize subsystems
+
+ ST_Message("V_Init: allocate screens.\n");
+ V_Init();
+
+ // Load defaults before initing other systems
+ ST_Message("M_LoadDefaults: Load system defaults.\n");
+ M_LoadDefaults(CONFIG_FILE_NAME);
+
+ // HEXEN MODIFICATION:
+ // There is a realloc() in W_AddFile() that might fail if the zone
+ // heap has been previously allocated, so we need to initialize the
+ // WAD files BEFORE the zone memory initialization.
+ ST_Message("W_Init: Init WADfiles.\n");
+ W_InitMultipleFiles(wadfiles);
+ W_CheckWADFiles();
+
+ ST_Message("Z_Init: Init zone memory allocation daemon.\n");
+ Z_Init();
+
+ ST_Message("MN_Init: Init menu system.\n");
+ MN_Init();
+
+ ST_Message("CT_Init: Init chat mode data.\n");
+ CT_Init();
+
+ InitMapMusicInfo(); // Init music fields in mapinfo
+
+ ST_Message("S_InitScript\n");
+ S_InitScript();
+
+ ST_Message("SN_InitSequenceScript: Registering sound sequences.\n");
+ SN_InitSequenceScript();
+ ST_Message("I_Init: Setting up machine state.\n");
+ I_Init();
+
+ ST_Message("ST_Init: Init startup screen.\n");
+ ST_Init();
+
+ S_StartSongName("orb", true);
+
+ // Show version message now, so it's visible during R_Init()
+ ST_Message("Executable: "VERSIONTEXT".\n");
+
+ ST_Message("R_Init: Init Hexen refresh daemon");
+ R_Init();
+ ST_Message("\n");
+
+ if (M_CheckParm("-net"))
+ ST_NetProgress(); // Console player found
+
+ ST_Message("P_Init: Init Playloop state.\n");
+ P_Init();
+
+ // Check for command line warping. Follows P_Init() because the
+ // MAPINFO.TXT script must be already processed.
+ WarpCheck();
+
+ if (autostart)
+ {
+ ST_Message("Warp to Map %d (\"%s\":%d), Skill %d\n",
+ WarpMap, P_GetMapName(startmap), startmap, startskill + 1);
+ }
+
+ ST_Message("D_CheckNetGame: Checking network game status.\n");
+ D_CheckNetGame();
+
+ ST_Message("SB_Init: Loading patches.\n");
+ SB_Init();
+
+ CheckRecordFrom();
+
+ p = M_CheckParm("-record");
+ if (p && p < myargc - 1)
+ {
+ G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p + 1]);
+ H2_GameLoop(); // Never returns
+ }
+
+ p = M_CheckParm("-playdemo");
+ if (p && p < myargc - 1)
+ {
+ singledemo = true; // Quit after one demo
+ G_DeferedPlayDemo(myargv[p + 1]);
+ H2_GameLoop(); // Never returns
+ }
+
+ p = M_CheckParm("-timedemo");
+ if (p && p < myargc - 1)
+ {
+ G_TimeDemo(myargv[p + 1]);
+ H2_GameLoop(); // Never returns
+ }
+
+ p = M_CheckParm("-loadgame");
+ if (p && p < myargc - 1)
+ {
+ G_LoadGame(atoi(myargv[p + 1]));
+ }
+
+ if (gameaction != ga_loadgame)
+ {
+ UpdateState |= I_FULLSCRN;
+ BorderNeedRefresh = true;
+ if (autostart || netgame)
+ {
+ G_StartNewInit();
+ G_InitNew(startskill, startepisode, startmap);
+ }
+ else
+ {
+ H2_StartTitle();
+ }
+ }
+ H2_GameLoop(); // Never returns
+}
+
+//==========================================================================
+//
+// HandleArgs
+//
+//==========================================================================
+
+static void HandleArgs(void)
+{
+ int p;
+ execOpt_t *opt;
+
+ nomonsters = M_ParmExists("-nomonsters");
+ respawnparm = M_ParmExists("-respawn");
+ randomclass = M_ParmExists("-randclass");
+ ravpic = M_ParmExists("-ravpic");
+ artiskip = M_ParmExists("-artiskip");
+ debugmode = M_ParmExists("-debug");
+ deathmatch = M_ParmExists("-deathmatch");
+ cmdfrag = M_ParmExists("-cmdfrag");
+
+ // Process command line options
+ for (opt = ExecOptions; opt->name != NULL; opt++)
+ {
+ p = M_CheckParm(opt->name);
+ if (p && p < myargc-opt->requiredArgs)
+ {
+ opt->func(&myargv[p], opt->tag);
+ }
+ }
+
+ // Look for an external device driver
+ I_CheckExternDriver();
+}
+
+//==========================================================================
+//
+// WarpCheck
+//
+//==========================================================================
+
+static void WarpCheck(void)
+{
+ int p;
+ int map;
+
+ p = M_CheckParm("-warp");
+ if (p && p < myargc - 1)
+ {
+ WarpMap = atoi(myargv[p + 1]);
+ map = P_TranslateMap(WarpMap);
+ if (map == -1)
+ { // Couldn't find real map number
+ startmap = 1;
+ ST_Message("-WARP: Invalid map number.\n");
+ }
+ else
+ { // Found a valid startmap
+ startmap = map;
+ autostart = true;
+ }
+ }
+ else
+ {
+ WarpMap = 1;
+ startmap = P_TranslateMap(1);
+ if (startmap == -1)
+ {
+ startmap = 1;
+ }
+ }
+}
+
+//==========================================================================
+//
+// ExecOptionSKILL
+//
+//==========================================================================
+
+static void ExecOptionSKILL(const char **args, int tag)
+{
+ startskill = args[1][0] - '1';
+ autostart = true;
+}
+
+//==========================================================================
+//
+// ExecOptionFILE
+//
+//==========================================================================
+
+static void ExecOptionFILE(const char **args, int tag)
+{
+ int p;
+
+ p = M_CheckParm("-file");
+ while (++p != myargc && myargv[p][0] != '-')
+ {
+ AddWADFile(myargv[p]);
+ }
+}
+
+
+//==========================================================================
+//
+// ExecOptionPLAYDEMO
+//
+//==========================================================================
+
+static void ExecOptionPLAYDEMO(const char **args, int tag)
+{
+ char file[256];
+
+ snprintf(file, sizeof(file), "%s.lmp", args[1]);
+ AddWADFile(file);
+ ST_Message("Playing demo %s.lmp.\n", args[1]);
+}
+
+//==========================================================================
+//
+// ExecOptionSCRIPTS
+//
+//==========================================================================
+
+static void ExecOptionSCRIPTS(const char **args, int tag)
+{
+ sc_FileScripts = true;
+ sc_ScriptsDir = args[1];
+}
+
+//==========================================================================
+//
+// ExecOptionDEVMAPS
+//
+//==========================================================================
+
+static void ExecOptionDEVMAPS(const char **args, int tag)
+{
+ char *ptr;
+ DevMaps = true;
+ ST_Message("Map development mode enabled:\n");
+ ST_Message("[config ] = %s\n", args[1]);
+ SC_OpenFileCLib(args[1]);
+ SC_MustGetStringName("mapsdir");
+ SC_MustGetString();
+ ST_Message("[mapsdir ] = %s\n", sc_String);
+ ptr = (char *) malloc(strlen(sc_String) + 1);
+ strcpy(ptr, sc_String);
+ DevMapsDir = ptr;
+ SC_MustGetStringName("scriptsdir");
+ SC_MustGetString();
+ ST_Message("[scriptsdir] = %s\n", sc_String);
+ sc_FileScripts = true;
+ ptr = (char *) malloc(strlen(sc_String) + 1);
+ strcpy(ptr, sc_String);
+ sc_ScriptsDir = ptr;
+ while (SC_GetString())
+ {
+ if (SC_Compare("file"))
+ {
+ SC_MustGetString();
+ AddWADFile(sc_String);
+ }
+ else
+ {
+ SC_ScriptError(NULL);
+ }
+ }
+ SC_Close();
+}
+
+
+static long superatol(const char *s)
+{
+ long int n = 0, r = 10, x, mul = 1;
+ const char *c = s;
+
+ for ( ; *c; c++)
+ {
+ x = (*c & 223) - 16;
+
+ if (x == -3)
+ {
+ mul = -mul;
+ }
+ else if (x == 72 && r == 10)
+ {
+ n -= (r = n);
+ if (!r)
+ r = 16;
+ if (r < 2 || r > 36)
+ return -1;
+ }
+ else
+ {
+ if (x > 10)
+ x -= 39;
+ if (x >= r)
+ return -1;
+ n = (n*r) + x;
+ }
+ }
+ return (mul*n);
+}
+
+static void ExecOptionMAXZONE(const char **args, int tag)
+{
+ int size;
+
+ size = (int) superatol(args[1]);
+ if (size < MINIMUM_HEAP_SIZE)
+ size = MINIMUM_HEAP_SIZE;
+ if (size > MAXIMUM_HEAP_SIZE)
+ size = MAXIMUM_HEAP_SIZE;
+ maxzone = size;
+}
+
+//==========================================================================
+//
+// H2_GameLoop
+//
+//==========================================================================
+
+void H2_GameLoop(void)
+{
+ if (M_CheckParm("-debugfile"))
+ {
+ char filename[20];
+ snprintf(filename, sizeof(filename), "debug%i.txt", consoleplayer);
+ debugfile = fopen(filename,"w");
+ }
+ I_InitGraphics();
+ while (1)
+ {
+ // Frame syncronous IO operations
+ I_StartFrame();
+
+ // Process one or more tics
+ if (singletics)
+ {
+ I_StartTic();
+ H2_ProcessEvents();
+ G_BuildTiccmd(&netcmds[consoleplayer][maketic % BACKUPTICS]);
+ if (advancedemo)
+ {
+ H2_DoAdvanceDemo();
+ }
+ G_Ticker();
+ gametic++;
+ maketic++;
+ }
+ else
+ {
+ // Will run at least one tic
+ TryRunTics();
+ }
+
+ // Move positional sounds
+ S_UpdateSounds(players[displayplayer].mo);
+
+ DrawAndBlit();
+ }
+}
+
+//==========================================================================
+//
+// H2_ProcessEvents
+//
+// Send all the events of the given timestamp down the responder chain.
+//
+//==========================================================================
+
+void H2_ProcessEvents(void)
+{
+ event_t *ev;
+
+ while (eventtail != eventhead)
+ {
+ ev = &events[eventtail];
+ if (F_Responder(ev))
+ {
+ goto _next_ev;
+ }
+ if (MN_Responder(ev))
+ {
+ goto _next_ev;
+ }
+ G_Responder(ev);
+ _next_ev:
+ eventtail = (eventtail + 1) & (MAXEVENTS - 1);
+ }
+}
+
+//==========================================================================
+//
+// H2_PostEvent
+//
+// Called by the I/O functions when input is detected.
+//
+//==========================================================================
+
+void H2_PostEvent(event_t *ev)
+{
+ events[eventhead] = *ev;
+ eventhead++;
+ eventhead &= (MAXEVENTS - 1);
+}
+
+//==========================================================================
+//
+// DrawAndBlit
+//
+//==========================================================================
+
+static void DrawAndBlit(void)
+{
+ // Change the view size if needed
+ if (setsizeneeded)
+ {
+ R_ExecuteSetViewSize();
+ }
+
+ // Do buffered drawing
+ switch (gamestate)
+ {
+ case GS_LEVEL:
+ if (!gametic)
+ break;
+#if AM_TRANSPARENT
+ R_RenderPlayerView(&players[displayplayer]);
+#endif
+ if (automapactive)
+ AM_Drawer();
+#if !AM_TRANSPARENT
+ else
+ {
+ R_RenderPlayerView(&players[displayplayer]);
+ }
+#endif
+ CT_Drawer();
+ UpdateState |= I_FULLVIEW;
+ SB_Drawer();
+ break;
+ case GS_INTERMISSION:
+ IN_Drawer();
+ break;
+ case GS_FINALE:
+ F_Drawer();
+ break;
+ case GS_DEMOSCREEN:
+ PageDrawer();
+ break;
+ }
+
+ if (paused && !MenuActive && !askforquit)
+ {
+ if (!netgame)
+ {
+ V_DrawPatch(160, viewwindowy + 5, (PATCH_REF)WR_CacheLumpName("PAUSED", PU_CACHE));
+ }
+ else
+ {
+ V_DrawPatch(160, 70, (PATCH_REF)WR_CacheLumpName("PAUSED", PU_CACHE));
+ }
+ }
+
+#ifdef RENDER3D
+ if (OGL_DrawFilter())
+ BorderNeedRefresh = true;
+#endif
+
+ // Draw current message
+ DrawMessage();
+
+ // Draw Menu
+ MN_Drawer();
+
+ // Send out any new accumulation
+ NetUpdate();
+
+ // Flush buffered stuff to screen
+ I_Update();
+}
+
+//==========================================================================
+//
+// DrawMessage
+//
+//==========================================================================
+
+static void DrawMessage(void)
+{
+ player_t *player;
+
+ player = &players[consoleplayer];
+ if (player->messageTics <= 0 || !player->message)
+ { // No message
+ return;
+ }
+ if (player->yellowMessage)
+ {
+ MN_DrTextAYellow(player->message, 160 - MN_TextAWidth(player->message)/2, 1);
+ }
+ else
+ {
+ MN_DrTextA(player->message, 160 - MN_TextAWidth(player->message)/2, 1);
+ }
+}
+
+//==========================================================================
+//
+// H2_PageTicker
+//
+//==========================================================================
+
+void H2_PageTicker(void)
+{
+ if (--pagetic < 0)
+ {
+ H2_AdvanceDemo();
+ }
+}
+
+//==========================================================================
+//
+// PageDrawer
+//
+//==========================================================================
+
+static void PageDrawer(void)
+{
+ V_DrawRawScreen((BYTE_REF)WR_CacheLumpName(pagename, PU_CACHE));
+ if (demosequence == 1)
+ {
+ V_DrawPatch(4, 160, (PATCH_REF)WR_CacheLumpName("ADVISOR", PU_CACHE));
+ }
+ UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// H2_AdvanceDemo
+//
+// Called after each demo or intro demosequence finishes.
+//
+//==========================================================================
+
+void H2_AdvanceDemo(void)
+{
+ advancedemo = true;
+}
+
+//==========================================================================
+//
+// H2_DoAdvanceDemo
+//
+//==========================================================================
+
+void H2_DoAdvanceDemo(void)
+{
+ players[consoleplayer].playerstate = PST_LIVE; // don't reborn
+ advancedemo = false;
+ usergame = false; // can't save/end game here
+ paused = false;
+ gameaction = ga_nothing;
+ demosequence = (demosequence + 1) % 7;
+ switch (demosequence)
+ {
+ case 0:
+ pagetic = 280;
+ gamestate = GS_DEMOSCREEN;
+ pagename = "TITLE";
+ S_StartSongName("hexen", true);
+ break;
+ case 1:
+ pagetic = 210;
+ gamestate = GS_DEMOSCREEN;
+ pagename = "TITLE";
+ break;
+ case 2:
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ G_DeferedPlayDemo("demo1");
+ break;
+ case 3:
+ pagetic = 200;
+ gamestate = GS_DEMOSCREEN;
+ pagename = "CREDIT";
+ break;
+ case 4:
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ G_DeferedPlayDemo("demo2");
+ break;
+ case 5:
+ pagetic = 200;
+ gamestate = GS_DEMOSCREEN;
+ pagename = (mac_hexen == true) ? "PRSGCRED" /* credits for Mac port by Presage */
+ : "CREDIT"; /* original Raven/iD credits page . */
+ break;
+ case 6:
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ G_DeferedPlayDemo("demo3");
+ break;
+ }
+}
+
+//==========================================================================
+//
+// H2_StartTitle
+//
+//==========================================================================
+
+void H2_StartTitle(void)
+{
+ gameaction = ga_nothing;
+ demosequence = -1;
+ H2_AdvanceDemo();
+}
+
+//==========================================================================
+//
+// CheckRecordFrom
+//
+// -recordfrom <savegame num> <demoname>
+//
+//==========================================================================
+
+static void CheckRecordFrom(void)
+{
+ int p;
+
+ p = M_CheckParm("-recordfrom");
+ if (!p || p >= myargc - 2)
+ { // Bad args
+ return;
+ }
+ G_LoadGame(atoi(myargv[p + 1]));
+ G_DoLoadGame(); // Load the gameskill etc info from savegame
+ G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p + 2]);
+ H2_GameLoop(); // Never returns
+}
+
+//==========================================================================
+//
+// AddWADFile
+//
+//==========================================================================
+
+static void AddWADFile(const char *file)
+{
+ int i = 0;
+ char *newwad;
+
+ ST_Message("Adding external file: %s\n", file);
+ while (wadfiles[i])
+ {
+ if (++i == MAXWADFILES)
+ I_Error ("MAXWADFILES reached for %s", file);
+ }
+ newwad = (char *) malloc(strlen(file) + 1);
+ strcpy(newwad, file);
+ wadfiles[i] = newwad;
+ if (++i <= MAXWADFILES)
+ wadfiles[i] = NULL;
+}
+
+
+//==========================================================================
+//
+// Fixed Point math
+//
+//==========================================================================
+
+#if defined(_HAVE_FIXED_ASM)
+
+#if defined(__i386__) || defined(__386__) || defined(_M_IX86)
+#if defined(__GNUC__) && !defined(_INLINE_FIXED_ASM)
+fixed_t FixedMul (fixed_t a, fixed_t b)
+{
+ fixed_t retval;
+ __asm__ __volatile__(
+ "imull %%edx \n\t"
+ "shrdl $16, %%edx, %%eax \n\t"
+ : "=a" (retval)
+ : "a" (a), "d" (b)
+ : "cc"
+ );
+ return retval;
+}
+
+fixed_t FixedDiv2 (fixed_t a, fixed_t b)
+{
+ fixed_t retval;
+ __asm__ __volatile__(
+ "cdq \n\t"
+ "shldl $16, %%eax, %%edx \n\t"
+ "sall $16, %%eax \n\t"
+ "idivl %%ebx \n\t"
+ : "=a" (retval)
+ : "a" (a), "b" (b)
+ : "%edx", "cc"
+ );
+ return retval;
+}
+#endif /* GCC and !_INLINE_FIXED_ASM */
+#endif /* x86 */
+
+#else /* C-only versions */
+
+fixed_t FixedMul (fixed_t a, fixed_t b)
+{
+ return ((int64_t) a * (int64_t) b) >> 16;
+}
+
+fixed_t FixedDiv2 (fixed_t a, fixed_t b)
+{
+ if (!b)
+ return 0;
+ return (fixed_t) (((double) a / (double) b) * FRACUNIT);
+}
+#endif
+
+fixed_t FixedDiv (fixed_t a, fixed_t b)
+{
+ if ((abs(a) >> 14) >= abs(b))
+ {
+ return ((a^b) < 0 ? H2MININT : H2MAXINT);
+ }
+ return (FixedDiv2(a, b));
+}
+
+//==========================================================================
+//
+// Byte swap functions
+//
+//==========================================================================
+
+int16_t ShortSwap (int16_t x)
+{
+ return (int16_t) (((uint16_t)x << 8) | ((uint16_t)x >> 8));
+}
+
+int32_t LongSwap (int32_t x)
+{
+ return (int32_t) (((uint32_t)x << 24) | ((uint32_t)x >> 24) |
+ (((uint32_t)x & (uint32_t)0x0000ff00UL) << 8) |
+ (((uint32_t)x & (uint32_t)0x00ff0000UL) >> 8));
+}
+
--- /dev/null
+++ b/h2def.h
@@ -1,0 +1,1695 @@
+
+//**************************************************************************
+//**
+//** h2def.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 590 $
+//** $Date: 2012-10-23 23:55:31 +0300 (Tue, 23 Oct 2012) $
+//**
+//**************************************************************************
+
+#ifndef __H2DEF__
+#define __H2DEF__
+
+/* if rangecheck is undefined, most parameter
+ * validation debugging code will not be compiled
+ */
+#ifndef NORANGECHECKING
+#define RANGECHECK 1
+#endif
+
+#define __STRINGIFY(x) #x
+#define STRINGIFY(x) __STRINGIFY(x)
+
+/* 8-player support is added by hexen version 1.1:
+ * Hexen v1.0 supported 4 players, just like Doom.
+ * Changing the following MAXPLAYERS macros would
+ * break many things.
+ */
+#define MAXPLAYERS_10 4
+#define MAXPLAYERS_11 8
+#if defined(VERSION10_WAD)
+#define MAXPLAYERS (MAXPLAYERS_10)
+#else
+#define MAXPLAYERS (MAXPLAYERS_11)
+#endif
+
+#if (MAXPLAYERS == MAXPLAYERS_10)
+#define VERSION 100
+#define VERSION_TEXT "v1.0"
+#else
+#define VERSION 110
+#define VERSION_TEXT "v1.1"
+#endif
+
+#define VERSION_MAJ 1
+#define VERSION_MIN 6
+#define VERSION_PATCH 3
+#define HHEXEN_VERSION "v" STRINGIFY(VERSION_MAJ) "." STRINGIFY(VERSION_MIN) "." STRINGIFY(VERSION_PATCH)
+
+#if 0
+/* Version texts of old releases */
+#define VERSIONTEXT "ID V1.2"
+#define VERSIONTEXT "RETAIL STORE BETA" /* 9/26/95 */
+#define VERSIONTEXT "DVL BETA 10 05 95" /* Used for GT for testing */
+#define VERSIONTEXT "DVL BETA 10 07 95" /* Just an update for Romero */
+#define VERSIONTEXT "FINAL 1.0 (10 13 95)" /* Just an update for Romero */
+#endif
+
+/*
+#define VER_ID "RETAIL"
+*/
+#define VER_ID "DVL"
+
+#if (MAXPLAYERS == MAXPLAYERS_10)
+#define VER_ID2 VER_ID "/4PLYR"
+#else
+#define VER_ID2 VER_ID "/8PLYR"
+#endif
+
+#ifdef RANGECHECK
+#define VER_ID_FINAL VER_ID2 "+R"
+#else
+#define VER_ID_FINAL VER_ID2
+#endif
+
+#define VERSIONTEXT HHEXEN_VERSION " " __DATE__ " (" VER_ID_FINAL ")"
+
+#if defined(__linux)
+#define VERSION_PLATFORM "Linux"
+#elif defined (__FreeBSD__)
+#define VERSION_PLATFORM "FreeBSD"
+#elif defined (_WIN32)
+#define VERSION_PLATFORM "Windows"
+#else
+#define VERSION_PLATFORM "Unknown"
+#endif
+
+/* compatibility definitions: */
+#if defined(_WIN32) && !defined(F_OK)
+/* values for the mode argument of access(). MS does not define them.
+ these aren't in h2stdinc.h, because not all files include io.h or
+ unistd.h */
+#define R_OK 4 /* Test for read permission. */
+#define W_OK 2 /* Test for write permission. */
+#define X_OK 1 /* Test for execute permission. */
+#define F_OK 0 /* Test for existence. */
+#endif
+
+/* max length of a filesystem pathname */
+#define MAX_OSPATH 256
+
+#define DATA_ENVVAR "HHEXEN_DATA"
+#define H_USERDIR ".hhexen"
+
+/* path to the user directory with a trailing
+ * directory separator character. initialized
+ * to DUMMY_BASEPATH string, which is "./" or
+ * empty string "", so that it will have no
+ * effect when user directories are disabled.
+ */
+extern const char *basePath;
+#define DUMMY_BASEPATH ""
+
+#define CONFIG_FILE_NAME "hhexen.cfg"
+
+
+#include "st_start.h"
+
+/* all exterior data is defined here */
+#include "xddefs.h"
+
+/* all important printed strings */
+#include "textdefs.h"
+
+/* header generated by multigen utility */
+#include "info.h"
+
+extern byte *destview, *destscreen; /* PC direct to screen pointers */
+
+/* most key data are simple ascii (uppercased) */
+#define KEY_TAB 9
+#define KEY_ENTER 13
+#define KEY_ESCAPE 27
+#define KEY_SPACE 32 /* 0x20 */
+#define KEY_MINUS 45 /* 0x2D */
+
+#define KEY_FIVE 53 /* 0x35 */
+#define KEY_SIX 54 /* 0x36 */
+#define KEY_SEVEN 55 /* 0x37 */
+#define KEY_EIGHT 56 /* 0x38 */
+#define KEY_NINE 57 /* 0x39 */
+#define KEY_ZERO 48 /* 0x30 */
+
+#define KEY_EQUALS 61 /* 0x3D */
+
+/* These added by S.A. */
+#define KEY_LEFTBRACKET 91
+#define KEY_RIGHTBRACKET 93
+#define KEY_BACKQUOTE 96
+#define KEY_QUOTEDBL 34
+#define KEY_QUOTE 39
+#define KEY_SEMICOLON 59
+#define KEY_PERIOD 46
+#define KEY_COMMA 44
+#define KEY_SLASH 47
+
+#define KEY_BACKSLASH 92 /* 0x5C */
+
+#define KEY_BACKSPACE 127 /* 0x7F */
+
+#define KEY_UPARROW 128 /* 0x80 */
+#define KEY_DOWNARROW 129
+#define KEY_LEFTARROW 130
+#define KEY_RIGHTARROW 131
+
+#define KEY_ALT 132
+#define KEY_LALT KEY_ALT
+#define KEY_RALT KEY_ALT
+
+#define KEY_CTRL 133
+#define KEY_LCTRL KEY_CTRL
+#define KEY_RCTRL KEY_CTRL
+
+#define KEY_SHIFT 134
+#define KEY_LSHIFT KEY_SHIFT
+#define KEY_RSHIFT KEY_SHIFT
+
+#define KEY_F1 135
+#define KEY_F2 136
+#define KEY_F3 137
+#define KEY_F4 138
+#define KEY_F5 139
+#define KEY_F6 140
+#define KEY_F7 141
+#define KEY_F8 142
+#define KEY_F9 143
+#define KEY_F10 144
+#define KEY_F11 145
+#define KEY_F12 146
+#define KEY_INS 147
+#define KEY_DEL 148
+#define KEY_PGDN 149
+#define KEY_PGUP 150
+#define KEY_HOME 151
+#define KEY_END 152
+
+#define KEY_PAUSE 255 /* 0xFF */
+
+/* mouse buttons */
+#define KEY_MOUSE1 200 /* 0xC8 */
+#define KEY_MOUSE2 201 /* right mouse button */
+#define KEY_MOUSE3 202 /* middle mouse button */
+#define KEY_MWHEELUP 203 /* wheel-up as a virtual button */
+#define KEY_MWHEELDOWN 204 /* wheel-down as a virtual button */
+#define KEY_MOUSE4 205 /* thumb buttons */
+#define KEY_MOUSE5 206 /* thumb buttons */
+
+/* joystick buttons */
+#define KEY_JOY1 207
+#define KEY_JOY2 208
+#define KEY_JOY3 209
+#define KEY_JOY4 210
+
+/* aux keys, for multi-buttoned joysticks */
+#define KEY_AUX1 211
+#define KEY_AUX2 212
+#define KEY_AUX3 213
+#define KEY_AUX4 214
+#define KEY_AUX5 215
+#define KEY_AUX6 216
+#define KEY_AUX7 217
+#define KEY_AUX8 218
+#define KEY_AUX9 219
+#define KEY_AUX10 220
+#define KEY_AUX11 221
+#define KEY_AUX12 222
+#define KEY_AUX13 223
+#define KEY_AUX14 224
+#define KEY_AUX15 225
+#define KEY_AUX16 226
+#define KEY_AUX17 227
+#define KEY_AUX18 228
+#define KEY_AUX19 229
+#define KEY_AUX20 230
+#define KEY_AUX21 231
+#define KEY_AUX22 232
+#define KEY_AUX23 233
+#define KEY_AUX24 234
+#define KEY_AUX25 235
+#define KEY_AUX26 236
+#define KEY_AUX27 237
+#define KEY_AUX28 238
+#define KEY_AUX29 239
+#define KEY_AUX30 240
+#define KEY_AUX31 241
+#define KEY_AUX32 242
+
+#define MAXKEYS 256
+
+
+#define FINEANGLES 8192
+#define FINEMASK (FINEANGLES - 1)
+#define ANGLETOFINESHIFT 19 /* 0x100000000 to 0x2000 */
+
+/*
+===============================================================================
+
+ GLOBAL TYPES
+
+===============================================================================
+*/
+
+/*
+#define NUMARTIFCTS 28
+*/
+
+#define TICRATE 35 /* number of tics / second */
+#define TICSPERSEC 35
+
+#define MINIMUM_HEAP_SIZE 0x800000 /* 8 meg */
+#define MAXIMUM_HEAP_SIZE 0x2000000 /* 32 meg */
+
+/*
+#define ANGLE_1 0x01000000
+*/
+#define ANGLE_45 0x20000000
+#define ANGLE_90 0x40000000
+#define ANGLE_180 0x80000000
+#define ANGLE_MAX 0xffffffff
+#define ANGLE_1 (ANGLE_45 / 45)
+#define ANGLE_60 (ANGLE_180 / 3)
+
+#define ANG45 0x20000000
+#define ANG90 0x40000000
+#define ANG180 0x80000000
+#define ANG270 0xc0000000
+
+typedef unsigned angle_t;
+
+typedef enum
+{
+ sk_baby,
+ sk_easy,
+ sk_medium,
+ sk_hard,
+ sk_nightmare
+} skill_t;
+
+typedef enum
+{
+ ev_keydown,
+ ev_keyup,
+ ev_mouse,
+ ev_joystick
+} evtype_t;
+
+typedef struct
+{
+ evtype_t type;
+ int data1; /* keys / mouse/joystick buttons */
+ int data2; /* mouse/joystick x move */
+ int data3; /* mouse/joystick y move */
+} event_t;
+
+typedef struct
+{
+ signed char forwardmove; /* *2048 for move */
+ signed char sidemove; /* *2048 for move */
+ short angleturn; /* <<16 for angle delta */
+ short consistancy; /* checks for net game */
+ byte chatchar;
+ byte buttons;
+ byte lookfly; /* look/fly up/down/centering */
+ byte arti; /* artitype_t to use */
+} ticcmd_t;
+
+#define BT_ATTACK 1
+#define BT_USE 2
+#define BT_CHANGE 4 /* if true, the next 3 bits hold weapon num */
+#define BT_WEAPONMASK (8 + 16 + 32)
+#define BT_WEAPONSHIFT 3
+
+#define BT_SPECIAL 128 /* game events, not really buttons */
+#define BTS_SAVEMASK (4 + 8 + 16)
+#define BTS_SAVESHIFT 2
+#define BT_SPECIALMASK 3
+#define BTS_PAUSE 1 /* pause the game */
+#define BTS_SAVEGAME 2 /* save the game at each console */
+/* savegame slot numbers occupy the second byte of buttons */
+
+/* The top 3 bits of the artifact field in the
+ * ticcmd_t struct are used as additional flags
+ */
+#define AFLAG_MASK 0x3F
+#define AFLAG_SUICIDE 0x40
+#define AFLAG_JUMP 0x80
+
+typedef enum
+{
+ GS_LEVEL,
+ GS_INTERMISSION,
+ GS_FINALE,
+ GS_DEMOSCREEN
+} gamestate_t;
+
+typedef enum
+{
+ ga_nothing,
+ ga_loadlevel,
+ ga_initnew,
+ ga_newgame,
+ ga_loadgame,
+ ga_savegame,
+ ga_playdemo,
+ ga_completed,
+ ga_leavemap,
+ ga_singlereborn,
+ ga_victory,
+ ga_worlddone,
+ ga_screenshot
+} gameaction_t;
+
+typedef enum
+{
+ wipe_0,
+ wipe_1,
+ wipe_2,
+ wipe_3,
+ wipe_4,
+ NUMWIPES,
+ wipe_random
+} wipe_t;
+
+typedef struct
+{
+ const char *name;
+ int *location;
+ int defaultvalue;
+ int minvalue;
+ int maxvalue;
+} default_t;
+
+typedef struct
+{
+ const char *name;
+ char *location; /* pointer to an 80 char array, null terminated */
+ char *defaultvalue; /* backup of the default value. malloc'ed at init */
+} default_str_t;
+
+/*
+===============================================================================
+
+ MAPOBJ DATA
+
+===============================================================================
+*/
+
+/* think_t is a function pointer to a routine to handle an actor */
+typedef void (*think_t) (void*);
+
+typedef struct thinker_s
+{
+ struct thinker_s *prev, *next;
+ think_t function;
+} thinker_t;
+
+struct player_s;
+
+typedef struct mobj_s
+{
+ thinker_t thinker; /* thinker node */
+
+ /* info for drawing */
+ fixed_t x, y, z;
+ struct mobj_s *snext, *sprev; /* links in sector (if needed) */
+ angle_t angle;
+ spritenum_t sprite; /* used to find patch_t and flip value */
+ int frame; /* might be ord with FF_FULLBRIGHT */
+
+ /* interaction info */
+ struct mobj_s *bnext, *bprev; /* links in blocks (if needed) */
+ struct subsector_s *subsector;
+ fixed_t floorz, ceilingz; /* closest together of contacted secs */
+ fixed_t floorpic; /* contacted sec floorpic */
+ fixed_t radius, height; /* for movement checking */
+ fixed_t momx, momy, momz; /* momentums */
+ int validcount; /* if == validcount, already checked */
+ mobjtype_t type;
+ mobjinfo_t *info; /* &mobjinfo[mobj->type] */
+ int tics; /* state tic counter */
+ state_t *state;
+ int damage; /* For missiles */
+ int flags;
+ int flags2; /* Heretic flags */
+
+ /* be doubly careful with these two: they may be used to store
+ * a state or the address of an mobj_t or player_t structure!!!
+ */
+ intptr_t special1; /* Special info */
+ intptr_t special2; /* Special info */
+
+ int health;
+ int movedir; /* 0-7 */
+ int movecount; /* when 0, select a new dir */
+ struct mobj_s *target; /* thing being chased/attacked (or NULL)
+ also the originator for missiles */
+ int reactiontime; /* if non 0, don't attack yet
+ used by player to freeze a bit after
+ teleporting */
+ int threshold; /* if > 0, the target will be chased
+ no matter what (even if shot) */
+ struct player_s *player; /* only valid if type == MT_PLAYER */
+ int lastlook; /* player number last looked for */
+ fixed_t floorclip; /* value to use for floor clipping */
+ int archiveNum; /* Identity during archive */
+ short tid; /* thing identifier */
+ byte special; /* special */
+ byte args[5]; /* special arguments */
+} mobj_t;
+
+/* each sector has a degenmobj_t in it's center for sound origin purposes */
+typedef struct
+{
+ thinker_t thinker; /* not used for anything. */
+ fixed_t x, y, z;
+} degenmobj_t;
+
+/* Most damage defined using HITDICE */
+#define HITDICE(a) ((1 + (P_Random() & 7)) * (a))
+
+/* frame flags */
+#define FF_FULLBRIGHT 0x8000 /* flag in thing->frame */
+#define FF_FRAMEMASK 0x7fff
+
+/* --- mobj.flags --- */
+#define MF_SPECIAL 1 /* call P_SpecialThing when touched */
+#define MF_SOLID 2
+#define MF_SHOOTABLE 4
+#define MF_NOSECTOR 8 /* don't use the sector links (invisible but touchable) */
+#define MF_NOBLOCKMAP 16 /* don't use the blocklinks (inert but displayable) */
+#define MF_AMBUSH 32
+#define MF_JUSTHIT 64 /* try to attack right back */
+#define MF_JUSTATTACKED 128 /* take at least one step before attacking */
+#define MF_SPAWNCEILING 256 /* hang from ceiling instead of floor */
+#define MF_NOGRAVITY 512 /* don't apply gravity every tic */
+
+/* movement flags */
+#define MF_DROPOFF 0x400 /* allow jumps from high places */
+#define MF_PICKUP 0x800 /* for players to pick up items */
+#define MF_NOCLIP 0x1000 /* player cheat */
+#define MF_SLIDE 0x2000 /* keep info about sliding along walls */
+#define MF_FLOAT 0x4000 /* allow moves to any height, no gravity */
+#define MF_TELEPORT 0x8000 /* don't cross lines or look at heights */
+#define MF_MISSILE 0x10000 /* don't hit same species, explode on block */
+
+#define MF_ALTSHADOW 0x20000 /* alternate fuzzy draw */
+#define MF_SHADOW 0x40000 /* use fuzzy draw (shadow demons / invis) */
+#define MF_NOBLOOD 0x80000 /* don't bleed when shot (use puff) */
+#define MF_CORPSE 0x100000 /* don't stop moving halfway off a step */
+#define MF_INFLOAT 0x200000 /* floating to a height for a move, don't */
+ /* auto float to target's height. */
+
+#define MF_COUNTKILL 0x400000 /* count towards intermission kill total */
+#define MF_ICECORPSE 0x800000 /* a frozen corpse (for blasting) */
+
+#define MF_SKULLFLY 0x1000000 /* skull in flight */
+#define MF_NOTDMATCH 0x2000000 /* don't spawn in death match (key cards) */
+
+//#define MF_TRANSLATION 0xc000000 /* if 0x4 0x8 or 0xc, use a translation */
+#define MF_TRANSLATION 0x1c000000 /* use a translation table (>>MF_TRANSHIFT) */
+
+#define MF_TRANSSHIFT 26 /* table for player colormaps */
+
+/* --- mobj.flags2 --- */
+
+#define MF2_LOGRAV 0x00000001 /* alternate gravity setting */
+#define MF2_WINDTHRUST 0x00000002 /* gets pushed around by the wind specials */
+#define MF2_FLOORBOUNCE 0x00000004 /* bounces off the floor */
+#define MF2_BLASTED 0x00000008 /* missile will pass through ghosts */
+#define MF2_FLY 0x00000010 /* fly mode is active */
+#define MF2_FLOORCLIP 0x00000020 /* if feet are allowed to be clipped */
+#define MF2_SPAWNFLOAT 0x00000040 /* spawn random float z */
+#define MF2_NOTELEPORT 0x00000080 /* does not teleport */
+#define MF2_RIP 0x00000100 /* missile rips through solid targets */
+#define MF2_PUSHABLE 0x00000200 /* can be pushed by other moving mobjs */
+#define MF2_SLIDE 0x00000400 /* slides against walls */
+#define MF2_ONMOBJ 0x00000800 /* mobj is resting on top of another mobj */
+#define MF2_PASSMOBJ 0x00001000 /* Enable z block checking. If on, */
+ /* this flag will allow the mobj to */
+ /* pass over/under other mobjs. */
+#define MF2_CANNOTPUSH 0x00002000 /* cannot push other pushable mobjs */
+#define MF2_DROPPED 0x00004000 /* dropped by a demon */
+#define MF2_BOSS 0x00008000 /* mobj is a major boss */
+#define MF2_FIREDAMAGE 0x00010000 /* does fire damage */
+#define MF2_NODMGTHRUST 0x00020000 /* does not thrust target when damaging */
+#define MF2_TELESTOMP 0x00040000 /* mobj can stomp another */
+#define MF2_FLOATBOB 0x00080000 /* use float bobbing z movement */
+#define MF2_DONTDRAW 0x00100000 /* don't generate a vissprite */
+#define MF2_IMPACT 0x00200000 /* an MF_MISSILE mobj can activate SPAC_IMPACT */
+#define MF2_PUSHWALL 0x00400000 /* mobj can push walls */
+#define MF2_MCROSS 0x00800000 /* can activate monster cross lines */
+#define MF2_PCROSS 0x01000000 /* can activate projectile cross lines */
+#define MF2_CANTLEAVEFLOORPIC 0x02000000 /* stay within a certain floor type */
+#define MF2_NONSHOOTABLE 0x04000000 /* mobj is totally non-shootable, but still considered solid */
+#define MF2_INVULNERABLE 0x08000000 /* mobj is invulnerable */
+#define MF2_DORMANT 0x10000000 /* thing is dormant */
+#define MF2_ICEDAMAGE 0x20000000 /* does ice damage */
+#define MF2_SEEKERMISSILE 0x40000000 /* is a seeker (for reflection) */
+#define MF2_REFLECTIVE 0x80000000 /* reflects missiles */
+
+/*============================================================================*/
+
+/* ===== Player Class Types ===== */
+typedef enum
+{
+ PCLASS_FIGHTER,
+ PCLASS_CLERIC,
+ PCLASS_MAGE,
+#ifdef ASSASSIN
+ PCLASS_ASS,
+#endif
+ /* end of the actual classes */
+ NUMCLASSES_HUMAN,
+
+ /* morphed classes (Pig ...) */
+ PCLASS_PIG = NUMCLASSES_HUMAN,
+
+ NUMCLASSES /* all classes */
+} pclass_t;
+
+typedef enum
+{
+ PST_LIVE, /* playing */
+ PST_DEAD, /* dead on the ground */
+ PST_REBORN /* ready to restart */
+} playerstate_t;
+
+/* psprites are scaled shapes directly on the view screen
+ * coordinates are given for a 320*200 view screen
+ */
+typedef enum
+{
+ ps_weapon,
+ ps_flash,
+ NUMPSPRITES
+} psprnum_t;
+
+typedef struct
+{
+ state_t *state; /* a NULL state means not active */
+ int tics;
+ fixed_t sx, sy;
+} pspdef_t;
+
+/* Old Heretic key type
+typedef enum
+{
+ key_yellow,
+ key_green,
+ key_blue,
+ NUMKEYS
+} keytype_t;
+*/
+
+typedef enum
+{
+ KEY_1,
+ KEY_2,
+ KEY_3,
+ KEY_4,
+ KEY_5,
+ KEY_6,
+ KEY_7,
+ KEY_8,
+ KEY_9,
+ KEY_A,
+ KEY_B,
+ NUMKEYS
+} keytype_t;
+
+typedef enum
+{
+ ARMOR_ARMOR,
+ ARMOR_SHIELD,
+ ARMOR_HELMET,
+ ARMOR_AMULET,
+ NUMARMOR
+} armortype_t;
+
+typedef enum
+{
+ WP_FIRST,
+ WP_SECOND,
+ WP_THIRD,
+ WP_FOURTH,
+ NUMWEAPONS,
+ WP_NOCHANGE
+} weapontype_t;
+
+typedef enum
+{
+ MANA_1,
+ MANA_2,
+ NUMMANA,
+ MANA_BOTH,
+ MANA_NONE
+} manatype_t;
+
+#define MAX_MANA 200
+
+#define WPIECE1 1
+#define WPIECE2 2
+#define WPIECE3 4
+
+typedef struct
+{
+ manatype_t mana;
+ int upstate;
+ int downstate;
+ int readystate;
+ int atkstate;
+ int holdatkstate;
+ int flashstate;
+} weaponinfo_t;
+
+extern weaponinfo_t WeaponInfo[NUMWEAPONS][NUMCLASSES];
+
+typedef enum
+{
+ arti_none,
+ arti_invulnerability,
+ arti_health,
+ arti_superhealth,
+ arti_healingradius,
+ arti_summon,
+ arti_torch,
+ arti_egg,
+ arti_fly,
+ arti_blastradius,
+ arti_poisonbag,
+ arti_teleportother,
+ arti_speed,
+ arti_boostmana,
+ arti_boostarmor,
+ arti_teleport,
+ /* Puzzle artifacts */
+ arti_firstpuzzitem,
+ arti_puzzskull = arti_firstpuzzitem,
+ arti_puzzgembig,
+ arti_puzzgemred,
+ arti_puzzgemgreen1,
+ arti_puzzgemgreen2,
+ arti_puzzgemblue1,
+ arti_puzzgemblue2,
+ arti_puzzbook1,
+ arti_puzzbook2,
+ arti_puzzskull2,
+ arti_puzzfweapon,
+ arti_puzzcweapon,
+ arti_puzzmweapon,
+ arti_puzzgear1,
+ arti_puzzgear2,
+ arti_puzzgear3,
+ arti_puzzgear4,
+ NUMARTIFACTS
+} artitype_t;
+
+typedef enum
+{
+ pw_None,
+ pw_invulnerability,
+ pw_allmap,
+ pw_infrared,
+ pw_flight,
+ pw_shield,
+ pw_health2,
+ pw_speed,
+ pw_minotaur,
+ NUMPOWERS
+} powertype_t;
+
+#define INVULNTICS (30 * 35)
+#define INVISTICS (60 * 35)
+#define INFRATICS (120* 35)
+#define IRONTICS (60 * 35)
+#define WPNLEV2TICS (40 * 35)
+#define FLIGHTTICS (60 * 35)
+#define SPEEDTICS (45 * 35)
+#define MORPHTICS (40 * 35)
+#define MAULATORTICS (25 * 35)
+
+#define MESSAGETICS ( 4 * 35)
+#define BLINKTHRESHOLD ( 4 * 35)
+
+#define NUMINVENTORYSLOTS NUMARTIFACTS
+
+typedef struct
+{
+ int type;
+ int count;
+} inventory_t;
+
+/*
+================
+player_t
+================
+*/
+typedef struct player_s
+{
+ mobj_t *mo;
+ playerstate_t playerstate;
+ ticcmd_t cmd;
+
+ pclass_t playerclass; /* player class type */
+
+ fixed_t viewz; /* focal origin above r.z */
+ fixed_t viewheight; /* base height above floor for viewz */
+ fixed_t deltaviewheight; /* squat speed */
+ fixed_t bob; /* bounded/scaled total momentum */
+
+ int flyheight;
+ int lookdir;
+ boolean centering;
+ int health; /* only used between levels, mo->health */
+ /* is used during levels */
+ int armorpoints[NUMARMOR];
+
+ inventory_t inventory[NUMINVENTORYSLOTS];
+ artitype_t readyArtifact;
+ int artifactCount;
+ int inventorySlotNum;
+ int powers[NUMPOWERS];
+ int keys;
+ int pieces; /* Fourth Weapon pieces */
+ signed int frags[MAXPLAYERS]; /* kills of other players */
+ weapontype_t readyweapon;
+ weapontype_t pendingweapon; /* wp_nochange if not changing */
+ boolean weaponowned[NUMWEAPONS];
+ int mana[NUMMANA];
+ int attackdown, usedown; /* true if button down last tic */
+ int cheats; /* bit flags */
+
+ int refire; /* refired shots are less accurate */
+
+ int killcount, itemcount, secretcount; /* for intermission */
+ char message[80]; /* hint messages */
+ int messageTics; /* counter for showing messages */
+ short ultimateMessage;
+ short yellowMessage;
+ int damagecount, bonuscount;/* for screen flashing */
+ int poisoncount; /* screen flash for poison damage */
+ mobj_t *poisoner; /* NULL for non-player mobjs */
+ mobj_t *attacker; /* who did damage (NULL for floors) */
+ int extralight; /* so gun flashes light up areas */
+ int fixedcolormap; /* can be set to REDCOLORMAP, etc */
+ int colormap; /* 0-3 for which color to draw player */
+ pspdef_t psprites[NUMPSPRITES]; /* view sprites (gun, etc) */
+ int morphTics; /* player is a pig if > 0 */
+ unsigned int jumpTics; /* delay the next jump for a moment */
+ unsigned int worldTimer; /* total time the player's been playing */
+} player_t;
+
+#define CF_NOCLIP 1
+#define CF_GODMODE 2
+#define CF_NOMOMENTUM 4 /* not really a cheat, just a debug aid */
+
+
+#define BACKUPTICS 12
+
+typedef struct
+{
+ unsigned int checksum; /* high bit is retransmit request */
+ byte retransmitfrom; /* only valid if NCMD_RETRANSMIT */
+ byte starttic;
+ byte player, numtics;
+ ticcmd_t cmds[BACKUPTICS];
+} doomdata_t;
+
+typedef struct
+{
+ int32_t id;
+ short intnum; /* DOOM executes an int to execute commands */
+
+/* communication between DOOM and the driver */
+ short command; /* CMD_SEND or CMD_GET */
+ short remotenode; /* dest for send, set by get (-1 = no packet) */
+ short datalength; /* bytes in doomdata to be sent */
+
+/* info common to all nodes */
+ short numnodes; /* console is allways node 0 */
+ short ticdup; /* 1 = no duplication, 2-5 = dup for slow nets */
+ short extratics; /* 1 = send a backup tic in every packet */
+ short deathmatch; /* 1 = deathmatch */
+ short savegame; /* -1 = new game, 0-5 = load savegame */
+ short episode; /* 1-3 */
+ short map; /* 1-9 */
+ short skill; /* 1-5 */
+
+/* info specific to this node */
+ short consoleplayer;
+ short numplayers;
+ short angleoffset; /* 1 = left, 0 = center, -1 = right */
+ short drone; /* 1 = drone */
+
+/* packet data to be sent */
+ doomdata_t data;
+} doomcom_t;
+
+#define DOOMCOM_ID 0x12345678l
+
+extern doomcom_t *doomcom;
+extern doomdata_t *netbuffer; /* points inside doomcom */
+
+/*
+#define MAXNETNODES 8
+*/
+#define MAXNETNODES 16 /* max computers in a game */
+
+#define CMD_SEND 1
+#define CMD_GET 2
+#define CMD_FRAG 3
+
+#define SBARHEIGHT 39 /* status bar height at bottom of screen */
+
+void NET_SendFrags(player_t *player);
+
+/*
+===============================================================================
+
+ GLOBAL VARIABLES
+
+===============================================================================
+*/
+
+#define TELEFOGHEIGHT (32 * FRACUNIT)
+
+#define MAXEVENTS 64
+
+extern event_t events[MAXEVENTS];
+extern int eventhead;
+extern int eventtail;
+
+extern fixed_t finesine[5*FINEANGLES/4];
+extern fixed_t *finecosine;
+
+extern gameaction_t gameaction;
+extern boolean paused;
+extern boolean shareware; /* true if other episodes not present */
+extern boolean oldwad_10; /* true if version 1.0 wad files (shareware or full) */
+extern boolean mac_hexen; /* true if Macintosh version wad (shareware or full) */
+extern boolean DevMaps; /* true = map development mode */
+extern const char *DevMapsDir; /* development maps directory */
+extern boolean nomonsters; /* checkparm of -nomonsters */
+extern boolean respawnparm; /* checkparm of -respawn */
+extern boolean randomclass; /* checkparm of -randclass */
+extern boolean debugmode; /* checkparm of -debug */
+extern boolean usergame; /* ok to save / end game */
+extern boolean ravpic; /* checkparm of -ravpic */
+extern boolean deathmatch; /* only if started as net death */
+extern boolean netgame; /* only true if >1 player */
+extern boolean cmdfrag; /* true if a CMD_FRAG packet should be sent out every kill */
+
+extern boolean playeringame[MAXPLAYERS];
+extern pclass_t PlayerClasses[MAXPLAYERS];
+extern int consoleplayer; /* player taking events and displaying */
+extern int displayplayer;
+extern int viewangleoffset;/* ANG90 = left side, ANG270 = right */
+extern player_t players[MAXPLAYERS];
+
+extern boolean singletics; /* debug flag to cancel adaptiveness */
+extern boolean DebugSound; /* debug flag for displaying sound info */
+
+extern boolean demoplayback;
+extern int Sky1Texture;
+extern int Sky2Texture;
+
+extern int maxzone; /* Maximum chunk allocated for zone heap */
+
+extern gamestate_t gamestate;
+extern skill_t gameskill;
+extern int gameepisode;
+extern int gamemap;
+extern int prevmap;
+extern int levelstarttic; /* gametic at level start */
+extern int leveltime; /* tics in game play for par */
+
+extern int ticcount;
+
+extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
+extern int ticdup;
+extern ticcmd_t localcmds[BACKUPTICS];
+extern int rndindex;
+extern int gametic, maketic;
+extern int nettics[MAXNETNODES];
+
+#define MAXDEATHMATCHSTARTS 16
+extern mapthing_t *deathmatch_p;
+extern mapthing_t deathmatchstarts[MAXDEATHMATCHSTARTS];
+
+/* Position indicator for cooperative net-play reborn */
+extern int RebornPosition;
+
+#define MAX_PLAYER_STARTS 8
+extern mapthing_t playerstarts[MAX_PLAYER_STARTS][MAXPLAYERS];
+
+extern int viewwindowx;
+extern int viewwindowy;
+extern int viewwidth;
+extern int scaledviewwidth;
+extern int viewheight;
+
+extern int mouseSensitivity;
+
+extern boolean precache; /* if true, load all graphics at level load */
+
+extern byte *screen; /* off screen work buffer, from V_video.c */
+
+extern boolean singledemo; /* quit after playing a demo from cmdline */
+
+extern FILE *debugfile;
+extern int bodyqueslot;
+extern skill_t startskill;
+extern int startepisode;
+extern int startmap;
+extern boolean autostart;
+
+
+/*
+===============================================================================
+
+ GLOBAL FUNCTIONS
+
+===============================================================================
+*/
+
+
+fixed_t FixedMul (fixed_t a, fixed_t b);
+fixed_t FixedDiv (fixed_t a, fixed_t b);
+fixed_t FixedDiv2 (fixed_t a, fixed_t b);
+
+#undef _HAVE_FIXED_ASM
+
+#if !defined(_DISABLE_ASM)
+#if defined(__i386__) || defined(__386__) || defined(_M_IX86)
+#if defined(__WATCOMC__)
+
+#define _HAVE_FIXED_ASM 1
+
+#pragma aux FixedMul = \
+ "imul ebx", \
+ "shrd eax,edx,16" \
+ parm [eax] [ebx] \
+ value [eax] \
+ modify exact [eax edx]
+
+#pragma aux FixedDiv2 = \
+ "cdq", \
+ "shld edx,eax,16", \
+ "sal eax,16", \
+ "idiv ebx" \
+ parm [eax] [ebx] \
+ value [eax] \
+ modify exact [eax edx]
+
+#elif defined(__GNUC__)
+
+#define _HAVE_FIXED_ASM 1
+
+# if defined(_INLINE_FIXED_ASM)
+# if (__GNUC__ == 2) && (__GNUC_MINOR__ <= 91)
+# define FixedMul(fa,fb) ({ int __value, __fb = (fb); \
+ __asm__("imul %%ebx; shrd $16,%%edx,%%eax" \
+ : "=a" (__value) \
+ : "0" (fa), "b" (__fb) \
+ : "eax", "edx" ); __value; })
+
+# define FixedDiv2(fa,fb) ({ int __value; \
+ __asm__("cdq; shld $16,%%eax,%%edx; sall $16,%%eax; idiv %%ebx" \
+ : "=a" (__value) \
+ : "0" (fa), "b" (fb) \
+ : "eax", "edx" ); __value; })
+
+# else /* GCC > 2.91.x */
+# define FixedMul(fa,fb) ({ int __value, __fb = (fb); \
+ __asm__("imul %%ebx; shrd $16,%%edx,%%eax" \
+ : "=a" (__value) \
+ : "0" (fa), "b" (__fb) \
+ : "edx" ); __value; })
+
+# define FixedDiv2(fa,fb) ({ int __value; \
+ __asm__("cdq; shld $16,%%eax,%%edx; sall $16,%%eax; idiv %%ebx" \
+ : "=a" (__value) \
+ : "0" (fa), "b" (fb) \
+ : "edx" ); __value; })
+
+# endif /* GCC/EGCS versions */
+
+# endif /* _INLINE_FIXED_ASM */
+#endif
+#endif /* X86 */
+#endif /* !_DISABLE_ASM */
+
+#define FIX2FLT(x) ((float)((x)>>FRACBITS) + (float)((x)&(FRACUNIT-1)) / (float)(FRACUNIT))
+#define Q_FIX2FLT(x) ((float)((x)>>FRACBITS))
+
+
+int16_t ShortSwap(int16_t) __attribute__((__const__));
+int32_t LongSwap (int32_t) __attribute__((__const__));
+
+#if defined(__GNUC__)
+static inline __attribute__((__const__)) int16_t _H2_SWAP16(int16_t x)
+{
+ return (int16_t) (((uint16_t)x << 8) | ((uint16_t)x >> 8));
+}
+static inline __attribute__((__const__)) int32_t _H2_SWAP32(int32_t x)
+{
+ return (int32_t) (((uint32_t)x << 24) | ((uint32_t)x >> 24) |
+ (((uint32_t)x & (uint32_t)0x0000ff00UL) << 8) |
+ (((uint32_t)x & (uint32_t)0x00ff0000UL) >> 8));
+}
+#endif /* GCC */
+
+/*
+#ifdef __BIG_ENDIAN__
+*/
+#ifdef WORDS_BIGENDIAN
+# ifdef __GNUC__
+# define SHORT(a) _H2_SWAP16((a))
+# define LONG(a) _H2_SWAP32((a))
+# else
+# define SHORT(x) ShortSwap((x))
+# define LONG(x) LongSwap((x))
+# endif
+#else
+#define SHORT(x) (x)
+#define LONG(x) (x)
+#endif
+
+/* ---- READ_INT16/32 --- */
+
+#define READ_INT16(b) ((b)[0] | ((b)[1] << 8))
+#define READ_INT32(b) ((b)[0] | ((b)[1] << 8) | ((b)[2] << 16) | ((b)[3] << 24))
+#define INCR_INT16(b) (b)+=2
+#define INCR_INT32(b) (b)+=4
+
+
+/* ----- MEMORY ZONE ---- */
+
+/* tags < 100 are not overwritten until freed */
+#define PU_STATIC 1 /* static entire execution time */
+#define PU_SOUND 2 /* static while playing */
+#define PU_MUSIC 3 /* static while playing */
+#define PU_DAVE 4 /* anything else Dave wants static */
+#define PU_LEVEL 50 /* static until level exited */
+#define PU_LEVSPEC 51 /* a special thinker in a level */
+/* tags >= 100 are purgable whenever needed */
+#define PU_PURGELEVEL 100
+#define PU_CACHE 101
+
+#define ZONEID 0x1d4a11
+
+void Z_Init (void);
+void *Z_Malloc (int size, int tag, void *ptr);
+void Z_Free (void *ptr);
+void Z_FreeTags (int lowtag, int hightag);
+void Z_CheckHeap (void);
+void Z_ChangeTag2 (void *ptr, int tag);
+/*
+void Z_DumpHeap (int lowtag, int hightag);
+void Z_FileDumpHeap (FILE *f);
+int Z_FreeMemory (void);
+*/
+
+typedef struct memblock_s
+{
+ int size; /* including the header and possibly tiny fragments */
+ void **user; /* NULL if a free block */
+ int tag; /* purgelevel */
+ int id; /* should be ZONEID */
+ struct memblock_s *next, *prev;
+} memblock_t;
+
+#define Z_ChangeTag(p,t) \
+{ \
+ if (((memblock_t *)((byte *)((p)) - sizeof(memblock_t)))->id != ZONEID) \
+ I_Error("Z_CT at %s:%i", __FILE__, __LINE__); \
+ Z_ChangeTag2((p),(t)); \
+};
+
+/* ------- WADFILE ------- */
+typedef struct
+{
+ char name[8];
+ int handle, position, size;
+} lumpinfo_t;
+
+extern lumpinfo_t *lumpinfo;
+extern int numlumps;
+extern const char *waddir;
+
+boolean W_IsWadPresent(const char *filename);
+void W_InitMultipleFiles(const char **filenames);
+void W_OpenAuxiliary(const char *filename);
+void W_CloseAuxiliaryFile(void);
+void W_CloseAuxiliary(void);
+void W_UsePrimary(void);
+void W_UseAuxiliary(void);
+int W_CheckNumForName(const char *name);
+int W_GetNumForName(const char *name);
+int W_LumpLength(int lump);
+void W_ReadLump(int lump, void *dest);
+void *W_CacheLumpNum(int lump, int tag);
+void *W_CacheLumpName(const char *name, int tag);
+void W_CheckWADFiles(void);
+
+
+/* ---------- BASE LEVEL ---------- */
+
+void H2_Main(void);
+/* not a globally visible function, just included for source reference
+ * calls all startup code
+ * parses command line options
+ * if not overrided, calls N_AdvanceDemo
+ */
+
+void H2_GameLoop(void);
+/* not a globally visible function, just included for source reference
+ * called by H2_Main, never exits
+ * manages timing and IO
+ * calls all ?_Responder, ?_Ticker, and ?_Drawer functions
+ * calls I_GetTime, I_StartFrame, and I_StartTic
+ */
+
+void H2_PostEvent(event_t *ev);
+/* called by IO functions when input is detected */
+
+void NetUpdate (void);
+/* create any new ticcmds and broadcast to other players */
+
+void D_QuitNetGame (void);
+/* broadcasts special packets to other players to notify of game exit */
+
+void TryRunTics (void);
+
+#if !(defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__) || \
+ defined(_WIN32) || defined(_WIN64))
+char *strupr (char *str);
+char *strlwr (char *str);
+int filelength(int handle);
+#endif
+
+
+/* --------- SYSTEM IO --------- */
+
+#if 1
+#define SCREENWIDTH 320
+#define SCREENHEIGHT 200
+#else
+#define SCREENWIDTH 560
+#define SCREENHEIGHT 375
+#endif
+
+byte *I_ZoneBase (int *size);
+/* called by startup code to get the ammount of memory to malloc
+ * for the zone management
+ */
+
+int I_GetTime (void);
+/* called by H2_GameLoop
+ * returns current time in tics
+ */
+
+void I_StartFrame (void);
+/* called by H2_GameLoop
+ * called before processing any tics in a frame (just after displaying a frame)
+ * time consuming syncronous operations are performed here (joystick reading)
+ * can call H2_PostEvent
+ */
+
+void I_StartTic (void);
+/* called by H2_GameLoop
+ * called before processing each tic in a frame
+ * quick syncronous operations are performed here
+ * can call H2_PostEvent
+ *
+ * asyncronous interrupt functions should maintain private ques that are
+ * read by the syncronous functions to be converted into events
+ */
+
+void I_Init (void);
+/* called by H2_Main
+ * determines the hardware configuration and sets up the video mode
+ */
+
+void I_InitGraphics (void);
+
+void I_InitNetwork (void);
+void I_NetCmd (void);
+
+void I_CheckExternDriver(void);
+
+void I_Error (const char *error, ...) __attribute__((__format__(__printf__,1,2), __noreturn__));
+/* called by anything that can generate a terminal error
+ * bad exit with diagnostic message
+ */
+
+void I_Quit (void) __attribute__((__noreturn__));
+/* called by M_Responder when quit is selected
+ * clean exit, displays sell blurb
+ */
+
+void I_SetPalette (byte *palette);
+/* takes full 8 bit values */
+
+void I_Update(void);
+/* Copy buffer to video */
+
+void I_WipeUpdate(wipe_t wipe);
+/* Copy buffer to video with wipe effect */
+
+void I_WaitVBL(int count);
+/* wait for vertical retrace or pause a bit */
+
+void I_BeginRead (void);
+void I_EndRead (void);
+
+byte *I_AllocLow (int length);
+/* allocates from low memory under dos, just mallocs under unix */
+
+extern boolean useexterndriver;
+
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+#define EBT_FIRE 1
+#define EBT_OPENDOOR 2
+#define EBT_SPEED 4
+#define EBT_STRAFE 8
+#define EBT_MAP 0x10
+#define EBT_INVENTORYLEFT 0x20
+#define EBT_INVENTORYRIGHT 0x40
+#define EBT_USEARTIFACT 0x80
+#define EBT_FLYDROP 0x100
+#define EBT_CENTERVIEW 0x200
+#define EBT_PAUSE 0x400
+#define EBT_WEAPONCYCLE 0x800
+#define EBT_JUMP 0x1000
+
+typedef struct
+{
+ short vector; /* Interrupt vector */
+
+ signed char moveForward; /* forward/backward (maxes at 50) */
+ signed char moveSideways; /* strafe (maxes at 24) */
+ short angleTurn; /* turning speed (640 [slow] 1280 [fast]) */
+ short angleHead; /* head angle (+2080 [left] : 0 [center] : -2048 [right]) */
+ signed char pitch; /* look up/down (-110 : +90) */
+ signed char flyDirection; /* flyheight (+1/-1) */
+ unsigned short buttons; /* EBT_* flags */
+} externdata_t;
+
+void I_Tactile (int on, int off, int total);
+#endif /* externdriver, DOS */
+
+
+/* ---- GAME ---- */
+
+void G_DeathMatchSpawnPlayer (int playernum);
+
+void G_InitNew (skill_t skill, int episode, int map);
+
+void G_DeferedInitNew (skill_t skill, int episode, int map);
+/* can be called by the startup code or M_Responder
+ * a normal game starts at map 1, but a warp test can start elsewhere
+ */
+
+void G_DeferredNewGame(skill_t skill);
+
+void G_DeferedPlayDemo (const char *demo);
+
+void G_LoadGame(int slot);
+/* can be called by the startup code or M_Responder
+ * calls P_SetupLevel or W_EnterWorld
+ */
+
+void G_DoLoadGame (void);
+
+void G_SaveGame (int slot, const char *description);
+/* called by M_Responder */
+
+void G_RecordDemo (skill_t skill, int numplayers, int episode,
+ int map, const char *name);
+/* only called by startup code */
+
+void G_PlayDemo (const char *name);
+void G_TimeDemo (const char *name);
+
+void G_TeleportNewMap(int map, int position);
+
+void G_Completed(int map, int position);
+/*
+void G_ExitLevel (void);
+void G_SecretExitLevel (void);
+*/
+
+void G_StartNewGame(skill_t skill);
+void G_StartNewInit(void);
+
+void G_WorldDone (void);
+
+void G_Ticker (void);
+boolean G_Responder (event_t *ev);
+
+void G_ScreenShot (void);
+
+
+/* ------- SV_SAVE ------- */
+
+#if (MAXPLAYERS == MAXPLAYERS_10)
+#define HXS_VERSION_TEXT "HXS Ver 2.36"
+#else
+#define HXS_VERSION_TEXT "HXS Ver 2.37"
+#endif
+#define HXS_VERSION_TEXT_LENGTH 16
+#define HXS_DESCRIPTION_LENGTH 24
+
+void SV_SaveGame(int slot, const char *description);
+void SV_SaveMap(boolean savePlayers);
+void SV_LoadGame(int slot);
+void SV_MapTeleport(int map, int position);
+void SV_LoadMap(void);
+void SV_InitBaseSlot(void);
+void SV_UpdateRebornSlot(void);
+void SV_ClearRebornSlot(void);
+boolean SV_RebornSlotAvailable(void);
+int SV_GetRebornSlot(void);
+
+
+/* ----- PLAY ----- */
+
+void P_Ticker (void);
+/* called by C_Ticker
+ * can call G_PlayerExited
+ * carries out all thinking of monsters and players
+ */
+
+void P_SetupLevel (int episode, int map, int playermask, skill_t skill);
+/* called by W_Ticker */
+
+void P_Init (void);
+/* called by startup code */
+
+int P_GetMapCluster(int map);
+int P_TranslateMap(int map);
+int P_GetMapCDTrack(int map);
+int P_GetMapWarpTrans(int map);
+int P_GetMapNextMap(int map);
+int P_GetMapSky1Texture(int map);
+int P_GetMapSky2Texture(int map);
+const char *P_GetMapName(int map);
+fixed_t P_GetMapSky1ScrollDelta(int map);
+fixed_t P_GetMapSky2ScrollDelta(int map);
+boolean P_GetMapDoubleSky(int map);
+boolean P_GetMapLightning(int map);
+boolean P_GetMapFadeTable(int map);
+const char *P_GetMapSongLump(int map);
+void P_PutMapSongLump(int map, const char *lumpName);
+int P_GetCDStartTrack(void);
+int P_GetCDEnd1Track(void);
+int P_GetCDEnd2Track(void);
+int P_GetCDEnd3Track(void);
+int P_GetCDIntermissionTrack(void);
+int P_GetCDTitleTrack(void);
+
+
+/* ------- REFRESH ------- */
+
+extern boolean setsizeneeded;
+
+extern boolean BorderNeedRefresh;
+extern boolean BorderTopRefresh;
+
+extern int UpdateState;
+
+/* define the different areas for the dirty map */
+#define I_NOUPDATE 0
+#define I_FULLVIEW 1
+#define I_STATBAR 2
+#define I_MESSAGES 4
+#define I_FULLSCRN 8
+
+void R_RenderPlayerView (player_t *player);
+/* called by G_Drawer */
+
+void R_Init (void);
+/* called by startup code */
+
+void R_DrawViewBorder (void);
+void R_DrawTopBorder (void);
+/* if the view size is not full screen, draws a border around it */
+
+void R_SetViewSize (int blocks, int detail);
+/* called by M_Responder */
+
+int R_FlatNumForName (const char *name);
+
+int R_TextureNumForName (const char *name);
+int R_CheckTextureNumForName (const char *name);
+/* called by P_Ticker for switches and animations
+ * returns the texture number for the texture name
+ */
+
+
+/* ---- MISC ---- */
+extern const char **myargv;
+extern int myargc;
+extern int localQuakeHappening[MAXPLAYERS];
+
+int M_CheckParm(const char *check);
+/* returns the position of the given parameter in the arg list (0 if not found) */
+
+boolean M_ParmExists(const char *check);
+
+void M_ExtractFileBase(const char *path, char *dest);
+
+void M_ForceUppercase(char *text);
+/* Changes a string to uppercase */
+
+int M_Random (void);
+/* returns a number from 0 to 255 */
+
+unsigned char P_Random(void);
+/* as M_Random, but used only by the play simulation */
+
+void M_ClearRandom (void);
+/* fix randoms for demos */
+
+void M_FindResponseFile(void);
+
+void M_ClearBox (fixed_t *box);
+void M_AddToBox (fixed_t *box, fixed_t x, fixed_t y);
+/* bounding box functions */
+
+boolean M_WriteFile(char const *name, const void *source, int length);
+int M_ReadFile(char const *name, void **buffer);
+int M_ReadFileCLib(char const *name, void **buffer);
+
+void M_ScreenShot (void);
+
+void M_LoadDefaults(const char *fileName);
+
+void M_SaveDefaults (void);
+
+
+/* ----- SC_man.c ---- */
+
+void SC_Open(const char *name);
+void SC_OpenLump(const char *name);
+void SC_OpenFile(const char *name);
+void SC_OpenFileCLib(const char *name);
+void SC_Close(void);
+boolean SC_GetString(void);
+void SC_MustGetString(void);
+void SC_MustGetStringName(const char *name);
+boolean SC_GetNumber(void);
+void SC_MustGetNumber(void);
+void SC_UnGet(void);
+/*
+boolean SC_Check(void);
+*/
+boolean SC_Compare(const char *text);
+int SC_MatchString(const char **strings);
+int SC_MustMatchString(const char **strings);
+void SC_ScriptError(const char *message) __attribute__((__noreturn__));
+
+extern char *sc_String;
+extern int sc_Number;
+extern int sc_Line;
+extern boolean sc_End;
+extern boolean sc_Crossed;
+extern boolean sc_FileScripts;
+extern const char *sc_ScriptsDir;
+
+
+/* ---- SN_sonix.c ---- */
+
+enum
+{
+ SEQ_PLATFORM,
+ SEQ_PLATFORM_HEAVY, /* same script as a normal platform */
+ SEQ_PLATFORM_METAL,
+ SEQ_PLATFORM_CREAK, /* same script as a normal platform */
+ SEQ_PLATFORM_SILENCE,
+ SEQ_PLATFORM_LAVA,
+ SEQ_PLATFORM_WATER,
+ SEQ_PLATFORM_ICE,
+ SEQ_PLATFORM_EARTH,
+ SEQ_PLATFORM_METAL2,
+ SEQ_DOOR_STONE,
+ SEQ_DOOR_HEAVY,
+ SEQ_DOOR_METAL,
+ SEQ_DOOR_CREAK,
+ SEQ_DOOR_SILENCE,
+ SEQ_DOOR_LAVA,
+ SEQ_DOOR_WATER,
+ SEQ_DOOR_ICE,
+ SEQ_DOOR_EARTH,
+ SEQ_DOOR_METAL2,
+ SEQ_ESOUND_WIND,
+ SEQ_NUMSEQ
+};
+
+typedef enum
+{
+ SEQTYPE_STONE,
+ SEQTYPE_HEAVY,
+ SEQTYPE_METAL,
+ SEQTYPE_CREAK,
+ SEQTYPE_SILENCE,
+ SEQTYPE_LAVA,
+ SEQTYPE_WATER,
+ SEQTYPE_ICE,
+ SEQTYPE_EARTH,
+ SEQTYPE_METAL2,
+ SEQTYPE_NUMSEQ
+} seqtype_t;
+
+void SN_InitSequenceScript(void);
+void SN_StartSequence(mobj_t *mobj, int sequence);
+void SN_StartSequenceName(mobj_t *mobj, const char *name);
+void SN_StopSequence(mobj_t *mobj);
+void SN_UpdateActiveSequences(void);
+void SN_StopAllSequences(void);
+int SN_GetSequenceOffset(int sequence, int *sequencePtr);
+void SN_ChangeNodeData(int nodeNum, int seqOffset, int delayTics, int volume, int currentSoundID);
+
+typedef struct seqnode_s seqnode_t;
+struct seqnode_s
+{
+ int *sequencePtr;
+ int sequence;
+ mobj_t *mobj;
+ int currentSoundID;
+ int delayTics;
+ int volume;
+ int stopSound;
+ seqnode_t *prev;
+ seqnode_t *next;
+};
+
+extern int ActiveSequences;
+extern seqnode_t *SequenceListHead;
+
+extern boolean nosound;
+extern int mouselook;
+
+
+/* ---- Interlude (IN_lude.c) ---- */
+
+extern boolean intermission;
+
+void IN_Start(void);
+void IN_Ticker(void);
+void IN_Drawer(void);
+
+/* ---- Interlude (hubmsg.c) ----- */
+
+const char *GetClusterText(int sequence);
+const char *GetFinaleText (int sequence);
+
+/* ---- Finale (F_finale.c) ------ */
+
+void F_Drawer(void);
+void F_Ticker(void);
+void F_StartFinale(void);
+
+
+/* ---- Chat mode (CT_chat.c) ---- */
+
+void CT_Init(void);
+void CT_Drawer(void);
+boolean CT_Responder(event_t *ev);
+void CT_Ticker(void);
+char CT_dequeueChatChar(void);
+
+extern char chat_macros[10][80];
+extern boolean chatmodeon;
+
+
+/* ---- STATUS BAR (SB_bar.c) ---- */
+
+extern int inv_ptr;
+extern int curpos;
+extern int SB_state;
+
+void SB_Init(void);
+void SB_SetClassData(void);
+boolean SB_Responder(event_t *event);
+void SB_Ticker(void);
+void SB_Drawer(void);
+void Draw_TeleportIcon(void);
+void Draw_SaveIcon(void);
+void Draw_LoadIcon(void);
+
+
+/* ---- MENU (MN_menu.c) ---- */
+
+void MN_Init(void);
+void MN_ActivateMenu(void);
+void MN_DeactivateMenu(void);
+boolean MN_Responder(event_t *event);
+void MN_Ticker(void);
+void MN_Drawer(void);
+void MN_DrTextA(const char *text, int x, int y);
+void MN_DrTextAYellow(const char *text, int x, int y);
+int MN_TextAWidth(const char *text);
+void MN_DrTextB(const char *text, int x, int y);
+int MN_TextBWidth(const char *text);
+
+
+/* --- AUTOMAP---- */
+
+#define AM_TRANSPARENT 1 /* compile time option. 0: old style map drawn */
+ /* onto solid background. 1: transparent map. */
+
+extern boolean automapactive;
+
+
+/* ---- VIDEO ---- */
+
+extern int dirtybox[4];
+extern byte gammatable[5][256];
+extern int usegamma;
+
+void V_Init(void); /* Allocates buffer screens, call before R_Init */
+void V_DrawPatch(int x, int y, patch_t *patch);
+void V_DrawPatchBuffer(int x, int y, patch_t *patch, byte *buffer);
+void V_DrawFuzzPatch(int x, int y, patch_t *patch);
+void V_DrawAltFuzzPatch(int x, int y, patch_t *patch);
+void V_DrawShadowedPatch(int x, int y, patch_t *patch);
+void V_BlitToScreen (int x, int y, byte *buffer, int width, int height);
+void V_DrawRawScreen(byte *raw);
+
+#include "sounds.h"
+
+#endif /* __H2DEF__ */
+
--- /dev/null
+++ b/h2stdinc.h
@@ -1,0 +1,166 @@
+/*
+ h2stdinc.h
+ includes the minimum necessary stdc headers,
+ defines common and / or missing types.
+
+ $Id: h2stdinc.h 577 2011-06-11 13:30:45Z sezero $
+*/
+
+#ifndef __H2STDINC_H
+#define __H2STDINC_H
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+
+#define uint32_t u32int
+#define int32_t s32int
+#define int16_t s16int
+#define uint16_t u16int
+#define uint64_t u64int
+#define int64_t s64int
+
+#define intptr_t vlong
+#define uintptr_t uvlong
+#define ptrdiff_t vlong
+
+#define size_t uvlong
+
+#undef PI
+
+
+/*==========================================================================*/
+
+#ifndef NULL
+#if defined(__cplusplus)
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif
+
+#define H2MAXCHAR ((char)0x7f)
+#define H2MAXSHORT ((short)0x7fff)
+#define H2MAXINT ((int)0x7fffffff) /* max positive 32-bit integer */
+#define H2MINCHAR ((char)0x80)
+#define H2MINSHORT ((short)0x8000)
+#define H2MININT ((int)0x80000000) /* max negative 32-bit integer */
+
+/* Make sure the types really have the right
+ * sizes: These macros are from SDL headers.
+ */
+#define COMPILE_TIME_ASSERT(name, x) \
+ typedef int dummy_ ## name[(x) * 2 - 1]
+
+COMPILE_TIME_ASSERT(char, sizeof(char) == 1);
+COMPILE_TIME_ASSERT(float, sizeof(float) == 4);
+COMPILE_TIME_ASSERT(long, sizeof(long) >= 4);
+COMPILE_TIME_ASSERT(int, sizeof(int) == 4);
+COMPILE_TIME_ASSERT(short, sizeof(short) == 2);
+
+/* make sure enums are the size of ints for structure packing */
+typedef enum {
+ THE_DUMMY_VALUE
+} THE_DUMMY_ENUM;
+COMPILE_TIME_ASSERT(enum, sizeof(THE_DUMMY_ENUM) == sizeof(int));
+
+
+/*==========================================================================*/
+
+typedef unsigned char byte;
+
+#undef true
+#undef false
+#if defined(__cplusplus)
+/* some structures have boolean members and the x86 asm code expect
+ * those members to be 4 bytes long. therefore, boolean must be 32
+ * bits and it can NOT be binary compatible with the 8 bit C++ bool. */
+typedef int boolean;
+COMPILE_TIME_ASSERT(falsehood, (0 == false));
+COMPILE_TIME_ASSERT(truth, (1 == true));
+#else
+typedef enum {
+ false = 0,
+ true = 1
+} boolean;
+COMPILE_TIME_ASSERT(falsehood, ((1 != 1) == false));
+COMPILE_TIME_ASSERT(truth, ((1 == 1) == true));
+#endif
+COMPILE_TIME_ASSERT(boolean, sizeof(boolean) == 4);
+
+/*==========================================================================*/
+
+/* math */
+#define FRACBITS 16
+#define FRACUNIT (1 << FRACBITS)
+
+typedef int fixed_t;
+
+
+/*==========================================================================*/
+
+/* compatibility with DOS/Windows */
+#ifndef O_BINARY
+# if defined(_O_BINARY)
+# define O_BINARY _O_BINARY
+# else
+# define O_BINARY 0
+# endif
+#endif
+
+/* compatibility with M$ types */
+#if !defined(_WIN32)
+#define PASCAL
+#define FAR
+#define APIENTRY
+#endif /* ! WINDOWS */
+
+/*==========================================================================*/
+
+/* compiler specific definitions */
+
+#if !defined(__GNUC__)
+#define __attribute__(x)
+#endif /* __GNUC__ */
+
+/* argument format attributes for function
+ * pointers are supported for gcc >= 3.1
+ */
+#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0))
+#define __fp_attribute__ __attribute__
+#else
+#define __fp_attribute__(x)
+#endif
+
+/* function optimize attribute is added
+ * starting with gcc 4.4.0
+ */
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 3))
+#define __no_optimize __attribute__((__optimize__("0")))
+#else
+#define __no_optimize
+#endif
+
+/*==========================================================================*/
+
+/* Some compilers, such as OpenWatcom, and possibly other compilers
+ * from the DOS universe, define __386__ instead of __i386__
+ */
+#if defined(__386__) && !defined(__i386__)
+#define __i386__ 1
+#endif
+
+/*==========================================================================*/
+
+/* Provide a substitute for offsetof() if we don't have one.
+ * This variant works on most (but not *all*) systems...
+ */
+#ifndef offsetof
+#define offsetof(t,m) ((size_t)&(((t *)0)->m))
+#endif
+
+/*==========================================================================*/
+
+
+#endif /* __H2STDINC_H */
+
--- /dev/null
+++ b/h_hubmsg.c
@@ -1,0 +1,122 @@
+
+//**************************************************************************
+//**
+//** h_hubmsg.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "h_hubmsg.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static char ClusterMessage[MAX_INTRMSN_MESSAGE_SIZE];
+
+static const char *ClusMsgLumpNames[] =
+{
+ "CLUS1MSG",
+ "CLUS2MSG",
+ "CLUS3MSG",
+ "CLUS4MSG",
+ "CLUS5MSG"
+};
+
+static const char *winMsgLumpNames[] =
+{
+ "WIN1MSG",
+ "WIN2MSG",
+ "WIN3MSG"
+};
+
+static const char *winMsg_OldWad[] =
+{
+ TXT_WIN1MSG,
+ TXT_WIN2MSG,
+ TXT_WIN3MSG
+};
+
+static const char *ClusMsg_OldWad[] =
+{
+ TXT_CLUS1MSG,
+ TXT_CLUS2MSG,
+ TXT_CLUS3MSG,
+ TXT_CLUS4MSG,
+ TXT_CLUS5MSG
+};
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// GetClusterText
+//
+//==========================================================================
+
+const char *GetClusterText (int sequence)
+{
+ const char *msgLumpName;
+ int msgSize;
+ int msgLump;
+
+ if (oldwad_10)
+ return ClusMsg_OldWad[sequence];
+
+ msgLumpName = ClusMsgLumpNames[sequence];
+ msgLump = W_GetNumForName(msgLumpName);
+ msgSize = W_LumpLength(msgLump);
+ if (msgSize >= MAX_INTRMSN_MESSAGE_SIZE)
+ {
+ I_Error("Cluster message too long (%s)", msgLumpName);
+ }
+ W_ReadLump(msgLump, ClusterMessage);
+ ClusterMessage[msgSize] = 0; // Append terminator
+ return ClusterMessage;
+}
+
+//==========================================================================
+//
+// GetFinaleText
+//
+//==========================================================================
+
+const char *GetFinaleText (int sequence)
+{
+ const char *msgLumpName;
+ int msgSize;
+ int msgLump;
+
+ if (oldwad_10)
+ return winMsg_OldWad[sequence];
+
+ msgLumpName = winMsgLumpNames[sequence];
+ msgLump = W_GetNumForName(msgLumpName);
+ msgSize = W_LumpLength(msgLump);
+ if (msgSize >= MAX_INTRMSN_MESSAGE_SIZE)
+ {
+ I_Error("Finale message too long (%s)", msgLumpName);
+ }
+ W_ReadLump(msgLump, ClusterMessage);
+ ClusterMessage[msgSize] = 0; // Append terminator
+ return ClusterMessage;
+}
+
--- /dev/null
+++ b/h_hubmsg.h
@@ -1,0 +1,125 @@
+
+//**************************************************************************
+//**
+//** h_hubmsg.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef _H_HUBMSG
+#define _H_HUBMSG
+
+#define MAX_INTRMSN_MESSAGE_SIZE 1024
+
+const char *GetClusterText(int sequence);
+const char *GetFinaleText (int sequence);
+
+/* Hardcoded Cluster Ending Messages for Version 1.0 WAD files: ----------*/
+/* h_hubmsg.c -----------------------------------------------------------*/
+
+#define TXT_CLUS1MSG "HAVING PASSED THE SEVEN PORTALS\n" \
+ "WHICH SEALED THIS REALM, A VAST\n" \
+ "DOMAIN OF HARSH WILDERNESS STRETCHES\n" \
+ "BEFORE YOU. FIRE, ICE, AND STEEL HAVE\n" \
+ "TESTED YOU, BUT GREATER CHALLANGES\n" \
+ "REMAIN AHEAD. THE DENSE TANGLE OF\n" \
+ "FOREST SURELY HIDES HOSTILE EYES,\n" \
+ "BUT WHAT LIES BEYOND WILL BE WORSE.\n\n" \
+ "BARREN DESERT, DANK SWAMPS AND\n" \
+ "MUSTY CAVERNS BAR YOUR WAY, BUT YOU\n" \
+ "CANNOT LET ANYTHING KEEP YOU FROM\n" \
+ "YOUR FATE, EVEN IF YOU MIGHT COME\n" \
+ "TO WISH THAT IT WOULD.\n\n" \
+ "AND BEYOND, FLICKERING IN THE\n" \
+ "DISTANCE, THE EVER-SHIFTING WALLS\n" \
+ "OF THE HYPOSTYLE SEEM TO MOCK\n" \
+ "YOUR EVERY EFFORT."
+
+#define TXT_CLUS2MSG "YOUR MIND STILL REELING FROM YOUR\n" \
+ "ENCOUNTERS WITHIN THE HYPOSTYLE, YOU\n" \
+ "STAGGER TOWARD WHAT YOU HOPE IS\n" \
+ "A WAY OUT, THINGS SEEM TO MOVE FASTER\n" \
+ "AND FASTER, YOUR VISION BLURS AND\n" \
+ "BEGINS TO FADE...\n" \
+ "AS THE WORLD COLLAPSES AROUND YOU,\n" \
+ "THE BRIGHTNESS OF A TELEPORTAL\n" \
+ "ENGULFS YOU. A FLASH OF LIGHT AND THEN\n" \
+ "YOU CLIMB WEARILY TO YOUR FEET.\n\n" \
+ "YOU STAND ATOP A HIGH TOWER, AND\n" \
+ "FROM BELOW COME THE SCREAMS OF THE\n" \
+ "DAMNED. YOU STEP FORWARD, AND\n" \
+ "INSTANTLY THE SOUND OF DEMONIC\n" \
+ "CHANTING CHILLS YOUR BLOOD.\n" \
+ "BY ALL THE GODS OF DEATH! WHAT PLACE\n" \
+ "HAVE YOU COME TO? BY ALL THE GODS OF\n" \
+ "PAIN, HOW WILL YOU EVER FIND YOUR\n" \
+ "WAY OUT?"
+
+#define TXT_CLUS3MSG "THE MIGHTIEST WEAPONS AND ARTIFACTS\n" \
+ "OF THE ANCIENTS BARELY SUFFICED TO\n" \
+ "DEFEAT THE HERESIARCH AND HIS\n" \
+ "MINIONS, BUT NOW THEIR FOUL REMAINS\n" \
+ "LIE STREWN AT YOUR FEET. GATHERING\n" \
+ "THE LAST OF YOUR STRENGTH, YOU\n" \
+ "PREPARE TO ENTER THE PORTAL WHICH\n" \
+ "LEADS FROM THE HERESIARCH'S INNER\n" \
+ "SANCTUM.\n\n" \
+ "ABOVE YOU, THE RAMPARTS OF AN\n" \
+ "IMMENSE CASTLE LOOM. SILENT TOWERS\n" \
+ "AND BARE WALLS SURROUND A SINGLE\n" \
+ "SPIRE OF BLACK STONE, WHICH SQUATS\n" \
+ "IN THE CENTER OF THE CASTLE LIKE A\n" \
+ "BROODING GIANT. FIRE AND SHADOW\n" \
+ "TWIST BEHIND GAPING WINDOWS, DOZENS\n" \
+ "OF BALEFUL EYES GLARING DOWN UPON\n" \
+ "YOU.\n" \
+ "SOMEWHERE WITHIN, YOUR ENEMIES ARE\n" \
+ "WAITING..."
+
+#define TXT_CLUS4MSG "\"... AND HE SHALL JOURNEY INTO THE\n" \
+ "REALMS OF THE DEAD, AND CONTEST WITH\n" \
+ "THE FORCES THEREIN, UNTO THE VERY\n" \
+ "GATES OF DESPAIR, BUT WHETHER HE\n" \
+ "SHALL RETURN AGAIN TO THE WORLD OF\n" \
+ "LIGHT, NO MAN KNOWS.\"\n" \
+ "\n\n\n\n\n" \
+ "DAMN."
+
+#define TXT_CLUS5MSG "PLEASE EMAIL THE DEVELOPERS\n" \
+ "AND TELL THEM HOW YOU FOUND\n" \
+ "THIS MESSAGE IN AS MUCH DETAIL\n" \
+ "AS POSSIBLE SO THEY CAN PUT\n" \
+ "THE RIGHT MESSAGE HERE.\n\n" \
+ "THANKS."
+
+#define TXT_WIN1MSG "WITH A SCREAM OF AGONY YOU ARE\n" \
+ "WRENCHED FROM THIS WORLD INTO\n" \
+ "ANTOHER, EVERY PART OF YOUR BODY\n" \
+ "WREATHED IN MYSTIC FIRE. WHEN YOUR\n" \
+ "VISION CLEARS, YOU FIND YOURSELF\n" \
+ "STANDING IN A GREAT HALL, FILLED\n" \
+ "WITH GHOSTLY ECHOES AND MENACING\n" \
+ "SHADOWS. IN THE DISTANCE YOU CAN\n" \
+ "SEE A RAISED DAIS, AND UPON IT THE\n" \
+ "ONLY SOURCE OF LIGHT IN THIS WORLD."
+
+#define TXT_WIN2MSG "THIS CAN ONLY BE THE CHAOS SPHERE,\n" \
+ "THE SOURCE OF KORAX'S POWER. WITH\n" \
+ "THIS, YOU CAN CREATE WORLDS... OR\n" \
+ "DESTROY THEM. BY RIGHTS OF BATTLE\n" \
+ "AND CONQUEST IT IS YOURS, AND WITH\n" \
+ "TREMBLING HANDS YOU REACH TO GRASP\n" \
+ "IT. PERHAPS, NOW, A NEW PLAYER WILL\n" \
+ "JOIN THE COSMIC GAME OF POWER. LIKE\n" \
+ "THE PAWN WHO IS PROMOTED TO QUEEN,\n" \
+ "SUDDENLY THE VERY REACHES OF THE\n" \
+ "BOARD SEEM TO BE WITHIN YOUR GRASP."
+
+#define TXT_WIN3MSG "BUT THERE ARE OTHER PLAYERS MIGHTIER\n" \
+ "THAN YOU, AND WHO CAN KNOW THEIR\n" \
+ "NEXT MOVES?"
+
+#endif /* _H_HUBMSG */
+
--- /dev/null
+++ b/i_cdmus.h
@@ -1,0 +1,44 @@
+
+//**************************************************************************
+//**
+//** i_cdmus.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 421 $
+//** $Date: 2009-05-22 16:08:37 +0300 (Fri, 22 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __ICDMUS__
+#define __ICDMUS__
+
+#define CDERR_NOTINSTALLED 10 /* MSCDEX not installed */
+#define CDERR_NOAUDIOSUPPORT 11 /* CD-ROM Doesn't support audio */
+#define CDERR_NOAUDIOTRACKS 12 /* Current CD has no audio tracks */
+#define CDERR_BADDRIVE 20 /* Bad drive number */
+#define CDERR_BADTRACK 21 /* Bad track number */
+#define CDERR_IOCTLBUFFMEM 22 /* Not enough low memory for IOCTL */
+#define CDERR_DEVREQBASE 100 /* DevReq errors */
+
+extern boolean i_CDMusic; /* is cdaudio initialized */
+extern int cdaudio; /* boolean: is cd audio enabled or disabled */
+
+extern int i_CDTrack;
+extern int i_CDCurrentTrack;
+extern int i_CDMusicLength;
+extern int oldTic;
+
+extern int cd_Error;
+
+int I_CDMusInit(void);
+int I_CDMusPlay(int track);
+int I_CDMusStop(void);
+int I_CDMusResume(void);
+int I_CDMusSetVolume(int volume);
+int I_CDMusFirstTrack(void);
+int I_CDMusLastTrack(void);
+int I_CDMusTrackLength(int track);
+void I_CDMusUpdate(void);
+void I_CDMusShutdown(void);
+
+#endif /* __ICDMUS__ */
+
--- /dev/null
+++ b/i_sound.h
@@ -1,0 +1,54 @@
+//**************************************************************************
+//**
+//** i_sound.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 421 $
+//** $Date: 2009-05-22 16:08:37 +0300 (Fri, 22 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __SOUND__
+#define __SOUND__
+
+#define SND_TICRATE 140 /* tic rate for updating sound */
+#define SND_MAXSONGS 40 /* max number of songs in game */
+#define SND_SAMPLERATE 11025 /* sample rate of sound effects */
+
+typedef enum
+{
+ snd_none,
+ snd_PC,
+ snd_Adlib,
+ snd_SB,
+ snd_PAS,
+ snd_GUS,
+ snd_MPU,
+ snd_MPU2,
+ snd_MPU3,
+ snd_AWE,
+ snd_CDMUSIC,
+ NUM_SCARDS
+} cardenum_t;
+
+void I_PauseSong(int handle);
+void I_ResumeSong(int handle);
+void I_SetMusicVolume(int volume);
+void I_SetSfxVolume(int volume);
+int I_RegisterSong(void *data);
+int I_RegisterExternalSong(const char *name); /* External music file support */
+void I_UnRegisterSong(int handle);
+int I_QrySongPlaying(int handle);
+void I_StopSong(int handle);
+void I_PlaySong(int handle, boolean looping);
+int I_GetSfxLumpNum(sfxinfo_t *sound);
+int I_StartSound (int id, void *data, int vol, int sep, int pitch, int priority);
+void I_StopSound(int handle);
+int I_SoundIsPlaying(int handle);
+void I_UpdateSoundParams(int handle, int vol, int sep, int pitch);
+void I_sndArbitrateCards(void);
+void I_StartupSound (void);
+void I_ShutdownSound (void);
+void I_SetChannels(int channels);
+
+#endif /* __SOUND__ */
+
--- /dev/null
+++ b/in_lude.c
@@ -1,0 +1,586 @@
+
+//**************************************************************************
+//**
+//** in_lude.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 458 $
+//** $Date: 2009-05-25 15:35:27 +0300 (Mon, 25 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "v_compat.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define TEXTSPEED 3
+#define TEXTWAIT 140
+
+#ifdef RENDER3D
+#define V_DrawPatch(x,y,p) OGL_DrawPatch((x),(y),(p))
+#define V_DrawRawScreen(a) OGL_DrawRawScreen((a))
+#endif
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+ SINGLE,
+ COOPERATIVE,
+ DEATHMATCH
+} gametype_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+extern void AM_Stop(void);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+void IN_Start(void);
+void IN_Ticker(void);
+void IN_Drawer(void);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void WaitStop(void);
+static void Stop(void);
+static void LoadPics(void);
+static void UnloadPics(void);
+static void CheckForSkip(void);
+static void InitStats(void);
+static void DrDeathTally(void);
+static void DrNumber(int val, int x, int y, int wrapThresh);
+static void DrNumberBold(int val, int x, int y, int wrapThresh);
+static void DrawHubText(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DECLARATIONS ------------------------------------------------
+
+boolean intermission;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static boolean skipintermission;
+static int interstate = 0;
+static int intertime = -1;
+static gametype_t gametype;
+static int cnt;
+static int slaughterboy; // in DM, the player with the most kills
+static PATCH_REF patchINTERPIC;
+static PATCH_REF FontBNumbers[10];
+static PATCH_REF FontBNegative;
+static PATCH_REF FontBSlash;
+static PATCH_REF FontBPercent;
+static int FontABaseLump;
+static int FontBLump;
+static int FontBLumpBase;
+
+static signed int totalFrags[MAXPLAYERS];
+
+static int HubCount;
+static const char *HubText;
+
+// CODE --------------------------------------------------------------------
+
+//========================================================================
+//
+// IN_Start
+//
+//========================================================================
+
+void IN_Start(void)
+{
+ int i;
+
+ V_SetPaletteBase();
+ InitStats();
+ LoadPics();
+ intermission = true;
+ interstate = 0;
+ skipintermission = false;
+ intertime = 0;
+ AM_Stop();
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ players[i].messageTics = 0;
+ players[i].message[0] = 0;
+ }
+ SN_StopAllSequences();
+}
+
+//========================================================================
+//
+// Stop
+//
+//========================================================================
+
+static void Stop(void)
+{
+ intermission = false;
+ UnloadPics();
+ SB_state = -1;
+ BorderNeedRefresh = true;
+}
+
+//========================================================================
+//
+// WaitStop
+//
+//========================================================================
+
+void WaitStop(void)
+{
+ if (!--cnt)
+ {
+ Stop();
+// gamestate = GS_LEVEL;
+// G_DoLoadLevel();
+ gameaction = ga_leavemap;
+// G_WorldDone();
+ }
+}
+
+//========================================================================
+//
+// InitStats
+//
+// Initializes the stats for single player mode
+//========================================================================
+
+static void InitStats(void)
+{
+ int i;
+ int j;
+ int oldCluster;
+ signed int slaughterfrags;
+ int posnum;
+ int slaughtercount;
+ int playercount;
+
+ extern int LeaveMap;
+
+ if (!deathmatch)
+ {
+ gametype = SINGLE;
+ HubCount = 0;
+ oldCluster = P_GetMapCluster(gamemap);
+ if (oldCluster != P_GetMapCluster(LeaveMap))
+ {
+ if (oldCluster >= 1 && oldCluster <= 5)
+ {
+ HubText = GetClusterText(oldCluster - 1);
+ HubCount = strlen(HubText)*TEXTSPEED + TEXTWAIT;
+ S_StartSongName("hub", true);
+ }
+ }
+ }
+ else
+ {
+ gametype = DEATHMATCH;
+ slaughterboy = 0;
+ slaughterfrags = -9999;
+ posnum = 0;
+ playercount = 0;
+ slaughtercount = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ totalFrags[i] = 0;
+ if (playeringame[i])
+ {
+ playercount++;
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ if (playeringame[j])
+ {
+ totalFrags[i] += players[i].frags[j];
+ }
+ }
+ posnum++;
+ }
+ if (totalFrags[i] > slaughterfrags)
+ {
+ slaughterboy = 1<<i;
+ slaughterfrags = totalFrags[i];
+ slaughtercount = 1;
+ }
+ else if (totalFrags[i] == slaughterfrags)
+ {
+ slaughterboy |= 1<<i;
+ slaughtercount++;
+ }
+ }
+ if (playercount == slaughtercount)
+ { // don't do the slaughter stuff if everyone is equal
+ slaughterboy = 0;
+ }
+ S_StartSongName("hub", true);
+ }
+}
+
+//========================================================================
+//
+// LoadPics
+//
+//========================================================================
+
+static void LoadPics(void)
+{
+ int i;
+
+ if (HubCount || gametype == DEATHMATCH)
+ {
+ patchINTERPIC = (PATCH_REF) WR_CacheLumpName("INTERPIC", PU_STATIC);
+ FontBLumpBase = W_GetNumForName("FONTB16");
+ for (i = 0; i < 10; i++)
+ {
+ FontBNumbers[i] = (PATCH_REF) WR_CacheLumpNum(FontBLumpBase + i, PU_STATIC);
+ }
+ FontBLump = W_GetNumForName("FONTB_S") + 1;
+ FontBNegative = (PATCH_REF) WR_CacheLumpName("FONTB13", PU_STATIC);
+ FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+
+ FontBSlash = (PATCH_REF) WR_CacheLumpName("FONTB15", PU_STATIC);
+ FontBPercent = (PATCH_REF) WR_CacheLumpName("FONTB05", PU_STATIC);
+ }
+}
+
+//========================================================================
+//
+// UnloadPics
+//
+//========================================================================
+
+static void UnloadPics(void)
+{
+#ifndef RENDER3D
+ int i;
+
+ if (HubCount || gametype == DEATHMATCH)
+ {
+ Z_ChangeTag(patchINTERPIC, PU_CACHE);
+ for (i = 0; i < 10; i++)
+ {
+ Z_ChangeTag(FontBNumbers[i], PU_CACHE);
+ }
+ Z_ChangeTag(FontBNegative, PU_CACHE);
+ Z_ChangeTag(FontBSlash, PU_CACHE);
+ Z_ChangeTag(FontBPercent, PU_CACHE);
+ }
+#endif
+}
+
+//========================================================================
+//
+// IN_Ticker
+//
+//========================================================================
+
+void IN_Ticker(void)
+{
+ if (!intermission)
+ {
+ return;
+ }
+ if (interstate)
+ {
+ WaitStop();
+ return;
+ }
+ skipintermission = false;
+ CheckForSkip();
+ intertime++;
+ if (skipintermission || (gametype == SINGLE && !HubCount))
+ {
+ interstate = 1;
+ cnt = 10;
+ skipintermission = false;
+ //S_StartSound(NULL, sfx_dorcls);
+ }
+}
+
+//========================================================================
+//
+// CheckForSkip
+//
+// Check to see if any player hit a key
+//========================================================================
+
+static void CheckForSkip(void)
+{
+ int i;
+ player_t *player;
+ static boolean triedToSkip;
+
+ for (i = 0, player = players; i < MAXPLAYERS; i++, player++)
+ {
+ if (playeringame[i])
+ {
+ if (player->cmd.buttons & BT_ATTACK)
+ {
+ if (!player->attackdown)
+ {
+ skipintermission = 1;
+ }
+ player->attackdown = true;
+ }
+ else
+ {
+ player->attackdown = false;
+ }
+ if (player->cmd.buttons & BT_USE)
+ {
+ if (!player->usedown)
+ {
+ skipintermission = 1;
+ }
+ player->usedown = true;
+ }
+ else
+ {
+ player->usedown = false;
+ }
+ }
+ }
+ if (deathmatch && intertime < 140)
+ { // wait for 4 seconds before allowing a skip
+ if (skipintermission == 1)
+ {
+ triedToSkip = true;
+ skipintermission = 0;
+ }
+ }
+ else
+ {
+ if (triedToSkip)
+ {
+ skipintermission = 1;
+ triedToSkip = false;
+ }
+ }
+}
+
+//========================================================================
+//
+// IN_Drawer
+//
+//========================================================================
+
+void IN_Drawer(void)
+{
+ if (!intermission)
+ {
+ return;
+ }
+ if (interstate)
+ {
+ return;
+ }
+ UpdateState |= I_FULLSCRN;
+
+ V_DrawRawScreen((BYTE_REF) patchINTERPIC);
+
+ if (gametype == SINGLE)
+ {
+ if (HubCount)
+ {
+ DrawHubText();
+ }
+ }
+ else
+ {
+ DrDeathTally();
+ }
+}
+
+//========================================================================
+//
+// DrDeathTally
+//
+//========================================================================
+
+#define TALLY_EFFECT_TICKS 20
+#define TALLY_FINAL_X_DELTA (23 * FRACUNIT)
+#define TALLY_FINAL_Y_DELTA (13 * FRACUNIT)
+#define TALLY_START_XPOS (178* FRACUNIT)
+#define TALLY_STOP_XPOS (90 * FRACUNIT)
+#define TALLY_START_YPOS (132* FRACUNIT)
+#define TALLY_STOP_YPOS (83 * FRACUNIT)
+#define TALLY_TOP_X 85
+#define TALLY_TOP_Y 9
+#define TALLY_LEFT_X 7
+#define TALLY_LEFT_Y 71
+#define TALLY_TOTALS_X 291
+
+static void DrDeathTally(void)
+{
+ int i, j, temp;
+ fixed_t xPos, yPos;
+ fixed_t xDelta, yDelta;
+ fixed_t xStart, scale;
+ int x, y;
+ boolean bold;
+ static boolean showTotals;
+
+ V_DrawPatch(TALLY_TOP_X, TALLY_TOP_Y, (PATCH_REF)WR_CacheLumpName("tallytop", PU_CACHE));
+ V_DrawPatch(TALLY_LEFT_X, TALLY_LEFT_Y, (PATCH_REF)WR_CacheLumpName("tallylft", PU_CACHE));
+ if (intertime < TALLY_EFFECT_TICKS)
+ {
+ showTotals = false;
+ scale = (intertime * FRACUNIT) / TALLY_EFFECT_TICKS;
+ xDelta = FixedMul(scale, TALLY_FINAL_X_DELTA);
+ yDelta = FixedMul(scale, TALLY_FINAL_Y_DELTA);
+ xStart = TALLY_START_XPOS - FixedMul(scale, TALLY_START_XPOS-TALLY_STOP_XPOS);
+ yPos = TALLY_START_YPOS - FixedMul(scale, TALLY_START_YPOS-TALLY_STOP_YPOS);
+ }
+ else
+ {
+ xDelta = TALLY_FINAL_X_DELTA;
+ yDelta = TALLY_FINAL_Y_DELTA;
+ xStart = TALLY_STOP_XPOS;
+ yPos = TALLY_STOP_YPOS;
+ }
+ if (intertime >= TALLY_EFFECT_TICKS && showTotals == false)
+ {
+ showTotals = true;
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ }
+ y = yPos>>FRACBITS;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ xPos = xStart;
+ for (j = 0; j < MAXPLAYERS; j++, xPos += xDelta)
+ {
+ x = xPos>>FRACBITS;
+ bold = (i == consoleplayer || j == consoleplayer);
+ if (playeringame[i] && playeringame[j])
+ {
+ if (bold)
+ {
+ DrNumberBold(players[i].frags[j], x, y, 100);
+ }
+ else
+ {
+ DrNumber(players[i].frags[j], x, y, 100);
+ }
+ }
+ else
+ {
+ temp = MN_TextAWidth("--")/2;
+ if (bold)
+ {
+ MN_DrTextAYellow("--", x - temp, y);
+ }
+ else
+ {
+ MN_DrTextA("--", x - temp, y);
+ }
+ }
+ }
+ if (showTotals && playeringame[i]
+ && !((slaughterboy & (1<<i)) && !(intertime & 16)))
+ {
+ DrNumber(totalFrags[i], TALLY_TOTALS_X, y, 1000);
+ }
+ yPos += yDelta;
+ y = yPos>>FRACBITS;
+ }
+}
+
+//==========================================================================
+//
+// DrNumber
+//
+//==========================================================================
+
+static void DrNumber(int val, int x, int y, int wrapThresh)
+{
+ char buff[8] = "XX";
+
+ if (!(val < -9 && wrapThresh < 1000))
+ {
+ snprintf(buff, sizeof(buff), "%d", val >= wrapThresh ? val % wrapThresh : val);
+ }
+ MN_DrTextA(buff, x - MN_TextAWidth(buff)/2, y);
+}
+
+//==========================================================================
+//
+// DrNumberBold
+//
+//==========================================================================
+
+static void DrNumberBold(int val, int x, int y, int wrapThresh)
+{
+ char buff[8] = "XX";
+
+ if (!(val < -9 && wrapThresh < 1000))
+ {
+ snprintf(buff, sizeof(buff), "%d", val >= wrapThresh ? val % wrapThresh : val);
+ }
+ MN_DrTextAYellow(buff, x - MN_TextAWidth(buff)/2, y);
+}
+
+//===========================================================================
+//
+// DrawHubText
+//
+//===========================================================================
+
+static void DrawHubText(void)
+{
+ int count;
+ const char *ch;
+ int c;
+ int cx, cy;
+ patch_t *w;
+ int width;
+
+ cy = 5;
+ cx = 10;
+ ch = HubText;
+ count = (intertime - 10) / TEXTSPEED;
+ if (count < 0)
+ {
+ count = 0;
+ }
+ for ( ; count; count--)
+ {
+ c = *ch++;
+ if (!c)
+ {
+ break;
+ }
+ if (c == '\n')
+ {
+ cx = 10;
+ cy += 9;
+ continue;
+ }
+ if (c < 32)
+ {
+ continue;
+ }
+ c = toupper(c);
+ if (c == 32)
+ {
+ cx += 5;
+ continue;
+ }
+ w = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ width = SHORT(w->width);
+ if (cx + width > SCREENWIDTH)
+ {
+ break;
+ }
+#ifdef RENDER3D
+ OGL_DrawPatch_CS(cx, cy, FontABaseLump + c - 33);
+#else
+ V_DrawPatch(cx, cy, w);
+#endif
+ cx += width;
+ }
+}
+
--- /dev/null
+++ b/info.c
@@ -1,0 +1,14174 @@
+
+//**************************************************************************
+//**
+//** info.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+// generated by stateco
+
+const char *sprnames[NUMSPRITES] = {
+"MAN1","ACLO","TLGL","FBL1","XPL1","ARRW","DART","RIPP","CFCF","BLAD",
+"SHRD","FFSM","FFLG","PTN1","PTN2","SOAR","INVU","SUMN","TSPK","TELO",
+"TRNG","ROCK","FOGS","FOGM","FOGL","SGSA","SGSB","PORK","EGGM","FHFX",
+"SPHL","STWN","GMPD","ASKU","ABGM","AGMR","AGMG","AGG2","AGMB","AGB2",
+"ABK1","ABK2","ASK2","AFWP","ACWP","AMWP","AGER","AGR2","AGR3","AGR4",
+"TRCH","PSBG","ATLP","THRW","SPED","BMAN","BRAC","BLST","HRAD","SPSH",
+"LVAS","SLDG","STTW","RCK1","RCK2","RCK3","RCK4","CDLR","TRE1","TRDT",
+"TRE2","TRE3","STM1","STM2","STM3","STM4","MSH1","MSH2","MSH3","MSH4",
+"MSH5","MSH6","MSH7","MSH8","SGMP","SGM1","SGM2","SGM3","SLC1","SLC2",
+"SLC3","MSS1","MSS2","SWMV","CPS1","CPS2","TMS1","TMS2","TMS3","TMS4",
+"TMS5","TMS6","TMS7","CPS3","STT2","STT3","STT4","STT5","GAR1","GAR2",
+"GAR3","GAR4","GAR5","GAR6","GAR7","GAR8","GAR9","BNR1","TRE4","TRE5",
+"TRE6","TRE7","LOGG","ICT1","ICT2","ICT3","ICT4","ICM1","ICM2","ICM3",
+"ICM4","RKBL","RKBS","RKBK","RBL1","RBL2","RBL3","VASE","POT1","POT2",
+"POT3","PBIT","CPS4","CPS5","CPS6","CPB1","CPB2","CPB3","CPB4","BDRP",
+"BDSH","BDPL","CNDL","LEF1","LEF3","LEF2","TWTR","WLTR","BARL","SHB1",
+"SHB2","BCKT","SHRM","FBUL","FSKL","BRTR","SUIT","BBLL","CAND","IRON",
+"XMAS","CDRN","CHNS","TST1","TST2","TST3","TST4","TST5","TST6","TST7",
+"TST8","TST9","TST0","TELE","TSMK","FPCH","WFAX","FAXE","WFHM","FHMR",
+"FSRD","FSFX","CMCE","WCSS","CSSF","WCFM","CFLM","CFFX","CHLY","SPIR",
+"MWND","WMLG","MLNG","MLFX","MLF2","MSTF","MSP1","MSP2","WFR1","WFR2",
+"WFR3","WCH1","WCH2","WCH3","WMS1","WMS2","WMS3","WPIG","WMCS","CONE",
+"SHEX","BLOD","GIBS","PLAY","FDTH","BSKL","ICEC","CLER","MAGE","PIGY",
+"CENT","CTXD","CTFX","CTDP","DEMN","DEMA","DEMB","DEMC","DEMD","DEME",
+"DMFX","DEM2","DMBA","DMBB","DMBC","DMBD","DMBE","D2FX","WRTH","WRT2",
+"WRBL","MNTR","FX12","FX13","MNSM","SSPT","SSDV","SSXD","SSFX","BISH",
+"BPFX","DRAG","DRFX","ARM1","ARM2","ARM3","ARM4","MAN2","MAN3","KEY1",
+"KEY2","KEY3","KEY4","KEY5","KEY6","KEY7","KEY8","KEY9","KEYA","KEYB",
+"ETTN","ETTB","FDMN","FDMB","ICEY","ICPR","ICWS","SORC","SBMP","SBS4",
+"SBMB","SBS3","SBMG","SBS1","SBS2","SBFX","RADE","WATR","KORX","ABAT",
+#ifdef ASSASSIN
+"AKTR","ACSB","AGRN","ASTF","ASP1","ASP2","ASSN",
+#endif
+NULL
+};
+
+void A_FreeTargMobj ();
+void A_FlameCheck ();
+void A_HideThing ();
+void A_UnHideThing ();
+void A_RestoreSpecialThing1 ();
+void A_RestoreSpecialThing2 ();
+void A_RestoreArtifact ();
+void A_Summon ();
+void A_ThrustInitUp ();
+void A_ThrustInitDn ();
+void A_ThrustRaise ();
+void A_ThrustBlock ();
+void A_ThrustImpale ();
+void A_ThrustLower ();
+void A_TeloSpawnC ();
+void A_TeloSpawnB ();
+void A_TeloSpawnA ();
+void A_TeloSpawnD ();
+void A_CheckTeleRing ();
+void A_FogSpawn ();
+void A_FogMove ();
+void A_Quake ();
+void A_ContMobjSound ();
+void A_Scream ();
+void A_Explode ();
+void A_PoisonBagInit ();
+void A_PoisonBagDamage ();
+void A_PoisonBagCheck ();
+void A_CheckThrowBomb ();
+void A_NoGravity ();
+void A_PotteryExplode ();
+void A_PotteryChooseBit ();
+void A_PotteryCheck ();
+void A_CorpseBloodDrip ();
+void A_CorpseExplode ();
+void A_LeafSpawn ();
+void A_LeafThrust ();
+void A_LeafCheck ();
+void A_BridgeInit ();
+void A_BridgeOrbit ();
+void A_TreeDeath ();
+void A_PoisonShroom ();
+void A_Pain ();
+void A_SoAExplode ();
+void A_BellReset1 ();
+void A_BellReset2 ();
+void A_NoBlocking ();
+void A_Light0 ();
+void A_WeaponReady ();
+void A_Lower ();
+void A_Raise ();
+void A_FPunchAttack ();
+void A_ReFire ();
+void A_FAxeAttack ();
+void A_FHammerAttack ();
+void A_FHammerThrow ();
+void A_FSwordAttack ();
+void A_FSwordFlames ();
+void A_CMaceAttack ();
+void A_CStaffInitBlink ();
+void A_CStaffCheckBlink ();
+void A_CStaffCheck ();
+void A_CStaffAttack ();
+void A_CStaffMissileSlither ();
+void A_CFlameAttack ();
+void A_CFlameRotate ();
+void A_CFlamePuff ();
+void A_CFlameMissile ();
+void A_CHolyAttack ();
+void A_CHolyPalette ();
+void A_CHolySeek ();
+void A_CHolyCheckScream ();
+void A_CHolyTail ();
+void A_CHolySpawnPuff ();
+void A_CHolyAttack2 ();
+void A_MWandAttack ();
+void A_LightningReady ();
+void A_MLightningAttack ();
+void A_LightningZap ();
+void A_LightningClip ();
+void A_LightningRemove ();
+void A_LastZap ();
+void A_ZapMimic ();
+void A_MStaffAttack ();
+void A_MStaffPalette ();
+void A_MStaffWeave ();
+void A_MStaffTrack ();
+void A_SnoutAttack ();
+void A_FireConePL1 ();
+void A_ShedShard ();
+void A_AddPlayerCorpse ();
+void A_SkullPop ();
+void A_FreezeDeath ();
+void A_FreezeDeathChunks ();
+void A_CheckBurnGone ();
+void A_CheckSkullFloor ();
+void A_CheckSkullDone ();
+void A_SpeedFade ();
+void A_IceSetTics ();
+void A_IceCheckHeadDone ();
+void A_PigPain ();
+void A_PigLook ();
+void A_PigChase ();
+void A_FaceTarget ();
+void A_PigAttack ();
+void A_QueueCorpse ();
+void A_Look ();
+void A_Chase ();
+void A_CentaurAttack ();
+void A_CentaurAttack2 ();
+void A_SetReflective ();
+void A_CentaurDefend ();
+void A_UnSetReflective ();
+void A_CentaurDropStuff ();
+void A_CheckFloor ();
+void A_DemonAttack1 ();
+void A_DemonAttack2 ();
+void A_DemonDeath ();
+void A_Demon2Death ();
+void A_WraithRaiseInit ();
+void A_WraithRaise ();
+void A_WraithInit ();
+void A_WraithLook ();
+void A_WraithChase ();
+void A_WraithFX3 ();
+void A_WraithMelee ();
+void A_WraithMissile ();
+void A_WraithFX2 ();
+void A_MinotaurFade1 ();
+void A_MinotaurFade2 ();
+void A_MinotaurLook ();
+void A_MinotaurChase ();
+void A_MinotaurRoam ();
+void A_MinotaurAtk1 ();
+void A_MinotaurDecide ();
+void A_MinotaurAtk2 ();
+void A_MinotaurAtk3 ();
+void A_MinotaurCharge ();
+void A_SmokePuffExit ();
+void A_MinotaurFade0 ();
+void A_MntrFloorFire ();
+void A_SerpentChase ();
+void A_SerpentHumpDecide ();
+void A_SerpentUnHide ();
+void A_SerpentRaiseHump ();
+void A_SerpentLowerHump ();
+void A_SerpentHide ();
+void A_SerpentBirthScream ();
+void A_SetShootable ();
+void A_SerpentCheckForAttack ();
+void A_UnSetShootable ();
+void A_SerpentDiveSound ();
+void A_SerpentWalk ();
+void A_SerpentChooseAttack ();
+void A_SerpentMeleeAttack ();
+void A_SerpentMissileAttack ();
+void A_SerpentHeadPop ();
+void A_SerpentSpawnGibs ();
+void A_SerpentHeadCheck ();
+void A_FloatGib ();
+void A_DelayGib ();
+void A_SinkGib ();
+void A_BishopDecide ();
+void A_BishopDoBlur ();
+void A_BishopSpawnBlur ();
+void A_BishopChase ();
+void A_BishopAttack ();
+void A_BishopAttack2 ();
+void A_BishopPainBlur ();
+void A_BishopPuff ();
+void A_SetAltShadow ();
+void A_BishopMissileWeave ();
+void A_BishopMissileSeek ();
+void A_DragonInitFlight ();
+void A_DragonFlap ();
+void A_DragonFlight ();
+void A_DragonAttack ();
+void A_DragonPain ();
+void A_DragonCheckCrash ();
+void A_DragonFX2 ();
+void A_ESound ();
+void A_EttinAttack ();
+void A_DropMace ();
+void A_FiredRocks ();
+void A_UnSetInvulnerable ();
+void A_FiredChase ();
+void A_FiredAttack ();
+void A_FiredSplotch ();
+void A_SmBounce ();
+void A_IceGuyLook ();
+void A_IceGuyChase ();
+void A_IceGuyAttack ();
+void A_IceGuyDie ();
+void A_IceGuyMissilePuff ();
+void A_IceGuyMissileExplode ();
+void A_ClassBossHealth ();
+void A_FastChase ();
+void A_FighterAttack ();
+void A_ClericAttack ();
+void A_MageAttack ();
+void A_SorcSpinBalls ();
+void A_SpeedBalls ();
+void A_SpawnFizzle ();
+void A_SorcBossAttack ();
+void A_SorcBallOrbit ();
+void A_SorcBallPop ();
+void A_BounceCheck ();
+void A_SorcFX1Seek ();
+void A_SorcFX2Split ();
+void A_SorcFX2Orbit ();
+void A_SorcererBishopEntry ();
+void A_SpawnBishop ();
+void A_SorcFX4Check ();
+void A_KoraxStep2 ();
+void A_KoraxChase ();
+void A_KoraxStep ();
+void A_KoraxDecide ();
+void A_KoraxMissile ();
+void A_KoraxCommand ();
+void A_KoraxBonePop ();
+void A_KSpiritRoam ();
+void A_KBoltRaise ();
+void A_KBolt ();
+void A_BatSpawnInit ();
+void A_BatSpawn ();
+void A_BatMove ();
+#ifdef ASSASSIN
+void A_AKnifeAttack ();
+void A_ACrossAttack ();
+void A_AGrenAttack ();
+void A_AStaffAttack ();
+#endif
+
+state_t states[NUMSTATES] = {
+{SPR_MAN1,0,-1,NULL,S_NULL,0,0}, // S_NULL
+{SPR_ACLO,4,1050,A_FreeTargMobj,S_NULL,0,0}, // S_FREETARGMOBJ
+{SPR_TLGL,0,-1,NULL,S_NULL,0,0}, // S_MAPSPOT
+{SPR_FBL1,32768,4,NULL,S_FIREBALL1_2,0,0}, // S_FIREBALL1_1
+{SPR_FBL1,32769,4,NULL,S_FIREBALL1_1,0,0}, // S_FIREBALL1_2
+{SPR_XPL1,32768,4,NULL,S_FIREBALL1_X2,0,0}, // S_FIREBALL1_X1
+{SPR_XPL1,32769,4,NULL,S_FIREBALL1_X3,0,0}, // S_FIREBALL1_X2
+{SPR_XPL1,32770,4,NULL,S_FIREBALL1_X4,0,0}, // S_FIREBALL1_X3
+{SPR_XPL1,32771,4,NULL,S_FIREBALL1_X5,0,0}, // S_FIREBALL1_X4
+{SPR_XPL1,32772,4,NULL,S_FIREBALL1_X6,0,0}, // S_FIREBALL1_X5
+{SPR_XPL1,32773,4,NULL,S_NULL,0,0}, // S_FIREBALL1_X6
+{SPR_ARRW,0,-1,NULL,S_NULL,0,0}, // S_ARROW_1
+{SPR_ARRW,0,1,NULL,S_NULL,0,0}, // S_ARROW_X1
+{SPR_DART,0,-1,NULL,S_NULL,0,0}, // S_DART_1
+{SPR_DART,0,1,NULL,S_NULL,0,0}, // S_DART_X1
+{SPR_DART,0,-1,NULL,S_NULL,0,0}, // S_POISONDART_1
+{SPR_DART,0,1,NULL,S_NULL,0,0}, // S_POISONDART_X1
+{SPR_RIPP,0,3,NULL,S_RIPPERBALL_2,0,0}, // S_RIPPERBALL_1
+{SPR_RIPP,1,3,NULL,S_RIPPERBALL_3,0,0}, // S_RIPPERBALL_2
+{SPR_RIPP,2,3,NULL,S_RIPPERBALL_1,0,0}, // S_RIPPERBALL_3
+{SPR_CFCF,32784,4,NULL,S_RIPPERBALL_X2,0,0}, // S_RIPPERBALL_X1
+{SPR_CFCF,32785,3,NULL,S_RIPPERBALL_X3,0,0}, // S_RIPPERBALL_X2
+{SPR_CFCF,32786,4,NULL,S_RIPPERBALL_X4,0,0}, // S_RIPPERBALL_X3
+{SPR_CFCF,32787,3,NULL,S_RIPPERBALL_X5,0,0}, // S_RIPPERBALL_X4
+{SPR_CFCF,32788,4,NULL,S_RIPPERBALL_X6,0,0}, // S_RIPPERBALL_X5
+{SPR_CFCF,32789,3,NULL,S_RIPPERBALL_X7,0,0}, // S_RIPPERBALL_X6
+{SPR_CFCF,32790,4,NULL,S_RIPPERBALL_X8,0,0}, // S_RIPPERBALL_X7
+{SPR_CFCF,32791,3,NULL,S_RIPPERBALL_X9,0,0}, // S_RIPPERBALL_X8
+{SPR_CFCF,32792,4,NULL,S_RIPPERBALL_X10,0,0}, // S_RIPPERBALL_X9
+{SPR_CFCF,32793,3,NULL,S_NULL,0,0}, // S_RIPPERBALL_X10
+{SPR_BLAD,0,-1,NULL,S_NULL,0,0}, // S_PRJ_BLADE1
+{SPR_BLAD,0,1,NULL,S_NULL,0,0}, // S_PRJ_BLADE_X1
+{SPR_SHRD,32768,3,NULL,S_ICESHARD2,0,0}, // S_ICESHARD1
+{SPR_SHRD,32769,3,NULL,S_ICESHARD3,0,0}, // S_ICESHARD2
+{SPR_SHRD,32770,3,NULL,S_ICESHARD1,0,0}, // S_ICESHARD3
+{SPR_FFSM,32768,3,NULL,S_FLAME_TSMALL2,0,0}, // S_FLAME_TSMALL1
+{SPR_FFSM,32769,3,NULL,S_FLAME_TSMALL3,0,0}, // S_FLAME_TSMALL2
+{SPR_FFSM,32770,2,A_FlameCheck,S_FLAME_TSMALL4,0,0}, // S_FLAME_TSMALL3
+{SPR_FFSM,32770,2,NULL,S_FLAME_TSMALL5,0,0}, // S_FLAME_TSMALL4
+{SPR_FFSM,32771,3,NULL,S_FLAME_TSMALL6,0,0}, // S_FLAME_TSMALL5
+{SPR_FFSM,32772,3,A_FlameCheck,S_FLAME_TSMALL1,0,0}, // S_FLAME_TSMALL6
+{SPR_FFLG,32768,4,NULL,S_FLAME_TLARGE2,0,0}, // S_FLAME_TLARGE1
+{SPR_FFLG,32769,4,A_FlameCheck,S_FLAME_TLARGE3,0,0}, // S_FLAME_TLARGE2
+{SPR_FFLG,32770,4,NULL,S_FLAME_TLARGE4,0,0}, // S_FLAME_TLARGE3
+{SPR_FFLG,32771,4,A_FlameCheck,S_FLAME_TLARGE5,0,0}, // S_FLAME_TLARGE4
+{SPR_FFLG,32772,4,NULL,S_FLAME_TLARGE6,0,0}, // S_FLAME_TLARGE5
+{SPR_FFLG,32773,4,A_FlameCheck,S_FLAME_TLARGE7,0,0}, // S_FLAME_TLARGE6
+{SPR_FFLG,32774,4,NULL,S_FLAME_TLARGE8,0,0}, // S_FLAME_TLARGE7
+{SPR_FFLG,32775,4,A_FlameCheck,S_FLAME_TLARGE9,0,0}, // S_FLAME_TLARGE8
+{SPR_FFLG,32776,4,NULL,S_FLAME_TLARGE10,0,0}, // S_FLAME_TLARGE9
+{SPR_FFLG,32777,4,A_FlameCheck,S_FLAME_TLARGE11,0,0}, // S_FLAME_TLARGE10
+{SPR_FFLG,32778,4,NULL,S_FLAME_TLARGE12,0,0}, // S_FLAME_TLARGE11
+{SPR_FFLG,32779,4,A_FlameCheck,S_FLAME_TLARGE13,0,0}, // S_FLAME_TLARGE12
+{SPR_FFLG,32780,4,NULL,S_FLAME_TLARGE14,0,0}, // S_FLAME_TLARGE13
+{SPR_FFLG,32781,4,A_FlameCheck,S_FLAME_TLARGE15,0,0}, // S_FLAME_TLARGE14
+{SPR_FFLG,32782,4,NULL,S_FLAME_TLARGE16,0,0}, // S_FLAME_TLARGE15
+{SPR_FFLG,32783,4,A_FlameCheck,S_FLAME_TLARGE5,0,0}, // S_FLAME_TLARGE16
+{SPR_FFSM,0,2,NULL,S_FLAME_SDORM2,0,0}, // S_FLAME_SDORM1
+{SPR_FFSM,1,2,A_HideThing,S_FLAME_SDORM3,0,0}, // S_FLAME_SDORM2
+{SPR_FFSM,2,200,NULL,S_FLAME_SDORM3,0,0}, // S_FLAME_SDORM3
+{SPR_FFSM,32768,3,NULL,S_FLAME_SMALL2,0,0}, // S_FLAME_SMALL1
+{SPR_FFSM,32768,3,A_UnHideThing,S_FLAME_SMALL3,0,0}, // S_FLAME_SMALL2
+{SPR_FFSM,32768,3,NULL,S_FLAME_SMALL4,0,0}, // S_FLAME_SMALL3
+{SPR_FFSM,32769,3,NULL,S_FLAME_SMALL5,0,0}, // S_FLAME_SMALL4
+{SPR_FFSM,32770,3,NULL,S_FLAME_SMALL6,0,0}, // S_FLAME_SMALL5
+{SPR_FFSM,32771,3,NULL,S_FLAME_SMALL7,0,0}, // S_FLAME_SMALL6
+{SPR_FFSM,32772,3,NULL,S_FLAME_SMALL3,0,0}, // S_FLAME_SMALL7
+{SPR_FFLG,3,2,NULL,S_FLAME_LDORM2,0,0}, // S_FLAME_LDORM1
+{SPR_FFLG,2,2,NULL,S_FLAME_LDORM3,0,0}, // S_FLAME_LDORM2
+{SPR_FFLG,1,2,NULL,S_FLAME_LDORM4,0,0}, // S_FLAME_LDORM3
+{SPR_FFLG,0,2,A_HideThing,S_FLAME_LDORM5,0,0}, // S_FLAME_LDORM4
+{SPR_FFLG,0,200,NULL,S_FLAME_LDORM5,0,0}, // S_FLAME_LDORM5
+{SPR_FFLG,32768,2,NULL,S_FLAME_LARGE2,0,0}, // S_FLAME_LARGE1
+{SPR_FFLG,32768,2,A_UnHideThing,S_FLAME_LARGE3,0,0}, // S_FLAME_LARGE2
+{SPR_FFLG,32768,4,NULL,S_FLAME_LARGE4,0,0}, // S_FLAME_LARGE3
+{SPR_FFLG,32769,4,NULL,S_FLAME_LARGE5,0,0}, // S_FLAME_LARGE4
+{SPR_FFLG,32770,4,NULL,S_FLAME_LARGE6,0,0}, // S_FLAME_LARGE5
+{SPR_FFLG,32771,4,NULL,S_FLAME_LARGE7,0,0}, // S_FLAME_LARGE6
+{SPR_FFLG,32772,4,NULL,S_FLAME_LARGE8,0,0}, // S_FLAME_LARGE7
+{SPR_FFLG,32773,4,NULL,S_FLAME_LARGE9,0,0}, // S_FLAME_LARGE8
+{SPR_FFLG,32774,4,NULL,S_FLAME_LARGE10,0,0}, // S_FLAME_LARGE9
+{SPR_FFLG,32775,4,NULL,S_FLAME_LARGE11,0,0}, // S_FLAME_LARGE10
+{SPR_FFLG,32776,4,NULL,S_FLAME_LARGE12,0,0}, // S_FLAME_LARGE11
+{SPR_FFLG,32777,4,NULL,S_FLAME_LARGE13,0,0}, // S_FLAME_LARGE12
+{SPR_FFLG,32778,4,NULL,S_FLAME_LARGE14,0,0}, // S_FLAME_LARGE13
+{SPR_FFLG,32779,4,NULL,S_FLAME_LARGE15,0,0}, // S_FLAME_LARGE14
+{SPR_FFLG,32780,4,NULL,S_FLAME_LARGE16,0,0}, // S_FLAME_LARGE15
+{SPR_FFLG,32781,4,NULL,S_FLAME_LARGE17,0,0}, // S_FLAME_LARGE16
+{SPR_FFLG,32782,4,NULL,S_FLAME_LARGE18,0,0}, // S_FLAME_LARGE17
+{SPR_FFLG,32783,4,NULL,S_FLAME_LARGE7,0,0}, // S_FLAME_LARGE18
+{SPR_PTN1,0,3,NULL,S_ITEM_PTN1_2,0,0}, // S_ITEM_PTN1_1
+{SPR_PTN1,1,3,NULL,S_ITEM_PTN1_3,0,0}, // S_ITEM_PTN1_2
+{SPR_PTN1,2,3,NULL,S_ITEM_PTN1_1,0,0}, // S_ITEM_PTN1_3
+{SPR_ACLO,4,1400,NULL,S_HIDESPECIAL2,0,0}, // S_HIDESPECIAL1
+{SPR_ACLO,0,4,A_RestoreSpecialThing1,S_HIDESPECIAL3,0,0}, // S_HIDESPECIAL2
+{SPR_ACLO,1,4,NULL,S_HIDESPECIAL4,0,0}, // S_HIDESPECIAL3
+{SPR_ACLO,0,4,NULL,S_HIDESPECIAL5,0,0}, // S_HIDESPECIAL4
+{SPR_ACLO,1,4,NULL,S_HIDESPECIAL6,0,0}, // S_HIDESPECIAL5
+{SPR_ACLO,2,4,NULL,S_HIDESPECIAL7,0,0}, // S_HIDESPECIAL6
+{SPR_ACLO,1,4,NULL,S_HIDESPECIAL8,0,0}, // S_HIDESPECIAL7
+{SPR_ACLO,2,4,NULL,S_HIDESPECIAL9,0,0}, // S_HIDESPECIAL8
+{SPR_ACLO,3,4,NULL,S_HIDESPECIAL10,0,0}, // S_HIDESPECIAL9
+{SPR_ACLO,2,4,NULL,S_HIDESPECIAL11,0,0}, // S_HIDESPECIAL10
+{SPR_ACLO,3,4,A_RestoreSpecialThing2,S_NULL,0,0}, // S_HIDESPECIAL11
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI1_2,0,0}, // S_DORMANTARTI1_1
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_3,0,0}, // S_DORMANTARTI1_2
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI1_4,0,0}, // S_DORMANTARTI1_3
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_5,0,0}, // S_DORMANTARTI1_4
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_6,0,0}, // S_DORMANTARTI1_5
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_7,0,0}, // S_DORMANTARTI1_6
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_8,0,0}, // S_DORMANTARTI1_7
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI1_9,0,0}, // S_DORMANTARTI1_8
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_10,0,0}, // S_DORMANTARTI1_9
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI1_11,0,0}, // S_DORMANTARTI1_10
+{SPR_ACLO,0,1400,A_HideThing,S_DORMANTARTI1_12,0,0}, // S_DORMANTARTI1_11
+{SPR_ACLO,0,3,A_UnHideThing,S_DORMANTARTI1_13,0,0}, // S_DORMANTARTI1_12
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_14,0,0}, // S_DORMANTARTI1_13
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI1_15,0,0}, // S_DORMANTARTI1_14
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_16,0,0}, // S_DORMANTARTI1_15
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_17,0,0}, // S_DORMANTARTI1_16
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI1_18,0,0}, // S_DORMANTARTI1_17
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_19,0,0}, // S_DORMANTARTI1_18
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI1_20,0,0}, // S_DORMANTARTI1_19
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI1_21,0,0}, // S_DORMANTARTI1_20
+{SPR_ACLO,3,3,A_RestoreArtifact,S_NULL,0,0}, // S_DORMANTARTI1_21
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI2_2,0,0}, // S_DORMANTARTI2_1
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_3,0,0}, // S_DORMANTARTI2_2
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI2_4,0,0}, // S_DORMANTARTI2_3
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_5,0,0}, // S_DORMANTARTI2_4
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_6,0,0}, // S_DORMANTARTI2_5
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_7,0,0}, // S_DORMANTARTI2_6
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_8,0,0}, // S_DORMANTARTI2_7
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI2_9,0,0}, // S_DORMANTARTI2_8
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_10,0,0}, // S_DORMANTARTI2_9
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI2_11,0,0}, // S_DORMANTARTI2_10
+{SPR_ACLO,0,4200,A_HideThing,S_DORMANTARTI2_12,0,0}, // S_DORMANTARTI2_11
+{SPR_ACLO,0,3,A_UnHideThing,S_DORMANTARTI2_13,0,0}, // S_DORMANTARTI2_12
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_14,0,0}, // S_DORMANTARTI2_13
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI2_15,0,0}, // S_DORMANTARTI2_14
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_16,0,0}, // S_DORMANTARTI2_15
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_17,0,0}, // S_DORMANTARTI2_16
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI2_18,0,0}, // S_DORMANTARTI2_17
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_19,0,0}, // S_DORMANTARTI2_18
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI2_20,0,0}, // S_DORMANTARTI2_19
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI2_21,0,0}, // S_DORMANTARTI2_20
+{SPR_ACLO,3,3,A_RestoreArtifact,S_NULL,0,0}, // S_DORMANTARTI2_21
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI3_2,0,0}, // S_DORMANTARTI3_1
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_3,0,0}, // S_DORMANTARTI3_2
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI3_4,0,0}, // S_DORMANTARTI3_3
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_5,0,0}, // S_DORMANTARTI3_4
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_6,0,0}, // S_DORMANTARTI3_5
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_7,0,0}, // S_DORMANTARTI3_6
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_8,0,0}, // S_DORMANTARTI3_7
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI3_9,0,0}, // S_DORMANTARTI3_8
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_10,0,0}, // S_DORMANTARTI3_9
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI3_11,0,0}, // S_DORMANTARTI3_10
+{SPR_ACLO,0,21000,A_HideThing,S_DORMANTARTI3_12,0,0}, // S_DORMANTARTI3_11
+{SPR_ACLO,0,3,A_UnHideThing,S_DORMANTARTI3_13,0,0}, // S_DORMANTARTI3_12
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_14,0,0}, // S_DORMANTARTI3_13
+{SPR_ACLO,0,3,NULL,S_DORMANTARTI3_15,0,0}, // S_DORMANTARTI3_14
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_16,0,0}, // S_DORMANTARTI3_15
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_17,0,0}, // S_DORMANTARTI3_16
+{SPR_ACLO,1,3,NULL,S_DORMANTARTI3_18,0,0}, // S_DORMANTARTI3_17
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_19,0,0}, // S_DORMANTARTI3_18
+{SPR_ACLO,3,3,NULL,S_DORMANTARTI3_20,0,0}, // S_DORMANTARTI3_19
+{SPR_ACLO,2,3,NULL,S_DORMANTARTI3_21,0,0}, // S_DORMANTARTI3_20
+{SPR_ACLO,3,3,A_RestoreArtifact,S_NULL,0,0}, // S_DORMANTARTI3_21
+{SPR_ACLO,3,3,NULL,S_DEADARTI2,0,0}, // S_DEADARTI1
+{SPR_ACLO,2,3,NULL,S_DEADARTI3,0,0}, // S_DEADARTI2
+{SPR_ACLO,3,3,NULL,S_DEADARTI4,0,0}, // S_DEADARTI3
+{SPR_ACLO,2,3,NULL,S_DEADARTI5,0,0}, // S_DEADARTI4
+{SPR_ACLO,1,3,NULL,S_DEADARTI6,0,0}, // S_DEADARTI5
+{SPR_ACLO,2,3,NULL,S_DEADARTI7,0,0}, // S_DEADARTI6
+{SPR_ACLO,1,3,NULL,S_DEADARTI8,0,0}, // S_DEADARTI7
+{SPR_ACLO,0,3,NULL,S_DEADARTI9,0,0}, // S_DEADARTI8
+{SPR_ACLO,1,3,NULL,S_DEADARTI10,0,0}, // S_DEADARTI9
+{SPR_ACLO,0,3,NULL,S_NULL,0,0}, // S_DEADARTI10
+{SPR_PTN2,0,4,NULL,S_ARTI_PTN2_2,0,0}, // S_ARTI_PTN2_1
+{SPR_PTN2,1,4,NULL,S_ARTI_PTN2_3,0,0}, // S_ARTI_PTN2_2
+{SPR_PTN2,2,4,NULL,S_ARTI_PTN2_1,0,0}, // S_ARTI_PTN2_3
+{SPR_SOAR,0,5,NULL,S_ARTI_SOAR2,0,0}, // S_ARTI_SOAR1
+{SPR_SOAR,1,5,NULL,S_ARTI_SOAR3,0,0}, // S_ARTI_SOAR2
+{SPR_SOAR,2,5,NULL,S_ARTI_SOAR4,0,0}, // S_ARTI_SOAR3
+{SPR_SOAR,1,5,NULL,S_ARTI_SOAR1,0,0}, // S_ARTI_SOAR4
+{SPR_INVU,0,3,NULL,S_ARTI_INVU2,0,0}, // S_ARTI_INVU1
+{SPR_INVU,1,3,NULL,S_ARTI_INVU3,0,0}, // S_ARTI_INVU2
+{SPR_INVU,2,3,NULL,S_ARTI_INVU4,0,0}, // S_ARTI_INVU3
+{SPR_INVU,3,3,NULL,S_ARTI_INVU1,0,0}, // S_ARTI_INVU4
+{SPR_SUMN,0,350,NULL,S_ARTI_SUMMON,0,0}, // S_ARTI_SUMMON
+{SPR_SUMN,0,4,NULL,S_SUMMON_FX1_1,0,0}, // S_SUMMON_FX1_1
+{SPR_SUMN,0,4,NULL,S_SUMMON_FX2_2,0,0}, // S_SUMMON_FX2_1
+{SPR_SUMN,0,4,NULL,S_SUMMON_FX2_3,0,0}, // S_SUMMON_FX2_2
+{SPR_SUMN,0,4,A_Summon,S_NULL,0,0}, // S_SUMMON_FX2_3
+{SPR_TSPK,0,3,NULL,S_THRUSTINIT2_2,0,0}, // S_THRUSTINIT2_1
+{SPR_TSPK,0,4,A_ThrustInitUp,S_THRUSTBLOCK,0,0}, // S_THRUSTINIT2_2
+{SPR_TSPK,1,3,NULL,S_BTHRUSTINIT2_2,0,0}, // S_BTHRUSTINIT2_1
+{SPR_TSPK,1,4,A_ThrustInitUp,S_BTHRUSTBLOCK,0,0}, // S_BTHRUSTINIT2_2
+{SPR_TSPK,0,3,NULL,S_THRUSTINIT1_2,0,0}, // S_THRUSTINIT1_1
+{SPR_TSPK,0,4,A_ThrustInitDn,S_THRUSTSTAY,0,0}, // S_THRUSTINIT1_2
+{SPR_TSPK,1,3,NULL,S_BTHRUSTINIT1_2,0,0}, // S_BTHRUSTINIT1_1
+{SPR_TSPK,1,4,A_ThrustInitDn,S_BTHRUSTSTAY,0,0}, // S_BTHRUSTINIT1_2
+{SPR_TSPK,0,8,A_ThrustRaise,S_THRUSTRAISE2,0,0}, // S_THRUSTRAISE1
+{SPR_TSPK,0,6,A_ThrustRaise,S_THRUSTRAISE3,0,0}, // S_THRUSTRAISE2
+{SPR_TSPK,0,4,A_ThrustRaise,S_THRUSTRAISE4,0,0}, // S_THRUSTRAISE3
+{SPR_TSPK,0,3,A_ThrustBlock,S_THRUSTIMPALE,0,0}, // S_THRUSTRAISE4
+{SPR_TSPK,1,8,A_ThrustRaise,S_BTHRUSTRAISE2,0,0}, // S_BTHRUSTRAISE1
+{SPR_TSPK,1,6,A_ThrustRaise,S_BTHRUSTRAISE3,0,0}, // S_BTHRUSTRAISE2
+{SPR_TSPK,1,4,A_ThrustRaise,S_BTHRUSTRAISE4,0,0}, // S_BTHRUSTRAISE3
+{SPR_TSPK,1,3,A_ThrustBlock,S_BTHRUSTIMPALE,0,0}, // S_BTHRUSTRAISE4
+{SPR_TSPK,0,2,A_ThrustImpale,S_THRUSTRAISE,0,0}, // S_THRUSTIMPALE
+{SPR_TSPK,1,2,A_ThrustImpale,S_BTHRUSTRAISE,0,0}, // S_BTHRUSTIMPALE
+{SPR_TSPK,0,2,A_ThrustRaise,S_THRUSTRAISE,0,0}, // S_THRUSTRAISE
+{SPR_TSPK,1,2,A_ThrustRaise,S_BTHRUSTRAISE,0,0}, // S_BTHRUSTRAISE
+{SPR_TSPK,0,10,NULL,S_THRUSTBLOCK,0,0}, // S_THRUSTBLOCK
+{SPR_TSPK,1,10,NULL,S_BTHRUSTBLOCK,0,0}, // S_BTHRUSTBLOCK
+{SPR_TSPK,0,2,A_ThrustLower,S_THRUSTLOWER,0,0}, // S_THRUSTLOWER
+{SPR_TSPK,1,2,A_ThrustLower,S_BTHRUSTLOWER,0,0}, // S_BTHRUSTLOWER
+{SPR_TSPK,0,-1,NULL,S_THRUSTSTAY,0,0}, // S_THRUSTSTAY
+{SPR_TSPK,1,-1,NULL,S_BTHRUSTSTAY,0,0}, // S_BTHRUSTSTAY
+{SPR_TELO,0,5,NULL,S_ARTI_TELOTHER2,0,0}, // S_ARTI_TELOTHER1
+{SPR_TELO,1,5,NULL,S_ARTI_TELOTHER3,0,0}, // S_ARTI_TELOTHER2
+{SPR_TELO,2,5,NULL,S_ARTI_TELOTHER4,0,0}, // S_ARTI_TELOTHER3
+{SPR_TELO,3,5,NULL,S_ARTI_TELOTHER1,0,0}, // S_ARTI_TELOTHER4
+{SPR_TRNG,32772,5,NULL,S_TELO_FX2,0,0}, // S_TELO_FX1
+{SPR_TRNG,32771,4,NULL,S_TELO_FX3,0,0}, // S_TELO_FX2
+{SPR_TRNG,32770,3,A_TeloSpawnC,S_TELO_FX4,0,0}, // S_TELO_FX3
+{SPR_TRNG,32769,3,A_TeloSpawnB,S_TELO_FX5,0,0}, // S_TELO_FX4
+{SPR_TRNG,32768,3,A_TeloSpawnA,S_TELO_FX6,0,0}, // S_TELO_FX5
+{SPR_TRNG,32769,3,A_TeloSpawnB,S_TELO_FX7,0,0}, // S_TELO_FX6
+{SPR_TRNG,32770,3,A_TeloSpawnC,S_TELO_FX8,0,0}, // S_TELO_FX7
+{SPR_TRNG,32771,3,A_TeloSpawnD,S_TELO_FX3,0,0}, // S_TELO_FX8
+{SPR_TRNG,32772,3,NULL,S_NULL,0,0}, // S_TELO_FX9
+{SPR_TRNG,32769,4,NULL,S_TELO_FX2_2,0,0}, // S_TELO_FX2_1
+{SPR_TRNG,32770,4,NULL,S_TELO_FX2_3,0,0}, // S_TELO_FX2_2
+{SPR_TRNG,32771,4,NULL,S_TELO_FX2_4,0,0}, // S_TELO_FX2_3
+{SPR_TRNG,32770,4,NULL,S_TELO_FX2_5,0,0}, // S_TELO_FX2_4
+{SPR_TRNG,32769,4,NULL,S_TELO_FX2_6,0,0}, // S_TELO_FX2_5
+{SPR_TRNG,32768,4,A_CheckTeleRing,S_TELO_FX2_1,0,0}, // S_TELO_FX2_6
+{SPR_TRNG,32770,4,NULL,S_TELO_FX3_2,0,0}, // S_TELO_FX3_1
+{SPR_TRNG,32771,4,NULL,S_TELO_FX3_3,0,0}, // S_TELO_FX3_2
+{SPR_TRNG,32770,4,NULL,S_TELO_FX3_4,0,0}, // S_TELO_FX3_3
+{SPR_TRNG,32769,4,NULL,S_TELO_FX3_5,0,0}, // S_TELO_FX3_4
+{SPR_TRNG,32768,4,NULL,S_TELO_FX3_6,0,0}, // S_TELO_FX3_5
+{SPR_TRNG,32769,4,A_CheckTeleRing,S_TELO_FX3_1,0,0}, // S_TELO_FX3_6
+{SPR_TRNG,32771,4,NULL,S_TELO_FX4_2,0,0}, // S_TELO_FX4_1
+{SPR_TRNG,32770,4,NULL,S_TELO_FX4_3,0,0}, // S_TELO_FX4_2
+{SPR_TRNG,32769,4,NULL,S_TELO_FX4_4,0,0}, // S_TELO_FX4_3
+{SPR_TRNG,32768,4,NULL,S_TELO_FX4_5,0,0}, // S_TELO_FX4_4
+{SPR_TRNG,32769,4,NULL,S_TELO_FX4_6,0,0}, // S_TELO_FX4_5
+{SPR_TRNG,32770,4,A_CheckTeleRing,S_TELO_FX4_1,0,0}, // S_TELO_FX4_6
+{SPR_TRNG,32770,4,NULL,S_TELO_FX5_2,0,0}, // S_TELO_FX5_1
+{SPR_TRNG,32769,4,NULL,S_TELO_FX5_3,0,0}, // S_TELO_FX5_2
+{SPR_TRNG,32768,4,NULL,S_TELO_FX5_4,0,0}, // S_TELO_FX5_3
+{SPR_TRNG,32769,4,NULL,S_TELO_FX5_5,0,0}, // S_TELO_FX5_4
+{SPR_TRNG,32770,4,NULL,S_TELO_FX5_6,0,0}, // S_TELO_FX5_5
+{SPR_TRNG,32771,4,A_CheckTeleRing,S_TELO_FX5_1,0,0}, // S_TELO_FX5_6
+{SPR_ROCK,3,20,NULL,S_DIRT1_1,0,0}, // S_DIRT1_1
+{SPR_ROCK,3,10,NULL,S_NULL,0,0}, // S_DIRT1_D
+{SPR_ROCK,4,20,NULL,S_DIRT2_1,0,0}, // S_DIRT2_1
+{SPR_ROCK,4,10,NULL,S_NULL,0,0}, // S_DIRT2_D
+{SPR_ROCK,5,20,NULL,S_DIRT3_1,0,0}, // S_DIRT3_1
+{SPR_ROCK,5,10,NULL,S_NULL,0,0}, // S_DIRT3_D
+{SPR_ROCK,6,20,NULL,S_DIRT4_1,0,0}, // S_DIRT4_1
+{SPR_ROCK,6,10,NULL,S_NULL,0,0}, // S_DIRT4_D
+{SPR_ROCK,7,20,NULL,S_DIRT5_1,0,0}, // S_DIRT5_1
+{SPR_ROCK,7,10,NULL,S_NULL,0,0}, // S_DIRT5_D
+{SPR_ROCK,8,20,NULL,S_DIRT6_1,0,0}, // S_DIRT6_1
+{SPR_ROCK,8,10,NULL,S_NULL,0,0}, // S_DIRT6_D
+{SPR_TSPK,2,20,NULL,S_DIRTCLUMP1,0,0}, // S_DIRTCLUMP1
+{SPR_ROCK,0,20,NULL,S_ROCK1_1,0,0}, // S_ROCK1_1
+{SPR_ROCK,0,10,NULL,S_NULL,0,0}, // S_ROCK1_D
+{SPR_ROCK,1,20,NULL,S_ROCK2_1,0,0}, // S_ROCK2_1
+{SPR_ROCK,1,10,NULL,S_NULL,0,0}, // S_ROCK2_D
+{SPR_ROCK,2,20,NULL,S_ROCK3_1,0,0}, // S_ROCK3_1
+{SPR_ROCK,2,10,NULL,S_NULL,0,0}, // S_ROCK3_D
+{SPR_MAN1,0,20,A_FogSpawn,S_SPAWNFOG1,0,0}, // S_SPAWNFOG1
+{SPR_FOGS,0,7,A_FogMove,S_FOGPATCHS2,0,0}, // S_FOGPATCHS1
+{SPR_FOGS,1,7,A_FogMove,S_FOGPATCHS3,0,0}, // S_FOGPATCHS2
+{SPR_FOGS,2,7,A_FogMove,S_FOGPATCHS4,0,0}, // S_FOGPATCHS3
+{SPR_FOGS,3,7,A_FogMove,S_FOGPATCHS5,0,0}, // S_FOGPATCHS4
+{SPR_FOGS,4,7,A_FogMove,S_FOGPATCHS1,0,0}, // S_FOGPATCHS5
+{SPR_FOGS,4,5,NULL,S_NULL,0,0}, // S_FOGPATCHS0
+{SPR_FOGM,0,7,A_FogMove,S_FOGPATCHM2,0,0}, // S_FOGPATCHM1
+{SPR_FOGM,1,7,A_FogMove,S_FOGPATCHM3,0,0}, // S_FOGPATCHM2
+{SPR_FOGM,2,7,A_FogMove,S_FOGPATCHM4,0,0}, // S_FOGPATCHM3
+{SPR_FOGM,3,7,A_FogMove,S_FOGPATCHM5,0,0}, // S_FOGPATCHM4
+{SPR_FOGM,4,7,A_FogMove,S_FOGPATCHM1,0,0}, // S_FOGPATCHM5
+{SPR_FOGS,0,5,NULL,S_FOGPATCHMA,0,0}, // S_FOGPATCHM0
+{SPR_FOGS,1,5,NULL,S_FOGPATCHMB,0,0}, // S_FOGPATCHMA
+{SPR_FOGS,2,5,NULL,S_FOGPATCHMC,0,0}, // S_FOGPATCHMB
+{SPR_FOGS,3,5,NULL,S_FOGPATCHMD,0,0}, // S_FOGPATCHMC
+{SPR_FOGS,4,5,NULL,S_FOGPATCHS0,0,0}, // S_FOGPATCHMD
+{SPR_FOGL,0,7,A_FogMove,S_FOGPATCHL2,0,0}, // S_FOGPATCHL1
+{SPR_FOGL,1,7,A_FogMove,S_FOGPATCHL3,0,0}, // S_FOGPATCHL2
+{SPR_FOGL,2,7,A_FogMove,S_FOGPATCHL4,0,0}, // S_FOGPATCHL3
+{SPR_FOGL,3,7,A_FogMove,S_FOGPATCHL5,0,0}, // S_FOGPATCHL4
+{SPR_FOGL,4,7,A_FogMove,S_FOGPATCHL1,0,0}, // S_FOGPATCHL5
+{SPR_FOGM,0,4,NULL,S_FOGPATCHLA,0,0}, // S_FOGPATCHL0
+{SPR_FOGM,1,4,NULL,S_FOGPATCHLB,0,0}, // S_FOGPATCHLA
+{SPR_FOGM,2,4,NULL,S_FOGPATCHLC,0,0}, // S_FOGPATCHLB
+{SPR_FOGM,3,4,NULL,S_FOGPATCHLD,0,0}, // S_FOGPATCHLC
+{SPR_FOGM,4,4,NULL,S_FOGPATCHM0,0,0}, // S_FOGPATCHLD
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE2,0,0}, // S_QUAKE_ACTIVE1
+{SPR_MAN1,0,1,A_ContMobjSound,S_QUAKE_ACTIVE3,0,0}, // S_QUAKE_ACTIVE2
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE4,0,0}, // S_QUAKE_ACTIVE3
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE5,0,0}, // S_QUAKE_ACTIVE4
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE6,0,0}, // S_QUAKE_ACTIVE5
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE7,0,0}, // S_QUAKE_ACTIVE6
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE8,0,0}, // S_QUAKE_ACTIVE7
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE9,0,0}, // S_QUAKE_ACTIVE8
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE0,0,0}, // S_QUAKE_ACTIVE9
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEA,0,0}, // S_QUAKE_ACTIVE0
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEB,0,0}, // S_QUAKE_ACTIVEA
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEC,0,0}, // S_QUAKE_ACTIVEB
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVED,0,0}, // S_QUAKE_ACTIVEC
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEE,0,0}, // S_QUAKE_ACTIVED
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEF,0,0}, // S_QUAKE_ACTIVEE
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEG,0,0}, // S_QUAKE_ACTIVEF
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEH,0,0}, // S_QUAKE_ACTIVEG
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEI,0,0}, // S_QUAKE_ACTIVEH
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEJ,0,0}, // S_QUAKE_ACTIVEI
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEK,0,0}, // S_QUAKE_ACTIVEJ
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEL,0,0}, // S_QUAKE_ACTIVEK
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEM,0,0}, // S_QUAKE_ACTIVEL
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEN,0,0}, // S_QUAKE_ACTIVEM
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEO,0,0}, // S_QUAKE_ACTIVEN
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEP,0,0}, // S_QUAKE_ACTIVEO
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEQ,0,0}, // S_QUAKE_ACTIVEP
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVER,0,0}, // S_QUAKE_ACTIVEQ
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVES,0,0}, // S_QUAKE_ACTIVER
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVET,0,0}, // S_QUAKE_ACTIVES
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEU,0,0}, // S_QUAKE_ACTIVET
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEV,0,0}, // S_QUAKE_ACTIVEU
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEW,0,0}, // S_QUAKE_ACTIVEV
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEX,0,0}, // S_QUAKE_ACTIVEW
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEY,0,0}, // S_QUAKE_ACTIVEX
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVEZ,0,0}, // S_QUAKE_ACTIVEY
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT1,0,0}, // S_QUAKE_ACTIVEZ
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT2,0,0}, // S_QUAKE_ACT1
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT3,0,0}, // S_QUAKE_ACT2
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT4,0,0}, // S_QUAKE_ACT3
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT5,0,0}, // S_QUAKE_ACT4
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT6,0,0}, // S_QUAKE_ACT5
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT7,0,0}, // S_QUAKE_ACT6
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT8,0,0}, // S_QUAKE_ACT7
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT9,0,0}, // S_QUAKE_ACT8
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACT0,0,0}, // S_QUAKE_ACT9
+{SPR_MAN1,0,2,A_Quake,S_QUAKE_ACTIVE1,0,0}, // S_QUAKE_ACT0
+{SPR_SGSA,0,4,NULL,S_SGSHARD1_2,0,0}, // S_SGSHARD1_1
+{SPR_SGSA,1,4,NULL,S_SGSHARD1_3,0,0}, // S_SGSHARD1_2
+{SPR_SGSA,2,4,NULL,S_SGSHARD1_4,0,0}, // S_SGSHARD1_3
+{SPR_SGSA,3,4,NULL,S_SGSHARD1_5,0,0}, // S_SGSHARD1_4
+{SPR_SGSA,4,4,NULL,S_SGSHARD1_1,0,0}, // S_SGSHARD1_5
+{SPR_SGSA,4,30,NULL,S_NULL,0,0}, // S_SGSHARD1_D
+{SPR_SGSA,5,4,NULL,S_SGSHARD2_2,0,0}, // S_SGSHARD2_1
+{SPR_SGSA,6,4,NULL,S_SGSHARD2_3,0,0}, // S_SGSHARD2_2
+{SPR_SGSA,7,4,NULL,S_SGSHARD2_4,0,0}, // S_SGSHARD2_3
+{SPR_SGSA,8,4,NULL,S_SGSHARD2_5,0,0}, // S_SGSHARD2_4
+{SPR_SGSA,9,4,NULL,S_SGSHARD2_1,0,0}, // S_SGSHARD2_5
+{SPR_SGSA,9,30,NULL,S_NULL,0,0}, // S_SGSHARD2_D
+{SPR_SGSA,10,4,NULL,S_SGSHARD3_2,0,0}, // S_SGSHARD3_1
+{SPR_SGSA,11,4,NULL,S_SGSHARD3_3,0,0}, // S_SGSHARD3_2
+{SPR_SGSA,12,4,NULL,S_SGSHARD3_4,0,0}, // S_SGSHARD3_3
+{SPR_SGSA,13,4,NULL,S_SGSHARD3_5,0,0}, // S_SGSHARD3_4
+{SPR_SGSA,14,4,NULL,S_SGSHARD3_1,0,0}, // S_SGSHARD3_5
+{SPR_SGSA,14,30,NULL,S_NULL,0,0}, // S_SGSHARD3_D
+{SPR_SGSA,15,4,NULL,S_SGSHARD4_2,0,0}, // S_SGSHARD4_1
+{SPR_SGSA,16,4,NULL,S_SGSHARD4_3,0,0}, // S_SGSHARD4_2
+{SPR_SGSA,17,4,NULL,S_SGSHARD4_4,0,0}, // S_SGSHARD4_3
+{SPR_SGSA,18,4,NULL,S_SGSHARD4_5,0,0}, // S_SGSHARD4_4
+{SPR_SGSA,19,4,NULL,S_SGSHARD4_1,0,0}, // S_SGSHARD4_5
+{SPR_SGSA,19,30,NULL,S_NULL,0,0}, // S_SGSHARD4_D
+{SPR_SGSA,20,4,NULL,S_SGSHARD5_2,0,0}, // S_SGSHARD5_1
+{SPR_SGSA,21,4,NULL,S_SGSHARD5_3,0,0}, // S_SGSHARD5_2
+{SPR_SGSA,22,4,NULL,S_SGSHARD5_4,0,0}, // S_SGSHARD5_3
+{SPR_SGSA,23,4,NULL,S_SGSHARD5_5,0,0}, // S_SGSHARD5_4
+{SPR_SGSA,24,4,NULL,S_SGSHARD5_1,0,0}, // S_SGSHARD5_5
+{SPR_SGSA,24,30,NULL,S_NULL,0,0}, // S_SGSHARD5_D
+{SPR_SGSB,0,4,NULL,S_SGSHARD6_1,0,0}, // S_SGSHARD6_1
+{SPR_SGSB,0,30,NULL,S_NULL,0,0}, // S_SGSHARD6_D
+{SPR_SGSB,1,4,NULL,S_SGSHARD7_1,0,0}, // S_SGSHARD7_1
+{SPR_SGSB,1,30,NULL,S_NULL,0,0}, // S_SGSHARD7_D
+{SPR_SGSB,2,4,NULL,S_SGSHARD8_1,0,0}, // S_SGSHARD8_1
+{SPR_SGSB,2,30,NULL,S_NULL,0,0}, // S_SGSHARD8_D
+{SPR_SGSB,3,4,NULL,S_SGSHARD9_1,0,0}, // S_SGSHARD9_1
+{SPR_SGSB,3,30,NULL,S_NULL,0,0}, // S_SGSHARD9_D
+{SPR_SGSB,4,4,NULL,S_SGSHARD0_1,0,0}, // S_SGSHARD0_1
+{SPR_SGSB,4,30,NULL,S_NULL,0,0}, // S_SGSHARD0_D
+{SPR_PORK,0,5,NULL,S_ARTI_EGGC2,0,0}, // S_ARTI_EGGC1
+{SPR_PORK,1,5,NULL,S_ARTI_EGGC3,0,0}, // S_ARTI_EGGC2
+{SPR_PORK,2,5,NULL,S_ARTI_EGGC4,0,0}, // S_ARTI_EGGC3
+{SPR_PORK,3,5,NULL,S_ARTI_EGGC5,0,0}, // S_ARTI_EGGC4
+{SPR_PORK,4,5,NULL,S_ARTI_EGGC6,0,0}, // S_ARTI_EGGC5
+{SPR_PORK,5,5,NULL,S_ARTI_EGGC7,0,0}, // S_ARTI_EGGC6
+{SPR_PORK,6,5,NULL,S_ARTI_EGGC8,0,0}, // S_ARTI_EGGC7
+{SPR_PORK,7,5,NULL,S_ARTI_EGGC1,0,0}, // S_ARTI_EGGC8
+{SPR_EGGM,0,4,NULL,S_EGGFX2,0,0}, // S_EGGFX1
+{SPR_EGGM,1,4,NULL,S_EGGFX3,0,0}, // S_EGGFX2
+{SPR_EGGM,2,4,NULL,S_EGGFX4,0,0}, // S_EGGFX3
+{SPR_EGGM,3,4,NULL,S_EGGFX5,0,0}, // S_EGGFX4
+{SPR_EGGM,4,4,NULL,S_EGGFX1,0,0}, // S_EGGFX5
+{SPR_FHFX,32776,3,NULL,S_EGGFXI1_2,0,0}, // S_EGGFXI1_1
+{SPR_FHFX,32777,3,NULL,S_EGGFXI1_3,0,0}, // S_EGGFXI1_2
+{SPR_FHFX,32778,3,NULL,S_EGGFXI1_4,0,0}, // S_EGGFXI1_3
+{SPR_FHFX,32779,3,NULL,S_NULL,0,0}, // S_EGGFXI1_4
+{SPR_SPHL,0,350,NULL,S_ARTI_SPHL1,0,0}, // S_ARTI_SPHL1
+{SPR_STWN,0,-1,NULL,S_NULL,0,0}, // S_ZWINGEDSTATUENOSKULL
+{SPR_STWN,1,-1,NULL,S_NULL,0,0}, // S_ZWINGEDSTATUENOSKULL2
+{SPR_GMPD,0,-1,NULL,S_NULL,0,0}, // S_ZGEMPEDESTAL1
+{SPR_GMPD,1,-1,NULL,S_NULL,0,0}, // S_ZGEMPEDESTAL2
+{SPR_ASKU,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZSKULL
+{SPR_ABGM,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZGEMBIG
+{SPR_AGMR,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZGEMRED
+{SPR_AGMG,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZGEMGREEN1
+{SPR_AGG2,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZGEMGREEN2
+{SPR_AGMB,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZGEMBLUE1
+{SPR_AGB2,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZGEMBLUE2
+{SPR_ABK1,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZBOOK1
+{SPR_ABK2,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZBOOK2
+{SPR_ASK2,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZSKULL2
+{SPR_AFWP,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZFWEAPON
+{SPR_ACWP,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZCWEAPON
+{SPR_AMWP,0,-1,NULL,S_NULL,0,0}, // S_ARTIPUZZMWEAPON
+{SPR_AGER,32768,4,NULL,S_ARTIPUZZGEAR_2,0,0}, // S_ARTIPUZZGEAR_1
+{SPR_AGER,32769,4,NULL,S_ARTIPUZZGEAR_3,0,0}, // S_ARTIPUZZGEAR_2
+{SPR_AGER,32770,4,NULL,S_ARTIPUZZGEAR_4,0,0}, // S_ARTIPUZZGEAR_3
+{SPR_AGER,32771,4,NULL,S_ARTIPUZZGEAR_5,0,0}, // S_ARTIPUZZGEAR_4
+{SPR_AGER,32772,4,NULL,S_ARTIPUZZGEAR_6,0,0}, // S_ARTIPUZZGEAR_5
+{SPR_AGER,32773,4,NULL,S_ARTIPUZZGEAR_7,0,0}, // S_ARTIPUZZGEAR_6
+{SPR_AGER,32774,4,NULL,S_ARTIPUZZGEAR_8,0,0}, // S_ARTIPUZZGEAR_7
+{SPR_AGER,32775,4,NULL,S_ARTIPUZZGEAR_1,0,0}, // S_ARTIPUZZGEAR_8
+{SPR_AGR2,32768,4,NULL,S_ARTIPUZZGEAR2_2,0,0}, // S_ARTIPUZZGEAR2_1
+{SPR_AGR2,32769,4,NULL,S_ARTIPUZZGEAR2_3,0,0}, // S_ARTIPUZZGEAR2_2
+{SPR_AGR2,32770,4,NULL,S_ARTIPUZZGEAR2_4,0,0}, // S_ARTIPUZZGEAR2_3
+{SPR_AGR2,32771,4,NULL,S_ARTIPUZZGEAR2_5,0,0}, // S_ARTIPUZZGEAR2_4
+{SPR_AGR2,32772,4,NULL,S_ARTIPUZZGEAR2_6,0,0}, // S_ARTIPUZZGEAR2_5
+{SPR_AGR2,32773,4,NULL,S_ARTIPUZZGEAR2_7,0,0}, // S_ARTIPUZZGEAR2_6
+{SPR_AGR2,32774,4,NULL,S_ARTIPUZZGEAR2_8,0,0}, // S_ARTIPUZZGEAR2_7
+{SPR_AGR2,32775,4,NULL,S_ARTIPUZZGEAR2_1,0,0}, // S_ARTIPUZZGEAR2_8
+{SPR_AGR3,32768,4,NULL,S_ARTIPUZZGEAR3_2,0,0}, // S_ARTIPUZZGEAR3_1
+{SPR_AGR3,32769,4,NULL,S_ARTIPUZZGEAR3_3,0,0}, // S_ARTIPUZZGEAR3_2
+{SPR_AGR3,32770,4,NULL,S_ARTIPUZZGEAR3_4,0,0}, // S_ARTIPUZZGEAR3_3
+{SPR_AGR3,32771,4,NULL,S_ARTIPUZZGEAR3_5,0,0}, // S_ARTIPUZZGEAR3_4
+{SPR_AGR3,32772,4,NULL,S_ARTIPUZZGEAR3_6,0,0}, // S_ARTIPUZZGEAR3_5
+{SPR_AGR3,32773,4,NULL,S_ARTIPUZZGEAR3_7,0,0}, // S_ARTIPUZZGEAR3_6
+{SPR_AGR3,32774,4,NULL,S_ARTIPUZZGEAR3_8,0,0}, // S_ARTIPUZZGEAR3_7
+{SPR_AGR3,32775,4,NULL,S_ARTIPUZZGEAR3_1,0,0}, // S_ARTIPUZZGEAR3_8
+{SPR_AGR4,32768,4,NULL,S_ARTIPUZZGEAR4_2,0,0}, // S_ARTIPUZZGEAR4_1
+{SPR_AGR4,32769,4,NULL,S_ARTIPUZZGEAR4_3,0,0}, // S_ARTIPUZZGEAR4_2
+{SPR_AGR4,32770,4,NULL,S_ARTIPUZZGEAR4_4,0,0}, // S_ARTIPUZZGEAR4_3
+{SPR_AGR4,32771,4,NULL,S_ARTIPUZZGEAR4_5,0,0}, // S_ARTIPUZZGEAR4_4
+{SPR_AGR4,32772,4,NULL,S_ARTIPUZZGEAR4_6,0,0}, // S_ARTIPUZZGEAR4_5
+{SPR_AGR4,32773,4,NULL,S_ARTIPUZZGEAR4_7,0,0}, // S_ARTIPUZZGEAR4_6
+{SPR_AGR4,32774,4,NULL,S_ARTIPUZZGEAR4_8,0,0}, // S_ARTIPUZZGEAR4_7
+{SPR_AGR4,32775,4,NULL,S_ARTIPUZZGEAR4_1,0,0}, // S_ARTIPUZZGEAR4_8
+{SPR_TRCH,32768,3,NULL,S_ARTI_TRCH2,0,0}, // S_ARTI_TRCH1
+{SPR_TRCH,32769,3,NULL,S_ARTI_TRCH3,0,0}, // S_ARTI_TRCH2
+{SPR_TRCH,32770,3,NULL,S_ARTI_TRCH1,0,0}, // S_ARTI_TRCH3
+{SPR_PSBG,0,20,NULL,S_FIREBOMB2,0,0}, // S_FIREBOMB1
+{SPR_PSBG,0,10,NULL,S_FIREBOMB3,0,0}, // S_FIREBOMB2
+{SPR_PSBG,0,10,NULL,S_FIREBOMB4,0,0}, // S_FIREBOMB3
+{SPR_PSBG,1,4,NULL,S_FIREBOMB5,0,0}, // S_FIREBOMB4
+{SPR_PSBG,2,4,A_Scream,S_FIREBOMB6,0,0}, // S_FIREBOMB5
+{SPR_XPL1,32768,4,A_Explode,S_FIREBOMB7,0,0}, // S_FIREBOMB6
+{SPR_XPL1,32769,4,NULL,S_FIREBOMB8,0,0}, // S_FIREBOMB7
+{SPR_XPL1,32770,4,NULL,S_FIREBOMB9,0,0}, // S_FIREBOMB8
+{SPR_XPL1,32771,4,NULL,S_FIREBOMB10,0,0}, // S_FIREBOMB9
+{SPR_XPL1,32772,4,NULL,S_FIREBOMB11,0,0}, // S_FIREBOMB10
+{SPR_XPL1,32773,4,NULL,S_NULL,0,0}, // S_FIREBOMB11
+{SPR_ATLP,0,4,NULL,S_ARTI_ATLP2,0,0}, // S_ARTI_ATLP1
+{SPR_ATLP,1,4,NULL,S_ARTI_ATLP3,0,0}, // S_ARTI_ATLP2
+{SPR_ATLP,2,4,NULL,S_ARTI_ATLP4,0,0}, // S_ARTI_ATLP3
+{SPR_ATLP,1,4,NULL,S_ARTI_ATLP1,0,0}, // S_ARTI_ATLP4
+{SPR_PSBG,0,-1,NULL,S_NULL,0,0}, // S_ARTI_PSBG1
+{SPR_PSBG,32768,18,NULL,S_POISONBAG2,0,0}, // S_POISONBAG1
+{SPR_PSBG,32769,4,NULL,S_POISONBAG3,0,0}, // S_POISONBAG2
+{SPR_PSBG,2,3,NULL,S_POISONBAG4,0,0}, // S_POISONBAG3
+{SPR_PSBG,2,1,A_PoisonBagInit,S_NULL,0,0}, // S_POISONBAG4
+{SPR_PSBG,3,1,NULL,S_POISONCLOUD2,0,0}, // S_POISONCLOUD1
+{SPR_PSBG,3,1,A_Scream,S_POISONCLOUD3,0,0}, // S_POISONCLOUD2
+{SPR_PSBG,3,2,A_PoisonBagDamage,S_POISONCLOUD4,0,0}, // S_POISONCLOUD3
+{SPR_PSBG,4,2,A_PoisonBagDamage,S_POISONCLOUD5,0,0}, // S_POISONCLOUD4
+{SPR_PSBG,4,2,A_PoisonBagDamage,S_POISONCLOUD6,0,0}, // S_POISONCLOUD5
+{SPR_PSBG,4,2,A_PoisonBagDamage,S_POISONCLOUD7,0,0}, // S_POISONCLOUD6
+{SPR_PSBG,5,2,A_PoisonBagDamage,S_POISONCLOUD8,0,0}, // S_POISONCLOUD7
+{SPR_PSBG,5,2,A_PoisonBagDamage,S_POISONCLOUD9,0,0}, // S_POISONCLOUD8
+{SPR_PSBG,5,2,A_PoisonBagDamage,S_POISONCLOUD10,0,0}, // S_POISONCLOUD9
+{SPR_PSBG,6,2,A_PoisonBagDamage,S_POISONCLOUD11,0,0}, // S_POISONCLOUD10
+{SPR_PSBG,6,2,A_PoisonBagDamage,S_POISONCLOUD12,0,0}, // S_POISONCLOUD11
+{SPR_PSBG,6,2,A_PoisonBagDamage,S_POISONCLOUD13,0,0}, // S_POISONCLOUD12
+{SPR_PSBG,7,2,A_PoisonBagDamage,S_POISONCLOUD14,0,0}, // S_POISONCLOUD13
+{SPR_PSBG,7,2,A_PoisonBagDamage,S_POISONCLOUD15,0,0}, // S_POISONCLOUD14
+{SPR_PSBG,7,2,A_PoisonBagDamage,S_POISONCLOUD16,0,0}, // S_POISONCLOUD15
+{SPR_PSBG,8,2,A_PoisonBagDamage,S_POISONCLOUD17,0,0}, // S_POISONCLOUD16
+{SPR_PSBG,8,1,A_PoisonBagDamage,S_POISONCLOUD18,0,0}, // S_POISONCLOUD17
+{SPR_PSBG,8,1,A_PoisonBagCheck,S_POISONCLOUD4,0,0}, // S_POISONCLOUD18
+{SPR_PSBG,7,7,NULL,S_POISONCLOUD_X2,0,0}, // S_POISONCLOUD_X1
+{SPR_PSBG,6,7,NULL,S_POISONCLOUD_X3,0,0}, // S_POISONCLOUD_X2
+{SPR_PSBG,5,6,NULL,S_POISONCLOUD_X4,0,0}, // S_POISONCLOUD_X3
+{SPR_PSBG,3,6,NULL,S_NULL,0,0}, // S_POISONCLOUD_X4
+{SPR_THRW,0,4,A_CheckThrowBomb,S_THROWINGBOMB2,0,0}, // S_THROWINGBOMB1
+{SPR_THRW,1,3,A_CheckThrowBomb,S_THROWINGBOMB3,0,0}, // S_THROWINGBOMB2
+{SPR_THRW,2,3,A_CheckThrowBomb,S_THROWINGBOMB4,0,0}, // S_THROWINGBOMB3
+{SPR_THRW,3,3,A_CheckThrowBomb,S_THROWINGBOMB5,0,0}, // S_THROWINGBOMB4
+{SPR_THRW,4,3,A_CheckThrowBomb,S_THROWINGBOMB6,0,0}, // S_THROWINGBOMB5
+{SPR_THRW,5,3,A_CheckThrowBomb,S_THROWINGBOMB1,0,0}, // S_THROWINGBOMB6
+{SPR_THRW,6,6,A_CheckThrowBomb,S_THROWINGBOMB8,0,0}, // S_THROWINGBOMB7
+{SPR_THRW,5,4,A_CheckThrowBomb,S_THROWINGBOMB9,0,0}, // S_THROWINGBOMB8
+{SPR_THRW,7,6,A_CheckThrowBomb,S_THROWINGBOMB10,0,0}, // S_THROWINGBOMB9
+{SPR_THRW,5,4,A_CheckThrowBomb,S_THROWINGBOMB11,0,0}, // S_THROWINGBOMB10
+{SPR_THRW,6,6,A_CheckThrowBomb,S_THROWINGBOMB12,0,0}, // S_THROWINGBOMB11
+{SPR_THRW,5,3,A_CheckThrowBomb,S_THROWINGBOMB12,0,0}, // S_THROWINGBOMB12
+{SPR_CFCF,32784,4,A_NoGravity,S_THROWINGBOMB_X2,0,0}, // S_THROWINGBOMB_X1
+{SPR_CFCF,32785,3,A_Scream,S_THROWINGBOMB_X3,0,0}, // S_THROWINGBOMB_X2
+{SPR_CFCF,32786,4,A_Explode,S_THROWINGBOMB_X4,0,0}, // S_THROWINGBOMB_X3
+{SPR_CFCF,32787,3,NULL,S_THROWINGBOMB_X5,0,0}, // S_THROWINGBOMB_X4
+{SPR_CFCF,32788,4,NULL,S_THROWINGBOMB_X6,0,0}, // S_THROWINGBOMB_X5
+{SPR_CFCF,32790,3,NULL,S_THROWINGBOMB_X7,0,0}, // S_THROWINGBOMB_X6
+{SPR_CFCF,32791,4,NULL,S_THROWINGBOMB_X8,0,0}, // S_THROWINGBOMB_X7
+{SPR_CFCF,32793,3,NULL,S_NULL,0,0}, // S_THROWINGBOMB_X8
+{SPR_SPED,32768,3,NULL,S_ARTI_BOOTS2,0,0}, // S_ARTI_BOOTS1
+{SPR_SPED,32769,3,NULL,S_ARTI_BOOTS3,0,0}, // S_ARTI_BOOTS2
+{SPR_SPED,32770,3,NULL,S_ARTI_BOOTS4,0,0}, // S_ARTI_BOOTS3
+{SPR_SPED,32771,3,NULL,S_ARTI_BOOTS5,0,0}, // S_ARTI_BOOTS4
+{SPR_SPED,32772,3,NULL,S_ARTI_BOOTS6,0,0}, // S_ARTI_BOOTS5
+{SPR_SPED,32773,3,NULL,S_ARTI_BOOTS7,0,0}, // S_ARTI_BOOTS6
+{SPR_SPED,32774,3,NULL,S_ARTI_BOOTS8,0,0}, // S_ARTI_BOOTS7
+{SPR_SPED,32775,3,NULL,S_ARTI_BOOTS1,0,0}, // S_ARTI_BOOTS8
+{SPR_BMAN,32768,-1,NULL,S_NULL,0,0}, // S_ARTI_MANA
+{SPR_BRAC,32768,4,NULL,S_ARTI_ARMOR2,0,0}, // S_ARTI_ARMOR1
+{SPR_BRAC,32769,4,NULL,S_ARTI_ARMOR3,0,0}, // S_ARTI_ARMOR2
+{SPR_BRAC,32770,4,NULL,S_ARTI_ARMOR4,0,0}, // S_ARTI_ARMOR3
+{SPR_BRAC,32771,4,NULL,S_ARTI_ARMOR5,0,0}, // S_ARTI_ARMOR4
+{SPR_BRAC,32772,4,NULL,S_ARTI_ARMOR6,0,0}, // S_ARTI_ARMOR5
+{SPR_BRAC,32773,4,NULL,S_ARTI_ARMOR7,0,0}, // S_ARTI_ARMOR6
+{SPR_BRAC,32774,4,NULL,S_ARTI_ARMOR8,0,0}, // S_ARTI_ARMOR7
+{SPR_BRAC,32775,4,NULL,S_ARTI_ARMOR1,0,0}, // S_ARTI_ARMOR8
+{SPR_BLST,32768,4,NULL,S_ARTI_BLAST2,0,0}, // S_ARTI_BLAST1
+{SPR_BLST,32769,4,NULL,S_ARTI_BLAST3,0,0}, // S_ARTI_BLAST2
+{SPR_BLST,32770,4,NULL,S_ARTI_BLAST4,0,0}, // S_ARTI_BLAST3
+{SPR_BLST,32771,4,NULL,S_ARTI_BLAST5,0,0}, // S_ARTI_BLAST4
+{SPR_BLST,32772,4,NULL,S_ARTI_BLAST6,0,0}, // S_ARTI_BLAST5
+{SPR_BLST,32773,4,NULL,S_ARTI_BLAST7,0,0}, // S_ARTI_BLAST6
+{SPR_BLST,32774,4,NULL,S_ARTI_BLAST8,0,0}, // S_ARTI_BLAST7
+{SPR_BLST,32775,4,NULL,S_ARTI_BLAST1,0,0}, // S_ARTI_BLAST8
+{SPR_HRAD,32768,4,NULL,S_ARTI_HEALRAD2,0,0}, // S_ARTI_HEALRAD1
+{SPR_HRAD,32769,4,NULL,S_ARTI_HEALRAD3,0,0}, // S_ARTI_HEALRAD2
+{SPR_HRAD,32770,4,NULL,S_ARTI_HEALRAD4,0,0}, // S_ARTI_HEALRAD3
+{SPR_HRAD,32771,4,NULL,S_ARTI_HEALRAD5,0,0}, // S_ARTI_HEALRAD4
+{SPR_HRAD,32772,4,NULL,S_ARTI_HEALRAD6,0,0}, // S_ARTI_HEALRAD5
+{SPR_HRAD,32773,4,NULL,S_ARTI_HEALRAD7,0,0}, // S_ARTI_HEALRAD6
+{SPR_HRAD,32774,4,NULL,S_ARTI_HEALRAD8,0,0}, // S_ARTI_HEALRAD7
+{SPR_HRAD,32775,4,NULL,S_ARTI_HEALRAD9,0,0}, // S_ARTI_HEALRAD8
+{SPR_HRAD,32776,4,NULL,S_ARTI_HEALRAD0,0,0}, // S_ARTI_HEALRAD9
+{SPR_HRAD,32777,4,NULL,S_ARTI_HEALRADA,0,0}, // S_ARTI_HEALRAD0
+{SPR_HRAD,32778,4,NULL,S_ARTI_HEALRADB,0,0}, // S_ARTI_HEALRADA
+{SPR_HRAD,32779,4,NULL,S_ARTI_HEALRADC,0,0}, // S_ARTI_HEALRADB
+{SPR_HRAD,32780,4,NULL,S_ARTI_HEALRADD,0,0}, // S_ARTI_HEALRADC
+{SPR_HRAD,32781,4,NULL,S_ARTI_HEALRADE,0,0}, // S_ARTI_HEALRADD
+{SPR_HRAD,32782,4,NULL,S_ARTI_HEALRADF,0,0}, // S_ARTI_HEALRADE
+{SPR_HRAD,32783,4,NULL,S_ARTI_HEALRAD1,0,0}, // S_ARTI_HEALRADF
+{SPR_SPSH,0,8,NULL,S_SPLASH2,0,0}, // S_SPLASH1
+{SPR_SPSH,1,8,NULL,S_SPLASH3,0,0}, // S_SPLASH2
+{SPR_SPSH,2,8,NULL,S_SPLASH4,0,0}, // S_SPLASH3
+{SPR_SPSH,3,16,NULL,S_NULL,0,0}, // S_SPLASH4
+{SPR_SPSH,3,10,NULL,S_NULL,0,0}, // S_SPLASHX
+{SPR_SPSH,4,5,NULL,S_SPLASHBASE2,0,0}, // S_SPLASHBASE1
+{SPR_SPSH,5,5,NULL,S_SPLASHBASE3,0,0}, // S_SPLASHBASE2
+{SPR_SPSH,6,5,NULL,S_SPLASHBASE4,0,0}, // S_SPLASHBASE3
+{SPR_SPSH,7,5,NULL,S_SPLASHBASE5,0,0}, // S_SPLASHBASE4
+{SPR_SPSH,8,5,NULL,S_SPLASHBASE6,0,0}, // S_SPLASHBASE5
+{SPR_SPSH,9,5,NULL,S_SPLASHBASE7,0,0}, // S_SPLASHBASE6
+{SPR_SPSH,10,5,NULL,S_NULL,0,0}, // S_SPLASHBASE7
+{SPR_LVAS,32768,5,NULL,S_LAVASPLASH2,0,0}, // S_LAVASPLASH1
+{SPR_LVAS,32769,5,NULL,S_LAVASPLASH3,0,0}, // S_LAVASPLASH2
+{SPR_LVAS,32770,5,NULL,S_LAVASPLASH4,0,0}, // S_LAVASPLASH3
+{SPR_LVAS,32771,5,NULL,S_LAVASPLASH5,0,0}, // S_LAVASPLASH4
+{SPR_LVAS,32772,5,NULL,S_LAVASPLASH6,0,0}, // S_LAVASPLASH5
+{SPR_LVAS,32773,5,NULL,S_NULL,0,0}, // S_LAVASPLASH6
+{SPR_LVAS,32774,5,NULL,S_LAVASMOKE2,0,0}, // S_LAVASMOKE1
+{SPR_LVAS,32775,5,NULL,S_LAVASMOKE3,0,0}, // S_LAVASMOKE2
+{SPR_LVAS,32776,5,NULL,S_LAVASMOKE4,0,0}, // S_LAVASMOKE3
+{SPR_LVAS,32777,5,NULL,S_LAVASMOKE5,0,0}, // S_LAVASMOKE4
+{SPR_LVAS,32778,5,NULL,S_NULL,0,0}, // S_LAVASMOKE5
+{SPR_SLDG,0,8,NULL,S_SLUDGECHUNK2,0,0}, // S_SLUDGECHUNK1
+{SPR_SLDG,1,8,NULL,S_SLUDGECHUNK3,0,0}, // S_SLUDGECHUNK2
+{SPR_SLDG,2,8,NULL,S_SLUDGECHUNK4,0,0}, // S_SLUDGECHUNK3
+{SPR_SLDG,3,8,NULL,S_NULL,0,0}, // S_SLUDGECHUNK4
+{SPR_SLDG,3,6,NULL,S_NULL,0,0}, // S_SLUDGECHUNKX
+{SPR_SLDG,4,6,NULL,S_SLUDGESPLASH2,0,0}, // S_SLUDGESPLASH1
+{SPR_SLDG,5,6,NULL,S_SLUDGESPLASH3,0,0}, // S_SLUDGESPLASH2
+{SPR_SLDG,6,6,NULL,S_SLUDGESPLASH4,0,0}, // S_SLUDGESPLASH3
+{SPR_SLDG,7,6,NULL,S_NULL,0,0}, // S_SLUDGESPLASH4
+{SPR_STTW,0,-1,NULL,S_NULL,0,0}, // S_ZWINGEDSTATUE1
+{SPR_RCK1,0,-1,NULL,S_NULL,0,0}, // S_ZROCK1_1
+{SPR_RCK2,0,-1,NULL,S_NULL,0,0}, // S_ZROCK2_1
+{SPR_RCK3,0,-1,NULL,S_NULL,0,0}, // S_ZROCK3_1
+{SPR_RCK4,0,-1,NULL,S_NULL,0,0}, // S_ZROCK4_1
+{SPR_CDLR,0,4,NULL,S_ZCHANDELIER2,0,0}, // S_ZCHANDELIER1
+{SPR_CDLR,1,4,NULL,S_ZCHANDELIER3,0,0}, // S_ZCHANDELIER2
+{SPR_CDLR,2,4,NULL,S_ZCHANDELIER1,0,0}, // S_ZCHANDELIER3
+{SPR_CDLR,3,-1,NULL,S_NULL,0,0}, // S_ZCHANDELIER_U
+{SPR_TRE1,0,-1,NULL,S_NULL,0,0}, // S_ZTREEDEAD1
+{SPR_TRE1,0,-1,NULL,S_NULL,0,0}, // S_ZTREE
+{SPR_TRDT,0,-1,NULL,S_NULL,0,0}, // S_ZTREEDESTRUCTIBLE1
+{SPR_TRDT,1,5,NULL,S_ZTREEDES_D2,0,0}, // S_ZTREEDES_D1
+{SPR_TRDT,2,5,A_Scream,S_ZTREEDES_D3,0,0}, // S_ZTREEDES_D2
+{SPR_TRDT,3,5,NULL,S_ZTREEDES_D4,0,0}, // S_ZTREEDES_D3
+{SPR_TRDT,4,5,NULL,S_ZTREEDES_D5,0,0}, // S_ZTREEDES_D4
+{SPR_TRDT,5,5,NULL,S_ZTREEDES_D6,0,0}, // S_ZTREEDES_D5
+{SPR_TRDT,6,-1,NULL,S_NULL,0,0}, // S_ZTREEDES_D6
+{SPR_TRDT,32775,5,NULL,S_ZTREEDES_X2,0,0}, // S_ZTREEDES_X1
+{SPR_TRDT,32776,5,NULL,S_ZTREEDES_X3,0,0}, // S_ZTREEDES_X2
+{SPR_TRDT,32777,5,NULL,S_ZTREEDES_X4,0,0}, // S_ZTREEDES_X3
+{SPR_TRDT,32778,5,NULL,S_ZTREEDES_X5,0,0}, // S_ZTREEDES_X4
+{SPR_TRDT,32779,5,NULL,S_ZTREEDES_X6,0,0}, // S_ZTREEDES_X5
+{SPR_TRDT,32780,5,A_Explode,S_ZTREEDES_X7,0,0}, // S_ZTREEDES_X6
+{SPR_TRDT,32781,5,NULL,S_ZTREEDES_X8,0,0}, // S_ZTREEDES_X7
+{SPR_TRDT,14,5,NULL,S_ZTREEDES_X9,0,0}, // S_ZTREEDES_X8
+{SPR_TRDT,15,5,NULL,S_ZTREEDES_X10,0,0}, // S_ZTREEDES_X9
+{SPR_TRDT,16,-1,NULL,S_NULL,0,0}, // S_ZTREEDES_X10
+{SPR_TRE2,0,-1,NULL,S_NULL,0,0}, // S_ZTREESWAMP182_1
+{SPR_TRE3,0,-1,NULL,S_NULL,0,0}, // S_ZTREESWAMP172_1
+{SPR_STM1,0,-1,NULL,S_NULL,0,0}, // S_ZSTUMPBURNED1
+{SPR_STM2,0,-1,NULL,S_NULL,0,0}, // S_ZSTUMPBARE1
+{SPR_STM3,0,-1,NULL,S_NULL,0,0}, // S_ZSTUMPSWAMP1_1
+{SPR_STM4,0,-1,NULL,S_NULL,0,0}, // S_ZSTUMPSWAMP2_1
+{SPR_MSH1,0,-1,NULL,S_NULL,0,0}, // S_ZSHROOMLARGE1_1
+{SPR_MSH2,0,-1,NULL,S_NULL,0,0}, // S_ZSHROOMLARGE2_1
+{SPR_MSH3,0,-1,NULL,S_NULL,0,0}, // S_ZSHROOMLARGE3_1
+{SPR_MSH4,0,-1,NULL,S_NULL,0,0}, // S_ZSHROOMSMALL1_1
+{SPR_MSH5,0,-1,NULL,S_NULL,0,0}, // S_ZSHROOMSMALL2_1
+{SPR_MSH6,0,-1,NULL,S_NULL,0,0}, // S_ZSHROOMSMALL3_1
+{SPR_MSH7,0,-1,NULL,S_NULL,0,0}, // S_ZSHROOMSMALL4_1
+{SPR_MSH8,0,-1,NULL,S_NULL,0,0}, // S_ZSHROOMSMALL5_1
+{SPR_SGMP,0,-1,NULL,S_NULL,0,0}, // S_ZSTALAGMITEPILLAR1
+{SPR_SGM1,0,-1,NULL,S_NULL,0,0}, // S_ZSTALAGMITELARGE1
+{SPR_SGM2,0,-1,NULL,S_NULL,0,0}, // S_ZSTALAGMITEMEDIUM1
+{SPR_SGM3,0,-1,NULL,S_NULL,0,0}, // S_ZSTALAGMITESMALL1
+{SPR_SLC1,0,-1,NULL,S_NULL,0,0}, // S_ZSTALACTITELARGE1
+{SPR_SLC2,0,-1,NULL,S_NULL,0,0}, // S_ZSTALACTITEMEDIUM1
+{SPR_SLC3,0,-1,NULL,S_NULL,0,0}, // S_ZSTALACTITESMALL1
+{SPR_MSS1,0,-1,NULL,S_NULL,0,0}, // S_ZMOSSCEILING1_1
+{SPR_MSS2,0,-1,NULL,S_NULL,0,0}, // S_ZMOSSCEILING2_1
+{SPR_SWMV,0,-1,NULL,S_NULL,0,0}, // S_ZSWAMPVINE1
+{SPR_CPS1,0,-1,NULL,S_NULL,0,0}, // S_ZCORPSEKABOB1
+{SPR_CPS2,0,-1,NULL,S_NULL,0,0}, // S_ZCORPSESLEEPING1
+{SPR_TMS1,0,-1,NULL,S_NULL,0,0}, // S_ZTOMBSTONERIP1
+{SPR_TMS2,0,-1,NULL,S_NULL,0,0}, // S_ZTOMBSTONESHANE1
+{SPR_TMS3,0,-1,NULL,S_NULL,0,0}, // S_ZTOMBSTONEBIGCROSS1
+{SPR_TMS4,0,-1,NULL,S_NULL,0,0}, // S_ZTOMBSTONEBRIANR1
+{SPR_TMS5,0,-1,NULL,S_NULL,0,0}, // S_ZTOMBSTONECROSSCIRCLE1
+{SPR_TMS6,0,-1,NULL,S_NULL,0,0}, // S_ZTOMBSTONESMALLCROSS1
+{SPR_TMS7,0,-1,NULL,S_NULL,0,0}, // S_ZTOMBSTONEBRIANP1
+{SPR_CPS3,0,-1,NULL,S_NULL,0,0}, // S_CORPSEHANGING_1
+{SPR_STT2,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLEGREENTALL_1
+{SPR_STT3,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLEBLUETALL_1
+{SPR_STT4,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLEGREENSHORT_1
+{SPR_STT5,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLEBLUESHORT_1
+{SPR_GAR1,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLESTRIPETALL_1
+{SPR_GAR2,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLEDARKREDTALL_1
+{SPR_GAR3,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLEREDTALL_1
+{SPR_GAR4,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLETANTALL_1
+{SPR_GAR5,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLERUSTTALL_1
+{SPR_GAR6,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLEDARKREDSHORT_1
+{SPR_GAR7,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLEREDSHORT_1
+{SPR_GAR8,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLETANSHORT_1
+{SPR_GAR9,0,-1,NULL,S_NULL,0,0}, // S_ZSTATUEGARGOYLERUSTSHORT_1
+{SPR_BNR1,0,-1,NULL,S_NULL,0,0}, // S_ZBANNERTATTERED_1
+{SPR_TRE4,0,-1,NULL,S_NULL,0,0}, // S_ZTREELARGE1
+{SPR_TRE5,0,-1,NULL,S_NULL,0,0}, // S_ZTREELARGE2
+{SPR_TRE6,0,-1,NULL,S_NULL,0,0}, // S_ZTREEGNARLED1
+{SPR_TRE7,0,-1,NULL,S_NULL,0,0}, // S_ZTREEGNARLED2
+{SPR_LOGG,0,-1,NULL,S_NULL,0,0}, // S_ZLOG
+{SPR_ICT1,0,-1,NULL,S_NULL,0,0}, // S_ZSTALACTITEICELARGE
+{SPR_ICT2,0,-1,NULL,S_NULL,0,0}, // S_ZSTALACTITEICEMEDIUM
+{SPR_ICT3,0,-1,NULL,S_NULL,0,0}, // S_ZSTALACTITEICESMALL
+{SPR_ICT4,0,-1,NULL,S_NULL,0,0}, // S_ZSTALACTITEICETINY
+{SPR_ICM1,0,-1,NULL,S_NULL,0,0}, // S_ZSTALAGMITEICELARGE
+{SPR_ICM2,0,-1,NULL,S_NULL,0,0}, // S_ZSTALAGMITEICEMEDIUM
+{SPR_ICM3,0,-1,NULL,S_NULL,0,0}, // S_ZSTALAGMITEICESMALL
+{SPR_ICM4,0,-1,NULL,S_NULL,0,0}, // S_ZSTALAGMITEICETINY
+{SPR_RKBL,0,-1,NULL,S_NULL,0,0}, // S_ZROCKBROWN1
+{SPR_RKBS,0,-1,NULL,S_NULL,0,0}, // S_ZROCKBROWN2
+{SPR_RKBK,0,-1,NULL,S_NULL,0,0}, // S_ZROCKBLACK
+{SPR_RBL1,0,-1,NULL,S_NULL,0,0}, // S_ZRUBBLE1
+{SPR_RBL2,0,-1,NULL,S_NULL,0,0}, // S_ZRUBBLE2
+{SPR_RBL3,0,-1,NULL,S_NULL,0,0}, // S_ZRUBBLE3
+{SPR_VASE,0,-1,NULL,S_NULL,0,0}, // S_ZVASEPILLAR
+{SPR_POT1,0,-1,NULL,S_NULL,0,0}, // S_ZPOTTERY1
+{SPR_POT2,0,-1,NULL,S_NULL,0,0}, // S_ZPOTTERY2
+{SPR_POT3,0,-1,NULL,S_NULL,0,0}, // S_ZPOTTERY3
+{SPR_POT1,0,0,A_PotteryExplode,S_NULL,0,0}, // S_ZPOTTERY_EXPLODE
+{SPR_PBIT,0,-1,NULL,S_NULL,0,0}, // S_POTTERYBIT_1
+{SPR_PBIT,1,-1,NULL,S_NULL,0,0}, // S_POTTERYBIT_2
+{SPR_PBIT,2,-1,NULL,S_NULL,0,0}, // S_POTTERYBIT_3
+{SPR_PBIT,3,-1,NULL,S_NULL,0,0}, // S_POTTERYBIT_4
+{SPR_PBIT,4,-1,NULL,S_NULL,0,0}, // S_POTTERYBIT_5
+{SPR_PBIT,5,0,A_PotteryChooseBit,S_NULL,0,0}, // S_POTTERYBIT_EX0
+{SPR_PBIT,5,140,NULL,S_POTTERYBIT_EX1_2,0,0}, // S_POTTERYBIT_EX1
+{SPR_PBIT,5,1,A_PotteryCheck,S_NULL,0,0}, // S_POTTERYBIT_EX1_2
+{SPR_PBIT,6,140,NULL,S_POTTERYBIT_EX2_2,0,0}, // S_POTTERYBIT_EX2
+{SPR_PBIT,6,1,A_PotteryCheck,S_NULL,0,0}, // S_POTTERYBIT_EX2_2
+{SPR_PBIT,7,140,NULL,S_POTTERYBIT_EX3_2,0,0}, // S_POTTERYBIT_EX3
+{SPR_PBIT,7,1,A_PotteryCheck,S_NULL,0,0}, // S_POTTERYBIT_EX3_2
+{SPR_PBIT,8,140,NULL,S_POTTERYBIT_EX4_2,0,0}, // S_POTTERYBIT_EX4
+{SPR_PBIT,8,1,A_PotteryCheck,S_NULL,0,0}, // S_POTTERYBIT_EX4_2
+{SPR_PBIT,9,140,NULL,S_POTTERYBIT_EX5_2,0,0}, // S_POTTERYBIT_EX5
+{SPR_PBIT,9,1,A_PotteryCheck,S_NULL,0,0}, // S_POTTERYBIT_EX5_2
+{SPR_CPS4,0,-1,NULL,S_NULL,0,0}, // S_ZCORPSELYNCHED1
+{SPR_CPS5,0,140,A_CorpseBloodDrip,S_ZCORPSELYNCHED2,0,0}, // S_ZCORPSELYNCHED2
+{SPR_CPS6,0,-1,NULL,S_NULL,0,0}, // S_ZCORPSESITTING
+{SPR_CPS6,0,1,A_CorpseExplode,S_NULL,0,0}, // S_ZCORPSESITTING_X
+{SPR_CPB1,0,-1,NULL,S_NULL,0,0}, // S_CORPSEBIT_1
+{SPR_CPB2,0,-1,NULL,S_NULL,0,0}, // S_CORPSEBIT_2
+{SPR_CPB3,0,-1,NULL,S_NULL,0,0}, // S_CORPSEBIT_3
+{SPR_CPB4,0,-1,NULL,S_NULL,0,0}, // S_CORPSEBIT_4
+{SPR_BDRP,0,-1,NULL,S_NULL,0,0}, // S_CORPSEBLOODDRIP
+{SPR_BDSH,0,3,NULL,S_CORPSEBLOODDRIP_X2,0,0}, // S_CORPSEBLOODDRIP_X1
+{SPR_BDSH,1,3,NULL,S_CORPSEBLOODDRIP_X3,0,0}, // S_CORPSEBLOODDRIP_X2
+{SPR_BDSH,2,2,NULL,S_CORPSEBLOODDRIP_X4,0,0}, // S_CORPSEBLOODDRIP_X3
+{SPR_BDSH,3,2,NULL,S_NULL,0,0}, // S_CORPSEBLOODDRIP_X4
+{SPR_BDPL,0,-1,NULL,S_NULL,0,0}, // S_BLOODPOOL
+{SPR_CNDL,32768,4,NULL,S_ZCANDLE2,0,0}, // S_ZCANDLE1
+{SPR_CNDL,32769,4,NULL,S_ZCANDLE3,0,0}, // S_ZCANDLE2
+{SPR_CNDL,32770,4,NULL,S_ZCANDLE1,0,0}, // S_ZCANDLE3
+{SPR_MAN1,0,20,A_LeafSpawn,S_ZLEAFSPAWNER,0,0}, // S_ZLEAFSPAWNER
+{SPR_LEF1,0,4,NULL,S_LEAF1_2,0,0}, // S_LEAF1_1
+{SPR_LEF1,1,4,NULL,S_LEAF1_3,0,0}, // S_LEAF1_2
+{SPR_LEF1,2,4,NULL,S_LEAF1_4,0,0}, // S_LEAF1_3
+{SPR_LEF1,3,4,A_LeafThrust,S_LEAF1_5,0,0}, // S_LEAF1_4
+{SPR_LEF1,4,4,NULL,S_LEAF1_6,0,0}, // S_LEAF1_5
+{SPR_LEF1,5,4,NULL,S_LEAF1_7,0,0}, // S_LEAF1_6
+{SPR_LEF1,6,4,NULL,S_LEAF1_8,0,0}, // S_LEAF1_7
+{SPR_LEF1,7,4,A_LeafThrust,S_LEAF1_9,0,0}, // S_LEAF1_8
+{SPR_LEF1,8,4,NULL,S_LEAF1_10,0,0}, // S_LEAF1_9
+{SPR_LEF1,0,4,NULL,S_LEAF1_11,0,0}, // S_LEAF1_10
+{SPR_LEF1,1,4,NULL,S_LEAF1_12,0,0}, // S_LEAF1_11
+{SPR_LEF1,2,4,A_LeafThrust,S_LEAF1_13,0,0}, // S_LEAF1_12
+{SPR_LEF1,3,4,NULL,S_LEAF1_14,0,0}, // S_LEAF1_13
+{SPR_LEF1,4,4,NULL,S_LEAF1_15,0,0}, // S_LEAF1_14
+{SPR_LEF1,5,4,NULL,S_LEAF1_16,0,0}, // S_LEAF1_15
+{SPR_LEF1,6,4,A_LeafThrust,S_LEAF1_17,0,0}, // S_LEAF1_16
+{SPR_LEF1,7,4,NULL,S_LEAF1_18,0,0}, // S_LEAF1_17
+{SPR_LEF1,8,4,NULL,S_NULL,0,0}, // S_LEAF1_18
+{SPR_LEF3,3,10,A_LeafCheck,S_LEAF_X1,0,0}, // S_LEAF_X1
+{SPR_LEF2,0,4,NULL,S_LEAF2_2,0,0}, // S_LEAF2_1
+{SPR_LEF2,1,4,NULL,S_LEAF2_3,0,0}, // S_LEAF2_2
+{SPR_LEF2,2,4,NULL,S_LEAF2_4,0,0}, // S_LEAF2_3
+{SPR_LEF2,3,4,A_LeafThrust,S_LEAF2_5,0,0}, // S_LEAF2_4
+{SPR_LEF2,4,4,NULL,S_LEAF2_6,0,0}, // S_LEAF2_5
+{SPR_LEF2,5,4,NULL,S_LEAF2_7,0,0}, // S_LEAF2_6
+{SPR_LEF2,6,4,NULL,S_LEAF2_8,0,0}, // S_LEAF2_7
+{SPR_LEF2,7,4,A_LeafThrust,S_LEAF2_9,0,0}, // S_LEAF2_8
+{SPR_LEF2,8,4,NULL,S_LEAF2_10,0,0}, // S_LEAF2_9
+{SPR_LEF2,0,4,NULL,S_LEAF2_11,0,0}, // S_LEAF2_10
+{SPR_LEF2,1,4,NULL,S_LEAF2_12,0,0}, // S_LEAF2_11
+{SPR_LEF2,2,4,A_LeafThrust,S_LEAF2_13,0,0}, // S_LEAF2_12
+{SPR_LEF2,3,4,NULL,S_LEAF2_14,0,0}, // S_LEAF2_13
+{SPR_LEF2,4,4,NULL,S_LEAF2_15,0,0}, // S_LEAF2_14
+{SPR_LEF2,5,4,NULL,S_LEAF2_16,0,0}, // S_LEAF2_15
+{SPR_LEF2,6,4,A_LeafThrust,S_LEAF2_17,0,0}, // S_LEAF2_16
+{SPR_LEF2,7,4,NULL,S_LEAF2_18,0,0}, // S_LEAF2_17
+{SPR_LEF2,8,4,NULL,S_NULL,0,0}, // S_LEAF2_18
+{SPR_TWTR,32768,4,NULL,S_ZTWINEDTORCH_2,0,0}, // S_ZTWINEDTORCH_1
+{SPR_TWTR,32769,4,NULL,S_ZTWINEDTORCH_3,0,0}, // S_ZTWINEDTORCH_2
+{SPR_TWTR,32770,4,NULL,S_ZTWINEDTORCH_4,0,0}, // S_ZTWINEDTORCH_3
+{SPR_TWTR,32771,4,NULL,S_ZTWINEDTORCH_5,0,0}, // S_ZTWINEDTORCH_4
+{SPR_TWTR,32772,4,NULL,S_ZTWINEDTORCH_6,0,0}, // S_ZTWINEDTORCH_5
+{SPR_TWTR,32773,4,NULL,S_ZTWINEDTORCH_7,0,0}, // S_ZTWINEDTORCH_6
+{SPR_TWTR,32774,4,NULL,S_ZTWINEDTORCH_8,0,0}, // S_ZTWINEDTORCH_7
+{SPR_TWTR,32775,4,NULL,S_ZTWINEDTORCH_1,0,0}, // S_ZTWINEDTORCH_8
+{SPR_TWTR,8,-1,NULL,S_NULL,0,0}, // S_ZTWINEDTORCH_UNLIT
+{SPR_TLGL,0,2,NULL,S_BRIDGE2,0,0}, // S_BRIDGE1
+{SPR_TLGL,0,2,A_BridgeInit,S_BRIDGE3,0,0}, // S_BRIDGE2
+{SPR_TLGL,0,-1,NULL,S_NULL,0,0}, // S_BRIDGE3
+{SPR_TLGL,0,2,NULL,S_FREE_BRIDGE2,0,0}, // S_FREE_BRIDGE1
+{SPR_TLGL,0,300,NULL,S_NULL,0,0}, // S_FREE_BRIDGE2
+{SPR_TLGL,0,2,NULL,S_BBALL2,0,0}, // S_BBALL1
+{SPR_TLGL,0,5,A_BridgeOrbit,S_BBALL2,0,0}, // S_BBALL2
+{SPR_WLTR,32768,5,NULL,S_ZWALLTORCH2,0,0}, // S_ZWALLTORCH1
+{SPR_WLTR,32769,5,NULL,S_ZWALLTORCH3,0,0}, // S_ZWALLTORCH2
+{SPR_WLTR,32770,5,NULL,S_ZWALLTORCH4,0,0}, // S_ZWALLTORCH3
+{SPR_WLTR,32771,5,NULL,S_ZWALLTORCH5,0,0}, // S_ZWALLTORCH4
+{SPR_WLTR,32772,5,NULL,S_ZWALLTORCH6,0,0}, // S_ZWALLTORCH5
+{SPR_WLTR,32773,5,NULL,S_ZWALLTORCH7,0,0}, // S_ZWALLTORCH6
+{SPR_WLTR,32774,5,NULL,S_ZWALLTORCH8,0,0}, // S_ZWALLTORCH7
+{SPR_WLTR,32775,5,NULL,S_ZWALLTORCH1,0,0}, // S_ZWALLTORCH8
+{SPR_WLTR,8,-1,NULL,S_NULL,0,0}, // S_ZWALLTORCH_U
+{SPR_BARL,0,-1,NULL,S_NULL,0,0}, // S_ZBARREL1
+{SPR_SHB1,0,-1,NULL,S_NULL,0,0}, // S_ZSHRUB1
+{SPR_SHB1,0,1,A_TreeDeath,S_ZSHRUB1,0,0}, // S_ZSHRUB1_DIE
+{SPR_SHB1,32769,7,NULL,S_ZSHRUB1_X2,0,0}, // S_ZSHRUB1_X1
+{SPR_SHB1,32770,6,A_Scream,S_ZSHRUB1_X3,0,0}, // S_ZSHRUB1_X2
+{SPR_SHB1,32771,5,NULL,S_NULL,0,0}, // S_ZSHRUB1_X3
+{SPR_SHB2,0,-1,NULL,S_NULL,0,0}, // S_ZSHRUB2
+{SPR_SHB2,0,1,A_TreeDeath,S_ZSHRUB2,0,0}, // S_ZSHRUB2_DIE
+{SPR_SHB2,32769,7,NULL,S_ZSHRUB2_X2,0,0}, // S_ZSHRUB2_X1
+{SPR_SHB2,32770,6,A_Scream,S_ZSHRUB2_X3,0,0}, // S_ZSHRUB2_X2
+{SPR_SHB2,32771,5,A_Explode,S_ZSHRUB2_X4,0,0}, // S_ZSHRUB2_X3
+{SPR_SHB2,32772,5,NULL,S_NULL,0,0}, // S_ZSHRUB2_X4
+{SPR_BCKT,0,-1,NULL,S_NULL,0,0}, // S_ZBUCKET1
+{SPR_SHRM,0,5,A_PoisonShroom,S_ZPOISONSHROOM_P2,0,0}, // S_ZPOISONSHROOM1
+{SPR_SHRM,0,6,NULL,S_ZPOISONSHROOM_P2,0,0}, // S_ZPOISONSHROOM_P1
+{SPR_SHRM,1,8,A_Pain,S_ZPOISONSHROOM1,0,0}, // S_ZPOISONSHROOM_P2
+{SPR_SHRM,2,5,NULL,S_ZPOISONSHROOM_X2,0,0}, // S_ZPOISONSHROOM_X1
+{SPR_SHRM,3,5,NULL,S_ZPOISONSHROOM_X3,0,0}, // S_ZPOISONSHROOM_X2
+{SPR_SHRM,4,5,A_PoisonBagInit,S_ZPOISONSHROOM_X4,0,0}, // S_ZPOISONSHROOM_X3
+{SPR_SHRM,5,-1,NULL,S_NULL,0,0}, // S_ZPOISONSHROOM_X4
+{SPR_FBUL,32768,4,NULL,S_ZFIREBULL2,0,0}, // S_ZFIREBULL1
+{SPR_FBUL,32769,4,NULL,S_ZFIREBULL3,0,0}, // S_ZFIREBULL2
+{SPR_FBUL,32770,4,NULL,S_ZFIREBULL4,0,0}, // S_ZFIREBULL3
+{SPR_FBUL,32771,4,NULL,S_ZFIREBULL5,0,0}, // S_ZFIREBULL4
+{SPR_FBUL,32772,4,NULL,S_ZFIREBULL6,0,0}, // S_ZFIREBULL5
+{SPR_FBUL,32773,4,NULL,S_ZFIREBULL7,0,0}, // S_ZFIREBULL6
+{SPR_FBUL,32774,4,NULL,S_ZFIREBULL1,0,0}, // S_ZFIREBULL7
+{SPR_FBUL,32777,4,NULL,S_ZFIREBULL_DEATH2,0,0}, // S_ZFIREBULL_DEATH
+{SPR_FBUL,32776,4,NULL,S_ZFIREBULL_U,0,0}, // S_ZFIREBULL_DEATH2
+{SPR_FBUL,7,-1,NULL,S_NULL,0,0}, // S_ZFIREBULL_U
+{SPR_FBUL,32776,4,NULL,S_ZFIREBULL_BIRTH2,0,0}, // S_ZFIREBULL_BIRTH
+{SPR_FBUL,32777,4,NULL,S_ZFIREBULL1,0,0}, // S_ZFIREBULL_BIRTH2
+{SPR_FSKL,32768,4,NULL,S_ZFIRETHING2,0,0}, // S_ZFIRETHING1
+{SPR_FSKL,32769,3,NULL,S_ZFIRETHING3,0,0}, // S_ZFIRETHING2
+{SPR_FSKL,32770,4,NULL,S_ZFIRETHING4,0,0}, // S_ZFIRETHING3
+{SPR_FSKL,32771,3,NULL,S_ZFIRETHING5,0,0}, // S_ZFIRETHING4
+{SPR_FSKL,32772,4,NULL,S_ZFIRETHING6,0,0}, // S_ZFIRETHING5
+{SPR_FSKL,32773,3,NULL,S_ZFIRETHING7,0,0}, // S_ZFIRETHING6
+{SPR_FSKL,32774,4,NULL,S_ZFIRETHING8,0,0}, // S_ZFIRETHING7
+{SPR_FSKL,32775,3,NULL,S_ZFIRETHING9,0,0}, // S_ZFIRETHING8
+{SPR_FSKL,32776,4,NULL,S_ZFIRETHING1,0,0}, // S_ZFIRETHING9
+{SPR_BRTR,32768,4,NULL,S_ZBRASSTORCH2,0,0}, // S_ZBRASSTORCH1
+{SPR_BRTR,32769,4,NULL,S_ZBRASSTORCH3,0,0}, // S_ZBRASSTORCH2
+{SPR_BRTR,32770,4,NULL,S_ZBRASSTORCH4,0,0}, // S_ZBRASSTORCH3
+{SPR_BRTR,32771,4,NULL,S_ZBRASSTORCH5,0,0}, // S_ZBRASSTORCH4
+{SPR_BRTR,32772,4,NULL,S_ZBRASSTORCH6,0,0}, // S_ZBRASSTORCH5
+{SPR_BRTR,32773,4,NULL,S_ZBRASSTORCH7,0,0}, // S_ZBRASSTORCH6
+{SPR_BRTR,32774,4,NULL,S_ZBRASSTORCH8,0,0}, // S_ZBRASSTORCH7
+{SPR_BRTR,32775,4,NULL,S_ZBRASSTORCH9,0,0}, // S_ZBRASSTORCH8
+{SPR_BRTR,32776,4,NULL,S_ZBRASSTORCH10,0,0}, // S_ZBRASSTORCH9
+{SPR_BRTR,32777,4,NULL,S_ZBRASSTORCH11,0,0}, // S_ZBRASSTORCH10
+{SPR_BRTR,32778,4,NULL,S_ZBRASSTORCH12,0,0}, // S_ZBRASSTORCH11
+{SPR_BRTR,32779,4,NULL,S_ZBRASSTORCH13,0,0}, // S_ZBRASSTORCH12
+{SPR_BRTR,32780,4,NULL,S_ZBRASSTORCH1,0,0}, // S_ZBRASSTORCH13
+{SPR_SUIT,0,-1,NULL,S_NULL,0,0}, // S_ZSUITOFARMOR
+{SPR_SUIT,0,1,A_SoAExplode,S_NULL,0,0}, // S_ZSUITOFARMOR_X1
+{SPR_SUIT,1,-1,NULL,S_NULL,0,0}, // S_ZARMORCHUNK1
+{SPR_SUIT,2,-1,NULL,S_NULL,0,0}, // S_ZARMORCHUNK2
+{SPR_SUIT,3,-1,NULL,S_NULL,0,0}, // S_ZARMORCHUNK3
+{SPR_SUIT,4,-1,NULL,S_NULL,0,0}, // S_ZARMORCHUNK4
+{SPR_SUIT,5,-1,NULL,S_NULL,0,0}, // S_ZARMORCHUNK5
+{SPR_SUIT,6,-1,NULL,S_NULL,0,0}, // S_ZARMORCHUNK6
+{SPR_SUIT,7,-1,NULL,S_NULL,0,0}, // S_ZARMORCHUNK7
+{SPR_SUIT,8,-1,NULL,S_NULL,0,0}, // S_ZARMORCHUNK8
+{SPR_SUIT,9,-1,NULL,S_NULL,0,0}, // S_ZARMORCHUNK9
+{SPR_SUIT,10,-1,NULL,S_NULL,0,0}, // S_ZARMORCHUNK10
+{SPR_BBLL,5,-1,NULL,S_NULL,0,0}, // S_ZBELL
+{SPR_BBLL,0,4,A_BellReset1,S_ZBELL_X2,0,0}, // S_ZBELL_X1
+{SPR_BBLL,1,4,NULL,S_ZBELL_X3,0,0}, // S_ZBELL_X2
+{SPR_BBLL,2,4,NULL,S_ZBELL_X4,0,0}, // S_ZBELL_X3
+{SPR_BBLL,3,5,A_Scream,S_ZBELL_X5,0,0}, // S_ZBELL_X4
+{SPR_BBLL,2,4,NULL,S_ZBELL_X6,0,0}, // S_ZBELL_X5
+{SPR_BBLL,1,4,NULL,S_ZBELL_X7,0,0}, // S_ZBELL_X6
+{SPR_BBLL,0,3,NULL,S_ZBELL_X8,0,0}, // S_ZBELL_X7
+{SPR_BBLL,4,4,NULL,S_ZBELL_X9,0,0}, // S_ZBELL_X8
+{SPR_BBLL,5,5,NULL,S_ZBELL_X10,0,0}, // S_ZBELL_X9
+{SPR_BBLL,6,6,A_Scream,S_ZBELL_X11,0,0}, // S_ZBELL_X10
+{SPR_BBLL,5,5,NULL,S_ZBELL_X12,0,0}, // S_ZBELL_X11
+{SPR_BBLL,4,4,NULL,S_ZBELL_X13,0,0}, // S_ZBELL_X12
+{SPR_BBLL,0,4,NULL,S_ZBELL_X14,0,0}, // S_ZBELL_X13
+{SPR_BBLL,1,5,NULL,S_ZBELL_X15,0,0}, // S_ZBELL_X14
+{SPR_BBLL,2,5,NULL,S_ZBELL_X16,0,0}, // S_ZBELL_X15
+{SPR_BBLL,3,6,A_Scream,S_ZBELL_X17,0,0}, // S_ZBELL_X16
+{SPR_BBLL,2,5,NULL,S_ZBELL_X18,0,0}, // S_ZBELL_X17
+{SPR_BBLL,1,5,NULL,S_ZBELL_X19,0,0}, // S_ZBELL_X18
+{SPR_BBLL,0,4,NULL,S_ZBELL_X20,0,0}, // S_ZBELL_X19
+{SPR_BBLL,4,5,NULL,S_ZBELL_X21,0,0}, // S_ZBELL_X20
+{SPR_BBLL,5,5,NULL,S_ZBELL_X22,0,0}, // S_ZBELL_X21
+{SPR_BBLL,6,7,A_Scream,S_ZBELL_X23,0,0}, // S_ZBELL_X22
+{SPR_BBLL,5,5,NULL,S_ZBELL_X24,0,0}, // S_ZBELL_X23
+{SPR_BBLL,4,5,NULL,S_ZBELL_X25,0,0}, // S_ZBELL_X24
+{SPR_BBLL,0,5,NULL,S_ZBELL_X26,0,0}, // S_ZBELL_X25
+{SPR_BBLL,1,6,NULL,S_ZBELL_X27,0,0}, // S_ZBELL_X26
+{SPR_BBLL,2,6,NULL,S_ZBELL_X28,0,0}, // S_ZBELL_X27
+{SPR_BBLL,3,7,A_Scream,S_ZBELL_X29,0,0}, // S_ZBELL_X28
+{SPR_BBLL,2,6,NULL,S_ZBELL_X30,0,0}, // S_ZBELL_X29
+{SPR_BBLL,1,6,NULL,S_ZBELL_X31,0,0}, // S_ZBELL_X30
+{SPR_BBLL,0,5,NULL,S_ZBELL_X32,0,0}, // S_ZBELL_X31
+{SPR_BBLL,4,6,NULL,S_ZBELL_X33,0,0}, // S_ZBELL_X32
+{SPR_BBLL,5,6,NULL,S_ZBELL_X34,0,0}, // S_ZBELL_X33
+{SPR_BBLL,6,7,A_Scream,S_ZBELL_X35,0,0}, // S_ZBELL_X34
+{SPR_BBLL,5,6,NULL,S_ZBELL_X36,0,0}, // S_ZBELL_X35
+{SPR_BBLL,4,6,NULL,S_ZBELL_X37,0,0}, // S_ZBELL_X36
+{SPR_BBLL,0,6,NULL,S_ZBELL_X38,0,0}, // S_ZBELL_X37
+{SPR_BBLL,1,6,NULL,S_ZBELL_X39,0,0}, // S_ZBELL_X38
+{SPR_BBLL,2,6,NULL,S_ZBELL_X40,0,0}, // S_ZBELL_X39
+{SPR_BBLL,1,7,NULL,S_ZBELL_X41,0,0}, // S_ZBELL_X40
+{SPR_BBLL,0,8,NULL,S_ZBELL_X42,0,0}, // S_ZBELL_X41
+{SPR_BBLL,4,12,NULL,S_ZBELL_X43,0,0}, // S_ZBELL_X42
+{SPR_BBLL,0,10,NULL,S_ZBELL_X44,0,0}, // S_ZBELL_X43
+{SPR_BBLL,1,12,NULL,S_ZBELL_X45,0,0}, // S_ZBELL_X44
+{SPR_BBLL,0,12,NULL,S_ZBELL_X46,0,0}, // S_ZBELL_X45
+{SPR_BBLL,4,14,NULL,S_ZBELL_X47,0,0}, // S_ZBELL_X46
+{SPR_BBLL,0,1,A_BellReset2,S_ZBELL,0,0}, // S_ZBELL_X47
+{SPR_CAND,32768,5,NULL,S_ZBLUE_CANDLE2,0,0}, // S_ZBLUE_CANDLE1
+{SPR_CAND,32769,5,NULL,S_ZBLUE_CANDLE3,0,0}, // S_ZBLUE_CANDLE2
+{SPR_CAND,32770,5,NULL,S_ZBLUE_CANDLE4,0,0}, // S_ZBLUE_CANDLE3
+{SPR_CAND,32771,5,NULL,S_ZBLUE_CANDLE5,0,0}, // S_ZBLUE_CANDLE4
+{SPR_CAND,32772,5,NULL,S_ZBLUE_CANDLE1,0,0}, // S_ZBLUE_CANDLE5
+{SPR_IRON,0,-1,NULL,S_NULL,0,0}, // S_ZIRON_MAIDEN
+{SPR_XMAS,0,-1,NULL,S_NULL,0,0}, // S_ZXMAS_TREE
+{SPR_XMAS,0,4,A_TreeDeath,S_ZXMAS_TREE,0,0}, // S_ZXMAS_TREE_DIE
+{SPR_XMAS,32769,6,NULL,S_ZXMAS_TREE_X2,0,0}, // S_ZXMAS_TREE_X1
+{SPR_XMAS,32770,6,A_Scream,S_ZXMAS_TREE_X3,0,0}, // S_ZXMAS_TREE_X2
+{SPR_XMAS,32771,5,NULL,S_ZXMAS_TREE_X4,0,0}, // S_ZXMAS_TREE_X3
+{SPR_XMAS,32772,5,A_Explode,S_ZXMAS_TREE_X5,0,0}, // S_ZXMAS_TREE_X4
+{SPR_XMAS,32773,5,NULL,S_ZXMAS_TREE_X6,0,0}, // S_ZXMAS_TREE_X5
+{SPR_XMAS,32774,4,NULL,S_ZXMAS_TREE_X7,0,0}, // S_ZXMAS_TREE_X6
+{SPR_XMAS,7,5,NULL,S_ZXMAS_TREE_X8,0,0}, // S_ZXMAS_TREE_X7
+{SPR_XMAS,8,4,A_NoBlocking,S_ZXMAS_TREE_X9,0,0}, // S_ZXMAS_TREE_X8
+{SPR_XMAS,9,4,NULL,S_ZXMAS_TREE_X10,0,0}, // S_ZXMAS_TREE_X9
+{SPR_XMAS,10,-1,NULL,S_NULL,0,0}, // S_ZXMAS_TREE_X10
+{SPR_CDRN,32769,4,NULL,S_ZCAULDRON2,0,0}, // S_ZCAULDRON1
+{SPR_CDRN,32770,4,NULL,S_ZCAULDRON3,0,0}, // S_ZCAULDRON2
+{SPR_CDRN,32771,4,NULL,S_ZCAULDRON4,0,0}, // S_ZCAULDRON3
+{SPR_CDRN,32772,4,NULL,S_ZCAULDRON5,0,0}, // S_ZCAULDRON4
+{SPR_CDRN,32773,4,NULL,S_ZCAULDRON6,0,0}, // S_ZCAULDRON5
+{SPR_CDRN,32774,4,NULL,S_ZCAULDRON7,0,0}, // S_ZCAULDRON6
+{SPR_CDRN,32775,4,NULL,S_ZCAULDRON1,0,0}, // S_ZCAULDRON7
+{SPR_CDRN,0,-1,NULL,S_NULL,0,0}, // S_ZCAULDRON_U
+{SPR_CHNS,0,-1,NULL,S_NULL,0,0}, // S_ZCHAINBIT32
+{SPR_CHNS,1,-1,NULL,S_NULL,0,0}, // S_ZCHAINBIT64
+{SPR_CHNS,2,-1,NULL,S_NULL,0,0}, // S_ZCHAINEND_HEART
+{SPR_CHNS,3,-1,NULL,S_NULL,0,0}, // S_ZCHAINEND_HOOK1
+{SPR_CHNS,4,-1,NULL,S_NULL,0,0}, // S_ZCHAINEND_HOOK2
+{SPR_CHNS,5,-1,NULL,S_NULL,0,0}, // S_ZCHAINEND_SPIKE
+{SPR_CHNS,6,-1,NULL,S_NULL,0,0}, // S_ZCHAINEND_SKULL
+{SPR_TST1,0,-1,NULL,S_NULL,0,0}, // S_TABLE_SHIT1
+{SPR_TST2,0,-1,NULL,S_NULL,0,0}, // S_TABLE_SHIT2
+{SPR_TST3,0,-1,NULL,S_NULL,0,0}, // S_TABLE_SHIT3
+{SPR_TST4,0,-1,NULL,S_NULL,0,0}, // S_TABLE_SHIT4
+{SPR_TST5,0,-1,NULL,S_NULL,0,0}, // S_TABLE_SHIT5
+{SPR_TST6,0,-1,NULL,S_NULL,0,0}, // S_TABLE_SHIT6
+{SPR_TST7,0,-1,NULL,S_NULL,0,0}, // S_TABLE_SHIT7
+{SPR_TST8,0,-1,NULL,S_NULL,0,0}, // S_TABLE_SHIT8
+{SPR_TST9,0,-1,NULL,S_NULL,0,0}, // S_TABLE_SHIT9
+{SPR_TST0,0,-1,NULL,S_NULL,0,0}, // S_TABLE_SHIT10
+{SPR_TELE,32768,6,NULL,S_TFOG2,0,0}, // S_TFOG1
+{SPR_TELE,32769,6,NULL,S_TFOG3,0,0}, // S_TFOG2
+{SPR_TELE,32770,6,NULL,S_TFOG4,0,0}, // S_TFOG3
+{SPR_TELE,32771,6,NULL,S_TFOG5,0,0}, // S_TFOG4
+{SPR_TELE,32772,6,NULL,S_TFOG6,0,0}, // S_TFOG5
+{SPR_TELE,32773,6,NULL,S_TFOG7,0,0}, // S_TFOG6
+{SPR_TELE,32774,6,NULL,S_TFOG8,0,0}, // S_TFOG7
+{SPR_TELE,32775,6,NULL,S_TFOG9,0,0}, // S_TFOG8
+{SPR_TELE,32774,6,NULL,S_TFOG10,0,0}, // S_TFOG9
+{SPR_TELE,32773,6,NULL,S_TFOG11,0,0}, // S_TFOG10
+{SPR_TELE,32772,6,NULL,S_TFOG12,0,0}, // S_TFOG11
+{SPR_TELE,32771,6,NULL,S_TFOG13,0,0}, // S_TFOG12
+{SPR_TELE,32770,6,NULL,S_NULL,0,0}, // S_TFOG13
+{SPR_TSMK,0,4,NULL,S_TELESMOKE2,0,0}, // S_TELESMOKE1
+{SPR_TSMK,1,3,NULL,S_TELESMOKE3,0,0}, // S_TELESMOKE2
+{SPR_TSMK,2,4,NULL,S_TELESMOKE4,0,0}, // S_TELESMOKE3
+{SPR_TSMK,3,3,NULL,S_TELESMOKE5,0,0}, // S_TELESMOKE4
+{SPR_TSMK,4,4,NULL,S_TELESMOKE6,0,0}, // S_TELESMOKE5
+{SPR_TSMK,5,3,NULL,S_TELESMOKE7,0,0}, // S_TELESMOKE6
+{SPR_TSMK,6,4,NULL,S_TELESMOKE8,0,0}, // S_TELESMOKE7
+{SPR_TSMK,7,3,NULL,S_TELESMOKE9,0,0}, // S_TELESMOKE8
+{SPR_TSMK,8,4,NULL,S_TELESMOKE10,0,0}, // S_TELESMOKE9
+{SPR_TSMK,9,3,NULL,S_TELESMOKE11,0,0}, // S_TELESMOKE10
+{SPR_TSMK,10,4,NULL,S_TELESMOKE12,0,0}, // S_TELESMOKE11
+{SPR_TSMK,11,3,NULL,S_TELESMOKE13,0,0}, // S_TELESMOKE12
+{SPR_TSMK,12,4,NULL,S_TELESMOKE14,0,0}, // S_TELESMOKE13
+{SPR_TSMK,13,3,NULL,S_TELESMOKE15,0,0}, // S_TELESMOKE14
+{SPR_TSMK,14,4,NULL,S_TELESMOKE16,0,0}, // S_TELESMOKE15
+{SPR_TSMK,15,3,NULL,S_TELESMOKE17,0,0}, // S_TELESMOKE16
+{SPR_TSMK,16,4,NULL,S_TELESMOKE18,0,0}, // S_TELESMOKE17
+{SPR_TSMK,17,3,NULL,S_TELESMOKE19,0,0}, // S_TELESMOKE18
+{SPR_TSMK,18,4,NULL,S_TELESMOKE20,0,0}, // S_TELESMOKE19
+{SPR_TSMK,19,3,NULL,S_TELESMOKE21,0,0}, // S_TELESMOKE20
+{SPR_TSMK,20,4,NULL,S_TELESMOKE22,0,0}, // S_TELESMOKE21
+{SPR_TSMK,21,3,NULL,S_TELESMOKE23,0,0}, // S_TELESMOKE22
+{SPR_TSMK,22,4,NULL,S_TELESMOKE24,0,0}, // S_TELESMOKE23
+{SPR_TSMK,23,3,NULL,S_TELESMOKE25,0,0}, // S_TELESMOKE24
+{SPR_TSMK,24,4,NULL,S_TELESMOKE26,0,0}, // S_TELESMOKE25
+{SPR_TSMK,25,3,NULL,S_TELESMOKE1,0,0}, // S_TELESMOKE26
+{SPR_FPCH,0,0,A_Light0,S_NULL,0,0}, // S_LIGHTDONE
+{SPR_FPCH,0,1,A_WeaponReady,S_PUNCHREADY,0,0}, // S_PUNCHREADY
+{SPR_FPCH,0,1,A_Lower,S_PUNCHDOWN,0,0}, // S_PUNCHDOWN
+{SPR_FPCH,0,1,A_Raise,S_PUNCHUP,0,0}, // S_PUNCHUP
+{SPR_FPCH,1,5,NULL,S_PUNCHATK1_2,5,40}, // S_PUNCHATK1_1
+{SPR_FPCH,2,4,NULL,S_PUNCHATK1_3,5,40}, // S_PUNCHATK1_2
+{SPR_FPCH,3,4,A_FPunchAttack,S_PUNCHATK1_4,5,40}, // S_PUNCHATK1_3
+{SPR_FPCH,2,4,NULL,S_PUNCHATK1_5,5,40}, // S_PUNCHATK1_4
+{SPR_FPCH,1,5,A_ReFire,S_PUNCHREADY,5,40}, // S_PUNCHATK1_5
+{SPR_FPCH,3,4,NULL,S_PUNCHATK2_2,5,40}, // S_PUNCHATK2_1
+{SPR_FPCH,4,4,NULL,S_PUNCHATK2_3,5,40}, // S_PUNCHATK2_2
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_4,15,50}, // S_PUNCHATK2_3
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_5,25,60}, // S_PUNCHATK2_4
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_6,35,70}, // S_PUNCHATK2_5
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_7,45,80}, // S_PUNCHATK2_6
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_8,55,90}, // S_PUNCHATK2_7
+{SPR_FPCH,4,1,NULL,S_PUNCHATK2_9,65,100}, // S_PUNCHATK2_8
+{SPR_FPCH,4,10,NULL,S_PUNCHREADY,0,150}, // S_PUNCHATK2_9
+{SPR_FHFX,18,4,NULL,S_PUNCHPUFF2,0,0}, // S_PUNCHPUFF1
+{SPR_FHFX,19,4,NULL,S_PUNCHPUFF3,0,0}, // S_PUNCHPUFF2
+{SPR_FHFX,20,4,NULL,S_PUNCHPUFF4,0,0}, // S_PUNCHPUFF3
+{SPR_FHFX,21,4,NULL,S_PUNCHPUFF5,0,0}, // S_PUNCHPUFF4
+{SPR_FHFX,22,4,NULL,S_NULL,0,0}, // S_PUNCHPUFF5
+{SPR_WFAX,0,-1,NULL,S_NULL,0,0}, // S_AXE
+{SPR_FAXE,0,1,A_WeaponReady,S_FAXEREADY,0,0}, // S_FAXEREADY
+{SPR_FAXE,0,1,A_Lower,S_FAXEDOWN,0,0}, // S_FAXEDOWN
+{SPR_FAXE,0,1,A_Raise,S_FAXEUP,0,0}, // S_FAXEUP
+{SPR_FAXE,1,4,NULL,S_FAXEATK_2,15,32}, // S_FAXEATK_1
+{SPR_FAXE,2,3,NULL,S_FAXEATK_3,15,32}, // S_FAXEATK_2
+{SPR_FAXE,3,2,NULL,S_FAXEATK_4,15,32}, // S_FAXEATK_3
+{SPR_FAXE,3,1,A_FAxeAttack,S_FAXEATK_5,-5,70}, // S_FAXEATK_4
+{SPR_FAXE,3,2,NULL,S_FAXEATK_6,-25,90}, // S_FAXEATK_5
+{SPR_FAXE,4,1,NULL,S_FAXEATK_7,15,32}, // S_FAXEATK_6
+{SPR_FAXE,4,2,NULL,S_FAXEATK_8,10,54}, // S_FAXEATK_7
+{SPR_FAXE,4,7,NULL,S_FAXEATK_9,10,150}, // S_FAXEATK_8
+{SPR_FAXE,0,1,A_ReFire,S_FAXEATK_10,0,60}, // S_FAXEATK_9
+{SPR_FAXE,0,1,NULL,S_FAXEATK_11,0,52}, // S_FAXEATK_10
+{SPR_FAXE,0,1,NULL,S_FAXEATK_12,0,44}, // S_FAXEATK_11
+{SPR_FAXE,0,1,NULL,S_FAXEATK_13,0,36}, // S_FAXEATK_12
+{SPR_FAXE,0,1,NULL,S_FAXEREADY,0,0}, // S_FAXEATK_13
+{SPR_FAXE,11,1,A_WeaponReady,S_FAXEREADY_G1,0,0}, // S_FAXEREADY_G
+{SPR_FAXE,11,1,A_WeaponReady,S_FAXEREADY_G2,0,0}, // S_FAXEREADY_G1
+{SPR_FAXE,11,1,A_WeaponReady,S_FAXEREADY_G3,0,0}, // S_FAXEREADY_G2
+{SPR_FAXE,12,1,A_WeaponReady,S_FAXEREADY_G4,0,0}, // S_FAXEREADY_G3
+{SPR_FAXE,12,1,A_WeaponReady,S_FAXEREADY_G5,0,0}, // S_FAXEREADY_G4
+{SPR_FAXE,12,1,A_WeaponReady,S_FAXEREADY_G,0,0}, // S_FAXEREADY_G5
+{SPR_FAXE,11,1,A_Lower,S_FAXEDOWN_G,0,0}, // S_FAXEDOWN_G
+{SPR_FAXE,11,1,A_Raise,S_FAXEUP_G,0,0}, // S_FAXEUP_G
+{SPR_FAXE,13,4,NULL,S_FAXEATK_G2,15,32}, // S_FAXEATK_G1
+{SPR_FAXE,14,3,NULL,S_FAXEATK_G3,15,32}, // S_FAXEATK_G2
+{SPR_FAXE,15,2,NULL,S_FAXEATK_G4,15,32}, // S_FAXEATK_G3
+{SPR_FAXE,15,1,A_FAxeAttack,S_FAXEATK_G5,-5,70}, // S_FAXEATK_G4
+{SPR_FAXE,15,2,NULL,S_FAXEATK_G6,-25,90}, // S_FAXEATK_G5
+{SPR_FAXE,16,1,NULL,S_FAXEATK_G7,15,32}, // S_FAXEATK_G6
+{SPR_FAXE,16,2,NULL,S_FAXEATK_G8,10,54}, // S_FAXEATK_G7
+{SPR_FAXE,16,7,NULL,S_FAXEATK_G9,10,150}, // S_FAXEATK_G8
+{SPR_FAXE,0,1,A_ReFire,S_FAXEATK_G10,0,60}, // S_FAXEATK_G9
+{SPR_FAXE,0,1,NULL,S_FAXEATK_G11,0,52}, // S_FAXEATK_G10
+{SPR_FAXE,0,1,NULL,S_FAXEATK_G12,0,44}, // S_FAXEATK_G11
+{SPR_FAXE,0,1,NULL,S_FAXEATK_G13,0,36}, // S_FAXEATK_G12
+{SPR_FAXE,0,1,NULL,S_FAXEREADY_G,0,0}, // S_FAXEATK_G13
+{SPR_FAXE,32785,4,NULL,S_AXEPUFF_GLOW2,0,0}, // S_AXEPUFF_GLOW1
+{SPR_FAXE,32786,4,NULL,S_AXEPUFF_GLOW3,0,0}, // S_AXEPUFF_GLOW2
+{SPR_FAXE,32787,4,NULL,S_AXEPUFF_GLOW4,0,0}, // S_AXEPUFF_GLOW3
+{SPR_FAXE,32788,4,NULL,S_AXEPUFF_GLOW5,0,0}, // S_AXEPUFF_GLOW4
+{SPR_FAXE,32789,4,NULL,S_AXEPUFF_GLOW6,0,0}, // S_AXEPUFF_GLOW5
+{SPR_FAXE,32790,4,NULL,S_AXEPUFF_GLOW7,0,0}, // S_AXEPUFF_GLOW6
+{SPR_FAXE,32791,4,NULL,S_NULL,0,0}, // S_AXEPUFF_GLOW7
+{SPR_FAXE,5,3,NULL,S_AXEBLOOD2,0,0}, // S_AXEBLOOD1
+{SPR_FAXE,6,3,NULL,S_AXEBLOOD3,0,0}, // S_AXEBLOOD2
+{SPR_FAXE,7,3,NULL,S_AXEBLOOD4,0,0}, // S_AXEBLOOD3
+{SPR_FAXE,8,3,NULL,S_AXEBLOOD5,0,0}, // S_AXEBLOOD4
+{SPR_FAXE,9,3,NULL,S_AXEBLOOD6,0,0}, // S_AXEBLOOD5
+{SPR_FAXE,10,3,NULL,S_NULL,0,0}, // S_AXEBLOOD6
+{SPR_WFHM,0,-1,NULL,S_NULL,0,0}, // S_HAMM
+{SPR_FHMR,0,1,A_WeaponReady,S_FHAMMERREADY,0,0}, // S_FHAMMERREADY
+{SPR_FHMR,0,1,A_Lower,S_FHAMMERDOWN,0,0}, // S_FHAMMERDOWN
+{SPR_FHMR,0,1,A_Raise,S_FHAMMERUP,0,0}, // S_FHAMMERUP
+{SPR_FHMR,1,6,NULL,S_FHAMMERATK_2,5,0}, // S_FHAMMERATK_1
+{SPR_FHMR,2,3,A_FHammerAttack,S_FHAMMERATK_3,5,0}, // S_FHAMMERATK_2
+{SPR_FHMR,3,3,NULL,S_FHAMMERATK_4,5,0}, // S_FHAMMERATK_3
+{SPR_FHMR,4,2,NULL,S_FHAMMERATK_5,5,0}, // S_FHAMMERATK_4
+{SPR_FHMR,4,10,A_FHammerThrow,S_FHAMMERATK_6,5,150}, // S_FHAMMERATK_5
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_7,0,60}, // S_FHAMMERATK_6
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_8,0,55}, // S_FHAMMERATK_7
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_9,0,50}, // S_FHAMMERATK_8
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_10,0,45}, // S_FHAMMERATK_9
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_11,0,40}, // S_FHAMMERATK_10
+{SPR_FHMR,0,1,NULL,S_FHAMMERATK_12,0,35}, // S_FHAMMERATK_11
+{SPR_FHMR,0,1,NULL,S_FHAMMERREADY,0,0}, // S_FHAMMERATK_12
+{SPR_FHFX,32768,2,NULL,S_HAMMER_MISSILE_2,0,0}, // S_HAMMER_MISSILE_1
+{SPR_FHFX,32769,2,A_ContMobjSound,S_HAMMER_MISSILE_3,0,0}, // S_HAMMER_MISSILE_2
+{SPR_FHFX,32770,2,NULL,S_HAMMER_MISSILE_4,0,0}, // S_HAMMER_MISSILE_3
+{SPR_FHFX,32771,2,NULL,S_HAMMER_MISSILE_5,0,0}, // S_HAMMER_MISSILE_4
+{SPR_FHFX,32772,2,NULL,S_HAMMER_MISSILE_6,0,0}, // S_HAMMER_MISSILE_5
+{SPR_FHFX,32773,2,NULL,S_HAMMER_MISSILE_7,0,0}, // S_HAMMER_MISSILE_6
+{SPR_FHFX,32774,2,NULL,S_HAMMER_MISSILE_8,0,0}, // S_HAMMER_MISSILE_7
+{SPR_FHFX,32775,2,NULL,S_HAMMER_MISSILE_1,0,0}, // S_HAMMER_MISSILE_8
+{SPR_FHFX,32776,3,NULL,S_HAMMER_MISSILE_X2,0,0}, // S_HAMMER_MISSILE_X1
+{SPR_FHFX,32777,3,NULL,S_HAMMER_MISSILE_X3,0,0}, // S_HAMMER_MISSILE_X2
+{SPR_FHFX,32778,3,A_Explode,S_HAMMER_MISSILE_X4,0,0}, // S_HAMMER_MISSILE_X3
+{SPR_FHFX,32779,3,NULL,S_HAMMER_MISSILE_X5,0,0}, // S_HAMMER_MISSILE_X4
+{SPR_FHFX,32780,3,NULL,S_HAMMER_MISSILE_X6,0,0}, // S_HAMMER_MISSILE_X5
+{SPR_FHFX,13,3,NULL,S_HAMMER_MISSILE_X7,0,0}, // S_HAMMER_MISSILE_X6
+{SPR_FHFX,32782,3,NULL,S_HAMMER_MISSILE_X8,0,0}, // S_HAMMER_MISSILE_X7
+{SPR_FHFX,32783,3,NULL,S_HAMMER_MISSILE_X9,0,0}, // S_HAMMER_MISSILE_X8
+{SPR_FHFX,32784,3,NULL,S_HAMMER_MISSILE_X10,0,0}, // S_HAMMER_MISSILE_X9
+{SPR_FHFX,32785,3,NULL,S_NULL,0,0}, // S_HAMMER_MISSILE_X10
+{SPR_FHFX,18,4,NULL,S_HAMMERPUFF2,0,0}, // S_HAMMERPUFF1
+{SPR_FHFX,19,4,NULL,S_HAMMERPUFF3,0,0}, // S_HAMMERPUFF2
+{SPR_FHFX,20,4,NULL,S_HAMMERPUFF4,0,0}, // S_HAMMERPUFF3
+{SPR_FHFX,21,4,NULL,S_HAMMERPUFF5,0,0}, // S_HAMMERPUFF4
+{SPR_FHFX,22,4,NULL,S_NULL,0,0}, // S_HAMMERPUFF5
+{SPR_FSRD,32768,1,A_WeaponReady,S_FSWORDREADY1,0,0}, // S_FSWORDREADY
+{SPR_FSRD,32768,1,A_WeaponReady,S_FSWORDREADY2,0,0}, // S_FSWORDREADY1
+{SPR_FSRD,32768,1,A_WeaponReady,S_FSWORDREADY3,0,0}, // S_FSWORDREADY2
+{SPR_FSRD,32768,1,A_WeaponReady,S_FSWORDREADY4,0,0}, // S_FSWORDREADY3
+{SPR_FSRD,32769,1,A_WeaponReady,S_FSWORDREADY5,0,0}, // S_FSWORDREADY4
+{SPR_FSRD,32769,1,A_WeaponReady,S_FSWORDREADY6,0,0}, // S_FSWORDREADY5
+{SPR_FSRD,32769,1,A_WeaponReady,S_FSWORDREADY7,0,0}, // S_FSWORDREADY6
+{SPR_FSRD,32769,1,A_WeaponReady,S_FSWORDREADY8,0,0}, // S_FSWORDREADY7
+{SPR_FSRD,32770,1,A_WeaponReady,S_FSWORDREADY9,0,0}, // S_FSWORDREADY8
+{SPR_FSRD,32770,1,A_WeaponReady,S_FSWORDREADY10,0,0}, // S_FSWORDREADY9
+{SPR_FSRD,32770,1,A_WeaponReady,S_FSWORDREADY11,0,0}, // S_FSWORDREADY10
+{SPR_FSRD,32770,1,A_WeaponReady,S_FSWORDREADY,0,0}, // S_FSWORDREADY11
+{SPR_FSRD,32768,1,A_Lower,S_FSWORDDOWN,0,0}, // S_FSWORDDOWN
+{SPR_FSRD,32768,1,A_Raise,S_FSWORDUP,0,0}, // S_FSWORDUP
+{SPR_FSRD,32771,3,NULL,S_FSWORDATK_2,5,36}, // S_FSWORDATK_1
+{SPR_FSRD,32772,3,NULL,S_FSWORDATK_3,5,36}, // S_FSWORDATK_2
+{SPR_FSRD,32773,2,NULL,S_FSWORDATK_4,5,36}, // S_FSWORDATK_3
+{SPR_FSRD,32774,3,A_FSwordAttack,S_FSWORDATK_5,5,36}, // S_FSWORDATK_4
+{SPR_FSRD,32775,2,NULL,S_FSWORDATK_6,5,36}, // S_FSWORDATK_5
+{SPR_FSRD,32776,2,NULL,S_FSWORDATK_7,5,36}, // S_FSWORDATK_6
+{SPR_FSRD,32776,10,NULL,S_FSWORDATK_8,5,150}, // S_FSWORDATK_7
+{SPR_FSRD,32768,1,NULL,S_FSWORDATK_9,5,60}, // S_FSWORDATK_8
+{SPR_FSRD,32769,1,NULL,S_FSWORDATK_10,5,55}, // S_FSWORDATK_9
+{SPR_FSRD,32770,1,NULL,S_FSWORDATK_11,5,50}, // S_FSWORDATK_10
+{SPR_FSRD,32768,1,NULL,S_FSWORDATK_12,5,45}, // S_FSWORDATK_11
+{SPR_FSRD,32769,1,NULL,S_FSWORDREADY,5,40}, // S_FSWORDATK_12
+{SPR_FSFX,32768,3,NULL,S_FSWORD_MISSILE2,0,0}, // S_FSWORD_MISSILE1
+{SPR_FSFX,32769,3,NULL,S_FSWORD_MISSILE3,0,0}, // S_FSWORD_MISSILE2
+{SPR_FSFX,32770,3,NULL,S_FSWORD_MISSILE1,0,0}, // S_FSWORD_MISSILE3
+{SPR_FSFX,32771,4,NULL,S_FSWORD_MISSILE_X2,0,0}, // S_FSWORD_MISSILE_X1
+{SPR_FSFX,32772,3,A_FSwordFlames,S_FSWORD_MISSILE_X3,0,0}, // S_FSWORD_MISSILE_X2
+{SPR_FSFX,32773,4,A_Explode,S_FSWORD_MISSILE_X4,0,0}, // S_FSWORD_MISSILE_X3
+{SPR_FSFX,32774,3,NULL,S_FSWORD_MISSILE_X5,0,0}, // S_FSWORD_MISSILE_X4
+{SPR_FSFX,32775,4,NULL,S_FSWORD_MISSILE_X6,0,0}, // S_FSWORD_MISSILE_X5
+{SPR_FSFX,32776,3,NULL,S_FSWORD_MISSILE_X7,0,0}, // S_FSWORD_MISSILE_X6
+{SPR_FSFX,32777,4,NULL,S_FSWORD_MISSILE_X8,0,0}, // S_FSWORD_MISSILE_X7
+{SPR_FSFX,32778,3,NULL,S_FSWORD_MISSILE_X9,0,0}, // S_FSWORD_MISSILE_X8
+{SPR_FSFX,32779,3,NULL,S_FSWORD_MISSILE_X10,0,0}, // S_FSWORD_MISSILE_X9
+{SPR_FSFX,32780,3,NULL,S_NULL,0,0}, // S_FSWORD_MISSILE_X10
+{SPR_FSFX,32781,3,NULL,S_FSWORD_FLAME2,0,0}, // S_FSWORD_FLAME1
+{SPR_FSFX,32782,3,NULL,S_FSWORD_FLAME3,0,0}, // S_FSWORD_FLAME2
+{SPR_FSFX,32783,3,NULL,S_FSWORD_FLAME4,0,0}, // S_FSWORD_FLAME3
+{SPR_FSFX,32784,3,NULL,S_FSWORD_FLAME5,0,0}, // S_FSWORD_FLAME4
+{SPR_FSFX,32785,3,NULL,S_FSWORD_FLAME6,0,0}, // S_FSWORD_FLAME5
+{SPR_FSFX,32786,3,NULL,S_FSWORD_FLAME7,0,0}, // S_FSWORD_FLAME6
+{SPR_FSFX,32787,3,NULL,S_FSWORD_FLAME8,0,0}, // S_FSWORD_FLAME7
+{SPR_FSFX,32788,3,NULL,S_FSWORD_FLAME9,0,0}, // S_FSWORD_FLAME8
+{SPR_FSFX,32789,3,NULL,S_FSWORD_FLAME10,0,0}, // S_FSWORD_FLAME9
+{SPR_FSFX,32790,3,NULL,S_NULL,0,0}, // S_FSWORD_FLAME10
+{SPR_CMCE,0,1,A_WeaponReady,S_CMACEREADY,0,0}, // S_CMACEREADY
+{SPR_CMCE,0,1,A_Lower,S_CMACEDOWN,0,0}, // S_CMACEDOWN
+{SPR_CMCE,0,1,A_Raise,S_CMACEUP,0,0}, // S_CMACEUP
+{SPR_CMCE,1,2,NULL,S_CMACEATK_2,60,20}, // S_CMACEATK_1
+{SPR_CMCE,1,1,NULL,S_CMACEATK_3,30,33}, // S_CMACEATK_2
+{SPR_CMCE,1,2,NULL,S_CMACEATK_4,8,45}, // S_CMACEATK_3
+{SPR_CMCE,2,1,NULL,S_CMACEATK_5,8,45}, // S_CMACEATK_4
+{SPR_CMCE,3,1,NULL,S_CMACEATK_6,8,45}, // S_CMACEATK_5
+{SPR_CMCE,4,1,NULL,S_CMACEATK_7,8,45}, // S_CMACEATK_6
+{SPR_CMCE,4,1,A_CMaceAttack,S_CMACEATK_8,-11,58}, // S_CMACEATK_7
+{SPR_CMCE,5,1,NULL,S_CMACEATK_9,8,45}, // S_CMACEATK_8
+{SPR_CMCE,5,2,NULL,S_CMACEATK_10,-8,74}, // S_CMACEATK_9
+{SPR_CMCE,5,1,NULL,S_CMACEATK_11,-20,96}, // S_CMACEATK_10
+{SPR_CMCE,5,8,NULL,S_CMACEATK_12,-33,160}, // S_CMACEATK_11
+{SPR_CMCE,0,2,A_ReFire,S_CMACEATK_13,8,75}, // S_CMACEATK_12
+{SPR_CMCE,0,1,NULL,S_CMACEATK_14,8,65}, // S_CMACEATK_13
+{SPR_CMCE,0,2,NULL,S_CMACEATK_15,8,60}, // S_CMACEATK_14
+{SPR_CMCE,0,1,NULL,S_CMACEATK_16,8,55}, // S_CMACEATK_15
+{SPR_CMCE,0,2,NULL,S_CMACEATK_17,8,50}, // S_CMACEATK_16
+{SPR_CMCE,0,1,NULL,S_CMACEREADY,8,45}, // S_CMACEATK_17
+{SPR_WCSS,0,-1,NULL,S_NULL,0,0}, // S_CSTAFF
+{SPR_CSSF,2,4,NULL,S_CSTAFFREADY1,0,0}, // S_CSTAFFREADY
+{SPR_CSSF,1,3,A_CStaffInitBlink,S_CSTAFFREADY2,0,0}, // S_CSTAFFREADY1
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY3,0,0}, // S_CSTAFFREADY2
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY4,0,0}, // S_CSTAFFREADY3
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY5,0,0}, // S_CSTAFFREADY4
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY6,0,0}, // S_CSTAFFREADY5
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY7,0,0}, // S_CSTAFFREADY6
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY8,0,0}, // S_CSTAFFREADY7
+{SPR_CSSF,0,1,A_WeaponReady,S_CSTAFFREADY9,0,0}, // S_CSTAFFREADY8
+{SPR_CSSF,0,1,A_CStaffCheckBlink,S_CSTAFFREADY2,0,0}, // S_CSTAFFREADY9
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFBLINK2,0,0}, // S_CSTAFFBLINK1
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFBLINK3,0,0}, // S_CSTAFFBLINK2
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFBLINK4,0,0}, // S_CSTAFFBLINK3
+{SPR_CSSF,2,1,A_WeaponReady,S_CSTAFFBLINK5,0,0}, // S_CSTAFFBLINK4
+{SPR_CSSF,2,1,A_WeaponReady,S_CSTAFFBLINK6,0,0}, // S_CSTAFFBLINK5
+{SPR_CSSF,2,1,A_WeaponReady,S_CSTAFFBLINK7,0,0}, // S_CSTAFFBLINK6
+{SPR_CSSF,2,1,A_WeaponReady,S_CSTAFFBLINK8,0,0}, // S_CSTAFFBLINK7
+{SPR_CSSF,2,1,A_WeaponReady,S_CSTAFFBLINK9,0,0}, // S_CSTAFFBLINK8
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFBLINK10,0,0}, // S_CSTAFFBLINK9
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFBLINK11,0,0}, // S_CSTAFFBLINK10
+{SPR_CSSF,1,1,A_WeaponReady,S_CSTAFFREADY2,0,0}, // S_CSTAFFBLINK11
+{SPR_CSSF,1,3,NULL,S_CSTAFFDOWN2,0,0}, // S_CSTAFFDOWN
+{SPR_CSSF,2,4,NULL,S_CSTAFFDOWN3,0,0}, // S_CSTAFFDOWN2
+{SPR_CSSF,2,1,A_Lower,S_CSTAFFDOWN3,0,0}, // S_CSTAFFDOWN3
+{SPR_CSSF,2,1,A_Raise,S_CSTAFFUP,0,0}, // S_CSTAFFUP
+{SPR_CSSF,0,1,A_CStaffCheck,S_CSTAFFATK_2,0,45}, // S_CSTAFFATK_1
+{SPR_CSSF,9,1,A_CStaffAttack,S_CSTAFFATK_3,0,50}, // S_CSTAFFATK_2
+{SPR_CSSF,9,2,NULL,S_CSTAFFATK_4,0,50}, // S_CSTAFFATK_3
+{SPR_CSSF,9,2,NULL,S_CSTAFFATK_5,0,45}, // S_CSTAFFATK_4
+{SPR_CSSF,0,2,NULL,S_CSTAFFATK_6,0,40}, // S_CSTAFFATK_5
+{SPR_CSSF,0,2,NULL,S_CSTAFFREADY2,0,36}, // S_CSTAFFATK_6
+{SPR_CSSF,10,10,NULL,S_CSTAFFREADY2,0,36}, // S_CSTAFFATK2_1
+{SPR_CSSF,32771,1,A_CStaffMissileSlither,S_CSTAFF_MISSILE2,0,0}, // S_CSTAFF_MISSILE1
+{SPR_CSSF,32771,1,A_CStaffMissileSlither,S_CSTAFF_MISSILE3,0,0}, // S_CSTAFF_MISSILE2
+{SPR_CSSF,32772,1,A_CStaffMissileSlither,S_CSTAFF_MISSILE4,0,0}, // S_CSTAFF_MISSILE3
+{SPR_CSSF,32772,1,A_CStaffMissileSlither,S_CSTAFF_MISSILE1,0,0}, // S_CSTAFF_MISSILE4
+{SPR_CSSF,32773,4,NULL,S_CSTAFF_MISSILE_X2,0,0}, // S_CSTAFF_MISSILE_X1
+{SPR_CSSF,32774,4,NULL,S_CSTAFF_MISSILE_X3,0,0}, // S_CSTAFF_MISSILE_X2
+{SPR_CSSF,32775,3,NULL,S_CSTAFF_MISSILE_X4,0,0}, // S_CSTAFF_MISSILE_X3
+{SPR_CSSF,32776,3,NULL,S_NULL,0,0}, // S_CSTAFF_MISSILE_X4
+{SPR_FHFX,18,4,NULL,S_CSTAFFPUFF2,0,0}, // S_CSTAFFPUFF1
+{SPR_FHFX,19,4,NULL,S_CSTAFFPUFF3,0,0}, // S_CSTAFFPUFF2
+{SPR_FHFX,20,4,NULL,S_CSTAFFPUFF4,0,0}, // S_CSTAFFPUFF3
+{SPR_FHFX,21,4,NULL,S_CSTAFFPUFF5,0,0}, // S_CSTAFFPUFF4
+{SPR_FHFX,22,4,NULL,S_NULL,0,0}, // S_CSTAFFPUFF5
+{SPR_WCFM,32768,4,NULL,S_CFLAME2,0,0}, // S_CFLAME1
+{SPR_WCFM,32769,4,NULL,S_CFLAME3,0,0}, // S_CFLAME2
+{SPR_WCFM,32770,4,NULL,S_CFLAME4,0,0}, // S_CFLAME3
+{SPR_WCFM,32771,4,NULL,S_CFLAME5,0,0}, // S_CFLAME4
+{SPR_WCFM,32772,4,NULL,S_CFLAME6,0,0}, // S_CFLAME5
+{SPR_WCFM,32773,4,NULL,S_CFLAME7,0,0}, // S_CFLAME6
+{SPR_WCFM,32774,4,NULL,S_CFLAME8,0,0}, // S_CFLAME7
+{SPR_WCFM,32775,4,NULL,S_CFLAME1,0,0}, // S_CFLAME8
+{SPR_CFLM,0,1,A_WeaponReady,S_CFLAMEREADY2,0,0}, // S_CFLAMEREADY1
+{SPR_CFLM,0,1,A_WeaponReady,S_CFLAMEREADY3,0,0}, // S_CFLAMEREADY2
+{SPR_CFLM,0,1,A_WeaponReady,S_CFLAMEREADY4,0,0}, // S_CFLAMEREADY3
+{SPR_CFLM,0,1,A_WeaponReady,S_CFLAMEREADY5,0,0}, // S_CFLAMEREADY4
+{SPR_CFLM,1,1,A_WeaponReady,S_CFLAMEREADY6,0,0}, // S_CFLAMEREADY5
+{SPR_CFLM,1,1,A_WeaponReady,S_CFLAMEREADY7,0,0}, // S_CFLAMEREADY6
+{SPR_CFLM,1,1,A_WeaponReady,S_CFLAMEREADY8,0,0}, // S_CFLAMEREADY7
+{SPR_CFLM,1,1,A_WeaponReady,S_CFLAMEREADY9,0,0}, // S_CFLAMEREADY8
+{SPR_CFLM,2,1,A_WeaponReady,S_CFLAMEREADY10,0,0}, // S_CFLAMEREADY9
+{SPR_CFLM,2,1,A_WeaponReady,S_CFLAMEREADY11,0,0}, // S_CFLAMEREADY10
+{SPR_CFLM,2,1,A_WeaponReady,S_CFLAMEREADY12,0,0}, // S_CFLAMEREADY11
+{SPR_CFLM,2,1,A_WeaponReady,S_CFLAMEREADY1,0,0}, // S_CFLAMEREADY12
+{SPR_CFLM,0,1,A_Lower,S_CFLAMEDOWN,0,0}, // S_CFLAMEDOWN
+{SPR_CFLM,0,1,A_Raise,S_CFLAMEUP,0,0}, // S_CFLAMEUP
+{SPR_CFLM,0,2,NULL,S_CFLAMEATK_2,0,40}, // S_CFLAMEATK_1
+{SPR_CFLM,3,2,NULL,S_CFLAMEATK_3,0,50}, // S_CFLAMEATK_2
+{SPR_CFLM,3,2,NULL,S_CFLAMEATK_4,0,36}, // S_CFLAMEATK_3
+{SPR_CFLM,32772,4,NULL,S_CFLAMEATK_5,0,0}, // S_CFLAMEATK_4
+{SPR_CFLM,32773,4,A_CFlameAttack,S_CFLAMEATK_6,0,0}, // S_CFLAMEATK_5
+{SPR_CFLM,32772,4,NULL,S_CFLAMEATK_7,0,0}, // S_CFLAMEATK_6
+{SPR_CFLM,6,2,NULL,S_CFLAMEATK_8,0,40}, // S_CFLAMEATK_7
+{SPR_CFLM,6,2,NULL,S_CFLAMEREADY1,0,0}, // S_CFLAMEATK_8
+{SPR_CFFX,32781,5,NULL,S_CFLAMEFLOOR2,0,0}, // S_CFLAMEFLOOR1
+{SPR_CFFX,32782,4,NULL,S_CFLAMEFLOOR3,0,0}, // S_CFLAMEFLOOR2
+{SPR_CFFX,32783,3,NULL,S_NULL,0,0}, // S_CFLAMEFLOOR3
+{SPR_CFFX,32768,3,NULL,S_FLAMEPUFF2,0,0}, // S_FLAMEPUFF1
+{SPR_CFFX,32769,3,NULL,S_FLAMEPUFF3,0,0}, // S_FLAMEPUFF2
+{SPR_CFFX,32770,3,NULL,S_FLAMEPUFF4,0,0}, // S_FLAMEPUFF3
+{SPR_CFFX,32771,4,NULL,S_FLAMEPUFF5,0,0}, // S_FLAMEPUFF4
+{SPR_CFFX,32772,3,NULL,S_FLAMEPUFF6,0,0}, // S_FLAMEPUFF5
+{SPR_CFFX,32773,4,NULL,S_FLAMEPUFF7,0,0}, // S_FLAMEPUFF6
+{SPR_CFFX,32774,3,NULL,S_FLAMEPUFF8,0,0}, // S_FLAMEPUFF7
+{SPR_CFFX,32775,4,NULL,S_FLAMEPUFF9,0,0}, // S_FLAMEPUFF8
+{SPR_CFFX,32776,3,NULL,S_FLAMEPUFF10,0,0}, // S_FLAMEPUFF9
+{SPR_CFFX,32777,4,NULL,S_FLAMEPUFF11,0,0}, // S_FLAMEPUFF10
+{SPR_CFFX,32778,3,NULL,S_FLAMEPUFF12,0,0}, // S_FLAMEPUFF11
+{SPR_CFFX,32779,4,NULL,S_FLAMEPUFF13,0,0}, // S_FLAMEPUFF12
+{SPR_CFFX,32780,3,NULL,S_NULL,0,0}, // S_FLAMEPUFF13
+{SPR_CFFX,32768,3,NULL,S_FLAMEPUFF2_2,0,0}, // S_FLAMEPUFF2_1
+{SPR_CFFX,32769,3,NULL,S_FLAMEPUFF2_3,0,0}, // S_FLAMEPUFF2_2
+{SPR_CFFX,32770,3,NULL,S_FLAMEPUFF2_4,0,0}, // S_FLAMEPUFF2_3
+{SPR_CFFX,32771,4,NULL,S_FLAMEPUFF2_5,0,0}, // S_FLAMEPUFF2_4
+{SPR_CFFX,32772,3,NULL,S_FLAMEPUFF2_6,0,0}, // S_FLAMEPUFF2_5
+{SPR_CFFX,32773,4,NULL,S_FLAMEPUFF2_7,0,0}, // S_FLAMEPUFF2_6
+{SPR_CFFX,32774,3,NULL,S_FLAMEPUFF2_8,0,0}, // S_FLAMEPUFF2_7
+{SPR_CFFX,32775,4,NULL,S_FLAMEPUFF2_9,0,0}, // S_FLAMEPUFF2_8
+{SPR_CFFX,32776,3,NULL,S_FLAMEPUFF2_10,0,0}, // S_FLAMEPUFF2_9
+{SPR_CFFX,32770,3,NULL,S_FLAMEPUFF2_11,0,0}, // S_FLAMEPUFF2_10
+{SPR_CFFX,32771,4,NULL,S_FLAMEPUFF2_12,0,0}, // S_FLAMEPUFF2_11
+{SPR_CFFX,32772,3,NULL,S_FLAMEPUFF2_13,0,0}, // S_FLAMEPUFF2_12
+{SPR_CFFX,32773,4,NULL,S_FLAMEPUFF2_14,0,0}, // S_FLAMEPUFF2_13
+{SPR_CFFX,32774,3,NULL,S_FLAMEPUFF2_15,0,0}, // S_FLAMEPUFF2_14
+{SPR_CFFX,32775,4,NULL,S_FLAMEPUFF2_16,0,0}, // S_FLAMEPUFF2_15
+{SPR_CFFX,32776,3,NULL,S_FLAMEPUFF2_17,0,0}, // S_FLAMEPUFF2_16
+{SPR_CFFX,32777,4,NULL,S_FLAMEPUFF2_18,0,0}, // S_FLAMEPUFF2_17
+{SPR_CFFX,32778,3,NULL,S_FLAMEPUFF2_19,0,0}, // S_FLAMEPUFF2_18
+{SPR_CFFX,32779,4,NULL,S_FLAMEPUFF2_20,0,0}, // S_FLAMEPUFF2_19
+{SPR_CFFX,32780,3,NULL,S_NULL,0,0}, // S_FLAMEPUFF2_20
+{SPR_CFCF,32768,4,NULL,S_CIRCLE_FLAME2,0,0}, // S_CIRCLE_FLAME1
+{SPR_CFCF,32769,2,A_CFlameRotate,S_CIRCLE_FLAME3,0,0}, // S_CIRCLE_FLAME2
+{SPR_CFCF,32770,2,NULL,S_CIRCLE_FLAME4,0,0}, // S_CIRCLE_FLAME3
+{SPR_CFCF,32771,1,NULL,S_CIRCLE_FLAME5,0,0}, // S_CIRCLE_FLAME4
+{SPR_CFCF,32772,2,NULL,S_CIRCLE_FLAME6,0,0}, // S_CIRCLE_FLAME5
+{SPR_CFCF,32773,2,A_CFlameRotate,S_CIRCLE_FLAME7,0,0}, // S_CIRCLE_FLAME6
+{SPR_CFCF,32774,1,NULL,S_CIRCLE_FLAME8,0,0}, // S_CIRCLE_FLAME7
+{SPR_CFCF,32775,2,NULL,S_CIRCLE_FLAME9,0,0}, // S_CIRCLE_FLAME8
+{SPR_CFCF,32776,2,NULL,S_CIRCLE_FLAME10,0,0}, // S_CIRCLE_FLAME9
+{SPR_CFCF,32777,1,A_CFlameRotate,S_CIRCLE_FLAME11,0,0}, // S_CIRCLE_FLAME10
+{SPR_CFCF,32778,2,NULL,S_CIRCLE_FLAME12,0,0}, // S_CIRCLE_FLAME11
+{SPR_CFCF,32779,3,NULL,S_CIRCLE_FLAME13,0,0}, // S_CIRCLE_FLAME12
+{SPR_CFCF,32780,3,NULL,S_CIRCLE_FLAME14,0,0}, // S_CIRCLE_FLAME13
+{SPR_CFCF,32781,2,A_CFlameRotate,S_CIRCLE_FLAME15,0,0}, // S_CIRCLE_FLAME14
+{SPR_CFCF,32782,3,NULL,S_CIRCLE_FLAME16,0,0}, // S_CIRCLE_FLAME15
+{SPR_CFCF,32783,2,NULL,S_NULL,0,0}, // S_CIRCLE_FLAME16
+{SPR_CFCF,32784,3,NULL,S_CIRCLE_FLAME_X2,0,0}, // S_CIRCLE_FLAME_X1
+{SPR_CFCF,32785,3,NULL,S_CIRCLE_FLAME_X3,0,0}, // S_CIRCLE_FLAME_X2
+{SPR_CFCF,32786,3,A_Explode,S_CIRCLE_FLAME_X4,0,0}, // S_CIRCLE_FLAME_X3
+{SPR_CFCF,32787,3,NULL,S_CIRCLE_FLAME_X5,0,0}, // S_CIRCLE_FLAME_X4
+{SPR_CFCF,32788,3,NULL,S_CIRCLE_FLAME_X6,0,0}, // S_CIRCLE_FLAME_X5
+{SPR_CFCF,32789,3,NULL,S_CIRCLE_FLAME_X7,0,0}, // S_CIRCLE_FLAME_X6
+{SPR_CFCF,32790,3,NULL,S_CIRCLE_FLAME_X8,0,0}, // S_CIRCLE_FLAME_X7
+{SPR_CFCF,32791,3,NULL,S_CIRCLE_FLAME_X9,0,0}, // S_CIRCLE_FLAME_X8
+{SPR_CFCF,32792,3,NULL,S_CIRCLE_FLAME_X10,0,0}, // S_CIRCLE_FLAME_X9
+{SPR_CFCF,32793,3,NULL,S_NULL,0,0}, // S_CIRCLE_FLAME_X10
+{SPR_CFFX,32768,4,NULL,S_CFLAME_MISSILE2,0,0}, // S_CFLAME_MISSILE1
+{SPR_CFFX,0,1,A_CFlamePuff,S_FLAMEPUFF1,0,0}, // S_CFLAME_MISSILE2
+{SPR_CFFX,32768,1,A_CFlameMissile,S_FLAMEPUFF1,0,0}, // S_CFLAME_MISSILE_X
+{SPR_CHLY,0,1,A_WeaponReady,S_CHOLYREADY,0,0}, // S_CHOLYREADY
+{SPR_CHLY,0,1,A_Lower,S_CHOLYDOWN,0,0}, // S_CHOLYDOWN
+{SPR_CHLY,0,1,A_Raise,S_CHOLYUP,0,0}, // S_CHOLYUP
+{SPR_CHLY,32768,1,NULL,S_CHOLYATK_2,0,40}, // S_CHOLYATK_1
+{SPR_CHLY,32769,1,NULL,S_CHOLYATK_3,0,40}, // S_CHOLYATK_2
+{SPR_CHLY,32770,2,NULL,S_CHOLYATK_4,0,43}, // S_CHOLYATK_3
+{SPR_CHLY,32771,2,NULL,S_CHOLYATK_5,0,43}, // S_CHOLYATK_4
+{SPR_CHLY,32772,2,NULL,S_CHOLYATK_6,0,45}, // S_CHOLYATK_5
+{SPR_CHLY,32773,6,A_CHolyAttack,S_CHOLYATK_7,0,48}, // S_CHOLYATK_6
+{SPR_CHLY,32774,2,A_CHolyPalette,S_CHOLYATK_8,0,40}, // S_CHOLYATK_7
+{SPR_CHLY,32774,2,A_CHolyPalette,S_CHOLYATK_9,0,40}, // S_CHOLYATK_8
+{SPR_CHLY,32774,2,A_CHolyPalette,S_CHOLYREADY,0,36}, // S_CHOLYATK_9
+{SPR_SPIR,0,2,A_CHolySeek,S_HOLY_FX2,0,0}, // S_HOLY_FX1
+{SPR_SPIR,0,2,A_CHolySeek,S_HOLY_FX3,0,0}, // S_HOLY_FX2
+{SPR_SPIR,1,2,A_CHolySeek,S_HOLY_FX4,0,0}, // S_HOLY_FX3
+{SPR_SPIR,1,2,A_CHolyCheckScream,S_HOLY_FX1,0,0}, // S_HOLY_FX4
+{SPR_SPIR,3,4,NULL,S_HOLY_FX_X2,0,0}, // S_HOLY_FX_X1
+{SPR_SPIR,4,4,A_Scream,S_HOLY_FX_X3,0,0}, // S_HOLY_FX_X2
+{SPR_SPIR,5,4,NULL,S_HOLY_FX_X4,0,0}, // S_HOLY_FX_X3
+{SPR_SPIR,6,4,NULL,S_HOLY_FX_X5,0,0}, // S_HOLY_FX_X4
+{SPR_SPIR,7,4,NULL,S_HOLY_FX_X6,0,0}, // S_HOLY_FX_X5
+{SPR_SPIR,8,4,NULL,S_NULL,0,0}, // S_HOLY_FX_X6
+{SPR_SPIR,2,1,A_CHolyTail,S_HOLY_TAIL1,0,0}, // S_HOLY_TAIL1
+{SPR_SPIR,3,-1,NULL,S_NULL,0,0}, // S_HOLY_TAIL2
+{SPR_SPIR,10,3,NULL,S_HOLY_PUFF2,0,0}, // S_HOLY_PUFF1
+{SPR_SPIR,11,3,NULL,S_HOLY_PUFF3,0,0}, // S_HOLY_PUFF2
+{SPR_SPIR,12,3,NULL,S_HOLY_PUFF4,0,0}, // S_HOLY_PUFF3
+{SPR_SPIR,13,3,NULL,S_HOLY_PUFF5,0,0}, // S_HOLY_PUFF4
+{SPR_SPIR,14,3,NULL,S_NULL,0,0}, // S_HOLY_PUFF5
+{SPR_SPIR,32783,3,A_CHolySpawnPuff,S_HOLY_MISSILE2,0,0}, // S_HOLY_MISSILE1
+{SPR_SPIR,32783,3,A_CHolySpawnPuff,S_HOLY_MISSILE3,0,0}, // S_HOLY_MISSILE2
+{SPR_SPIR,32783,3,A_CHolySpawnPuff,S_HOLY_MISSILE4,0,0}, // S_HOLY_MISSILE3
+{SPR_SPIR,32783,3,A_CHolySpawnPuff,S_HOLY_MISSILE_X,0,0}, // S_HOLY_MISSILE4
+{SPR_SPIR,32783,1,A_CHolyAttack2,S_NULL,0,0}, // S_HOLY_MISSILE_X
+{SPR_SPIR,16,3,NULL,S_HOLY_MISSILE_P2,0,0}, // S_HOLY_MISSILE_P1
+{SPR_SPIR,17,3,NULL,S_HOLY_MISSILE_P3,0,0}, // S_HOLY_MISSILE_P2
+{SPR_SPIR,18,3,NULL,S_HOLY_MISSILE_P4,0,0}, // S_HOLY_MISSILE_P3
+{SPR_SPIR,19,3,NULL,S_HOLY_MISSILE_P5,0,0}, // S_HOLY_MISSILE_P4
+{SPR_SPIR,20,3,NULL,S_NULL,0,0}, // S_HOLY_MISSILE_P5
+{SPR_MWND,0,1,A_WeaponReady,S_MWANDREADY,0,0}, // S_MWANDREADY
+{SPR_MWND,0,1,A_Lower,S_MWANDDOWN,0,0}, // S_MWANDDOWN
+{SPR_MWND,0,1,A_Raise,S_MWANDUP,0,0}, // S_MWANDUP
+{SPR_MWND,0,6,NULL,S_MWANDATK_2,0,0}, // S_MWANDATK_1
+{SPR_MWND,32769,6,A_MWandAttack,S_MWANDATK_3,0,48}, // S_MWANDATK_2
+{SPR_MWND,0,3,NULL,S_MWANDATK_4,0,40}, // S_MWANDATK_3
+{SPR_MWND,0,3,A_ReFire,S_MWANDREADY,0,36}, // S_MWANDATK_4
+{SPR_MWND,32772,4,NULL,S_MWANDPUFF2,0,0}, // S_MWANDPUFF1
+{SPR_MWND,32773,3,NULL,S_MWANDPUFF3,0,0}, // S_MWANDPUFF2
+{SPR_MWND,32774,4,NULL,S_MWANDPUFF4,0,0}, // S_MWANDPUFF3
+{SPR_MWND,32775,3,NULL,S_MWANDPUFF5,0,0}, // S_MWANDPUFF4
+{SPR_MWND,32776,4,NULL,S_NULL,0,0}, // S_MWANDPUFF5
+{SPR_MWND,2,4,NULL,S_MWANDSMOKE2,0,0}, // S_MWANDSMOKE1
+{SPR_MWND,3,4,NULL,S_MWANDSMOKE3,0,0}, // S_MWANDSMOKE2
+{SPR_MWND,2,4,NULL,S_MWANDSMOKE4,0,0}, // S_MWANDSMOKE3
+{SPR_MWND,3,4,NULL,S_NULL,0,0}, // S_MWANDSMOKE4
+{SPR_MWND,32770,4,NULL,S_MWAND_MISSILE2,0,0}, // S_MWAND_MISSILE1
+{SPR_MWND,32771,4,NULL,S_MWAND_MISSILE1,0,0}, // S_MWAND_MISSILE2
+{SPR_WMLG,32768,4,NULL,S_MW_LIGHTNING2,0,0}, // S_MW_LIGHTNING1
+{SPR_WMLG,32769,4,NULL,S_MW_LIGHTNING3,0,0}, // S_MW_LIGHTNING2
+{SPR_WMLG,32770,4,NULL,S_MW_LIGHTNING4,0,0}, // S_MW_LIGHTNING3
+{SPR_WMLG,32771,4,NULL,S_MW_LIGHTNING5,0,0}, // S_MW_LIGHTNING4
+{SPR_WMLG,32772,4,NULL,S_MW_LIGHTNING6,0,0}, // S_MW_LIGHTNING5
+{SPR_WMLG,32773,4,NULL,S_MW_LIGHTNING7,0,0}, // S_MW_LIGHTNING6
+{SPR_WMLG,32774,4,NULL,S_MW_LIGHTNING8,0,0}, // S_MW_LIGHTNING7
+{SPR_WMLG,32775,4,NULL,S_MW_LIGHTNING1,0,0}, // S_MW_LIGHTNING8
+{SPR_MLNG,32768,1,A_WeaponReady,S_MLIGHTNINGREADY2,0,0}, // S_MLIGHTNINGREADY
+{SPR_MLNG,32768,1,A_WeaponReady,S_MLIGHTNINGREADY3,0,0}, // S_MLIGHTNINGREADY2
+{SPR_MLNG,32768,1,A_WeaponReady,S_MLIGHTNINGREADY4,0,0}, // S_MLIGHTNINGREADY3
+{SPR_MLNG,32768,1,A_WeaponReady,S_MLIGHTNINGREADY5,0,0}, // S_MLIGHTNINGREADY4
+{SPR_MLNG,32768,1,A_WeaponReady,S_MLIGHTNINGREADY6,0,0}, // S_MLIGHTNINGREADY5
+{SPR_MLNG,32768,1,A_LightningReady,S_MLIGHTNINGREADY7,0,0}, // S_MLIGHTNINGREADY6
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY8,0,0}, // S_MLIGHTNINGREADY7
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY9,0,0}, // S_MLIGHTNINGREADY8
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY10,0,0}, // S_MLIGHTNINGREADY9
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY11,0,0}, // S_MLIGHTNINGREADY10
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY12,0,0}, // S_MLIGHTNINGREADY11
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY13,0,0}, // S_MLIGHTNINGREADY12
+{SPR_MLNG,32770,1,A_WeaponReady,S_MLIGHTNINGREADY14,0,0}, // S_MLIGHTNINGREADY13
+{SPR_MLNG,32770,1,A_WeaponReady,S_MLIGHTNINGREADY15,0,0}, // S_MLIGHTNINGREADY14
+{SPR_MLNG,32770,1,A_WeaponReady,S_MLIGHTNINGREADY16,0,0}, // S_MLIGHTNINGREADY15
+{SPR_MLNG,32770,1,A_WeaponReady,S_MLIGHTNINGREADY17,0,0}, // S_MLIGHTNINGREADY16
+{SPR_MLNG,32770,1,A_WeaponReady,S_MLIGHTNINGREADY18,0,0}, // S_MLIGHTNINGREADY17
+{SPR_MLNG,32770,1,A_LightningReady,S_MLIGHTNINGREADY19,0,0}, // S_MLIGHTNINGREADY18
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY20,0,0}, // S_MLIGHTNINGREADY19
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY21,0,0}, // S_MLIGHTNINGREADY20
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY22,0,0}, // S_MLIGHTNINGREADY21
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY23,0,0}, // S_MLIGHTNINGREADY22
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY24,0,0}, // S_MLIGHTNINGREADY23
+{SPR_MLNG,32769,1,A_WeaponReady,S_MLIGHTNINGREADY,0,0}, // S_MLIGHTNINGREADY24
+{SPR_MLNG,32768,1,A_Lower,S_MLIGHTNINGDOWN,0,0}, // S_MLIGHTNINGDOWN
+{SPR_MLNG,32768,1,A_Raise,S_MLIGHTNINGUP,0,0}, // S_MLIGHTNINGUP
+{SPR_MLNG,32771,3,NULL,S_MLIGHTNINGATK_2,0,0}, // S_MLIGHTNINGATK_1
+{SPR_MLNG,32772,3,NULL,S_MLIGHTNINGATK_3,0,0}, // S_MLIGHTNINGATK_2
+{SPR_MLNG,32773,4,A_MLightningAttack,S_MLIGHTNINGATK_4,0,0}, // S_MLIGHTNINGATK_3
+{SPR_MLNG,32774,4,NULL,S_MLIGHTNINGATK_5,0,0}, // S_MLIGHTNINGATK_4
+{SPR_MLNG,32775,3,NULL,S_MLIGHTNINGATK_6,0,0}, // S_MLIGHTNINGATK_5
+{SPR_MLNG,32776,3,NULL,S_MLIGHTNINGATK_7,0,0}, // S_MLIGHTNINGATK_6
+{SPR_MLNG,32776,6,NULL,S_MLIGHTNINGATK_8,0,199}, // S_MLIGHTNINGATK_7
+{SPR_MLNG,32770,2,NULL,S_MLIGHTNINGATK_9,0,55}, // S_MLIGHTNINGATK_8
+{SPR_MLNG,32769,2,NULL,S_MLIGHTNINGATK_10,0,50}, // S_MLIGHTNINGATK_9
+{SPR_MLNG,32769,2,NULL,S_MLIGHTNINGATK_11,0,45}, // S_MLIGHTNINGATK_10
+{SPR_MLNG,32769,2,NULL,S_MLIGHTNINGREADY,0,40}, // S_MLIGHTNINGATK_11
+{SPR_MLFX,32768,2,A_LightningZap,S_LIGHTNING_CEILING2,0,0}, // S_LIGHTNING_CEILING1
+{SPR_MLFX,32769,2,A_LightningClip,S_LIGHTNING_CEILING3,0,0}, // S_LIGHTNING_CEILING2
+{SPR_MLFX,32770,2,A_LightningClip,S_LIGHTNING_CEILING4,0,0}, // S_LIGHTNING_CEILING3
+{SPR_MLFX,32771,2,A_LightningClip,S_LIGHTNING_CEILING1,0,0}, // S_LIGHTNING_CEILING4
+{SPR_MLF2,32768,2,A_LightningRemove,S_LIGHTNING_C_X2,0,0}, // S_LIGHTNING_C_X1
+{SPR_MLF2,32769,3,NULL,S_LIGHTNING_C_X3,0,0}, // S_LIGHTNING_C_X2
+{SPR_MLF2,32770,3,NULL,S_LIGHTNING_C_X4,0,0}, // S_LIGHTNING_C_X3
+{SPR_MLF2,32771,3,NULL,S_LIGHTNING_C_X5,0,0}, // S_LIGHTNING_C_X4
+{SPR_MLF2,32772,3,NULL,S_LIGHTNING_C_X6,0,0}, // S_LIGHTNING_C_X5
+{SPR_MLF2,32778,3,NULL,S_LIGHTNING_C_X7,0,0}, // S_LIGHTNING_C_X6
+{SPR_MLF2,32779,3,NULL,S_LIGHTNING_C_X8,0,0}, // S_LIGHTNING_C_X7
+{SPR_MLF2,32780,3,NULL,S_LIGHTNING_C_X9,0,0}, // S_LIGHTNING_C_X8
+{SPR_ACLO,4,35,NULL,S_LIGHTNING_C_X10,0,0}, // S_LIGHTNING_C_X9
+{SPR_MLF2,32781,3,NULL,S_LIGHTNING_C_X11,0,0}, // S_LIGHTNING_C_X10
+{SPR_MLF2,32782,3,NULL,S_LIGHTNING_C_X12,0,0}, // S_LIGHTNING_C_X11
+{SPR_MLF2,32783,4,NULL,S_LIGHTNING_C_X13,0,0}, // S_LIGHTNING_C_X12
+{SPR_MLF2,32784,3,NULL,S_LIGHTNING_C_X14,0,0}, // S_LIGHTNING_C_X13
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_C_X15,0,0}, // S_LIGHTNING_C_X14
+{SPR_MLF2,32784,4,NULL,S_LIGHTNING_C_X16,0,0}, // S_LIGHTNING_C_X15
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_C_X17,0,0}, // S_LIGHTNING_C_X16
+{SPR_MLF2,32782,3,NULL,S_LIGHTNING_C_X18,0,0}, // S_LIGHTNING_C_X17
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_C_X19,0,0}, // S_LIGHTNING_C_X18
+{SPR_MLF2,32783,1,A_HideThing,S_FREETARGMOBJ,0,0}, // S_LIGHTNING_C_X19
+{SPR_MLFX,32772,2,A_LightningZap,S_LIGHTNING_FLOOR2,0,0}, // S_LIGHTNING_FLOOR1
+{SPR_MLFX,32773,2,A_LightningClip,S_LIGHTNING_FLOOR3,0,0}, // S_LIGHTNING_FLOOR2
+{SPR_MLFX,32774,2,A_LightningClip,S_LIGHTNING_FLOOR4,0,0}, // S_LIGHTNING_FLOOR3
+{SPR_MLFX,32775,2,A_LightningClip,S_LIGHTNING_FLOOR1,0,0}, // S_LIGHTNING_FLOOR4
+{SPR_MLF2,32773,2,A_LightningRemove,S_LIGHTNING_F_X2,0,0}, // S_LIGHTNING_F_X1
+{SPR_MLF2,32774,3,NULL,S_LIGHTNING_F_X3,0,0}, // S_LIGHTNING_F_X2
+{SPR_MLF2,32775,3,NULL,S_LIGHTNING_F_X4,0,0}, // S_LIGHTNING_F_X3
+{SPR_MLF2,32776,3,NULL,S_LIGHTNING_F_X5,0,0}, // S_LIGHTNING_F_X4
+{SPR_MLF2,32777,3,NULL,S_LIGHTNING_F_X6,0,0}, // S_LIGHTNING_F_X5
+{SPR_MLF2,32778,3,NULL,S_LIGHTNING_F_X7,0,0}, // S_LIGHTNING_F_X6
+{SPR_MLF2,32779,3,NULL,S_LIGHTNING_F_X8,0,0}, // S_LIGHTNING_F_X7
+{SPR_MLF2,32780,3,NULL,S_LIGHTNING_F_X9,0,0}, // S_LIGHTNING_F_X8
+{SPR_ACLO,4,20,NULL,S_LIGHTNING_F_X10,0,0}, // S_LIGHTNING_F_X9
+{SPR_MLF2,32781,3,NULL,S_LIGHTNING_F_X11,0,0}, // S_LIGHTNING_F_X10
+{SPR_MLF2,32782,3,NULL,S_LIGHTNING_F_X12,0,0}, // S_LIGHTNING_F_X11
+{SPR_MLF2,32783,4,NULL,S_LIGHTNING_F_X13,0,0}, // S_LIGHTNING_F_X12
+{SPR_MLF2,32784,3,NULL,S_LIGHTNING_F_X14,0,0}, // S_LIGHTNING_F_X13
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_F_X15,0,0}, // S_LIGHTNING_F_X14
+{SPR_MLF2,32784,4,A_LastZap,S_LIGHTNING_F_X16,0,0}, // S_LIGHTNING_F_X15
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_F_X17,0,0}, // S_LIGHTNING_F_X16
+{SPR_MLF2,32782,3,NULL,S_LIGHTNING_F_X18,0,0}, // S_LIGHTNING_F_X17
+{SPR_MLF2,32783,3,NULL,S_LIGHTNING_F_X19,0,0}, // S_LIGHTNING_F_X18
+{SPR_MLF2,32783,1,A_HideThing,S_FREETARGMOBJ,0,0}, // S_LIGHTNING_F_X19
+{SPR_MLFX,32776,2,A_ZapMimic,S_LIGHTNING_ZAP2,0,0}, // S_LIGHTNING_ZAP1
+{SPR_MLFX,32777,2,A_ZapMimic,S_LIGHTNING_ZAP3,0,0}, // S_LIGHTNING_ZAP2
+{SPR_MLFX,32778,2,A_ZapMimic,S_LIGHTNING_ZAP4,0,0}, // S_LIGHTNING_ZAP3
+{SPR_MLFX,32779,2,A_ZapMimic,S_LIGHTNING_ZAP5,0,0}, // S_LIGHTNING_ZAP4
+{SPR_MLFX,32780,2,A_ZapMimic,S_LIGHTNING_ZAP1,0,0}, // S_LIGHTNING_ZAP5
+{SPR_MLFX,32781,2,NULL,S_LIGHTNING_ZAP_X2,0,0}, // S_LIGHTNING_ZAP_X1
+{SPR_MLFX,32782,2,NULL,S_LIGHTNING_ZAP_X3,0,0}, // S_LIGHTNING_ZAP_X2
+{SPR_MLFX,32783,2,NULL,S_LIGHTNING_ZAP_X4,0,0}, // S_LIGHTNING_ZAP_X3
+{SPR_MLFX,32784,2,NULL,S_LIGHTNING_ZAP_X5,0,0}, // S_LIGHTNING_ZAP_X4
+{SPR_MLFX,32785,2,NULL,S_LIGHTNING_ZAP_X6,0,0}, // S_LIGHTNING_ZAP_X5
+{SPR_MLFX,32786,2,NULL,S_LIGHTNING_ZAP_X7,0,0}, // S_LIGHTNING_ZAP_X6
+{SPR_MLFX,32787,2,NULL,S_LIGHTNING_ZAP_X8,0,0}, // S_LIGHTNING_ZAP_X7
+{SPR_MLFX,32788,2,NULL,S_NULL,0,0}, // S_LIGHTNING_ZAP_X8
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY2,0,0}, // S_MSTAFFREADY
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY3,0,0}, // S_MSTAFFREADY2
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY4,0,0}, // S_MSTAFFREADY3
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY5,0,0}, // S_MSTAFFREADY4
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY6,0,0}, // S_MSTAFFREADY5
+{SPR_MSTF,0,1,A_WeaponReady,S_MSTAFFREADY7,0,0}, // S_MSTAFFREADY6
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY8,0,0}, // S_MSTAFFREADY7
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY9,0,0}, // S_MSTAFFREADY8
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY10,0,0}, // S_MSTAFFREADY9
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY11,0,0}, // S_MSTAFFREADY10
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY12,0,0}, // S_MSTAFFREADY11
+{SPR_MSTF,1,1,A_WeaponReady,S_MSTAFFREADY13,0,0}, // S_MSTAFFREADY12
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY14,0,0}, // S_MSTAFFREADY13
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY15,0,0}, // S_MSTAFFREADY14
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY16,0,0}, // S_MSTAFFREADY15
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY17,0,0}, // S_MSTAFFREADY16
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY18,0,0}, // S_MSTAFFREADY17
+{SPR_MSTF,2,1,A_WeaponReady,S_MSTAFFREADY19,0,0}, // S_MSTAFFREADY18
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY20,0,0}, // S_MSTAFFREADY19
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY21,0,0}, // S_MSTAFFREADY20
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY22,0,0}, // S_MSTAFFREADY21
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY23,0,0}, // S_MSTAFFREADY22
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY24,0,0}, // S_MSTAFFREADY23
+{SPR_MSTF,3,1,A_WeaponReady,S_MSTAFFREADY25,0,0}, // S_MSTAFFREADY24
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY26,0,0}, // S_MSTAFFREADY25
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY27,0,0}, // S_MSTAFFREADY26
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY28,0,0}, // S_MSTAFFREADY27
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY29,0,0}, // S_MSTAFFREADY28
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY30,0,0}, // S_MSTAFFREADY29
+{SPR_MSTF,4,1,A_WeaponReady,S_MSTAFFREADY31,0,0}, // S_MSTAFFREADY30
+{SPR_MSTF,5,1,A_WeaponReady,S_MSTAFFREADY32,0,0}, // S_MSTAFFREADY31
+{SPR_MSTF,5,1,A_WeaponReady,S_MSTAFFREADY33,0,0}, // S_MSTAFFREADY32
+{SPR_MSTF,5,1,A_WeaponReady,S_MSTAFFREADY34,0,0}, // S_MSTAFFREADY33
+{SPR_MSTF,5,1,A_WeaponReady,S_MSTAFFREADY35,0,0}, // S_MSTAFFREADY34
+{SPR_MSTF,5,1,A_WeaponReady,S_MSTAFFREADY,0,0}, // S_MSTAFFREADY35
+{SPR_MSTF,0,1,A_Lower,S_MSTAFFDOWN,0,0}, // S_MSTAFFDOWN
+{SPR_MSTF,0,1,A_Raise,S_MSTAFFUP,0,0}, // S_MSTAFFUP
+{SPR_MSTF,6,4,NULL,S_MSTAFFATK_2,0,40}, // S_MSTAFFATK_1
+{SPR_MSTF,32775,4,A_MStaffAttack,S_MSTAFFATK_3,0,48}, // S_MSTAFFATK_2
+{SPR_MSTF,32775,2,A_MStaffPalette,S_MSTAFFATK_4,0,48}, // S_MSTAFFATK_3
+{SPR_MSTF,8,2,A_MStaffPalette,S_MSTAFFATK_5,0,48}, // S_MSTAFFATK_4
+{SPR_MSTF,8,2,A_MStaffPalette,S_MSTAFFATK_6,0,48}, // S_MSTAFFATK_5
+{SPR_MSTF,8,1,NULL,S_MSTAFFATK_7,0,40}, // S_MSTAFFATK_6
+{SPR_MSTF,9,5,NULL,S_MSTAFFREADY,0,36}, // S_MSTAFFATK_7
+{SPR_MSP1,32768,3,A_MStaffWeave,S_MSTAFF_FX1_2,0,0}, // S_MSTAFF_FX1_1
+{SPR_MSP1,32769,3,A_MStaffWeave,S_MSTAFF_FX1_3,0,0}, // S_MSTAFF_FX1_2
+{SPR_MSP1,32770,3,A_MStaffWeave,S_MSTAFF_FX1_4,0,0}, // S_MSTAFF_FX1_3
+{SPR_MSP1,32771,3,A_MStaffWeave,S_MSTAFF_FX1_5,0,0}, // S_MSTAFF_FX1_4
+{SPR_MSP1,32772,3,A_MStaffWeave,S_MSTAFF_FX1_6,0,0}, // S_MSTAFF_FX1_5
+{SPR_MSP1,32773,3,A_MStaffWeave,S_MSTAFF_FX1_1,0,0}, // S_MSTAFF_FX1_6
+{SPR_MSP1,32774,4,NULL,S_MSTAFF_FX_X2,0,0}, // S_MSTAFF_FX_X1
+{SPR_MSP1,32775,5,A_Explode,S_MSTAFF_FX_X3,0,0}, // S_MSTAFF_FX_X2
+{SPR_MSP1,32776,4,NULL,S_MSTAFF_FX_X4,0,0}, // S_MSTAFF_FX_X3
+{SPR_MSP1,32777,5,NULL,S_MSTAFF_FX_X5,0,0}, // S_MSTAFF_FX_X4
+{SPR_MSP1,32778,4,NULL,S_MSTAFF_FX_X6,0,0}, // S_MSTAFF_FX_X5
+{SPR_MSP1,32779,5,NULL,S_MSTAFF_FX_X7,0,0}, // S_MSTAFF_FX_X6
+{SPR_MSP1,32780,4,NULL,S_MSTAFF_FX_X8,0,0}, // S_MSTAFF_FX_X7
+{SPR_MSP1,32781,5,NULL,S_MSTAFF_FX_X9,0,0}, // S_MSTAFF_FX_X8
+{SPR_MSP1,32782,4,NULL,S_MSTAFF_FX_X10,0,0}, // S_MSTAFF_FX_X9
+{SPR_MSP1,32783,4,NULL,S_NULL,0,0}, // S_MSTAFF_FX_X10
+{SPR_MSP2,32768,2,A_MStaffTrack,S_MSTAFF_FX2_2,0,0}, // S_MSTAFF_FX2_1
+{SPR_MSP2,32769,2,A_MStaffTrack,S_MSTAFF_FX2_3,0,0}, // S_MSTAFF_FX2_2
+{SPR_MSP2,32770,2,A_MStaffTrack,S_MSTAFF_FX2_4,0,0}, // S_MSTAFF_FX2_3
+{SPR_MSP2,32771,2,A_MStaffTrack,S_MSTAFF_FX2_1,0,0}, // S_MSTAFF_FX2_4
+{SPR_MSP2,32772,4,NULL,S_MSTAFF_FX2_X2,0,0}, // S_MSTAFF_FX2_X1
+{SPR_MSP2,32773,5,A_Explode,S_MSTAFF_FX2_X3,0,0}, // S_MSTAFF_FX2_X2
+{SPR_MSP2,32774,5,NULL,S_MSTAFF_FX2_X4,0,0}, // S_MSTAFF_FX2_X3
+{SPR_MSP2,32775,5,NULL,S_MSTAFF_FX2_X5,0,0}, // S_MSTAFF_FX2_X4
+{SPR_MSP2,32776,4,NULL,S_NULL,0,0}, // S_MSTAFF_FX2_X5
+{SPR_WFR1,32768,-1,NULL,S_NULL,0,0}, // S_FSWORD1
+{SPR_WFR2,32768,-1,NULL,S_NULL,0,0}, // S_FSWORD2
+{SPR_WFR3,32768,-1,NULL,S_NULL,0,0}, // S_FSWORD3
+{SPR_WCH1,32768,-1,NULL,S_NULL,0,0}, // S_CHOLY1
+{SPR_WCH2,32768,-1,NULL,S_NULL,0,0}, // S_CHOLY2
+{SPR_WCH3,32768,-1,NULL,S_NULL,0,0}, // S_CHOLY3
+{SPR_WMS1,32768,-1,NULL,S_NULL,0,0}, // S_MSTAFF1
+{SPR_WMS2,32768,-1,NULL,S_NULL,0,0}, // S_MSTAFF2
+{SPR_WMS3,32768,-1,NULL,S_NULL,0,0}, // S_MSTAFF3
+{SPR_WPIG,0,1,A_WeaponReady,S_SNOUTREADY,0,0}, // S_SNOUTREADY
+{SPR_WPIG,0,1,A_Lower,S_SNOUTDOWN,0,0}, // S_SNOUTDOWN
+{SPR_WPIG,0,1,A_Raise,S_SNOUTUP,0,0}, // S_SNOUTUP
+{SPR_WPIG,0,4,A_SnoutAttack,S_SNOUTATK2,0,0}, // S_SNOUTATK1
+{SPR_WPIG,1,8,A_SnoutAttack,S_SNOUTREADY,0,0}, // S_SNOUTATK2
+{SPR_WMCS,32768,8,NULL,S_COS2,0,0}, // S_COS1
+{SPR_WMCS,32769,8,NULL,S_COS3,0,0}, // S_COS2
+{SPR_WMCS,32770,8,NULL,S_COS1,0,0}, // S_COS3
+{SPR_CONE,0,1,A_WeaponReady,S_CONEREADY,0,0}, // S_CONEREADY
+{SPR_CONE,0,1,A_Lower,S_CONEDOWN,0,0}, // S_CONEDOWN
+{SPR_CONE,0,1,A_Raise,S_CONEUP,0,0}, // S_CONEUP
+{SPR_CONE,1,3,NULL,S_CONEATK1_2,0,0}, // S_CONEATK1_1
+{SPR_CONE,2,4,NULL,S_CONEATK1_3,0,0}, // S_CONEATK1_2
+{SPR_CONE,3,3,NULL,S_CONEATK1_4,0,0}, // S_CONEATK1_3
+{SPR_CONE,4,5,NULL,S_CONEATK1_5,0,0}, // S_CONEATK1_4
+{SPR_CONE,5,3,A_FireConePL1,S_CONEATK1_6,0,0}, // S_CONEATK1_5
+{SPR_CONE,6,3,NULL,S_CONEATK1_7,0,0}, // S_CONEATK1_6
+{SPR_CONE,0,9,NULL,S_CONEATK1_8,0,0}, // S_CONEATK1_7
+{SPR_CONE,0,10,A_ReFire,S_CONEREADY,0,0}, // S_CONEATK1_8
+{SPR_SHRD,32768,2,NULL,S_SHARDFX1_2,0,0}, // S_SHARDFX1_1
+{SPR_SHRD,32768,3,A_ShedShard,S_SHARDFX1_3,0,0}, // S_SHARDFX1_2
+{SPR_SHRD,32769,3,NULL,S_SHARDFX1_4,0,0}, // S_SHARDFX1_3
+{SPR_SHRD,32770,3,NULL,S_SHARDFX1_1,0,0}, // S_SHARDFX1_4
+{SPR_SHEX,32768,5,NULL,S_SHARDFXE1_2,0,0}, // S_SHARDFXE1_1
+{SPR_SHEX,32769,5,NULL,S_SHARDFXE1_3,0,0}, // S_SHARDFXE1_2
+{SPR_SHEX,32770,5,NULL,S_SHARDFXE1_4,0,0}, // S_SHARDFXE1_3
+{SPR_SHEX,32771,5,NULL,S_SHARDFXE1_5,0,0}, // S_SHARDFXE1_4
+{SPR_SHEX,32772,5,NULL,S_NULL,0,0}, // S_SHARDFXE1_5
+{SPR_BLOD,2,8,NULL,S_BLOOD2,0,0}, // S_BLOOD1
+{SPR_BLOD,1,8,NULL,S_BLOOD3,0,0}, // S_BLOOD2
+{SPR_BLOD,0,8,NULL,S_NULL,0,0}, // S_BLOOD3
+{SPR_BLOD,2,8,NULL,S_BLOODSPLATTER2,0,0}, // S_BLOODSPLATTER1
+{SPR_BLOD,1,8,NULL,S_BLOODSPLATTER3,0,0}, // S_BLOODSPLATTER2
+{SPR_BLOD,0,8,NULL,S_NULL,0,0}, // S_BLOODSPLATTER3
+{SPR_BLOD,0,6,NULL,S_NULL,0,0}, // S_BLOODSPLATTERX
+{SPR_GIBS,0,-1,NULL,S_NULL,0,0}, // S_GIBS1
+{SPR_PLAY,0,-1,NULL,S_NULL,0,0}, // S_FPLAY
+{SPR_PLAY,0,4,NULL,S_FPLAY_RUN2,0,0}, // S_FPLAY_RUN1
+{SPR_PLAY,1,4,NULL,S_FPLAY_RUN3,0,0}, // S_FPLAY_RUN2
+{SPR_PLAY,2,4,NULL,S_FPLAY_RUN4,0,0}, // S_FPLAY_RUN3
+{SPR_PLAY,3,4,NULL,S_FPLAY_RUN1,0,0}, // S_FPLAY_RUN4
+{SPR_PLAY,4,8,NULL,S_FPLAY_ATK2,0,0}, // S_FPLAY_ATK1
+{SPR_PLAY,5,8,NULL,S_FPLAY,0,0}, // S_FPLAY_ATK2
+{SPR_PLAY,6,4,NULL,S_FPLAY_PAIN2,0,0}, // S_FPLAY_PAIN
+{SPR_PLAY,6,4,A_Pain,S_FPLAY,0,0}, // S_FPLAY_PAIN2
+{SPR_PLAY,7,6,NULL,S_FPLAY_DIE2,0,0}, // S_FPLAY_DIE1
+{SPR_PLAY,8,6,A_Scream,S_FPLAY_DIE3,0,0}, // S_FPLAY_DIE2
+{SPR_PLAY,9,6,NULL,S_FPLAY_DIE4,0,0}, // S_FPLAY_DIE3
+{SPR_PLAY,10,6,NULL,S_FPLAY_DIE5,0,0}, // S_FPLAY_DIE4
+{SPR_PLAY,11,6,A_NoBlocking,S_FPLAY_DIE6,0,0}, // S_FPLAY_DIE5
+{SPR_PLAY,12,6,NULL,S_FPLAY_DIE7,0,0}, // S_FPLAY_DIE6
+{SPR_PLAY,13,-1,A_AddPlayerCorpse,S_NULL,0,0}, // S_FPLAY_DIE7
+{SPR_PLAY,14,5,A_Scream,S_FPLAY_XDIE2,0,0}, // S_FPLAY_XDIE1
+{SPR_PLAY,15,5,A_SkullPop,S_FPLAY_XDIE3,0,0}, // S_FPLAY_XDIE2
+{SPR_PLAY,17,5,A_NoBlocking,S_FPLAY_XDIE4,0,0}, // S_FPLAY_XDIE3
+{SPR_PLAY,18,5,NULL,S_FPLAY_XDIE5,0,0}, // S_FPLAY_XDIE4
+{SPR_PLAY,19,5,NULL,S_FPLAY_XDIE6,0,0}, // S_FPLAY_XDIE5
+{SPR_PLAY,20,5,NULL,S_FPLAY_XDIE7,0,0}, // S_FPLAY_XDIE6
+{SPR_PLAY,21,5,NULL,S_FPLAY_XDIE8,0,0}, // S_FPLAY_XDIE7
+{SPR_PLAY,22,-1,A_AddPlayerCorpse,S_NULL,0,0}, // S_FPLAY_XDIE8
+{SPR_PLAY,23,5,A_FreezeDeath,S_FPLAY_ICE2,0,0}, // S_FPLAY_ICE
+{SPR_PLAY,23,1,A_FreezeDeathChunks,S_FPLAY_ICE2,0,0}, // S_FPLAY_ICE2
+{SPR_FDTH,32768,5,NULL,S_PLAY_F_FDTH2,0,0}, // S_PLAY_F_FDTH1
+{SPR_FDTH,32769,4,NULL,S_PLAY_FDTH3,0,0}, // S_PLAY_F_FDTH2
+{SPR_FDTH,32770,5,NULL,S_PLAY_C_FDTH2,0,0}, // S_PLAY_C_FDTH1
+{SPR_FDTH,32771,4,NULL,S_PLAY_FDTH3,0,0}, // S_PLAY_C_FDTH2
+{SPR_FDTH,32772,5,NULL,S_PLAY_M_FDTH2,0,0}, // S_PLAY_M_FDTH1
+{SPR_FDTH,32773,4,NULL,S_PLAY_FDTH3,0,0}, // S_PLAY_M_FDTH2
+{SPR_FDTH,32774,5,NULL,S_PLAY_FDTH4,0,0}, // S_PLAY_FDTH3
+{SPR_FDTH,32775,4,A_Scream,S_PLAY_FDTH5,0,0}, // S_PLAY_FDTH4
+{SPR_FDTH,32776,5,NULL,S_PLAY_FDTH6,0,0}, // S_PLAY_FDTH5
+{SPR_FDTH,32777,4,NULL,S_PLAY_FDTH7,0,0}, // S_PLAY_FDTH6
+{SPR_FDTH,32778,5,NULL,S_PLAY_FDTH8,0,0}, // S_PLAY_FDTH7
+{SPR_FDTH,32779,4,NULL,S_PLAY_FDTH9,0,0}, // S_PLAY_FDTH8
+{SPR_FDTH,32780,5,NULL,S_PLAY_FDTH10,0,0}, // S_PLAY_FDTH9
+{SPR_FDTH,32781,4,NULL,S_PLAY_FDTH11,0,0}, // S_PLAY_FDTH10
+{SPR_FDTH,32782,5,NULL,S_PLAY_FDTH12,0,0}, // S_PLAY_FDTH11
+{SPR_FDTH,32783,4,NULL,S_PLAY_FDTH13,0,0}, // S_PLAY_FDTH12
+{SPR_FDTH,32784,5,NULL,S_PLAY_FDTH14,0,0}, // S_PLAY_FDTH13
+{SPR_FDTH,32785,4,NULL,S_PLAY_FDTH15,0,0}, // S_PLAY_FDTH14
+{SPR_FDTH,32786,5,A_NoBlocking,S_PLAY_FDTH16,0,0}, // S_PLAY_FDTH15
+{SPR_FDTH,32787,4,NULL,S_PLAY_FDTH17,0,0}, // S_PLAY_FDTH16
+{SPR_FDTH,32788,5,NULL,S_PLAY_FDTH18,0,0}, // S_PLAY_FDTH17
+{SPR_FDTH,32789,4,NULL,S_PLAY_FDTH19,0,0}, // S_PLAY_FDTH18
+{SPR_ACLO,4,35,A_CheckBurnGone,S_PLAY_FDTH19,0,0}, // S_PLAY_FDTH19
+{SPR_ACLO,4,8,NULL,S_NULL,0,0}, // S_PLAY_FDTH20
+{SPR_BSKL,0,5,A_CheckSkullFloor,S_BLOODYSKULL2,0,0}, // S_BLOODYSKULL1
+{SPR_BSKL,1,5,A_CheckSkullFloor,S_BLOODYSKULL3,0,0}, // S_BLOODYSKULL2
+{SPR_BSKL,2,5,A_CheckSkullFloor,S_BLOODYSKULL4,0,0}, // S_BLOODYSKULL3
+{SPR_BSKL,3,5,A_CheckSkullFloor,S_BLOODYSKULL5,0,0}, // S_BLOODYSKULL4
+{SPR_BSKL,5,5,A_CheckSkullFloor,S_BLOODYSKULL6,0,0}, // S_BLOODYSKULL5
+{SPR_BSKL,6,5,A_CheckSkullFloor,S_BLOODYSKULL7,0,0}, // S_BLOODYSKULL6
+{SPR_BSKL,7,5,A_CheckSkullFloor,S_BLOODYSKULL1,0,0}, // S_BLOODYSKULL7
+{SPR_BSKL,8,16,A_CheckSkullDone,S_BLOODYSKULLX1,0,0}, // S_BLOODYSKULLX1
+{SPR_BSKL,8,1050,NULL,S_NULL,0,0}, // S_BLOODYSKULLX2
+{SPR_PLAY,0,5,NULL,S_PLAYER_SPEED2,0,0}, // S_PLAYER_SPEED1
+{SPR_PLAY,0,3,A_SpeedFade,S_NULL,0,0}, // S_PLAYER_SPEED2
+{SPR_ICEC,0,10,NULL,S_ICECHUNK2,0,0}, // S_ICECHUNK1
+{SPR_ICEC,1,10,A_IceSetTics,S_ICECHUNK3,0,0}, // S_ICECHUNK2
+{SPR_ICEC,2,10,A_IceSetTics,S_ICECHUNK4,0,0}, // S_ICECHUNK3
+{SPR_ICEC,3,10,A_IceSetTics,S_NULL,0,0}, // S_ICECHUNK4
+{SPR_ICEC,0,10,A_IceCheckHeadDone,S_ICECHUNK_HEAD,0,0}, // S_ICECHUNK_HEAD
+{SPR_ICEC,0,1050,NULL,S_NULL,0,0}, // S_ICECHUNK_HEAD2
+{SPR_CLER,0,-1,NULL,S_NULL,0,0}, // S_CPLAY
+{SPR_CLER,0,4,NULL,S_CPLAY_RUN2,0,0}, // S_CPLAY_RUN1
+{SPR_CLER,1,4,NULL,S_CPLAY_RUN3,0,0}, // S_CPLAY_RUN2
+{SPR_CLER,2,4,NULL,S_CPLAY_RUN4,0,0}, // S_CPLAY_RUN3
+{SPR_CLER,3,4,NULL,S_CPLAY_RUN1,0,0}, // S_CPLAY_RUN4
+{SPR_CLER,4,6,NULL,S_CPLAY_ATK2,0,0}, // S_CPLAY_ATK1
+{SPR_CLER,5,6,NULL,S_CPLAY_ATK3,0,0}, // S_CPLAY_ATK2
+{SPR_CLER,6,6,NULL,S_CPLAY,0,0}, // S_CPLAY_ATK3
+{SPR_CLER,7,4,NULL,S_CPLAY_PAIN2,0,0}, // S_CPLAY_PAIN
+{SPR_CLER,7,4,A_Pain,S_CPLAY,0,0}, // S_CPLAY_PAIN2
+{SPR_CLER,8,6,NULL,S_CPLAY_DIE2,0,0}, // S_CPLAY_DIE1
+{SPR_CLER,10,6,A_Scream,S_CPLAY_DIE3,0,0}, // S_CPLAY_DIE2
+{SPR_CLER,11,6,NULL,S_CPLAY_DIE4,0,0}, // S_CPLAY_DIE3
+{SPR_CLER,11,6,NULL,S_CPLAY_DIE5,0,0}, // S_CPLAY_DIE4
+{SPR_CLER,12,6,A_NoBlocking,S_CPLAY_DIE6,0,0}, // S_CPLAY_DIE5
+{SPR_CLER,13,6,NULL,S_CPLAY_DIE7,0,0}, // S_CPLAY_DIE6
+{SPR_CLER,14,6,NULL,S_CPLAY_DIE8,0,0}, // S_CPLAY_DIE7
+{SPR_CLER,15,6,NULL,S_CPLAY_DIE9,0,0}, // S_CPLAY_DIE8
+{SPR_CLER,16,-1,A_AddPlayerCorpse,S_NULL,0,0}, // S_CPLAY_DIE9
+{SPR_CLER,17,5,A_Scream,S_CPLAY_XDIE2,0,0}, // S_CPLAY_XDIE1
+{SPR_CLER,18,5,NULL,S_CPLAY_XDIE3,0,0}, // S_CPLAY_XDIE2
+{SPR_CLER,19,5,A_NoBlocking,S_CPLAY_XDIE4,0,0}, // S_CPLAY_XDIE3
+{SPR_CLER,20,5,NULL,S_CPLAY_XDIE5,0,0}, // S_CPLAY_XDIE4
+{SPR_CLER,21,5,NULL,S_CPLAY_XDIE6,0,0}, // S_CPLAY_XDIE5
+{SPR_CLER,22,5,NULL,S_CPLAY_XDIE7,0,0}, // S_CPLAY_XDIE6
+{SPR_CLER,23,5,NULL,S_CPLAY_XDIE8,0,0}, // S_CPLAY_XDIE7
+{SPR_CLER,24,5,NULL,S_CPLAY_XDIE9,0,0}, // S_CPLAY_XDIE8
+{SPR_CLER,25,5,NULL,S_CPLAY_XDIE10,0,0}, // S_CPLAY_XDIE9
+{SPR_CLER,26,-1,A_AddPlayerCorpse,S_NULL,0,0}, // S_CPLAY_XDIE10
+{SPR_CLER,27,5,A_FreezeDeath,S_CPLAY_ICE2,0,0}, // S_CPLAY_ICE
+{SPR_CLER,27,1,A_FreezeDeathChunks,S_CPLAY_ICE2,0,0}, // S_CPLAY_ICE2
+{SPR_MAGE,0,-1,NULL,S_NULL,0,0}, // S_MPLAY
+{SPR_MAGE,0,4,NULL,S_MPLAY_RUN2,0,0}, // S_MPLAY_RUN1
+{SPR_MAGE,1,4,NULL,S_MPLAY_RUN3,0,0}, // S_MPLAY_RUN2
+{SPR_MAGE,2,4,NULL,S_MPLAY_RUN4,0,0}, // S_MPLAY_RUN3
+{SPR_MAGE,3,4,NULL,S_MPLAY_RUN1,0,0}, // S_MPLAY_RUN4
+{SPR_MAGE,4,8,NULL,S_MPLAY_ATK2,0,0}, // S_MPLAY_ATK1
+{SPR_MAGE,32773,8,NULL,S_MPLAY,0,0}, // S_MPLAY_ATK2
+{SPR_MAGE,6,4,NULL,S_MPLAY_PAIN2,0,0}, // S_MPLAY_PAIN
+{SPR_MAGE,6,4,A_Pain,S_MPLAY,0,0}, // S_MPLAY_PAIN2
+{SPR_MAGE,7,6,NULL,S_MPLAY_DIE2,0,0}, // S_MPLAY_DIE1
+{SPR_MAGE,8,6,A_Scream,S_MPLAY_DIE3,0,0}, // S_MPLAY_DIE2
+{SPR_MAGE,9,6,NULL,S_MPLAY_DIE4,0,0}, // S_MPLAY_DIE3
+{SPR_MAGE,10,6,NULL,S_MPLAY_DIE5,0,0}, // S_MPLAY_DIE4
+{SPR_MAGE,11,6,A_NoBlocking,S_MPLAY_DIE6,0,0}, // S_MPLAY_DIE5
+{SPR_MAGE,12,6,NULL,S_MPLAY_DIE7,0,0}, // S_MPLAY_DIE6
+{SPR_MAGE,13,-1,A_AddPlayerCorpse,S_NULL,0,0}, // S_MPLAY_DIE7
+{SPR_MAGE,14,5,A_Scream,S_MPLAY_XDIE2,0,0}, // S_MPLAY_XDIE1
+{SPR_MAGE,15,5,NULL,S_MPLAY_XDIE3,0,0}, // S_MPLAY_XDIE2
+{SPR_MAGE,17,5,A_NoBlocking,S_MPLAY_XDIE4,0,0}, // S_MPLAY_XDIE3
+{SPR_MAGE,18,5,NULL,S_MPLAY_XDIE5,0,0}, // S_MPLAY_XDIE4
+{SPR_MAGE,19,5,NULL,S_MPLAY_XDIE6,0,0}, // S_MPLAY_XDIE5
+{SPR_MAGE,20,5,NULL,S_MPLAY_XDIE7,0,0}, // S_MPLAY_XDIE6
+{SPR_MAGE,21,5,NULL,S_MPLAY_XDIE8,0,0}, // S_MPLAY_XDIE7
+{SPR_MAGE,22,5,NULL,S_MPLAY_XDIE9,0,0}, // S_MPLAY_XDIE8
+{SPR_MAGE,23,-1,A_AddPlayerCorpse,S_NULL,0,0}, // S_MPLAY_XDIE9
+{SPR_MAGE,24,5,A_FreezeDeath,S_MPLAY_ICE2,0,0}, // S_MPLAY_ICE
+{SPR_MAGE,24,1,A_FreezeDeathChunks,S_MPLAY_ICE2,0,0}, // S_MPLAY_ICE2
+{SPR_PIGY,0,-1,NULL,S_NULL,0,0}, // S_PIGPLAY
+{SPR_PIGY,0,3,NULL,S_PIGPLAY_RUN2,0,0}, // S_PIGPLAY_RUN1
+{SPR_PIGY,1,3,NULL,S_PIGPLAY_RUN3,0,0}, // S_PIGPLAY_RUN2
+{SPR_PIGY,2,3,NULL,S_PIGPLAY_RUN4,0,0}, // S_PIGPLAY_RUN3
+{SPR_PIGY,3,3,NULL,S_PIGPLAY_RUN1,0,0}, // S_PIGPLAY_RUN4
+{SPR_PIGY,0,12,NULL,S_PIGPLAY,0,0}, // S_PIGPLAY_ATK1
+{SPR_PIGY,3,4,A_PigPain,S_PIGPLAY,0,0}, // S_PIGPLAY_PAIN
+{SPR_PIGY,1,10,A_PigLook,S_PIG_LOOK1,0,0}, // S_PIG_LOOK1
+{SPR_PIGY,0,3,A_PigChase,S_PIG_WALK2,0,0}, // S_PIG_WALK1
+{SPR_PIGY,1,3,A_PigChase,S_PIG_WALK3,0,0}, // S_PIG_WALK2
+{SPR_PIGY,2,3,A_PigChase,S_PIG_WALK4,0,0}, // S_PIG_WALK3
+{SPR_PIGY,3,3,A_PigChase,S_PIG_WALK1,0,0}, // S_PIG_WALK4
+{SPR_PIGY,3,4,A_PigPain,S_PIG_WALK1,0,0}, // S_PIG_PAIN
+{SPR_PIGY,0,5,A_FaceTarget,S_PIG_ATK2,0,0}, // S_PIG_ATK1
+{SPR_PIGY,0,10,A_PigAttack,S_PIG_WALK1,0,0}, // S_PIG_ATK2
+{SPR_PIGY,4,4,A_Scream,S_PIG_DIE2,0,0}, // S_PIG_DIE1
+{SPR_PIGY,5,3,A_NoBlocking,S_PIG_DIE3,0,0}, // S_PIG_DIE2
+{SPR_PIGY,6,4,A_QueueCorpse,S_PIG_DIE4,0,0}, // S_PIG_DIE3
+{SPR_PIGY,7,3,NULL,S_PIG_DIE5,0,0}, // S_PIG_DIE4
+{SPR_PIGY,8,4,NULL,S_PIG_DIE6,0,0}, // S_PIG_DIE5
+{SPR_PIGY,9,4,NULL,S_PIG_DIE7,0,0}, // S_PIG_DIE6
+{SPR_PIGY,10,4,NULL,S_PIG_DIE8,0,0}, // S_PIG_DIE7
+{SPR_PIGY,11,-1,NULL,S_NULL,0,0}, // S_PIG_DIE8
+{SPR_PIGY,12,5,A_FreezeDeath,S_PIG_ICE2,0,0}, // S_PIG_ICE
+{SPR_PIGY,12,1,A_FreezeDeathChunks,S_PIG_ICE2,0,0}, // S_PIG_ICE2
+{SPR_CENT,0,10,A_Look,S_CENTAUR_LOOK2,0,0}, // S_CENTAUR_LOOK1
+{SPR_CENT,1,10,A_Look,S_CENTAUR_LOOK1,0,0}, // S_CENTAUR_LOOK2
+{SPR_CENT,0,4,A_Chase,S_CENTAUR_WALK2,0,0}, // S_CENTAUR_WALK1
+{SPR_CENT,1,4,A_Chase,S_CENTAUR_WALK3,0,0}, // S_CENTAUR_WALK2
+{SPR_CENT,2,4,A_Chase,S_CENTAUR_WALK4,0,0}, // S_CENTAUR_WALK3
+{SPR_CENT,3,4,A_Chase,S_CENTAUR_WALK1,0,0}, // S_CENTAUR_WALK4
+{SPR_CENT,7,5,A_FaceTarget,S_CENTAUR_ATK2,0,0}, // S_CENTAUR_ATK1
+{SPR_CENT,8,4,A_FaceTarget,S_CENTAUR_ATK3,0,0}, // S_CENTAUR_ATK2
+{SPR_CENT,9,7,A_CentaurAttack,S_CENTAUR_WALK1,0,0}, // S_CENTAUR_ATK3
+{SPR_CENT,4,10,A_FaceTarget,S_CENTAUR_MISSILE2,0,0}, // S_CENTAUR_MISSILE1
+{SPR_CENT,32773,8,A_CentaurAttack2,S_CENTAUR_MISSILE3,0,0}, // S_CENTAUR_MISSILE2
+{SPR_CENT,4,10,A_FaceTarget,S_CENTAUR_MISSILE4,0,0}, // S_CENTAUR_MISSILE3
+{SPR_CENT,32773,8,A_CentaurAttack2,S_CENTAUR_WALK1,0,0}, // S_CENTAUR_MISSILE4
+{SPR_CENT,6,6,A_Pain,S_CENTAUR_PAIN2,0,0}, // S_CENTAUR_PAIN1
+{SPR_CENT,6,6,A_SetReflective,S_CENTAUR_PAIN3,0,0}, // S_CENTAUR_PAIN2
+{SPR_CENT,4,15,A_CentaurDefend,S_CENTAUR_PAIN4,0,0}, // S_CENTAUR_PAIN3
+{SPR_CENT,4,15,A_CentaurDefend,S_CENTAUR_PAIN5,0,0}, // S_CENTAUR_PAIN4
+{SPR_CENT,4,15,A_CentaurDefend,S_CENTAUR_PAIN6,0,0}, // S_CENTAUR_PAIN5
+{SPR_CENT,4,1,A_UnSetReflective,S_CENTAUR_WALK1,0,0}, // S_CENTAUR_PAIN6
+{SPR_CENT,10,4,NULL,S_CENTAUR_DEATH2,0,0}, // S_CENTAUR_DEATH1
+{SPR_CENT,11,4,A_Scream,S_CENTAUR_DEATH3,0,0}, // S_CENTAUR_DEATH2
+{SPR_CENT,12,4,NULL,S_CENTAUR_DEATH4,0,0}, // S_CENTAUR_DEATH3
+{SPR_CENT,13,4,NULL,S_CENTAUR_DEATH5,0,0}, // S_CENTAUR_DEATH4
+{SPR_CENT,14,4,A_NoBlocking,S_CENTAUR_DEATH6,0,0}, // S_CENTAUR_DEATH5
+{SPR_CENT,15,4,NULL,S_CENTAUR_DEATH7,0,0}, // S_CENTAUR_DEATH6
+{SPR_CENT,16,4,NULL,S_CENTAUR_DEATH8,0,0}, // S_CENTAUR_DEATH7
+{SPR_CENT,17,4,A_QueueCorpse,S_CENTAUR_DEATH9,0,0}, // S_CENTAUR_DEATH8
+{SPR_CENT,18,4,NULL,S_CENTAUR_DEATH0,0,0}, // S_CENTAUR_DEATH9
+{SPR_CENT,19,-1,NULL,S_NULL,0,0}, // S_CENTAUR_DEATH0
+{SPR_CTXD,0,4,NULL,S_CENTAUR_DEATH_X2,0,0}, // S_CENTAUR_DEATH_X1
+{SPR_CTXD,1,4,A_NoBlocking,S_CENTAUR_DEATH_X3,0,0}, // S_CENTAUR_DEATH_X2
+{SPR_CTXD,2,4,A_CentaurDropStuff,S_CENTAUR_DEATH_X4,0,0}, // S_CENTAUR_DEATH_X3
+{SPR_CTXD,3,3,A_Scream,S_CENTAUR_DEATH_X5,0,0}, // S_CENTAUR_DEATH_X4
+{SPR_CTXD,4,4,A_QueueCorpse,S_CENTAUR_DEATH_X6,0,0}, // S_CENTAUR_DEATH_X5
+{SPR_CTXD,5,3,NULL,S_CENTAUR_DEATH_X7,0,0}, // S_CENTAUR_DEATH_X6
+{SPR_CTXD,6,4,NULL,S_CENTAUR_DEATH_X8,0,0}, // S_CENTAUR_DEATH_X7
+{SPR_CTXD,7,3,NULL,S_CENTAUR_DEATH_X9,0,0}, // S_CENTAUR_DEATH_X8
+{SPR_CTXD,8,4,NULL,S_CENTAUR_DEATH_X10,0,0}, // S_CENTAUR_DEATH_X9
+{SPR_CTXD,9,3,NULL,S_CENTAUR_DEATH_X11,0,0}, // S_CENTAUR_DEATH_X10
+{SPR_CTXD,10,-1,NULL,S_NULL,0,0}, // S_CENTAUR_DEATH_X11
+{SPR_CENT,20,5,A_FreezeDeath,S_CENTAUR_ICE2,0,0}, // S_CENTAUR_ICE
+{SPR_CENT,20,1,A_FreezeDeathChunks,S_CENTAUR_ICE2,0,0}, // S_CENTAUR_ICE2
+{SPR_CTFX,32768,-1,NULL,S_NULL,0,0}, // S_CENTAUR_FX1
+{SPR_CTFX,32769,4,NULL,S_CENTAUR_FX_X2,0,0}, // S_CENTAUR_FX_X1
+{SPR_CTFX,32770,3,NULL,S_CENTAUR_FX_X3,0,0}, // S_CENTAUR_FX_X2
+{SPR_CTFX,32771,4,NULL,S_CENTAUR_FX_X4,0,0}, // S_CENTAUR_FX_X3
+{SPR_CTFX,32772,3,NULL,S_CENTAUR_FX_X5,0,0}, // S_CENTAUR_FX_X4
+{SPR_CTFX,32773,2,NULL,S_NULL,0,0}, // S_CENTAUR_FX_X5
+{SPR_CTDP,0,3,A_CheckFloor,S_CENTAUR_SHIELD2,0,0}, // S_CENTAUR_SHIELD1
+{SPR_CTDP,1,3,A_CheckFloor,S_CENTAUR_SHIELD3,0,0}, // S_CENTAUR_SHIELD2
+{SPR_CTDP,2,3,A_CheckFloor,S_CENTAUR_SHIELD4,0,0}, // S_CENTAUR_SHIELD3
+{SPR_CTDP,3,3,A_CheckFloor,S_CENTAUR_SHIELD5,0,0}, // S_CENTAUR_SHIELD4
+{SPR_CTDP,4,3,A_CheckFloor,S_CENTAUR_SHIELD6,0,0}, // S_CENTAUR_SHIELD5
+{SPR_CTDP,5,3,A_CheckFloor,S_CENTAUR_SHIELD3,0,0}, // S_CENTAUR_SHIELD6
+{SPR_CTDP,6,4,NULL,S_CENTAUR_SHIELD_X2,0,0}, // S_CENTAUR_SHIELD_X1
+{SPR_CTDP,7,4,A_QueueCorpse,S_CENTAUR_SHIELD_X3,0,0}, // S_CENTAUR_SHIELD_X2
+{SPR_CTDP,8,4,NULL,S_CENTAUR_SHIELD_X4,0,0}, // S_CENTAUR_SHIELD_X3
+{SPR_CTDP,9,-1,NULL,S_NULL,0,0}, // S_CENTAUR_SHIELD_X4
+{SPR_CTDP,10,3,A_CheckFloor,S_CENTAUR_SWORD2,0,0}, // S_CENTAUR_SWORD1
+{SPR_CTDP,11,3,A_CheckFloor,S_CENTAUR_SWORD3,0,0}, // S_CENTAUR_SWORD2
+{SPR_CTDP,12,3,A_CheckFloor,S_CENTAUR_SWORD4,0,0}, // S_CENTAUR_SWORD3
+{SPR_CTDP,13,3,A_CheckFloor,S_CENTAUR_SWORD5,0,0}, // S_CENTAUR_SWORD4
+{SPR_CTDP,14,3,A_CheckFloor,S_CENTAUR_SWORD6,0,0}, // S_CENTAUR_SWORD5
+{SPR_CTDP,15,3,A_CheckFloor,S_CENTAUR_SWORD7,0,0}, // S_CENTAUR_SWORD6
+{SPR_CTDP,16,3,A_CheckFloor,S_CENTAUR_SWORD3,0,0}, // S_CENTAUR_SWORD7
+{SPR_CTDP,17,4,NULL,S_CENTAUR_SWORD_X2,0,0}, // S_CENTAUR_SWORD_X1
+{SPR_CTDP,18,4,A_QueueCorpse,S_CENTAUR_SWORD_X3,0,0}, // S_CENTAUR_SWORD_X2
+{SPR_CTDP,19,-1,NULL,S_NULL,0,0}, // S_CENTAUR_SWORD_X3
+{SPR_DEMN,0,10,A_Look,S_DEMN_LOOK2,0,0}, // S_DEMN_LOOK1
+{SPR_DEMN,0,10,A_Look,S_DEMN_LOOK1,0,0}, // S_DEMN_LOOK2
+{SPR_DEMN,0,4,A_Chase,S_DEMN_CHASE2,0,0}, // S_DEMN_CHASE1
+{SPR_DEMN,1,4,A_Chase,S_DEMN_CHASE3,0,0}, // S_DEMN_CHASE2
+{SPR_DEMN,2,4,A_Chase,S_DEMN_CHASE4,0,0}, // S_DEMN_CHASE3
+{SPR_DEMN,3,4,A_Chase,S_DEMN_CHASE1,0,0}, // S_DEMN_CHASE4
+{SPR_DEMN,4,6,A_FaceTarget,S_DEMN_ATK1_2,0,0}, // S_DEMN_ATK1_1
+{SPR_DEMN,5,8,A_FaceTarget,S_DEMN_ATK1_3,0,0}, // S_DEMN_ATK1_2
+{SPR_DEMN,6,6,A_DemonAttack1,S_DEMN_CHASE1,0,0}, // S_DEMN_ATK1_3
+{SPR_DEMN,4,5,A_FaceTarget,S_DEMN_ATK2_2,0,0}, // S_DEMN_ATK2_1
+{SPR_DEMN,5,6,A_FaceTarget,S_DEMN_ATK2_3,0,0}, // S_DEMN_ATK2_2
+{SPR_DEMN,6,5,A_DemonAttack2,S_DEMN_CHASE1,0,0}, // S_DEMN_ATK2_3
+{SPR_DEMN,4,4,NULL,S_DEMN_PAIN2,0,0}, // S_DEMN_PAIN1
+{SPR_DEMN,4,4,A_Pain,S_DEMN_CHASE1,0,0}, // S_DEMN_PAIN2
+{SPR_DEMN,7,6,NULL,S_DEMN_DEATH2,0,0}, // S_DEMN_DEATH1
+{SPR_DEMN,8,6,NULL,S_DEMN_DEATH3,0,0}, // S_DEMN_DEATH2
+{SPR_DEMN,9,6,A_Scream,S_DEMN_DEATH4,0,0}, // S_DEMN_DEATH3
+{SPR_DEMN,10,6,A_NoBlocking,S_DEMN_DEATH5,0,0}, // S_DEMN_DEATH4
+{SPR_DEMN,11,6,A_QueueCorpse,S_DEMN_DEATH6,0,0}, // S_DEMN_DEATH5
+{SPR_DEMN,12,6,NULL,S_DEMN_DEATH7,0,0}, // S_DEMN_DEATH6
+{SPR_DEMN,13,6,NULL,S_DEMN_DEATH8,0,0}, // S_DEMN_DEATH7
+{SPR_DEMN,14,6,NULL,S_DEMN_DEATH9,0,0}, // S_DEMN_DEATH8
+{SPR_DEMN,15,-1,NULL,S_NULL,0,0}, // S_DEMN_DEATH9
+{SPR_DEMN,7,6,NULL,S_DEMN_XDEATH2,0,0}, // S_DEMN_XDEATH1
+{SPR_DEMN,8,6,A_DemonDeath,S_DEMN_XDEATH3,0,0}, // S_DEMN_XDEATH2
+{SPR_DEMN,9,6,A_Scream,S_DEMN_XDEATH4,0,0}, // S_DEMN_XDEATH3
+{SPR_DEMN,10,6,A_NoBlocking,S_DEMN_XDEATH5,0,0}, // S_DEMN_XDEATH4
+{SPR_DEMN,11,6,A_QueueCorpse,S_DEMN_XDEATH6,0,0}, // S_DEMN_XDEATH5
+{SPR_DEMN,12,6,NULL,S_DEMN_XDEATH7,0,0}, // S_DEMN_XDEATH6
+{SPR_DEMN,13,6,NULL,S_DEMN_XDEATH8,0,0}, // S_DEMN_XDEATH7
+{SPR_DEMN,14,6,NULL,S_DEMN_XDEATH9,0,0}, // S_DEMN_XDEATH8
+{SPR_DEMN,15,-1,NULL,S_NULL,0,0}, // S_DEMN_XDEATH9
+{SPR_DEMN,16,5,A_FreezeDeath,S_DEMON_ICE2,0,0}, // S_DEMON_ICE
+{SPR_DEMN,16,1,A_FreezeDeathChunks,S_DEMON_ICE2,0,0}, // S_DEMON_ICE2
+{SPR_DEMA,0,4,NULL,S_DEMONCHUNK1_2,0,0}, // S_DEMONCHUNK1_1
+{SPR_DEMA,0,10,A_QueueCorpse,S_DEMONCHUNK1_3,0,0}, // S_DEMONCHUNK1_2
+{SPR_DEMA,0,20,NULL,S_DEMONCHUNK1_3,0,0}, // S_DEMONCHUNK1_3
+{SPR_DEMA,0,-1,NULL,S_NULL,0,0}, // S_DEMONCHUNK1_4
+{SPR_DEMB,0,4,NULL,S_DEMONCHUNK2_2,0,0}, // S_DEMONCHUNK2_1
+{SPR_DEMB,0,10,A_QueueCorpse,S_DEMONCHUNK2_3,0,0}, // S_DEMONCHUNK2_2
+{SPR_DEMB,0,20,NULL,S_DEMONCHUNK2_3,0,0}, // S_DEMONCHUNK2_3
+{SPR_DEMB,0,-1,NULL,S_NULL,0,0}, // S_DEMONCHUNK2_4
+{SPR_DEMC,0,4,NULL,S_DEMONCHUNK3_2,0,0}, // S_DEMONCHUNK3_1
+{SPR_DEMC,0,10,A_QueueCorpse,S_DEMONCHUNK3_3,0,0}, // S_DEMONCHUNK3_2
+{SPR_DEMC,0,20,NULL,S_DEMONCHUNK3_3,0,0}, // S_DEMONCHUNK3_3
+{SPR_DEMC,0,-1,NULL,S_NULL,0,0}, // S_DEMONCHUNK3_4
+{SPR_DEMD,0,4,NULL,S_DEMONCHUNK4_2,0,0}, // S_DEMONCHUNK4_1
+{SPR_DEMD,0,10,A_QueueCorpse,S_DEMONCHUNK4_3,0,0}, // S_DEMONCHUNK4_2
+{SPR_DEMD,0,20,NULL,S_DEMONCHUNK4_3,0,0}, // S_DEMONCHUNK4_3
+{SPR_DEMD,0,-1,NULL,S_NULL,0,0}, // S_DEMONCHUNK4_4
+{SPR_DEME,0,4,NULL,S_DEMONCHUNK5_2,0,0}, // S_DEMONCHUNK5_1
+{SPR_DEME,0,10,A_QueueCorpse,S_DEMONCHUNK5_3,0,0}, // S_DEMONCHUNK5_2
+{SPR_DEME,0,20,NULL,S_DEMONCHUNK5_3,0,0}, // S_DEMONCHUNK5_3
+{SPR_DEME,0,-1,NULL,S_NULL,0,0}, // S_DEMONCHUNK5_4
+{SPR_DMFX,32768,4,NULL,S_DEMONFX_MOVE2,0,0}, // S_DEMONFX_MOVE1
+{SPR_DMFX,32769,4,NULL,S_DEMONFX_MOVE3,0,0}, // S_DEMONFX_MOVE2
+{SPR_DMFX,32770,4,NULL,S_DEMONFX_MOVE1,0,0}, // S_DEMONFX_MOVE3
+{SPR_DMFX,32771,4,NULL,S_DEMONFX_BOOM2,0,0}, // S_DEMONFX_BOOM1
+{SPR_DMFX,32772,4,NULL,S_DEMONFX_BOOM3,0,0}, // S_DEMONFX_BOOM2
+{SPR_DMFX,32773,3,NULL,S_DEMONFX_BOOM4,0,0}, // S_DEMONFX_BOOM3
+{SPR_DMFX,32774,3,NULL,S_DEMONFX_BOOM5,0,0}, // S_DEMONFX_BOOM4
+{SPR_DMFX,32775,3,NULL,S_NULL,0,0}, // S_DEMONFX_BOOM5
+{SPR_DEM2,0,10,A_Look,S_DEMN2_LOOK2,0,0}, // S_DEMN2_LOOK1
+{SPR_DEM2,0,10,A_Look,S_DEMN2_LOOK1,0,0}, // S_DEMN2_LOOK2
+{SPR_DEM2,0,4,A_Chase,S_DEMN2_CHASE2,0,0}, // S_DEMN2_CHASE1
+{SPR_DEM2,1,4,A_Chase,S_DEMN2_CHASE3,0,0}, // S_DEMN2_CHASE2
+{SPR_DEM2,2,4,A_Chase,S_DEMN2_CHASE4,0,0}, // S_DEMN2_CHASE3
+{SPR_DEM2,3,4,A_Chase,S_DEMN2_CHASE1,0,0}, // S_DEMN2_CHASE4
+{SPR_DEM2,4,6,A_FaceTarget,S_DEMN2_ATK1_2,0,0}, // S_DEMN2_ATK1_1
+{SPR_DEM2,5,8,A_FaceTarget,S_DEMN2_ATK1_3,0,0}, // S_DEMN2_ATK1_2
+{SPR_DEM2,6,6,A_DemonAttack1,S_DEMN2_CHASE1,0,0}, // S_DEMN2_ATK1_3
+{SPR_DEM2,4,5,A_FaceTarget,S_DEMN2_ATK2_2,0,0}, // S_DEMN2_ATK2_1
+{SPR_DEM2,5,6,A_FaceTarget,S_DEMN2_ATK2_3,0,0}, // S_DEMN2_ATK2_2
+{SPR_DEM2,6,5,A_DemonAttack2,S_DEMN2_CHASE1,0,0}, // S_DEMN2_ATK2_3
+{SPR_DEM2,4,4,NULL,S_DEMN2_PAIN2,0,0}, // S_DEMN2_PAIN1
+{SPR_DEM2,4,4,A_Pain,S_DEMN2_CHASE1,0,0}, // S_DEMN2_PAIN2
+{SPR_DEM2,7,6,NULL,S_DEMN2_DEATH2,0,0}, // S_DEMN2_DEATH1
+{SPR_DEM2,8,6,NULL,S_DEMN2_DEATH3,0,0}, // S_DEMN2_DEATH2
+{SPR_DEM2,9,6,A_Scream,S_DEMN2_DEATH4,0,0}, // S_DEMN2_DEATH3
+{SPR_DEM2,10,6,A_NoBlocking,S_DEMN2_DEATH5,0,0}, // S_DEMN2_DEATH4
+{SPR_DEM2,11,6,A_QueueCorpse,S_DEMN2_DEATH6,0,0}, // S_DEMN2_DEATH5
+{SPR_DEM2,12,6,NULL,S_DEMN2_DEATH7,0,0}, // S_DEMN2_DEATH6
+{SPR_DEM2,13,6,NULL,S_DEMN2_DEATH8,0,0}, // S_DEMN2_DEATH7
+{SPR_DEM2,14,6,NULL,S_DEMN2_DEATH9,0,0}, // S_DEMN2_DEATH8
+{SPR_DEM2,15,-1,NULL,S_NULL,0,0}, // S_DEMN2_DEATH9
+{SPR_DEM2,7,6,NULL,S_DEMN2_XDEATH2,0,0}, // S_DEMN2_XDEATH1
+{SPR_DEM2,8,6,A_Demon2Death,S_DEMN2_XDEATH3,0,0}, // S_DEMN2_XDEATH2
+{SPR_DEM2,9,6,A_Scream,S_DEMN2_XDEATH4,0,0}, // S_DEMN2_XDEATH3
+{SPR_DEM2,10,6,A_NoBlocking,S_DEMN2_XDEATH5,0,0}, // S_DEMN2_XDEATH4
+{SPR_DEM2,11,6,A_QueueCorpse,S_DEMN2_XDEATH6,0,0}, // S_DEMN2_XDEATH5
+{SPR_DEM2,12,6,NULL,S_DEMN2_XDEATH7,0,0}, // S_DEMN2_XDEATH6
+{SPR_DEM2,13,6,NULL,S_DEMN2_XDEATH8,0,0}, // S_DEMN2_XDEATH7
+{SPR_DEM2,14,6,NULL,S_DEMN2_XDEATH9,0,0}, // S_DEMN2_XDEATH8
+{SPR_DEM2,15,-1,NULL,S_NULL,0,0}, // S_DEMN2_XDEATH9
+{SPR_DMBA,0,4,NULL,S_DEMON2CHUNK1_2,0,0}, // S_DEMON2CHUNK1_1
+{SPR_DMBA,0,10,A_QueueCorpse,S_DEMON2CHUNK1_3,0,0}, // S_DEMON2CHUNK1_2
+{SPR_DMBA,0,20,NULL,S_DEMON2CHUNK1_3,0,0}, // S_DEMON2CHUNK1_3
+{SPR_DMBA,0,-1,NULL,S_NULL,0,0}, // S_DEMON2CHUNK1_4
+{SPR_DMBB,0,4,NULL,S_DEMON2CHUNK2_2,0,0}, // S_DEMON2CHUNK2_1
+{SPR_DMBB,0,10,A_QueueCorpse,S_DEMON2CHUNK2_3,0,0}, // S_DEMON2CHUNK2_2
+{SPR_DMBB,0,20,NULL,S_DEMON2CHUNK2_3,0,0}, // S_DEMON2CHUNK2_3
+{SPR_DMBB,0,-1,NULL,S_NULL,0,0}, // S_DEMON2CHUNK2_4
+{SPR_DMBC,0,4,NULL,S_DEMON2CHUNK3_2,0,0}, // S_DEMON2CHUNK3_1
+{SPR_DMBC,0,10,A_QueueCorpse,S_DEMON2CHUNK3_3,0,0}, // S_DEMON2CHUNK3_2
+{SPR_DMBC,0,20,NULL,S_DEMON2CHUNK3_3,0,0}, // S_DEMON2CHUNK3_3
+{SPR_DMBC,0,-1,NULL,S_NULL,0,0}, // S_DEMON2CHUNK3_4
+{SPR_DMBD,0,4,NULL,S_DEMON2CHUNK4_2,0,0}, // S_DEMON2CHUNK4_1
+{SPR_DMBD,0,10,A_QueueCorpse,S_DEMON2CHUNK4_3,0,0}, // S_DEMON2CHUNK4_2
+{SPR_DMBD,0,20,NULL,S_DEMON2CHUNK4_3,0,0}, // S_DEMON2CHUNK4_3
+{SPR_DMBD,0,-1,NULL,S_NULL,0,0}, // S_DEMON2CHUNK4_4
+{SPR_DMBE,0,4,NULL,S_DEMON2CHUNK5_2,0,0}, // S_DEMON2CHUNK5_1
+{SPR_DMBE,0,10,NULL,S_DEMON2CHUNK5_3,0,0}, // S_DEMON2CHUNK5_2
+{SPR_DMBE,0,20,NULL,S_DEMON2CHUNK5_3,0,0}, // S_DEMON2CHUNK5_3
+{SPR_DMBE,0,-1,NULL,S_NULL,0,0}, // S_DEMON2CHUNK5_4
+{SPR_D2FX,32768,4,NULL,S_DEMON2FX_MOVE2,0,0}, // S_DEMON2FX_MOVE1
+{SPR_D2FX,32769,4,NULL,S_DEMON2FX_MOVE3,0,0}, // S_DEMON2FX_MOVE2
+{SPR_D2FX,32770,4,NULL,S_DEMON2FX_MOVE4,0,0}, // S_DEMON2FX_MOVE3
+{SPR_D2FX,32771,4,NULL,S_DEMON2FX_MOVE5,0,0}, // S_DEMON2FX_MOVE4
+{SPR_D2FX,32772,4,NULL,S_DEMON2FX_MOVE6,0,0}, // S_DEMON2FX_MOVE5
+{SPR_D2FX,32773,4,NULL,S_DEMON2FX_MOVE1,0,0}, // S_DEMON2FX_MOVE6
+{SPR_D2FX,32774,4,NULL,S_DEMON2FX_BOOM2,0,0}, // S_DEMON2FX_BOOM1
+{SPR_D2FX,32775,4,NULL,S_DEMON2FX_BOOM3,0,0}, // S_DEMON2FX_BOOM2
+{SPR_D2FX,32776,4,NULL,S_DEMON2FX_BOOM4,0,0}, // S_DEMON2FX_BOOM3
+{SPR_D2FX,32777,4,NULL,S_DEMON2FX_BOOM5,0,0}, // S_DEMON2FX_BOOM4
+{SPR_D2FX,32778,3,NULL,S_DEMON2FX_BOOM6,0,0}, // S_DEMON2FX_BOOM5
+{SPR_D2FX,32779,3,NULL,S_NULL,0,0}, // S_DEMON2FX_BOOM6
+{SPR_WRTH,0,2,A_WraithRaiseInit,S_WRAITH_RAISE2,0,0}, // S_WRAITH_RAISE1
+{SPR_WRTH,0,2,A_WraithRaise,S_WRAITH_RAISE3,0,0}, // S_WRAITH_RAISE2
+{SPR_WRTH,0,2,A_FaceTarget,S_WRAITH_RAISE4,0,0}, // S_WRAITH_RAISE3
+{SPR_WRTH,1,2,A_WraithRaise,S_WRAITH_RAISE5,0,0}, // S_WRAITH_RAISE4
+{SPR_WRTH,1,2,A_WraithRaise,S_WRAITH_RAISE2,0,0}, // S_WRAITH_RAISE5
+{SPR_WRTH,0,10,NULL,S_WRAITH_INIT2,0,0}, // S_WRAITH_INIT1
+{SPR_WRTH,1,5,A_WraithInit,S_WRAITH_LOOK1,0,0}, // S_WRAITH_INIT2
+{SPR_WRTH,0,15,A_WraithLook,S_WRAITH_LOOK2,0,0}, // S_WRAITH_LOOK1
+{SPR_WRTH,1,15,A_WraithLook,S_WRAITH_LOOK1,0,0}, // S_WRAITH_LOOK2
+{SPR_WRTH,0,4,A_WraithChase,S_WRAITH_CHASE2,0,0}, // S_WRAITH_CHASE1
+{SPR_WRTH,1,4,A_WraithChase,S_WRAITH_CHASE3,0,0}, // S_WRAITH_CHASE2
+{SPR_WRTH,2,4,A_WraithChase,S_WRAITH_CHASE4,0,0}, // S_WRAITH_CHASE3
+{SPR_WRTH,3,4,A_WraithChase,S_WRAITH_CHASE1,0,0}, // S_WRAITH_CHASE4
+{SPR_WRTH,4,6,A_FaceTarget,S_WRAITH_ATK1_2,0,0}, // S_WRAITH_ATK1_1
+{SPR_WRTH,5,6,A_WraithFX3,S_WRAITH_ATK1_3,0,0}, // S_WRAITH_ATK1_2
+{SPR_WRTH,6,6,A_WraithMelee,S_WRAITH_CHASE1,0,0}, // S_WRAITH_ATK1_3
+{SPR_WRTH,4,6,A_FaceTarget,S_WRAITH_ATK2_2,0,0}, // S_WRAITH_ATK2_1
+{SPR_WRTH,5,6,NULL,S_WRAITH_ATK2_3,0,0}, // S_WRAITH_ATK2_2
+{SPR_WRTH,6,6,A_WraithMissile,S_WRAITH_CHASE1,0,0}, // S_WRAITH_ATK2_3
+{SPR_WRTH,0,2,NULL,S_WRAITH_PAIN2,0,0}, // S_WRAITH_PAIN1
+{SPR_WRTH,7,6,A_Pain,S_WRAITH_CHASE1,0,0}, // S_WRAITH_PAIN2
+{SPR_WRTH,8,4,NULL,S_WRAITH_DEATH1_2,0,0}, // S_WRAITH_DEATH1_1
+{SPR_WRTH,9,4,A_Scream,S_WRAITH_DEATH1_3,0,0}, // S_WRAITH_DEATH1_2
+{SPR_WRTH,10,4,NULL,S_WRAITH_DEATH1_4,0,0}, // S_WRAITH_DEATH1_3
+{SPR_WRTH,11,4,NULL,S_WRAITH_DEATH1_5,0,0}, // S_WRAITH_DEATH1_4
+{SPR_WRTH,12,4,A_NoBlocking,S_WRAITH_DEATH1_6,0,0}, // S_WRAITH_DEATH1_5
+{SPR_WRTH,13,4,A_QueueCorpse,S_WRAITH_DEATH1_7,0,0}, // S_WRAITH_DEATH1_6
+{SPR_WRTH,14,4,NULL,S_WRAITH_DEATH1_8,0,0}, // S_WRAITH_DEATH1_7
+{SPR_WRTH,15,5,NULL,S_WRAITH_DEATH1_9,0,0}, // S_WRAITH_DEATH1_8
+{SPR_WRTH,16,5,NULL,S_WRAITH_DEATH1_0,0,0}, // S_WRAITH_DEATH1_9
+{SPR_WRTH,17,-1,NULL,S_NULL,0,0}, // S_WRAITH_DEATH1_0
+{SPR_WRT2,0,5,NULL,S_WRAITH_DEATH2_2,0,0}, // S_WRAITH_DEATH2_1
+{SPR_WRT2,1,5,A_Scream,S_WRAITH_DEATH2_3,0,0}, // S_WRAITH_DEATH2_2
+{SPR_WRT2,2,5,NULL,S_WRAITH_DEATH2_4,0,0}, // S_WRAITH_DEATH2_3
+{SPR_WRT2,3,5,NULL,S_WRAITH_DEATH2_5,0,0}, // S_WRAITH_DEATH2_4
+{SPR_WRT2,4,5,A_NoBlocking,S_WRAITH_DEATH2_6,0,0}, // S_WRAITH_DEATH2_5
+{SPR_WRT2,5,5,A_QueueCorpse,S_WRAITH_DEATH2_7,0,0}, // S_WRAITH_DEATH2_6
+{SPR_WRT2,6,5,NULL,S_WRAITH_DEATH2_8,0,0}, // S_WRAITH_DEATH2_7
+{SPR_WRT2,7,-1,NULL,S_NULL,0,0}, // S_WRAITH_DEATH2_8
+{SPR_WRT2,8,5,A_FreezeDeath,S_WRAITH_ICE2,0,0}, // S_WRAITH_ICE
+{SPR_WRT2,8,1,A_FreezeDeathChunks,S_WRAITH_ICE2,0,0}, // S_WRAITH_ICE2
+{SPR_WRBL,32768,3,NULL,S_WRTHFX_MOVE2,0,0}, // S_WRTHFX_MOVE1
+{SPR_WRBL,32769,3,A_WraithFX2,S_WRTHFX_MOVE3,0,0}, // S_WRTHFX_MOVE2
+{SPR_WRBL,32770,3,NULL,S_WRTHFX_MOVE1,0,0}, // S_WRTHFX_MOVE3
+{SPR_WRBL,32771,4,NULL,S_WRTHFX_BOOM2,0,0}, // S_WRTHFX_BOOM1
+{SPR_WRBL,32772,4,A_WraithFX2,S_WRTHFX_BOOM3,0,0}, // S_WRTHFX_BOOM2
+{SPR_WRBL,32773,4,NULL,S_WRTHFX_BOOM4,0,0}, // S_WRTHFX_BOOM3
+{SPR_WRBL,32774,3,A_WraithFX2,S_WRTHFX_BOOM5,0,0}, // S_WRTHFX_BOOM4
+{SPR_WRBL,32775,3,A_WraithFX2,S_WRTHFX_BOOM6,0,0}, // S_WRTHFX_BOOM5
+{SPR_WRBL,32776,3,NULL,S_NULL,0,0}, // S_WRTHFX_BOOM6
+{SPR_WRBL,32777,4,NULL,S_WRTHFX_SIZZLE2,0,0}, // S_WRTHFX_SIZZLE1
+{SPR_WRBL,32778,4,NULL,S_WRTHFX_SIZZLE3,0,0}, // S_WRTHFX_SIZZLE2
+{SPR_WRBL,32779,4,NULL,S_WRTHFX_SIZZLE4,0,0}, // S_WRTHFX_SIZZLE3
+{SPR_WRBL,32780,4,NULL,S_WRTHFX_SIZZLE5,0,0}, // S_WRTHFX_SIZZLE4
+{SPR_WRBL,32781,4,NULL,S_WRTHFX_SIZZLE6,0,0}, // S_WRTHFX_SIZZLE5
+{SPR_WRBL,32782,4,NULL,S_WRTHFX_SIZZLE7,0,0}, // S_WRTHFX_SIZZLE6
+{SPR_WRBL,32783,4,NULL,S_NULL,0,0}, // S_WRTHFX_SIZZLE7
+{SPR_WRBL,32784,4,NULL,S_WRTHFX_DROP2,0,0}, // S_WRTHFX_DROP1
+{SPR_WRBL,32785,4,NULL,S_WRTHFX_DROP3,0,0}, // S_WRTHFX_DROP2
+{SPR_WRBL,32786,4,NULL,S_WRTHFX_DROP1,0,0}, // S_WRTHFX_DROP3
+{SPR_WRBL,32786,4,NULL,S_NULL,0,0}, // S_WRTHFX_DEAD1
+{SPR_WRBL,19,4,NULL,S_WRTHFX_ADROP2,0,0}, // S_WRTHFX_ADROP1
+{SPR_WRBL,20,4,NULL,S_WRTHFX_ADROP3,0,0}, // S_WRTHFX_ADROP2
+{SPR_WRBL,21,4,NULL,S_WRTHFX_ADROP4,0,0}, // S_WRTHFX_ADROP3
+{SPR_WRBL,22,4,NULL,S_WRTHFX_ADROP1,0,0}, // S_WRTHFX_ADROP4
+{SPR_WRBL,22,10,NULL,S_NULL,0,0}, // S_WRTHFX_ADEAD1
+{SPR_WRBL,23,7,NULL,S_WRTHFX_BDROP2,0,0}, // S_WRTHFX_BDROP1
+{SPR_WRBL,24,7,NULL,S_WRTHFX_BDROP3,0,0}, // S_WRTHFX_BDROP2
+{SPR_WRBL,25,7,NULL,S_WRTHFX_BDROP1,0,0}, // S_WRTHFX_BDROP3
+{SPR_WRBL,25,35,NULL,S_NULL,0,0}, // S_WRTHFX_BDEAD1
+{SPR_MNTR,0,15,NULL,S_MNTR_SPAWN2,0,0}, // S_MNTR_SPAWN1
+{SPR_MNTR,0,15,A_MinotaurFade1,S_MNTR_SPAWN3,0,0}, // S_MNTR_SPAWN2
+{SPR_MNTR,0,3,A_MinotaurFade2,S_MNTR_LOOK1,0,0}, // S_MNTR_SPAWN3
+{SPR_MNTR,0,10,A_MinotaurLook,S_MNTR_LOOK2,0,0}, // S_MNTR_LOOK1
+{SPR_MNTR,1,10,A_MinotaurLook,S_MNTR_LOOK1,0,0}, // S_MNTR_LOOK2
+{SPR_MNTR,0,5,A_MinotaurChase,S_MNTR_WALK2,0,0}, // S_MNTR_WALK1
+{SPR_MNTR,1,5,A_MinotaurChase,S_MNTR_WALK3,0,0}, // S_MNTR_WALK2
+{SPR_MNTR,2,5,A_MinotaurChase,S_MNTR_WALK4,0,0}, // S_MNTR_WALK3
+{SPR_MNTR,3,5,A_MinotaurChase,S_MNTR_WALK1,0,0}, // S_MNTR_WALK4
+{SPR_MNTR,0,5,A_MinotaurRoam,S_MNTR_ROAM2,0,0}, // S_MNTR_ROAM1
+{SPR_MNTR,1,5,A_MinotaurRoam,S_MNTR_ROAM3,0,0}, // S_MNTR_ROAM2
+{SPR_MNTR,2,5,A_MinotaurRoam,S_MNTR_ROAM4,0,0}, // S_MNTR_ROAM3
+{SPR_MNTR,3,5,A_MinotaurRoam,S_MNTR_ROAM1,0,0}, // S_MNTR_ROAM4
+{SPR_MNTR,6,10,A_FaceTarget,S_MNTR_ATK1_2,0,0}, // S_MNTR_ATK1_1
+{SPR_MNTR,7,7,A_FaceTarget,S_MNTR_ATK1_3,0,0}, // S_MNTR_ATK1_2
+{SPR_MNTR,8,12,A_MinotaurAtk1,S_MNTR_WALK1,0,0}, // S_MNTR_ATK1_3
+{SPR_MNTR,6,10,A_MinotaurDecide,S_MNTR_ATK2_2,0,0}, // S_MNTR_ATK2_1
+{SPR_MNTR,9,4,A_FaceTarget,S_MNTR_ATK2_3,0,0}, // S_MNTR_ATK2_2
+{SPR_MNTR,10,9,A_MinotaurAtk2,S_MNTR_WALK1,0,0}, // S_MNTR_ATK2_3
+{SPR_MNTR,6,10,A_FaceTarget,S_MNTR_ATK3_2,0,0}, // S_MNTR_ATK3_1
+{SPR_MNTR,7,7,A_FaceTarget,S_MNTR_ATK3_3,0,0}, // S_MNTR_ATK3_2
+{SPR_MNTR,8,12,A_MinotaurAtk3,S_MNTR_WALK1,0,0}, // S_MNTR_ATK3_3
+{SPR_MNTR,8,12,NULL,S_MNTR_ATK3_1,0,0}, // S_MNTR_ATK3_4
+{SPR_MNTR,5,2,A_MinotaurCharge,S_MNTR_ATK4_1,0,0}, // S_MNTR_ATK4_1
+{SPR_MNTR,4,3,NULL,S_MNTR_PAIN2,0,0}, // S_MNTR_PAIN1
+{SPR_MNTR,4,6,A_Pain,S_MNTR_WALK1,0,0}, // S_MNTR_PAIN2
+{SPR_MNTR,4,6,NULL,S_MNTR_DIE2,0,0}, // S_MNTR_DIE1
+{SPR_MNTR,4,2,A_Scream,S_MNTR_DIE3,0,0}, // S_MNTR_DIE2
+{SPR_MNTR,4,5,A_SmokePuffExit,S_MNTR_DIE4,0,0}, // S_MNTR_DIE3
+{SPR_MNTR,4,5,NULL,S_MNTR_DIE5,0,0}, // S_MNTR_DIE4
+{SPR_MNTR,4,5,A_NoBlocking,S_MNTR_DIE6,0,0}, // S_MNTR_DIE5
+{SPR_MNTR,4,5,NULL,S_MNTR_DIE7,0,0}, // S_MNTR_DIE6
+{SPR_MNTR,4,5,A_MinotaurFade1,S_MNTR_DIE8,0,0}, // S_MNTR_DIE7
+{SPR_MNTR,4,5,A_MinotaurFade0,S_MNTR_DIE9,0,0}, // S_MNTR_DIE8
+{SPR_MNTR,4,10,NULL,S_NULL,0,0}, // S_MNTR_DIE9
+{SPR_FX12,32768,6,NULL,S_MNTRFX1_2,0,0}, // S_MNTRFX1_1
+{SPR_FX12,32769,6,NULL,S_MNTRFX1_1,0,0}, // S_MNTRFX1_2
+{SPR_FX12,32770,5,NULL,S_MNTRFXI1_2,0,0}, // S_MNTRFXI1_1
+{SPR_FX12,32771,5,NULL,S_MNTRFXI1_3,0,0}, // S_MNTRFXI1_2
+{SPR_FX12,32772,5,NULL,S_MNTRFXI1_4,0,0}, // S_MNTRFXI1_3
+{SPR_FX12,32773,5,NULL,S_MNTRFXI1_5,0,0}, // S_MNTRFXI1_4
+{SPR_FX12,32774,5,NULL,S_MNTRFXI1_6,0,0}, // S_MNTRFXI1_5
+{SPR_FX12,32775,5,NULL,S_NULL,0,0}, // S_MNTRFXI1_6
+{SPR_FX13,0,2,A_MntrFloorFire,S_MNTRFX2_1,0,0}, // S_MNTRFX2_1
+{SPR_FX13,32776,4,A_Explode,S_MNTRFXI2_2,0,0}, // S_MNTRFXI2_1
+{SPR_FX13,32777,4,NULL,S_MNTRFXI2_3,0,0}, // S_MNTRFXI2_2
+{SPR_FX13,32778,4,NULL,S_MNTRFXI2_4,0,0}, // S_MNTRFXI2_3
+{SPR_FX13,32779,4,NULL,S_MNTRFXI2_5,0,0}, // S_MNTRFXI2_4
+{SPR_FX13,32780,4,NULL,S_NULL,0,0}, // S_MNTRFXI2_5
+{SPR_FX13,32771,4,NULL,S_MNTRFX3_2,0,0}, // S_MNTRFX3_1
+{SPR_FX13,32770,4,NULL,S_MNTRFX3_3,0,0}, // S_MNTRFX3_2
+{SPR_FX13,32769,5,NULL,S_MNTRFX3_4,0,0}, // S_MNTRFX3_3
+{SPR_FX13,32770,5,NULL,S_MNTRFX3_5,0,0}, // S_MNTRFX3_4
+{SPR_FX13,32771,5,NULL,S_MNTRFX3_6,0,0}, // S_MNTRFX3_5
+{SPR_FX13,32772,5,NULL,S_MNTRFX3_7,0,0}, // S_MNTRFX3_6
+{SPR_FX13,32773,4,NULL,S_MNTRFX3_8,0,0}, // S_MNTRFX3_7
+{SPR_FX13,32774,4,NULL,S_MNTRFX3_9,0,0}, // S_MNTRFX3_8
+{SPR_FX13,32775,4,NULL,S_NULL,0,0}, // S_MNTRFX3_9
+{SPR_MNSM,0,3,NULL,S_MINOSMOKE2,0,0}, // S_MINOSMOKE1
+{SPR_MNSM,1,3,NULL,S_MINOSMOKE3,0,0}, // S_MINOSMOKE2
+{SPR_MNSM,2,3,NULL,S_MINOSMOKE4,0,0}, // S_MINOSMOKE3
+{SPR_MNSM,3,3,NULL,S_MINOSMOKE5,0,0}, // S_MINOSMOKE4
+{SPR_MNSM,4,3,NULL,S_MINOSMOKE6,0,0}, // S_MINOSMOKE5
+{SPR_MNSM,5,3,NULL,S_MINOSMOKE7,0,0}, // S_MINOSMOKE6
+{SPR_MNSM,6,3,NULL,S_MINOSMOKE8,0,0}, // S_MINOSMOKE7
+{SPR_MNSM,7,3,NULL,S_MINOSMOKE9,0,0}, // S_MINOSMOKE8
+{SPR_MNSM,8,3,NULL,S_MINOSMOKE0,0,0}, // S_MINOSMOKE9
+{SPR_MNSM,9,3,NULL,S_MINOSMOKEA,0,0}, // S_MINOSMOKE0
+{SPR_MNSM,10,3,NULL,S_MINOSMOKEB,0,0}, // S_MINOSMOKEA
+{SPR_MNSM,11,3,NULL,S_MINOSMOKEC,0,0}, // S_MINOSMOKEB
+{SPR_MNSM,12,3,NULL,S_MINOSMOKED,0,0}, // S_MINOSMOKEC
+{SPR_MNSM,13,3,NULL,S_MINOSMOKEE,0,0}, // S_MINOSMOKED
+{SPR_MNSM,14,3,NULL,S_MINOSMOKEF,0,0}, // S_MINOSMOKEE
+{SPR_MNSM,15,3,NULL,S_MINOSMOKEG,0,0}, // S_MINOSMOKEF
+{SPR_MNSM,16,3,NULL,S_NULL,0,0}, // S_MINOSMOKEG
+{SPR_MNSM,0,3,NULL,S_MINOSMOKEX2,0,0}, // S_MINOSMOKEX1
+{SPR_MNSM,1,3,NULL,S_MINOSMOKEX3,0,0}, // S_MINOSMOKEX2
+{SPR_MNSM,2,3,NULL,S_MINOSMOKEX4,0,0}, // S_MINOSMOKEX3
+{SPR_MNSM,3,3,NULL,S_MINOSMOKEX5,0,0}, // S_MINOSMOKEX4
+{SPR_MNSM,4,3,NULL,S_MINOSMOKEX6,0,0}, // S_MINOSMOKEX5
+{SPR_MNSM,5,3,NULL,S_MINOSMOKEX7,0,0}, // S_MINOSMOKEX6
+{SPR_MNSM,6,3,NULL,S_MINOSMOKEX8,0,0}, // S_MINOSMOKEX7
+{SPR_MNSM,7,3,NULL,S_MINOSMOKEX9,0,0}, // S_MINOSMOKEX8
+{SPR_MNSM,8,3,NULL,S_MINOSMOKEX0,0,0}, // S_MINOSMOKEX9
+{SPR_MNSM,9,3,NULL,S_MINOSMOKEXA,0,0}, // S_MINOSMOKEX0
+{SPR_MNSM,8,3,NULL,S_MINOSMOKEXB,0,0}, // S_MINOSMOKEXA
+{SPR_MNSM,7,3,NULL,S_MINOSMOKEXC,0,0}, // S_MINOSMOKEXB
+{SPR_MNSM,6,3,NULL,S_MINOSMOKEXD,0,0}, // S_MINOSMOKEXC
+{SPR_MNSM,5,3,NULL,S_MINOSMOKEXE,0,0}, // S_MINOSMOKEXD
+{SPR_MNSM,4,3,NULL,S_MINOSMOKEXF,0,0}, // S_MINOSMOKEXE
+{SPR_MNSM,3,3,NULL,S_MINOSMOKEXG,0,0}, // S_MINOSMOKEXF
+{SPR_MNSM,2,3,NULL,S_MINOSMOKEXH,0,0}, // S_MINOSMOKEXG
+{SPR_MNSM,1,3,NULL,S_MINOSMOKEXI,0,0}, // S_MINOSMOKEXH
+{SPR_MNSM,0,3,NULL,S_NULL,0,0}, // S_MINOSMOKEXI
+{SPR_SSPT,7,10,A_Look,S_SERPENT_LOOK1,0,0}, // S_SERPENT_LOOK1
+{SPR_SSPT,7,1,A_SerpentChase,S_SERPENT_SWIM2,0,0}, // S_SERPENT_SWIM1
+{SPR_SSPT,7,1,A_SerpentChase,S_SERPENT_SWIM3,0,0}, // S_SERPENT_SWIM2
+{SPR_SSPT,7,2,A_SerpentHumpDecide,S_SERPENT_SWIM1,0,0}, // S_SERPENT_SWIM3
+{SPR_SSPT,7,3,A_SerpentUnHide,S_SERPENT_HUMP2,0,0}, // S_SERPENT_HUMP1
+{SPR_SSPT,4,3,A_SerpentRaiseHump,S_SERPENT_HUMP3,0,0}, // S_SERPENT_HUMP2
+{SPR_SSPT,5,3,A_SerpentRaiseHump,S_SERPENT_HUMP4,0,0}, // S_SERPENT_HUMP3
+{SPR_SSPT,6,3,A_SerpentRaiseHump,S_SERPENT_HUMP5,0,0}, // S_SERPENT_HUMP4
+{SPR_SSPT,4,3,A_SerpentRaiseHump,S_SERPENT_HUMP6,0,0}, // S_SERPENT_HUMP5
+{SPR_SSPT,5,3,A_SerpentRaiseHump,S_SERPENT_HUMP7,0,0}, // S_SERPENT_HUMP6
+{SPR_SSPT,6,3,NULL,S_SERPENT_HUMP8,0,0}, // S_SERPENT_HUMP7
+{SPR_SSPT,4,3,NULL,S_SERPENT_HUMP9,0,0}, // S_SERPENT_HUMP8
+{SPR_SSPT,5,3,NULL,S_SERPENT_HUMP10,0,0}, // S_SERPENT_HUMP9
+{SPR_SSPT,6,3,A_SerpentLowerHump,S_SERPENT_HUMP11,0,0}, // S_SERPENT_HUMP10
+{SPR_SSPT,4,3,A_SerpentLowerHump,S_SERPENT_HUMP12,0,0}, // S_SERPENT_HUMP11
+{SPR_SSPT,5,3,A_SerpentLowerHump,S_SERPENT_HUMP13,0,0}, // S_SERPENT_HUMP12
+{SPR_SSPT,6,3,A_SerpentLowerHump,S_SERPENT_HUMP14,0,0}, // S_SERPENT_HUMP13
+{SPR_SSPT,4,3,A_SerpentLowerHump,S_SERPENT_HUMP15,0,0}, // S_SERPENT_HUMP14
+{SPR_SSPT,5,3,A_SerpentHide,S_SERPENT_SWIM1,0,0}, // S_SERPENT_HUMP15
+{SPR_SSPT,0,1,A_UnHideThing,S_SERPENT_SURFACE2,0,0}, // S_SERPENT_SURFACE1
+{SPR_SSPT,0,1,A_SerpentBirthScream,S_SERPENT_SURFACE3,0,0}, // S_SERPENT_SURFACE2
+{SPR_SSPT,1,3,A_SetShootable,S_SERPENT_SURFACE4,0,0}, // S_SERPENT_SURFACE3
+{SPR_SSPT,2,3,NULL,S_SERPENT_SURFACE5,0,0}, // S_SERPENT_SURFACE4
+{SPR_SSPT,3,4,A_SerpentCheckForAttack,S_SERPENT_DIVE1,0,0}, // S_SERPENT_SURFACE5
+{SPR_SSDV,0,4,NULL,S_SERPENT_DIVE2,0,0}, // S_SERPENT_DIVE1
+{SPR_SSDV,1,4,NULL,S_SERPENT_DIVE3,0,0}, // S_SERPENT_DIVE2
+{SPR_SSDV,2,4,NULL,S_SERPENT_DIVE4,0,0}, // S_SERPENT_DIVE3
+{SPR_SSDV,3,4,A_UnSetShootable,S_SERPENT_DIVE5,0,0}, // S_SERPENT_DIVE4
+{SPR_SSDV,4,3,A_SerpentDiveSound,S_SERPENT_DIVE6,0,0}, // S_SERPENT_DIVE5
+{SPR_SSDV,5,3,NULL,S_SERPENT_DIVE7,0,0}, // S_SERPENT_DIVE6
+{SPR_SSDV,6,4,NULL,S_SERPENT_DIVE8,0,0}, // S_SERPENT_DIVE7
+{SPR_SSDV,7,4,NULL,S_SERPENT_DIVE9,0,0}, // S_SERPENT_DIVE8
+{SPR_SSDV,8,3,NULL,S_SERPENT_DIVE10,0,0}, // S_SERPENT_DIVE9
+{SPR_SSDV,9,3,A_SerpentHide,S_SERPENT_SWIM1,0,0}, // S_SERPENT_DIVE10
+{SPR_SSPT,8,5,A_SerpentWalk,S_SERPENT_WALK2,0,0}, // S_SERPENT_WALK1
+{SPR_SSPT,9,5,A_SerpentWalk,S_SERPENT_WALK3,0,0}, // S_SERPENT_WALK2
+{SPR_SSPT,8,5,A_SerpentWalk,S_SERPENT_WALK4,0,0}, // S_SERPENT_WALK3
+{SPR_SSPT,9,5,A_SerpentCheckForAttack,S_SERPENT_DIVE1,0,0}, // S_SERPENT_WALK4
+{SPR_SSPT,11,5,NULL,S_SERPENT_PAIN2,0,0}, // S_SERPENT_PAIN1
+{SPR_SSPT,11,5,A_Pain,S_SERPENT_DIVE1,0,0}, // S_SERPENT_PAIN2
+{SPR_SSPT,10,6,A_FaceTarget,S_SERPENT_ATK2,0,0}, // S_SERPENT_ATK1
+{SPR_SSPT,11,5,A_SerpentChooseAttack,S_SERPENT_MELEE1,0,0}, // S_SERPENT_ATK2
+{SPR_SSPT,13,5,A_SerpentMeleeAttack,S_SERPENT_DIVE1,0,0}, // S_SERPENT_MELEE1
+{SPR_SSPT,13,5,A_SerpentMissileAttack,S_SERPENT_DIVE1,0,0}, // S_SERPENT_MISSILE1
+{SPR_SSPT,14,4,NULL,S_SERPENT_DIE2,0,0}, // S_SERPENT_DIE1
+{SPR_SSPT,15,4,A_Scream,S_SERPENT_DIE3,0,0}, // S_SERPENT_DIE2
+{SPR_SSPT,16,4,A_NoBlocking,S_SERPENT_DIE4,0,0}, // S_SERPENT_DIE3
+{SPR_SSPT,17,4,NULL,S_SERPENT_DIE5,0,0}, // S_SERPENT_DIE4
+{SPR_SSPT,18,4,NULL,S_SERPENT_DIE6,0,0}, // S_SERPENT_DIE5
+{SPR_SSPT,19,4,NULL,S_SERPENT_DIE7,0,0}, // S_SERPENT_DIE6
+{SPR_SSPT,20,4,NULL,S_SERPENT_DIE8,0,0}, // S_SERPENT_DIE7
+{SPR_SSPT,21,4,NULL,S_SERPENT_DIE9,0,0}, // S_SERPENT_DIE8
+{SPR_SSPT,22,4,NULL,S_SERPENT_DIE10,0,0}, // S_SERPENT_DIE9
+{SPR_SSPT,23,4,NULL,S_SERPENT_DIE11,0,0}, // S_SERPENT_DIE10
+{SPR_SSPT,24,4,NULL,S_SERPENT_DIE12,0,0}, // S_SERPENT_DIE11
+{SPR_SSPT,25,4,NULL,S_NULL,0,0}, // S_SERPENT_DIE12
+{SPR_SSXD,0,4,NULL,S_SERPENT_XDIE2,0,0}, // S_SERPENT_XDIE1
+{SPR_SSXD,1,4,A_SerpentHeadPop,S_SERPENT_XDIE3,0,0}, // S_SERPENT_XDIE2
+{SPR_SSXD,2,4,A_NoBlocking,S_SERPENT_XDIE4,0,0}, // S_SERPENT_XDIE3
+{SPR_SSXD,3,4,NULL,S_SERPENT_XDIE5,0,0}, // S_SERPENT_XDIE4
+{SPR_SSXD,4,4,NULL,S_SERPENT_XDIE6,0,0}, // S_SERPENT_XDIE5
+{SPR_SSXD,5,3,NULL,S_SERPENT_XDIE7,0,0}, // S_SERPENT_XDIE6
+{SPR_SSXD,6,3,NULL,S_SERPENT_XDIE8,0,0}, // S_SERPENT_XDIE7
+{SPR_SSXD,7,3,A_SerpentSpawnGibs,S_NULL,0,0}, // S_SERPENT_XDIE8
+{SPR_SSPT,26,5,A_FreezeDeath,S_SERPENT_ICE2,0,0}, // S_SERPENT_ICE
+{SPR_SSPT,26,1,A_FreezeDeathChunks,S_SERPENT_ICE2,0,0}, // S_SERPENT_ICE2
+{SPR_SSFX,32768,3,A_ContMobjSound,S_SERPENT_FX2,0,0}, // S_SERPENT_FX1
+{SPR_SSFX,32769,3,NULL,S_SERPENT_FX3,0,0}, // S_SERPENT_FX2
+{SPR_SSFX,32768,3,NULL,S_SERPENT_FX4,0,0}, // S_SERPENT_FX3
+{SPR_SSFX,32769,3,NULL,S_SERPENT_FX1,0,0}, // S_SERPENT_FX4
+{SPR_SSFX,32770,4,NULL,S_SERPENT_FX_X2,0,0}, // S_SERPENT_FX_X1
+{SPR_SSFX,32771,4,NULL,S_SERPENT_FX_X3,0,0}, // S_SERPENT_FX_X2
+{SPR_SSFX,32772,4,NULL,S_SERPENT_FX_X4,0,0}, // S_SERPENT_FX_X3
+{SPR_SSFX,32773,4,NULL,S_SERPENT_FX_X5,0,0}, // S_SERPENT_FX_X4
+{SPR_SSFX,32774,4,NULL,S_SERPENT_FX_X6,0,0}, // S_SERPENT_FX_X5
+{SPR_SSFX,32775,4,NULL,S_NULL,0,0}, // S_SERPENT_FX_X6
+{SPR_SSXD,8,4,A_SerpentHeadCheck,S_SERPENT_HEAD2,0,0}, // S_SERPENT_HEAD1
+{SPR_SSXD,9,4,A_SerpentHeadCheck,S_SERPENT_HEAD3,0,0}, // S_SERPENT_HEAD2
+{SPR_SSXD,10,4,A_SerpentHeadCheck,S_SERPENT_HEAD4,0,0}, // S_SERPENT_HEAD3
+{SPR_SSXD,11,4,A_SerpentHeadCheck,S_SERPENT_HEAD5,0,0}, // S_SERPENT_HEAD4
+{SPR_SSXD,12,4,A_SerpentHeadCheck,S_SERPENT_HEAD6,0,0}, // S_SERPENT_HEAD5
+{SPR_SSXD,13,4,A_SerpentHeadCheck,S_SERPENT_HEAD7,0,0}, // S_SERPENT_HEAD6
+{SPR_SSXD,14,4,A_SerpentHeadCheck,S_SERPENT_HEAD8,0,0}, // S_SERPENT_HEAD7
+{SPR_SSXD,15,4,A_SerpentHeadCheck,S_SERPENT_HEAD1,0,0}, // S_SERPENT_HEAD8
+{SPR_SSXD,18,-1,NULL,S_SERPENT_HEAD_X1,0,0}, // S_SERPENT_HEAD_X1
+{SPR_SSXD,16,6,NULL,S_SERPENT_GIB1_2,0,0}, // S_SERPENT_GIB1_1
+{SPR_SSXD,16,6,A_FloatGib,S_SERPENT_GIB1_3,0,0}, // S_SERPENT_GIB1_2
+{SPR_SSXD,16,8,A_FloatGib,S_SERPENT_GIB1_4,0,0}, // S_SERPENT_GIB1_3
+{SPR_SSXD,16,8,A_FloatGib,S_SERPENT_GIB1_5,0,0}, // S_SERPENT_GIB1_4
+{SPR_SSXD,16,12,A_FloatGib,S_SERPENT_GIB1_6,0,0}, // S_SERPENT_GIB1_5
+{SPR_SSXD,16,12,A_FloatGib,S_SERPENT_GIB1_7,0,0}, // S_SERPENT_GIB1_6
+{SPR_SSXD,16,232,A_DelayGib,S_SERPENT_GIB1_8,0,0}, // S_SERPENT_GIB1_7
+{SPR_SSXD,16,12,A_SinkGib,S_SERPENT_GIB1_9,0,0}, // S_SERPENT_GIB1_8
+{SPR_SSXD,16,12,A_SinkGib,S_SERPENT_GIB1_10,0,0}, // S_SERPENT_GIB1_9
+{SPR_SSXD,16,8,A_SinkGib,S_SERPENT_GIB1_11,0,0}, // S_SERPENT_GIB1_10
+{SPR_SSXD,16,8,A_SinkGib,S_SERPENT_GIB1_12,0,0}, // S_SERPENT_GIB1_11
+{SPR_SSXD,16,8,A_SinkGib,S_NULL,0,0}, // S_SERPENT_GIB1_12
+{SPR_SSXD,17,6,NULL,S_SERPENT_GIB2_2,0,0}, // S_SERPENT_GIB2_1
+{SPR_SSXD,17,6,A_FloatGib,S_SERPENT_GIB2_3,0,0}, // S_SERPENT_GIB2_2
+{SPR_SSXD,17,8,A_FloatGib,S_SERPENT_GIB2_4,0,0}, // S_SERPENT_GIB2_3
+{SPR_SSXD,17,8,A_FloatGib,S_SERPENT_GIB2_5,0,0}, // S_SERPENT_GIB2_4
+{SPR_SSXD,17,12,A_FloatGib,S_SERPENT_GIB2_6,0,0}, // S_SERPENT_GIB2_5
+{SPR_SSXD,17,12,A_FloatGib,S_SERPENT_GIB2_7,0,0}, // S_SERPENT_GIB2_6
+{SPR_SSXD,17,232,A_DelayGib,S_SERPENT_GIB2_8,0,0}, // S_SERPENT_GIB2_7
+{SPR_SSXD,17,12,A_SinkGib,S_SERPENT_GIB2_9,0,0}, // S_SERPENT_GIB2_8
+{SPR_SSXD,17,12,A_SinkGib,S_SERPENT_GIB2_10,0,0}, // S_SERPENT_GIB2_9
+{SPR_SSXD,17,8,A_SinkGib,S_SERPENT_GIB2_11,0,0}, // S_SERPENT_GIB2_10
+{SPR_SSXD,17,8,A_SinkGib,S_SERPENT_GIB2_12,0,0}, // S_SERPENT_GIB2_11
+{SPR_SSXD,17,8,A_SinkGib,S_NULL,0,0}, // S_SERPENT_GIB2_12
+{SPR_SSXD,19,6,NULL,S_SERPENT_GIB3_2,0,0}, // S_SERPENT_GIB3_1
+{SPR_SSXD,19,6,A_FloatGib,S_SERPENT_GIB3_3,0,0}, // S_SERPENT_GIB3_2
+{SPR_SSXD,19,8,A_FloatGib,S_SERPENT_GIB3_4,0,0}, // S_SERPENT_GIB3_3
+{SPR_SSXD,19,8,A_FloatGib,S_SERPENT_GIB3_5,0,0}, // S_SERPENT_GIB3_4
+{SPR_SSXD,19,12,A_FloatGib,S_SERPENT_GIB3_6,0,0}, // S_SERPENT_GIB3_5
+{SPR_SSXD,19,12,A_FloatGib,S_SERPENT_GIB3_7,0,0}, // S_SERPENT_GIB3_6
+{SPR_SSXD,19,232,A_DelayGib,S_SERPENT_GIB3_8,0,0}, // S_SERPENT_GIB3_7
+{SPR_SSXD,19,12,A_SinkGib,S_SERPENT_GIB3_9,0,0}, // S_SERPENT_GIB3_8
+{SPR_SSXD,19,12,A_SinkGib,S_SERPENT_GIB3_10,0,0}, // S_SERPENT_GIB3_9
+{SPR_SSXD,19,8,A_SinkGib,S_SERPENT_GIB3_11,0,0}, // S_SERPENT_GIB3_10
+{SPR_SSXD,19,8,A_SinkGib,S_SERPENT_GIB3_12,0,0}, // S_SERPENT_GIB3_11
+{SPR_SSXD,19,8,A_SinkGib,S_NULL,0,0}, // S_SERPENT_GIB3_12
+{SPR_BISH,0,10,A_Look,S_BISHOP_LOOK1,0,0}, // S_BISHOP_LOOK1
+{SPR_BISH,0,1,A_BishopDecide,S_BISHOP_WALK1,0,0}, // S_BISHOP_DECIDE
+{SPR_BISH,0,2,A_BishopDoBlur,S_BISHOP_BLUR2,0,0}, // S_BISHOP_BLUR1
+{SPR_BISH,0,4,A_BishopSpawnBlur,S_BISHOP_BLUR2,0,0}, // S_BISHOP_BLUR2
+{SPR_BISH,0,2,A_Chase,S_BISHOP_WALK2,0,0}, // S_BISHOP_WALK1
+{SPR_BISH,0,2,A_BishopChase,S_BISHOP_WALK3,0,0}, // S_BISHOP_WALK2
+{SPR_BISH,0,2,NULL,S_BISHOP_WALK4,0,0}, // S_BISHOP_WALK3
+{SPR_BISH,1,2,A_BishopChase,S_BISHOP_WALK5,0,0}, // S_BISHOP_WALK4
+{SPR_BISH,1,2,A_Chase,S_BISHOP_WALK6,0,0}, // S_BISHOP_WALK5
+{SPR_BISH,1,2,A_BishopChase,S_BISHOP_DECIDE,0,0}, // S_BISHOP_WALK6
+{SPR_BISH,0,3,A_FaceTarget,S_BISHOP_ATK2,0,0}, // S_BISHOP_ATK1
+{SPR_BISH,32771,3,A_FaceTarget,S_BISHOP_ATK3,0,0}, // S_BISHOP_ATK2
+{SPR_BISH,32772,3,A_FaceTarget,S_BISHOP_ATK4,0,0}, // S_BISHOP_ATK3
+{SPR_BISH,32773,3,A_BishopAttack,S_BISHOP_ATK5,0,0}, // S_BISHOP_ATK4
+{SPR_BISH,32773,5,A_BishopAttack2,S_BISHOP_ATK5,0,0}, // S_BISHOP_ATK5
+{SPR_BISH,2,6,A_Pain,S_BISHOP_PAIN2,0,0}, // S_BISHOP_PAIN1
+{SPR_BISH,2,6,A_BishopPainBlur,S_BISHOP_PAIN3,0,0}, // S_BISHOP_PAIN2
+{SPR_BISH,2,6,A_BishopPainBlur,S_BISHOP_PAIN4,0,0}, // S_BISHOP_PAIN3
+{SPR_BISH,2,6,A_BishopPainBlur,S_BISHOP_PAIN5,0,0}, // S_BISHOP_PAIN4
+{SPR_BISH,2,0,NULL,S_BISHOP_WALK1,0,0}, // S_BISHOP_PAIN5
+{SPR_BISH,6,6,NULL,S_BISHOP_DEATH2,0,0}, // S_BISHOP_DEATH1
+{SPR_BISH,32775,6,A_Scream,S_BISHOP_DEATH3,0,0}, // S_BISHOP_DEATH2
+{SPR_BISH,32776,5,A_NoBlocking,S_BISHOP_DEATH4,0,0}, // S_BISHOP_DEATH3
+{SPR_BISH,32777,5,A_Explode,S_BISHOP_DEATH5,0,0}, // S_BISHOP_DEATH4
+{SPR_BISH,32778,5,NULL,S_BISHOP_DEATH6,0,0}, // S_BISHOP_DEATH5
+{SPR_BISH,32779,4,NULL,S_BISHOP_DEATH7,0,0}, // S_BISHOP_DEATH6
+{SPR_BISH,32780,4,NULL,S_BISHOP_DEATH8,0,0}, // S_BISHOP_DEATH7
+{SPR_BISH,13,4,A_BishopPuff,S_BISHOP_DEATH9,0,0}, // S_BISHOP_DEATH8
+{SPR_BISH,14,4,A_QueueCorpse,S_BISHOP_DEATH10,0,0}, // S_BISHOP_DEATH9
+{SPR_BISH,15,-1,NULL,S_NULL,0,0}, // S_BISHOP_DEATH10
+{SPR_BISH,23,5,A_FreezeDeath,S_BISHOP_ICE2,0,0}, // S_BISHOP_ICE
+{SPR_BISH,23,1,A_FreezeDeathChunks,S_BISHOP_ICE2,0,0}, // S_BISHOP_ICE2
+{SPR_BISH,16,5,NULL,S_BISHOP_PUFF2,0,0}, // S_BISHOP_PUFF1
+{SPR_BISH,17,5,NULL,S_BISHOP_PUFF3,0,0}, // S_BISHOP_PUFF2
+{SPR_BISH,18,5,NULL,S_BISHOP_PUFF4,0,0}, // S_BISHOP_PUFF3
+{SPR_BISH,19,5,NULL,S_BISHOP_PUFF5,0,0}, // S_BISHOP_PUFF4
+{SPR_BISH,20,6,NULL,S_BISHOP_PUFF6,0,0}, // S_BISHOP_PUFF5
+{SPR_BISH,21,6,NULL,S_BISHOP_PUFF7,0,0}, // S_BISHOP_PUFF6
+{SPR_BISH,22,5,NULL,S_NULL,0,0}, // S_BISHOP_PUFF7
+{SPR_BISH,0,16,NULL,S_BISHOPBLUR2,0,0}, // S_BISHOPBLUR1
+{SPR_BISH,0,8,A_SetAltShadow,S_NULL,0,0}, // S_BISHOPBLUR2
+{SPR_BISH,2,8,NULL,S_NULL,0,0}, // S_BISHOPPAINBLUR1
+{SPR_BPFX,32768,1,A_BishopMissileWeave,S_BISHFX1_2,0,0}, // S_BISHFX1_1
+{SPR_BPFX,32769,1,A_BishopMissileWeave,S_BISHFX1_3,0,0}, // S_BISHFX1_2
+{SPR_BPFX,32768,1,A_BishopMissileWeave,S_BISHFX1_4,0,0}, // S_BISHFX1_3
+{SPR_BPFX,32769,1,A_BishopMissileWeave,S_BISHFX1_5,0,0}, // S_BISHFX1_4
+{SPR_BPFX,32769,0,A_BishopMissileSeek,S_BISHFX1_1,0,0}, // S_BISHFX1_5
+{SPR_BPFX,32770,4,NULL,S_BISHFXI1_2,0,0}, // S_BISHFXI1_1
+{SPR_BPFX,32771,4,NULL,S_BISHFXI1_3,0,0}, // S_BISHFXI1_2
+{SPR_BPFX,32772,4,NULL,S_BISHFXI1_4,0,0}, // S_BISHFXI1_3
+{SPR_BPFX,32773,4,NULL,S_BISHFXI1_5,0,0}, // S_BISHFXI1_4
+{SPR_BPFX,32774,3,NULL,S_BISHFXI1_6,0,0}, // S_BISHFXI1_5
+{SPR_BPFX,32775,3,NULL,S_NULL,0,0}, // S_BISHFXI1_6
+{SPR_DRAG,3,10,A_Look,S_DRAGON_LOOK1,0,0}, // S_DRAGON_LOOK1
+{SPR_DRAG,2,5,NULL,S_DRAGON_INIT2,0,0}, // S_DRAGON_INIT
+{SPR_DRAG,1,5,NULL,S_DRAGON_INIT3,0,0}, // S_DRAGON_INIT2
+{SPR_DRAG,0,5,A_DragonInitFlight,S_DRAGON_WALK1,0,0}, // S_DRAGON_INIT3
+{SPR_DRAG,1,3,A_DragonFlap,S_DRAGON_WALK2,0,0}, // S_DRAGON_WALK1
+{SPR_DRAG,1,3,A_DragonFlight,S_DRAGON_WALK3,0,0}, // S_DRAGON_WALK2
+{SPR_DRAG,2,3,A_DragonFlight,S_DRAGON_WALK4,0,0}, // S_DRAGON_WALK3
+{SPR_DRAG,2,3,A_DragonFlight,S_DRAGON_WALK5,0,0}, // S_DRAGON_WALK4
+{SPR_DRAG,3,3,A_DragonFlight,S_DRAGON_WALK6,0,0}, // S_DRAGON_WALK5
+{SPR_DRAG,3,3,A_DragonFlight,S_DRAGON_WALK7,0,0}, // S_DRAGON_WALK6
+{SPR_DRAG,2,3,A_DragonFlight,S_DRAGON_WALK8,0,0}, // S_DRAGON_WALK7
+{SPR_DRAG,2,3,A_DragonFlight,S_DRAGON_WALK9,0,0}, // S_DRAGON_WALK8
+{SPR_DRAG,1,3,A_DragonFlight,S_DRAGON_WALK10,0,0}, // S_DRAGON_WALK9
+{SPR_DRAG,1,3,A_DragonFlight,S_DRAGON_WALK11,0,0}, // S_DRAGON_WALK10
+{SPR_DRAG,0,3,A_DragonFlight,S_DRAGON_WALK12,0,0}, // S_DRAGON_WALK11
+{SPR_DRAG,0,3,A_DragonFlight,S_DRAGON_WALK1,0,0}, // S_DRAGON_WALK12
+{SPR_DRAG,4,8,A_DragonAttack,S_DRAGON_WALK1,0,0}, // S_DRAGON_ATK1
+{SPR_DRAG,5,10,A_DragonPain,S_DRAGON_WALK1,0,0}, // S_DRAGON_PAIN1
+{SPR_DRAG,6,5,A_Scream,S_DRAGON_DEATH2,0,0}, // S_DRAGON_DEATH1
+{SPR_DRAG,7,4,A_NoBlocking,S_DRAGON_DEATH3,0,0}, // S_DRAGON_DEATH2
+{SPR_DRAG,8,4,NULL,S_DRAGON_DEATH4,0,0}, // S_DRAGON_DEATH3
+{SPR_DRAG,9,4,A_DragonCheckCrash,S_DRAGON_DEATH4,0,0}, // S_DRAGON_DEATH4
+{SPR_DRAG,10,5,NULL,S_DRAGON_CRASH2,0,0}, // S_DRAGON_CRASH1
+{SPR_DRAG,11,5,NULL,S_DRAGON_CRASH3,0,0}, // S_DRAGON_CRASH2
+{SPR_DRAG,12,-1,NULL,S_NULL,0,0}, // S_DRAGON_CRASH3
+{SPR_DRFX,32768,4,NULL,S_DRAGON_FX1_2,0,0}, // S_DRAGON_FX1_1
+{SPR_DRFX,32769,4,NULL,S_DRAGON_FX1_3,0,0}, // S_DRAGON_FX1_2
+{SPR_DRFX,32770,4,NULL,S_DRAGON_FX1_4,0,0}, // S_DRAGON_FX1_3
+{SPR_DRFX,32771,4,NULL,S_DRAGON_FX1_5,0,0}, // S_DRAGON_FX1_4
+{SPR_DRFX,32772,4,NULL,S_DRAGON_FX1_6,0,0}, // S_DRAGON_FX1_5
+{SPR_DRFX,32773,4,NULL,S_DRAGON_FX1_1,0,0}, // S_DRAGON_FX1_6
+{SPR_DRFX,32774,4,NULL,S_DRAGON_FX1_X2,0,0}, // S_DRAGON_FX1_X1
+{SPR_DRFX,32775,4,NULL,S_DRAGON_FX1_X3,0,0}, // S_DRAGON_FX1_X2
+{SPR_DRFX,32776,4,NULL,S_DRAGON_FX1_X4,0,0}, // S_DRAGON_FX1_X3
+{SPR_DRFX,32777,4,A_DragonFX2,S_DRAGON_FX1_X5,0,0}, // S_DRAGON_FX1_X4
+{SPR_DRFX,32778,3,NULL,S_DRAGON_FX1_X6,0,0}, // S_DRAGON_FX1_X5
+{SPR_DRFX,32779,3,NULL,S_NULL,0,0}, // S_DRAGON_FX1_X6
+{SPR_CFCF,32784,1,NULL,S_DRAGON_FX2_2,0,0}, // S_DRAGON_FX2_1
+{SPR_CFCF,32784,4,A_UnHideThing,S_DRAGON_FX2_3,0,0}, // S_DRAGON_FX2_2
+{SPR_CFCF,32785,3,A_Scream,S_DRAGON_FX2_4,0,0}, // S_DRAGON_FX2_3
+{SPR_CFCF,32786,4,NULL,S_DRAGON_FX2_5,0,0}, // S_DRAGON_FX2_4
+{SPR_CFCF,32787,3,A_Explode,S_DRAGON_FX2_6,0,0}, // S_DRAGON_FX2_5
+{SPR_CFCF,32788,4,NULL,S_DRAGON_FX2_7,0,0}, // S_DRAGON_FX2_6
+{SPR_CFCF,32789,3,NULL,S_DRAGON_FX2_8,0,0}, // S_DRAGON_FX2_7
+{SPR_CFCF,32790,4,NULL,S_DRAGON_FX2_9,0,0}, // S_DRAGON_FX2_8
+{SPR_CFCF,32791,3,NULL,S_DRAGON_FX2_10,0,0}, // S_DRAGON_FX2_9
+{SPR_CFCF,32792,4,NULL,S_DRAGON_FX2_11,0,0}, // S_DRAGON_FX2_10
+{SPR_CFCF,32793,3,NULL,S_NULL,0,0}, // S_DRAGON_FX2_11
+{SPR_ARM1,0,-1,NULL,S_NULL,0,0}, // S_ARMOR_1
+{SPR_ARM2,0,-1,NULL,S_NULL,0,0}, // S_ARMOR_2
+{SPR_ARM3,0,-1,NULL,S_NULL,0,0}, // S_ARMOR_3
+{SPR_ARM4,0,-1,NULL,S_NULL,0,0}, // S_ARMOR_4
+{SPR_MAN1,32768,4,NULL,S_MANA1_2,0,0}, // S_MANA1_1
+{SPR_MAN1,32769,4,NULL,S_MANA1_3,0,0}, // S_MANA1_2
+{SPR_MAN1,32770,4,NULL,S_MANA1_4,0,0}, // S_MANA1_3
+{SPR_MAN1,32771,4,NULL,S_MANA1_5,0,0}, // S_MANA1_4
+{SPR_MAN1,32772,4,NULL,S_MANA1_6,0,0}, // S_MANA1_5
+{SPR_MAN1,32773,4,NULL,S_MANA1_7,0,0}, // S_MANA1_6
+{SPR_MAN1,32774,4,NULL,S_MANA1_8,0,0}, // S_MANA1_7
+{SPR_MAN1,32775,4,NULL,S_MANA1_9,0,0}, // S_MANA1_8
+{SPR_MAN1,32776,4,NULL,S_MANA1_1,0,0}, // S_MANA1_9
+{SPR_MAN2,32768,4,NULL,S_MANA2_2,0,0}, // S_MANA2_1
+{SPR_MAN2,32769,4,NULL,S_MANA2_3,0,0}, // S_MANA2_2
+{SPR_MAN2,32770,4,NULL,S_MANA2_4,0,0}, // S_MANA2_3
+{SPR_MAN2,32771,4,NULL,S_MANA2_5,0,0}, // S_MANA2_4
+{SPR_MAN2,32772,4,NULL,S_MANA2_6,0,0}, // S_MANA2_5
+{SPR_MAN2,32773,4,NULL,S_MANA2_7,0,0}, // S_MANA2_6
+{SPR_MAN2,32774,4,NULL,S_MANA2_8,0,0}, // S_MANA2_7
+{SPR_MAN2,32775,4,NULL,S_MANA2_9,0,0}, // S_MANA2_8
+{SPR_MAN2,32776,4,NULL,S_MANA2_10,0,0}, // S_MANA2_9
+{SPR_MAN2,32777,4,NULL,S_MANA2_11,0,0}, // S_MANA2_10
+{SPR_MAN2,32778,4,NULL,S_MANA2_12,0,0}, // S_MANA2_11
+{SPR_MAN2,32779,4,NULL,S_MANA2_13,0,0}, // S_MANA2_12
+{SPR_MAN2,32780,4,NULL,S_MANA2_14,0,0}, // S_MANA2_13
+{SPR_MAN2,32781,4,NULL,S_MANA2_15,0,0}, // S_MANA2_14
+{SPR_MAN2,32782,4,NULL,S_MANA2_16,0,0}, // S_MANA2_15
+{SPR_MAN2,32783,4,NULL,S_MANA2_1,0,0}, // S_MANA2_16
+{SPR_MAN3,32768,4,NULL,S_MANA3_2,0,0}, // S_MANA3_1
+{SPR_MAN3,32769,4,NULL,S_MANA3_3,0,0}, // S_MANA3_2
+{SPR_MAN3,32770,4,NULL,S_MANA3_4,0,0}, // S_MANA3_3
+{SPR_MAN3,32771,4,NULL,S_MANA3_5,0,0}, // S_MANA3_4
+{SPR_MAN3,32772,4,NULL,S_MANA3_6,0,0}, // S_MANA3_5
+{SPR_MAN3,32773,4,NULL,S_MANA3_7,0,0}, // S_MANA3_6
+{SPR_MAN3,32774,4,NULL,S_MANA3_8,0,0}, // S_MANA3_7
+{SPR_MAN3,32775,4,NULL,S_MANA3_9,0,0}, // S_MANA3_8
+{SPR_MAN3,32776,4,NULL,S_MANA3_10,0,0}, // S_MANA3_9
+{SPR_MAN3,32777,4,NULL,S_MANA3_11,0,0}, // S_MANA3_10
+{SPR_MAN3,32778,4,NULL,S_MANA3_12,0,0}, // S_MANA3_11
+{SPR_MAN3,32779,4,NULL,S_MANA3_13,0,0}, // S_MANA3_12
+{SPR_MAN3,32780,4,NULL,S_MANA3_14,0,0}, // S_MANA3_13
+{SPR_MAN3,32781,4,NULL,S_MANA3_15,0,0}, // S_MANA3_14
+{SPR_MAN3,32782,4,NULL,S_MANA3_16,0,0}, // S_MANA3_15
+{SPR_MAN3,32783,4,NULL,S_MANA3_1,0,0}, // S_MANA3_16
+{SPR_KEY1,0,-1,NULL,S_NULL,0,0}, // S_KEY1
+{SPR_KEY2,0,-1,NULL,S_NULL,0,0}, // S_KEY2
+{SPR_KEY3,0,-1,NULL,S_NULL,0,0}, // S_KEY3
+{SPR_KEY4,0,-1,NULL,S_NULL,0,0}, // S_KEY4
+{SPR_KEY5,0,-1,NULL,S_NULL,0,0}, // S_KEY5
+{SPR_KEY6,0,-1,NULL,S_NULL,0,0}, // S_KEY6
+{SPR_KEY7,0,-1,NULL,S_NULL,0,0}, // S_KEY7
+{SPR_KEY8,0,-1,NULL,S_NULL,0,0}, // S_KEY8
+{SPR_KEY9,0,-1,NULL,S_NULL,0,0}, // S_KEY9
+{SPR_KEYA,0,-1,NULL,S_NULL,0,0}, // S_KEYA
+{SPR_KEYB,0,-1,NULL,S_NULL,0,0}, // S_KEYB
+{SPR_TLGL,0,1,NULL,S_SND_WIND2,0,0}, // S_SND_WIND1
+{SPR_TLGL,0,200,A_ESound,S_SND_WIND2,0,0}, // S_SND_WIND2
+{SPR_TLGL,0,85,A_ESound,S_SND_WATERFALL,0,0}, // S_SND_WATERFALL
+{SPR_ETTN,0,10,A_Look,S_ETTIN_LOOK2,0,0}, // S_ETTIN_LOOK1
+{SPR_ETTN,0,10,A_Look,S_ETTIN_LOOK1,0,0}, // S_ETTIN_LOOK2
+{SPR_ETTN,0,5,A_Chase,S_ETTIN_CHASE2,0,0}, // S_ETTIN_CHASE1
+{SPR_ETTN,1,5,A_Chase,S_ETTIN_CHASE3,0,0}, // S_ETTIN_CHASE2
+{SPR_ETTN,2,5,A_Chase,S_ETTIN_CHASE4,0,0}, // S_ETTIN_CHASE3
+{SPR_ETTN,3,5,A_Chase,S_ETTIN_CHASE1,0,0}, // S_ETTIN_CHASE4
+{SPR_ETTN,7,7,A_Pain,S_ETTIN_CHASE1,0,0}, // S_ETTIN_PAIN1
+{SPR_ETTN,4,6,A_FaceTarget,S_ETTIN_ATK1_2,0,0}, // S_ETTIN_ATK1_1
+{SPR_ETTN,5,6,A_FaceTarget,S_ETTIN_ATK1_3,0,0}, // S_ETTIN_ATK1_2
+{SPR_ETTN,6,8,A_EttinAttack,S_ETTIN_CHASE1,0,0}, // S_ETTIN_ATK1_3
+{SPR_ETTN,8,4,NULL,S_ETTIN_DEATH1_2,0,0}, // S_ETTIN_DEATH1_1
+{SPR_ETTN,9,4,NULL,S_ETTIN_DEATH1_3,0,0}, // S_ETTIN_DEATH1_2
+{SPR_ETTN,10,4,A_Scream,S_ETTIN_DEATH1_4,0,0}, // S_ETTIN_DEATH1_3
+{SPR_ETTN,11,4,A_NoBlocking,S_ETTIN_DEATH1_5,0,0}, // S_ETTIN_DEATH1_4
+{SPR_ETTN,12,4,A_QueueCorpse,S_ETTIN_DEATH1_6,0,0}, // S_ETTIN_DEATH1_5
+{SPR_ETTN,13,4,NULL,S_ETTIN_DEATH1_7,0,0}, // S_ETTIN_DEATH1_6
+{SPR_ETTN,14,4,NULL,S_ETTIN_DEATH1_8,0,0}, // S_ETTIN_DEATH1_7
+{SPR_ETTN,15,4,NULL,S_ETTIN_DEATH1_9,0,0}, // S_ETTIN_DEATH1_8
+{SPR_ETTN,16,-1,NULL,S_NULL,0,0}, // S_ETTIN_DEATH1_9
+{SPR_ETTB,0,4,NULL,S_ETTIN_DEATH2_2,0,0}, // S_ETTIN_DEATH2_1
+{SPR_ETTB,1,4,A_NoBlocking,S_ETTIN_DEATH2_3,0,0}, // S_ETTIN_DEATH2_2
+{SPR_ETTB,2,4,A_DropMace,S_ETTIN_DEATH2_4,0,0}, // S_ETTIN_DEATH2_3
+{SPR_ETTB,3,4,A_Scream,S_ETTIN_DEATH2_5,0,0}, // S_ETTIN_DEATH2_4
+{SPR_ETTB,4,4,A_QueueCorpse,S_ETTIN_DEATH2_6,0,0}, // S_ETTIN_DEATH2_5
+{SPR_ETTB,5,4,NULL,S_ETTIN_DEATH2_7,0,0}, // S_ETTIN_DEATH2_6
+{SPR_ETTB,6,4,NULL,S_ETTIN_DEATH2_8,0,0}, // S_ETTIN_DEATH2_7
+{SPR_ETTB,7,4,NULL,S_ETTIN_DEATH2_9,0,0}, // S_ETTIN_DEATH2_8
+{SPR_ETTB,8,4,NULL,S_ETTIN_DEATH2_0,0,0}, // S_ETTIN_DEATH2_9
+{SPR_ETTB,9,4,NULL,S_ETTIN_DEATH2_A,0,0}, // S_ETTIN_DEATH2_0
+{SPR_ETTB,10,4,NULL,S_ETTIN_DEATH2_B,0,0}, // S_ETTIN_DEATH2_A
+{SPR_ETTB,11,-1,NULL,S_NULL,0,0}, // S_ETTIN_DEATH2_B
+{SPR_ETTN,17,5,A_FreezeDeath,S_ETTIN_ICE2,0,0}, // S_ETTIN_ICE1
+{SPR_ETTN,17,1,A_FreezeDeathChunks,S_ETTIN_ICE2,0,0}, // S_ETTIN_ICE2
+{SPR_ETTB,12,5,A_CheckFloor,S_ETTIN_MACE2,0,0}, // S_ETTIN_MACE1
+{SPR_ETTB,13,5,A_CheckFloor,S_ETTIN_MACE3,0,0}, // S_ETTIN_MACE2
+{SPR_ETTB,14,5,A_CheckFloor,S_ETTIN_MACE4,0,0}, // S_ETTIN_MACE3
+{SPR_ETTB,15,5,A_CheckFloor,S_ETTIN_MACE1,0,0}, // S_ETTIN_MACE4
+{SPR_ETTB,16,5,NULL,S_ETTIN_MACE6,0,0}, // S_ETTIN_MACE5
+{SPR_ETTB,17,5,A_QueueCorpse,S_ETTIN_MACE7,0,0}, // S_ETTIN_MACE6
+{SPR_ETTB,18,-1,NULL,S_NULL,0,0}, // S_ETTIN_MACE7
+{SPR_FDMN,32791,5,NULL,S_FIRED_LOOK1,0,0}, // S_FIRED_SPAWN1
+{SPR_FDMN,32772,10,A_Look,S_FIRED_LOOK2,0,0}, // S_FIRED_LOOK1
+{SPR_FDMN,32773,10,A_Look,S_FIRED_LOOK3,0,0}, // S_FIRED_LOOK2
+{SPR_FDMN,32774,10,A_Look,S_FIRED_LOOK1,0,0}, // S_FIRED_LOOK3
+{SPR_FDMN,32772,8,NULL,S_FIRED_LOOK5,0,0}, // S_FIRED_LOOK4
+{SPR_FDMN,32773,6,NULL,S_FIRED_LOOK6,0,0}, // S_FIRED_LOOK5
+{SPR_FDMN,32774,5,NULL,S_FIRED_LOOK7,0,0}, // S_FIRED_LOOK6
+{SPR_FDMN,32773,8,NULL,S_FIRED_LOOK8,0,0}, // S_FIRED_LOOK7
+{SPR_FDMN,32772,6,NULL,S_FIRED_LOOK9,0,0}, // S_FIRED_LOOK8
+{SPR_FDMN,32773,7,A_FiredRocks,S_FIRED_LOOK0,0,0}, // S_FIRED_LOOK9
+{SPR_FDMN,32775,5,NULL,S_FIRED_LOOKA,0,0}, // S_FIRED_LOOK0
+{SPR_FDMN,32776,5,NULL,S_FIRED_LOOKB,0,0}, // S_FIRED_LOOKA
+{SPR_FDMN,32777,5,A_UnSetInvulnerable,S_FIRED_WALK1,0,0}, // S_FIRED_LOOKB
+{SPR_FDMN,32768,5,A_FiredChase,S_FIRED_WALK2,0,0}, // S_FIRED_WALK1
+{SPR_FDMN,32769,5,A_FiredChase,S_FIRED_WALK3,0,0}, // S_FIRED_WALK2
+{SPR_FDMN,32770,5,A_FiredChase,S_FIRED_WALK1,0,0}, // S_FIRED_WALK3
+{SPR_FDMN,32771,6,A_Pain,S_FIRED_WALK1,0,0}, // S_FIRED_PAIN1
+{SPR_FDMN,32778,3,A_FaceTarget,S_FIRED_ATTACK2,0,0}, // S_FIRED_ATTACK1
+{SPR_FDMN,32778,5,A_FiredAttack,S_FIRED_ATTACK3,0,0}, // S_FIRED_ATTACK2
+{SPR_FDMN,32778,5,A_FiredAttack,S_FIRED_ATTACK4,0,0}, // S_FIRED_ATTACK3
+{SPR_FDMN,32778,5,A_FiredAttack,S_FIRED_WALK1,0,0}, // S_FIRED_ATTACK4
+{SPR_FDMN,32771,4,A_FaceTarget,S_FIRED_DEATH2,0,0}, // S_FIRED_DEATH1
+{SPR_FDMN,32779,4,A_Scream,S_FIRED_DEATH3,0,0}, // S_FIRED_DEATH2
+{SPR_FDMN,32779,4,A_NoBlocking,S_FIRED_DEATH4,0,0}, // S_FIRED_DEATH3
+{SPR_FDMN,32779,200,NULL,S_NULL,0,0}, // S_FIRED_DEATH4
+{SPR_FDMN,12,5,A_FaceTarget,S_FIRED_XDEATH2,0,0}, // S_FIRED_XDEATH1
+{SPR_FDMN,13,5,A_NoBlocking,S_FIRED_XDEATH3,0,0}, // S_FIRED_XDEATH2
+{SPR_FDMN,14,5,A_FiredSplotch,S_NULL,0,0}, // S_FIRED_XDEATH3
+{SPR_FDMN,17,5,A_FreezeDeath,S_FIRED_ICE2,0,0}, // S_FIRED_ICE1
+{SPR_FDMN,17,1,A_FreezeDeathChunks,S_FIRED_ICE2,0,0}, // S_FIRED_ICE2
+{SPR_FDMN,15,3,NULL,S_FIRED_CORPSE2,0,0}, // S_FIRED_CORPSE1
+{SPR_FDMN,15,6,A_QueueCorpse,S_FIRED_CORPSE3,0,0}, // S_FIRED_CORPSE2
+{SPR_FDMN,24,-1,NULL,S_NULL,0,0}, // S_FIRED_CORPSE3
+{SPR_FDMN,16,3,NULL,S_FIRED_CORPSE5,0,0}, // S_FIRED_CORPSE4
+{SPR_FDMN,16,6,A_QueueCorpse,S_FIRED_CORPSE6,0,0}, // S_FIRED_CORPSE5
+{SPR_FDMN,25,-1,NULL,S_NULL,0,0}, // S_FIRED_CORPSE6
+{SPR_FDMN,18,4,NULL,S_FIRED_RDROP1,0,0}, // S_FIRED_RDROP1
+{SPR_FDMN,18,5,A_SmBounce,S_FIRED_RDEAD1_2,0,0}, // S_FIRED_RDEAD1_1
+{SPR_FDMN,18,200,NULL,S_NULL,0,0}, // S_FIRED_RDEAD1_2
+{SPR_FDMN,19,4,NULL,S_FIRED_RDROP2,0,0}, // S_FIRED_RDROP2
+{SPR_FDMN,19,5,A_SmBounce,S_FIRED_RDEAD2_2,0,0}, // S_FIRED_RDEAD2_1
+{SPR_FDMN,19,200,NULL,S_NULL,0,0}, // S_FIRED_RDEAD2_2
+{SPR_FDMN,20,4,NULL,S_FIRED_RDROP3,0,0}, // S_FIRED_RDROP3
+{SPR_FDMN,20,5,A_SmBounce,S_FIRED_RDEAD3_2,0,0}, // S_FIRED_RDEAD3_1
+{SPR_FDMN,20,200,NULL,S_NULL,0,0}, // S_FIRED_RDEAD3_2
+{SPR_FDMN,21,4,NULL,S_FIRED_RDROP4,0,0}, // S_FIRED_RDROP4
+{SPR_FDMN,21,5,A_SmBounce,S_FIRED_RDEAD4_2,0,0}, // S_FIRED_RDEAD4_1
+{SPR_FDMN,21,200,NULL,S_NULL,0,0}, // S_FIRED_RDEAD4_2
+{SPR_FDMN,22,4,NULL,S_FIRED_RDROP5,0,0}, // S_FIRED_RDROP5
+{SPR_FDMN,22,5,A_SmBounce,S_FIRED_RDEAD5_2,0,0}, // S_FIRED_RDEAD5_1
+{SPR_FDMN,22,200,NULL,S_NULL,0,0}, // S_FIRED_RDEAD5_2
+{SPR_FDMB,32768,5,NULL,S_FIRED_FX6_1,0,0}, // S_FIRED_FX6_1
+{SPR_FDMB,32769,5,NULL,S_FIRED_FX6_3,0,0}, // S_FIRED_FX6_2
+{SPR_FDMB,32770,5,NULL,S_FIRED_FX6_4,0,0}, // S_FIRED_FX6_3
+{SPR_FDMB,32771,5,NULL,S_FIRED_FX6_5,0,0}, // S_FIRED_FX6_4
+{SPR_FDMB,32772,5,NULL,S_NULL,0,0}, // S_FIRED_FX6_5
+{SPR_ICEY,0,10,A_IceGuyLook,S_ICEGUY_LOOK,0,0}, // S_ICEGUY_LOOK
+{SPR_ICEY,0,-1,NULL,S_ICEGUY_LOOK,0,0}, // S_ICEGUY_DORMANT
+{SPR_ICEY,0,4,A_Chase,S_ICEGUY_WALK2,0,0}, // S_ICEGUY_WALK1
+{SPR_ICEY,1,4,A_IceGuyChase,S_ICEGUY_WALK3,0,0}, // S_ICEGUY_WALK2
+{SPR_ICEY,2,4,A_Chase,S_ICEGUY_WALK4,0,0}, // S_ICEGUY_WALK3
+{SPR_ICEY,3,4,A_Chase,S_ICEGUY_WALK1,0,0}, // S_ICEGUY_WALK4
+{SPR_ICEY,4,3,A_FaceTarget,S_ICEGUY_ATK2,0,0}, // S_ICEGUY_ATK1
+{SPR_ICEY,5,3,A_FaceTarget,S_ICEGUY_ATK3,0,0}, // S_ICEGUY_ATK2
+{SPR_ICEY,32774,8,A_IceGuyAttack,S_ICEGUY_ATK4,0,0}, // S_ICEGUY_ATK3
+{SPR_ICEY,5,4,A_FaceTarget,S_ICEGUY_WALK1,0,0}, // S_ICEGUY_ATK4
+{SPR_ICEY,0,1,A_Pain,S_ICEGUY_WALK1,0,0}, // S_ICEGUY_PAIN1
+{SPR_ICEY,0,1,A_IceGuyDie,S_NULL,0,0}, // S_ICEGUY_DEATH
+{SPR_ICPR,32768,3,A_IceGuyMissilePuff,S_ICEGUY_FX2,0,0}, // S_ICEGUY_FX1
+{SPR_ICPR,32769,3,A_IceGuyMissilePuff,S_ICEGUY_FX3,0,0}, // S_ICEGUY_FX2
+{SPR_ICPR,32770,3,A_IceGuyMissilePuff,S_ICEGUY_FX1,0,0}, // S_ICEGUY_FX3
+{SPR_ICPR,32771,4,NULL,S_ICEGUY_FX_X2,0,0}, // S_ICEGUY_FX_X1
+{SPR_ICPR,32772,4,A_IceGuyMissileExplode,S_ICEGUY_FX_X3,0,0}, // S_ICEGUY_FX_X2
+{SPR_ICPR,32773,4,NULL,S_ICEGUY_FX_X4,0,0}, // S_ICEGUY_FX_X3
+{SPR_ICPR,32774,4,NULL,S_ICEGUY_FX_X5,0,0}, // S_ICEGUY_FX_X4
+{SPR_ICPR,32775,3,NULL,S_NULL,0,0}, // S_ICEGUY_FX_X5
+{SPR_ICPR,8,3,NULL,S_ICEFX_PUFF2,0,0}, // S_ICEFX_PUFF1
+{SPR_ICPR,9,3,NULL,S_ICEFX_PUFF3,0,0}, // S_ICEFX_PUFF2
+{SPR_ICPR,10,3,NULL,S_ICEFX_PUFF4,0,0}, // S_ICEFX_PUFF3
+{SPR_ICPR,11,2,NULL,S_ICEFX_PUFF5,0,0}, // S_ICEFX_PUFF4
+{SPR_ICPR,12,2,NULL,S_NULL,0,0}, // S_ICEFX_PUFF5
+{SPR_ICPR,32781,3,NULL,S_ICEGUY_FX2_2,0,0}, // S_ICEGUY_FX2_1
+{SPR_ICPR,32782,3,NULL,S_ICEGUY_FX2_3,0,0}, // S_ICEGUY_FX2_2
+{SPR_ICPR,32783,3,NULL,S_ICEGUY_FX2_1,0,0}, // S_ICEGUY_FX2_3
+{SPR_ICPR,32784,50,NULL,S_NULL,0,0}, // S_ICEGUY_BIT1
+{SPR_ICPR,32785,50,NULL,S_NULL,0,0}, // S_ICEGUY_BIT2
+{SPR_ICWS,0,2,NULL,S_ICEGUY_WISP1_2,0,0}, // S_ICEGUY_WISP1_1
+{SPR_ICWS,1,2,NULL,S_ICEGUY_WISP1_3,0,0}, // S_ICEGUY_WISP1_2
+{SPR_ICWS,2,2,NULL,S_ICEGUY_WISP1_4,0,0}, // S_ICEGUY_WISP1_3
+{SPR_ICWS,3,2,NULL,S_ICEGUY_WISP1_5,0,0}, // S_ICEGUY_WISP1_4
+{SPR_ICWS,4,2,NULL,S_ICEGUY_WISP1_6,0,0}, // S_ICEGUY_WISP1_5
+{SPR_ICWS,5,2,NULL,S_ICEGUY_WISP1_7,0,0}, // S_ICEGUY_WISP1_6
+{SPR_ICWS,6,2,NULL,S_ICEGUY_WISP1_8,0,0}, // S_ICEGUY_WISP1_7
+{SPR_ICWS,7,2,NULL,S_ICEGUY_WISP1_9,0,0}, // S_ICEGUY_WISP1_8
+{SPR_ICWS,8,2,NULL,S_NULL,0,0}, // S_ICEGUY_WISP1_9
+{SPR_ICWS,9,2,NULL,S_ICEGUY_WISP2_2,0,0}, // S_ICEGUY_WISP2_1
+{SPR_ICWS,10,2,NULL,S_ICEGUY_WISP2_3,0,0}, // S_ICEGUY_WISP2_2
+{SPR_ICWS,11,2,NULL,S_ICEGUY_WISP2_4,0,0}, // S_ICEGUY_WISP2_3
+{SPR_ICWS,12,2,NULL,S_ICEGUY_WISP2_5,0,0}, // S_ICEGUY_WISP2_4
+{SPR_ICWS,13,2,NULL,S_ICEGUY_WISP2_6,0,0}, // S_ICEGUY_WISP2_5
+{SPR_ICWS,14,2,NULL,S_ICEGUY_WISP2_7,0,0}, // S_ICEGUY_WISP2_6
+{SPR_ICWS,15,2,NULL,S_ICEGUY_WISP2_8,0,0}, // S_ICEGUY_WISP2_7
+{SPR_ICWS,16,2,NULL,S_ICEGUY_WISP2_9,0,0}, // S_ICEGUY_WISP2_8
+{SPR_ICWS,17,2,NULL,S_NULL,0,0}, // S_ICEGUY_WISP2_9
+{SPR_PLAY,0,2,NULL,S_FIGHTER2,0,0}, // S_FIGHTER
+{SPR_PLAY,0,3,A_ClassBossHealth,S_FIGHTERLOOK,0,0}, // S_FIGHTER2
+{SPR_PLAY,0,5,A_Look,S_FIGHTERLOOK,0,0}, // S_FIGHTERLOOK
+{SPR_PLAY,0,4,A_FastChase,S_FIGHTER_RUN2,0,0}, // S_FIGHTER_RUN1
+{SPR_PLAY,1,4,A_FastChase,S_FIGHTER_RUN3,0,0}, // S_FIGHTER_RUN2
+{SPR_PLAY,2,4,A_FastChase,S_FIGHTER_RUN4,0,0}, // S_FIGHTER_RUN3
+{SPR_PLAY,3,4,A_FastChase,S_FIGHTER_RUN1,0,0}, // S_FIGHTER_RUN4
+{SPR_PLAY,4,8,A_FaceTarget,S_FIGHTER_ATK2,0,0}, // S_FIGHTER_ATK1
+{SPR_PLAY,5,8,A_FighterAttack,S_FIGHTER_RUN1,0,0}, // S_FIGHTER_ATK2
+{SPR_PLAY,6,4,NULL,S_FIGHTER_PAIN2,0,0}, // S_FIGHTER_PAIN
+{SPR_PLAY,6,4,A_Pain,S_FIGHTER_RUN1,0,0}, // S_FIGHTER_PAIN2
+{SPR_PLAY,7,6,NULL,S_FIGHTER_DIE2,0,0}, // S_FIGHTER_DIE1
+{SPR_PLAY,8,6,A_Scream,S_FIGHTER_DIE3,0,0}, // S_FIGHTER_DIE2
+{SPR_PLAY,9,6,NULL,S_FIGHTER_DIE4,0,0}, // S_FIGHTER_DIE3
+{SPR_PLAY,10,6,NULL,S_FIGHTER_DIE5,0,0}, // S_FIGHTER_DIE4
+{SPR_PLAY,11,6,A_NoBlocking,S_FIGHTER_DIE6,0,0}, // S_FIGHTER_DIE5
+{SPR_PLAY,12,6,NULL,S_FIGHTER_DIE7,0,0}, // S_FIGHTER_DIE6
+{SPR_PLAY,13,-1,NULL,S_NULL,0,0}, // S_FIGHTER_DIE7
+{SPR_PLAY,14,5,A_Scream,S_FIGHTER_XDIE2,0,0}, // S_FIGHTER_XDIE1
+{SPR_PLAY,15,5,A_SkullPop,S_FIGHTER_XDIE3,0,0}, // S_FIGHTER_XDIE2
+{SPR_PLAY,17,5,A_NoBlocking,S_FIGHTER_XDIE4,0,0}, // S_FIGHTER_XDIE3
+{SPR_PLAY,18,5,NULL,S_FIGHTER_XDIE5,0,0}, // S_FIGHTER_XDIE4
+{SPR_PLAY,19,5,NULL,S_FIGHTER_XDIE6,0,0}, // S_FIGHTER_XDIE5
+{SPR_PLAY,20,5,NULL,S_FIGHTER_XDIE7,0,0}, // S_FIGHTER_XDIE6
+{SPR_PLAY,21,5,NULL,S_FIGHTER_XDIE8,0,0}, // S_FIGHTER_XDIE7
+{SPR_PLAY,22,-1,NULL,S_NULL,0,0}, // S_FIGHTER_XDIE8
+{SPR_PLAY,23,5,A_FreezeDeath,S_FIGHTER_ICE2,0,0}, // S_FIGHTER_ICE
+{SPR_PLAY,23,1,A_FreezeDeathChunks,S_FIGHTER_ICE2,0,0}, // S_FIGHTER_ICE2
+{SPR_CLER,0,2,NULL,S_CLERIC2,0,0}, // S_CLERIC
+{SPR_CLER,0,3,A_ClassBossHealth,S_CLERICLOOK,0,0}, // S_CLERIC2
+{SPR_CLER,0,5,A_Look,S_CLERICLOOK,0,0}, // S_CLERICLOOK
+{SPR_CLER,0,4,A_FastChase,S_CLERIC_RUN2,0,0}, // S_CLERIC_RUN1
+{SPR_CLER,1,4,A_FastChase,S_CLERIC_RUN3,0,0}, // S_CLERIC_RUN2
+{SPR_CLER,2,4,A_FastChase,S_CLERIC_RUN4,0,0}, // S_CLERIC_RUN3
+{SPR_CLER,3,4,A_FastChase,S_CLERIC_RUN1,0,0}, // S_CLERIC_RUN4
+{SPR_CLER,4,8,A_FaceTarget,S_CLERIC_ATK2,0,0}, // S_CLERIC_ATK1
+{SPR_CLER,5,8,A_FaceTarget,S_CLERIC_ATK3,0,0}, // S_CLERIC_ATK2
+{SPR_CLER,6,10,A_ClericAttack,S_CLERIC_RUN1,0,0}, // S_CLERIC_ATK3
+{SPR_CLER,7,4,NULL,S_CLERIC_PAIN2,0,0}, // S_CLERIC_PAIN
+{SPR_CLER,7,4,A_Pain,S_CLERIC_RUN1,0,0}, // S_CLERIC_PAIN2
+{SPR_CLER,8,6,NULL,S_CLERIC_DIE2,0,0}, // S_CLERIC_DIE1
+{SPR_CLER,10,6,A_Scream,S_CLERIC_DIE3,0,0}, // S_CLERIC_DIE2
+{SPR_CLER,11,6,NULL,S_CLERIC_DIE4,0,0}, // S_CLERIC_DIE3
+{SPR_CLER,11,6,NULL,S_CLERIC_DIE5,0,0}, // S_CLERIC_DIE4
+{SPR_CLER,12,6,A_NoBlocking,S_CLERIC_DIE6,0,0}, // S_CLERIC_DIE5
+{SPR_CLER,13,6,NULL,S_CLERIC_DIE7,0,0}, // S_CLERIC_DIE6
+{SPR_CLER,14,6,NULL,S_CLERIC_DIE8,0,0}, // S_CLERIC_DIE7
+{SPR_CLER,15,6,NULL,S_CLERIC_DIE9,0,0}, // S_CLERIC_DIE8
+{SPR_CLER,16,-1,NULL,S_NULL,0,0}, // S_CLERIC_DIE9
+{SPR_CLER,17,5,A_Scream,S_CLERIC_XDIE2,0,0}, // S_CLERIC_XDIE1
+{SPR_CLER,18,5,NULL,S_CLERIC_XDIE3,0,0}, // S_CLERIC_XDIE2
+{SPR_CLER,19,5,A_NoBlocking,S_CLERIC_XDIE4,0,0}, // S_CLERIC_XDIE3
+{SPR_CLER,20,5,NULL,S_CLERIC_XDIE5,0,0}, // S_CLERIC_XDIE4
+{SPR_CLER,21,5,NULL,S_CLERIC_XDIE6,0,0}, // S_CLERIC_XDIE5
+{SPR_CLER,22,5,NULL,S_CLERIC_XDIE7,0,0}, // S_CLERIC_XDIE6
+{SPR_CLER,23,5,NULL,S_CLERIC_XDIE8,0,0}, // S_CLERIC_XDIE7
+{SPR_CLER,24,5,NULL,S_CLERIC_XDIE9,0,0}, // S_CLERIC_XDIE8
+{SPR_CLER,25,5,NULL,S_CLERIC_XDIE10,0,0}, // S_CLERIC_XDIE9
+{SPR_CLER,26,-1,NULL,S_NULL,0,0}, // S_CLERIC_XDIE10
+{SPR_CLER,27,5,A_FreezeDeath,S_CLERIC_ICE2,0,0}, // S_CLERIC_ICE
+{SPR_CLER,27,1,A_FreezeDeathChunks,S_CLERIC_ICE2,0,0}, // S_CLERIC_ICE2
+{SPR_MAGE,0,2,NULL,S_MAGE2,0,0}, // S_MAGE
+{SPR_MAGE,0,3,A_ClassBossHealth,S_MAGELOOK,0,0}, // S_MAGE2
+{SPR_MAGE,0,5,A_Look,S_MAGELOOK,0,0}, // S_MAGELOOK
+{SPR_MAGE,0,4,A_FastChase,S_MAGE_RUN2,0,0}, // S_MAGE_RUN1
+{SPR_MAGE,1,4,A_FastChase,S_MAGE_RUN3,0,0}, // S_MAGE_RUN2
+{SPR_MAGE,2,4,A_FastChase,S_MAGE_RUN4,0,0}, // S_MAGE_RUN3
+{SPR_MAGE,3,4,A_FastChase,S_MAGE_RUN1,0,0}, // S_MAGE_RUN4
+{SPR_MAGE,4,8,A_FaceTarget,S_MAGE_ATK2,0,0}, // S_MAGE_ATK1
+{SPR_MAGE,32773,8,A_MageAttack,S_MAGE_RUN1,0,0}, // S_MAGE_ATK2
+{SPR_MAGE,6,4,NULL,S_MAGE_PAIN2,0,0}, // S_MAGE_PAIN
+{SPR_MAGE,6,4,A_Pain,S_MAGE_RUN1,0,0}, // S_MAGE_PAIN2
+{SPR_MAGE,7,6,NULL,S_MAGE_DIE2,0,0}, // S_MAGE_DIE1
+{SPR_MAGE,8,6,A_Scream,S_MAGE_DIE3,0,0}, // S_MAGE_DIE2
+{SPR_MAGE,9,6,NULL,S_MAGE_DIE4,0,0}, // S_MAGE_DIE3
+{SPR_MAGE,10,6,NULL,S_MAGE_DIE5,0,0}, // S_MAGE_DIE4
+{SPR_MAGE,11,6,A_NoBlocking,S_MAGE_DIE6,0,0}, // S_MAGE_DIE5
+{SPR_MAGE,12,6,NULL,S_MAGE_DIE7,0,0}, // S_MAGE_DIE6
+{SPR_MAGE,13,-1,NULL,S_NULL,0,0}, // S_MAGE_DIE7
+{SPR_MAGE,14,5,A_Scream,S_MAGE_XDIE2,0,0}, // S_MAGE_XDIE1
+{SPR_MAGE,15,5,NULL,S_MAGE_XDIE3,0,0}, // S_MAGE_XDIE2
+{SPR_MAGE,17,5,A_NoBlocking,S_MAGE_XDIE4,0,0}, // S_MAGE_XDIE3
+{SPR_MAGE,18,5,NULL,S_MAGE_XDIE5,0,0}, // S_MAGE_XDIE4
+{SPR_MAGE,19,5,NULL,S_MAGE_XDIE6,0,0}, // S_MAGE_XDIE5
+{SPR_MAGE,20,5,NULL,S_MAGE_XDIE7,0,0}, // S_MAGE_XDIE6
+{SPR_MAGE,21,5,NULL,S_MAGE_XDIE8,0,0}, // S_MAGE_XDIE7
+{SPR_MAGE,22,5,NULL,S_MAGE_XDIE9,0,0}, // S_MAGE_XDIE8
+{SPR_MAGE,23,-1,NULL,S_NULL,0,0}, // S_MAGE_XDIE9
+{SPR_MAGE,24,5,A_FreezeDeath,S_MAGE_ICE2,0,0}, // S_MAGE_ICE
+{SPR_MAGE,24,1,A_FreezeDeathChunks,S_MAGE_ICE2,0,0}, // S_MAGE_ICE2
+{SPR_SORC,0,3,NULL,S_SORC_SPAWN2,0,0}, // S_SORC_SPAWN1
+{SPR_SORC,0,2,A_SorcSpinBalls,S_SORC_LOOK1,0,0}, // S_SORC_SPAWN2
+{SPR_SORC,0,10,A_Look,S_SORC_LOOK1,0,0}, // S_SORC_LOOK1
+{SPR_SORC,0,5,A_Chase,S_SORC_WALK2,0,0}, // S_SORC_WALK1
+{SPR_SORC,1,5,A_Chase,S_SORC_WALK3,0,0}, // S_SORC_WALK2
+{SPR_SORC,2,5,A_Chase,S_SORC_WALK4,0,0}, // S_SORC_WALK3
+{SPR_SORC,3,5,A_Chase,S_SORC_WALK1,0,0}, // S_SORC_WALK4
+{SPR_SORC,6,8,NULL,S_SORC_PAIN2,0,0}, // S_SORC_PAIN1
+{SPR_SORC,6,8,A_Pain,S_SORC_WALK1,0,0}, // S_SORC_PAIN2
+{SPR_SORC,32773,6,A_FaceTarget,S_SORC_ATK2_2,0,0}, // S_SORC_ATK2_1
+{SPR_SORC,32773,6,A_SpeedBalls,S_SORC_ATK2_3,0,0}, // S_SORC_ATK2_2
+{SPR_SORC,32773,6,A_FaceTarget,S_SORC_ATK2_3,0,0}, // S_SORC_ATK2_3
+{SPR_SORC,32772,6,NULL,S_SORC_ATTACK2,0,0}, // S_SORC_ATTACK1
+{SPR_SORC,32772,6,A_SpawnFizzle,S_SORC_ATTACK3,0,0}, // S_SORC_ATTACK2
+{SPR_SORC,32772,5,A_FaceTarget,S_SORC_ATTACK2,0,0}, // S_SORC_ATTACK3
+{SPR_SORC,32772,2,NULL,S_SORC_ATTACK5,0,0}, // S_SORC_ATTACK4
+{SPR_SORC,32772,2,A_SorcBossAttack,S_SORC_WALK1,0,0}, // S_SORC_ATTACK5
+{SPR_SORC,32775,5,NULL,S_SORC_DIE2,0,0}, // S_SORC_DIE1
+{SPR_SORC,32776,5,A_FaceTarget,S_SORC_DIE3,0,0}, // S_SORC_DIE2
+{SPR_SORC,32777,5,A_Scream,S_SORC_DIE4,0,0}, // S_SORC_DIE3
+{SPR_SORC,32778,5,NULL,S_SORC_DIE5,0,0}, // S_SORC_DIE4
+{SPR_SORC,32779,5,NULL,S_SORC_DIE6,0,0}, // S_SORC_DIE5
+{SPR_SORC,32780,5,NULL,S_SORC_DIE7,0,0}, // S_SORC_DIE6
+{SPR_SORC,32781,5,NULL,S_SORC_DIE8,0,0}, // S_SORC_DIE7
+{SPR_SORC,32782,5,NULL,S_SORC_DIE9,0,0}, // S_SORC_DIE8
+{SPR_SORC,32783,5,NULL,S_SORC_DIE0,0,0}, // S_SORC_DIE9
+{SPR_SORC,32784,5,NULL,S_SORC_DIEA,0,0}, // S_SORC_DIE0
+{SPR_SORC,32785,5,NULL,S_SORC_DIEB,0,0}, // S_SORC_DIEA
+{SPR_SORC,32786,5,NULL,S_SORC_DIEC,0,0}, // S_SORC_DIEB
+{SPR_SORC,32787,5,NULL,S_SORC_DIED,0,0}, // S_SORC_DIEC
+{SPR_SORC,32788,5,A_NoBlocking,S_SORC_DIEE,0,0}, // S_SORC_DIED
+{SPR_SORC,32789,5,NULL,S_SORC_DIEF,0,0}, // S_SORC_DIEE
+{SPR_SORC,32790,5,NULL,S_SORC_DIEG,0,0}, // S_SORC_DIEF
+{SPR_SORC,32791,5,NULL,S_SORC_DIEH,0,0}, // S_SORC_DIEG
+{SPR_SORC,32792,5,NULL,S_SORC_DIEI,0,0}, // S_SORC_DIEH
+{SPR_SORC,32793,-1,NULL,S_NULL,0,0}, // S_SORC_DIEI
+{SPR_SBMP,0,2,A_SorcBallOrbit,S_SORCBALL1_2,0,0}, // S_SORCBALL1_1
+{SPR_SBMP,1,2,A_SorcBallOrbit,S_SORCBALL1_3,0,0}, // S_SORCBALL1_2
+{SPR_SBMP,2,2,A_SorcBallOrbit,S_SORCBALL1_4,0,0}, // S_SORCBALL1_3
+{SPR_SBMP,3,2,A_SorcBallOrbit,S_SORCBALL1_5,0,0}, // S_SORCBALL1_4
+{SPR_SBMP,4,2,A_SorcBallOrbit,S_SORCBALL1_6,0,0}, // S_SORCBALL1_5
+{SPR_SBMP,5,2,A_SorcBallOrbit,S_SORCBALL1_7,0,0}, // S_SORCBALL1_6
+{SPR_SBMP,6,2,A_SorcBallOrbit,S_SORCBALL1_8,0,0}, // S_SORCBALL1_7
+{SPR_SBMP,7,2,A_SorcBallOrbit,S_SORCBALL1_9,0,0}, // S_SORCBALL1_8
+{SPR_SBMP,8,2,A_SorcBallOrbit,S_SORCBALL1_0,0,0}, // S_SORCBALL1_9
+{SPR_SBMP,9,2,A_SorcBallOrbit,S_SORCBALL1_A,0,0}, // S_SORCBALL1_0
+{SPR_SBMP,10,2,A_SorcBallOrbit,S_SORCBALL1_B,0,0}, // S_SORCBALL1_A
+{SPR_SBMP,11,2,A_SorcBallOrbit,S_SORCBALL1_C,0,0}, // S_SORCBALL1_B
+{SPR_SBMP,12,2,A_SorcBallOrbit,S_SORCBALL1_D,0,0}, // S_SORCBALL1_C
+{SPR_SBMP,13,2,A_SorcBallOrbit,S_SORCBALL1_E,0,0}, // S_SORCBALL1_D
+{SPR_SBMP,14,2,A_SorcBallOrbit,S_SORCBALL1_F,0,0}, // S_SORCBALL1_E
+{SPR_SBMP,15,2,A_SorcBallOrbit,S_SORCBALL1_1,0,0}, // S_SORCBALL1_F
+{SPR_SBMP,0,5,A_SorcBallPop,S_SORCBALL1_D2,0,0}, // S_SORCBALL1_D1
+{SPR_SBMP,1,2,A_BounceCheck,S_SORCBALL1_D2,0,0}, // S_SORCBALL1_D2
+{SPR_SBS4,3,5,A_Explode,S_SORCBALL1_D6,0,0}, // S_SORCBALL1_D5
+{SPR_SBS4,4,5,NULL,S_SORCBALL1_D7,0,0}, // S_SORCBALL1_D6
+{SPR_SBS4,5,6,NULL,S_SORCBALL1_D8,0,0}, // S_SORCBALL1_D7
+{SPR_SBS4,6,6,NULL,S_SORCBALL1_D9,0,0}, // S_SORCBALL1_D8
+{SPR_SBS4,7,6,NULL,S_NULL,0,0}, // S_SORCBALL1_D9
+{SPR_SBMB,0,2,A_SorcBallOrbit,S_SORCBALL2_2,0,0}, // S_SORCBALL2_1
+{SPR_SBMB,1,2,A_SorcBallOrbit,S_SORCBALL2_3,0,0}, // S_SORCBALL2_2
+{SPR_SBMB,2,2,A_SorcBallOrbit,S_SORCBALL2_4,0,0}, // S_SORCBALL2_3
+{SPR_SBMB,3,2,A_SorcBallOrbit,S_SORCBALL2_5,0,0}, // S_SORCBALL2_4
+{SPR_SBMB,4,2,A_SorcBallOrbit,S_SORCBALL2_6,0,0}, // S_SORCBALL2_5
+{SPR_SBMB,5,2,A_SorcBallOrbit,S_SORCBALL2_7,0,0}, // S_SORCBALL2_6
+{SPR_SBMB,6,2,A_SorcBallOrbit,S_SORCBALL2_8,0,0}, // S_SORCBALL2_7
+{SPR_SBMB,7,2,A_SorcBallOrbit,S_SORCBALL2_9,0,0}, // S_SORCBALL2_8
+{SPR_SBMB,8,2,A_SorcBallOrbit,S_SORCBALL2_0,0,0}, // S_SORCBALL2_9
+{SPR_SBMB,9,2,A_SorcBallOrbit,S_SORCBALL2_A,0,0}, // S_SORCBALL2_0
+{SPR_SBMB,10,2,A_SorcBallOrbit,S_SORCBALL2_B,0,0}, // S_SORCBALL2_A
+{SPR_SBMB,11,2,A_SorcBallOrbit,S_SORCBALL2_C,0,0}, // S_SORCBALL2_B
+{SPR_SBMB,12,2,A_SorcBallOrbit,S_SORCBALL2_D,0,0}, // S_SORCBALL2_C
+{SPR_SBMB,13,2,A_SorcBallOrbit,S_SORCBALL2_E,0,0}, // S_SORCBALL2_D
+{SPR_SBMB,14,2,A_SorcBallOrbit,S_SORCBALL2_F,0,0}, // S_SORCBALL2_E
+{SPR_SBMB,15,2,A_SorcBallOrbit,S_SORCBALL2_1,0,0}, // S_SORCBALL2_F
+{SPR_SBMB,0,5,A_SorcBallPop,S_SORCBALL2_D2,0,0}, // S_SORCBALL2_D1
+{SPR_SBMB,1,2,A_BounceCheck,S_SORCBALL2_D2,0,0}, // S_SORCBALL2_D2
+{SPR_SBS3,3,5,A_Explode,S_SORCBALL2_D6,0,0}, // S_SORCBALL2_D5
+{SPR_SBS3,4,5,NULL,S_SORCBALL2_D7,0,0}, // S_SORCBALL2_D6
+{SPR_SBS3,5,6,NULL,S_SORCBALL2_D8,0,0}, // S_SORCBALL2_D7
+{SPR_SBS3,6,6,NULL,S_SORCBALL2_D9,0,0}, // S_SORCBALL2_D8
+{SPR_SBS3,7,6,NULL,S_NULL,0,0}, // S_SORCBALL2_D9
+{SPR_SBMG,0,2,A_SorcBallOrbit,S_SORCBALL3_2,0,0}, // S_SORCBALL3_1
+{SPR_SBMG,1,2,A_SorcBallOrbit,S_SORCBALL3_3,0,0}, // S_SORCBALL3_2
+{SPR_SBMG,2,2,A_SorcBallOrbit,S_SORCBALL3_4,0,0}, // S_SORCBALL3_3
+{SPR_SBMG,3,2,A_SorcBallOrbit,S_SORCBALL3_5,0,0}, // S_SORCBALL3_4
+{SPR_SBMG,4,2,A_SorcBallOrbit,S_SORCBALL3_6,0,0}, // S_SORCBALL3_5
+{SPR_SBMG,5,2,A_SorcBallOrbit,S_SORCBALL3_7,0,0}, // S_SORCBALL3_6
+{SPR_SBMG,6,2,A_SorcBallOrbit,S_SORCBALL3_8,0,0}, // S_SORCBALL3_7
+{SPR_SBMG,7,2,A_SorcBallOrbit,S_SORCBALL3_9,0,0}, // S_SORCBALL3_8
+{SPR_SBMG,8,2,A_SorcBallOrbit,S_SORCBALL3_0,0,0}, // S_SORCBALL3_9
+{SPR_SBMG,9,2,A_SorcBallOrbit,S_SORCBALL3_A,0,0}, // S_SORCBALL3_0
+{SPR_SBMG,10,2,A_SorcBallOrbit,S_SORCBALL3_B,0,0}, // S_SORCBALL3_A
+{SPR_SBMG,11,2,A_SorcBallOrbit,S_SORCBALL3_C,0,0}, // S_SORCBALL3_B
+{SPR_SBMG,12,2,A_SorcBallOrbit,S_SORCBALL3_D,0,0}, // S_SORCBALL3_C
+{SPR_SBMG,13,2,A_SorcBallOrbit,S_SORCBALL3_E,0,0}, // S_SORCBALL3_D
+{SPR_SBMG,14,2,A_SorcBallOrbit,S_SORCBALL3_F,0,0}, // S_SORCBALL3_E
+{SPR_SBMG,15,2,A_SorcBallOrbit,S_SORCBALL3_1,0,0}, // S_SORCBALL3_F
+{SPR_SBMG,0,5,A_SorcBallPop,S_SORCBALL3_D2,0,0}, // S_SORCBALL3_D1
+{SPR_SBMG,1,2,A_BounceCheck,S_SORCBALL3_D2,0,0}, // S_SORCBALL3_D2
+{SPR_SBS3,3,5,A_Explode,S_SORCBALL3_D6,0,0}, // S_SORCBALL3_D5
+{SPR_SBS3,4,5,NULL,S_SORCBALL3_D7,0,0}, // S_SORCBALL3_D6
+{SPR_SBS3,5,6,NULL,S_SORCBALL3_D8,0,0}, // S_SORCBALL3_D7
+{SPR_SBS3,6,6,NULL,S_SORCBALL3_D9,0,0}, // S_SORCBALL3_D8
+{SPR_SBS3,7,6,NULL,S_NULL,0,0}, // S_SORCBALL3_D9
+{SPR_SBS1,32768,2,NULL,S_SORCFX1_2,0,0}, // S_SORCFX1_1
+{SPR_SBS1,32769,3,A_SorcFX1Seek,S_SORCFX1_3,0,0}, // S_SORCFX1_2
+{SPR_SBS1,32770,3,A_SorcFX1Seek,S_SORCFX1_4,0,0}, // S_SORCFX1_3
+{SPR_SBS1,32771,3,A_SorcFX1Seek,S_SORCFX1_1,0,0}, // S_SORCFX1_4
+{SPR_FHFX,32786,2,A_Explode,S_SORCFX1_D2,0,0}, // S_SORCFX1_D1
+{SPR_FHFX,32786,6,NULL,S_SORCFX1_D3,0,0}, // S_SORCFX1_D2
+{SPR_FHFX,32786,6,NULL,S_NULL,0,0}, // S_SORCFX1_D3
+{SPR_SBS2,32768,3,A_SorcFX2Split,S_SORCFX2_SPLIT1,0,0}, // S_SORCFX2_SPLIT1
+{SPR_SBS2,32768,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT2,0,0}, // S_SORCFX2_ORBIT1
+{SPR_SBS2,32769,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT3,0,0}, // S_SORCFX2_ORBIT2
+{SPR_SBS2,32770,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT4,0,0}, // S_SORCFX2_ORBIT3
+{SPR_SBS2,32771,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT5,0,0}, // S_SORCFX2_ORBIT4
+{SPR_SBS2,32772,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT6,0,0}, // S_SORCFX2_ORBIT5
+{SPR_SBS2,32773,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT7,0,0}, // S_SORCFX2_ORBIT6
+{SPR_SBS2,32774,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT8,0,0}, // S_SORCFX2_ORBIT7
+{SPR_SBS2,32775,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT9,0,0}, // S_SORCFX2_ORBIT8
+{SPR_SBS2,32776,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT0,0,0}, // S_SORCFX2_ORBIT9
+{SPR_SBS2,32777,2,A_SorcFX2Orbit,S_SORCFX2_ORBITA,0,0}, // S_SORCFX2_ORBIT0
+{SPR_SBS2,32778,2,A_SorcFX2Orbit,S_SORCFX2_ORBITB,0,0}, // S_SORCFX2_ORBITA
+{SPR_SBS2,32779,2,A_SorcFX2Orbit,S_SORCFX2_ORBITC,0,0}, // S_SORCFX2_ORBITB
+{SPR_SBS2,32780,2,A_SorcFX2Orbit,S_SORCFX2_ORBITD,0,0}, // S_SORCFX2_ORBITC
+{SPR_SBS2,32781,2,A_SorcFX2Orbit,S_SORCFX2_ORBITE,0,0}, // S_SORCFX2_ORBITD
+{SPR_SBS2,32782,2,A_SorcFX2Orbit,S_SORCFX2_ORBITF,0,0}, // S_SORCFX2_ORBITE
+{SPR_SBS2,32783,2,A_SorcFX2Orbit,S_SORCFX2_ORBIT1,0,0}, // S_SORCFX2_ORBITF
+{SPR_SBS2,0,10,NULL,S_NULL,0,0}, // S_SORCFX2T1
+{SPR_SBS3,32768,2,NULL,S_SORCFX3_2,0,0}, // S_SORCFX3_1
+{SPR_SBS3,32769,2,NULL,S_SORCFX3_3,0,0}, // S_SORCFX3_2
+{SPR_SBS3,32770,2,NULL,S_SORCFX3_1,0,0}, // S_SORCFX3_3
+{SPR_SBS3,32768,4,NULL,S_BISHMORPHA,0,0}, // S_BISHMORPH1
+{SPR_BISH,15,4,A_SorcererBishopEntry,S_BISHMORPHB,0,0}, // S_BISHMORPHA
+{SPR_BISH,14,4,NULL,S_BISHMORPHC,0,0}, // S_BISHMORPHB
+{SPR_BISH,13,4,NULL,S_BISHMORPHD,0,0}, // S_BISHMORPHC
+{SPR_BISH,12,3,NULL,S_BISHMORPHE,0,0}, // S_BISHMORPHD
+{SPR_BISH,11,3,NULL,S_BISHMORPHF,0,0}, // S_BISHMORPHE
+{SPR_BISH,10,3,NULL,S_BISHMORPHG,0,0}, // S_BISHMORPHF
+{SPR_BISH,9,3,NULL,S_BISHMORPHH,0,0}, // S_BISHMORPHG
+{SPR_BISH,8,3,NULL,S_BISHMORPHI,0,0}, // S_BISHMORPHH
+{SPR_BISH,7,3,NULL,S_BISHMORPHJ,0,0}, // S_BISHMORPHI
+{SPR_BISH,6,3,A_SpawnBishop,S_NULL,0,0}, // S_BISHMORPHJ
+{SPR_SBS3,3,3,NULL,S_SORCFX3_EXP2,0,0}, // S_SORCFX3_EXP1
+{SPR_SBS3,4,3,NULL,S_SORCFX3_EXP3,0,0}, // S_SORCFX3_EXP2
+{SPR_SBS3,5,3,NULL,S_SORCFX3_EXP4,0,0}, // S_SORCFX3_EXP3
+{SPR_SBS3,6,3,NULL,S_SORCFX3_EXP5,0,0}, // S_SORCFX3_EXP4
+{SPR_SBS3,7,3,NULL,S_NULL,0,0}, // S_SORCFX3_EXP5
+{SPR_SBS4,32768,2,A_SorcFX4Check,S_SORCFX4_2,0,0}, // S_SORCFX4_1
+{SPR_SBS4,32769,2,A_SorcFX4Check,S_SORCFX4_3,0,0}, // S_SORCFX4_2
+{SPR_SBS4,32770,2,A_SorcFX4Check,S_SORCFX4_1,0,0}, // S_SORCFX4_3
+{SPR_SBS4,32771,2,NULL,S_SORCFX4_D2,0,0}, // S_SORCFX4_D1
+{SPR_SBS4,32772,2,A_Explode,S_SORCFX4_D3,0,0}, // S_SORCFX4_D2
+{SPR_SBS4,32773,2,NULL,S_SORCFX4_D4,0,0}, // S_SORCFX4_D3
+{SPR_SBS4,32774,2,NULL,S_SORCFX4_D5,0,0}, // S_SORCFX4_D4
+{SPR_SBS4,32775,2,NULL,S_NULL,0,0}, // S_SORCFX4_D5
+{SPR_SBFX,32768,4,NULL,S_SORCSPARK2,0,0}, // S_SORCSPARK1
+{SPR_SBFX,32769,4,NULL,S_SORCSPARK3,0,0}, // S_SORCSPARK2
+{SPR_SBFX,32770,4,NULL,S_SORCSPARK4,0,0}, // S_SORCSPARK3
+{SPR_SBFX,32771,4,NULL,S_SORCSPARK5,0,0}, // S_SORCSPARK4
+{SPR_SBFX,32772,4,NULL,S_SORCSPARK6,0,0}, // S_SORCSPARK5
+{SPR_SBFX,32773,4,NULL,S_SORCSPARK7,0,0}, // S_SORCSPARK6
+{SPR_SBFX,32774,4,NULL,S_NULL,0,0}, // S_SORCSPARK7
+{SPR_RADE,0,4,NULL,S_BLASTEFFECT2,0,0}, // S_BLASTEFFECT1
+{SPR_RADE,1,4,NULL,S_BLASTEFFECT3,0,0}, // S_BLASTEFFECT2
+{SPR_RADE,2,4,NULL,S_BLASTEFFECT4,0,0}, // S_BLASTEFFECT3
+{SPR_RADE,3,4,NULL,S_BLASTEFFECT5,0,0}, // S_BLASTEFFECT4
+{SPR_RADE,4,4,NULL,S_BLASTEFFECT6,0,0}, // S_BLASTEFFECT5
+{SPR_RADE,5,4,NULL,S_BLASTEFFECT7,0,0}, // S_BLASTEFFECT6
+{SPR_RADE,6,4,NULL,S_BLASTEFFECT8,0,0}, // S_BLASTEFFECT7
+{SPR_RADE,7,4,NULL,S_BLASTEFFECT9,0,0}, // S_BLASTEFFECT8
+{SPR_RADE,8,4,NULL,S_NULL,0,0}, // S_BLASTEFFECT9
+{SPR_WATR,0,5,NULL,S_WATERDRIP1,0,0}, // S_WATERDRIP1
+{SPR_KORX,0,5,A_Look,S_KORAX_LOOK1,0,0}, // S_KORAX_LOOK1
+{SPR_KORX,0,3,A_KoraxStep2,S_KORAX_CHASE2,0,0}, // S_KORAX_CHASE1
+{SPR_KORX,0,3,A_KoraxChase,S_KORAX_CHASE3,0,0}, // S_KORAX_CHASE2
+{SPR_KORX,0,3,A_KoraxChase,S_KORAX_CHASE4,0,0}, // S_KORAX_CHASE3
+{SPR_KORX,0,3,A_KoraxChase,S_KORAX_CHASE5,0,0}, // S_KORAX_CHASE4
+{SPR_KORX,1,3,A_KoraxStep,S_KORAX_CHASE6,0,0}, // S_KORAX_CHASE5
+{SPR_KORX,1,3,A_KoraxChase,S_KORAX_CHASE7,0,0}, // S_KORAX_CHASE6
+{SPR_KORX,1,3,A_KoraxChase,S_KORAX_CHASE8,0,0}, // S_KORAX_CHASE7
+{SPR_KORX,1,3,A_KoraxChase,S_KORAX_CHASE9,0,0}, // S_KORAX_CHASE8
+{SPR_KORX,2,3,A_KoraxStep2,S_KORAX_CHASE0,0,0}, // S_KORAX_CHASE9
+{SPR_KORX,2,3,A_KoraxChase,S_KORAX_CHASEA,0,0}, // S_KORAX_CHASE0
+{SPR_KORX,2,3,A_KoraxChase,S_KORAX_CHASEB,0,0}, // S_KORAX_CHASEA
+{SPR_KORX,2,3,A_KoraxChase,S_KORAX_CHASEC,0,0}, // S_KORAX_CHASEB
+{SPR_KORX,3,3,A_KoraxStep,S_KORAX_CHASED,0,0}, // S_KORAX_CHASEC
+{SPR_KORX,3,3,A_KoraxChase,S_KORAX_CHASEE,0,0}, // S_KORAX_CHASED
+{SPR_KORX,3,3,A_KoraxChase,S_KORAX_CHASEF,0,0}, // S_KORAX_CHASEE
+{SPR_KORX,3,3,A_KoraxChase,S_KORAX_CHASE1,0,0}, // S_KORAX_CHASEF
+{SPR_KORX,7,5,A_Pain,S_KORAX_PAIN2,0,0}, // S_KORAX_PAIN1
+{SPR_KORX,7,5,NULL,S_KORAX_CHASE2,0,0}, // S_KORAX_PAIN2
+{SPR_KORX,32772,2,A_FaceTarget,S_KORAX_ATTACK2,0,0}, // S_KORAX_ATTACK1
+{SPR_KORX,32772,5,A_KoraxDecide,S_KORAX_ATTACK2,0,0}, // S_KORAX_ATTACK2
+{SPR_KORX,32772,4,A_FaceTarget,S_KORAX_MISSILE2,0,0}, // S_KORAX_MISSILE1
+{SPR_KORX,32773,8,A_KoraxMissile,S_KORAX_MISSILE3,0,0}, // S_KORAX_MISSILE2
+{SPR_KORX,32772,8,NULL,S_KORAX_CHASE2,0,0}, // S_KORAX_MISSILE3
+{SPR_KORX,32772,5,A_FaceTarget,S_KORAX_COMMAND2,0,0}, // S_KORAX_COMMAND1
+{SPR_KORX,32790,10,A_FaceTarget,S_KORAX_COMMAND3,0,0}, // S_KORAX_COMMAND2
+{SPR_KORX,32774,15,A_KoraxCommand,S_KORAX_COMMAND4,0,0}, // S_KORAX_COMMAND3
+{SPR_KORX,32790,10,NULL,S_KORAX_COMMAND5,0,0}, // S_KORAX_COMMAND4
+{SPR_KORX,32772,5,NULL,S_KORAX_CHASE2,0,0}, // S_KORAX_COMMAND5
+{SPR_KORX,8,5,NULL,S_KORAX_DEATH2,0,0}, // S_KORAX_DEATH1
+{SPR_KORX,9,5,A_FaceTarget,S_KORAX_DEATH3,0,0}, // S_KORAX_DEATH2
+{SPR_KORX,10,5,A_Scream,S_KORAX_DEATH4,0,0}, // S_KORAX_DEATH3
+{SPR_KORX,11,5,NULL,S_KORAX_DEATH5,0,0}, // S_KORAX_DEATH4
+{SPR_KORX,12,5,NULL,S_KORAX_DEATH6,0,0}, // S_KORAX_DEATH5
+{SPR_KORX,13,5,NULL,S_KORAX_DEATH7,0,0}, // S_KORAX_DEATH6
+{SPR_KORX,14,5,NULL,S_KORAX_DEATH8,0,0}, // S_KORAX_DEATH7
+{SPR_KORX,15,5,NULL,S_KORAX_DEATH9,0,0}, // S_KORAX_DEATH8
+{SPR_KORX,16,10,NULL,S_KORAX_DEATH0,0,0}, // S_KORAX_DEATH9
+{SPR_KORX,17,5,A_KoraxBonePop,S_KORAX_DEATHA,0,0}, // S_KORAX_DEATH0
+{SPR_KORX,18,5,A_NoBlocking,S_KORAX_DEATHB,0,0}, // S_KORAX_DEATHA
+{SPR_KORX,19,5,NULL,S_KORAX_DEATHC,0,0}, // S_KORAX_DEATHB
+{SPR_KORX,20,5,NULL,S_KORAX_DEATHD,0,0}, // S_KORAX_DEATHC
+{SPR_KORX,21,-1,NULL,S_NULL,0,0}, // S_KORAX_DEATHD
+{SPR_SPIR,0,5,A_KSpiritRoam,S_KSPIRIT_ROAM2,0,0}, // S_KSPIRIT_ROAM1
+{SPR_SPIR,1,5,A_KSpiritRoam,S_KSPIRIT_ROAM1,0,0}, // S_KSPIRIT_ROAM2
+{SPR_SPIR,3,5,NULL,S_KSPIRIT_DEATH2,0,0}, // S_KSPIRIT_DEATH1
+{SPR_SPIR,4,5,NULL,S_KSPIRIT_DEATH3,0,0}, // S_KSPIRIT_DEATH2
+{SPR_SPIR,5,5,NULL,S_KSPIRIT_DEATH4,0,0}, // S_KSPIRIT_DEATH3
+{SPR_SPIR,6,5,NULL,S_KSPIRIT_DEATH5,0,0}, // S_KSPIRIT_DEATH4
+{SPR_SPIR,7,5,NULL,S_KSPIRIT_DEATH6,0,0}, // S_KSPIRIT_DEATH5
+{SPR_SPIR,8,5,NULL,S_NULL,0,0}, // S_KSPIRIT_DEATH6
+{SPR_MLFX,32776,2,NULL,S_KBOLT2,0,0}, // S_KBOLT1
+{SPR_MLFX,32777,2,A_KBoltRaise,S_KBOLT3,0,0}, // S_KBOLT2
+{SPR_MLFX,32776,2,A_KBolt,S_KBOLT4,0,0}, // S_KBOLT3
+{SPR_MLFX,32777,2,A_KBolt,S_KBOLT5,0,0}, // S_KBOLT4
+{SPR_MLFX,32778,2,A_KBolt,S_KBOLT6,0,0}, // S_KBOLT5
+{SPR_MLFX,32779,2,A_KBolt,S_KBOLT7,0,0}, // S_KBOLT6
+{SPR_MLFX,32780,2,A_KBolt,S_KBOLT3,0,0}, // S_KBOLT7
+{SPR_MAN1,0,2,NULL,S_SPAWNBATS2,0,0}, // S_SPAWNBATS1
+{SPR_MAN1,0,2,A_BatSpawnInit,S_SPAWNBATS3,0,0}, // S_SPAWNBATS2
+{SPR_MAN1,0,2,A_BatSpawn,S_SPAWNBATS3,0,0}, // S_SPAWNBATS3
+{SPR_MAN1,0,-1,NULL,S_NULL,0,0}, // S_SPAWNBATS_OFF
+{SPR_ABAT,0,2,A_BatMove,S_BAT2,0,0}, // S_BAT1
+{SPR_ABAT,1,2,A_BatMove,S_BAT3,0,0}, // S_BAT2
+{SPR_ABAT,2,2,A_BatMove,S_BAT1,0,0}, // S_BAT3
+{SPR_ABAT,0,2,NULL,S_NULL,0,0}, // S_BAT_DEATH
+#ifdef ASSASSIN
+{SPR_AKTR,0,1,A_WeaponReady,S_KATARREADY,0,0}, // S_KATARREADY
+{SPR_AKTR,0,1,A_Lower,S_KATARDOWN,0,0}, // S_KATARDOWN
+{SPR_AKTR,0,1,A_Raise,S_KATARUP,0,0}, // S_KATARUP
+{SPR_AKTR,1,4,NULL,S_KATARATK1_2,5,40}, // S_KATARATK1_1
+{SPR_AKTR,2,3,NULL,S_KATARATK1_3,5,40}, // S_KATARATK1_2
+{SPR_AKTR,3,3,A_AKnifeAttack,S_KATARATK1_4,5,40}, // S_KATARATK1_3
+{SPR_AKTR,2,3,NULL,S_KATARATK1_5,5,40}, // S_KATARATK1_4
+{SPR_AKTR,1,5,A_ReFire,S_KATARREADY,5,40}, // S_KATARATK1_5
+{SPR_AKTR,3,4,NULL,S_KATARATK2_2,5,40}, // S_KATARATK2_1
+{SPR_AKTR,4,4,NULL,S_KATARATK2_3,5,40}, // S_KATARATK2_2
+{SPR_AKTR,4,1,NULL,S_KATARATK2_4,15,50}, // S_KATARATK2_3
+{SPR_AKTR,4,1,NULL,S_KATARATK2_5,25,60}, // S_KATARATK2_4
+{SPR_AKTR,4,1,NULL,S_KATARATK2_6,35,70}, // S_KATARATK2_5
+{SPR_AKTR,4,1,NULL,S_KATARATK2_7,45,80}, // S_KATARATK2_6
+{SPR_AKTR,4,1,NULL,S_KATARATK2_8,55,90}, // S_KATARATK2_7
+{SPR_AKTR,4,1,NULL,S_KATARATK2_9,65,100}, // S_KATARATK2_8
+{SPR_AKTR,4,10,NULL,S_KATARREADY,0,150}, // S_KATARATK2_9
+{SPR_ACSB,2,4,NULL,S_ACROSSREADY1,0,0}, // S_ACROSSREADY
+{SPR_ACSB,1,3,NULL,S_ACROSSREADY2,0,0}, // S_ACROSSREADY1
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY3,0,0}, // S_ACROSSREADY2
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY4,0,0}, // S_ACROSSREADY3
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY5,0,0}, // S_ACROSSREADY4
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY6,0,0}, // S_ACROSSREADY5
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY7,0,0}, // S_ACROSSREADY6
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY8,0,0}, // S_ACROSSREADY7
+{SPR_ACSB,0,1,A_WeaponReady,S_ACROSSREADY9,0,0}, // S_ACROSSREADY8
+{SPR_ACSB,0,1,NULL,S_ACROSSREADY2,0,0}, // S_ACROSSREADY9
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSBLINK2,0,0}, // S_ACROSSBLINK1
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSBLINK3,0,0}, // S_ACROSSBLINK2
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSBLINK4,0,0}, // S_ACROSSBLINK3
+{SPR_ACSB,2,1,A_WeaponReady,S_ACROSSBLINK5,0,0}, // S_ACROSSBLINK4
+{SPR_ACSB,2,1,A_WeaponReady,S_ACROSSBLINK6,0,0}, // S_ACROSSBLINK5
+{SPR_ACSB,2,1,A_WeaponReady,S_ACROSSBLINK7,0,0}, // S_ACROSSBLINK6
+{SPR_ACSB,2,1,A_WeaponReady,S_ACROSSBLINK8,0,0}, // S_ACROSSBLINK7
+{SPR_ACSB,2,1,A_WeaponReady,S_ACROSSBLINK9,0,0}, // S_ACROSSBLINK8
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSBLINK10,0,0}, // S_ACROSSBLINK9
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSBLINK11,0,0}, // S_ACROSSBLINK10
+{SPR_ACSB,1,1,A_WeaponReady,S_ACROSSREADY2,0,0}, // S_ACROSSBLINK11
+{SPR_ACSB,1,3,NULL,S_ACROSSDOWN2,0,0}, // S_ACROSSDOWN
+{SPR_ACSB,2,4,NULL,S_ACROSSDOWN3,0,0}, // S_ACROSSDOWN2
+{SPR_ACSB,2,1,A_Lower,S_ACROSSDOWN3,0,0}, // S_ACROSSDOWN3
+{SPR_ACSB,2,1,A_Raise,S_ACROSSUP,0,0}, // S_ACROSSUP
+/* jim {SPR_ACSB,0,1,A_ACrossCheck,S_ACROSSATK_2,0,45}, // S_ACROSSATK_1 */
+{SPR_ACSB,0,1,NULL,S_ACROSSATK_2,0,45}, // S_ACROSSATK_1
+{SPR_ACSB,1,1,A_ACrossAttack,S_ACROSSATK_3,0,50}, // S_ACROSSATK_2
+{SPR_ACSB,1,2,NULL,S_ACROSSATK_4,0,50}, // S_ACROSSATK_3
+{SPR_ACSB,1,2,NULL,S_ACROSSATK_5,0,45}, // S_ACROSSATK_4
+{SPR_ACSB,0,2,NULL,S_ACROSSATK_6,0,40}, // S_ACROSSATK_5
+{SPR_ACSB,0,2,NULL,S_ACROSSREADY,0,36}, // S_ACROSSATK_6
+/* jim {SPR_ACSB,10,10,NULL,S_ACROSSREADY2,0,36}, // S_ACROSSATK2_1 */
+{SPR_ACSB,32771,1,NULL,S_ACROSS_MISSILE2,0,0}, // S_ACROSS_MISSILE1
+{SPR_ACSB,32771,1,NULL,S_ACROSS_MISSILE3,0,0}, // S_ACROSS_MISSILE2
+{SPR_ACSB,32772,1,NULL,S_ACROSS_MISSILE4,0,0}, // S_ACROSS_MISSILE3
+{SPR_ACSB,32772,1,NULL,S_ACROSS_MISSILE1,0,0}, // S_ACROSS_MISSILE4
+{SPR_ACSB,32773,4,NULL,S_ACROSS_MISSILE_X2,0,0}, // S_ACROSS_MISSILE_X1
+{SPR_ACSB,32774,4,NULL,S_ACROSS_MISSILE_X3,0,0}, // S_ACROSS_MISSILE_X2
+{SPR_ACSB,32775,3,NULL,S_ACROSS_MISSILE_X4,0,0}, // S_ACROSS_MISSILE_X3
+{SPR_ACSB,32776,3,NULL,S_NULL,0,0}, // S_ACROSS_MISSILE_X4
+{SPR_AGRN,0,1,A_WeaponReady,S_AGRENREADY,0,0}, // S_AGRENREADY
+{SPR_AGRN,0,1,A_Lower,S_AGRENDOWN,0,0}, // S_AGRENDOWN
+{SPR_AGRN,0,1,A_Raise,S_AGRENUP,0,0}, // S_AGRENUP
+{SPR_AGRN,0,6,NULL,S_AGRENATK_2,0,0}, // S_AGRENATK_1
+{SPR_AGRN,32769,6,A_AGrenAttack,S_AGRENATK_3,0,48}, // S_AGRENATK_2
+{SPR_AGRN,0,3,NULL,S_AGRENATK_4,0,40}, // S_AGRENATK_3
+{SPR_AGRN,0,3,A_ReFire,S_AGRENREADY,0,36}, // S_AGRENATK_4
+{SPR_AGRN,32772,4,NULL,S_AGRENPUFF2,0,0}, // S_AGRENPUFF1
+{SPR_AGRN,32773,3,NULL,S_AGRENPUFF3,0,0}, // S_AGRENPUFF2
+{SPR_AGRN,32774,4,NULL,S_AGRENPUFF4,0,0}, // S_AGRENPUFF3
+{SPR_AGRN,32775,3,NULL,S_AGRENPUFF5,0,0}, // S_AGRENPUFF4
+{SPR_AGRN,32776,4,NULL,S_NULL,0,0}, // S_AGRENPUFF5
+{SPR_AGRN,2,4,NULL,S_AGRENSMOKE2,0,0}, // S_AGRENSMOKE1
+{SPR_AGRN,3,4,NULL,S_AGRENSMOKE3,0,0}, // S_AGRENSMOKE2
+{SPR_AGRN,2,4,NULL,S_AGRENSMOKE4,0,0}, // S_AGRENSMOKE3
+{SPR_AGRN,3,4,NULL,S_NULL,0,0}, // S_AGRENSMOKE4
+{SPR_AGRN,32770,4,NULL,S_AGREN_MISSILE2,0,0}, // S_AGREN_MISSILE1
+{SPR_AGRN,32771,4,NULL,S_AGREN_MISSILE1,0,0}, // S_AGREN_MISSILE2
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY2,0,0}, // S_ASTAFFREADY
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY3,0,0}, // S_ASTAFFREADY2
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY4,0,0}, // S_ASTAFFREADY3
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY5,0,0}, // S_ASTAFFREADY4
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY6,0,0}, // S_ASTAFFREADY5
+{SPR_ASTF,0,1,A_WeaponReady,S_ASTAFFREADY7,0,0}, // S_ASTAFFREADY6
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY8,0,0}, // S_ASTAFFREADY7
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY9,0,0}, // S_ASTAFFREADY8
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY10,0,0}, // S_ASTAFFREADY9
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY11,0,0}, // S_ASTAFFREADY10
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY12,0,0}, // S_ASTAFFREADY11
+{SPR_ASTF,1,1,A_WeaponReady,S_ASTAFFREADY13,0,0}, // S_ASTAFFREADY12
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY14,0,0}, // S_ASTAFFREADY13
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY15,0,0}, // S_ASTAFFREADY14
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY16,0,0}, // S_ASTAFFREADY15
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY17,0,0}, // S_ASTAFFREADY16
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY18,0,0}, // S_ASTAFFREADY17
+{SPR_ASTF,2,1,A_WeaponReady,S_ASTAFFREADY19,0,0}, // S_ASTAFFREADY18
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY20,0,0}, // S_ASTAFFREADY19
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY21,0,0}, // S_ASTAFFREADY20
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY22,0,0}, // S_ASTAFFREADY21
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY23,0,0}, // S_ASTAFFREADY22
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY24,0,0}, // S_ASTAFFREADY23
+{SPR_ASTF,3,1,A_WeaponReady,S_ASTAFFREADY25,0,0}, // S_ASTAFFREADY24
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY26,0,0}, // S_ASTAFFREADY25
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY27,0,0}, // S_ASTAFFREADY26
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY28,0,0}, // S_ASTAFFREADY27
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY29,0,0}, // S_ASTAFFREADY28
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY30,0,0}, // S_ASTAFFREADY29
+{SPR_ASTF,4,1,A_WeaponReady,S_ASTAFFREADY31,0,0}, // S_ASTAFFREADY30
+{SPR_ASTF,5,1,A_WeaponReady,S_ASTAFFREADY32,0,0}, // S_ASTAFFREADY31
+{SPR_ASTF,5,1,A_WeaponReady,S_ASTAFFREADY33,0,0}, // S_ASTAFFREADY32
+{SPR_ASTF,5,1,A_WeaponReady,S_ASTAFFREADY34,0,0}, // S_ASTAFFREADY33
+{SPR_ASTF,5,1,A_WeaponReady,S_ASTAFFREADY35,0,0}, // S_ASTAFFREADY34
+{SPR_ASTF,5,1,A_WeaponReady,S_ASTAFFREADY,0,0}, // S_ASTAFFREADY35
+{SPR_ASTF,0,1,A_Lower,S_ASTAFFDOWN,0,0}, // S_ASTAFFDOWN
+{SPR_ASTF,0,1,A_Raise,S_ASTAFFUP,0,0}, // S_ASTAFFUP
+{SPR_ASTF,6,4,NULL,S_ASTAFFATK_2,0,40}, // S_ASTAFFATK_1
+{SPR_ASTF,32775,4,A_AStaffAttack,S_ASTAFFATK_3,0,48}, // S_ASTAFFATK_2
+{SPR_ASTF,32775,2,NULL,S_ASTAFFATK_4,0,48}, // S_ASTAFFATK_3
+{SPR_ASTF,8,2,NULL,S_ASTAFFATK_5,0,48}, // S_ASTAFFATK_4
+{SPR_ASTF,8,2,NULL,S_ASTAFFATK_6,0,48}, // S_ASTAFFATK_5
+{SPR_ASTF,8,1,NULL,S_ASTAFFATK_7,0,40}, // S_ASTAFFATK_6
+{SPR_ASTF,9,5,NULL,S_ASTAFFREADY,0,36}, // S_ASTAFFATK_7
+{SPR_ASP1,32768,3,A_MStaffWeave,S_ASTAFF_FX1_2,0,0}, // S_ASTAFF_FX1_1
+{SPR_ASP1,32769,3,A_MStaffWeave,S_ASTAFF_FX1_3,0,0}, // S_ASTAFF_FX1_2
+{SPR_ASP1,32770,3,A_MStaffWeave,S_ASTAFF_FX1_4,0,0}, // S_ASTAFF_FX1_3
+{SPR_ASP1,32771,3,A_MStaffWeave,S_ASTAFF_FX1_5,0,0}, // S_ASTAFF_FX1_4
+{SPR_ASP1,32772,3,A_MStaffWeave,S_ASTAFF_FX1_6,0,0}, // S_ASTAFF_FX1_5
+{SPR_ASP1,32773,3,A_MStaffWeave,S_ASTAFF_FX1_1,0,0}, // S_ASTAFF_FX1_6
+{SPR_ASP1,32774,4,NULL,S_ASTAFF_FX_X2,0,0}, // S_ASTAFF_FX_X1
+{SPR_ASP1,32775,5,A_Explode,S_ASTAFF_FX_X3,0,0}, // S_ASTAFF_FX_X2
+{SPR_ASP1,32776,4,NULL,S_ASTAFF_FX_X4,0,0}, // S_ASTAFF_FX_X3
+{SPR_ASP1,32777,5,NULL,S_ASTAFF_FX_X5,0,0}, // S_ASTAFF_FX_X4
+{SPR_ASP1,32778,4,NULL,S_ASTAFF_FX_X6,0,0}, // S_ASTAFF_FX_X5
+{SPR_ASP1,32779,5,NULL,S_ASTAFF_FX_X7,0,0}, // S_ASTAFF_FX_X6
+{SPR_ASP1,32780,4,NULL,S_ASTAFF_FX_X8,0,0}, // S_ASTAFF_FX_X7
+{SPR_ASP1,32781,5,NULL,S_ASTAFF_FX_X9,0,0}, // S_ASTAFF_FX_X8
+{SPR_ASP1,32782,4,NULL,S_ASTAFF_FX_X10,0,0}, // S_ASTAFF_FX_X9
+{SPR_ASP1,32783,4,NULL,S_NULL,0,0}, // S_ASTAFF_FX_X10
+{SPR_ASP2,32768,2,A_MStaffTrack,S_ASTAFF_FX2_2,0,0}, // S_ASTAFF_FX2_1
+{SPR_ASP2,32769,2,A_MStaffTrack,S_ASTAFF_FX2_3,0,0}, // S_ASTAFF_FX2_2
+{SPR_ASP2,32770,2,A_MStaffTrack,S_ASTAFF_FX2_4,0,0}, // S_ASTAFF_FX2_3
+{SPR_ASP2,32771,2,A_MStaffTrack,S_ASTAFF_FX2_1,0,0}, // S_ASTAFF_FX2_4
+{SPR_ASP2,32772,4,NULL,S_ASTAFF_FX2_X2,0,0}, // S_ASTAFF_FX2_X1
+{SPR_ASP2,32773,5,A_Explode,S_ASTAFF_FX2_X3,0,0}, // S_ASTAFF_FX2_X2
+{SPR_ASP2,32774,5,NULL,S_ASTAFF_FX2_X4,0,0}, // S_ASTAFF_FX2_X3
+{SPR_ASP2,32775,5,NULL,S_ASTAFF_FX2_X5,0,0}, // S_ASTAFF_FX2_X4
+{SPR_ASP2,32776,4,NULL,S_NULL,0,0}, // S_ASTAFF_FX2_X5
+{SPR_ASSN,0,-1,NULL,S_NULL,0,0}, // S_APLAY
+{SPR_ASSN,0,4,NULL,S_APLAY_RUN2,0,0}, // S_APLAY_RUN1
+{SPR_ASSN,1,4,NULL,S_APLAY_RUN3,0,0}, // S_APLAY_RUN2
+{SPR_ASSN,2,4,NULL,S_APLAY_RUN4,0,0}, // S_APLAY_RUN3
+{SPR_ASSN,3,4,NULL,S_APLAY_RUN1,0,0}, // S_APLAY_RUN4
+{SPR_ASSN,4,6,NULL,S_APLAY_ATK2,0,0}, // S_APLAY_ATK1
+{SPR_ASSN,5,6,NULL,S_APLAY_ATK3,0,0}, // S_APLAY_ATK2
+{SPR_ASSN,6,6,NULL,S_APLAY,0,0}, // S_APLAY_ATK3
+{SPR_ASSN,7,4,NULL,S_APLAY_PAIN2,0,0}, // S_APLAY_PAIN
+{SPR_ASSN,7,4,A_Pain,S_APLAY,0,0}, // S_APLAY_PAIN2
+{SPR_ASSN,8,6,NULL,S_APLAY_DIE2,0,0}, // S_APLAY_DIE1
+{SPR_ASSN,10,6,A_Scream,S_APLAY_DIE3,0,0}, // S_APLAY_DIE2
+{SPR_ASSN,11,6,NULL,S_APLAY_DIE4,0,0}, // S_APLAY_DIE3
+{SPR_ASSN,11,6,NULL,S_APLAY_DIE5,0,0}, // S_APLAY_DIE4
+{SPR_ASSN,12,6,A_NoBlocking,S_APLAY_DIE6,0,0}, // S_APLAY_DIE5
+{SPR_ASSN,13,6,NULL,S_APLAY_DIE7,0,0}, // S_APLAY_DIE6
+{SPR_ASSN,14,6,NULL,S_APLAY_DIE8,0,0}, // S_APLAY_DIE7
+{SPR_ASSN,15,6,NULL,S_APLAY_DIE9,0,0}, // S_APLAY_DIE8
+{SPR_ASSN,16,-1,A_AddPlayerCorpse,S_NULL,0,0}, // S_APLAY_DIE9
+{SPR_ASSN,17,5,A_Scream,S_APLAY_XDIE2,0,0}, // S_APLAY_XDIE1
+{SPR_ASSN,18,5,NULL,S_APLAY_XDIE3,0,0}, // S_APLAY_XDIE2
+{SPR_ASSN,19,5,A_NoBlocking,S_APLAY_XDIE4,0,0}, // S_APLAY_XDIE3
+{SPR_ASSN,20,5,NULL,S_APLAY_XDIE5,0,0}, // S_APLAY_XDIE4
+{SPR_ASSN,21,5,NULL,S_APLAY_XDIE6,0,0}, // S_APLAY_XDIE5
+{SPR_ASSN,22,5,NULL,S_APLAY_XDIE7,0,0}, // S_APLAY_XDIE6
+{SPR_ASSN,23,5,NULL,S_APLAY_XDIE8,0,0}, // S_APLAY_XDIE7
+{SPR_ASSN,24,5,NULL,S_APLAY_XDIE9,0,0}, // S_APLAY_XDIE8
+{SPR_ASSN,25,5,NULL,S_APLAY_XDIE10,0,0}, // S_APLAY_XDIE9
+{SPR_ASSN,26,-1,A_AddPlayerCorpse,S_NULL,0,0}, // S_APLAY_XDIE10
+{SPR_ASSN,27,5,A_FreezeDeath,S_APLAY_ICE2,0,0}, // S_APLAY_ICE
+{SPR_ASSN,27,1,A_FreezeDeathChunks,S_APLAY_ICE2,0,0} // S_APLAY_ICE2
+#endif /* ASSASSIN */
+};
+
+
+mobjinfo_t mobjinfo[NUMMOBJTYPES] = {
+
+{ // MT_MAPSPOT
+9001, // doomednum
+S_MAPSPOT, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MAPSPOTGRAVITY
+9013, // doomednum
+S_MAPSPOT, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+MF2_DONTDRAW // flags2
+ },
+
+{ // MT_FIREBALL1
+-1, // doomednum
+S_FIREBALL1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_FIREBALL1_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_FIREBALL, // deathsound
+2*FRACUNIT, // speed
+8*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+4, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_ARROW
+-1, // doomednum
+S_ARROW_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ARROW_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+6*FRACUNIT, // speed
+8*FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+4, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_DART
+-1, // doomednum
+S_DART_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DART_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+6*FRACUNIT, // speed
+8*FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+2, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_POISONDART
+-1, // doomednum
+S_POISONDART_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_POISONDART_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+6*FRACUNIT, // speed
+8*FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+2, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_RIPPERBALL
+-1, // doomednum
+S_RIPPERBALL_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_RIPPERBALL_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+6*FRACUNIT, // speed
+8*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+2, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_RIP // flags2
+ },
+
+{ // MT_PROJECTILE_BLADE
+-1, // doomednum
+S_PRJ_BLADE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_PRJ_BLADE_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+6*FRACUNIT, // speed
+6*FRACUNIT, // radius
+6*FRACUNIT, // height
+100, // mass
+3, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_ICESHARD
+-1, // doomednum
+S_ICESHARD1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SHARDFXE1_1, // deathstate
+S_NULL, // xdeathstate
+SFX_MAGE_SHARDS_EXPLODE, // deathsound
+25*FRACUNIT, // speed
+13*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+1, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_ICEDAMAGE // flags2
+ },
+
+{ // MT_FLAME_SMALL_TEMP
+10500, // doomednum
+S_FLAME_TSMALL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_FLAME_LARGE_TEMP
+10502, // doomednum
+S_FLAME_TLARGE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_FLAME_SMALL
+10501, // doomednum
+S_FLAME_SMALL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+MF2_NOTELEPORT|MF2_DONTDRAW // flags2
+ },
+
+{ // MT_FLAME_LARGE
+10503, // doomednum
+S_FLAME_LARGE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+MF2_NOTELEPORT|MF2_DONTDRAW // flags2
+ },
+
+{ // MT_HEALINGBOTTLE
+81, // doomednum
+S_ITEM_PTN1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_HEALTHFLASK
+82, // doomednum
+S_ARTI_PTN2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_ARTIFLY
+83, // doomednum
+S_ARTI_SOAR1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_ARTIINVULNERABILITY
+84, // doomednum
+S_ARTI_INVU1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_SUMMONMAULATOR
+86, // doomednum
+S_ARTI_SUMMON, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_SUMMON_FX
+-1, // doomednum
+S_SUMMON_FX1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SUMMON_FX2_1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+20*FRACUNIT, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_MISSILE|MF_DROPOFF|MF_NOBLOCKMAP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_THRUSTFLOOR_UP
+10091, // doomednum
+S_THRUSTINIT2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+128*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_THRUSTFLOOR_DOWN
+10090, // doomednum
+S_THRUSTINIT1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+128*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP|MF2_DONTDRAW // flags2
+ },
+
+{ // MT_TELEPORTOTHER
+10040, // doomednum
+S_ARTI_TELOTHER1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_TELOTHER_FX1
+-1, // doomednum
+S_TELO_FX1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_TELO_FX9, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+20*FRACUNIT, // speed
+16*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+10001, // damage
+SFX_NONE, // activesound
+MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOBLOCKMAP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_TELOTHER_FX2
+-1, // doomednum
+S_TELO_FX2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_TELO_FX9, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+16*FRACUNIT, // speed
+16*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+10001, // damage
+SFX_NONE, // activesound
+MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOBLOCKMAP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_TELOTHER_FX3
+-1, // doomednum
+S_TELO_FX3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_TELO_FX9, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+16*FRACUNIT, // speed
+16*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+10001, // damage
+SFX_NONE, // activesound
+MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOBLOCKMAP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_TELOTHER_FX4
+-1, // doomednum
+S_TELO_FX4_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_TELO_FX9, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+16*FRACUNIT, // speed
+16*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+10001, // damage
+SFX_NONE, // activesound
+MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOBLOCKMAP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_TELOTHER_FX5
+-1, // doomednum
+S_TELO_FX5_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_TELO_FX9, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+16*FRACUNIT, // speed
+16*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+10001, // damage
+SFX_NONE, // activesound
+MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOBLOCKMAP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_DIRT1
+-1, // doomednum
+S_DIRT1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DIRT1_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_DIRT2
+-1, // doomednum
+S_DIRT2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DIRT2_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_DIRT3
+-1, // doomednum
+S_DIRT3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DIRT3_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_DIRT4
+-1, // doomednum
+S_DIRT4_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DIRT4_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_LOGRAV // flags2
+ },
+
+{ // MT_DIRT5
+-1, // doomednum
+S_DIRT5_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DIRT5_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_LOGRAV // flags2
+ },
+
+{ // MT_DIRT6
+-1, // doomednum
+S_DIRT6_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DIRT6_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_LOGRAV // flags2
+ },
+
+{ // MT_DIRTCLUMP
+-1, // doomednum
+S_DIRTCLUMP1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_ROCK1
+-1, // doomednum
+S_ROCK1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ROCK1_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_ROCK2
+-1, // doomednum
+S_ROCK2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ROCK2_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_ROCK3
+-1, // doomednum
+S_ROCK3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ROCK3_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_FOGSPAWNER
+10000, // doomednum
+S_SPAWNFOG1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOSECTOR, // flags
+MF2_DONTDRAW|MF2_FLOATBOB // flags2
+ },
+
+{ // MT_FOGPATCHS
+10001, // doomednum
+S_FOGPATCHS1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_FOGPATCHS0, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+FRACUNIT, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_FLOAT|MF_NOGRAVITY|MF_SHADOW|MF_NOCLIP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_FOGPATCHM
+10002, // doomednum
+S_FOGPATCHM1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_FOGPATCHM0, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+FRACUNIT, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_FLOAT|MF_NOGRAVITY|MF_SHADOW|MF_NOCLIP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_FOGPATCHL
+10003, // doomednum
+S_FOGPATCHL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_FOGPATCHL0, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+FRACUNIT, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_FLOAT|MF_NOGRAVITY|MF_SHADOW|MF_NOCLIP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_QUAKE_FOCUS
+-1, // doomednum
+S_QUAKE_ACTIVE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOSECTOR, // flags
+MF2_DONTDRAW // flags2
+ },
+
+{ // MT_SGSHARD1
+-1, // doomednum
+S_SGSHARD1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SGSHARD1_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+16*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SGSHARD2
+-1, // doomednum
+S_SGSHARD2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SGSHARD2_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+16*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SGSHARD3
+-1, // doomednum
+S_SGSHARD3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SGSHARD3_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+16*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SGSHARD4
+-1, // doomednum
+S_SGSHARD4_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SGSHARD4_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+16*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SGSHARD5
+-1, // doomednum
+S_SGSHARD5_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SGSHARD5_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+16*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SGSHARD6
+-1, // doomednum
+S_SGSHARD6_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SGSHARD6_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+16*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SGSHARD7
+-1, // doomednum
+S_SGSHARD7_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SGSHARD7_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+16*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SGSHARD8
+-1, // doomednum
+S_SGSHARD8_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SGSHARD8_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+16*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SGSHARD9
+-1, // doomednum
+S_SGSHARD9_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SGSHARD9_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+16*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SGSHARD0
+-1, // doomednum
+S_SGSHARD0_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SGSHARD0_D, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+16*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_ARTIEGG
+30, // doomednum
+S_ARTI_EGGC1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_EGGFX
+-1, // doomednum
+S_EGGFX1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+0, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_EGGFXI1_1, // deathstate
+S_NULL, // xdeathstate
+0, // deathsound
+18*FRACUNIT, // speed
+8*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+1, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_ARTISUPERHEAL
+32, // doomednum
+S_ARTI_SPHL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_ZWINGEDSTATUENOSKULL
+9011, // doomednum
+S_ZWINGEDSTATUENOSKULL, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+62*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_ZGEMPEDESTAL
+9012, // doomednum
+S_ZGEMPEDESTAL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+40*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZSKULL
+9002, // doomednum
+S_ARTIPUZZSKULL, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZGEMBIG
+9003, // doomednum
+S_ARTIPUZZGEMBIG, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZGEMRED
+9004, // doomednum
+S_ARTIPUZZGEMRED, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZGEMGREEN1
+9005, // doomednum
+S_ARTIPUZZGEMGREEN1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZGEMGREEN2
+9009, // doomednum
+S_ARTIPUZZGEMGREEN2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZGEMBLUE1
+9006, // doomednum
+S_ARTIPUZZGEMBLUE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZGEMBLUE2
+9010, // doomednum
+S_ARTIPUZZGEMBLUE2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZBOOK1
+9007, // doomednum
+S_ARTIPUZZBOOK1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZBOOK2
+9008, // doomednum
+S_ARTIPUZZBOOK2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZSKULL2
+9014, // doomednum
+S_ARTIPUZZSKULL2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZFWEAPON
+9015, // doomednum
+S_ARTIPUZZFWEAPON, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZCWEAPON
+9016, // doomednum
+S_ARTIPUZZCWEAPON, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZMWEAPON
+9017, // doomednum
+S_ARTIPUZZMWEAPON, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZGEAR
+9018, // doomednum
+S_ARTIPUZZGEAR_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZGEAR2
+9019, // doomednum
+S_ARTIPUZZGEAR2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZGEAR3
+9020, // doomednum
+S_ARTIPUZZGEAR3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTIPUZZGEAR4
+9021, // doomednum
+S_ARTIPUZZGEAR4_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARTITORCH
+33, // doomednum
+S_ARTI_TRCH1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_FIREBOMB
+-1, // doomednum
+S_FIREBOMB1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_FLECHETTE_EXPLODE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOGRAVITY|MF_ALTSHADOW, // flags
+MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_ARTITELEPORT
+36, // doomednum
+S_ARTI_ATLP1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_ARTIPOISONBAG
+8000, // doomednum
+S_ARTI_PSBG1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_POISONBAG
+-1, // doomednum
+S_POISONBAG1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOGRAVITY|MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_POISONCLOUD
+-1, // doomednum
+S_POISONCLOUD1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_POISONSHROOM_DEATH, // deathsound
+0, // speed
+1, // radius
+1, // height
+H2MAXINT, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOGRAVITY|MF_NOBLOCKMAP|MF_SHADOW|MF_NOCLIP|MF_DROPOFF, // flags
+MF2_NODMGTHRUST // flags2
+ },
+
+{ // MT_THROWINGBOMB
+-1, // doomednum
+S_THROWINGBOMB1, // spawnstate
+48, // spawnhealth
+S_NULL, // seestate
+SFX_FLECHETTE_BOUNCE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_THROWINGBOMB_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_FLECHETTE_EXPLODE, // deathsound
+12*FRACUNIT, // speed
+8*FRACUNIT, // radius
+10*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_FLOORBOUNCE|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_SPEEDBOOTS
+8002, // doomednum
+S_ARTI_BOOTS1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_BOOSTMANA
+8003, // doomednum
+S_ARTI_MANA, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_BOOSTARMOR
+8041, // doomednum
+S_ARTI_ARMOR1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_BLASTRADIUS
+10110, // doomednum
+S_ARTI_BLAST1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_HEALRADIUS
+10120, // doomednum
+S_ARTI_HEALRAD1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_SPLASH
+-1, // doomednum
+S_SPLASH1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SPLASHX, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+2*FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_LOGRAV|MF2_CANNOTPUSH // flags2
+ },
+
+{ // MT_SPLASHBASE
+-1, // doomednum
+S_SPLASHBASE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_LAVASPLASH
+-1, // doomednum
+S_LAVASPLASH1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_LAVASMOKE
+-1, // doomednum
+S_LAVASMOKE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+0 // flags2
+ },
+
+{ // MT_SLUDGECHUNK
+-1, // doomednum
+S_SLUDGECHUNK1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SLUDGECHUNKX, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+2*FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_LOGRAV|MF2_CANNOTPUSH // flags2
+ },
+
+{ // MT_SLUDGESPLASH
+-1, // doomednum
+S_SLUDGESPLASH1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_MISC0
+5, // doomednum
+S_ZWINGEDSTATUE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+62*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC1
+6, // doomednum
+S_ZROCK1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC2
+7, // doomednum
+S_ZROCK2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC3
+9, // doomednum
+S_ZROCK3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC4
+15, // doomednum
+S_ZROCK4_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC5
+17, // doomednum
+S_ZCHANDELIER1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+60*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC6
+8063, // doomednum
+S_ZCHANDELIER_U, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+60*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC7
+24, // doomednum
+S_ZTREEDEAD1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+96*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC8
+25, // doomednum
+S_ZTREE, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+15*FRACUNIT, // radius
+128*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_TREEDESTRUCTIBLE
+8062, // doomednum
+S_ZTREEDESTRUCTIBLE1, // spawnstate
+70, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZTREEDES_D1, // deathstate
+S_NULL, // xdeathstate
+SFX_TREE_BREAK, // deathsound
+0, // speed
+15*FRACUNIT, // radius
+180*FRACUNIT, // height
+H2MAXINT, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD, // flags
+0 // flags2
+ },
+
+{ // MT_MISC9
+26, // doomednum
+S_ZTREESWAMP182_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+150*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC10
+27, // doomednum
+S_ZTREESWAMP172_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+120*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC11
+28, // doomednum
+S_ZSTUMPBURNED1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+12*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC12
+29, // doomednum
+S_ZSTUMPBARE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+12*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC13
+37, // doomednum
+S_ZSTUMPSWAMP1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC14
+38, // doomednum
+S_ZSTUMPSWAMP2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC15
+39, // doomednum
+S_ZSHROOMLARGE1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC16
+40, // doomednum
+S_ZSHROOMLARGE2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC17
+41, // doomednum
+S_ZSHROOMLARGE3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC18
+42, // doomednum
+S_ZSHROOMSMALL1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC19
+44, // doomednum
+S_ZSHROOMSMALL2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC20
+45, // doomednum
+S_ZSHROOMSMALL3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC21
+46, // doomednum
+S_ZSHROOMSMALL4_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC22
+47, // doomednum
+S_ZSHROOMSMALL5_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC23
+48, // doomednum
+S_ZSTALAGMITEPILLAR1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+138*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC24
+49, // doomednum
+S_ZSTALAGMITELARGE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+48*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC25
+50, // doomednum
+S_ZSTALAGMITEMEDIUM1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+6*FRACUNIT, // radius
+40*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC26
+51, // doomednum
+S_ZSTALAGMITESMALL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+36*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC27
+52, // doomednum
+S_ZSTALACTITELARGE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+66*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC28
+56, // doomednum
+S_ZSTALACTITEMEDIUM1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+6*FRACUNIT, // radius
+50*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC29
+57, // doomednum
+S_ZSTALACTITESMALL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+40*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC30
+58, // doomednum
+S_ZMOSSCEILING1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC31
+59, // doomednum
+S_ZMOSSCEILING2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+24*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC32
+60, // doomednum
+S_ZSWAMPVINE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+52*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC33
+61, // doomednum
+S_ZCORPSEKABOB1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+92*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC34
+62, // doomednum
+S_ZCORPSESLEEPING1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC35
+63, // doomednum
+S_ZTOMBSTONERIP1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+46*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC36
+64, // doomednum
+S_ZTOMBSTONESHANE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+46*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC37
+65, // doomednum
+S_ZTOMBSTONEBIGCROSS1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+46*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC38
+66, // doomednum
+S_ZTOMBSTONEBRIANR1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+52*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC39
+67, // doomednum
+S_ZTOMBSTONECROSSCIRCLE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+52*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC40
+68, // doomednum
+S_ZTOMBSTONESMALLCROSS1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+46*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC41
+69, // doomednum
+S_ZTOMBSTONEBRIANP1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+46*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC42
+71, // doomednum
+S_CORPSEHANGING_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+6*FRACUNIT, // radius
+75*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC43
+72, // doomednum
+S_ZSTATUEGARGOYLEGREENTALL_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+108*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC44
+73, // doomednum
+S_ZSTATUEGARGOYLEBLUETALL_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+108*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC45
+74, // doomednum
+S_ZSTATUEGARGOYLEGREENSHORT_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+62*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC46
+76, // doomednum
+S_ZSTATUEGARGOYLEBLUESHORT_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+62*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC47
+8044, // doomednum
+S_ZSTATUEGARGOYLESTRIPETALL_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+108*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC48
+8045, // doomednum
+S_ZSTATUEGARGOYLEDARKREDTALL_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+108*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC49
+8046, // doomednum
+S_ZSTATUEGARGOYLEREDTALL_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+108*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC50
+8047, // doomednum
+S_ZSTATUEGARGOYLETANTALL_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+108*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC51
+8048, // doomednum
+S_ZSTATUEGARGOYLERUSTTALL_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+108*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC52
+8049, // doomednum
+S_ZSTATUEGARGOYLEDARKREDSHORT_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+62*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC53
+8050, // doomednum
+S_ZSTATUEGARGOYLEREDSHORT_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+62*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC54
+8051, // doomednum
+S_ZSTATUEGARGOYLETANSHORT_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+62*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC55
+8052, // doomednum
+S_ZSTATUEGARGOYLERUSTSHORT_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+14*FRACUNIT, // radius
+62*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC56
+77, // doomednum
+S_ZBANNERTATTERED_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+120*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC57
+78, // doomednum
+S_ZTREELARGE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZTREELARGE1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+15*FRACUNIT, // radius
+180*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC58
+79, // doomednum
+S_ZTREELARGE2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZTREELARGE2, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+15*FRACUNIT, // radius
+180*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC59
+80, // doomednum
+S_ZTREEGNARLED1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+22*FRACUNIT, // radius
+100*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC60
+87, // doomednum
+S_ZTREEGNARLED2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+22*FRACUNIT, // radius
+100*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC61
+88, // doomednum
+S_ZLOG, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+25*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC62
+89, // doomednum
+S_ZSTALACTITEICELARGE, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+66*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC63
+90, // doomednum
+S_ZSTALACTITEICEMEDIUM, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+50*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC64
+91, // doomednum
+S_ZSTALACTITEICESMALL, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+32*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC65
+92, // doomednum
+S_ZSTALACTITEICETINY, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC66
+93, // doomednum
+S_ZSTALAGMITEICELARGE, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+66*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC67
+94, // doomednum
+S_ZSTALAGMITEICEMEDIUM, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+50*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC68
+95, // doomednum
+S_ZSTALAGMITEICESMALL, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+32*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC69
+96, // doomednum
+S_ZSTALAGMITEICETINY, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC70
+97, // doomednum
+S_ZROCKBROWN1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+17*FRACUNIT, // radius
+72*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC71
+98, // doomednum
+S_ZROCKBROWN2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+15*FRACUNIT, // radius
+50*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC72
+99, // doomednum
+S_ZROCKBLACK, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+40*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_MISC73
+100, // doomednum
+S_ZRUBBLE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC74
+101, // doomednum
+S_ZRUBBLE2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC75
+102, // doomednum
+S_ZRUBBLE3, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_MISC76
+103, // doomednum
+S_ZVASEPILLAR, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+12*FRACUNIT, // radius
+54*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_POTTERY1
+104, // doomednum
+S_ZPOTTERY1, // spawnstate
+15, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZPOTTERY_EXPLODE, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+32*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_DROPOFF, // flags
+MF2_SLIDE|MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ // flags2
+ },
+
+{ // MT_POTTERY2
+105, // doomednum
+S_ZPOTTERY2, // spawnstate
+15, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZPOTTERY_EXPLODE, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+25*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_DROPOFF, // flags
+MF2_SLIDE|MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ // flags2
+ },
+
+{ // MT_POTTERY3
+106, // doomednum
+S_ZPOTTERY3, // spawnstate
+15, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZPOTTERY_EXPLODE, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+15*FRACUNIT, // radius
+25*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_DROPOFF, // flags
+MF2_SLIDE|MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ // flags2
+ },
+
+{ // MT_POTTERYBIT1
+-1, // doomednum
+S_POTTERYBIT_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_POTTERYBIT_EX0, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_MISC77
+108, // doomednum
+S_ZCORPSELYNCHED1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+11*FRACUNIT, // radius
+95*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ZLYNCHED_NOHEART
+109, // doomednum
+S_ZCORPSELYNCHED2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+100*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC78
+110, // doomednum
+S_ZCORPSESITTING, // spawnstate
+30, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZCORPSESITTING_X, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+15*FRACUNIT, // radius
+35*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD, // flags
+0 // flags2
+ },
+
+{ // MT_CORPSEBIT
+-1, // doomednum
+S_CORPSEBIT_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+MF2_TELESTOMP // flags2
+ },
+
+{ // MT_CORPSEBLOODDRIP
+-1, // doomednum
+S_CORPSEBLOODDRIP, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_CORPSEBLOODDRIP_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_DRIP, // deathsound
+0, // speed
+FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_MISSILE, // flags
+MF2_LOGRAV // flags2
+ },
+
+{ // MT_BLOODPOOL
+111, // doomednum
+S_BLOODPOOL, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_MISC79
+119, // doomednum
+S_ZCANDLE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC80
+113, // doomednum
+S_ZLEAFSPAWNER, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOSECTOR, // flags
+MF2_DONTDRAW // flags2
+ },
+
+{ // MT_LEAF1
+-1, // doomednum
+S_LEAF1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_LEAF_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+2*FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_LOGRAV // flags2
+ },
+
+{ // MT_LEAF2
+-1, // doomednum
+S_LEAF2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_LEAF_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+2*FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_LOGRAV // flags2
+ },
+
+{ // MT_ZTWINEDTORCH
+116, // doomednum
+S_ZTWINEDTORCH_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+64*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_ZTWINEDTORCH_UNLIT
+117, // doomednum
+S_ZTWINEDTORCH_UNLIT, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+10*FRACUNIT, // radius
+64*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_BRIDGE
+118, // doomednum
+S_BRIDGE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+32*FRACUNIT, // radius
+2*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_NOGRAVITY, // flags
+MF2_DONTDRAW // flags2
+ },
+
+{ // MT_BRIDGEBALL
+-1, // doomednum
+S_BBALL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_ZWALLTORCH
+54, // doomednum
+S_ZWALLTORCH1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ZWALLTORCH_UNLIT
+55, // doomednum
+S_ZWALLTORCH_U, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ZBARREL
+8100, // doomednum
+S_ZBARREL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+15*FRACUNIT, // radius
+32*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_ZSHRUB1
+8101, // doomednum
+S_ZSHRUB1, // spawnstate
+20, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_ZSHRUB1_X1, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZSHRUB1_DIE, // deathstate
+S_NULL, // xdeathstate
+SFX_TREE_EXPLODE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+24*FRACUNIT, // height
+H2MAXINT, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD, // flags
+0 // flags2
+ },
+
+{ // MT_ZSHRUB2
+8102, // doomednum
+S_ZSHRUB2, // spawnstate
+10, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_ZSHRUB2_X1, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZSHRUB2_DIE, // deathstate
+S_NULL, // xdeathstate
+SFX_TREE_EXPLODE, // deathsound
+0, // speed
+16*FRACUNIT, // radius
+40*FRACUNIT, // height
+H2MAXINT, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD, // flags
+0 // flags2
+ },
+
+{ // MT_ZBUCKET
+8103, // doomednum
+S_ZBUCKET1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+72*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ZPOISONSHROOM
+8104, // doomednum
+S_ZPOISONSHROOM1, // spawnstate
+30, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_ZPOISONSHROOM_P1, // painstate
+255, // painchance
+SFX_POISONSHROOM_PAIN, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZPOISONSHROOM_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_POISONSHROOM_DEATH, // deathsound
+0, // speed
+6*FRACUNIT, // radius
+20*FRACUNIT, // height
+H2MAXINT, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SHOOTABLE|MF_SOLID|MF_NOBLOOD, // flags
+0 // flags2
+ },
+
+{ // MT_ZFIREBULL
+8042, // doomednum
+S_ZFIREBULL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+80*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_ZFIREBULL_UNLIT
+8043, // doomednum
+S_ZFIREBULL_U, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+80*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_FIRETHING
+8060, // doomednum
+S_ZFIRETHING1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+10*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_BRASSTORCH
+8061, // doomednum
+S_ZBRASSTORCH1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+6*FRACUNIT, // radius
+35*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_ZSUITOFARMOR
+8064, // doomednum
+S_ZSUITOFARMOR, // spawnstate
+60, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZSUITOFARMOR_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_SUITOFARMOR_BREAK, // deathsound
+0, // speed
+16*FRACUNIT, // radius
+72*FRACUNIT, // height
+H2MAXINT, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD, // flags
+0 // flags2
+ },
+
+{ // MT_ZARMORCHUNK
+-1, // doomednum
+S_ZARMORCHUNK1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+0, // flags
+0 // flags2
+ },
+
+{ // MT_ZBELL
+8065, // doomednum
+S_ZBELL, // spawnstate
+5, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZBELL_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_BELLRING, // deathsound
+0, // speed
+56*FRACUNIT, // radius
+120*FRACUNIT, // height
+H2MAXINT, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_NOGRAVITY|MF_SPAWNCEILING, // flags
+0 // flags2
+ },
+
+{ // MT_ZBLUE_CANDLE
+8066, // doomednum
+S_ZBLUE_CANDLE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_ZIRON_MAIDEN
+8067, // doomednum
+S_ZIRON_MAIDEN, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+12*FRACUNIT, // radius
+60*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_ZXMAS_TREE
+8068, // doomednum
+S_ZXMAS_TREE, // spawnstate
+20, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_ZXMAS_TREE_X1, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ZXMAS_TREE_DIE, // deathstate
+S_NULL, // xdeathstate
+SFX_TREE_EXPLODE, // deathsound
+0, // speed
+11*FRACUNIT, // radius
+130*FRACUNIT, // height
+H2MAXINT, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD, // flags
+0 // flags2
+ },
+
+{ // MT_ZCAULDRON
+8069, // doomednum
+S_ZCAULDRON1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+12*FRACUNIT, // radius
+26*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_ZCAULDRON_UNLIT
+8070, // doomednum
+S_ZCAULDRON_U, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+12*FRACUNIT, // radius
+26*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID, // flags
+0 // flags2
+ },
+
+{ // MT_ZCHAINBIT32
+8071, // doomednum
+S_ZCHAINBIT32, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+32*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING, // flags
+0 // flags2
+ },
+
+{ // MT_ZCHAINBIT64
+8072, // doomednum
+S_ZCHAINBIT64, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+64*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING, // flags
+0 // flags2
+ },
+
+{ // MT_ZCHAINEND_HEART
+8073, // doomednum
+S_ZCHAINEND_HEART, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+32*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING, // flags
+0 // flags2
+ },
+
+{ // MT_ZCHAINEND_HOOK1
+8074, // doomednum
+S_ZCHAINEND_HOOK1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+32*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING, // flags
+0 // flags2
+ },
+
+{ // MT_ZCHAINEND_HOOK2
+8075, // doomednum
+S_ZCHAINEND_HOOK2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+32*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING, // flags
+0 // flags2
+ },
+
+{ // MT_ZCHAINEND_SPIKE
+8076, // doomednum
+S_ZCHAINEND_SPIKE, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+32*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING, // flags
+0 // flags2
+ },
+
+{ // MT_ZCHAINEND_SKULL
+8077, // doomednum
+S_ZCHAINEND_SKULL, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+32*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING, // flags
+0 // flags2
+ },
+
+{ // MT_TABLE_SHIT1
+8500, // doomednum
+S_TABLE_SHIT1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_TABLE_SHIT2
+8501, // doomednum
+S_TABLE_SHIT2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_TABLE_SHIT3
+8502, // doomednum
+S_TABLE_SHIT3, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_TABLE_SHIT4
+8503, // doomednum
+S_TABLE_SHIT4, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_TABLE_SHIT5
+8504, // doomednum
+S_TABLE_SHIT5, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_TABLE_SHIT6
+8505, // doomednum
+S_TABLE_SHIT6, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_TABLE_SHIT7
+8506, // doomednum
+S_TABLE_SHIT7, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_TABLE_SHIT8
+8507, // doomednum
+S_TABLE_SHIT8, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_TABLE_SHIT9
+8508, // doomednum
+S_TABLE_SHIT9, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_TABLE_SHIT10
+8509, // doomednum
+S_TABLE_SHIT10, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_TFOG
+-1, // doomednum
+S_TFOG1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MISC81
+140, // doomednum
+S_TELESMOKE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_TELEPORTMAN
+14, // doomednum
+S_NULL, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOSECTOR, // flags
+0 // flags2
+ },
+
+{ // MT_PUNCHPUFF
+-1, // doomednum
+S_PUNCHPUFF1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_FIGHTER_PUNCH_HITTHING, // seesound
+8, // reactiontime
+SFX_FIGHTER_PUNCH_HITWALL, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+0 // flags2
+ },
+
+{ // MT_FW_AXE
+8010, // doomednum
+S_AXE, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_AXEPUFF
+-1, // doomednum
+S_HAMMERPUFF1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_FIGHTER_AXE_HITTHING, // seesound
+8, // reactiontime
+SFX_FIGHTER_HAMMER_HITWALL, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+0 // flags2
+ },
+
+{ // MT_AXEPUFF_GLOW
+-1, // doomednum
+S_AXEPUFF_GLOW1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_FIGHTER_AXE_HITTHING, // seesound
+8, // reactiontime
+SFX_FIGHTER_HAMMER_HITWALL, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_AXEBLOOD
+-1, // doomednum
+S_AXEBLOOD1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_AXEBLOOD6, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+2*FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_CANNOTPUSH // flags2
+ },
+
+{ // MT_FW_HAMMER
+123, // doomednum
+S_HAMM, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_HAMMER_MISSILE
+-1, // doomednum
+S_HAMMER_MISSILE_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_HAMMER_MISSILE_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_FIGHTER_HAMMER_EXPLODE, // deathsound
+25*FRACUNIT, // speed
+14*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+10, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_HAMMERPUFF
+-1, // doomednum
+S_HAMMERPUFF1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_FIGHTER_HAMMER_HITTHING, // seesound
+8, // reactiontime
+SFX_FIGHTER_HAMMER_HITWALL, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+0 // flags2
+ },
+
+{ // MT_FSWORD_MISSILE
+-1, // doomednum
+S_FSWORD_MISSILE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_FSWORD_MISSILE_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_FIGHTER_SWORD_EXPLODE, // deathsound
+30*FRACUNIT, // speed
+16*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+8, // damage
+SFX_NONE, // activesound
+MF_MISSILE|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS // flags2
+ },
+
+{ // MT_FSWORD_FLAME
+-1, // doomednum
+S_FSWORD_FLAME1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+0 // flags2
+ },
+
+{ // MT_CW_SERPSTAFF
+10, // doomednum
+S_CSTAFF, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_CSTAFF_MISSILE
+-1, // doomednum
+S_CSTAFF_MISSILE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_CSTAFF_MISSILE_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_CLERIC_CSTAFF_EXPLODE, // deathsound
+22*FRACUNIT, // speed
+12*FRACUNIT, // radius
+10*FRACUNIT, // height
+100, // mass
+5, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS // flags2
+ },
+
+{ // MT_CSTAFFPUFF
+-1, // doomednum
+S_CSTAFFPUFF1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_CLERIC_CSTAFF_HITTHING, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+0 // flags2
+ },
+
+{ // MT_CW_FLAME
+8009, // doomednum
+S_CFLAME1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_CFLAMEFLOOR
+-1, // doomednum
+S_CFLAMEFLOOR1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_FLAMEPUFF
+-1, // doomednum
+S_FLAMEPUFF1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_CLERIC_FLAME_EXPLODE, // seesound
+8, // reactiontime
+SFX_CLERIC_FLAME_EXPLODE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+FRACUNIT, // radius
+FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_FLAMEPUFF2
+-1, // doomednum
+S_FLAMEPUFF2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_CLERIC_FLAME_EXPLODE, // seesound
+8, // reactiontime
+SFX_CLERIC_FLAME_EXPLODE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+FRACUNIT, // radius
+FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_CIRCLEFLAME
+-1, // doomednum
+S_CIRCLE_FLAME1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_CIRCLE_FLAME_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_CLERIC_FLAME_CIRCLE, // deathsound
+0, // speed
+6*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+2, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_CFLAME_MISSILE
+-1, // doomednum
+S_CFLAME_MISSILE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_CFLAME_MISSILE_X, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+200*FRACUNIT, // speed
+14*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+8, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_DONTDRAW|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_HOLY_FX
+-1, // doomednum
+S_HOLY_FX1, // spawnstate
+105, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_HOLY_FX_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_SPIRIT_DIE, // deathsound
+12*FRACUNIT, // speed
+10*FRACUNIT, // radius
+6*FRACUNIT, // height
+100, // mass
+3, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_SEEKERMISSILE|MF2_RIP|MF2_IMPACT|MF2_PCROSS // flags2
+ },
+
+{ // MT_HOLY_TAIL
+-1, // doomednum
+S_HOLY_TAIL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+FRACUNIT, // radius
+FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_NOCLIP|MF_ALTSHADOW, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_HOLY_PUFF
+-1, // doomednum
+S_HOLY_PUFF1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+0 // flags2
+ },
+
+{ // MT_HOLY_MISSILE
+-1, // doomednum
+S_HOLY_MISSILE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_HOLY_MISSILE_X, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+30*FRACUNIT, // speed
+15*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+4, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_HOLY_MISSILE_PUFF
+-1, // doomednum
+S_HOLY_MISSILE_P1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_MWANDPUFF
+-1, // doomednum
+S_MWANDPUFF1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_CANNOTPUSH|MF2_NODMGTHRUST // flags2
+ },
+
+{ // MT_MWANDSMOKE
+-1, // doomednum
+S_MWANDSMOKE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+MF2_NOTELEPORT|MF2_CANNOTPUSH|MF2_NODMGTHRUST // flags2
+ },
+
+{ // MT_MWAND_MISSILE
+-1, // doomednum
+S_MWAND_MISSILE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_MWANDPUFF1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+184*FRACUNIT, // speed
+12*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+2, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_RIP|MF2_IMPACT|MF2_PCROSS|MF2_NODMGTHRUST|MF2_CANNOTPUSH // flags2
+ },
+
+{ // MT_MW_LIGHTNING
+8040, // doomednum
+S_MW_LIGHTNING1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_LIGHTNING_CEILING
+-1, // doomednum
+S_LIGHTNING_CEILING1, // spawnstate
+144, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_LIGHTNING_C_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+25*FRACUNIT, // speed
+16*FRACUNIT, // radius
+40*FRACUNIT, // height
+100, // mass
+8, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS // flags2
+ },
+
+{ // MT_LIGHTNING_FLOOR
+-1, // doomednum
+S_LIGHTNING_FLOOR1, // spawnstate
+144, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_LIGHTNING_F_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+25*FRACUNIT, // speed
+16*FRACUNIT, // radius
+40*FRACUNIT, // height
+100, // mass
+8, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS // flags2
+ },
+
+{ // MT_LIGHTNING_ZAP
+-1, // doomednum
+S_LIGHTNING_ZAP1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_LIGHTNING_ZAP_X8, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+15*FRACUNIT, // radius
+35*FRACUNIT, // height
+100, // mass
+2, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE|MF_DROPOFF, // flags
+0 // flags2
+ },
+
+{ // MT_MSTAFF_FX
+-1, // doomednum
+S_MSTAFF_FX1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_MSTAFF_FX_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_MAGE_STAFF_EXPLODE, // deathsound
+20*FRACUNIT, // speed
+16*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+6, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE|MF2_RIP|MF2_IMPACT|MF2_PCROSS // flags2
+ },
+
+{ // MT_MSTAFF_FX2
+-1, // doomednum
+S_MSTAFF_FX2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_MSTAFF_FX2_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_MAGE_STAFF_EXPLODE, // deathsound
+17*FRACUNIT, // speed
+20*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+4, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE|MF2_IMPACT|MF2_PCROSS|MF2_SEEKERMISSILE // flags2
+ },
+
+{ // MT_FW_SWORD1
+12, // doomednum
+S_FSWORD1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_FW_SWORD2
+13, // doomednum
+S_FSWORD2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_FW_SWORD3
+16, // doomednum
+S_FSWORD3, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_CW_HOLY1
+18, // doomednum
+S_CHOLY1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_CW_HOLY2
+19, // doomednum
+S_CHOLY2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_CW_HOLY3
+20, // doomednum
+S_CHOLY3, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_MW_STAFF1
+21, // doomednum
+S_MSTAFF1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_MW_STAFF2
+22, // doomednum
+S_MSTAFF2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_MW_STAFF3
+23, // doomednum
+S_MSTAFF3, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_SNOUTPUFF
+-1, // doomednum
+S_PUNCHPUFF1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+0 // flags2
+ },
+
+{ // MT_MW_CONE
+53, // doomednum
+S_COS1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_SHARDFX1
+-1, // doomednum
+S_SHARDFX1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SHARDFXE1_1, // deathstate
+S_NULL, // xdeathstate
+SFX_MAGE_SHARDS_EXPLODE, // deathsound
+25*FRACUNIT, // speed
+13*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+1, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_ICEDAMAGE // flags2
+ },
+
+{ // MT_BLOOD
+-1, // doomednum
+S_BLOOD1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+0 // flags2
+ },
+
+{ // MT_BLOODSPLATTER
+-1, // doomednum
+S_BLOODSPLATTER1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_BLOODSPLATTERX, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+2*FRACUNIT, // radius
+4*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_CANNOTPUSH // flags2
+ },
+
+{ // MT_GIBS
+-1, // doomednum
+S_GIBS1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_PLAYER_FIGHTER
+-1, // doomednum
+S_FPLAY, // spawnstate
+100, // spawnhealth
+S_FPLAY_RUN1, // seestate
+SFX_NONE, // seesound
+0, // reactiontime
+SFX_NONE, // attacksound
+S_FPLAY_PAIN, // painstate
+255, // painchance
+SFX_PLAYER_FIGHTER_PAIN, // painsound
+S_NULL, // meleestate
+S_FPLAY_ATK1, // missilestate
+S_NULL, // crashstate
+S_FPLAY_DIE1, // deathstate
+S_FPLAY_XDIE1, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+16*FRACUNIT, // radius
+64*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH, // flags
+MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL // flags2
+ },
+
+{ // MT_BLOODYSKULL
+-1, // doomednum
+S_BLOODYSKULL1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+4*FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF, // flags
+MF2_LOGRAV|MF2_CANNOTPUSH // flags2
+ },
+
+{ // MT_PLAYER_SPEED
+-1, // doomednum
+S_PLAYER_SPEED1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_ALTSHADOW, // flags
+0 // flags2
+ },
+
+{ // MT_ICECHUNK
+-1, // doomednum
+S_ICECHUNK1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+3*FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF, // flags
+MF2_LOGRAV|MF2_CANNOTPUSH|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_PLAYER_CLERIC
+-1, // doomednum
+S_CPLAY, // spawnstate
+100, // spawnhealth
+S_CPLAY_RUN1, // seestate
+SFX_NONE, // seesound
+0, // reactiontime
+SFX_NONE, // attacksound
+S_CPLAY_PAIN, // painstate
+255, // painchance
+SFX_PLAYER_CLERIC_PAIN, // painsound
+S_NULL, // meleestate
+S_CPLAY_ATK1, // missilestate
+S_NULL, // crashstate
+S_CPLAY_DIE1, // deathstate
+S_CPLAY_XDIE1, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+16*FRACUNIT, // radius
+64*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH, // flags
+MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL // flags2
+ },
+
+{ // MT_PLAYER_MAGE
+-1, // doomednum
+S_MPLAY, // spawnstate
+100, // spawnhealth
+S_MPLAY_RUN1, // seestate
+SFX_NONE, // seesound
+0, // reactiontime
+SFX_NONE, // attacksound
+S_MPLAY_PAIN, // painstate
+255, // painchance
+SFX_PLAYER_MAGE_PAIN, // painsound
+S_NULL, // meleestate
+S_MPLAY_ATK1, // missilestate
+S_NULL, // crashstate
+S_MPLAY_DIE1, // deathstate
+S_MPLAY_XDIE1, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+16*FRACUNIT, // radius
+64*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH, // flags
+MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL // flags2
+ },
+
+#ifdef ASSASSIN
+{ // MT_PLAYER_ASS
+-1, // doomednum
+S_APLAY, // spawnstate
+100, // spawnhealth
+S_APLAY_RUN1, // seestate
+SFX_NONE, // seesound
+0, // reactiontime
+SFX_NONE, // attacksound
+S_APLAY_PAIN, // painstate
+255, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_APLAY_ATK1, // misslestate
+S_NULL, // crashstate
+S_APLAY_DIE1, // deathstate
+S_APLAY_XDIE1, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+16*FRACUNIT, // radius
+64*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH, // flags
+MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL // flags2
+ },
+#endif /* ASSASSIN */
+
+{ // MT_PIGPLAYER
+-1, // doomednum
+S_PIGPLAY, // spawnstate
+100, // spawnhealth
+S_PIGPLAY_RUN1, // seestate
+SFX_NONE, // seesound
+0, // reactiontime
+SFX_NONE, // attacksound
+S_PIGPLAY_PAIN, // painstate
+255, // painchance
+SFX_PIG_PAIN, // painsound
+S_NULL, // meleestate
+S_PIGPLAY_ATK1, // missilestate
+S_NULL, // crashstate
+S_PIG_DIE1, // deathstate
+S_NULL, // xdeathstate
+SFX_PIG_DEATH, // deathsound
+0, // speed
+16*FRACUNIT, // radius
+24*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_NOTDMATCH, // flags
+MF2_WINDTHRUST|MF2_SLIDE|MF2_PASSMOBJ|MF2_FLOORCLIP|MF2_TELESTOMP|MF2_PUSHWALL // flags2
+ },
+
+{ // MT_PIG
+-1, // doomednum
+S_PIG_LOOK1, // spawnstate
+25, // spawnhealth
+S_PIG_WALK1, // seestate
+SFX_PIG_ACTIVE1, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_PIG_PAIN, // painstate
+128, // painchance
+SFX_PIG_PAIN, // painsound
+S_PIG_ATK1, // meleestate
+0, // missilestate
+S_NULL, // crashstate
+S_PIG_DIE1, // deathstate
+S_NULL, // xdeathstate
+SFX_PIG_DEATH, // deathsound
+10, // speed
+12*FRACUNIT, // radius
+22*FRACUNIT, // height
+60, // mass
+0, // damage
+SFX_PIG_ACTIVE1, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
+MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_TELESTOMP // flags2
+ },
+
+{ // MT_CENTAUR
+107, // doomednum
+S_CENTAUR_LOOK1, // spawnstate
+200, // spawnhealth
+S_CENTAUR_WALK1, // seestate
+SFX_CENTAUR_SIGHT, // seesound
+8, // reactiontime
+SFX_CENTAUR_ATTACK, // attacksound
+S_CENTAUR_PAIN1, // painstate
+135, // painchance
+SFX_CENTAUR_PAIN, // painsound
+S_CENTAUR_ATK1, // meleestate
+0, // missilestate
+S_NULL, // crashstate
+S_CENTAUR_DEATH1, // deathstate
+S_CENTAUR_DEATH_X1, // xdeathstate
+SFX_CENTAUR_DEATH, // deathsound
+13, // speed
+20*FRACUNIT, // radius
+64*FRACUNIT, // height
+120, // mass
+0, // damage
+SFX_CENTAUR_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_MCROSS|MF2_TELESTOMP // flags2
+ },
+
+{ // MT_CENTAURLEADER
+115, // doomednum
+S_CENTAUR_LOOK1, // spawnstate
+250, // spawnhealth
+S_CENTAUR_WALK1, // seestate
+SFX_CENTAUR_SIGHT, // seesound
+8, // reactiontime
+SFX_CENTAUR_ATTACK, // attacksound
+S_CENTAUR_PAIN1, // painstate
+96, // painchance
+SFX_CENTAUR_PAIN, // painsound
+S_CENTAUR_ATK1, // meleestate
+S_CENTAUR_MISSILE1, // missilestate
+S_NULL, // crashstate
+S_CENTAUR_DEATH1, // deathstate
+S_CENTAUR_DEATH_X1, // xdeathstate
+SFX_CENTAUR_DEATH, // deathsound
+10, // speed
+20*FRACUNIT, // radius
+64*FRACUNIT, // height
+120, // mass
+0, // damage
+SFX_CENTAUR_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_MCROSS|MF2_TELESTOMP // flags2
+ },
+
+{ // MT_CENTAUR_FX
+-1, // doomednum
+S_CENTAUR_FX1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_CENTAUR_FX_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_CENTAUR_MISSILE_EXPLODE, // deathsound
+20*FRACUNIT, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+4, // damage
+SFX_NONE, // activesound
+MF_MISSILE|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS // flags2
+ },
+
+{ // MT_CENTAUR_SHIELD
+-1, // doomednum
+S_CENTAUR_SHIELD1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_CENTAUR_SHIELD_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_CENTAUR_SWORD
+-1, // doomednum
+S_CENTAUR_SWORD1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_CENTAUR_SWORD_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_DEMON
+31, // doomednum
+S_DEMN_LOOK1, // spawnstate
+250, // spawnhealth
+S_DEMN_CHASE1, // seestate
+SFX_DEMON_SIGHT, // seesound
+8, // reactiontime
+SFX_DEMON_ATTACK, // attacksound
+S_DEMN_PAIN1, // painstate
+50, // painchance
+SFX_DEMON_PAIN, // painsound
+S_DEMN_ATK1_1, // meleestate
+S_DEMN_ATK2_1, // missilestate
+S_NULL, // crashstate
+S_DEMN_DEATH1, // deathstate
+S_DEMN_XDEATH1, // xdeathstate
+SFX_DEMON_DEATH, // deathsound
+13, // speed
+32*FRACUNIT, // radius
+64*FRACUNIT, // height
+220, // mass
+0, // damage
+SFX_DEMON_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_TELESTOMP // flags2
+ },
+
+{ // MT_DEMONCHUNK1
+-1, // doomednum
+S_DEMONCHUNK1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMONCHUNK1_4, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_DEMONCHUNK2
+-1, // doomednum
+S_DEMONCHUNK2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMONCHUNK2_4, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_DEMONCHUNK3
+-1, // doomednum
+S_DEMONCHUNK3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMONCHUNK3_4, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_DEMONCHUNK4
+-1, // doomednum
+S_DEMONCHUNK4_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMONCHUNK4_4, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_DEMONCHUNK5
+-1, // doomednum
+S_DEMONCHUNK5_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMONCHUNK5_4, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_DEMONFX1
+-1, // doomednum
+S_DEMONFX_MOVE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMONFX_BOOM1, // deathstate
+S_NULL, // xdeathstate
+SFX_DEMON_MISSILE_EXPLODE, // deathsound
+15*FRACUNIT, // speed
+10*FRACUNIT, // radius
+6*FRACUNIT, // height
+100, // mass
+5, // damage
+SFX_NONE, // activesound
+MF_MISSILE|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_DEMON2
+8080, // doomednum
+S_DEMN2_LOOK1, // spawnstate
+250, // spawnhealth
+S_DEMN2_CHASE1, // seestate
+SFX_DEMON_SIGHT, // seesound
+8, // reactiontime
+SFX_DEMON_ATTACK, // attacksound
+S_DEMN2_PAIN1, // painstate
+50, // painchance
+SFX_DEMON_PAIN, // painsound
+S_DEMN2_ATK1_1, // meleestate
+S_DEMN2_ATK2_1, // missilestate
+S_NULL, // crashstate
+S_DEMN2_DEATH1, // deathstate
+S_DEMN2_XDEATH1, // xdeathstate
+SFX_DEMON_DEATH, // deathsound
+13, // speed
+32*FRACUNIT, // radius
+64*FRACUNIT, // height
+220, // mass
+0, // damage
+SFX_DEMON_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_TELESTOMP // flags2
+ },
+
+{ // MT_DEMON2CHUNK1
+-1, // doomednum
+S_DEMON2CHUNK1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMON2CHUNK1_4, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_DEMON2CHUNK2
+-1, // doomednum
+S_DEMON2CHUNK2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMON2CHUNK2_4, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_DEMON2CHUNK3
+-1, // doomednum
+S_DEMON2CHUNK3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMON2CHUNK3_4, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_DEMON2CHUNK4
+-1, // doomednum
+S_DEMON2CHUNK4_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMON2CHUNK4_4, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_DEMON2CHUNK5
+-1, // doomednum
+S_DEMON2CHUNK5_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMON2CHUNK5_4, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_DEMON2FX1
+-1, // doomednum
+S_DEMON2FX_MOVE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DEMON2FX_BOOM1, // deathstate
+S_NULL, // xdeathstate
+SFX_DEMON_MISSILE_EXPLODE, // deathsound
+15*FRACUNIT, // speed
+10*FRACUNIT, // radius
+6*FRACUNIT, // height
+100, // mass
+5, // damage
+SFX_NONE, // activesound
+MF_MISSILE|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_WRAITHB
+10011, // doomednum
+S_WRAITH_LOOK1, // spawnstate
+150, // spawnhealth
+S_WRAITH_RAISE1, // seestate
+SFX_WRAITH_SIGHT, // seesound
+8, // reactiontime
+SFX_WRAITH_ATTACK, // attacksound
+S_WRAITH_PAIN1, // painstate
+25, // painchance
+SFX_WRAITH_PAIN, // painsound
+S_WRAITH_ATK1_1, // meleestate
+S_WRAITH_ATK2_1, // missilestate
+S_NULL, // crashstate
+S_WRAITH_DEATH1_1, // deathstate
+S_WRAITH_DEATH2_1, // xdeathstate
+SFX_WRAITH_DEATH, // deathsound
+11, // speed
+20*FRACUNIT, // radius
+68*FRACUNIT, // height
+75, // mass
+10, // damage
+SFX_WRAITH_ACTIVE, // activesound
+MF_DROPOFF|MF_NOGRAVITY|MF_FLOAT|MF_COUNTKILL, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_TELESTOMP|MF2_DONTDRAW // flags2
+ },
+
+{ // MT_WRAITH
+34, // doomednum
+S_WRAITH_INIT1, // spawnstate
+150, // spawnhealth
+S_WRAITH_CHASE1, // seestate
+SFX_WRAITH_SIGHT, // seesound
+8, // reactiontime
+SFX_WRAITH_ATTACK, // attacksound
+S_WRAITH_PAIN1, // painstate
+25, // painchance
+SFX_WRAITH_PAIN, // painsound
+S_WRAITH_ATK1_1, // meleestate
+S_WRAITH_ATK2_1, // missilestate
+S_NULL, // crashstate
+S_WRAITH_DEATH1_1, // deathstate
+S_WRAITH_DEATH2_1, // xdeathstate
+SFX_WRAITH_DEATH, // deathsound
+11, // speed
+20*FRACUNIT, // radius
+55*FRACUNIT, // height
+75, // mass
+10, // damage
+SFX_WRAITH_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_DROPOFF|MF_NOGRAVITY|MF_FLOAT, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_TELESTOMP // flags2
+ },
+
+{ // MT_WRAITHFX1
+-1, // doomednum
+S_WRTHFX_MOVE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_WRTHFX_BOOM1, // deathstate
+S_NULL, // xdeathstate
+SFX_WRAITH_MISSILE_EXPLODE, // deathsound
+14*FRACUNIT, // speed
+10*FRACUNIT, // radius
+6*FRACUNIT, // height
+5, // mass
+5, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_FLOORCLIP|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_WRAITHFX2
+-1, // doomednum
+S_WRTHFX_SIZZLE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+2*FRACUNIT, // radius
+5*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_WRAITHFX3
+-1, // doomednum
+S_WRTHFX_DROP1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_WRTHFX_DEAD1, // deathstate
+S_NULL, // xdeathstate
+SFX_DRIP, // deathsound
+0, // speed
+2*FRACUNIT, // radius
+5*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_WRAITHFX4
+-1, // doomednum
+S_WRTHFX_ADROP1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_WRTHFX_ADEAD1, // deathstate
+S_NULL, // xdeathstate
+SFX_DRIP, // deathsound
+0, // speed
+2*FRACUNIT, // radius
+5*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_WRAITHFX5
+-1, // doomednum
+S_WRTHFX_BDROP1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_WRTHFX_BDEAD1, // deathstate
+S_NULL, // xdeathstate
+SFX_DRIP, // deathsound
+0, // speed
+2*FRACUNIT, // radius
+5*FRACUNIT, // height
+5, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_MINOTAUR
+9, // doomednum
+S_MNTR_SPAWN1, // spawnstate
+2500, // spawnhealth
+S_MNTR_WALK1, // seestate
+SFX_MAULATOR_SIGHT, // seesound
+8, // reactiontime
+SFX_MAULATOR_HAMMER_SWING, // attacksound
+S_MNTR_PAIN1, // painstate
+25, // painchance
+SFX_MAULATOR_PAIN, // painsound
+S_MNTR_ATK1_1, // meleestate
+S_MNTR_ATK2_1, // missilestate
+S_NULL, // crashstate
+S_MNTR_DIE1, // deathstate
+S_NULL, // xdeathstate
+SFX_MAULATOR_DEATH, // deathsound
+16, // speed
+28*FRACUNIT, // radius
+100*FRACUNIT, // height
+800, // mass
+7, // damage
+SFX_MAULATOR_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_SHADOW, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_TELESTOMP // flags2
+ },
+
+{ // MT_MNTRFX1
+-1, // doomednum
+S_MNTRFX1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_MNTRFXI1_1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+20*FRACUNIT, // speed
+10*FRACUNIT, // radius
+6*FRACUNIT, // height
+100, // mass
+3, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_MNTRFX2
+-1, // doomednum
+S_MNTRFX2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_MNTRFXI2_1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+14*FRACUNIT, // speed
+5*FRACUNIT, // radius
+12*FRACUNIT, // height
+100, // mass
+4, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_MNTRFX3
+-1, // doomednum
+S_MNTRFX3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+0, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_MNTRFXI2_1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+4, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_MNTRSMOKE
+-1, // doomednum
+S_MINOSMOKE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_MNTRSMOKEEXIT
+-1, // doomednum
+S_MINOSMOKEX1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_SERPENT
+121, // doomednum
+S_SERPENT_LOOK1, // spawnstate
+90, // spawnhealth
+S_SERPENT_SWIM1, // seestate
+SFX_SERPENT_SIGHT, // seesound
+8, // reactiontime
+SFX_SERPENT_ATTACK, // attacksound
+S_SERPENT_PAIN1, // painstate
+96, // painchance
+SFX_SERPENT_PAIN, // painsound
+S_SERPENT_SURFACE1, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SERPENT_DIE1, // deathstate
+S_SERPENT_XDIE1, // xdeathstate
+SFX_SERPENT_DEATH, // deathsound
+12, // speed
+32*FRACUNIT, // radius
+70*FRACUNIT, // height
+H2MAXINT, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_COUNTKILL|MF_NOBLOOD, // flags
+MF2_PASSMOBJ|MF2_DONTDRAW|MF2_CANTLEAVEFLOORPIC|MF2_NONSHOOTABLE|MF2_MCROSS // flags2
+ },
+
+{ // MT_SERPENTLEADER
+120, // doomednum
+S_SERPENT_LOOK1, // spawnstate
+90, // spawnhealth
+S_SERPENT_SWIM1, // seestate
+SFX_SERPENT_SIGHT, // seesound
+8, // reactiontime
+SFX_SERPENT_ATTACK, // attacksound
+S_SERPENT_PAIN1, // painstate
+96, // painchance
+SFX_SERPENT_PAIN, // painsound
+S_SERPENT_SURFACE1, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SERPENT_DIE1, // deathstate
+S_SERPENT_XDIE1, // xdeathstate
+SFX_SERPENT_DEATH, // deathsound
+12, // speed
+32*FRACUNIT, // radius
+70*FRACUNIT, // height
+200, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_COUNTKILL|MF_NOBLOOD, // flags
+MF2_PASSMOBJ|MF2_DONTDRAW|MF2_CANTLEAVEFLOORPIC|MF2_NONSHOOTABLE|MF2_MCROSS // flags2
+ },
+
+{ // MT_SERPENTFX
+-1, // doomednum
+S_SERPENT_FX1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+0, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SERPENT_FX_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_SERPENTFX_HIT, // deathsound
+15*FRACUNIT, // speed
+8*FRACUNIT, // radius
+10*FRACUNIT, // height
+100, // mass
+4, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_SERPENT_HEAD
+-1, // doomednum
+S_SERPENT_HEAD1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+10*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+MF2_LOGRAV // flags2
+ },
+
+{ // MT_SERPENT_GIB1
+-1, // doomednum
+S_SERPENT_GIB1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+3*FRACUNIT, // radius
+3*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_SERPENT_GIB2
+-1, // doomednum
+S_SERPENT_GIB2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+3*FRACUNIT, // radius
+3*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_SERPENT_GIB3
+-1, // doomednum
+S_SERPENT_GIB3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+3*FRACUNIT, // radius
+3*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_BISHOP
+114, // doomednum
+S_BISHOP_LOOK1, // spawnstate
+130, // spawnhealth
+S_BISHOP_WALK1, // seestate
+SFX_BISHOP_SIGHT, // seesound
+8, // reactiontime
+SFX_BISHOP_ATTACK, // attacksound
+S_BISHOP_PAIN1, // painstate
+110, // painchance
+SFX_BISHOP_PAIN, // painsound
+0, // meleestate
+S_BISHOP_ATK1, // missilestate
+S_NULL, // crashstate
+S_BISHOP_DEATH1, // deathstate
+S_NULL, // xdeathstate
+SFX_BISHOP_DEATH, // deathsound
+10, // speed
+22*FRACUNIT, // radius
+65*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_BISHOP_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_FLOAT|MF_NOGRAVITY|MF_NOBLOOD, // flags
+MF2_PASSMOBJ|MF2_PUSHWALL|MF2_TELESTOMP // flags2
+ },
+
+{ // MT_BISHOP_PUFF
+-1, // doomednum
+S_BISHOP_PUFF1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SHADOW|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_BISHOPBLUR
+-1, // doomednum
+S_BISHOPBLUR1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+0 // flags2
+ },
+
+{ // MT_BISHOPPAINBLUR
+-1, // doomednum
+S_BISHOPPAINBLUR1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW, // flags
+0 // flags2
+ },
+
+{ // MT_BISH_FX
+-1, // doomednum
+S_BISHFX1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_BISHFXI1_1, // deathstate
+S_NULL, // xdeathstate
+SFX_BISHOP_MISSILE_EXPLODE, // deathsound
+10*FRACUNIT, // speed
+10*FRACUNIT, // radius
+6*FRACUNIT, // height
+100, // mass
+1, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_SEEKERMISSILE // flags2
+ },
+
+{ // MT_DRAGON
+254, // doomednum
+S_DRAGON_LOOK1, // spawnstate
+640, // spawnhealth
+S_DRAGON_INIT, // seestate
+SFX_DRAGON_SIGHT, // seesound
+8, // reactiontime
+SFX_DRAGON_ATTACK, // attacksound
+S_DRAGON_PAIN1, // painstate
+128, // painchance
+SFX_DRAGON_PAIN, // painsound
+S_NULL, // meleestate
+S_DRAGON_ATK1, // missilestate
+S_NULL, // crashstate
+S_DRAGON_DEATH1, // deathstate
+S_NULL, // xdeathstate
+SFX_DRAGON_DEATH, // deathsound
+10*FRACUNIT, // speed
+20*FRACUNIT, // radius
+65*FRACUNIT, // height
+H2MAXINT, // mass
+0, // damage
+SFX_DRAGON_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_FLOAT|MF_NOGRAVITY|MF_NOBLOOD, // flags
+MF2_PASSMOBJ|MF2_BOSS // flags2
+ },
+
+{ // MT_DRAGON_FX
+-1, // doomednum
+S_DRAGON_FX1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_DRAGON_FX1_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_DRAGON_FIREBALL_EXPLODE, // deathsound
+24*FRACUNIT, // speed
+12*FRACUNIT, // radius
+10*FRACUNIT, // height
+100, // mass
+6, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_DRAGON_FX2
+-1, // doomednum
+S_DRAGON_FX2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_DRAGON_FIREBALL_EXPLODE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP, // flags
+MF2_NOTELEPORT|MF2_FIREDAMAGE|MF2_DONTDRAW // flags2
+ },
+
+{ // MT_ARMOR_1
+8005, // doomednum
+S_ARMOR_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARMOR_2
+8006, // doomednum
+S_ARMOR_2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARMOR_3
+8007, // doomednum
+S_ARMOR_3, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_ARMOR_4
+8008, // doomednum
+S_ARMOR_4, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+ },
+
+{ // MT_MANA1
+122, // doomednum
+S_MANA1_1, // spawnstate
+10, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_MANA2
+124, // doomednum
+S_MANA2_1, // spawnstate
+10, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_MANA3
+8004, // doomednum
+S_MANA3_1, // spawnstate
+20, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+8*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+MF2_FLOATBOB // flags2
+ },
+
+{ // MT_KEY1
+8030, // doomednum
+S_KEY1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_KEY2
+8031, // doomednum
+S_KEY2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_KEY3
+8032, // doomednum
+S_KEY3, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_KEY4
+8033, // doomednum
+S_KEY4, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_KEY5
+8034, // doomednum
+S_KEY5, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_KEY6
+8035, // doomednum
+S_KEY6, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_KEY7
+8036, // doomednum
+S_KEY7, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_KEY8
+8037, // doomednum
+S_KEY8, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_KEY9
+8038, // doomednum
+S_KEY9, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_KEYA
+8039, // doomednum
+S_KEYA, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_KEYB
+8200, // doomednum
+S_KEYB, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+8*FRACUNIT, // radius
+20*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+{ // MT_SOUNDWIND
+1410, // doomednum
+S_SND_WIND1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOSECTOR, // flags
+0 // flags2
+ },
+
+{ // MT_SOUNDWATERFALL
+41, // doomednum
+S_SND_WATERFALL, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOSECTOR, // flags
+0 // flags2
+ },
+
+{ // MT_ETTIN
+10030, // doomednum
+S_ETTIN_LOOK1, // spawnstate
+175, // spawnhealth
+S_ETTIN_CHASE1, // seestate
+SFX_ETTIN_SIGHT, // seesound
+8, // reactiontime
+SFX_ETTIN_ATTACK, // attacksound
+S_ETTIN_PAIN1, // painstate
+60, // painchance
+SFX_ETTIN_PAIN, // painsound
+S_ETTIN_ATK1_1, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ETTIN_DEATH1_1, // deathstate
+S_ETTIN_DEATH2_1, // xdeathstate
+SFX_ETTIN_DEATH, // deathsound
+13, // speed
+25*FRACUNIT, // radius
+68*FRACUNIT, // height
+175, // mass
+3, // damage
+SFX_ETTIN_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
+MF2_FLOORCLIP|MF2_PUSHWALL|MF2_MCROSS|MF2_TELESTOMP // flags2
+ },
+
+{ // MT_ETTIN_MACE
+-1, // doomednum
+S_ETTIN_MACE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ETTIN_MACE5, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_FIREDEMON
+10060, // doomednum
+S_FIRED_SPAWN1, // spawnstate
+80, // spawnhealth
+S_FIRED_LOOK4, // seestate
+SFX_FIRED_SPAWN, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_FIRED_PAIN1, // painstate
+1, // painchance
+SFX_FIRED_PAIN, // painsound
+S_NULL, // meleestate
+S_FIRED_ATTACK1, // missilestate
+S_FIRED_XDEATH1, // crashstate
+S_FIRED_DEATH1, // deathstate
+S_FIRED_XDEATH1, // xdeathstate
+SFX_FIRED_DEATH, // deathsound
+13, // speed
+20*FRACUNIT, // radius
+68*FRACUNIT, // height
+75, // mass
+1, // damage
+SFX_FIRED_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_DROPOFF|MF_NOGRAVITY|MF_FLOAT, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_INVULNERABLE|MF2_MCROSS|MF2_TELESTOMP // flags2
+ },
+
+{ // MT_FIREDEMON_SPLOTCH1
+-1, // doomednum
+S_FIRED_CORPSE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+3*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_FIREDEMON_SPLOTCH2
+-1, // doomednum
+S_FIRED_CORPSE4, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+3*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_DROPOFF|MF_CORPSE, // flags
+MF2_NOTELEPORT|MF2_FLOORCLIP // flags2
+ },
+
+{ // MT_FIREDEMON_FX1
+-1, // doomednum
+S_FIRED_RDROP1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_FIRED_RDEAD1_1, // deathstate
+S_FIRED_RDEAD1_2, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+3*FRACUNIT, // radius
+5*FRACUNIT, // height
+16, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_FIREDEMON_FX2
+-1, // doomednum
+S_FIRED_RDROP2, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_FIRED_RDEAD2_1, // deathstate
+S_FIRED_RDEAD2_2, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+3*FRACUNIT, // radius
+5*FRACUNIT, // height
+16, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_FIREDEMON_FX3
+-1, // doomednum
+S_FIRED_RDROP3, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_FIRED_RDEAD3_1, // deathstate
+S_FIRED_RDEAD3_2, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+3*FRACUNIT, // radius
+5*FRACUNIT, // height
+16, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_FIREDEMON_FX4
+-1, // doomednum
+S_FIRED_RDROP4, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_FIRED_RDEAD4_1, // deathstate
+S_FIRED_RDEAD4_2, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+3*FRACUNIT, // radius
+5*FRACUNIT, // height
+16, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_FIREDEMON_FX5
+-1, // doomednum
+S_FIRED_RDROP5, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_FIRED_RDEAD5_1, // deathstate
+S_FIRED_RDEAD5_2, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+3*FRACUNIT, // radius
+5*FRACUNIT, // height
+16, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_FIREDEMON_FX6
+-1, // doomednum
+S_FIRED_FX6_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_FIRED_FX6_2, // deathstate
+S_NULL, // xdeathstate
+SFX_FIRED_MISSILE_HIT, // deathsound
+10*FRACUNIT, // speed
+10*FRACUNIT, // radius
+6*FRACUNIT, // height
+15, // mass
+1, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_FLOORCLIP|MF2_FIREDAMAGE // flags2
+ },
+
+{ // MT_ICEGUY
+8020, // doomednum
+S_ICEGUY_LOOK, // spawnstate
+120, // spawnhealth
+S_ICEGUY_WALK1, // seestate
+SFX_ICEGUY_SIGHT, // seesound
+8, // reactiontime
+SFX_ICEGUY_ATTACK, // attacksound
+S_ICEGUY_PAIN1, // painstate
+144, // painchance
+SFX_NONE, // painsound
+0, // meleestate
+S_ICEGUY_ATK1, // missilestate
+S_NULL, // crashstate
+S_ICEGUY_DEATH, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+14, // speed
+22*FRACUNIT, // radius
+75*FRACUNIT, // height
+150, // mass
+0, // damage
+SFX_ICEGUY_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_NOBLOOD, // flags
+MF2_PASSMOBJ|MF2_PUSHWALL|MF2_ICEDAMAGE|MF2_MCROSS|MF2_TELESTOMP // flags2
+ },
+
+{ // MT_ICEGUY_FX
+-1, // doomednum
+S_ICEGUY_FX1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ICEGUY_FX_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_ICEGUY_FX_EXPLODE, // deathsound
+14*FRACUNIT, // speed
+8*FRACUNIT, // radius
+10*FRACUNIT, // height
+100, // mass
+1, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_ICEDAMAGE // flags2
+ },
+
+{ // MT_ICEFX_PUFF
+-1, // doomednum
+S_ICEFX_PUFF1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+FRACUNIT, // radius
+FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SHADOW|MF_DROPOFF, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_ICEGUY_FX2
+-1, // doomednum
+S_ICEGUY_FX2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+10*FRACUNIT, // speed
+4*FRACUNIT, // radius
+4*FRACUNIT, // height
+100, // mass
+1, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_LOGRAV|MF2_ICEDAMAGE // flags2
+ },
+
+{ // MT_ICEGUY_BIT
+-1, // doomednum
+S_ICEGUY_BIT1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+FRACUNIT, // radius
+FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_LOGRAV // flags2
+ },
+
+{ // MT_ICEGUY_WISP1
+-1, // doomednum
+S_ICEGUY_WISP1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_ICEGUY_WISP2
+-1, // doomednum
+S_ICEGUY_WISP2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_FIGHTER_BOSS
+10100, // doomednum
+S_FIGHTER, // spawnstate
+800, // spawnhealth
+S_FIGHTER_RUN1, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_FIGHTER_PAIN, // painstate
+50, // painchance
+SFX_PLAYER_FIGHTER_PAIN, // painsound
+S_FIGHTER_ATK1, // meleestate
+S_FIGHTER_ATK1, // missilestate
+S_NULL, // crashstate
+S_FIGHTER_DIE1, // deathstate
+S_FIGHTER_XDIE1, // xdeathstate
+SFX_PLAYER_FIGHTER_CRAZY_DEATH, // deathsound
+25, // speed
+16*FRACUNIT, // radius
+64*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL|MF2_MCROSS // flags2
+ },
+
+{ // MT_CLERIC_BOSS
+10101, // doomednum
+S_CLERIC, // spawnstate
+800, // spawnhealth
+S_CLERIC_RUN1, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_CLERIC_PAIN, // painstate
+50, // painchance
+SFX_PLAYER_CLERIC_PAIN, // painsound
+S_CLERIC_ATK1, // meleestate
+S_CLERIC_ATK1, // missilestate
+S_NULL, // crashstate
+S_CLERIC_DIE1, // deathstate
+S_CLERIC_XDIE1, // xdeathstate
+SFX_PLAYER_CLERIC_CRAZY_DEATH, // deathsound
+25, // speed
+16*FRACUNIT, // radius
+64*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL|MF2_MCROSS // flags2
+ },
+
+{ // MT_MAGE_BOSS
+10102, // doomednum
+S_MAGE, // spawnstate
+800, // spawnhealth
+S_MAGE_RUN1, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_MAGE_PAIN, // painstate
+50, // painchance
+SFX_PLAYER_MAGE_PAIN, // painsound
+S_MAGE_ATK1, // meleestate
+S_MAGE_ATK1, // missilestate
+S_NULL, // crashstate
+S_MAGE_DIE1, // deathstate
+S_MAGE_XDIE1, // xdeathstate
+SFX_PLAYER_MAGE_CRAZY_DEATH, // deathsound
+25, // speed
+16*FRACUNIT, // radius
+64*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL|MF2_MCROSS // flags2
+ },
+
+{ // MT_SORCBOSS
+10080, // doomednum
+S_SORC_SPAWN1, // spawnstate
+5000, // spawnhealth
+S_SORC_WALK1, // seestate
+SFX_SORCERER_SIGHT, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_SORC_PAIN1, // painstate
+10, // painchance
+SFX_SORCERER_PAIN, // painsound
+S_NULL, // meleestate
+S_SORC_ATK2_1, // missilestate
+S_NULL, // crashstate
+S_SORC_DIE1, // deathstate
+S_NULL, // xdeathstate
+SFX_SORCERER_DEATHSCREAM, // deathsound
+16, // speed
+40*FRACUNIT, // radius
+110*FRACUNIT, // height
+500, // mass
+9, // damage
+SFX_SORCERER_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_NOBLOOD, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_BOSS|MF2_MCROSS // flags2
+ },
+
+{ // MT_SORCBALL1
+-1, // doomednum
+S_SORCBALL1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_SORCERER_BALLBOUNCE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_SORCBALL1_D1, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SORCBALL1_D5, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+10*FRACUNIT, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SORCBALL2
+-1, // doomednum
+S_SORCBALL2_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_SORCERER_BALLBOUNCE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_SORCBALL2_D1, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SORCBALL2_D5, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+10*FRACUNIT, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SORCBALL3
+-1, // doomednum
+S_SORCBALL3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_SORCERER_BALLBOUNCE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_SORCBALL3_D1, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SORCBALL3_D5, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+10*FRACUNIT, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SORCFX1
+-1, // doomednum
+S_SORCFX1_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_SORCERER_BALLBOUNCE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SORCFX1_D1, // deathstate
+S_SORCFX1_D1, // xdeathstate
+SFX_NONE, // deathsound
+7*FRACUNIT, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE, // flags
+MF2_NOTELEPORT|MF2_FLOORBOUNCE // flags2
+ },
+
+{ // MT_SORCFX2
+-1, // doomednum
+S_SORCFX2_SPLIT1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SORCFX2T1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+15*FRACUNIT, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_SORCFX2_T1
+-1, // doomednum
+S_SORCFX2T1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_ALTSHADOW, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_SORCFX3
+-1, // doomednum
+S_SORCFX3_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_SORCERER_BISHOPSPAWN, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_BISHMORPH1, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+15*FRACUNIT, // speed
+22*FRACUNIT, // radius
+65*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_SORCFX3_EXPLOSION
+-1, // doomednum
+S_SORCFX3_EXP1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_ALTSHADOW, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_SORCFX4
+-1, // doomednum
+S_SORCFX4_1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_SORCFX4_D1, // deathstate
+S_NULL, // xdeathstate
+SFX_SORCERER_BALLEXPLODE, // deathsound
+12*FRACUNIT, // speed
+10*FRACUNIT, // radius
+10*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_SORCSPARK1
+-1, // doomednum
+S_SORCSPARK1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+5*FRACUNIT, // radius
+5*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF, // flags
+MF2_NOTELEPORT|MF2_LOGRAV // flags2
+ },
+
+{ // MT_BLASTEFFECT
+-1, // doomednum
+S_BLASTEFFECT1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_ALTSHADOW, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_WATER_DRIP
+-1, // doomednum
+S_WATERDRIP1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_DRIP, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+1, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_MISSILE, // flags
+MF2_LOGRAV|MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_KORAX
+10200, // doomednum
+S_KORAX_LOOK1, // spawnstate
+5000, // spawnhealth
+S_KORAX_CHASE2, // seestate
+SFX_KORAX_SIGHT, // seesound
+8, // reactiontime
+SFX_KORAX_ATTACK, // attacksound
+S_KORAX_PAIN1, // painstate
+20, // painchance
+SFX_KORAX_PAIN, // painsound
+S_NULL, // meleestate
+S_KORAX_ATTACK1, // missilestate
+S_NULL, // crashstate
+S_KORAX_DEATH1, // deathstate
+S_NULL, // xdeathstate
+SFX_KORAX_DEATH, // deathsound
+10, // speed
+65*FRACUNIT, // radius
+115*FRACUNIT, // height
+2000, // mass
+15, // damage
+SFX_KORAX_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, // flags
+MF2_FLOORCLIP|MF2_PUSHWALL|MF2_MCROSS|MF2_TELESTOMP|MF2_BOSS // flags2
+ },
+
+{ // MT_KORAX_SPIRIT1
+-1, // doomednum
+S_KSPIRIT_ROAM1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+8*FRACUNIT, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_KORAX_SPIRIT2
+-1, // doomednum
+S_KSPIRIT_ROAM1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+8*FRACUNIT, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_KORAX_SPIRIT3
+-1, // doomednum
+S_KSPIRIT_ROAM1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+8*FRACUNIT, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_KORAX_SPIRIT4
+-1, // doomednum
+S_KSPIRIT_ROAM1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+8*FRACUNIT, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_KORAX_SPIRIT5
+-1, // doomednum
+S_KSPIRIT_ROAM1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+8*FRACUNIT, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_KORAX_SPIRIT6
+-1, // doomednum
+S_KSPIRIT_ROAM1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+8*FRACUNIT, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_DROPOFF|MF_NOGRAVITY|MF_ALTSHADOW|MF_MISSILE|MF_NOCLIP, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_DEMON_MASH
+-1, // doomednum
+S_DEMN_LOOK1, // spawnstate
+250, // spawnhealth
+S_DEMN_CHASE1, // seestate
+SFX_DEMON_SIGHT, // seesound
+8, // reactiontime
+SFX_DEMON_ATTACK, // attacksound
+S_DEMN_PAIN1, // painstate
+50, // painchance
+SFX_DEMON_PAIN, // painsound
+S_DEMN_ATK1_1, // meleestate
+S_DEMN_ATK2_1, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_DEMON_DEATH, // deathsound
+13, // speed
+32*FRACUNIT, // radius
+64*FRACUNIT, // height
+220, // mass
+0, // damage
+SFX_DEMON_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALTSHADOW|MF_NOBLOOD, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_PUSHWALL|MF2_BLASTED // flags2
+ },
+
+{ // MT_DEMON2_MASH
+-1, // doomednum
+S_DEMN2_LOOK1, // spawnstate
+250, // spawnhealth
+S_DEMN2_CHASE1, // seestate
+SFX_DEMON_SIGHT, // seesound
+8, // reactiontime
+SFX_DEMON_ATTACK, // attacksound
+S_DEMN2_PAIN1, // painstate
+50, // painchance
+SFX_DEMON_PAIN, // painsound
+S_DEMN2_ATK1_1, // meleestate
+S_DEMN2_ATK2_1, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_DEMON_DEATH, // deathsound
+13, // speed
+32*FRACUNIT, // radius
+64*FRACUNIT, // height
+220, // mass
+0, // damage
+SFX_DEMON_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALTSHADOW|MF_NOBLOOD, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_PUSHWALL|MF2_BLASTED // flags2
+ },
+
+{ // MT_ETTIN_MASH
+-1, // doomednum
+S_ETTIN_LOOK1, // spawnstate
+175, // spawnhealth
+S_ETTIN_CHASE1, // seestate
+SFX_ETTIN_SIGHT, // seesound
+8, // reactiontime
+SFX_ETTIN_ATTACK, // attacksound
+S_ETTIN_PAIN1, // painstate
+60, // painchance
+SFX_ETTIN_PAIN, // painsound
+S_ETTIN_ATK1_1, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_ETTIN_DEATH, // deathsound
+13, // speed
+25*FRACUNIT, // radius
+68*FRACUNIT, // height
+175, // mass
+3, // damage
+SFX_ETTIN_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALTSHADOW|MF_NOBLOOD, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_PUSHWALL|MF2_BLASTED // flags2
+ },
+
+{ // MT_CENTAUR_MASH
+-1, // doomednum
+S_CENTAUR_LOOK1, // spawnstate
+200, // spawnhealth
+S_CENTAUR_WALK1, // seestate
+SFX_CENTAUR_SIGHT, // seesound
+8, // reactiontime
+SFX_CENTAUR_ATTACK, // attacksound
+S_CENTAUR_PAIN1, // painstate
+135, // painchance
+SFX_CENTAUR_PAIN, // painsound
+S_CENTAUR_ATK1, // meleestate
+0, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_CENTAUR_DEATH, // deathsound
+13, // speed
+20*FRACUNIT, // radius
+64*FRACUNIT, // height
+120, // mass
+0, // damage
+SFX_CENTAUR_ACTIVE, // activesound
+MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALTSHADOW|MF_NOBLOOD, // flags
+MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_PUSHWALL|MF2_BLASTED // flags2
+ },
+
+{ // MT_KORAX_BOLT
+-1, // doomednum
+S_KBOLT1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+15*FRACUNIT, // radius
+35*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE|MF_DROPOFF, // flags
+MF2_NOTELEPORT // flags2
+ },
+
+{ // MT_BAT_SPAWNER
+10225, // doomednum
+S_SPAWNBATS1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY, // flags
+MF2_DONTDRAW // flags2
+ },
+
+{ // MT_BAT
+-1, // doomednum
+S_BAT1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_BAT_DEATH, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+5*FRACUNIT, // speed
+3*FRACUNIT, // radius
+3*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE, // flags
+MF2_PASSMOBJ|MF2_NOTELEPORT // flags2
+ },
+
+#ifdef ASSASSIN
+{ // MT_AW_CROSSBOW
+10, // doomednum
+S_CSTAFF, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+0, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // misslestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL, // flags
+0 // flags2
+ },
+
+ /* jim We need a missile type for it as well! */
+{ // MT_ACROSS_MISSILE
+-1, // doomednum
+S_ACROSS_MISSILE1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+8, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_ACROSS_MISSILE_X1, // deathstate
+S_NULL, // xdeathstate
+SFX_CLERIC_CSTAFF_EXPLODE, // deathsound
+110*FRACUNIT, // speed /* jim speed up the crossbow missles */
+12*FRACUNIT, // radius
+10*FRACUNIT, // height
+100, // mass
+5, // damage
+SFX_NONE, // activesound
+MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY, // flags
+MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS // flags2
+ },
+
+{ // MT_AW_GRENADES
+8040, // doomednum
+S_MW_LIGHTNING1, // spawnstate
+1000, // spawnhealth
+S_NULL, // seestate
+SFX_NONE, // seesound
+0, // reactiontime
+SFX_NONE, // attacksound
+S_NULL, // painstate
+0, // painchance
+SFX_NONE, // painsound
+S_NULL, // meleestate
+S_NULL, // missilestate
+S_NULL, // crashstate
+S_NULL, // deathstate
+S_NULL, // xdeathstate
+SFX_NONE, // deathsound
+0, // speed
+20*FRACUNIT, // radius
+16*FRACUNIT, // height
+100, // mass
+0, // damage
+SFX_NONE, // activesound
+MF_SPECIAL|MF_NOGRAVITY, // flags
+0 // flags2
+}
+#endif /* ASSASSIN */
+};
+
--- /dev/null
+++ b/info.h
@@ -1,0 +1,3813 @@
+
+//**************************************************************************
+//**
+//** info.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __INFO_H
+#define __INFO_H
+
+// generated by stateco
+
+typedef enum {
+SPR_MAN1,
+SPR_ACLO,
+SPR_TLGL,
+SPR_FBL1,
+SPR_XPL1,
+SPR_ARRW,
+SPR_DART,
+SPR_RIPP,
+SPR_CFCF,
+SPR_BLAD,
+SPR_SHRD,
+SPR_FFSM,
+SPR_FFLG,
+SPR_PTN1,
+SPR_PTN2,
+SPR_SOAR,
+SPR_INVU,
+SPR_SUMN,
+SPR_TSPK,
+SPR_TELO,
+SPR_TRNG,
+SPR_ROCK,
+SPR_FOGS,
+SPR_FOGM,
+SPR_FOGL,
+SPR_SGSA,
+SPR_SGSB,
+SPR_PORK,
+SPR_EGGM,
+SPR_FHFX,
+SPR_SPHL,
+SPR_STWN,
+SPR_GMPD,
+SPR_ASKU,
+SPR_ABGM,
+SPR_AGMR,
+SPR_AGMG,
+SPR_AGG2,
+SPR_AGMB,
+SPR_AGB2,
+SPR_ABK1,
+SPR_ABK2,
+SPR_ASK2,
+SPR_AFWP,
+SPR_ACWP,
+SPR_AMWP,
+SPR_AGER,
+SPR_AGR2,
+SPR_AGR3,
+SPR_AGR4,
+SPR_TRCH,
+SPR_PSBG,
+SPR_ATLP,
+SPR_THRW,
+SPR_SPED,
+SPR_BMAN,
+SPR_BRAC,
+SPR_BLST,
+SPR_HRAD,
+SPR_SPSH,
+SPR_LVAS,
+SPR_SLDG,
+SPR_STTW,
+SPR_RCK1,
+SPR_RCK2,
+SPR_RCK3,
+SPR_RCK4,
+SPR_CDLR,
+SPR_TRE1,
+SPR_TRDT,
+SPR_TRE2,
+SPR_TRE3,
+SPR_STM1,
+SPR_STM2,
+SPR_STM3,
+SPR_STM4,
+SPR_MSH1,
+SPR_MSH2,
+SPR_MSH3,
+SPR_MSH4,
+SPR_MSH5,
+SPR_MSH6,
+SPR_MSH7,
+SPR_MSH8,
+SPR_SGMP,
+SPR_SGM1,
+SPR_SGM2,
+SPR_SGM3,
+SPR_SLC1,
+SPR_SLC2,
+SPR_SLC3,
+SPR_MSS1,
+SPR_MSS2,
+SPR_SWMV,
+SPR_CPS1,
+SPR_CPS2,
+SPR_TMS1,
+SPR_TMS2,
+SPR_TMS3,
+SPR_TMS4,
+SPR_TMS5,
+SPR_TMS6,
+SPR_TMS7,
+SPR_CPS3,
+SPR_STT2,
+SPR_STT3,
+SPR_STT4,
+SPR_STT5,
+SPR_GAR1,
+SPR_GAR2,
+SPR_GAR3,
+SPR_GAR4,
+SPR_GAR5,
+SPR_GAR6,
+SPR_GAR7,
+SPR_GAR8,
+SPR_GAR9,
+SPR_BNR1,
+SPR_TRE4,
+SPR_TRE5,
+SPR_TRE6,
+SPR_TRE7,
+SPR_LOGG,
+SPR_ICT1,
+SPR_ICT2,
+SPR_ICT3,
+SPR_ICT4,
+SPR_ICM1,
+SPR_ICM2,
+SPR_ICM3,
+SPR_ICM4,
+SPR_RKBL,
+SPR_RKBS,
+SPR_RKBK,
+SPR_RBL1,
+SPR_RBL2,
+SPR_RBL3,
+SPR_VASE,
+SPR_POT1,
+SPR_POT2,
+SPR_POT3,
+SPR_PBIT,
+SPR_CPS4,
+SPR_CPS5,
+SPR_CPS6,
+SPR_CPB1,
+SPR_CPB2,
+SPR_CPB3,
+SPR_CPB4,
+SPR_BDRP,
+SPR_BDSH,
+SPR_BDPL,
+SPR_CNDL,
+SPR_LEF1,
+SPR_LEF3,
+SPR_LEF2,
+SPR_TWTR,
+SPR_WLTR,
+SPR_BARL,
+SPR_SHB1,
+SPR_SHB2,
+SPR_BCKT,
+SPR_SHRM,
+SPR_FBUL,
+SPR_FSKL,
+SPR_BRTR,
+SPR_SUIT,
+SPR_BBLL,
+SPR_CAND,
+SPR_IRON,
+SPR_XMAS,
+SPR_CDRN,
+SPR_CHNS,
+SPR_TST1,
+SPR_TST2,
+SPR_TST3,
+SPR_TST4,
+SPR_TST5,
+SPR_TST6,
+SPR_TST7,
+SPR_TST8,
+SPR_TST9,
+SPR_TST0,
+SPR_TELE,
+SPR_TSMK,
+SPR_FPCH,
+SPR_WFAX,
+SPR_FAXE,
+SPR_WFHM,
+SPR_FHMR,
+SPR_FSRD,
+SPR_FSFX,
+SPR_CMCE,
+SPR_WCSS,
+SPR_CSSF,
+SPR_WCFM,
+SPR_CFLM,
+SPR_CFFX,
+SPR_CHLY,
+SPR_SPIR,
+SPR_MWND,
+SPR_WMLG,
+SPR_MLNG,
+SPR_MLFX,
+SPR_MLF2,
+SPR_MSTF,
+SPR_MSP1,
+SPR_MSP2,
+SPR_WFR1,
+SPR_WFR2,
+SPR_WFR3,
+SPR_WCH1,
+SPR_WCH2,
+SPR_WCH3,
+SPR_WMS1,
+SPR_WMS2,
+SPR_WMS3,
+SPR_WPIG,
+SPR_WMCS,
+SPR_CONE,
+SPR_SHEX,
+SPR_BLOD,
+SPR_GIBS,
+SPR_PLAY,
+SPR_FDTH,
+SPR_BSKL,
+SPR_ICEC,
+SPR_CLER,
+SPR_MAGE,
+SPR_PIGY,
+SPR_CENT,
+SPR_CTXD,
+SPR_CTFX,
+SPR_CTDP,
+SPR_DEMN,
+SPR_DEMA,
+SPR_DEMB,
+SPR_DEMC,
+SPR_DEMD,
+SPR_DEME,
+SPR_DMFX,
+SPR_DEM2,
+SPR_DMBA,
+SPR_DMBB,
+SPR_DMBC,
+SPR_DMBD,
+SPR_DMBE,
+SPR_D2FX,
+SPR_WRTH,
+SPR_WRT2,
+SPR_WRBL,
+SPR_MNTR,
+SPR_FX12,
+SPR_FX13,
+SPR_MNSM,
+SPR_SSPT,
+SPR_SSDV,
+SPR_SSXD,
+SPR_SSFX,
+SPR_BISH,
+SPR_BPFX,
+SPR_DRAG,
+SPR_DRFX,
+SPR_ARM1,
+SPR_ARM2,
+SPR_ARM3,
+SPR_ARM4,
+SPR_MAN2,
+SPR_MAN3,
+SPR_KEY1,
+SPR_KEY2,
+SPR_KEY3,
+SPR_KEY4,
+SPR_KEY5,
+SPR_KEY6,
+SPR_KEY7,
+SPR_KEY8,
+SPR_KEY9,
+SPR_KEYA,
+SPR_KEYB,
+SPR_ETTN,
+SPR_ETTB,
+SPR_FDMN,
+SPR_FDMB,
+SPR_ICEY,
+SPR_ICPR,
+SPR_ICWS,
+SPR_SORC,
+SPR_SBMP,
+SPR_SBS4,
+SPR_SBMB,
+SPR_SBS3,
+SPR_SBMG,
+SPR_SBS1,
+SPR_SBS2,
+SPR_SBFX,
+SPR_RADE,
+SPR_WATR,
+SPR_KORX,
+SPR_ABAT,
+#ifdef ASSASSIN
+SPR_AKTR,
+SPR_ACSB,
+SPR_AGRN,
+SPR_ASTF,
+SPR_ASP1,
+SPR_ASP2,
+SPR_ASSN,
+#endif
+SPR_NULL, /* for the terminator in sprnames[] */
+NUMSPRITES
+} spritenum_t;
+
+typedef enum {
+S_NULL,
+S_FREETARGMOBJ,
+S_MAPSPOT,
+S_FIREBALL1_1,
+S_FIREBALL1_2,
+S_FIREBALL1_X1,
+S_FIREBALL1_X2,
+S_FIREBALL1_X3,
+S_FIREBALL1_X4,
+S_FIREBALL1_X5,
+S_FIREBALL1_X6,
+S_ARROW_1,
+S_ARROW_X1,
+S_DART_1,
+S_DART_X1,
+S_POISONDART_1,
+S_POISONDART_X1,
+S_RIPPERBALL_1,
+S_RIPPERBALL_2,
+S_RIPPERBALL_3,
+S_RIPPERBALL_X1,
+S_RIPPERBALL_X2,
+S_RIPPERBALL_X3,
+S_RIPPERBALL_X4,
+S_RIPPERBALL_X5,
+S_RIPPERBALL_X6,
+S_RIPPERBALL_X7,
+S_RIPPERBALL_X8,
+S_RIPPERBALL_X9,
+S_RIPPERBALL_X10,
+S_PRJ_BLADE1,
+S_PRJ_BLADE_X1,
+S_ICESHARD1,
+S_ICESHARD2,
+S_ICESHARD3,
+S_FLAME_TSMALL1,
+S_FLAME_TSMALL2,
+S_FLAME_TSMALL3,
+S_FLAME_TSMALL4,
+S_FLAME_TSMALL5,
+S_FLAME_TSMALL6,
+S_FLAME_TLARGE1,
+S_FLAME_TLARGE2,
+S_FLAME_TLARGE3,
+S_FLAME_TLARGE4,
+S_FLAME_TLARGE5,
+S_FLAME_TLARGE6,
+S_FLAME_TLARGE7,
+S_FLAME_TLARGE8,
+S_FLAME_TLARGE9,
+S_FLAME_TLARGE10,
+S_FLAME_TLARGE11,
+S_FLAME_TLARGE12,
+S_FLAME_TLARGE13,
+S_FLAME_TLARGE14,
+S_FLAME_TLARGE15,
+S_FLAME_TLARGE16,
+S_FLAME_SDORM1,
+S_FLAME_SDORM2,
+S_FLAME_SDORM3,
+S_FLAME_SMALL1,
+S_FLAME_SMALL2,
+S_FLAME_SMALL3,
+S_FLAME_SMALL4,
+S_FLAME_SMALL5,
+S_FLAME_SMALL6,
+S_FLAME_SMALL7,
+S_FLAME_LDORM1,
+S_FLAME_LDORM2,
+S_FLAME_LDORM3,
+S_FLAME_LDORM4,
+S_FLAME_LDORM5,
+S_FLAME_LARGE1,
+S_FLAME_LARGE2,
+S_FLAME_LARGE3,
+S_FLAME_LARGE4,
+S_FLAME_LARGE5,
+S_FLAME_LARGE6,
+S_FLAME_LARGE7,
+S_FLAME_LARGE8,
+S_FLAME_LARGE9,
+S_FLAME_LARGE10,
+S_FLAME_LARGE11,
+S_FLAME_LARGE12,
+S_FLAME_LARGE13,
+S_FLAME_LARGE14,
+S_FLAME_LARGE15,
+S_FLAME_LARGE16,
+S_FLAME_LARGE17,
+S_FLAME_LARGE18,
+S_ITEM_PTN1_1,
+S_ITEM_PTN1_2,
+S_ITEM_PTN1_3,
+S_HIDESPECIAL1,
+S_HIDESPECIAL2,
+S_HIDESPECIAL3,
+S_HIDESPECIAL4,
+S_HIDESPECIAL5,
+S_HIDESPECIAL6,
+S_HIDESPECIAL7,
+S_HIDESPECIAL8,
+S_HIDESPECIAL9,
+S_HIDESPECIAL10,
+S_HIDESPECIAL11,
+S_DORMANTARTI1_1,
+S_DORMANTARTI1_2,
+S_DORMANTARTI1_3,
+S_DORMANTARTI1_4,
+S_DORMANTARTI1_5,
+S_DORMANTARTI1_6,
+S_DORMANTARTI1_7,
+S_DORMANTARTI1_8,
+S_DORMANTARTI1_9,
+S_DORMANTARTI1_10,
+S_DORMANTARTI1_11,
+S_DORMANTARTI1_12,
+S_DORMANTARTI1_13,
+S_DORMANTARTI1_14,
+S_DORMANTARTI1_15,
+S_DORMANTARTI1_16,
+S_DORMANTARTI1_17,
+S_DORMANTARTI1_18,
+S_DORMANTARTI1_19,
+S_DORMANTARTI1_20,
+S_DORMANTARTI1_21,
+S_DORMANTARTI2_1,
+S_DORMANTARTI2_2,
+S_DORMANTARTI2_3,
+S_DORMANTARTI2_4,
+S_DORMANTARTI2_5,
+S_DORMANTARTI2_6,
+S_DORMANTARTI2_7,
+S_DORMANTARTI2_8,
+S_DORMANTARTI2_9,
+S_DORMANTARTI2_10,
+S_DORMANTARTI2_11,
+S_DORMANTARTI2_12,
+S_DORMANTARTI2_13,
+S_DORMANTARTI2_14,
+S_DORMANTARTI2_15,
+S_DORMANTARTI2_16,
+S_DORMANTARTI2_17,
+S_DORMANTARTI2_18,
+S_DORMANTARTI2_19,
+S_DORMANTARTI2_20,
+S_DORMANTARTI2_21,
+S_DORMANTARTI3_1,
+S_DORMANTARTI3_2,
+S_DORMANTARTI3_3,
+S_DORMANTARTI3_4,
+S_DORMANTARTI3_5,
+S_DORMANTARTI3_6,
+S_DORMANTARTI3_7,
+S_DORMANTARTI3_8,
+S_DORMANTARTI3_9,
+S_DORMANTARTI3_10,
+S_DORMANTARTI3_11,
+S_DORMANTARTI3_12,
+S_DORMANTARTI3_13,
+S_DORMANTARTI3_14,
+S_DORMANTARTI3_15,
+S_DORMANTARTI3_16,
+S_DORMANTARTI3_17,
+S_DORMANTARTI3_18,
+S_DORMANTARTI3_19,
+S_DORMANTARTI3_20,
+S_DORMANTARTI3_21,
+S_DEADARTI1,
+S_DEADARTI2,
+S_DEADARTI3,
+S_DEADARTI4,
+S_DEADARTI5,
+S_DEADARTI6,
+S_DEADARTI7,
+S_DEADARTI8,
+S_DEADARTI9,
+S_DEADARTI10,
+S_ARTI_PTN2_1,
+S_ARTI_PTN2_2,
+S_ARTI_PTN2_3,
+S_ARTI_SOAR1,
+S_ARTI_SOAR2,
+S_ARTI_SOAR3,
+S_ARTI_SOAR4,
+S_ARTI_INVU1,
+S_ARTI_INVU2,
+S_ARTI_INVU3,
+S_ARTI_INVU4,
+S_ARTI_SUMMON,
+S_SUMMON_FX1_1,
+S_SUMMON_FX2_1,
+S_SUMMON_FX2_2,
+S_SUMMON_FX2_3,
+S_THRUSTINIT2_1,
+S_THRUSTINIT2_2,
+S_BTHRUSTINIT2_1,
+S_BTHRUSTINIT2_2,
+S_THRUSTINIT1_1,
+S_THRUSTINIT1_2,
+S_BTHRUSTINIT1_1,
+S_BTHRUSTINIT1_2,
+S_THRUSTRAISE1,
+S_THRUSTRAISE2,
+S_THRUSTRAISE3,
+S_THRUSTRAISE4,
+S_BTHRUSTRAISE1,
+S_BTHRUSTRAISE2,
+S_BTHRUSTRAISE3,
+S_BTHRUSTRAISE4,
+S_THRUSTIMPALE,
+S_BTHRUSTIMPALE,
+S_THRUSTRAISE,
+S_BTHRUSTRAISE,
+S_THRUSTBLOCK,
+S_BTHRUSTBLOCK,
+S_THRUSTLOWER,
+S_BTHRUSTLOWER,
+S_THRUSTSTAY,
+S_BTHRUSTSTAY,
+S_ARTI_TELOTHER1,
+S_ARTI_TELOTHER2,
+S_ARTI_TELOTHER3,
+S_ARTI_TELOTHER4,
+S_TELO_FX1,
+S_TELO_FX2,
+S_TELO_FX3,
+S_TELO_FX4,
+S_TELO_FX5,
+S_TELO_FX6,
+S_TELO_FX7,
+S_TELO_FX8,
+S_TELO_FX9,
+S_TELO_FX2_1,
+S_TELO_FX2_2,
+S_TELO_FX2_3,
+S_TELO_FX2_4,
+S_TELO_FX2_5,
+S_TELO_FX2_6,
+S_TELO_FX3_1,
+S_TELO_FX3_2,
+S_TELO_FX3_3,
+S_TELO_FX3_4,
+S_TELO_FX3_5,
+S_TELO_FX3_6,
+S_TELO_FX4_1,
+S_TELO_FX4_2,
+S_TELO_FX4_3,
+S_TELO_FX4_4,
+S_TELO_FX4_5,
+S_TELO_FX4_6,
+S_TELO_FX5_1,
+S_TELO_FX5_2,
+S_TELO_FX5_3,
+S_TELO_FX5_4,
+S_TELO_FX5_5,
+S_TELO_FX5_6,
+S_DIRT1_1,
+S_DIRT1_D,
+S_DIRT2_1,
+S_DIRT2_D,
+S_DIRT3_1,
+S_DIRT3_D,
+S_DIRT4_1,
+S_DIRT4_D,
+S_DIRT5_1,
+S_DIRT5_D,
+S_DIRT6_1,
+S_DIRT6_D,
+S_DIRTCLUMP1,
+S_ROCK1_1,
+S_ROCK1_D,
+S_ROCK2_1,
+S_ROCK2_D,
+S_ROCK3_1,
+S_ROCK3_D,
+S_SPAWNFOG1,
+S_FOGPATCHS1,
+S_FOGPATCHS2,
+S_FOGPATCHS3,
+S_FOGPATCHS4,
+S_FOGPATCHS5,
+S_FOGPATCHS0,
+S_FOGPATCHM1,
+S_FOGPATCHM2,
+S_FOGPATCHM3,
+S_FOGPATCHM4,
+S_FOGPATCHM5,
+S_FOGPATCHM0,
+S_FOGPATCHMA,
+S_FOGPATCHMB,
+S_FOGPATCHMC,
+S_FOGPATCHMD,
+S_FOGPATCHL1,
+S_FOGPATCHL2,
+S_FOGPATCHL3,
+S_FOGPATCHL4,
+S_FOGPATCHL5,
+S_FOGPATCHL0,
+S_FOGPATCHLA,
+S_FOGPATCHLB,
+S_FOGPATCHLC,
+S_FOGPATCHLD,
+S_QUAKE_ACTIVE1,
+S_QUAKE_ACTIVE2,
+S_QUAKE_ACTIVE3,
+S_QUAKE_ACTIVE4,
+S_QUAKE_ACTIVE5,
+S_QUAKE_ACTIVE6,
+S_QUAKE_ACTIVE7,
+S_QUAKE_ACTIVE8,
+S_QUAKE_ACTIVE9,
+S_QUAKE_ACTIVE0,
+S_QUAKE_ACTIVEA,
+S_QUAKE_ACTIVEB,
+S_QUAKE_ACTIVEC,
+S_QUAKE_ACTIVED,
+S_QUAKE_ACTIVEE,
+S_QUAKE_ACTIVEF,
+S_QUAKE_ACTIVEG,
+S_QUAKE_ACTIVEH,
+S_QUAKE_ACTIVEI,
+S_QUAKE_ACTIVEJ,
+S_QUAKE_ACTIVEK,
+S_QUAKE_ACTIVEL,
+S_QUAKE_ACTIVEM,
+S_QUAKE_ACTIVEN,
+S_QUAKE_ACTIVEO,
+S_QUAKE_ACTIVEP,
+S_QUAKE_ACTIVEQ,
+S_QUAKE_ACTIVER,
+S_QUAKE_ACTIVES,
+S_QUAKE_ACTIVET,
+S_QUAKE_ACTIVEU,
+S_QUAKE_ACTIVEV,
+S_QUAKE_ACTIVEW,
+S_QUAKE_ACTIVEX,
+S_QUAKE_ACTIVEY,
+S_QUAKE_ACTIVEZ,
+S_QUAKE_ACT1,
+S_QUAKE_ACT2,
+S_QUAKE_ACT3,
+S_QUAKE_ACT4,
+S_QUAKE_ACT5,
+S_QUAKE_ACT6,
+S_QUAKE_ACT7,
+S_QUAKE_ACT8,
+S_QUAKE_ACT9,
+S_QUAKE_ACT0,
+S_SGSHARD1_1,
+S_SGSHARD1_2,
+S_SGSHARD1_3,
+S_SGSHARD1_4,
+S_SGSHARD1_5,
+S_SGSHARD1_D,
+S_SGSHARD2_1,
+S_SGSHARD2_2,
+S_SGSHARD2_3,
+S_SGSHARD2_4,
+S_SGSHARD2_5,
+S_SGSHARD2_D,
+S_SGSHARD3_1,
+S_SGSHARD3_2,
+S_SGSHARD3_3,
+S_SGSHARD3_4,
+S_SGSHARD3_5,
+S_SGSHARD3_D,
+S_SGSHARD4_1,
+S_SGSHARD4_2,
+S_SGSHARD4_3,
+S_SGSHARD4_4,
+S_SGSHARD4_5,
+S_SGSHARD4_D,
+S_SGSHARD5_1,
+S_SGSHARD5_2,
+S_SGSHARD5_3,
+S_SGSHARD5_4,
+S_SGSHARD5_5,
+S_SGSHARD5_D,
+S_SGSHARD6_1,
+S_SGSHARD6_D,
+S_SGSHARD7_1,
+S_SGSHARD7_D,
+S_SGSHARD8_1,
+S_SGSHARD8_D,
+S_SGSHARD9_1,
+S_SGSHARD9_D,
+S_SGSHARD0_1,
+S_SGSHARD0_D,
+S_ARTI_EGGC1,
+S_ARTI_EGGC2,
+S_ARTI_EGGC3,
+S_ARTI_EGGC4,
+S_ARTI_EGGC5,
+S_ARTI_EGGC6,
+S_ARTI_EGGC7,
+S_ARTI_EGGC8,
+S_EGGFX1,
+S_EGGFX2,
+S_EGGFX3,
+S_EGGFX4,
+S_EGGFX5,
+S_EGGFXI1_1,
+S_EGGFXI1_2,
+S_EGGFXI1_3,
+S_EGGFXI1_4,
+S_ARTI_SPHL1,
+S_ZWINGEDSTATUENOSKULL,
+S_ZWINGEDSTATUENOSKULL2,
+S_ZGEMPEDESTAL1,
+S_ZGEMPEDESTAL2,
+S_ARTIPUZZSKULL,
+S_ARTIPUZZGEMBIG,
+S_ARTIPUZZGEMRED,
+S_ARTIPUZZGEMGREEN1,
+S_ARTIPUZZGEMGREEN2,
+S_ARTIPUZZGEMBLUE1,
+S_ARTIPUZZGEMBLUE2,
+S_ARTIPUZZBOOK1,
+S_ARTIPUZZBOOK2,
+S_ARTIPUZZSKULL2,
+S_ARTIPUZZFWEAPON,
+S_ARTIPUZZCWEAPON,
+S_ARTIPUZZMWEAPON,
+S_ARTIPUZZGEAR_1,
+S_ARTIPUZZGEAR_2,
+S_ARTIPUZZGEAR_3,
+S_ARTIPUZZGEAR_4,
+S_ARTIPUZZGEAR_5,
+S_ARTIPUZZGEAR_6,
+S_ARTIPUZZGEAR_7,
+S_ARTIPUZZGEAR_8,
+S_ARTIPUZZGEAR2_1,
+S_ARTIPUZZGEAR2_2,
+S_ARTIPUZZGEAR2_3,
+S_ARTIPUZZGEAR2_4,
+S_ARTIPUZZGEAR2_5,
+S_ARTIPUZZGEAR2_6,
+S_ARTIPUZZGEAR2_7,
+S_ARTIPUZZGEAR2_8,
+S_ARTIPUZZGEAR3_1,
+S_ARTIPUZZGEAR3_2,
+S_ARTIPUZZGEAR3_3,
+S_ARTIPUZZGEAR3_4,
+S_ARTIPUZZGEAR3_5,
+S_ARTIPUZZGEAR3_6,
+S_ARTIPUZZGEAR3_7,
+S_ARTIPUZZGEAR3_8,
+S_ARTIPUZZGEAR4_1,
+S_ARTIPUZZGEAR4_2,
+S_ARTIPUZZGEAR4_3,
+S_ARTIPUZZGEAR4_4,
+S_ARTIPUZZGEAR4_5,
+S_ARTIPUZZGEAR4_6,
+S_ARTIPUZZGEAR4_7,
+S_ARTIPUZZGEAR4_8,
+S_ARTI_TRCH1,
+S_ARTI_TRCH2,
+S_ARTI_TRCH3,
+S_FIREBOMB1,
+S_FIREBOMB2,
+S_FIREBOMB3,
+S_FIREBOMB4,
+S_FIREBOMB5,
+S_FIREBOMB6,
+S_FIREBOMB7,
+S_FIREBOMB8,
+S_FIREBOMB9,
+S_FIREBOMB10,
+S_FIREBOMB11,
+S_ARTI_ATLP1,
+S_ARTI_ATLP2,
+S_ARTI_ATLP3,
+S_ARTI_ATLP4,
+S_ARTI_PSBG1,
+S_POISONBAG1,
+S_POISONBAG2,
+S_POISONBAG3,
+S_POISONBAG4,
+S_POISONCLOUD1,
+S_POISONCLOUD2,
+S_POISONCLOUD3,
+S_POISONCLOUD4,
+S_POISONCLOUD5,
+S_POISONCLOUD6,
+S_POISONCLOUD7,
+S_POISONCLOUD8,
+S_POISONCLOUD9,
+S_POISONCLOUD10,
+S_POISONCLOUD11,
+S_POISONCLOUD12,
+S_POISONCLOUD13,
+S_POISONCLOUD14,
+S_POISONCLOUD15,
+S_POISONCLOUD16,
+S_POISONCLOUD17,
+S_POISONCLOUD18,
+S_POISONCLOUD_X1,
+S_POISONCLOUD_X2,
+S_POISONCLOUD_X3,
+S_POISONCLOUD_X4,
+S_THROWINGBOMB1,
+S_THROWINGBOMB2,
+S_THROWINGBOMB3,
+S_THROWINGBOMB4,
+S_THROWINGBOMB5,
+S_THROWINGBOMB6,
+S_THROWINGBOMB7,
+S_THROWINGBOMB8,
+S_THROWINGBOMB9,
+S_THROWINGBOMB10,
+S_THROWINGBOMB11,
+S_THROWINGBOMB12,
+S_THROWINGBOMB_X1,
+S_THROWINGBOMB_X2,
+S_THROWINGBOMB_X3,
+S_THROWINGBOMB_X4,
+S_THROWINGBOMB_X5,
+S_THROWINGBOMB_X6,
+S_THROWINGBOMB_X7,
+S_THROWINGBOMB_X8,
+S_ARTI_BOOTS1,
+S_ARTI_BOOTS2,
+S_ARTI_BOOTS3,
+S_ARTI_BOOTS4,
+S_ARTI_BOOTS5,
+S_ARTI_BOOTS6,
+S_ARTI_BOOTS7,
+S_ARTI_BOOTS8,
+S_ARTI_MANA,
+S_ARTI_ARMOR1,
+S_ARTI_ARMOR2,
+S_ARTI_ARMOR3,
+S_ARTI_ARMOR4,
+S_ARTI_ARMOR5,
+S_ARTI_ARMOR6,
+S_ARTI_ARMOR7,
+S_ARTI_ARMOR8,
+S_ARTI_BLAST1,
+S_ARTI_BLAST2,
+S_ARTI_BLAST3,
+S_ARTI_BLAST4,
+S_ARTI_BLAST5,
+S_ARTI_BLAST6,
+S_ARTI_BLAST7,
+S_ARTI_BLAST8,
+S_ARTI_HEALRAD1,
+S_ARTI_HEALRAD2,
+S_ARTI_HEALRAD3,
+S_ARTI_HEALRAD4,
+S_ARTI_HEALRAD5,
+S_ARTI_HEALRAD6,
+S_ARTI_HEALRAD7,
+S_ARTI_HEALRAD8,
+S_ARTI_HEALRAD9,
+S_ARTI_HEALRAD0,
+S_ARTI_HEALRADA,
+S_ARTI_HEALRADB,
+S_ARTI_HEALRADC,
+S_ARTI_HEALRADD,
+S_ARTI_HEALRADE,
+S_ARTI_HEALRADF,
+S_SPLASH1,
+S_SPLASH2,
+S_SPLASH3,
+S_SPLASH4,
+S_SPLASHX,
+S_SPLASHBASE1,
+S_SPLASHBASE2,
+S_SPLASHBASE3,
+S_SPLASHBASE4,
+S_SPLASHBASE5,
+S_SPLASHBASE6,
+S_SPLASHBASE7,
+S_LAVASPLASH1,
+S_LAVASPLASH2,
+S_LAVASPLASH3,
+S_LAVASPLASH4,
+S_LAVASPLASH5,
+S_LAVASPLASH6,
+S_LAVASMOKE1,
+S_LAVASMOKE2,
+S_LAVASMOKE3,
+S_LAVASMOKE4,
+S_LAVASMOKE5,
+S_SLUDGECHUNK1,
+S_SLUDGECHUNK2,
+S_SLUDGECHUNK3,
+S_SLUDGECHUNK4,
+S_SLUDGECHUNKX,
+S_SLUDGESPLASH1,
+S_SLUDGESPLASH2,
+S_SLUDGESPLASH3,
+S_SLUDGESPLASH4,
+S_ZWINGEDSTATUE1,
+S_ZROCK1_1,
+S_ZROCK2_1,
+S_ZROCK3_1,
+S_ZROCK4_1,
+S_ZCHANDELIER1,
+S_ZCHANDELIER2,
+S_ZCHANDELIER3,
+S_ZCHANDELIER_U,
+S_ZTREEDEAD1,
+S_ZTREE,
+S_ZTREEDESTRUCTIBLE1,
+S_ZTREEDES_D1,
+S_ZTREEDES_D2,
+S_ZTREEDES_D3,
+S_ZTREEDES_D4,
+S_ZTREEDES_D5,
+S_ZTREEDES_D6,
+S_ZTREEDES_X1,
+S_ZTREEDES_X2,
+S_ZTREEDES_X3,
+S_ZTREEDES_X4,
+S_ZTREEDES_X5,
+S_ZTREEDES_X6,
+S_ZTREEDES_X7,
+S_ZTREEDES_X8,
+S_ZTREEDES_X9,
+S_ZTREEDES_X10,
+S_ZTREESWAMP182_1,
+S_ZTREESWAMP172_1,
+S_ZSTUMPBURNED1,
+S_ZSTUMPBARE1,
+S_ZSTUMPSWAMP1_1,
+S_ZSTUMPSWAMP2_1,
+S_ZSHROOMLARGE1_1,
+S_ZSHROOMLARGE2_1,
+S_ZSHROOMLARGE3_1,
+S_ZSHROOMSMALL1_1,
+S_ZSHROOMSMALL2_1,
+S_ZSHROOMSMALL3_1,
+S_ZSHROOMSMALL4_1,
+S_ZSHROOMSMALL5_1,
+S_ZSTALAGMITEPILLAR1,
+S_ZSTALAGMITELARGE1,
+S_ZSTALAGMITEMEDIUM1,
+S_ZSTALAGMITESMALL1,
+S_ZSTALACTITELARGE1,
+S_ZSTALACTITEMEDIUM1,
+S_ZSTALACTITESMALL1,
+S_ZMOSSCEILING1_1,
+S_ZMOSSCEILING2_1,
+S_ZSWAMPVINE1,
+S_ZCORPSEKABOB1,
+S_ZCORPSESLEEPING1,
+S_ZTOMBSTONERIP1,
+S_ZTOMBSTONESHANE1,
+S_ZTOMBSTONEBIGCROSS1,
+S_ZTOMBSTONEBRIANR1,
+S_ZTOMBSTONECROSSCIRCLE1,
+S_ZTOMBSTONESMALLCROSS1,
+S_ZTOMBSTONEBRIANP1,
+S_CORPSEHANGING_1,
+S_ZSTATUEGARGOYLEGREENTALL_1,
+S_ZSTATUEGARGOYLEBLUETALL_1,
+S_ZSTATUEGARGOYLEGREENSHORT_1,
+S_ZSTATUEGARGOYLEBLUESHORT_1,
+S_ZSTATUEGARGOYLESTRIPETALL_1,
+S_ZSTATUEGARGOYLEDARKREDTALL_1,
+S_ZSTATUEGARGOYLEREDTALL_1,
+S_ZSTATUEGARGOYLETANTALL_1,
+S_ZSTATUEGARGOYLERUSTTALL_1,
+S_ZSTATUEGARGOYLEDARKREDSHORT_1,
+S_ZSTATUEGARGOYLEREDSHORT_1,
+S_ZSTATUEGARGOYLETANSHORT_1,
+S_ZSTATUEGARGOYLERUSTSHORT_1,
+S_ZBANNERTATTERED_1,
+S_ZTREELARGE1,
+S_ZTREELARGE2,
+S_ZTREEGNARLED1,
+S_ZTREEGNARLED2,
+S_ZLOG,
+S_ZSTALACTITEICELARGE,
+S_ZSTALACTITEICEMEDIUM,
+S_ZSTALACTITEICESMALL,
+S_ZSTALACTITEICETINY,
+S_ZSTALAGMITEICELARGE,
+S_ZSTALAGMITEICEMEDIUM,
+S_ZSTALAGMITEICESMALL,
+S_ZSTALAGMITEICETINY,
+S_ZROCKBROWN1,
+S_ZROCKBROWN2,
+S_ZROCKBLACK,
+S_ZRUBBLE1,
+S_ZRUBBLE2,
+S_ZRUBBLE3,
+S_ZVASEPILLAR,
+S_ZPOTTERY1,
+S_ZPOTTERY2,
+S_ZPOTTERY3,
+S_ZPOTTERY_EXPLODE,
+S_POTTERYBIT_1,
+S_POTTERYBIT_2,
+S_POTTERYBIT_3,
+S_POTTERYBIT_4,
+S_POTTERYBIT_5,
+S_POTTERYBIT_EX0,
+S_POTTERYBIT_EX1,
+S_POTTERYBIT_EX1_2,
+S_POTTERYBIT_EX2,
+S_POTTERYBIT_EX2_2,
+S_POTTERYBIT_EX3,
+S_POTTERYBIT_EX3_2,
+S_POTTERYBIT_EX4,
+S_POTTERYBIT_EX4_2,
+S_POTTERYBIT_EX5,
+S_POTTERYBIT_EX5_2,
+S_ZCORPSELYNCHED1,
+S_ZCORPSELYNCHED2,
+S_ZCORPSESITTING,
+S_ZCORPSESITTING_X,
+S_CORPSEBIT_1,
+S_CORPSEBIT_2,
+S_CORPSEBIT_3,
+S_CORPSEBIT_4,
+S_CORPSEBLOODDRIP,
+S_CORPSEBLOODDRIP_X1,
+S_CORPSEBLOODDRIP_X2,
+S_CORPSEBLOODDRIP_X3,
+S_CORPSEBLOODDRIP_X4,
+S_BLOODPOOL,
+S_ZCANDLE1,
+S_ZCANDLE2,
+S_ZCANDLE3,
+S_ZLEAFSPAWNER,
+S_LEAF1_1,
+S_LEAF1_2,
+S_LEAF1_3,
+S_LEAF1_4,
+S_LEAF1_5,
+S_LEAF1_6,
+S_LEAF1_7,
+S_LEAF1_8,
+S_LEAF1_9,
+S_LEAF1_10,
+S_LEAF1_11,
+S_LEAF1_12,
+S_LEAF1_13,
+S_LEAF1_14,
+S_LEAF1_15,
+S_LEAF1_16,
+S_LEAF1_17,
+S_LEAF1_18,
+S_LEAF_X1,
+S_LEAF2_1,
+S_LEAF2_2,
+S_LEAF2_3,
+S_LEAF2_4,
+S_LEAF2_5,
+S_LEAF2_6,
+S_LEAF2_7,
+S_LEAF2_8,
+S_LEAF2_9,
+S_LEAF2_10,
+S_LEAF2_11,
+S_LEAF2_12,
+S_LEAF2_13,
+S_LEAF2_14,
+S_LEAF2_15,
+S_LEAF2_16,
+S_LEAF2_17,
+S_LEAF2_18,
+S_ZTWINEDTORCH_1,
+S_ZTWINEDTORCH_2,
+S_ZTWINEDTORCH_3,
+S_ZTWINEDTORCH_4,
+S_ZTWINEDTORCH_5,
+S_ZTWINEDTORCH_6,
+S_ZTWINEDTORCH_7,
+S_ZTWINEDTORCH_8,
+S_ZTWINEDTORCH_UNLIT,
+S_BRIDGE1,
+S_BRIDGE2,
+S_BRIDGE3,
+S_FREE_BRIDGE1,
+S_FREE_BRIDGE2,
+S_BBALL1,
+S_BBALL2,
+S_ZWALLTORCH1,
+S_ZWALLTORCH2,
+S_ZWALLTORCH3,
+S_ZWALLTORCH4,
+S_ZWALLTORCH5,
+S_ZWALLTORCH6,
+S_ZWALLTORCH7,
+S_ZWALLTORCH8,
+S_ZWALLTORCH_U,
+S_ZBARREL1,
+S_ZSHRUB1,
+S_ZSHRUB1_DIE,
+S_ZSHRUB1_X1,
+S_ZSHRUB1_X2,
+S_ZSHRUB1_X3,
+S_ZSHRUB2,
+S_ZSHRUB2_DIE,
+S_ZSHRUB2_X1,
+S_ZSHRUB2_X2,
+S_ZSHRUB2_X3,
+S_ZSHRUB2_X4,
+S_ZBUCKET1,
+S_ZPOISONSHROOM1,
+S_ZPOISONSHROOM_P1,
+S_ZPOISONSHROOM_P2,
+S_ZPOISONSHROOM_X1,
+S_ZPOISONSHROOM_X2,
+S_ZPOISONSHROOM_X3,
+S_ZPOISONSHROOM_X4,
+S_ZFIREBULL1,
+S_ZFIREBULL2,
+S_ZFIREBULL3,
+S_ZFIREBULL4,
+S_ZFIREBULL5,
+S_ZFIREBULL6,
+S_ZFIREBULL7,
+S_ZFIREBULL_DEATH,
+S_ZFIREBULL_DEATH2,
+S_ZFIREBULL_U,
+S_ZFIREBULL_BIRTH,
+S_ZFIREBULL_BIRTH2,
+S_ZFIRETHING1,
+S_ZFIRETHING2,
+S_ZFIRETHING3,
+S_ZFIRETHING4,
+S_ZFIRETHING5,
+S_ZFIRETHING6,
+S_ZFIRETHING7,
+S_ZFIRETHING8,
+S_ZFIRETHING9,
+S_ZBRASSTORCH1,
+S_ZBRASSTORCH2,
+S_ZBRASSTORCH3,
+S_ZBRASSTORCH4,
+S_ZBRASSTORCH5,
+S_ZBRASSTORCH6,
+S_ZBRASSTORCH7,
+S_ZBRASSTORCH8,
+S_ZBRASSTORCH9,
+S_ZBRASSTORCH10,
+S_ZBRASSTORCH11,
+S_ZBRASSTORCH12,
+S_ZBRASSTORCH13,
+S_ZSUITOFARMOR,
+S_ZSUITOFARMOR_X1,
+S_ZARMORCHUNK1,
+S_ZARMORCHUNK2,
+S_ZARMORCHUNK3,
+S_ZARMORCHUNK4,
+S_ZARMORCHUNK5,
+S_ZARMORCHUNK6,
+S_ZARMORCHUNK7,
+S_ZARMORCHUNK8,
+S_ZARMORCHUNK9,
+S_ZARMORCHUNK10,
+S_ZBELL,
+S_ZBELL_X1,
+S_ZBELL_X2,
+S_ZBELL_X3,
+S_ZBELL_X4,
+S_ZBELL_X5,
+S_ZBELL_X6,
+S_ZBELL_X7,
+S_ZBELL_X8,
+S_ZBELL_X9,
+S_ZBELL_X10,
+S_ZBELL_X11,
+S_ZBELL_X12,
+S_ZBELL_X13,
+S_ZBELL_X14,
+S_ZBELL_X15,
+S_ZBELL_X16,
+S_ZBELL_X17,
+S_ZBELL_X18,
+S_ZBELL_X19,
+S_ZBELL_X20,
+S_ZBELL_X21,
+S_ZBELL_X22,
+S_ZBELL_X23,
+S_ZBELL_X24,
+S_ZBELL_X25,
+S_ZBELL_X26,
+S_ZBELL_X27,
+S_ZBELL_X28,
+S_ZBELL_X29,
+S_ZBELL_X30,
+S_ZBELL_X31,
+S_ZBELL_X32,
+S_ZBELL_X33,
+S_ZBELL_X34,
+S_ZBELL_X35,
+S_ZBELL_X36,
+S_ZBELL_X37,
+S_ZBELL_X38,
+S_ZBELL_X39,
+S_ZBELL_X40,
+S_ZBELL_X41,
+S_ZBELL_X42,
+S_ZBELL_X43,
+S_ZBELL_X44,
+S_ZBELL_X45,
+S_ZBELL_X46,
+S_ZBELL_X47,
+S_ZBLUE_CANDLE1,
+S_ZBLUE_CANDLE2,
+S_ZBLUE_CANDLE3,
+S_ZBLUE_CANDLE4,
+S_ZBLUE_CANDLE5,
+S_ZIRON_MAIDEN,
+S_ZXMAS_TREE,
+S_ZXMAS_TREE_DIE,
+S_ZXMAS_TREE_X1,
+S_ZXMAS_TREE_X2,
+S_ZXMAS_TREE_X3,
+S_ZXMAS_TREE_X4,
+S_ZXMAS_TREE_X5,
+S_ZXMAS_TREE_X6,
+S_ZXMAS_TREE_X7,
+S_ZXMAS_TREE_X8,
+S_ZXMAS_TREE_X9,
+S_ZXMAS_TREE_X10,
+S_ZCAULDRON1,
+S_ZCAULDRON2,
+S_ZCAULDRON3,
+S_ZCAULDRON4,
+S_ZCAULDRON5,
+S_ZCAULDRON6,
+S_ZCAULDRON7,
+S_ZCAULDRON_U,
+S_ZCHAINBIT32,
+S_ZCHAINBIT64,
+S_ZCHAINEND_HEART,
+S_ZCHAINEND_HOOK1,
+S_ZCHAINEND_HOOK2,
+S_ZCHAINEND_SPIKE,
+S_ZCHAINEND_SKULL,
+S_TABLE_SHIT1,
+S_TABLE_SHIT2,
+S_TABLE_SHIT3,
+S_TABLE_SHIT4,
+S_TABLE_SHIT5,
+S_TABLE_SHIT6,
+S_TABLE_SHIT7,
+S_TABLE_SHIT8,
+S_TABLE_SHIT9,
+S_TABLE_SHIT10,
+S_TFOG1,
+S_TFOG2,
+S_TFOG3,
+S_TFOG4,
+S_TFOG5,
+S_TFOG6,
+S_TFOG7,
+S_TFOG8,
+S_TFOG9,
+S_TFOG10,
+S_TFOG11,
+S_TFOG12,
+S_TFOG13,
+S_TELESMOKE1,
+S_TELESMOKE2,
+S_TELESMOKE3,
+S_TELESMOKE4,
+S_TELESMOKE5,
+S_TELESMOKE6,
+S_TELESMOKE7,
+S_TELESMOKE8,
+S_TELESMOKE9,
+S_TELESMOKE10,
+S_TELESMOKE11,
+S_TELESMOKE12,
+S_TELESMOKE13,
+S_TELESMOKE14,
+S_TELESMOKE15,
+S_TELESMOKE16,
+S_TELESMOKE17,
+S_TELESMOKE18,
+S_TELESMOKE19,
+S_TELESMOKE20,
+S_TELESMOKE21,
+S_TELESMOKE22,
+S_TELESMOKE23,
+S_TELESMOKE24,
+S_TELESMOKE25,
+S_TELESMOKE26,
+S_LIGHTDONE,
+S_PUNCHREADY,
+S_PUNCHDOWN,
+S_PUNCHUP,
+S_PUNCHATK1_1,
+S_PUNCHATK1_2,
+S_PUNCHATK1_3,
+S_PUNCHATK1_4,
+S_PUNCHATK1_5,
+S_PUNCHATK2_1,
+S_PUNCHATK2_2,
+S_PUNCHATK2_3,
+S_PUNCHATK2_4,
+S_PUNCHATK2_5,
+S_PUNCHATK2_6,
+S_PUNCHATK2_7,
+S_PUNCHATK2_8,
+S_PUNCHATK2_9,
+S_PUNCHPUFF1,
+S_PUNCHPUFF2,
+S_PUNCHPUFF3,
+S_PUNCHPUFF4,
+S_PUNCHPUFF5,
+S_AXE,
+S_FAXEREADY,
+S_FAXEDOWN,
+S_FAXEUP,
+S_FAXEATK_1,
+S_FAXEATK_2,
+S_FAXEATK_3,
+S_FAXEATK_4,
+S_FAXEATK_5,
+S_FAXEATK_6,
+S_FAXEATK_7,
+S_FAXEATK_8,
+S_FAXEATK_9,
+S_FAXEATK_10,
+S_FAXEATK_11,
+S_FAXEATK_12,
+S_FAXEATK_13,
+S_FAXEREADY_G,
+S_FAXEREADY_G1,
+S_FAXEREADY_G2,
+S_FAXEREADY_G3,
+S_FAXEREADY_G4,
+S_FAXEREADY_G5,
+S_FAXEDOWN_G,
+S_FAXEUP_G,
+S_FAXEATK_G1,
+S_FAXEATK_G2,
+S_FAXEATK_G3,
+S_FAXEATK_G4,
+S_FAXEATK_G5,
+S_FAXEATK_G6,
+S_FAXEATK_G7,
+S_FAXEATK_G8,
+S_FAXEATK_G9,
+S_FAXEATK_G10,
+S_FAXEATK_G11,
+S_FAXEATK_G12,
+S_FAXEATK_G13,
+S_AXEPUFF_GLOW1,
+S_AXEPUFF_GLOW2,
+S_AXEPUFF_GLOW3,
+S_AXEPUFF_GLOW4,
+S_AXEPUFF_GLOW5,
+S_AXEPUFF_GLOW6,
+S_AXEPUFF_GLOW7,
+S_AXEBLOOD1,
+S_AXEBLOOD2,
+S_AXEBLOOD3,
+S_AXEBLOOD4,
+S_AXEBLOOD5,
+S_AXEBLOOD6,
+S_HAMM,
+S_FHAMMERREADY,
+S_FHAMMERDOWN,
+S_FHAMMERUP,
+S_FHAMMERATK_1,
+S_FHAMMERATK_2,
+S_FHAMMERATK_3,
+S_FHAMMERATK_4,
+S_FHAMMERATK_5,
+S_FHAMMERATK_6,
+S_FHAMMERATK_7,
+S_FHAMMERATK_8,
+S_FHAMMERATK_9,
+S_FHAMMERATK_10,
+S_FHAMMERATK_11,
+S_FHAMMERATK_12,
+S_HAMMER_MISSILE_1,
+S_HAMMER_MISSILE_2,
+S_HAMMER_MISSILE_3,
+S_HAMMER_MISSILE_4,
+S_HAMMER_MISSILE_5,
+S_HAMMER_MISSILE_6,
+S_HAMMER_MISSILE_7,
+S_HAMMER_MISSILE_8,
+S_HAMMER_MISSILE_X1,
+S_HAMMER_MISSILE_X2,
+S_HAMMER_MISSILE_X3,
+S_HAMMER_MISSILE_X4,
+S_HAMMER_MISSILE_X5,
+S_HAMMER_MISSILE_X6,
+S_HAMMER_MISSILE_X7,
+S_HAMMER_MISSILE_X8,
+S_HAMMER_MISSILE_X9,
+S_HAMMER_MISSILE_X10,
+S_HAMMERPUFF1,
+S_HAMMERPUFF2,
+S_HAMMERPUFF3,
+S_HAMMERPUFF4,
+S_HAMMERPUFF5,
+S_FSWORDREADY,
+S_FSWORDREADY1,
+S_FSWORDREADY2,
+S_FSWORDREADY3,
+S_FSWORDREADY4,
+S_FSWORDREADY5,
+S_FSWORDREADY6,
+S_FSWORDREADY7,
+S_FSWORDREADY8,
+S_FSWORDREADY9,
+S_FSWORDREADY10,
+S_FSWORDREADY11,
+S_FSWORDDOWN,
+S_FSWORDUP,
+S_FSWORDATK_1,
+S_FSWORDATK_2,
+S_FSWORDATK_3,
+S_FSWORDATK_4,
+S_FSWORDATK_5,
+S_FSWORDATK_6,
+S_FSWORDATK_7,
+S_FSWORDATK_8,
+S_FSWORDATK_9,
+S_FSWORDATK_10,
+S_FSWORDATK_11,
+S_FSWORDATK_12,
+S_FSWORD_MISSILE1,
+S_FSWORD_MISSILE2,
+S_FSWORD_MISSILE3,
+S_FSWORD_MISSILE_X1,
+S_FSWORD_MISSILE_X2,
+S_FSWORD_MISSILE_X3,
+S_FSWORD_MISSILE_X4,
+S_FSWORD_MISSILE_X5,
+S_FSWORD_MISSILE_X6,
+S_FSWORD_MISSILE_X7,
+S_FSWORD_MISSILE_X8,
+S_FSWORD_MISSILE_X9,
+S_FSWORD_MISSILE_X10,
+S_FSWORD_FLAME1,
+S_FSWORD_FLAME2,
+S_FSWORD_FLAME3,
+S_FSWORD_FLAME4,
+S_FSWORD_FLAME5,
+S_FSWORD_FLAME6,
+S_FSWORD_FLAME7,
+S_FSWORD_FLAME8,
+S_FSWORD_FLAME9,
+S_FSWORD_FLAME10,
+S_CMACEREADY,
+S_CMACEDOWN,
+S_CMACEUP,
+S_CMACEATK_1,
+S_CMACEATK_2,
+S_CMACEATK_3,
+S_CMACEATK_4,
+S_CMACEATK_5,
+S_CMACEATK_6,
+S_CMACEATK_7,
+S_CMACEATK_8,
+S_CMACEATK_9,
+S_CMACEATK_10,
+S_CMACEATK_11,
+S_CMACEATK_12,
+S_CMACEATK_13,
+S_CMACEATK_14,
+S_CMACEATK_15,
+S_CMACEATK_16,
+S_CMACEATK_17,
+S_CSTAFF,
+S_CSTAFFREADY,
+S_CSTAFFREADY1,
+S_CSTAFFREADY2,
+S_CSTAFFREADY3,
+S_CSTAFFREADY4,
+S_CSTAFFREADY5,
+S_CSTAFFREADY6,
+S_CSTAFFREADY7,
+S_CSTAFFREADY8,
+S_CSTAFFREADY9,
+S_CSTAFFBLINK1,
+S_CSTAFFBLINK2,
+S_CSTAFFBLINK3,
+S_CSTAFFBLINK4,
+S_CSTAFFBLINK5,
+S_CSTAFFBLINK6,
+S_CSTAFFBLINK7,
+S_CSTAFFBLINK8,
+S_CSTAFFBLINK9,
+S_CSTAFFBLINK10,
+S_CSTAFFBLINK11,
+S_CSTAFFDOWN,
+S_CSTAFFDOWN2,
+S_CSTAFFDOWN3,
+S_CSTAFFUP,
+S_CSTAFFATK_1,
+S_CSTAFFATK_2,
+S_CSTAFFATK_3,
+S_CSTAFFATK_4,
+S_CSTAFFATK_5,
+S_CSTAFFATK_6,
+S_CSTAFFATK2_1,
+S_CSTAFF_MISSILE1,
+S_CSTAFF_MISSILE2,
+S_CSTAFF_MISSILE3,
+S_CSTAFF_MISSILE4,
+S_CSTAFF_MISSILE_X1,
+S_CSTAFF_MISSILE_X2,
+S_CSTAFF_MISSILE_X3,
+S_CSTAFF_MISSILE_X4,
+S_CSTAFFPUFF1,
+S_CSTAFFPUFF2,
+S_CSTAFFPUFF3,
+S_CSTAFFPUFF4,
+S_CSTAFFPUFF5,
+S_CFLAME1,
+S_CFLAME2,
+S_CFLAME3,
+S_CFLAME4,
+S_CFLAME5,
+S_CFLAME6,
+S_CFLAME7,
+S_CFLAME8,
+S_CFLAMEREADY1,
+S_CFLAMEREADY2,
+S_CFLAMEREADY3,
+S_CFLAMEREADY4,
+S_CFLAMEREADY5,
+S_CFLAMEREADY6,
+S_CFLAMEREADY7,
+S_CFLAMEREADY8,
+S_CFLAMEREADY9,
+S_CFLAMEREADY10,
+S_CFLAMEREADY11,
+S_CFLAMEREADY12,
+S_CFLAMEDOWN,
+S_CFLAMEUP,
+S_CFLAMEATK_1,
+S_CFLAMEATK_2,
+S_CFLAMEATK_3,
+S_CFLAMEATK_4,
+S_CFLAMEATK_5,
+S_CFLAMEATK_6,
+S_CFLAMEATK_7,
+S_CFLAMEATK_8,
+S_CFLAMEFLOOR1,
+S_CFLAMEFLOOR2,
+S_CFLAMEFLOOR3,
+S_FLAMEPUFF1,
+S_FLAMEPUFF2,
+S_FLAMEPUFF3,
+S_FLAMEPUFF4,
+S_FLAMEPUFF5,
+S_FLAMEPUFF6,
+S_FLAMEPUFF7,
+S_FLAMEPUFF8,
+S_FLAMEPUFF9,
+S_FLAMEPUFF10,
+S_FLAMEPUFF11,
+S_FLAMEPUFF12,
+S_FLAMEPUFF13,
+S_FLAMEPUFF2_1,
+S_FLAMEPUFF2_2,
+S_FLAMEPUFF2_3,
+S_FLAMEPUFF2_4,
+S_FLAMEPUFF2_5,
+S_FLAMEPUFF2_6,
+S_FLAMEPUFF2_7,
+S_FLAMEPUFF2_8,
+S_FLAMEPUFF2_9,
+S_FLAMEPUFF2_10,
+S_FLAMEPUFF2_11,
+S_FLAMEPUFF2_12,
+S_FLAMEPUFF2_13,
+S_FLAMEPUFF2_14,
+S_FLAMEPUFF2_15,
+S_FLAMEPUFF2_16,
+S_FLAMEPUFF2_17,
+S_FLAMEPUFF2_18,
+S_FLAMEPUFF2_19,
+S_FLAMEPUFF2_20,
+S_CIRCLE_FLAME1,
+S_CIRCLE_FLAME2,
+S_CIRCLE_FLAME3,
+S_CIRCLE_FLAME4,
+S_CIRCLE_FLAME5,
+S_CIRCLE_FLAME6,
+S_CIRCLE_FLAME7,
+S_CIRCLE_FLAME8,
+S_CIRCLE_FLAME9,
+S_CIRCLE_FLAME10,
+S_CIRCLE_FLAME11,
+S_CIRCLE_FLAME12,
+S_CIRCLE_FLAME13,
+S_CIRCLE_FLAME14,
+S_CIRCLE_FLAME15,
+S_CIRCLE_FLAME16,
+S_CIRCLE_FLAME_X1,
+S_CIRCLE_FLAME_X2,
+S_CIRCLE_FLAME_X3,
+S_CIRCLE_FLAME_X4,
+S_CIRCLE_FLAME_X5,
+S_CIRCLE_FLAME_X6,
+S_CIRCLE_FLAME_X7,
+S_CIRCLE_FLAME_X8,
+S_CIRCLE_FLAME_X9,
+S_CIRCLE_FLAME_X10,
+S_CFLAME_MISSILE1,
+S_CFLAME_MISSILE2,
+S_CFLAME_MISSILE_X,
+S_CHOLYREADY,
+S_CHOLYDOWN,
+S_CHOLYUP,
+S_CHOLYATK_1,
+S_CHOLYATK_2,
+S_CHOLYATK_3,
+S_CHOLYATK_4,
+S_CHOLYATK_5,
+S_CHOLYATK_6,
+S_CHOLYATK_7,
+S_CHOLYATK_8,
+S_CHOLYATK_9,
+S_HOLY_FX1,
+S_HOLY_FX2,
+S_HOLY_FX3,
+S_HOLY_FX4,
+S_HOLY_FX_X1,
+S_HOLY_FX_X2,
+S_HOLY_FX_X3,
+S_HOLY_FX_X4,
+S_HOLY_FX_X5,
+S_HOLY_FX_X6,
+S_HOLY_TAIL1,
+S_HOLY_TAIL2,
+S_HOLY_PUFF1,
+S_HOLY_PUFF2,
+S_HOLY_PUFF3,
+S_HOLY_PUFF4,
+S_HOLY_PUFF5,
+S_HOLY_MISSILE1,
+S_HOLY_MISSILE2,
+S_HOLY_MISSILE3,
+S_HOLY_MISSILE4,
+S_HOLY_MISSILE_X,
+S_HOLY_MISSILE_P1,
+S_HOLY_MISSILE_P2,
+S_HOLY_MISSILE_P3,
+S_HOLY_MISSILE_P4,
+S_HOLY_MISSILE_P5,
+S_MWANDREADY,
+S_MWANDDOWN,
+S_MWANDUP,
+S_MWANDATK_1,
+S_MWANDATK_2,
+S_MWANDATK_3,
+S_MWANDATK_4,
+S_MWANDPUFF1,
+S_MWANDPUFF2,
+S_MWANDPUFF3,
+S_MWANDPUFF4,
+S_MWANDPUFF5,
+S_MWANDSMOKE1,
+S_MWANDSMOKE2,
+S_MWANDSMOKE3,
+S_MWANDSMOKE4,
+S_MWAND_MISSILE1,
+S_MWAND_MISSILE2,
+S_MW_LIGHTNING1,
+S_MW_LIGHTNING2,
+S_MW_LIGHTNING3,
+S_MW_LIGHTNING4,
+S_MW_LIGHTNING5,
+S_MW_LIGHTNING6,
+S_MW_LIGHTNING7,
+S_MW_LIGHTNING8,
+S_MLIGHTNINGREADY,
+S_MLIGHTNINGREADY2,
+S_MLIGHTNINGREADY3,
+S_MLIGHTNINGREADY4,
+S_MLIGHTNINGREADY5,
+S_MLIGHTNINGREADY6,
+S_MLIGHTNINGREADY7,
+S_MLIGHTNINGREADY8,
+S_MLIGHTNINGREADY9,
+S_MLIGHTNINGREADY10,
+S_MLIGHTNINGREADY11,
+S_MLIGHTNINGREADY12,
+S_MLIGHTNINGREADY13,
+S_MLIGHTNINGREADY14,
+S_MLIGHTNINGREADY15,
+S_MLIGHTNINGREADY16,
+S_MLIGHTNINGREADY17,
+S_MLIGHTNINGREADY18,
+S_MLIGHTNINGREADY19,
+S_MLIGHTNINGREADY20,
+S_MLIGHTNINGREADY21,
+S_MLIGHTNINGREADY22,
+S_MLIGHTNINGREADY23,
+S_MLIGHTNINGREADY24,
+S_MLIGHTNINGDOWN,
+S_MLIGHTNINGUP,
+S_MLIGHTNINGATK_1,
+S_MLIGHTNINGATK_2,
+S_MLIGHTNINGATK_3,
+S_MLIGHTNINGATK_4,
+S_MLIGHTNINGATK_5,
+S_MLIGHTNINGATK_6,
+S_MLIGHTNINGATK_7,
+S_MLIGHTNINGATK_8,
+S_MLIGHTNINGATK_9,
+S_MLIGHTNINGATK_10,
+S_MLIGHTNINGATK_11,
+S_LIGHTNING_CEILING1,
+S_LIGHTNING_CEILING2,
+S_LIGHTNING_CEILING3,
+S_LIGHTNING_CEILING4,
+S_LIGHTNING_C_X1,
+S_LIGHTNING_C_X2,
+S_LIGHTNING_C_X3,
+S_LIGHTNING_C_X4,
+S_LIGHTNING_C_X5,
+S_LIGHTNING_C_X6,
+S_LIGHTNING_C_X7,
+S_LIGHTNING_C_X8,
+S_LIGHTNING_C_X9,
+S_LIGHTNING_C_X10,
+S_LIGHTNING_C_X11,
+S_LIGHTNING_C_X12,
+S_LIGHTNING_C_X13,
+S_LIGHTNING_C_X14,
+S_LIGHTNING_C_X15,
+S_LIGHTNING_C_X16,
+S_LIGHTNING_C_X17,
+S_LIGHTNING_C_X18,
+S_LIGHTNING_C_X19,
+S_LIGHTNING_FLOOR1,
+S_LIGHTNING_FLOOR2,
+S_LIGHTNING_FLOOR3,
+S_LIGHTNING_FLOOR4,
+S_LIGHTNING_F_X1,
+S_LIGHTNING_F_X2,
+S_LIGHTNING_F_X3,
+S_LIGHTNING_F_X4,
+S_LIGHTNING_F_X5,
+S_LIGHTNING_F_X6,
+S_LIGHTNING_F_X7,
+S_LIGHTNING_F_X8,
+S_LIGHTNING_F_X9,
+S_LIGHTNING_F_X10,
+S_LIGHTNING_F_X11,
+S_LIGHTNING_F_X12,
+S_LIGHTNING_F_X13,
+S_LIGHTNING_F_X14,
+S_LIGHTNING_F_X15,
+S_LIGHTNING_F_X16,
+S_LIGHTNING_F_X17,
+S_LIGHTNING_F_X18,
+S_LIGHTNING_F_X19,
+S_LIGHTNING_ZAP1,
+S_LIGHTNING_ZAP2,
+S_LIGHTNING_ZAP3,
+S_LIGHTNING_ZAP4,
+S_LIGHTNING_ZAP5,
+S_LIGHTNING_ZAP_X1,
+S_LIGHTNING_ZAP_X2,
+S_LIGHTNING_ZAP_X3,
+S_LIGHTNING_ZAP_X4,
+S_LIGHTNING_ZAP_X5,
+S_LIGHTNING_ZAP_X6,
+S_LIGHTNING_ZAP_X7,
+S_LIGHTNING_ZAP_X8,
+S_MSTAFFREADY,
+S_MSTAFFREADY2,
+S_MSTAFFREADY3,
+S_MSTAFFREADY4,
+S_MSTAFFREADY5,
+S_MSTAFFREADY6,
+S_MSTAFFREADY7,
+S_MSTAFFREADY8,
+S_MSTAFFREADY9,
+S_MSTAFFREADY10,
+S_MSTAFFREADY11,
+S_MSTAFFREADY12,
+S_MSTAFFREADY13,
+S_MSTAFFREADY14,
+S_MSTAFFREADY15,
+S_MSTAFFREADY16,
+S_MSTAFFREADY17,
+S_MSTAFFREADY18,
+S_MSTAFFREADY19,
+S_MSTAFFREADY20,
+S_MSTAFFREADY21,
+S_MSTAFFREADY22,
+S_MSTAFFREADY23,
+S_MSTAFFREADY24,
+S_MSTAFFREADY25,
+S_MSTAFFREADY26,
+S_MSTAFFREADY27,
+S_MSTAFFREADY28,
+S_MSTAFFREADY29,
+S_MSTAFFREADY30,
+S_MSTAFFREADY31,
+S_MSTAFFREADY32,
+S_MSTAFFREADY33,
+S_MSTAFFREADY34,
+S_MSTAFFREADY35,
+S_MSTAFFDOWN,
+S_MSTAFFUP,
+S_MSTAFFATK_1,
+S_MSTAFFATK_2,
+S_MSTAFFATK_3,
+S_MSTAFFATK_4,
+S_MSTAFFATK_5,
+S_MSTAFFATK_6,
+S_MSTAFFATK_7,
+S_MSTAFF_FX1_1,
+S_MSTAFF_FX1_2,
+S_MSTAFF_FX1_3,
+S_MSTAFF_FX1_4,
+S_MSTAFF_FX1_5,
+S_MSTAFF_FX1_6,
+S_MSTAFF_FX_X1,
+S_MSTAFF_FX_X2,
+S_MSTAFF_FX_X3,
+S_MSTAFF_FX_X4,
+S_MSTAFF_FX_X5,
+S_MSTAFF_FX_X6,
+S_MSTAFF_FX_X7,
+S_MSTAFF_FX_X8,
+S_MSTAFF_FX_X9,
+S_MSTAFF_FX_X10,
+S_MSTAFF_FX2_1,
+S_MSTAFF_FX2_2,
+S_MSTAFF_FX2_3,
+S_MSTAFF_FX2_4,
+S_MSTAFF_FX2_X1,
+S_MSTAFF_FX2_X2,
+S_MSTAFF_FX2_X3,
+S_MSTAFF_FX2_X4,
+S_MSTAFF_FX2_X5,
+S_FSWORD1,
+S_FSWORD2,
+S_FSWORD3,
+S_CHOLY1,
+S_CHOLY2,
+S_CHOLY3,
+S_MSTAFF1,
+S_MSTAFF2,
+S_MSTAFF3,
+S_SNOUTREADY,
+S_SNOUTDOWN,
+S_SNOUTUP,
+S_SNOUTATK1,
+S_SNOUTATK2,
+S_COS1,
+S_COS2,
+S_COS3,
+S_CONEREADY,
+S_CONEDOWN,
+S_CONEUP,
+S_CONEATK1_1,
+S_CONEATK1_2,
+S_CONEATK1_3,
+S_CONEATK1_4,
+S_CONEATK1_5,
+S_CONEATK1_6,
+S_CONEATK1_7,
+S_CONEATK1_8,
+S_SHARDFX1_1,
+S_SHARDFX1_2,
+S_SHARDFX1_3,
+S_SHARDFX1_4,
+S_SHARDFXE1_1,
+S_SHARDFXE1_2,
+S_SHARDFXE1_3,
+S_SHARDFXE1_4,
+S_SHARDFXE1_5,
+S_BLOOD1,
+S_BLOOD2,
+S_BLOOD3,
+S_BLOODSPLATTER1,
+S_BLOODSPLATTER2,
+S_BLOODSPLATTER3,
+S_BLOODSPLATTERX,
+S_GIBS1,
+S_FPLAY,
+S_FPLAY_RUN1,
+S_FPLAY_RUN2,
+S_FPLAY_RUN3,
+S_FPLAY_RUN4,
+S_FPLAY_ATK1,
+S_FPLAY_ATK2,
+S_FPLAY_PAIN,
+S_FPLAY_PAIN2,
+S_FPLAY_DIE1,
+S_FPLAY_DIE2,
+S_FPLAY_DIE3,
+S_FPLAY_DIE4,
+S_FPLAY_DIE5,
+S_FPLAY_DIE6,
+S_FPLAY_DIE7,
+S_FPLAY_XDIE1,
+S_FPLAY_XDIE2,
+S_FPLAY_XDIE3,
+S_FPLAY_XDIE4,
+S_FPLAY_XDIE5,
+S_FPLAY_XDIE6,
+S_FPLAY_XDIE7,
+S_FPLAY_XDIE8,
+S_FPLAY_ICE,
+S_FPLAY_ICE2,
+S_PLAY_F_FDTH1,
+S_PLAY_F_FDTH2,
+S_PLAY_C_FDTH1,
+S_PLAY_C_FDTH2,
+S_PLAY_M_FDTH1,
+S_PLAY_M_FDTH2,
+S_PLAY_FDTH3,
+S_PLAY_FDTH4,
+S_PLAY_FDTH5,
+S_PLAY_FDTH6,
+S_PLAY_FDTH7,
+S_PLAY_FDTH8,
+S_PLAY_FDTH9,
+S_PLAY_FDTH10,
+S_PLAY_FDTH11,
+S_PLAY_FDTH12,
+S_PLAY_FDTH13,
+S_PLAY_FDTH14,
+S_PLAY_FDTH15,
+S_PLAY_FDTH16,
+S_PLAY_FDTH17,
+S_PLAY_FDTH18,
+S_PLAY_FDTH19,
+S_PLAY_FDTH20,
+S_BLOODYSKULL1,
+S_BLOODYSKULL2,
+S_BLOODYSKULL3,
+S_BLOODYSKULL4,
+S_BLOODYSKULL5,
+S_BLOODYSKULL6,
+S_BLOODYSKULL7,
+S_BLOODYSKULLX1,
+S_BLOODYSKULLX2,
+S_PLAYER_SPEED1,
+S_PLAYER_SPEED2,
+S_ICECHUNK1,
+S_ICECHUNK2,
+S_ICECHUNK3,
+S_ICECHUNK4,
+S_ICECHUNK_HEAD,
+S_ICECHUNK_HEAD2,
+S_CPLAY,
+S_CPLAY_RUN1,
+S_CPLAY_RUN2,
+S_CPLAY_RUN3,
+S_CPLAY_RUN4,
+S_CPLAY_ATK1,
+S_CPLAY_ATK2,
+S_CPLAY_ATK3,
+S_CPLAY_PAIN,
+S_CPLAY_PAIN2,
+S_CPLAY_DIE1,
+S_CPLAY_DIE2,
+S_CPLAY_DIE3,
+S_CPLAY_DIE4,
+S_CPLAY_DIE5,
+S_CPLAY_DIE6,
+S_CPLAY_DIE7,
+S_CPLAY_DIE8,
+S_CPLAY_DIE9,
+S_CPLAY_XDIE1,
+S_CPLAY_XDIE2,
+S_CPLAY_XDIE3,
+S_CPLAY_XDIE4,
+S_CPLAY_XDIE5,
+S_CPLAY_XDIE6,
+S_CPLAY_XDIE7,
+S_CPLAY_XDIE8,
+S_CPLAY_XDIE9,
+S_CPLAY_XDIE10,
+S_CPLAY_ICE,
+S_CPLAY_ICE2,
+S_MPLAY,
+S_MPLAY_RUN1,
+S_MPLAY_RUN2,
+S_MPLAY_RUN3,
+S_MPLAY_RUN4,
+S_MPLAY_ATK1,
+S_MPLAY_ATK2,
+S_MPLAY_PAIN,
+S_MPLAY_PAIN2,
+S_MPLAY_DIE1,
+S_MPLAY_DIE2,
+S_MPLAY_DIE3,
+S_MPLAY_DIE4,
+S_MPLAY_DIE5,
+S_MPLAY_DIE6,
+S_MPLAY_DIE7,
+S_MPLAY_XDIE1,
+S_MPLAY_XDIE2,
+S_MPLAY_XDIE3,
+S_MPLAY_XDIE4,
+S_MPLAY_XDIE5,
+S_MPLAY_XDIE6,
+S_MPLAY_XDIE7,
+S_MPLAY_XDIE8,
+S_MPLAY_XDIE9,
+S_MPLAY_ICE,
+S_MPLAY_ICE2,
+S_PIGPLAY,
+S_PIGPLAY_RUN1,
+S_PIGPLAY_RUN2,
+S_PIGPLAY_RUN3,
+S_PIGPLAY_RUN4,
+S_PIGPLAY_ATK1,
+S_PIGPLAY_PAIN,
+S_PIG_LOOK1,
+S_PIG_WALK1,
+S_PIG_WALK2,
+S_PIG_WALK3,
+S_PIG_WALK4,
+S_PIG_PAIN,
+S_PIG_ATK1,
+S_PIG_ATK2,
+S_PIG_DIE1,
+S_PIG_DIE2,
+S_PIG_DIE3,
+S_PIG_DIE4,
+S_PIG_DIE5,
+S_PIG_DIE6,
+S_PIG_DIE7,
+S_PIG_DIE8,
+S_PIG_ICE,
+S_PIG_ICE2,
+S_CENTAUR_LOOK1,
+S_CENTAUR_LOOK2,
+S_CENTAUR_WALK1,
+S_CENTAUR_WALK2,
+S_CENTAUR_WALK3,
+S_CENTAUR_WALK4,
+S_CENTAUR_ATK1,
+S_CENTAUR_ATK2,
+S_CENTAUR_ATK3,
+S_CENTAUR_MISSILE1,
+S_CENTAUR_MISSILE2,
+S_CENTAUR_MISSILE3,
+S_CENTAUR_MISSILE4,
+S_CENTAUR_PAIN1,
+S_CENTAUR_PAIN2,
+S_CENTAUR_PAIN3,
+S_CENTAUR_PAIN4,
+S_CENTAUR_PAIN5,
+S_CENTAUR_PAIN6,
+S_CENTAUR_DEATH1,
+S_CENTAUR_DEATH2,
+S_CENTAUR_DEATH3,
+S_CENTAUR_DEATH4,
+S_CENTAUR_DEATH5,
+S_CENTAUR_DEATH6,
+S_CENTAUR_DEATH7,
+S_CENTAUR_DEATH8,
+S_CENTAUR_DEATH9,
+S_CENTAUR_DEATH0,
+S_CENTAUR_DEATH_X1,
+S_CENTAUR_DEATH_X2,
+S_CENTAUR_DEATH_X3,
+S_CENTAUR_DEATH_X4,
+S_CENTAUR_DEATH_X5,
+S_CENTAUR_DEATH_X6,
+S_CENTAUR_DEATH_X7,
+S_CENTAUR_DEATH_X8,
+S_CENTAUR_DEATH_X9,
+S_CENTAUR_DEATH_X10,
+S_CENTAUR_DEATH_X11,
+S_CENTAUR_ICE,
+S_CENTAUR_ICE2,
+S_CENTAUR_FX1,
+S_CENTAUR_FX_X1,
+S_CENTAUR_FX_X2,
+S_CENTAUR_FX_X3,
+S_CENTAUR_FX_X4,
+S_CENTAUR_FX_X5,
+S_CENTAUR_SHIELD1,
+S_CENTAUR_SHIELD2,
+S_CENTAUR_SHIELD3,
+S_CENTAUR_SHIELD4,
+S_CENTAUR_SHIELD5,
+S_CENTAUR_SHIELD6,
+S_CENTAUR_SHIELD_X1,
+S_CENTAUR_SHIELD_X2,
+S_CENTAUR_SHIELD_X3,
+S_CENTAUR_SHIELD_X4,
+S_CENTAUR_SWORD1,
+S_CENTAUR_SWORD2,
+S_CENTAUR_SWORD3,
+S_CENTAUR_SWORD4,
+S_CENTAUR_SWORD5,
+S_CENTAUR_SWORD6,
+S_CENTAUR_SWORD7,
+S_CENTAUR_SWORD_X1,
+S_CENTAUR_SWORD_X2,
+S_CENTAUR_SWORD_X3,
+S_DEMN_LOOK1,
+S_DEMN_LOOK2,
+S_DEMN_CHASE1,
+S_DEMN_CHASE2,
+S_DEMN_CHASE3,
+S_DEMN_CHASE4,
+S_DEMN_ATK1_1,
+S_DEMN_ATK1_2,
+S_DEMN_ATK1_3,
+S_DEMN_ATK2_1,
+S_DEMN_ATK2_2,
+S_DEMN_ATK2_3,
+S_DEMN_PAIN1,
+S_DEMN_PAIN2,
+S_DEMN_DEATH1,
+S_DEMN_DEATH2,
+S_DEMN_DEATH3,
+S_DEMN_DEATH4,
+S_DEMN_DEATH5,
+S_DEMN_DEATH6,
+S_DEMN_DEATH7,
+S_DEMN_DEATH8,
+S_DEMN_DEATH9,
+S_DEMN_XDEATH1,
+S_DEMN_XDEATH2,
+S_DEMN_XDEATH3,
+S_DEMN_XDEATH4,
+S_DEMN_XDEATH5,
+S_DEMN_XDEATH6,
+S_DEMN_XDEATH7,
+S_DEMN_XDEATH8,
+S_DEMN_XDEATH9,
+S_DEMON_ICE,
+S_DEMON_ICE2,
+S_DEMONCHUNK1_1,
+S_DEMONCHUNK1_2,
+S_DEMONCHUNK1_3,
+S_DEMONCHUNK1_4,
+S_DEMONCHUNK2_1,
+S_DEMONCHUNK2_2,
+S_DEMONCHUNK2_3,
+S_DEMONCHUNK2_4,
+S_DEMONCHUNK3_1,
+S_DEMONCHUNK3_2,
+S_DEMONCHUNK3_3,
+S_DEMONCHUNK3_4,
+S_DEMONCHUNK4_1,
+S_DEMONCHUNK4_2,
+S_DEMONCHUNK4_3,
+S_DEMONCHUNK4_4,
+S_DEMONCHUNK5_1,
+S_DEMONCHUNK5_2,
+S_DEMONCHUNK5_3,
+S_DEMONCHUNK5_4,
+S_DEMONFX_MOVE1,
+S_DEMONFX_MOVE2,
+S_DEMONFX_MOVE3,
+S_DEMONFX_BOOM1,
+S_DEMONFX_BOOM2,
+S_DEMONFX_BOOM3,
+S_DEMONFX_BOOM4,
+S_DEMONFX_BOOM5,
+S_DEMN2_LOOK1,
+S_DEMN2_LOOK2,
+S_DEMN2_CHASE1,
+S_DEMN2_CHASE2,
+S_DEMN2_CHASE3,
+S_DEMN2_CHASE4,
+S_DEMN2_ATK1_1,
+S_DEMN2_ATK1_2,
+S_DEMN2_ATK1_3,
+S_DEMN2_ATK2_1,
+S_DEMN2_ATK2_2,
+S_DEMN2_ATK2_3,
+S_DEMN2_PAIN1,
+S_DEMN2_PAIN2,
+S_DEMN2_DEATH1,
+S_DEMN2_DEATH2,
+S_DEMN2_DEATH3,
+S_DEMN2_DEATH4,
+S_DEMN2_DEATH5,
+S_DEMN2_DEATH6,
+S_DEMN2_DEATH7,
+S_DEMN2_DEATH8,
+S_DEMN2_DEATH9,
+S_DEMN2_XDEATH1,
+S_DEMN2_XDEATH2,
+S_DEMN2_XDEATH3,
+S_DEMN2_XDEATH4,
+S_DEMN2_XDEATH5,
+S_DEMN2_XDEATH6,
+S_DEMN2_XDEATH7,
+S_DEMN2_XDEATH8,
+S_DEMN2_XDEATH9,
+S_DEMON2CHUNK1_1,
+S_DEMON2CHUNK1_2,
+S_DEMON2CHUNK1_3,
+S_DEMON2CHUNK1_4,
+S_DEMON2CHUNK2_1,
+S_DEMON2CHUNK2_2,
+S_DEMON2CHUNK2_3,
+S_DEMON2CHUNK2_4,
+S_DEMON2CHUNK3_1,
+S_DEMON2CHUNK3_2,
+S_DEMON2CHUNK3_3,
+S_DEMON2CHUNK3_4,
+S_DEMON2CHUNK4_1,
+S_DEMON2CHUNK4_2,
+S_DEMON2CHUNK4_3,
+S_DEMON2CHUNK4_4,
+S_DEMON2CHUNK5_1,
+S_DEMON2CHUNK5_2,
+S_DEMON2CHUNK5_3,
+S_DEMON2CHUNK5_4,
+S_DEMON2FX_MOVE1,
+S_DEMON2FX_MOVE2,
+S_DEMON2FX_MOVE3,
+S_DEMON2FX_MOVE4,
+S_DEMON2FX_MOVE5,
+S_DEMON2FX_MOVE6,
+S_DEMON2FX_BOOM1,
+S_DEMON2FX_BOOM2,
+S_DEMON2FX_BOOM3,
+S_DEMON2FX_BOOM4,
+S_DEMON2FX_BOOM5,
+S_DEMON2FX_BOOM6,
+S_WRAITH_RAISE1,
+S_WRAITH_RAISE2,
+S_WRAITH_RAISE3,
+S_WRAITH_RAISE4,
+S_WRAITH_RAISE5,
+S_WRAITH_INIT1,
+S_WRAITH_INIT2,
+S_WRAITH_LOOK1,
+S_WRAITH_LOOK2,
+S_WRAITH_CHASE1,
+S_WRAITH_CHASE2,
+S_WRAITH_CHASE3,
+S_WRAITH_CHASE4,
+S_WRAITH_ATK1_1,
+S_WRAITH_ATK1_2,
+S_WRAITH_ATK1_3,
+S_WRAITH_ATK2_1,
+S_WRAITH_ATK2_2,
+S_WRAITH_ATK2_3,
+S_WRAITH_PAIN1,
+S_WRAITH_PAIN2,
+S_WRAITH_DEATH1_1,
+S_WRAITH_DEATH1_2,
+S_WRAITH_DEATH1_3,
+S_WRAITH_DEATH1_4,
+S_WRAITH_DEATH1_5,
+S_WRAITH_DEATH1_6,
+S_WRAITH_DEATH1_7,
+S_WRAITH_DEATH1_8,
+S_WRAITH_DEATH1_9,
+S_WRAITH_DEATH1_0,
+S_WRAITH_DEATH2_1,
+S_WRAITH_DEATH2_2,
+S_WRAITH_DEATH2_3,
+S_WRAITH_DEATH2_4,
+S_WRAITH_DEATH2_5,
+S_WRAITH_DEATH2_6,
+S_WRAITH_DEATH2_7,
+S_WRAITH_DEATH2_8,
+S_WRAITH_ICE,
+S_WRAITH_ICE2,
+S_WRTHFX_MOVE1,
+S_WRTHFX_MOVE2,
+S_WRTHFX_MOVE3,
+S_WRTHFX_BOOM1,
+S_WRTHFX_BOOM2,
+S_WRTHFX_BOOM3,
+S_WRTHFX_BOOM4,
+S_WRTHFX_BOOM5,
+S_WRTHFX_BOOM6,
+S_WRTHFX_SIZZLE1,
+S_WRTHFX_SIZZLE2,
+S_WRTHFX_SIZZLE3,
+S_WRTHFX_SIZZLE4,
+S_WRTHFX_SIZZLE5,
+S_WRTHFX_SIZZLE6,
+S_WRTHFX_SIZZLE7,
+S_WRTHFX_DROP1,
+S_WRTHFX_DROP2,
+S_WRTHFX_DROP3,
+S_WRTHFX_DEAD1,
+S_WRTHFX_ADROP1,
+S_WRTHFX_ADROP2,
+S_WRTHFX_ADROP3,
+S_WRTHFX_ADROP4,
+S_WRTHFX_ADEAD1,
+S_WRTHFX_BDROP1,
+S_WRTHFX_BDROP2,
+S_WRTHFX_BDROP3,
+S_WRTHFX_BDEAD1,
+S_MNTR_SPAWN1,
+S_MNTR_SPAWN2,
+S_MNTR_SPAWN3,
+S_MNTR_LOOK1,
+S_MNTR_LOOK2,
+S_MNTR_WALK1,
+S_MNTR_WALK2,
+S_MNTR_WALK3,
+S_MNTR_WALK4,
+S_MNTR_ROAM1,
+S_MNTR_ROAM2,
+S_MNTR_ROAM3,
+S_MNTR_ROAM4,
+S_MNTR_ATK1_1,
+S_MNTR_ATK1_2,
+S_MNTR_ATK1_3,
+S_MNTR_ATK2_1,
+S_MNTR_ATK2_2,
+S_MNTR_ATK2_3,
+S_MNTR_ATK3_1,
+S_MNTR_ATK3_2,
+S_MNTR_ATK3_3,
+S_MNTR_ATK3_4,
+S_MNTR_ATK4_1,
+S_MNTR_PAIN1,
+S_MNTR_PAIN2,
+S_MNTR_DIE1,
+S_MNTR_DIE2,
+S_MNTR_DIE3,
+S_MNTR_DIE4,
+S_MNTR_DIE5,
+S_MNTR_DIE6,
+S_MNTR_DIE7,
+S_MNTR_DIE8,
+S_MNTR_DIE9,
+S_MNTRFX1_1,
+S_MNTRFX1_2,
+S_MNTRFXI1_1,
+S_MNTRFXI1_2,
+S_MNTRFXI1_3,
+S_MNTRFXI1_4,
+S_MNTRFXI1_5,
+S_MNTRFXI1_6,
+S_MNTRFX2_1,
+S_MNTRFXI2_1,
+S_MNTRFXI2_2,
+S_MNTRFXI2_3,
+S_MNTRFXI2_4,
+S_MNTRFXI2_5,
+S_MNTRFX3_1,
+S_MNTRFX3_2,
+S_MNTRFX3_3,
+S_MNTRFX3_4,
+S_MNTRFX3_5,
+S_MNTRFX3_6,
+S_MNTRFX3_7,
+S_MNTRFX3_8,
+S_MNTRFX3_9,
+S_MINOSMOKE1,
+S_MINOSMOKE2,
+S_MINOSMOKE3,
+S_MINOSMOKE4,
+S_MINOSMOKE5,
+S_MINOSMOKE6,
+S_MINOSMOKE7,
+S_MINOSMOKE8,
+S_MINOSMOKE9,
+S_MINOSMOKE0,
+S_MINOSMOKEA,
+S_MINOSMOKEB,
+S_MINOSMOKEC,
+S_MINOSMOKED,
+S_MINOSMOKEE,
+S_MINOSMOKEF,
+S_MINOSMOKEG,
+S_MINOSMOKEX1,
+S_MINOSMOKEX2,
+S_MINOSMOKEX3,
+S_MINOSMOKEX4,
+S_MINOSMOKEX5,
+S_MINOSMOKEX6,
+S_MINOSMOKEX7,
+S_MINOSMOKEX8,
+S_MINOSMOKEX9,
+S_MINOSMOKEX0,
+S_MINOSMOKEXA,
+S_MINOSMOKEXB,
+S_MINOSMOKEXC,
+S_MINOSMOKEXD,
+S_MINOSMOKEXE,
+S_MINOSMOKEXF,
+S_MINOSMOKEXG,
+S_MINOSMOKEXH,
+S_MINOSMOKEXI,
+S_SERPENT_LOOK1,
+S_SERPENT_SWIM1,
+S_SERPENT_SWIM2,
+S_SERPENT_SWIM3,
+S_SERPENT_HUMP1,
+S_SERPENT_HUMP2,
+S_SERPENT_HUMP3,
+S_SERPENT_HUMP4,
+S_SERPENT_HUMP5,
+S_SERPENT_HUMP6,
+S_SERPENT_HUMP7,
+S_SERPENT_HUMP8,
+S_SERPENT_HUMP9,
+S_SERPENT_HUMP10,
+S_SERPENT_HUMP11,
+S_SERPENT_HUMP12,
+S_SERPENT_HUMP13,
+S_SERPENT_HUMP14,
+S_SERPENT_HUMP15,
+S_SERPENT_SURFACE1,
+S_SERPENT_SURFACE2,
+S_SERPENT_SURFACE3,
+S_SERPENT_SURFACE4,
+S_SERPENT_SURFACE5,
+S_SERPENT_DIVE1,
+S_SERPENT_DIVE2,
+S_SERPENT_DIVE3,
+S_SERPENT_DIVE4,
+S_SERPENT_DIVE5,
+S_SERPENT_DIVE6,
+S_SERPENT_DIVE7,
+S_SERPENT_DIVE8,
+S_SERPENT_DIVE9,
+S_SERPENT_DIVE10,
+S_SERPENT_WALK1,
+S_SERPENT_WALK2,
+S_SERPENT_WALK3,
+S_SERPENT_WALK4,
+S_SERPENT_PAIN1,
+S_SERPENT_PAIN2,
+S_SERPENT_ATK1,
+S_SERPENT_ATK2,
+S_SERPENT_MELEE1,
+S_SERPENT_MISSILE1,
+S_SERPENT_DIE1,
+S_SERPENT_DIE2,
+S_SERPENT_DIE3,
+S_SERPENT_DIE4,
+S_SERPENT_DIE5,
+S_SERPENT_DIE6,
+S_SERPENT_DIE7,
+S_SERPENT_DIE8,
+S_SERPENT_DIE9,
+S_SERPENT_DIE10,
+S_SERPENT_DIE11,
+S_SERPENT_DIE12,
+S_SERPENT_XDIE1,
+S_SERPENT_XDIE2,
+S_SERPENT_XDIE3,
+S_SERPENT_XDIE4,
+S_SERPENT_XDIE5,
+S_SERPENT_XDIE6,
+S_SERPENT_XDIE7,
+S_SERPENT_XDIE8,
+S_SERPENT_ICE,
+S_SERPENT_ICE2,
+S_SERPENT_FX1,
+S_SERPENT_FX2,
+S_SERPENT_FX3,
+S_SERPENT_FX4,
+S_SERPENT_FX_X1,
+S_SERPENT_FX_X2,
+S_SERPENT_FX_X3,
+S_SERPENT_FX_X4,
+S_SERPENT_FX_X5,
+S_SERPENT_FX_X6,
+S_SERPENT_HEAD1,
+S_SERPENT_HEAD2,
+S_SERPENT_HEAD3,
+S_SERPENT_HEAD4,
+S_SERPENT_HEAD5,
+S_SERPENT_HEAD6,
+S_SERPENT_HEAD7,
+S_SERPENT_HEAD8,
+S_SERPENT_HEAD_X1,
+S_SERPENT_GIB1_1,
+S_SERPENT_GIB1_2,
+S_SERPENT_GIB1_3,
+S_SERPENT_GIB1_4,
+S_SERPENT_GIB1_5,
+S_SERPENT_GIB1_6,
+S_SERPENT_GIB1_7,
+S_SERPENT_GIB1_8,
+S_SERPENT_GIB1_9,
+S_SERPENT_GIB1_10,
+S_SERPENT_GIB1_11,
+S_SERPENT_GIB1_12,
+S_SERPENT_GIB2_1,
+S_SERPENT_GIB2_2,
+S_SERPENT_GIB2_3,
+S_SERPENT_GIB2_4,
+S_SERPENT_GIB2_5,
+S_SERPENT_GIB2_6,
+S_SERPENT_GIB2_7,
+S_SERPENT_GIB2_8,
+S_SERPENT_GIB2_9,
+S_SERPENT_GIB2_10,
+S_SERPENT_GIB2_11,
+S_SERPENT_GIB2_12,
+S_SERPENT_GIB3_1,
+S_SERPENT_GIB3_2,
+S_SERPENT_GIB3_3,
+S_SERPENT_GIB3_4,
+S_SERPENT_GIB3_5,
+S_SERPENT_GIB3_6,
+S_SERPENT_GIB3_7,
+S_SERPENT_GIB3_8,
+S_SERPENT_GIB3_9,
+S_SERPENT_GIB3_10,
+S_SERPENT_GIB3_11,
+S_SERPENT_GIB3_12,
+S_BISHOP_LOOK1,
+S_BISHOP_DECIDE,
+S_BISHOP_BLUR1,
+S_BISHOP_BLUR2,
+S_BISHOP_WALK1,
+S_BISHOP_WALK2,
+S_BISHOP_WALK3,
+S_BISHOP_WALK4,
+S_BISHOP_WALK5,
+S_BISHOP_WALK6,
+S_BISHOP_ATK1,
+S_BISHOP_ATK2,
+S_BISHOP_ATK3,
+S_BISHOP_ATK4,
+S_BISHOP_ATK5,
+S_BISHOP_PAIN1,
+S_BISHOP_PAIN2,
+S_BISHOP_PAIN3,
+S_BISHOP_PAIN4,
+S_BISHOP_PAIN5,
+S_BISHOP_DEATH1,
+S_BISHOP_DEATH2,
+S_BISHOP_DEATH3,
+S_BISHOP_DEATH4,
+S_BISHOP_DEATH5,
+S_BISHOP_DEATH6,
+S_BISHOP_DEATH7,
+S_BISHOP_DEATH8,
+S_BISHOP_DEATH9,
+S_BISHOP_DEATH10,
+S_BISHOP_ICE,
+S_BISHOP_ICE2,
+S_BISHOP_PUFF1,
+S_BISHOP_PUFF2,
+S_BISHOP_PUFF3,
+S_BISHOP_PUFF4,
+S_BISHOP_PUFF5,
+S_BISHOP_PUFF6,
+S_BISHOP_PUFF7,
+S_BISHOPBLUR1,
+S_BISHOPBLUR2,
+S_BISHOPPAINBLUR1,
+S_BISHFX1_1,
+S_BISHFX1_2,
+S_BISHFX1_3,
+S_BISHFX1_4,
+S_BISHFX1_5,
+S_BISHFXI1_1,
+S_BISHFXI1_2,
+S_BISHFXI1_3,
+S_BISHFXI1_4,
+S_BISHFXI1_5,
+S_BISHFXI1_6,
+S_DRAGON_LOOK1,
+S_DRAGON_INIT,
+S_DRAGON_INIT2,
+S_DRAGON_INIT3,
+S_DRAGON_WALK1,
+S_DRAGON_WALK2,
+S_DRAGON_WALK3,
+S_DRAGON_WALK4,
+S_DRAGON_WALK5,
+S_DRAGON_WALK6,
+S_DRAGON_WALK7,
+S_DRAGON_WALK8,
+S_DRAGON_WALK9,
+S_DRAGON_WALK10,
+S_DRAGON_WALK11,
+S_DRAGON_WALK12,
+S_DRAGON_ATK1,
+S_DRAGON_PAIN1,
+S_DRAGON_DEATH1,
+S_DRAGON_DEATH2,
+S_DRAGON_DEATH3,
+S_DRAGON_DEATH4,
+S_DRAGON_CRASH1,
+S_DRAGON_CRASH2,
+S_DRAGON_CRASH3,
+S_DRAGON_FX1_1,
+S_DRAGON_FX1_2,
+S_DRAGON_FX1_3,
+S_DRAGON_FX1_4,
+S_DRAGON_FX1_5,
+S_DRAGON_FX1_6,
+S_DRAGON_FX1_X1,
+S_DRAGON_FX1_X2,
+S_DRAGON_FX1_X3,
+S_DRAGON_FX1_X4,
+S_DRAGON_FX1_X5,
+S_DRAGON_FX1_X6,
+S_DRAGON_FX2_1,
+S_DRAGON_FX2_2,
+S_DRAGON_FX2_3,
+S_DRAGON_FX2_4,
+S_DRAGON_FX2_5,
+S_DRAGON_FX2_6,
+S_DRAGON_FX2_7,
+S_DRAGON_FX2_8,
+S_DRAGON_FX2_9,
+S_DRAGON_FX2_10,
+S_DRAGON_FX2_11,
+S_ARMOR_1,
+S_ARMOR_2,
+S_ARMOR_3,
+S_ARMOR_4,
+S_MANA1_1,
+S_MANA1_2,
+S_MANA1_3,
+S_MANA1_4,
+S_MANA1_5,
+S_MANA1_6,
+S_MANA1_7,
+S_MANA1_8,
+S_MANA1_9,
+S_MANA2_1,
+S_MANA2_2,
+S_MANA2_3,
+S_MANA2_4,
+S_MANA2_5,
+S_MANA2_6,
+S_MANA2_7,
+S_MANA2_8,
+S_MANA2_9,
+S_MANA2_10,
+S_MANA2_11,
+S_MANA2_12,
+S_MANA2_13,
+S_MANA2_14,
+S_MANA2_15,
+S_MANA2_16,
+S_MANA3_1,
+S_MANA3_2,
+S_MANA3_3,
+S_MANA3_4,
+S_MANA3_5,
+S_MANA3_6,
+S_MANA3_7,
+S_MANA3_8,
+S_MANA3_9,
+S_MANA3_10,
+S_MANA3_11,
+S_MANA3_12,
+S_MANA3_13,
+S_MANA3_14,
+S_MANA3_15,
+S_MANA3_16,
+S_KEY1,
+S_KEY2,
+S_KEY3,
+S_KEY4,
+S_KEY5,
+S_KEY6,
+S_KEY7,
+S_KEY8,
+S_KEY9,
+S_KEYA,
+S_KEYB,
+S_SND_WIND1,
+S_SND_WIND2,
+S_SND_WATERFALL,
+S_ETTIN_LOOK1,
+S_ETTIN_LOOK2,
+S_ETTIN_CHASE1,
+S_ETTIN_CHASE2,
+S_ETTIN_CHASE3,
+S_ETTIN_CHASE4,
+S_ETTIN_PAIN1,
+S_ETTIN_ATK1_1,
+S_ETTIN_ATK1_2,
+S_ETTIN_ATK1_3,
+S_ETTIN_DEATH1_1,
+S_ETTIN_DEATH1_2,
+S_ETTIN_DEATH1_3,
+S_ETTIN_DEATH1_4,
+S_ETTIN_DEATH1_5,
+S_ETTIN_DEATH1_6,
+S_ETTIN_DEATH1_7,
+S_ETTIN_DEATH1_8,
+S_ETTIN_DEATH1_9,
+S_ETTIN_DEATH2_1,
+S_ETTIN_DEATH2_2,
+S_ETTIN_DEATH2_3,
+S_ETTIN_DEATH2_4,
+S_ETTIN_DEATH2_5,
+S_ETTIN_DEATH2_6,
+S_ETTIN_DEATH2_7,
+S_ETTIN_DEATH2_8,
+S_ETTIN_DEATH2_9,
+S_ETTIN_DEATH2_0,
+S_ETTIN_DEATH2_A,
+S_ETTIN_DEATH2_B,
+S_ETTIN_ICE1,
+S_ETTIN_ICE2,
+S_ETTIN_MACE1,
+S_ETTIN_MACE2,
+S_ETTIN_MACE3,
+S_ETTIN_MACE4,
+S_ETTIN_MACE5,
+S_ETTIN_MACE6,
+S_ETTIN_MACE7,
+S_FIRED_SPAWN1,
+S_FIRED_LOOK1,
+S_FIRED_LOOK2,
+S_FIRED_LOOK3,
+S_FIRED_LOOK4,
+S_FIRED_LOOK5,
+S_FIRED_LOOK6,
+S_FIRED_LOOK7,
+S_FIRED_LOOK8,
+S_FIRED_LOOK9,
+S_FIRED_LOOK0,
+S_FIRED_LOOKA,
+S_FIRED_LOOKB,
+S_FIRED_WALK1,
+S_FIRED_WALK2,
+S_FIRED_WALK3,
+S_FIRED_PAIN1,
+S_FIRED_ATTACK1,
+S_FIRED_ATTACK2,
+S_FIRED_ATTACK3,
+S_FIRED_ATTACK4,
+S_FIRED_DEATH1,
+S_FIRED_DEATH2,
+S_FIRED_DEATH3,
+S_FIRED_DEATH4,
+S_FIRED_XDEATH1,
+S_FIRED_XDEATH2,
+S_FIRED_XDEATH3,
+S_FIRED_ICE1,
+S_FIRED_ICE2,
+S_FIRED_CORPSE1,
+S_FIRED_CORPSE2,
+S_FIRED_CORPSE3,
+S_FIRED_CORPSE4,
+S_FIRED_CORPSE5,
+S_FIRED_CORPSE6,
+S_FIRED_RDROP1,
+S_FIRED_RDEAD1_1,
+S_FIRED_RDEAD1_2,
+S_FIRED_RDROP2,
+S_FIRED_RDEAD2_1,
+S_FIRED_RDEAD2_2,
+S_FIRED_RDROP3,
+S_FIRED_RDEAD3_1,
+S_FIRED_RDEAD3_2,
+S_FIRED_RDROP4,
+S_FIRED_RDEAD4_1,
+S_FIRED_RDEAD4_2,
+S_FIRED_RDROP5,
+S_FIRED_RDEAD5_1,
+S_FIRED_RDEAD5_2,
+S_FIRED_FX6_1,
+S_FIRED_FX6_2,
+S_FIRED_FX6_3,
+S_FIRED_FX6_4,
+S_FIRED_FX6_5,
+S_ICEGUY_LOOK,
+S_ICEGUY_DORMANT,
+S_ICEGUY_WALK1,
+S_ICEGUY_WALK2,
+S_ICEGUY_WALK3,
+S_ICEGUY_WALK4,
+S_ICEGUY_ATK1,
+S_ICEGUY_ATK2,
+S_ICEGUY_ATK3,
+S_ICEGUY_ATK4,
+S_ICEGUY_PAIN1,
+S_ICEGUY_DEATH,
+S_ICEGUY_FX1,
+S_ICEGUY_FX2,
+S_ICEGUY_FX3,
+S_ICEGUY_FX_X1,
+S_ICEGUY_FX_X2,
+S_ICEGUY_FX_X3,
+S_ICEGUY_FX_X4,
+S_ICEGUY_FX_X5,
+S_ICEFX_PUFF1,
+S_ICEFX_PUFF2,
+S_ICEFX_PUFF3,
+S_ICEFX_PUFF4,
+S_ICEFX_PUFF5,
+S_ICEGUY_FX2_1,
+S_ICEGUY_FX2_2,
+S_ICEGUY_FX2_3,
+S_ICEGUY_BIT1,
+S_ICEGUY_BIT2,
+S_ICEGUY_WISP1_1,
+S_ICEGUY_WISP1_2,
+S_ICEGUY_WISP1_3,
+S_ICEGUY_WISP1_4,
+S_ICEGUY_WISP1_5,
+S_ICEGUY_WISP1_6,
+S_ICEGUY_WISP1_7,
+S_ICEGUY_WISP1_8,
+S_ICEGUY_WISP1_9,
+S_ICEGUY_WISP2_1,
+S_ICEGUY_WISP2_2,
+S_ICEGUY_WISP2_3,
+S_ICEGUY_WISP2_4,
+S_ICEGUY_WISP2_5,
+S_ICEGUY_WISP2_6,
+S_ICEGUY_WISP2_7,
+S_ICEGUY_WISP2_8,
+S_ICEGUY_WISP2_9,
+S_FIGHTER,
+S_FIGHTER2,
+S_FIGHTERLOOK,
+S_FIGHTER_RUN1,
+S_FIGHTER_RUN2,
+S_FIGHTER_RUN3,
+S_FIGHTER_RUN4,
+S_FIGHTER_ATK1,
+S_FIGHTER_ATK2,
+S_FIGHTER_PAIN,
+S_FIGHTER_PAIN2,
+S_FIGHTER_DIE1,
+S_FIGHTER_DIE2,
+S_FIGHTER_DIE3,
+S_FIGHTER_DIE4,
+S_FIGHTER_DIE5,
+S_FIGHTER_DIE6,
+S_FIGHTER_DIE7,
+S_FIGHTER_XDIE1,
+S_FIGHTER_XDIE2,
+S_FIGHTER_XDIE3,
+S_FIGHTER_XDIE4,
+S_FIGHTER_XDIE5,
+S_FIGHTER_XDIE6,
+S_FIGHTER_XDIE7,
+S_FIGHTER_XDIE8,
+S_FIGHTER_ICE,
+S_FIGHTER_ICE2,
+S_CLERIC,
+S_CLERIC2,
+S_CLERICLOOK,
+S_CLERIC_RUN1,
+S_CLERIC_RUN2,
+S_CLERIC_RUN3,
+S_CLERIC_RUN4,
+S_CLERIC_ATK1,
+S_CLERIC_ATK2,
+S_CLERIC_ATK3,
+S_CLERIC_PAIN,
+S_CLERIC_PAIN2,
+S_CLERIC_DIE1,
+S_CLERIC_DIE2,
+S_CLERIC_DIE3,
+S_CLERIC_DIE4,
+S_CLERIC_DIE5,
+S_CLERIC_DIE6,
+S_CLERIC_DIE7,
+S_CLERIC_DIE8,
+S_CLERIC_DIE9,
+S_CLERIC_XDIE1,
+S_CLERIC_XDIE2,
+S_CLERIC_XDIE3,
+S_CLERIC_XDIE4,
+S_CLERIC_XDIE5,
+S_CLERIC_XDIE6,
+S_CLERIC_XDIE7,
+S_CLERIC_XDIE8,
+S_CLERIC_XDIE9,
+S_CLERIC_XDIE10,
+S_CLERIC_ICE,
+S_CLERIC_ICE2,
+S_MAGE,
+S_MAGE2,
+S_MAGELOOK,
+S_MAGE_RUN1,
+S_MAGE_RUN2,
+S_MAGE_RUN3,
+S_MAGE_RUN4,
+S_MAGE_ATK1,
+S_MAGE_ATK2,
+S_MAGE_PAIN,
+S_MAGE_PAIN2,
+S_MAGE_DIE1,
+S_MAGE_DIE2,
+S_MAGE_DIE3,
+S_MAGE_DIE4,
+S_MAGE_DIE5,
+S_MAGE_DIE6,
+S_MAGE_DIE7,
+S_MAGE_XDIE1,
+S_MAGE_XDIE2,
+S_MAGE_XDIE3,
+S_MAGE_XDIE4,
+S_MAGE_XDIE5,
+S_MAGE_XDIE6,
+S_MAGE_XDIE7,
+S_MAGE_XDIE8,
+S_MAGE_XDIE9,
+S_MAGE_ICE,
+S_MAGE_ICE2,
+S_SORC_SPAWN1,
+S_SORC_SPAWN2,
+S_SORC_LOOK1,
+S_SORC_WALK1,
+S_SORC_WALK2,
+S_SORC_WALK3,
+S_SORC_WALK4,
+S_SORC_PAIN1,
+S_SORC_PAIN2,
+S_SORC_ATK2_1,
+S_SORC_ATK2_2,
+S_SORC_ATK2_3,
+S_SORC_ATTACK1,
+S_SORC_ATTACK2,
+S_SORC_ATTACK3,
+S_SORC_ATTACK4,
+S_SORC_ATTACK5,
+S_SORC_DIE1,
+S_SORC_DIE2,
+S_SORC_DIE3,
+S_SORC_DIE4,
+S_SORC_DIE5,
+S_SORC_DIE6,
+S_SORC_DIE7,
+S_SORC_DIE8,
+S_SORC_DIE9,
+S_SORC_DIE0,
+S_SORC_DIEA,
+S_SORC_DIEB,
+S_SORC_DIEC,
+S_SORC_DIED,
+S_SORC_DIEE,
+S_SORC_DIEF,
+S_SORC_DIEG,
+S_SORC_DIEH,
+S_SORC_DIEI,
+S_SORCBALL1_1,
+S_SORCBALL1_2,
+S_SORCBALL1_3,
+S_SORCBALL1_4,
+S_SORCBALL1_5,
+S_SORCBALL1_6,
+S_SORCBALL1_7,
+S_SORCBALL1_8,
+S_SORCBALL1_9,
+S_SORCBALL1_0,
+S_SORCBALL1_A,
+S_SORCBALL1_B,
+S_SORCBALL1_C,
+S_SORCBALL1_D,
+S_SORCBALL1_E,
+S_SORCBALL1_F,
+S_SORCBALL1_D1,
+S_SORCBALL1_D2,
+S_SORCBALL1_D5,
+S_SORCBALL1_D6,
+S_SORCBALL1_D7,
+S_SORCBALL1_D8,
+S_SORCBALL1_D9,
+S_SORCBALL2_1,
+S_SORCBALL2_2,
+S_SORCBALL2_3,
+S_SORCBALL2_4,
+S_SORCBALL2_5,
+S_SORCBALL2_6,
+S_SORCBALL2_7,
+S_SORCBALL2_8,
+S_SORCBALL2_9,
+S_SORCBALL2_0,
+S_SORCBALL2_A,
+S_SORCBALL2_B,
+S_SORCBALL2_C,
+S_SORCBALL2_D,
+S_SORCBALL2_E,
+S_SORCBALL2_F,
+S_SORCBALL2_D1,
+S_SORCBALL2_D2,
+S_SORCBALL2_D5,
+S_SORCBALL2_D6,
+S_SORCBALL2_D7,
+S_SORCBALL2_D8,
+S_SORCBALL2_D9,
+S_SORCBALL3_1,
+S_SORCBALL3_2,
+S_SORCBALL3_3,
+S_SORCBALL3_4,
+S_SORCBALL3_5,
+S_SORCBALL3_6,
+S_SORCBALL3_7,
+S_SORCBALL3_8,
+S_SORCBALL3_9,
+S_SORCBALL3_0,
+S_SORCBALL3_A,
+S_SORCBALL3_B,
+S_SORCBALL3_C,
+S_SORCBALL3_D,
+S_SORCBALL3_E,
+S_SORCBALL3_F,
+S_SORCBALL3_D1,
+S_SORCBALL3_D2,
+S_SORCBALL3_D5,
+S_SORCBALL3_D6,
+S_SORCBALL3_D7,
+S_SORCBALL3_D8,
+S_SORCBALL3_D9,
+S_SORCFX1_1,
+S_SORCFX1_2,
+S_SORCFX1_3,
+S_SORCFX1_4,
+S_SORCFX1_D1,
+S_SORCFX1_D2,
+S_SORCFX1_D3,
+S_SORCFX2_SPLIT1,
+S_SORCFX2_ORBIT1,
+S_SORCFX2_ORBIT2,
+S_SORCFX2_ORBIT3,
+S_SORCFX2_ORBIT4,
+S_SORCFX2_ORBIT5,
+S_SORCFX2_ORBIT6,
+S_SORCFX2_ORBIT7,
+S_SORCFX2_ORBIT8,
+S_SORCFX2_ORBIT9,
+S_SORCFX2_ORBIT0,
+S_SORCFX2_ORBITA,
+S_SORCFX2_ORBITB,
+S_SORCFX2_ORBITC,
+S_SORCFX2_ORBITD,
+S_SORCFX2_ORBITE,
+S_SORCFX2_ORBITF,
+S_SORCFX2T1,
+S_SORCFX3_1,
+S_SORCFX3_2,
+S_SORCFX3_3,
+S_BISHMORPH1,
+S_BISHMORPHA,
+S_BISHMORPHB,
+S_BISHMORPHC,
+S_BISHMORPHD,
+S_BISHMORPHE,
+S_BISHMORPHF,
+S_BISHMORPHG,
+S_BISHMORPHH,
+S_BISHMORPHI,
+S_BISHMORPHJ,
+S_SORCFX3_EXP1,
+S_SORCFX3_EXP2,
+S_SORCFX3_EXP3,
+S_SORCFX3_EXP4,
+S_SORCFX3_EXP5,
+S_SORCFX4_1,
+S_SORCFX4_2,
+S_SORCFX4_3,
+S_SORCFX4_D1,
+S_SORCFX4_D2,
+S_SORCFX4_D3,
+S_SORCFX4_D4,
+S_SORCFX4_D5,
+S_SORCSPARK1,
+S_SORCSPARK2,
+S_SORCSPARK3,
+S_SORCSPARK4,
+S_SORCSPARK5,
+S_SORCSPARK6,
+S_SORCSPARK7,
+S_BLASTEFFECT1,
+S_BLASTEFFECT2,
+S_BLASTEFFECT3,
+S_BLASTEFFECT4,
+S_BLASTEFFECT5,
+S_BLASTEFFECT6,
+S_BLASTEFFECT7,
+S_BLASTEFFECT8,
+S_BLASTEFFECT9,
+S_WATERDRIP1,
+S_KORAX_LOOK1,
+S_KORAX_CHASE1,
+S_KORAX_CHASE2,
+S_KORAX_CHASE3,
+S_KORAX_CHASE4,
+S_KORAX_CHASE5,
+S_KORAX_CHASE6,
+S_KORAX_CHASE7,
+S_KORAX_CHASE8,
+S_KORAX_CHASE9,
+S_KORAX_CHASE0,
+S_KORAX_CHASEA,
+S_KORAX_CHASEB,
+S_KORAX_CHASEC,
+S_KORAX_CHASED,
+S_KORAX_CHASEE,
+S_KORAX_CHASEF,
+S_KORAX_PAIN1,
+S_KORAX_PAIN2,
+S_KORAX_ATTACK1,
+S_KORAX_ATTACK2,
+S_KORAX_MISSILE1,
+S_KORAX_MISSILE2,
+S_KORAX_MISSILE3,
+S_KORAX_COMMAND1,
+S_KORAX_COMMAND2,
+S_KORAX_COMMAND3,
+S_KORAX_COMMAND4,
+S_KORAX_COMMAND5,
+S_KORAX_DEATH1,
+S_KORAX_DEATH2,
+S_KORAX_DEATH3,
+S_KORAX_DEATH4,
+S_KORAX_DEATH5,
+S_KORAX_DEATH6,
+S_KORAX_DEATH7,
+S_KORAX_DEATH8,
+S_KORAX_DEATH9,
+S_KORAX_DEATH0,
+S_KORAX_DEATHA,
+S_KORAX_DEATHB,
+S_KORAX_DEATHC,
+S_KORAX_DEATHD,
+S_KSPIRIT_ROAM1,
+S_KSPIRIT_ROAM2,
+S_KSPIRIT_DEATH1,
+S_KSPIRIT_DEATH2,
+S_KSPIRIT_DEATH3,
+S_KSPIRIT_DEATH4,
+S_KSPIRIT_DEATH5,
+S_KSPIRIT_DEATH6,
+S_KBOLT1,
+S_KBOLT2,
+S_KBOLT3,
+S_KBOLT4,
+S_KBOLT5,
+S_KBOLT6,
+S_KBOLT7,
+S_SPAWNBATS1,
+S_SPAWNBATS2,
+S_SPAWNBATS3,
+S_SPAWNBATS_OFF,
+S_BAT1,
+S_BAT2,
+S_BAT3,
+S_BAT_DEATH,
+#ifdef ASSASSIN
+S_KATARREADY,
+S_KATARDOWN,
+S_KATARUP,
+S_KATARATK1_1,
+S_KATARATK1_2,
+S_KATARATK1_3,
+S_KATARATK1_4,
+S_KATARATK1_5,
+S_KATARATK2_1,
+S_KATARATK2_2,
+S_KATARATK2_3,
+S_KATARATK2_4,
+S_KATARATK2_5,
+S_KATARATK2_6,
+S_KATARATK2_7,
+S_KATARATK2_8,
+S_KATARATK2_9,
+S_ACROSSREADY,
+S_ACROSSREADY1,
+S_ACROSSREADY2,
+S_ACROSSREADY3,
+S_ACROSSREADY4,
+S_ACROSSREADY5,
+S_ACROSSREADY6,
+S_ACROSSREADY7,
+S_ACROSSREADY8,
+S_ACROSSREADY9,
+S_ACROSSBLINK1,
+S_ACROSSBLINK2,
+S_ACROSSBLINK3,
+S_ACROSSBLINK4,
+S_ACROSSBLINK5,
+S_ACROSSBLINK6,
+S_ACROSSBLINK7,
+S_ACROSSBLINK8,
+S_ACROSSBLINK9,
+S_ACROSSBLINK10,
+S_ACROSSBLINK11,
+S_ACROSSDOWN,
+S_ACROSSDOWN2,
+S_ACROSSDOWN3,
+S_ACROSSUP,
+S_ACROSSATK_1,
+S_ACROSSATK_2,
+S_ACROSSATK_3,
+S_ACROSSATK_4,
+S_ACROSSATK_5,
+S_ACROSSATK_6,
+/* S_ACROSSATK2_1, jim not used (melee attack) */
+S_ACROSS_MISSILE1,
+S_ACROSS_MISSILE2,
+S_ACROSS_MISSILE3,
+S_ACROSS_MISSILE4,
+S_ACROSS_MISSILE_X1,
+S_ACROSS_MISSILE_X2,
+S_ACROSS_MISSILE_X3,
+S_ACROSS_MISSILE_X4,
+S_AGRENREADY,
+S_AGRENDOWN,
+S_AGRENUP,
+S_AGRENATK_1,
+S_AGRENATK_2,
+S_AGRENATK_3,
+S_AGRENATK_4,
+S_AGRENPUFF1,
+S_AGRENPUFF2,
+S_AGRENPUFF3,
+S_AGRENPUFF4,
+S_AGRENPUFF5,
+S_AGRENSMOKE1,
+S_AGRENSMOKE2,
+S_AGRENSMOKE3,
+S_AGRENSMOKE4,
+S_AGREN_MISSILE1,
+S_AGREN_MISSILE2,
+S_ASTAFFREADY,
+/*S_ASTAFFREADY1, jim No such state! */
+S_ASTAFFREADY2,
+S_ASTAFFREADY3,
+S_ASTAFFREADY4,
+S_ASTAFFREADY5,
+S_ASTAFFREADY6,
+S_ASTAFFREADY7,
+S_ASTAFFREADY8,
+S_ASTAFFREADY9,
+S_ASTAFFREADY10,
+S_ASTAFFREADY11,
+S_ASTAFFREADY12,
+S_ASTAFFREADY13,
+S_ASTAFFREADY14,
+S_ASTAFFREADY15,
+S_ASTAFFREADY16,
+S_ASTAFFREADY17,
+S_ASTAFFREADY18,
+S_ASTAFFREADY19,
+S_ASTAFFREADY20,
+S_ASTAFFREADY21,
+S_ASTAFFREADY22,
+S_ASTAFFREADY23,
+S_ASTAFFREADY24,
+S_ASTAFFREADY25,
+S_ASTAFFREADY26,
+S_ASTAFFREADY27,
+S_ASTAFFREADY28,
+S_ASTAFFREADY29,
+S_ASTAFFREADY30,
+S_ASTAFFREADY31,
+S_ASTAFFREADY32,
+S_ASTAFFREADY33,
+S_ASTAFFREADY34,
+S_ASTAFFREADY35,
+S_ASTAFFDOWN,
+S_ASTAFFUP,
+S_ASTAFFATK_1,
+S_ASTAFFATK_2,
+S_ASTAFFATK_3,
+S_ASTAFFATK_4,
+S_ASTAFFATK_5,
+S_ASTAFFATK_6,
+S_ASTAFFATK_7,
+S_ASTAFF_FX1_1,
+S_ASTAFF_FX1_2,
+S_ASTAFF_FX1_3,
+S_ASTAFF_FX1_4,
+S_ASTAFF_FX1_5,
+S_ASTAFF_FX1_6,
+S_ASTAFF_FX_X1,
+S_ASTAFF_FX_X2,
+S_ASTAFF_FX_X3,
+S_ASTAFF_FX_X4,
+S_ASTAFF_FX_X5,
+S_ASTAFF_FX_X6,
+S_ASTAFF_FX_X7,
+S_ASTAFF_FX_X8,
+S_ASTAFF_FX_X9,
+S_ASTAFF_FX_X10,
+S_ASTAFF_FX2_1,
+S_ASTAFF_FX2_2,
+S_ASTAFF_FX2_3,
+S_ASTAFF_FX2_4,
+S_ASTAFF_FX2_X1,
+S_ASTAFF_FX2_X2,
+S_ASTAFF_FX2_X3,
+S_ASTAFF_FX2_X4,
+S_ASTAFF_FX2_X5,
+S_APLAY,
+S_APLAY_RUN1,
+S_APLAY_RUN2,
+S_APLAY_RUN3,
+S_APLAY_RUN4,
+S_APLAY_ATK1,
+S_APLAY_ATK2,
+S_APLAY_ATK3,
+S_APLAY_PAIN,
+S_APLAY_PAIN2,
+S_APLAY_DIE1,
+S_APLAY_DIE2,
+S_APLAY_DIE3,
+S_APLAY_DIE4,
+S_APLAY_DIE5,
+S_APLAY_DIE6,
+S_APLAY_DIE7,
+S_APLAY_DIE8,
+S_APLAY_DIE9,
+S_APLAY_XDIE1,
+S_APLAY_XDIE2,
+S_APLAY_XDIE3,
+S_APLAY_XDIE4,
+S_APLAY_XDIE5,
+S_APLAY_XDIE6,
+S_APLAY_XDIE7,
+S_APLAY_XDIE8,
+S_APLAY_XDIE9,
+S_APLAY_XDIE10,
+S_APLAY_ICE,
+S_APLAY_ICE2,
+#endif /* ASSASSIN */
+NUMSTATES
+} statenum_t;
+
+typedef struct
+{
+ spritenum_t sprite;
+ int32_t frame;
+ int32_t tics;
+ void (*action) (void*,void*);
+ statenum_t nextstate;
+ int32_t misc1, misc2;
+} state_t;
+
+extern state_t states[NUMSTATES];
+extern const char *sprnames[NUMSPRITES];
+
+
+
+typedef enum {
+MT_MAPSPOT,
+MT_MAPSPOTGRAVITY,
+MT_FIREBALL1,
+MT_ARROW,
+MT_DART,
+MT_POISONDART,
+MT_RIPPERBALL,
+MT_PROJECTILE_BLADE,
+MT_ICESHARD,
+MT_FLAME_SMALL_TEMP,
+MT_FLAME_LARGE_TEMP,
+MT_FLAME_SMALL,
+MT_FLAME_LARGE,
+MT_HEALINGBOTTLE,
+MT_HEALTHFLASK,
+MT_ARTIFLY,
+MT_ARTIINVULNERABILITY,
+MT_SUMMONMAULATOR,
+MT_SUMMON_FX,
+MT_THRUSTFLOOR_UP,
+MT_THRUSTFLOOR_DOWN,
+MT_TELEPORTOTHER,
+MT_TELOTHER_FX1,
+MT_TELOTHER_FX2,
+MT_TELOTHER_FX3,
+MT_TELOTHER_FX4,
+MT_TELOTHER_FX5,
+MT_DIRT1,
+MT_DIRT2,
+MT_DIRT3,
+MT_DIRT4,
+MT_DIRT5,
+MT_DIRT6,
+MT_DIRTCLUMP,
+MT_ROCK1,
+MT_ROCK2,
+MT_ROCK3,
+MT_FOGSPAWNER,
+MT_FOGPATCHS,
+MT_FOGPATCHM,
+MT_FOGPATCHL,
+MT_QUAKE_FOCUS,
+MT_SGSHARD1,
+MT_SGSHARD2,
+MT_SGSHARD3,
+MT_SGSHARD4,
+MT_SGSHARD5,
+MT_SGSHARD6,
+MT_SGSHARD7,
+MT_SGSHARD8,
+MT_SGSHARD9,
+MT_SGSHARD0,
+MT_ARTIEGG,
+MT_EGGFX,
+MT_ARTISUPERHEAL,
+MT_ZWINGEDSTATUENOSKULL,
+MT_ZGEMPEDESTAL,
+MT_ARTIPUZZSKULL,
+MT_ARTIPUZZGEMBIG,
+MT_ARTIPUZZGEMRED,
+MT_ARTIPUZZGEMGREEN1,
+MT_ARTIPUZZGEMGREEN2,
+MT_ARTIPUZZGEMBLUE1,
+MT_ARTIPUZZGEMBLUE2,
+MT_ARTIPUZZBOOK1,
+MT_ARTIPUZZBOOK2,
+MT_ARTIPUZZSKULL2,
+MT_ARTIPUZZFWEAPON,
+MT_ARTIPUZZCWEAPON,
+MT_ARTIPUZZMWEAPON,
+MT_ARTIPUZZGEAR,
+MT_ARTIPUZZGEAR2,
+MT_ARTIPUZZGEAR3,
+MT_ARTIPUZZGEAR4,
+MT_ARTITORCH,
+MT_FIREBOMB,
+MT_ARTITELEPORT,
+MT_ARTIPOISONBAG,
+MT_POISONBAG,
+MT_POISONCLOUD,
+MT_THROWINGBOMB,
+MT_SPEEDBOOTS,
+MT_BOOSTMANA,
+MT_BOOSTARMOR,
+MT_BLASTRADIUS,
+MT_HEALRADIUS,
+MT_SPLASH,
+MT_SPLASHBASE,
+MT_LAVASPLASH,
+MT_LAVASMOKE,
+MT_SLUDGECHUNK,
+MT_SLUDGESPLASH,
+MT_MISC0,
+MT_MISC1,
+MT_MISC2,
+MT_MISC3,
+MT_MISC4,
+MT_MISC5,
+MT_MISC6,
+MT_MISC7,
+MT_MISC8,
+MT_TREEDESTRUCTIBLE,
+MT_MISC9,
+MT_MISC10,
+MT_MISC11,
+MT_MISC12,
+MT_MISC13,
+MT_MISC14,
+MT_MISC15,
+MT_MISC16,
+MT_MISC17,
+MT_MISC18,
+MT_MISC19,
+MT_MISC20,
+MT_MISC21,
+MT_MISC22,
+MT_MISC23,
+MT_MISC24,
+MT_MISC25,
+MT_MISC26,
+MT_MISC27,
+MT_MISC28,
+MT_MISC29,
+MT_MISC30,
+MT_MISC31,
+MT_MISC32,
+MT_MISC33,
+MT_MISC34,
+MT_MISC35,
+MT_MISC36,
+MT_MISC37,
+MT_MISC38,
+MT_MISC39,
+MT_MISC40,
+MT_MISC41,
+MT_MISC42,
+MT_MISC43,
+MT_MISC44,
+MT_MISC45,
+MT_MISC46,
+MT_MISC47,
+MT_MISC48,
+MT_MISC49,
+MT_MISC50,
+MT_MISC51,
+MT_MISC52,
+MT_MISC53,
+MT_MISC54,
+MT_MISC55,
+MT_MISC56,
+MT_MISC57,
+MT_MISC58,
+MT_MISC59,
+MT_MISC60,
+MT_MISC61,
+MT_MISC62,
+MT_MISC63,
+MT_MISC64,
+MT_MISC65,
+MT_MISC66,
+MT_MISC67,
+MT_MISC68,
+MT_MISC69,
+MT_MISC70,
+MT_MISC71,
+MT_MISC72,
+MT_MISC73,
+MT_MISC74,
+MT_MISC75,
+MT_MISC76,
+MT_POTTERY1,
+MT_POTTERY2,
+MT_POTTERY3,
+MT_POTTERYBIT1,
+MT_MISC77,
+MT_ZLYNCHED_NOHEART,
+MT_MISC78,
+MT_CORPSEBIT,
+MT_CORPSEBLOODDRIP,
+MT_BLOODPOOL,
+MT_MISC79,
+MT_MISC80,
+MT_LEAF1,
+MT_LEAF2,
+MT_ZTWINEDTORCH,
+MT_ZTWINEDTORCH_UNLIT,
+MT_BRIDGE,
+MT_BRIDGEBALL,
+MT_ZWALLTORCH,
+MT_ZWALLTORCH_UNLIT,
+MT_ZBARREL,
+MT_ZSHRUB1,
+MT_ZSHRUB2,
+MT_ZBUCKET,
+MT_ZPOISONSHROOM,
+MT_ZFIREBULL,
+MT_ZFIREBULL_UNLIT,
+MT_FIRETHING,
+MT_BRASSTORCH,
+MT_ZSUITOFARMOR,
+MT_ZARMORCHUNK,
+MT_ZBELL,
+MT_ZBLUE_CANDLE,
+MT_ZIRON_MAIDEN,
+MT_ZXMAS_TREE,
+MT_ZCAULDRON,
+MT_ZCAULDRON_UNLIT,
+MT_ZCHAINBIT32,
+MT_ZCHAINBIT64,
+MT_ZCHAINEND_HEART,
+MT_ZCHAINEND_HOOK1,
+MT_ZCHAINEND_HOOK2,
+MT_ZCHAINEND_SPIKE,
+MT_ZCHAINEND_SKULL,
+MT_TABLE_SHIT1,
+MT_TABLE_SHIT2,
+MT_TABLE_SHIT3,
+MT_TABLE_SHIT4,
+MT_TABLE_SHIT5,
+MT_TABLE_SHIT6,
+MT_TABLE_SHIT7,
+MT_TABLE_SHIT8,
+MT_TABLE_SHIT9,
+MT_TABLE_SHIT10,
+MT_TFOG,
+MT_MISC81,
+MT_TELEPORTMAN,
+MT_PUNCHPUFF,
+MT_FW_AXE,
+MT_AXEPUFF,
+MT_AXEPUFF_GLOW,
+MT_AXEBLOOD,
+MT_FW_HAMMER,
+MT_HAMMER_MISSILE,
+MT_HAMMERPUFF,
+MT_FSWORD_MISSILE,
+MT_FSWORD_FLAME,
+MT_CW_SERPSTAFF,
+MT_CSTAFF_MISSILE,
+MT_CSTAFFPUFF,
+MT_CW_FLAME,
+MT_CFLAMEFLOOR,
+MT_FLAMEPUFF,
+MT_FLAMEPUFF2,
+MT_CIRCLEFLAME,
+MT_CFLAME_MISSILE,
+MT_HOLY_FX,
+MT_HOLY_TAIL,
+MT_HOLY_PUFF,
+MT_HOLY_MISSILE,
+MT_HOLY_MISSILE_PUFF,
+MT_MWANDPUFF,
+MT_MWANDSMOKE,
+MT_MWAND_MISSILE,
+MT_MW_LIGHTNING,
+MT_LIGHTNING_CEILING,
+MT_LIGHTNING_FLOOR,
+MT_LIGHTNING_ZAP,
+MT_MSTAFF_FX,
+MT_MSTAFF_FX2,
+MT_FW_SWORD1,
+MT_FW_SWORD2,
+MT_FW_SWORD3,
+MT_CW_HOLY1,
+MT_CW_HOLY2,
+MT_CW_HOLY3,
+MT_MW_STAFF1,
+MT_MW_STAFF2,
+MT_MW_STAFF3,
+MT_SNOUTPUFF,
+MT_MW_CONE,
+MT_SHARDFX1,
+MT_BLOOD,
+MT_BLOODSPLATTER,
+MT_GIBS,
+MT_PLAYER_FIGHTER,
+MT_BLOODYSKULL,
+MT_PLAYER_SPEED,
+MT_ICECHUNK,
+MT_PLAYER_CLERIC,
+MT_PLAYER_MAGE,
+#ifdef ASSASSIN
+MT_PLAYER_ASS,
+#endif
+MT_PIGPLAYER,
+MT_PIG,
+MT_CENTAUR,
+MT_CENTAURLEADER,
+MT_CENTAUR_FX,
+MT_CENTAUR_SHIELD,
+MT_CENTAUR_SWORD,
+MT_DEMON,
+MT_DEMONCHUNK1,
+MT_DEMONCHUNK2,
+MT_DEMONCHUNK3,
+MT_DEMONCHUNK4,
+MT_DEMONCHUNK5,
+MT_DEMONFX1,
+MT_DEMON2,
+MT_DEMON2CHUNK1,
+MT_DEMON2CHUNK2,
+MT_DEMON2CHUNK3,
+MT_DEMON2CHUNK4,
+MT_DEMON2CHUNK5,
+MT_DEMON2FX1,
+MT_WRAITHB,
+MT_WRAITH,
+MT_WRAITHFX1,
+MT_WRAITHFX2,
+MT_WRAITHFX3,
+MT_WRAITHFX4,
+MT_WRAITHFX5,
+MT_MINOTAUR,
+MT_MNTRFX1,
+MT_MNTRFX2,
+MT_MNTRFX3,
+MT_MNTRSMOKE,
+MT_MNTRSMOKEEXIT,
+MT_SERPENT,
+MT_SERPENTLEADER,
+MT_SERPENTFX,
+MT_SERPENT_HEAD,
+MT_SERPENT_GIB1,
+MT_SERPENT_GIB2,
+MT_SERPENT_GIB3,
+MT_BISHOP,
+MT_BISHOP_PUFF,
+MT_BISHOPBLUR,
+MT_BISHOPPAINBLUR,
+MT_BISH_FX,
+MT_DRAGON,
+MT_DRAGON_FX,
+MT_DRAGON_FX2,
+MT_ARMOR_1,
+MT_ARMOR_2,
+MT_ARMOR_3,
+MT_ARMOR_4,
+MT_MANA1,
+MT_MANA2,
+MT_MANA3,
+MT_KEY1,
+MT_KEY2,
+MT_KEY3,
+MT_KEY4,
+MT_KEY5,
+MT_KEY6,
+MT_KEY7,
+MT_KEY8,
+MT_KEY9,
+MT_KEYA,
+MT_KEYB,
+MT_SOUNDWIND,
+MT_SOUNDWATERFALL,
+MT_ETTIN,
+MT_ETTIN_MACE,
+MT_FIREDEMON,
+MT_FIREDEMON_SPLOTCH1,
+MT_FIREDEMON_SPLOTCH2,
+MT_FIREDEMON_FX1,
+MT_FIREDEMON_FX2,
+MT_FIREDEMON_FX3,
+MT_FIREDEMON_FX4,
+MT_FIREDEMON_FX5,
+MT_FIREDEMON_FX6,
+MT_ICEGUY,
+MT_ICEGUY_FX,
+MT_ICEFX_PUFF,
+MT_ICEGUY_FX2,
+MT_ICEGUY_BIT,
+MT_ICEGUY_WISP1,
+MT_ICEGUY_WISP2,
+MT_FIGHTER_BOSS,
+MT_CLERIC_BOSS,
+MT_MAGE_BOSS,
+MT_SORCBOSS,
+MT_SORCBALL1,
+MT_SORCBALL2,
+MT_SORCBALL3,
+MT_SORCFX1,
+MT_SORCFX2,
+MT_SORCFX2_T1,
+MT_SORCFX3,
+MT_SORCFX3_EXPLOSION,
+MT_SORCFX4,
+MT_SORCSPARK1,
+MT_BLASTEFFECT,
+MT_WATER_DRIP,
+MT_KORAX,
+MT_KORAX_SPIRIT1,
+MT_KORAX_SPIRIT2,
+MT_KORAX_SPIRIT3,
+MT_KORAX_SPIRIT4,
+MT_KORAX_SPIRIT5,
+MT_KORAX_SPIRIT6,
+MT_DEMON_MASH,
+MT_DEMON2_MASH,
+MT_ETTIN_MASH,
+MT_CENTAUR_MASH,
+MT_KORAX_BOLT,
+MT_BAT_SPAWNER,
+MT_BAT,
+#ifdef ASSASSIN
+MT_AW_CROSSBOW,
+/* jim And its missiles! */
+MT_ACROSS_MISSILE,
+MT_AW_GRENADES,
+#endif
+NUMMOBJTYPES} mobjtype_t;
+
+typedef struct {
+ int doomednum;
+ int spawnstate;
+ int spawnhealth;
+ int seestate;
+ int seesound;
+ int reactiontime;
+ int attacksound;
+ int painstate;
+ int painchance;
+ int painsound;
+ int meleestate;
+ int missilestate;
+ int crashstate;
+ int deathstate;
+ int xdeathstate;
+ int deathsound;
+ int speed;
+ int radius;
+ int height;
+ int mass;
+ int damage;
+ int activesound;
+ int flags;
+ int flags2;
+} mobjinfo_t;
+
+extern mobjinfo_t mobjinfo[NUMMOBJTYPES];
+
+#endif /* __INFO_H */
+
--- /dev/null
+++ b/m_bams.h
@@ -1,0 +1,45 @@
+//**************************************************************************
+//**
+//** m_bams.h
+//**
+//** $Revision: 396 $
+//** $Date: 2009-05-21 12:32:55 +0300 (Thu, 21 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __MY_BAMS_MATH_H__
+#define __MY_BAMS_MATH_H__
+
+typedef unsigned short binangle;
+
+/* Some predefined angles */
+#define BANG_0 0 /* To the east. */
+#define BANG_45 0x2000 /* To the northeast. */
+#define BANG_90 0x4000 /* To the north. */
+#define BANG_135 0x6000 /* To the northwest. */
+#define BANG_180 0x8000 /* To the west. */
+#define BANG_225 0xa000 /* To the southwest. */
+#define BANG_270 0xc000 /* To the south. */
+#define BANG_315 0xe000 /* To the southeast. */
+#define BANG_360 0x10000 /* The same as angle 0. */
+#define BANG_MAX 0xffff /* The largest possible angle. */
+
+/* Compass directions, for convenience. */
+#define BANG_EAST BANG_0
+#define BANG_NORTHEAST BANG_45
+#define BANG_NORTH BANG_90
+#define BANG_NORTHWEST BANG_135
+#define BANG_WEST BANG_180
+#define BANG_SOUTHWEST BANG_225
+#define BANG_SOUTH BANG_270
+#define BANG_SOUTHEAST BANG_315
+
+#define BAMS_PI 3.14159265359
+#define RAD2BANG(x) ((binangle)((x)/BAMS_PI*BANG_180))
+#define BANG2RAD(x) ((float)((x)/(float)BANG_180*BAMS_PI))
+
+void bamsInit(void); /* Fill in the tables */
+binangle bamsAtan2(int y,int x);
+
+#endif /* __MY_BAMS_MATH_H__ */
+
--- /dev/null
+++ b/m_misc.c
@@ -1,0 +1,799 @@
+
+//**************************************************************************
+//**
+//** m_misc.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 560 $
+//** $Date: 2010-10-20 15:15:39 +0300 (Wed, 20 Oct 2010) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "p_local.h"
+#include "i_cdmus.h"
+#include "soundst.h"
+#ifdef __WATCOMC__
+#include "i_sound.h"
+#endif
+#ifdef RENDER3D
+#include "ogl_def.h"
+#endif
+
+// MACROS ------------------------------------------------------------------
+
+#define MALLOC_CLIB 1
+#define MALLOC_ZONE 2
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static int __ReadFile(char const *name, void **buffer, int mallocType);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int myargc;
+const char **myargv;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// M_CheckParm
+//
+// Checks for the given parameter in the program's command line arguments.
+// Returns the argument number (1 to argc-1) or 0 if not present.
+//
+//==========================================================================
+
+int M_CheckParm(const char *check)
+{
+ int i;
+
+ for (i = 1; i < myargc; i++)
+ {
+ if (!strcmp(check, myargv[i]))
+ {
+ return i;
+ }
+ }
+ return 0;
+}
+
+//==========================================================================
+//
+// M_ParmExists
+//
+// Returns true if the given parameter exists in the program's command
+// line arguments, false if not.
+//
+//==========================================================================
+
+boolean M_ParmExists(const char *check)
+{
+ return M_CheckParm(check) != 0 ? true : false;
+}
+
+//==========================================================================
+//
+// M_ExtractFileBase
+//
+//==========================================================================
+
+void M_ExtractFileBase(const char *path, char *dest)
+{
+ const char *src;
+ int length;
+
+ src = path + strlen(path) - 1;
+ if (src <= path)
+ {
+ *dest = '\0';
+ return;
+ }
+
+ // Back up until a \ or the start
+ while (src != path && src[-1] != '/' && src[-1] != '\\')
+ src--;
+
+ // Copy up to eight characters
+ memset(dest, 0, 8);
+ length = 0;
+ while (*src && *src != '.')
+ {
+ if (++length == 9)
+ {
+ I_Error("Filename base of %s > 8 chars", path);
+ }
+ *dest++ = toupper((int)*src++);
+ }
+}
+
+/*
+===============
+=
+= M_Random
+=
+= Returns a 0-255 number
+=
+===============
+*/
+
+// This is the new flat distribution table
+unsigned char rndtable[256] =
+{
+ 201, 1,243, 19, 18, 42,183,203,101,123,154,137, 34,118, 10,216,
+ 135,246, 0,107,133,229, 35,113,177,211,110, 17,139, 84,251,235,
+ 182,166,161,230,143, 91, 24, 81, 22, 94, 7, 51,232,104,122,248,
+ 175,138,127,171,222,213, 44, 16, 9, 33, 88,102,170,150,136,114,
+ 62, 3,142,237, 6,252,249, 56, 74, 30, 13, 21,180,199, 32,132,
+ 187,234, 78,210, 46,131,197, 8,206,244, 73, 4,236,178,195, 70,
+ 121, 97,167,217,103, 40,247,186,105, 39, 95,163, 99,149,253, 29,
+ 119, 83,254, 26,202, 65,130,155, 60, 64,184,106,221, 93,164,196,
+ 112,108,179,141, 54,109, 11,126, 75,165,191,227, 87,225,156, 15,
+ 98,162,116, 79,169,140,190,205,168,194, 41,250, 27, 20, 14,241,
+ 50,214, 72,192,220,233, 67,148, 96,185,176,181,215,207,172, 85,
+ 89, 90,209,128,124, 2, 55,173, 66,152, 47,129, 59, 43,159,240,
+ 239, 12,189,212,144, 28,200, 77,219,198,134,228, 45, 92,125,151,
+ 5, 53,255, 52, 68,245,160,158, 61, 86, 58, 82,117, 37,242,145,
+ 69,188,115, 76, 63,100, 49,111,153, 80, 38, 57,174,224, 71,231,
+ 23, 25, 48,218,120,147,208, 36,226,223,193,238,157,204,146, 31
+};
+
+int rndindex = 0;
+int prndindex = 0;
+
+unsigned char P_Random (void)
+{
+ prndindex = (prndindex + 1) & 0xff;
+ return rndtable[prndindex];
+}
+
+int M_Random (void)
+{
+ rndindex = (rndindex + 1) & 0xff;
+ return rndtable[rndindex];
+}
+
+void M_ClearRandom (void)
+{
+ rndindex = prndindex = 0;
+}
+
+
+void M_ClearBox (fixed_t *box)
+{
+ box[BOXTOP] = box[BOXRIGHT] = H2MININT;
+ box[BOXBOTTOM] = box[BOXLEFT] = H2MAXINT;
+}
+
+void M_AddToBox (fixed_t *box, fixed_t x, fixed_t y)
+{
+ if (x < box[BOXLEFT])
+ box[BOXLEFT] = x;
+ else if (x > box[BOXRIGHT])
+ box[BOXRIGHT] = x;
+ if (y < box[BOXBOTTOM])
+ box[BOXBOTTOM] = y;
+ else if (y > box[BOXTOP])
+ box[BOXTOP] = y;
+}
+
+/*
+==================
+=
+= M_WriteFile
+=
+==================
+*/
+
+boolean M_WriteFile (char const *name, const void *source, int length)
+{
+ int handle, count;
+
+ handle = create (name, OWRITE, 0666);
+ if (handle < 0)
+ return false;
+ count = write (handle, source, length);
+ close (handle);
+
+ if (count < length)
+ return false;
+
+ return true;
+}
+
+//==========================================================================
+//
+// M_ReadFile
+//
+// Read a file into a buffer allocated using Z_Malloc().
+//
+//==========================================================================
+
+int M_ReadFile(char const *name, void **buffer)
+{
+ return __ReadFile(name, buffer, MALLOC_ZONE);
+}
+
+//==========================================================================
+//
+// M_ReadFileCLib
+//
+// Read a file into a buffer allocated using malloc().
+//
+//==========================================================================
+
+int M_ReadFileCLib(char const *name, void **buffer)
+{
+ return __ReadFile(name, buffer, MALLOC_CLIB);
+}
+
+//==========================================================================
+//
+// ReadFile
+//
+//==========================================================================
+
+static int __ReadFile(char const *name, void **buffer, int mallocType)
+{
+ int handle, count, length;
+ struct stat fileinfo;
+ void *buf;
+ Dir *d;
+
+ handle = open(name, OREAD);
+ if (handle == -1)
+ {
+ I_Error("Couldn't read file %s", name);
+ }
+ d = dirfstat(handle);
+ if (d == nil)
+ {
+ I_Error("Couldn't read file %s", name);
+ }
+ length = d->length;
+ free(d);
+ if (mallocType == MALLOC_ZONE)
+ { // Use zone memory allocation
+ buf = Z_Malloc(length, PU_STATIC, NULL);
+ }
+ else
+ { // Use c library memory allocation
+ buf = malloc(length);
+ if (buf == NULL)
+ {
+ I_Error("Couldn't malloc buffer %d for file %s.",
+ length, name);
+ }
+ }
+ count = read(handle, buf, length);
+ close(handle);
+ if (count < length)
+ {
+ I_Error("Couldn't read file %s", name);
+ }
+ *buffer = buf;
+ return length;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC M_FindResponseFile
+//
+//---------------------------------------------------------------------------
+
+#define MAXARGVS 100
+
+void M_FindResponseFile(void)
+{
+ int i;
+
+ for (i = 1; i < myargc; i++)
+ {
+ if (myargv[i][0] == '@')
+ {
+ FILE *handle;
+ int size, k, idx;
+ int indexinfile;
+ char *infile;
+ char *file;
+ const char *moreargs[20];
+ const char *firstargv;
+
+ // READ THE RESPONSE FILE INTO MEMORY
+ handle = fopen(&myargv[i][1], "rb");
+ if (!handle)
+ {
+ printf("\nNo such response file!");
+ exits("No such response file!");
+ }
+ ST_Message("Found response file %s!\n",&myargv[i][1]);
+ fseek (handle, 0, SEEK_END);
+ size = ftell(handle);
+ fseek (handle, 0, SEEK_SET);
+ file = (char *) malloc (size);
+ fread (file, size, 1, handle);
+ fclose (handle);
+
+ // KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
+ for (idx = 0, k = i + 1; k < myargc; k++)
+ moreargs[idx++] = myargv[k];
+
+ firstargv = myargv[0];
+ myargv = (const char **) calloc(1, sizeof(char *) * MAXARGVS);
+ myargv[0] = firstargv;
+
+ infile = file;
+ indexinfile = k = 0;
+ indexinfile++; // SKIP PAST ARGV[0] (KEEP IT)
+ do
+ {
+ myargv[indexinfile++] = infile + k;
+ while (k < size && ((*(infile + k) >= ' ' + 1) && (*(infile + k) <= 'z')))
+ k++;
+ *(infile + k) = 0;
+ while (k < size && ((*(infile + k) <= ' ') || (*(infile + k) > 'z')))
+ k++;
+ } while (k < size);
+
+ for (k = 0; k < idx; k++)
+ myargv[indexinfile++] = moreargs[k];
+ myargc = indexinfile;
+ // DISPLAY ARGS
+ if (M_CheckParm("-debug"))
+ {
+ ST_Message("%d command-line args:\n", myargc);
+ for (k = 1; k < myargc; k++)
+ {
+ ST_Message("%s\n", myargv[k]);
+ }
+ }
+ break;
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC M_ForceUppercase
+//
+// Change string to uppercase.
+//
+//---------------------------------------------------------------------------
+
+void M_ForceUppercase(char *text)
+{
+ char c;
+
+ while ((c = *text) != 0)
+ {
+ if (c >= 'a' && c <= 'z')
+ {
+ *text++ = c-('a'-'A');
+ }
+ else
+ {
+ text++;
+ }
+ }
+}
+
+/*
+==============================================================================
+
+ DEFAULTS
+
+==============================================================================
+*/
+
+int usemouse;
+int usejoystick;
+
+int mouseSensitivity;
+
+extern int mouselook;
+extern int alwaysrun;
+
+extern int key_right, key_left, key_up, key_down;
+extern int key_strafeleft, key_straferight, key_jump;
+extern int key_fire, key_use, key_strafe, key_speed;
+extern int key_flyup, key_flydown, key_flycenter;
+extern int key_lookup, key_lookdown, key_lookcenter;
+extern int key_invleft, key_invright, key_useartifact;
+
+extern int mousebfire;
+extern int mousebstrafe;
+extern int mousebforward;
+extern int mousebjump;
+
+extern int joybfire;
+extern int joybstrafe;
+extern int joybuse;
+extern int joybspeed;
+extern int joybjump;
+
+extern int messageson;
+
+extern int viewwidth, viewheight;
+
+extern int screenblocks;
+
+extern int snd_Channels;
+#ifdef __WATCOMC__
+extern int snd_DesiredMusicDevice, snd_DesiredSfxDevice;
+extern int snd_MusicDevice, // current music card # (index to dmxCodes)
+ snd_SfxDevice; // current sfx card # (index to dmxCodes)
+
+extern int snd_SBport, snd_SBirq, snd_SBdma; // sound blaster variables
+extern int snd_Mport; // midi variables
+#endif /* DOS vars */
+
+default_t defaults[] =
+{
+/* change of order here affects mn_menu.c :
+ * see, for example, Options3Items there...
+ */
+ { "mouse_sensitivity", &mouseSensitivity, 5, 0, 50 },
+ { "sfx_volume", &snd_MaxVolume, 10, 0, 15 },
+ { "music_volume", &snd_MusicVolume, 10, 0, 15 },
+
+ { "key_right", &key_right, KEY_RIGHTARROW, 0, 254 },
+ { "key_left", &key_left, KEY_LEFTARROW, 0, 254 },
+ { "key_up", &key_up, KEY_UPARROW, 0, 254 },
+ { "key_down", &key_down, KEY_DOWNARROW, 0, 254 },
+ { "key_strafeleft", &key_strafeleft, ',', 0, 254 },
+ { "key_straferight", &key_straferight, '.', 0, 254 },
+ { "key_flyup", &key_flyup, KEY_PGUP, 0, 254 },
+ { "key_flydown", &key_flydown, KEY_INS, 0, 254 },
+ { "key_flycenter", &key_flycenter, KEY_HOME, 0, 254 },
+ { "key_lookup", &key_lookup, KEY_PGDN, 0, 254 },
+ { "key_lookdown", &key_lookdown, KEY_DEL, 0, 254 },
+ { "key_lookcenter", &key_lookcenter, KEY_END, 0, 254 },
+ { "key_invleft", &key_invleft, '[', 0, 254 },
+ { "key_invright", &key_invright, ']', 0, 254 },
+ { "key_useartifact", &key_useartifact, KEY_ENTER, 0, 254 },
+ { "key_fire", &key_fire, KEY_RCTRL, 0, 254 },
+ { "key_use", &key_use, ' ', 0, 254 },
+ { "key_strafe", &key_strafe, KEY_RALT, 0, 254 },
+ { "key_speed", &key_speed, KEY_RSHIFT, 0, 254 },
+ { "key_jump", &key_jump, '/', 0, 254 },
+
+ { "use_mouse", &usemouse, 1, 0, 1 },
+ { "mouseb_fire", &mousebfire, 0, -1, 2 },
+ { "mouseb_strafe", &mousebstrafe, 1, -1, 2 },
+ { "mouseb_forward", &mousebforward, 2, -1, 2 },
+ { "mouseb_jump", &mousebjump, -1, -1, 2 },
+
+ { "use_joystick", &usejoystick, 0, 0, 1 },
+ { "joyb_fire", &joybfire, 0, -1, 3 },
+ { "joyb_strafe", &joybstrafe, 1, -1, 3 },
+ { "joyb_use", &joybuse, 3, -1, 3 },
+ { "joyb_speed", &joybspeed, 2, -1, 3 },
+ { "joyb_jump", &joybjump, -1, -1, 3 },
+
+ { "screenblocks", &screenblocks, 10, 3, 11 },
+ { "usegamma", &usegamma, 0, 0, 4 },
+ { "messageson", &messageson, 1, 0, 1 },
+ { "mouselook", &mouselook, 1, 0, 2 },
+ { "cdaudio", &cdaudio, 0, 0, 1 },
+ { "alwaysrun", &alwaysrun, 0, 0, 1 },
+
+ { "snd_channels", &snd_Channels, 3, 3, MAX_CHANNELS },
+#ifdef __WATCOMC__
+ /* the min/max values I added here are pretty much meaningless.
+ the values used to be set by the DOS version's setup program. */
+ { "snd_musicdevice", &snd_DesiredMusicDevice,0, 0, NUM_SCARDS-1 },
+ { "snd_sfxdevice", &snd_DesiredSfxDevice, 0, 0, NUM_SCARDS-1 },
+ { "snd_sbport", &snd_SBport, 544, 0, 544 },
+ { "snd_sbirq", &snd_SBirq, -1, -1, 7 },
+ { "snd_sbdma", &snd_SBdma, -1, -1, 7 },
+ { "snd_mport", &snd_Mport, -1, -1, 360 }
+#endif /* DOS vars */
+};
+
+default_str_t default_strings[] =
+{
+ { "chatmacro0", chat_macros[0] },
+ { "chatmacro1", chat_macros[1] },
+ { "chatmacro2", chat_macros[2] },
+ { "chatmacro3", chat_macros[3] },
+ { "chatmacro4", chat_macros[4] },
+ { "chatmacro5", chat_macros[5] },
+ { "chatmacro6", chat_macros[6] },
+ { "chatmacro7", chat_macros[7] },
+ { "chatmacro8", chat_macros[8] },
+ { "chatmacro9", chat_macros[9] }
+};
+
+static int numdefaults, numstrings;
+static char defaultfile[MAX_OSPATH];
+
+/*
+==============
+=
+= M_SaveDefaults
+=
+==============
+*/
+
+void M_SaveDefaults (void)
+{
+ int i,v;
+ FILE *f;
+
+ f = fopen (defaultfile, "w");
+ if (!f)
+ return; // can't write the file, but don't complain
+
+ for (i = 0; i < numdefaults; i++)
+ {
+ v = *defaults[i].location;
+ fprintf (f, "%s\t\t%i\n", defaults[i].name, v);
+ }
+
+ for (i = 0; i < numstrings; i++)
+ {
+ fprintf (f, "%s\t\t\"%s\"\n", default_strings[i].name,
+ default_strings[i].location);
+ }
+
+ fclose (f);
+}
+
+//==========================================================================
+//
+// M_LoadDefaults
+//
+//==========================================================================
+
+void M_LoadDefaults(const char *fileName)
+{
+ int i;
+ int len;
+ FILE *f;
+ char def[80];
+ char strparm[100];
+ int parm;
+
+ numdefaults = sizeof(defaults) / sizeof(defaults[0]);
+ numstrings = sizeof(default_strings) / sizeof(default_strings[0]);
+ ST_Message("Loading default settings\n");
+ // Set everything to base values
+ for (i = 0; i < numdefaults; i++)
+ {
+ *defaults[i].location = defaults[i].defaultvalue;
+ }
+ // Make a backup of all default strings
+ for (i = 0; i < numstrings; i++)
+ {
+ default_strings[i].defaultvalue = (char *) calloc(1, 80);
+ strcpy (default_strings[i].defaultvalue, default_strings[i].location);
+ }
+
+ // Check for a custom config file
+ i = M_CheckParm("-config");
+ if (i && i < myargc-1)
+ {
+ snprintf(defaultfile, sizeof(defaultfile), "%s%s", basePath, myargv[i + 1]);
+ ST_Message("config file: %s\n", defaultfile);
+ }
+ else
+ {
+ snprintf(defaultfile, sizeof(defaultfile), "%s%s", basePath, fileName);
+ }
+
+ // Scan the config file
+ f = fopen(defaultfile, "r");
+ if (f)
+ {
+ while (!feof(f))
+ {
+ if (fscanf(f, "%79s %[^\n]\n", def, strparm) == 2)
+ {
+ if (strparm[0] == '"') /* string values */
+ {
+ for (i = 0; i < numstrings; i++)
+ {
+ if (!strcmp(def, default_strings[i].name))
+ {
+ len = (int)strlen(strparm) - 2;
+ if (len <= 0)
+ {
+ default_strings[i].location[0] = '\0';
+ break;
+ }
+ if (len > 79)
+ {
+ len = 79;
+ }
+ strncpy(default_strings[i].location, strparm + 1, len);
+ default_strings[i].location[len] = '\0';
+ break;
+ }
+ }
+ continue;
+ }
+
+ /* numeric values */
+ if (strparm[0] == '0' && strparm[1] == 'x')
+ {
+ sscanf(strparm + 2, "%x", &parm);
+ }
+ else
+ {
+ sscanf(strparm, "%i", &parm);
+ }
+ for (i = 0; i < numdefaults; i++)
+ {
+ if (!strcmp(def, defaults[i].name))
+ {
+ if (parm >= defaults[i].minvalue && parm <= defaults[i].maxvalue)
+ *defaults[i].location = parm;
+ break;
+ }
+ }
+ }
+ }
+ fclose (f);
+ }
+}
+
+
+/*
+==============================================================================
+
+ SCREEN SHOTS
+
+==============================================================================
+*/
+
+typedef struct
+{
+ char manufacturer;
+ char version;
+ char encoding;
+ char bits_per_pixel;
+ unsigned short xmin,ymin,xmax,ymax;
+ unsigned short hres,vres;
+ unsigned char palette[48];
+ char reserved;
+ char color_planes;
+ unsigned short bytes_per_line;
+ unsigned short palette_type;
+ char filler[58];
+ unsigned char data; // unbounded
+} pcx_t;
+
+/*
+==============
+=
+= WritePCXfile
+=
+==============
+*/
+
+void WritePCXfile (const char *filename, byte *data, int width, int height, byte *palette)
+{
+ int i, length;
+ pcx_t *pcx;
+ byte *pack;
+
+ pcx = (pcx_t *) Z_Malloc (width*height*2 + 1000, PU_STATIC, NULL);
+
+ pcx->manufacturer = 0x0a; // PCX id
+ pcx->version = 5; // 256 color
+ pcx->encoding = 1; // uncompressed
+ pcx->bits_per_pixel = 8; // 256 color
+ pcx->xmin = 0;
+ pcx->ymin = 0;
+ pcx->xmax = SHORT(width - 1);
+ pcx->ymax = SHORT(height - 1);
+ pcx->hres = SHORT(width);
+ pcx->vres = SHORT(height);
+ memset (pcx->palette, 0, sizeof(pcx->palette));
+ pcx->color_planes = 1; // chunky image
+ pcx->bytes_per_line = SHORT(width);
+ pcx->palette_type = SHORT(2); // not a grey scale
+ memset (pcx->filler, 0, sizeof(pcx->filler));
+
+//
+// pack the image
+//
+ pack = &pcx->data;
+
+ for (i = 0; i < width*height; i++)
+ {
+ if ((*data & 0xc0) != 0xc0)
+ *pack++ = *data++;
+ else
+ {
+ *pack++ = 0xc1;
+ *pack++ = *data++;
+ }
+ }
+
+//
+// write the palette
+//
+ *pack++ = 0x0c; // palette ID byte
+ for (i = 0; i < 768; i++)
+ *pack++ = *palette++;
+
+//
+// write output file
+//
+ length = pack - (byte *)pcx;
+ M_WriteFile (filename, pcx, length);
+
+ Z_Free (pcx);
+}
+
+
+//==============================================================================
+
+/*
+==================
+=
+= M_ScreenShot
+=
+==================
+*/
+#ifdef RENDER3D
+void M_ScreenShot (void)
+{
+ OGL_GrabScreen();
+}
+#else
+void M_ScreenShot (void)
+{
+ int i;
+ byte *linear;
+ char lbmname[MAX_OSPATH], *p;
+ byte *pal;
+
+//
+// munge planar buffer to linear
+//
+ linear = screen;
+//
+// find a file name to save it to
+//
+ snprintf (lbmname, sizeof(lbmname), "%shexen00.pcx", basePath);
+ p = lbmname + strlen(basePath);
+ for (i = 0; i <= 99; i++)
+ {
+ p[5] = i/10 + '0';
+ p[6] = i%10 + '0';
+ if (access(lbmname, AEXIST) == -1)
+ break; // file doesn't exist
+ }
+ if (i == 100)
+ {
+ P_SetMessage(&players[consoleplayer], "SCREEN SHOT FAILED", false);
+ return;
+ }
+
+//
+// save the pcx file
+//
+ pal = (byte *)W_CacheLumpName("PLAYPAL", PU_CACHE);
+
+ WritePCXfile (lbmname, linear, SCREENWIDTH, SCREENHEIGHT, pal);
+
+ P_SetMessage(&players[consoleplayer], "SCREEN SHOT", false);
+}
+#endif
+
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,60 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin
+TARG=hexen
+CFLAGS=-Fpw
+
+OFILES=\
+ am_map.$O \
+ a_action.$O \
+ ct_chat.$O \
+ d_net.$O \
+ f_finale.$O \
+ g_game.$O \
+ h2_main.$O \
+ h_hubmsg.$O \
+ info.$O \
+ in_lude.$O \
+ mn_menu.$O \
+ m_misc.$O \
+ p_acs.$O \
+ p_anim.$O \
+ p_ceilng.$O \
+ p_doors.$O \
+ p_enemy.$O \
+ p_floor.$O \
+ p_inter.$O \
+ p_lights.$O \
+ p_map.$O \
+ p_maputl.$O \
+ p_mobj.$O \
+ p_plats.$O \
+ p_pspr.$O \
+ p_setup.$O \
+ p_sight.$O \
+ p_spec.$O \
+ p_switch.$O \
+ p_telept.$O \
+ p_tick.$O \
+ p_things.$O \
+ p_user.$O \
+ po_man.$O \
+ r_bsp.$O \
+ r_data.$O \
+ r_draw.$O \
+ r_main.$O \
+ r_plane.$O \
+ r_segs.$O \
+ r_things.$O \
+ sb_bar.$O \
+ sc_man.$O \
+ s_sound.$O \
+ sn_sonix.$O \
+ st_start.$O \
+ sv_save.$O \
+ tables.$O \
+ v_video.$O \
+ w_wad.$O \
+ z_zone.$O
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/mmus2mid.c
@@ -1,0 +1,852 @@
+/* $Id: mmus2mid.c 543 2010-01-11 18:44:55Z sezero $
+ *
+ * Ripped && Adapted from the PrBoom project:
+ * PrBoom: a Doom port merged with LxDoom and LSDLDoom
+ * based on BOOM, a modified and improved DOOM engine
+ * Copyright (C) 1999 by
+ * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
+ * Copyright (C) 1999-2000 by
+ * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
+ * Copyright 2005, 2006 by
+ * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ *
+ * DESCRIPTION:
+ * This file supports conversion of MUS format music in memory
+ * to MIDI format 1 music in memory.
+ *
+ * The primary routine, mmus2mid, converts a block of memory in MUS format
+ * to an Allegro MIDI structure. This supports playing MUS lumps in a wad
+ * file with BOOM.
+ *
+ * Another routine, Midi2MIDI, converts a block of memory in MIDI format 1 to
+ * an Allegro MIDI structure. This supports playing MIDI lumps in a wad
+ * file with BOOM.
+ *
+ * For testing purposes, and to make a utility if desired, if the symbol
+ * STANDALONE is defined by uncommenting the definition below, a main
+ * routine is compiled that will convert a possibly wildcarded set of MUS
+ * files to a similarly named set of MIDI files.
+ *
+ * Much of the code here is thanks to S. Bacquet's source for QMUS2MID.C
+ *
+ */
+
+
+#include "h2stdinc.h"
+#include <sys/stat.h>
+#ifdef MSDOS
+#include <allegro.h>
+#endif /* !MSDOS */
+#include "h2def.h"
+#include "mmus2mid.h"
+
+//#define STANDALONE /* uncomment this to make MMUS2MID.EXE */
+
+// some macros to decode mus event bit fields
+
+#define last(e) ((uint8_t)((e) & 0x80))
+#define event_type(e) ((uint8_t)(((e) & 0x7F) >> 4))
+#define channel(e) ((uint8_t)((e) & 0x0F))
+
+// event types
+
+typedef enum
+{
+ RELEASE_NOTE,
+ PLAY_NOTE,
+ BEND_NOTE,
+ SYS_EVENT,
+ CNTL_CHANGE,
+ UNKNOWN_EVENT1,
+ SCORE_END,
+ UNKNOWN_EVENT2,
+} mus_event_t;
+
+// MUS format header structure
+
+typedef struct
+{
+ char ID[4]; // identifier "MUS"0x1A
+ uint16_t ScoreLength; // length of music portion
+ uint16_t ScoreStart; // offset of music portion
+ uint16_t channels; // count of primary channels
+ uint16_t SecChannels; // count of secondary channels
+ uint16_t InstrCnt; // number of instruments
+} __attribute__((__packed__)) MUSheader;
+
+// to keep track of information in a MIDI track
+
+typedef struct Track
+{
+ char velocity;
+ int32_t deltaT;
+ uint8_t lastEvt;
+ uint32_t alloced;
+} TrackInfo;
+
+// array of info about tracks
+
+static TrackInfo track[MIDI_TRACKS];
+
+// initial track size allocation
+#define TRACKBUFFERSIZE 1024
+
+// lookup table MUS -> MID controls
+static uint8_t MUS2MIDcontrol[15] =
+{
+ 0, // Program change - not a MIDI control change
+ 0x00, // Bank select
+ 0x01, // Modulation pot
+ 0x07, // Volume
+ 0x0A, // Pan pot
+ 0x0B, // Expression pot
+ 0x5B, // Reverb depth
+ 0x5D, // Chorus depth
+ 0x40, // Sustain pedal
+ 0x43, // Soft pedal
+ 0x78, // All sounds off
+ 0x7B, // All notes off
+ 0x7E, // Mono
+ 0x7F, // Poly
+ 0x79 // Reset all controllers
+};
+
+// some strings of uint8_ts used in the midi format
+
+static uint8_t midikey[] =
+{0x00,0xff,0x59,0x02,0x00,0x00}; // C major
+static uint8_t miditempo[] =
+{0x00,0xff,0x51,0x03,0x09,0xa3,0x1a}; // uS/qnote
+static uint8_t midihdr[] =
+{'M','T','h','d',0,0,0,6,0,1,0,0,0,0}; // header (length 6, format 1)
+static uint8_t trackhdr[] =
+{'M','T','r','k'}; // track header
+
+// static routine prototypes
+
+static int TWriteByte(MIDI *mididata, int MIDItrack, uint8_t value);
+static int TWriteVarLen(MIDI *mididata, int MIDItrack, uint32_t value);
+static uint32_t ReadTime(const uint8_t **musptrp);
+static int FirstChannelAvailable(int MUS2MIDchannel[]);
+static uint8_t MidiEvent(MIDI *mididata,uint8_t midicode,uint8_t MIDIchannel,
+ uint8_t MIDItrack,int nocomp);
+
+//
+// TWriteByte()
+//
+// write one byte to the selected MIDItrack, update current position
+// if track allocation exceeded, double it
+// if track not allocated, initially allocate TRACKBUFFERSIZE bytes
+//
+// Passed pointer to Allegro MIDI structure, number of the MIDI track being
+// written, and the byte to write.
+//
+// Returns 0 on success, MEMALLOC if a memory allocation error occurs
+//
+static int TWriteByte(MIDI *mididata, int MIDItrack, uint8_t value)
+{
+ uint32_t pos;
+
+ pos = mididata->track[MIDItrack].len;
+ if (pos >= track[MIDItrack].alloced)
+ {
+ track[MIDItrack].alloced = // double allocation
+ track[MIDItrack].alloced? // or set initial TRACKBUFFERSIZE
+ 2*track[MIDItrack].alloced :
+ TRACKBUFFERSIZE;
+
+ if (!(mididata->track[MIDItrack].data = // attempt to reallocate
+ realloc(mididata->track[MIDItrack].data,
+ track[MIDItrack].alloced)))
+ return MEMALLOC;
+ }
+ mididata->track[MIDItrack].data[pos] = value;
+ mididata->track[MIDItrack].len++;
+ return 0;
+}
+
+//
+// TWriteVarLen()
+//
+// write the ULONG value to tracknum-th track, in midi format, which is
+// big endian, 7 bits per byte, with all bytes but the last flagged by
+// bit 8 being set, allowing the length to vary.
+//
+// Passed the Allegro MIDI structure, the track number to write,
+// and the ULONG value to encode in midi format there
+//
+// Returns 0 if sucessful, MEMALLOC if a memory allocation error occurs
+//
+static int TWriteVarLen(MIDI *mididata, int tracknum, uint32_t value)
+{
+ uint32_t buffer;
+
+ buffer = value & 0x7f;
+ while ((value >>= 7)) // terminates because value unsigned
+ {
+ buffer <<= 8; // note first value shifted in has bit 8 clear
+ buffer |= 0x80; // all succeeding values do not
+ buffer += (value & 0x7f);
+ }
+ while (1) // write bytes out in opposite order
+ {
+ if (TWriteByte(mididata, tracknum, (uint8_t)(buffer&0xff))) // insure buffer masked
+ return MEMALLOC;
+
+ if (buffer & 0x80)
+ buffer >>= 8;
+ else // terminate on the byte with bit 8 clear
+ break;
+ }
+ return 0;
+}
+
+//
+// ReadTime()
+//
+// Read a time value from the MUS buffer, advancing the position in it
+//
+// A time value is a variable length sequence of 8 bit bytes, with all
+// but the last having bit 8 set.
+//
+// Passed a pointer to the pointer to the MUS buffer
+// Returns the integer unsigned long time value there and advances the pointer
+//
+static uint32_t ReadTime(const uint8_t **musptrp)
+{
+ uint32_t timeval = 0;
+ int _byte;
+
+ do // shift each byte read up in the result until a byte with bit 8 clear
+ {
+ _byte = *(*musptrp)++;
+ timeval = (timeval << 7) + (_byte & 0x7F);
+ }
+ while(_byte & 0x80);
+
+ return timeval;
+}
+
+//
+// FirstChannelAvailable()
+//
+// Return the next unassigned MIDI channel number
+//
+// The assignment for MUS channel 15 is not counted in the caculation, that
+// being percussion and always assigned to MIDI channel 9 (base 0).
+//
+// Passed the array of MIDI channels assigned to MUS channels
+// Returns the maximum channel number unassigned unless that is 9 in which
+// case 10 is returned.
+//
+// killough 10/7/98: changed char parameter, return values to int
+
+static int FirstChannelAvailable(int MUS2MIDchannel[])
+{
+ int i ;
+ int max = -1 ;
+
+ // find the largest MIDI channel assigned so far
+ for (i = 0; i < 15; i++)
+ if (MUS2MIDchannel[i] > max)
+ max = MUS2MIDchannel[i];
+
+ return (max == 8 ? 10 : max+1); // skip MIDI channel 9 (percussion)
+}
+
+//
+// MidiEvent()
+//
+// Constructs a MIDI event code, and writes it to the current MIDI track
+// unless its the same as the last event code and compressio is enabled
+// in which case nothing is written.
+//
+// Passed the Allegro MIDI structure, the midi event code, the current
+// MIDI channel number, the current MIDI track number, and whether compression
+// (running status) is enabled.
+//
+// Returns the new event code if successful, 0 if a memory allocation error
+//
+static uint8_t MidiEvent(MIDI *mididata,uint8_t midicode,uint8_t MIDIchannel,
+ uint8_t MIDItrack,int nocomp)
+{
+ uint8_t newevent;
+
+ newevent = midicode | MIDIchannel;
+ if ((newevent != track[MIDItrack].lastEvt) || nocomp)
+ {
+ if (TWriteByte(mididata,MIDItrack, newevent))
+ return 0; // indicates MEMALLOC error
+ track[MIDItrack].lastEvt = newevent;
+ }
+ return newevent;
+}
+
+//
+// mmus2mid()
+//
+// Convert a memory buffer contain MUS data to an Allegro MIDI structure
+// with specified time division and compression.
+//
+// Passed a pointer to the buffer containing MUS data, a pointer to the
+// Allegro MIDI structure, the divisions, and a flag whether to compress.
+//
+// Returns 0 if successful, otherwise an error code (see mmus2mid.h).
+//
+int mmus2mid(const uint8_t *mus, MIDI *mididata, uint16_t division, int nocomp)
+{
+ uint16_t TrackCnt = 0;
+ uint8_t evt, MUSchannel, MIDIchannel, MIDItrack=0, NewEvent;
+ int i, event, data;
+ const uint8_t *musptr;
+ size_t muslen;
+ static MUSheader MUSh;
+ uint8_t MIDIchan2track[MIDI_TRACKS]; // killough 10/7/98: fix too small array
+ int MUS2MIDchannel[MIDI_TRACKS]; // killough 10/7/98: fix too small array
+
+ // copy the MUS header from the MUS buffer to the MUSh header structure
+
+ memcpy(&MUSh,mus,sizeof(MUSheader));
+ MUSh.ScoreLength = SHORT(MUSh.ScoreLength);
+ MUSh.ScoreStart = SHORT(MUSh.ScoreStart);
+ MUSh.channels = SHORT(MUSh.channels);
+ MUSh.SecChannels = SHORT(MUSh.SecChannels);
+ MUSh.InstrCnt = SHORT(MUSh.InstrCnt);
+
+ // check some things and set length of MUS buffer from internal data
+
+ if (!(muslen = MUSh.ScoreLength + MUSh.ScoreStart))
+ return MUSDATAMT; // MUS file empty
+
+ if (MUSh.channels > 15) // MUSchannels + drum channel > 16
+ return TOOMCHAN ;
+
+ musptr = mus+MUSh.ScoreStart; // init musptr to start of score
+
+ for (i = 0; i < MIDI_TRACKS; i++) // init the track structure's tracks
+ {
+ MUS2MIDchannel[i] = -1; // flag for channel not used yet
+ track[i].velocity = 64;
+ track[i].deltaT = 0;
+ track[i].lastEvt = 0;
+ //free(mididata->track[i].data);//jff 3/5/98 remove old allocations
+ mididata->track[i].data=NULL;
+ track[i].alloced = 0;
+ mididata->track[i].len = 0;
+ }
+
+ if (!division)
+ division = 70;
+
+ // allocate the first track which is a special tempo/key track
+ // note multiple tracks means midi format 1
+
+ // set the divisions (ticks per quarter note)
+ mididata->divisions = division;
+
+ // allocate for midi tempo/key track, allow for end of track
+ if (!(mididata->track[0].data =
+ realloc(mididata->track[0].data,sizeof(midikey)+sizeof(miditempo)+4)))
+ return MEMALLOC;
+
+ // key C major
+ memcpy(mididata->track[0].data,midikey,sizeof(midikey));
+ // tempo uS/qnote
+ memcpy(mididata->track[0].data+sizeof(midikey),miditempo,sizeof(miditempo));
+ mididata->track[0].len = sizeof(midikey)+sizeof(miditempo);
+
+ TrackCnt++; // music tracks start at 1
+
+ // process the MUS events in the MUS buffer
+
+ do
+ {
+ // get a mus event, decode its type and channel fields
+
+ event = *musptr++;
+ if ((evt = event_type(event)) == SCORE_END) //jff 1/23/98 use symbol
+ break; // if end of score event, leave
+ MUSchannel = channel(event);
+
+ // if this channel not initialized, do so
+
+ if (MUS2MIDchannel[MUSchannel] == -1)
+ {
+ // set MIDIchannel and MIDItrack
+
+ MIDIchannel = MUS2MIDchannel[MUSchannel] =
+ (MUSchannel == 15 ? 9 : FirstChannelAvailable(MUS2MIDchannel));
+ MIDItrack = MIDIchan2track[MIDIchannel] = (uint8_t)TrackCnt++;
+ }
+ else // channel already allocated as a track, use those values
+ {
+ MIDIchannel = MUS2MIDchannel[MUSchannel];
+ MIDItrack = MIDIchan2track[MIDIchannel];
+ }
+
+ if (TWriteVarLen(mididata, MIDItrack, track[MIDItrack].deltaT))
+ return MEMALLOC;
+ track[MIDItrack].deltaT = 0;
+
+ switch(evt)
+ {
+ case RELEASE_NOTE:
+ // killough 10/7/98: Fix noise problems by not allowing compression
+ if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,1)))
+ return MEMALLOC;
+
+ data = *musptr++;
+ if (TWriteByte(mididata, MIDItrack, (uint8_t)(data & 0x7F)))
+ return MEMALLOC;
+ if (TWriteByte(mididata, MIDItrack, 0))
+ return MEMALLOC;
+ break;
+
+ case PLAY_NOTE:
+ if (!(NewEvent=MidiEvent(mididata,0x90,MIDIchannel,MIDItrack,nocomp)))
+ return MEMALLOC;
+
+ data = *musptr++;
+ if (TWriteByte(mididata, MIDItrack, (uint8_t)(data & 0x7F)))
+ return MEMALLOC;
+ if( data & 0x80 )
+ track[MIDItrack].velocity = (*musptr++) & 0x7f;
+ if (TWriteByte(mididata, MIDItrack, track[MIDItrack].velocity))
+ return MEMALLOC;
+ break;
+
+ case BEND_NOTE:
+ if (!(NewEvent=MidiEvent(mididata,0xE0,MIDIchannel,MIDItrack,nocomp)))
+ return MEMALLOC;
+
+ data = *musptr++;
+ if (TWriteByte(mididata, MIDItrack, (uint8_t)((data & 1) << 6)))
+ return MEMALLOC;
+ if (TWriteByte(mididata, MIDItrack, (uint8_t)(data >> 1)))
+ return MEMALLOC;
+ break;
+
+ case SYS_EVENT:
+ if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp)))
+ return MEMALLOC;
+
+ data = *musptr++;
+ if (data<10 || data>14)
+ return BADSYSEVT;
+
+ if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data]))
+ return MEMALLOC;
+ if (data == 12)
+ {
+ if (TWriteByte(mididata, MIDItrack, (uint8_t)(MUSh.channels+1)))
+ return MEMALLOC;
+ }
+ else
+ if (TWriteByte(mididata, MIDItrack, 0))
+ return MEMALLOC;
+ break;
+
+ case CNTL_CHANGE:
+ data = *musptr++;
+ if (data>9)
+ return BADCTLCHG;
+
+ if (data)
+ {
+ if (!(NewEvent=MidiEvent(mididata,0xB0,MIDIchannel,MIDItrack,nocomp)))
+ return MEMALLOC;
+
+ if (TWriteByte(mididata, MIDItrack, MUS2MIDcontrol[data]))
+ return MEMALLOC;
+ }
+ else
+ {
+ if (!(NewEvent=MidiEvent(mididata,0xC0,MIDIchannel,MIDItrack,nocomp)))
+ return MEMALLOC;
+ }
+ data = *musptr++;
+ if (TWriteByte(mididata, MIDItrack, (uint8_t)(data & 0x7F)))
+ return MEMALLOC;
+ break;
+
+ case UNKNOWN_EVENT1: // mus events 5 and 7
+ case UNKNOWN_EVENT2: // meaning not known
+ return BADMUSCTL;
+
+ case SCORE_END:
+ break;
+
+ default:
+ return BADMUSCTL; // exit with error
+ }
+ if (last(event))
+ {
+ uint32_t DeltaTime = ReadTime(&musptr); // killough 10/7/98: make local
+ for (i = 0;i < MIDI_TRACKS; i++) //jff 3/13/98 update all tracks
+ track[i].deltaT += DeltaTime; //whether allocated yet or not
+ }
+
+ }
+ while ((evt != SCORE_END) && ((size_t)(musptr-mus) < muslen));
+
+ if (evt!=SCORE_END)
+ return MUSDATACOR;
+
+ // Now add an end of track to each mididata track, correct allocation
+
+ for (i = 0; i < MIDI_TRACKS; i++)
+ if (mididata->track[i].len)
+ { // killough 10/7/98: simplify code
+ if (TWriteByte(mididata, i, 0x00) || // midi end of track code
+ TWriteByte(mididata, i, 0xFF) ||
+ TWriteByte(mididata, i, 0x2F) ||
+ TWriteByte(mididata, i, 0x00))
+ return MEMALLOC;
+
+ // jff 1/23/98 fix failure to set data NULL, len 0 for unused tracks
+ // shorten allocation to proper length (important for Allegro)
+ if (!(mididata->track[i].data =
+ realloc(mididata->track[i].data,mididata->track[i].len)))
+ return MEMALLOC;
+ }
+ else
+ {
+ free(mididata->track[i].data);
+ mididata->track[i].data = NULL;
+ }
+
+ return 0;
+}
+
+void free_mididata(MIDI *mid)
+{
+ int i;
+
+ for (i = 0; i < MIDI_TRACKS; i++)
+ if (mid->track[i].data)
+ free(mid->track[i].data);
+}
+
+//
+// ReadLength()
+//
+// Reads the length of a chunk in a midi buffer, advancing the pointer
+// 4 bytes, bigendian
+//
+// Passed a pointer to the pointer to a MIDI buffer
+// Returns the chunk length at the pointer position
+//
+static size_t ReadLength(uint8_t **mid)
+{
+ uint8_t *midptr = *mid;
+
+ size_t length = (*midptr++)<<24;
+ length += (*midptr++)<<16;
+ length += (*midptr++)<<8;
+ length += *midptr++;
+ *mid = midptr;
+ return length;
+}
+
+//
+// MidiToMIDI()
+//
+// Convert an in-memory copy of a MIDI format 0 or 1 file to
+// an Allegro MIDI structure, that is valid or has been zeroed
+//
+// Passed a pointer to a memory buffer with MIDI format music in it and a
+// pointer to an Allegro MIDI structure.
+//
+// Returns 0 if successful, BADMIDHDR if the buffer is not MIDI format
+//
+int MidiToMIDI(uint8_t *mid,MIDI *mididata)
+{
+ int i;
+ int ntracks;
+
+ // read the midi header
+
+ if (memcmp(mid,midihdr,4))
+ return BADMIDHDR;
+
+ mididata->divisions = (mid[12]<<8)+mid[13];
+ ntracks = (mid[10]<<8)+mid[11];
+
+ if (ntracks>=MIDI_TRACKS)
+ return BADMIDHDR;
+
+ mid += 4;
+ { // killough 10/7/98: fix mid from being modified twice before sequence pt.
+ size_t t = ReadLength(&mid); // seek past header
+ mid += t;
+ }
+
+ // now read each track
+
+ for (i=0;i<ntracks;i++)
+ {
+ while (memcmp(mid,trackhdr,4)) // simply skip non-track data
+ {
+ mid += 4;
+ {
+ size_t t = ReadLength(&mid); // seek past header
+ mid += t; // killough 10/7/98: prevent mid undefined behavior
+ }
+ }
+ mid += 4;
+ mididata->track[i].len = ReadLength(&mid); // get length, move mid past it
+
+ // read a track
+ mididata->track[i].data = realloc(mididata->track[i].data,mididata->track[i].len);
+ memcpy(mididata->track[i].data,mid,mididata->track[i].len);
+ mid += mididata->track[i].len;
+ }
+ for (;i<MIDI_TRACKS;i++)
+ if (mididata->track[i].len)
+ {
+ free(mididata->track[i].data);
+ mididata->track[i].data = NULL;
+ mididata->track[i].len = 0;
+ }
+ return 0;
+}
+
+//#ifdef STANDALONE /* this code unused by BOOM provided for future portability */
+// /* it also provides a MUS to MID file converter*/
+// proff: I moved this down, because I need MIDItoMidi
+
+//
+// TWriteLength()
+//
+// Write the length of a MIDI chunk to a midi buffer. The length is four
+// uint8_ts and is written uint8_t-reversed for bigendian. The pointer to the
+// midi buffer is advanced.
+//
+// Passed a pointer to the pointer to a midi buffer, and the length to write
+// Returns nothing
+//
+static void TWriteLength(uint8_t **midiptr,uint32_t length)
+{
+// proff: Added typecast to avoid warning
+ *(*midiptr)++ = (unsigned char)((length>>24)&0xff);
+ *(*midiptr)++ = (unsigned char)((length>>16)&0xff);
+ *(*midiptr)++ = (unsigned char)((length>>8)&0xff);
+ *(*midiptr)++ = (unsigned char)((length)&0xff);
+}
+
+//
+// MIDIToMidi()
+//
+// This routine converts an Allegro MIDI structure to a midi 1 format file
+// in memory. It is used to support memory MUS -> MIDI conversion
+//
+// Passed a pointer to an Allegro MIDI structure, a pointer to a pointer to
+// a buffer containing midi data, and a pointer to a length return.
+// Returns 0 if successful, MEMALLOC if a memory allocation error occurs
+//
+int MIDIToMidi(MIDI *mididata,uint8_t **mid,int *midlen)
+{
+ size_t total;
+ int i,ntrks;
+ uint8_t *midiptr;
+
+ // calculate how long the mid buffer must be, and allocate
+
+ total = sizeof(midihdr);
+ for (i=0,ntrks=0;i<MIDI_TRACKS;i++)
+ if (mididata->track[i].len)
+ {
+ total += 8 + mididata->track[i].len; // Track hdr + track length
+ ntrks++;
+ }
+ if ((*mid = malloc(total))==NULL)
+ return MEMALLOC;
+
+
+ // fill in number of tracks and bigendian divisions (ticks/qnote)
+
+ midihdr[10] = 0;
+ midihdr[11] = (uint8_t)ntrks; // set number of tracks in header
+ midihdr[12] = (mididata->divisions>>8) & 0x7f;
+ midihdr[13] = (mididata->divisions) & 0xff;
+
+ // write the midi header
+
+ midiptr = *mid;
+ memcpy(midiptr,midihdr,sizeof(midihdr));
+ midiptr += sizeof(midihdr);
+
+ // write the tracks
+
+ for (i=0;i<MIDI_TRACKS;i++)
+ {
+ if (mididata->track[i].len)
+ {
+ memcpy(midiptr,trackhdr,sizeof(trackhdr)); // header
+ midiptr += sizeof(trackhdr);
+ TWriteLength(&midiptr,mididata->track[i].len); // track length
+ // data
+ memcpy(midiptr,mididata->track[i].data,mididata->track[i].len);
+ midiptr += mididata->track[i].len;
+ }
+ }
+
+ // return length information
+
+ *midlen = midiptr - *mid;
+
+ return 0;
+}
+
+#ifdef STANDALONE /* this code unused by BOOM provided for future portability */
+ /* it also provides a MUS to MID file converter*/
+// proff: I moved this down, because I need MIDItoMidi
+
+//
+// FreeTracks()
+//
+// Free all track allocations in the MIDI structure
+//
+// Passed a pointer to an Allegro MIDI structure
+// Returns nothing
+//
+static void FreeTracks(MIDI *mididata)
+{
+ int i;
+
+ for (i=0; i<MIDI_TRACKS; i++)
+ {
+ free(mididata->track[i].data);
+ mididata->track[i].data = NULL;
+ mididata->track[i].len = 0;
+ }
+}
+
+//
+// main()
+//
+// Main routine that will convert a globbed set of MUS files to the
+// correspondingly named MID files using mmus2mid(). Only compiled
+// if the STANDALONE symbol is defined.
+//
+// Passed the command line arguments, returns 0 if successful
+//
+int main(int argc,char **argv)
+{
+ FILE *musst,*midst;
+ char musfile[FILENAME_MAX],midfile[FILENAME_MAX];
+ MUSheader MUSh;
+ uint8_t *mus,*mid;
+ static MIDI mididata;
+ int err,midlen;
+ char *p,*q;
+ int i;
+
+ if (argc<2)
+ {
+ //jff 8/3/98 use logical output routine
+ lprintf(LO_INFO,"Usage: MMUS2MID musfile[.MUS]\n");
+ lprintf(LO_INFO,"writes musfile.MID as output\n");
+ lprintf(LO_INFO,"musfile may contain wildcards\n");
+ exit(1);
+ }
+
+ for (i=1;i<argc;i++)
+ {
+ strcpy(musfile,argv[i]);
+ p = strrchr(musfile,'.');
+ q = strrchr(musfile,'\\');
+ if (p && (!q || q<p)) *p='\0';
+ strcpy(midfile,musfile);
+ strcat(musfile,".MUS");
+ strcat(midfile,".MID");
+
+ musst = fopen(musfile,"rb");
+ if (musst)
+ {
+ fread(&MUSh,sizeof(MUSheader),1,musst);
+ mus = malloc(MUSh.ScoreLength+MUSh.ScoreStart);
+ if (mus)
+ {
+ fseek(musst,0,SEEK_SET);
+ if (!fread(mus,MUSh.ScoreLength+MUSh.ScoreStart,1,musst))
+ {
+ //jff 8/3/98 use logical output routine
+ lprintf(LO_FATAL,"Error reading MUS file\n");
+ free(mus);
+ exit(1);
+ }
+ fclose(musst);
+ }
+ else
+ {
+ //jff 8/3/98 use logical output routine
+ lprintf(LO_FATAL,"Out of memory\n");
+ free(mus);
+ exit(1);
+ }
+
+ err = mmus2mid(mus,&mididata,89,1);
+ if (err)
+ {
+ //jff 8/3/98 use logical output routine
+ lprintf(LO_FATAL,"Error converting MUS file to MIDI: %d\n",err);
+ exit(1);
+ }
+ free(mus);
+
+ MIDIToMidi(&mididata,&mid,&midlen);
+
+ midst = fopen(midfile,"wb");
+ if (midst)
+ {
+ if (!fwrite(mid,midlen,1,midst))
+ {
+ //jff 8/3/98 use logical output routine
+ lprintf(LO_FATAL,"Error writing MIDI file\n");
+ FreeTracks(&mididata);
+ free(mid);
+ exit(1);
+ }
+ fclose(midst);
+ }
+ else
+ {
+ //jff 8/3/98 use logical output routine
+ lprintf(LO_FATAL,"Can't open MIDI file for output: %s\n", midfile);
+ FreeTracks(&mididata);
+ free(mid);
+ exit(1);
+ }
+ }
+ else
+ {
+ //jff 8/3/98 use logical output routine
+ lprintf(LO_FATAL,"Can't open MUS file for input: %s\n", midfile);
+ exit(1);
+ }
+
+ //jff 8/3/98 use logical output routine
+ lprintf(LO_CONFIRM,"MUS file %s converted to MIDI file %s\n",musfile,midfile);
+ FreeTracks(&mididata);
+ free(mid);
+ }
+ exit(0);
+}
+
+#endif
--- /dev/null
+++ b/mmus2mid.h
@@ -1,0 +1,69 @@
+/* $Id: mmus2mid.h 373 2009-05-19 18:14:28Z sezero $
+ *
+ * Ripped && Adapted from the PrBoom project:
+ * PrBoom: a Doom port merged with LxDoom and LSDLDoom
+ * based on BOOM, a modified and improved DOOM engine
+ * Copyright (C) 1999 by
+ * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
+ * Copyright (C) 1999-2000 by
+ * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
+ * Copyright 2005, 2006 by
+ * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ *
+ * DESCRIPTION:
+ * mmus2mid.c supports conversion of MUS format music in memory
+ * to MIDI format 1 music in memory.
+ */
+
+#if !defined( MMUS2MID_H )
+#define MMUS2MID_H
+
+// error codes
+
+typedef enum
+{
+ MUSDATACOR, // MUS data corrupt
+ TOOMCHAN, // Too many channels
+ MEMALLOC, // Memory allocation error
+ MUSDATAMT, // MUS file empty
+ BADMUSCTL, // MUS event 5 or 7 found
+ BADSYSEVT, // MUS system event not in 10-14 range
+ BADCTLCHG, // MUS control change larger than 9
+ TRACKOVF, // MIDI track exceeds allocation
+ BADMIDHDR, // bad midi header detected
+} error_code_t;
+
+#ifndef MSDOS /* proff: This is from allegro.h */
+#define MIDI_TRACKS 32
+
+typedef struct MIDI /* a midi file */
+{
+ int divisions; /* number of ticks per quarter note */
+ struct {
+ unsigned char *data; /* MIDI message stream */
+ int len; /* length of the track data */
+ } track[MIDI_TRACKS];
+} MIDI;
+#endif /* !MSDOS */
+
+extern int mmus2mid(const uint8_t *mus,MIDI *mid, uint16_t division, int nocomp);
+extern void free_mididata(MIDI *mid);
+extern int MIDIToMidi(MIDI *mididata,uint8_t **mid,int *midlen);
+extern int MidiToMIDI(uint8_t *mid,MIDI *mididata);
+
+#endif
--- /dev/null
+++ b/mn_menu.c
@@ -1,0 +1,2253 @@
+//**************************************************************************
+//**
+//** mn_menu.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 560 $
+//** $Date: 2010-10-20 15:15:39 +0300 (Wed, 20 Oct 2010) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include <ctype.h>
+#include "h2def.h"
+#include "p_local.h"
+#include "r_local.h"
+#include "i_cdmus.h"
+#include "soundst.h"
+#include "v_compat.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define LEFT_DIR 0
+#define RIGHT_DIR 1
+#define ITEM_HEIGHT 20
+#define SMALL_ITEM_HEIGHT 9
+#define MENU_MAX_MOUSE_SENS 50
+
+#define SELECTOR_XOFFSET (-28)
+#define SELECTOR_YOFFSET (-1)
+#define SLOTTEXTLEN 16
+#define ASCII_CURSOR '['
+
+#ifdef RENDER3D
+#define V_DrawPatch(x,y,p) OGL_DrawPatch((x),(y),(p))
+#define V_DrawRawScreen(a) OGL_DrawRawScreen((a))
+#endif
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+ ITT_EMPTY,
+ ITT_EFUNC,
+ ITT_LRFUNC,
+ ITT_SETMENU,
+ ITT_INERT,
+ ITT_SETKEY
+} ItemType_t;
+
+typedef enum
+{
+ MENU_MAIN,
+ MENU_CLASS,
+ MENU_SKILL,
+ MENU_OPTIONS,
+ MENU_OPTIONS2,
+ MENU_OPTIONS3,
+ MENU_FILES,
+ MENU_LOAD,
+ MENU_SAVE,
+ MENU_NONE
+} MenuType_t;
+
+typedef struct
+{
+ ItemType_t type;
+ const char *text;
+ void (*func)(int option);
+ int option;
+ MenuType_t menu;
+} MenuItem_t;
+
+typedef struct
+{
+ int x;
+ int y;
+ void (*drawFunc)(void);
+ int itemCount;
+ MenuItem_t *items;
+ int oldItPos;
+ int step;
+ MenuType_t prevMenu;
+} Menu_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static const char *Key2String(int key);
+static void ClearControls(int key);
+static void InitFonts(void);
+static void SetTheMenu(MenuType_t menu);
+static void SCQuitGame(int option);
+static void SCClass(int option);
+static void SCSkill(int option);
+static void SCMouseSensi(int option);
+static void SCSfxVolume(int option);
+static void SCMusicVolume(int option);
+static void SCScreenSize(int option);
+static boolean SCNetCheck(int option);
+static void SCNetCheck2(int option);
+static void SCLoadGame(int option);
+static void SCSaveGame(int option);
+static void SCMessages(int option);
+static void SCEndGame(int option);
+static void SCInfo(int option);
+static void SCSetKey(int option);
+static void SCMouselook(int option);
+static void SCAlwaysRun(int option);
+static void SCCDAudio(int option);
+static void DrawMainMenu(void);
+static void DrawClassMenu(void);
+static void DrawSkillMenu(void);
+static void DrawOptionsMenu(void);
+static void DrawOptions2Menu(void);
+static void DrawOptions3Menu(void);
+static void DrawFileSlots(Menu_t *menu);
+static void DrawFilesMenu(void);
+static void MN_DrawInfo(void);
+static void DrawLoadMenu(void);
+static void DrawSaveMenu(void);
+static void DrawSlider(Menu_t *menu, int item, int width, int slot);
+static void MN_LoadSlotText(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern default_t defaults[];
+
+extern int detailLevel;
+extern int screenblocks;
+extern boolean gamekeydown[MAXKEYS];
+
+extern int alwaysrun;
+extern int mouselook;
+
+extern int key_right,key_left,key_up,key_down;
+extern int key_straferight,key_strafeleft,key_jump;
+extern int key_fire, key_use, key_strafe, key_speed;
+extern int key_flyup, key_flydown, key_flycenter;
+extern int key_lookup, key_lookdown, key_lookcenter;
+extern int key_invleft, key_invright, key_useartifact;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+boolean MenuActive;
+int InfoType;
+int messageson; /* boolean */
+boolean mn_SuicideConsole;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int FontABaseLump;
+static int FontAYellowBaseLump;
+static int FontBBaseLump;
+static int MauloBaseLump;
+static Menu_t *CurrentMenu;
+static int CurrentItPos;
+static int MenuPClass;
+static int MenuTime;
+static boolean soundchanged;
+
+#ifdef RENDER3D
+static float bgAlpha = 0;
+static float outFade = 0;
+static boolean fadingOut = false;
+static int menuDarkTicks = 15;
+static int slamInTicks = 9;
+#endif
+
+boolean askforquit;
+static boolean FileMenuKeySteal;
+static boolean slottextloaded;
+static char SlotText[6][SLOTTEXTLEN+2];
+static char oldSlotText[SLOTTEXTLEN+2];
+static int SlotStatus[6];
+static int slotptr;
+static int currentSlot;
+static int quicksave;
+static int quickload;
+static int typeofask;
+
+static int FirstKey = 0;
+static boolean askforkey = false;
+static int keyaskedfor;
+
+static MenuItem_t MainItems[] =
+{
+ { ITT_SETMENU, "NEW GAME", SCNetCheck2, 1, MENU_CLASS },
+ { ITT_SETMENU, "OPTIONS", NULL, 0, MENU_OPTIONS },
+ { ITT_SETMENU, "GAME FILES", NULL, 0, MENU_FILES },
+ { ITT_EFUNC, "INFO", SCInfo, 0, MENU_NONE },
+ { ITT_EFUNC, "QUIT GAME", SCQuitGame, 0, MENU_NONE }
+};
+
+static Menu_t MainMenu =
+{
+ 110, 56,
+ DrawMainMenu,
+ 5, MainItems,
+ 0,
+ ITEM_HEIGHT,
+ MENU_NONE
+};
+
+static MenuItem_t ClassItems[] =
+{
+ { ITT_EFUNC, "FIGHTER", SCClass, 0, MENU_NONE },
+ { ITT_EFUNC, "CLERIC", SCClass, 1, MENU_NONE },
+ { ITT_EFUNC, "MAGE", SCClass, 2, MENU_NONE },
+#ifdef ASSASSIN
+ { ITT_EFUNC, "ASSASSIN", SCClass, 3, MENU_NONE }
+#endif
+};
+
+static Menu_t ClassMenu =
+{
+ 66, 66,
+ DrawClassMenu,
+ NUMCLASSES_HUMAN,
+ ClassItems,
+ 0,
+ ITEM_HEIGHT,
+ MENU_MAIN
+};
+
+static MenuItem_t FilesItems[] =
+{
+ { ITT_SETMENU, "LOAD GAME", SCNetCheck2, 2, MENU_LOAD },
+ { ITT_SETMENU, "SAVE GAME", NULL, 0, MENU_SAVE }
+};
+
+static Menu_t FilesMenu =
+{
+ 110, 60,
+ DrawFilesMenu,
+ 2, FilesItems,
+ 0,
+ ITEM_HEIGHT,
+ MENU_MAIN
+};
+
+static MenuItem_t LoadItems[] =
+{
+ { ITT_EFUNC, NULL, SCLoadGame, 0, MENU_NONE },
+ { ITT_EFUNC, NULL, SCLoadGame, 1, MENU_NONE },
+ { ITT_EFUNC, NULL, SCLoadGame, 2, MENU_NONE },
+ { ITT_EFUNC, NULL, SCLoadGame, 3, MENU_NONE },
+ { ITT_EFUNC, NULL, SCLoadGame, 4, MENU_NONE },
+ { ITT_EFUNC, NULL, SCLoadGame, 5, MENU_NONE }
+};
+
+static Menu_t LoadgameMenu =
+{
+ 70, 30,
+ DrawLoadMenu,
+ 6, LoadItems,
+ 0,
+ ITEM_HEIGHT,
+ MENU_FILES
+};
+
+static MenuItem_t SaveItems[] =
+{
+ { ITT_EFUNC, NULL, SCSaveGame, 0, MENU_NONE },
+ { ITT_EFUNC, NULL, SCSaveGame, 1, MENU_NONE },
+ { ITT_EFUNC, NULL, SCSaveGame, 2, MENU_NONE },
+ { ITT_EFUNC, NULL, SCSaveGame, 3, MENU_NONE },
+ { ITT_EFUNC, NULL, SCSaveGame, 4, MENU_NONE },
+ { ITT_EFUNC, NULL, SCSaveGame, 5, MENU_NONE }
+};
+
+static Menu_t SavegameMenu =
+{
+ 70, 30,
+ DrawSaveMenu,
+ 6, SaveItems,
+ 0,
+ ITEM_HEIGHT,
+ MENU_FILES
+};
+
+static MenuItem_t SkillItems[] =
+{
+ { ITT_EFUNC, NULL, SCSkill, sk_baby, MENU_NONE },
+ { ITT_EFUNC, NULL, SCSkill, sk_easy, MENU_NONE },
+ { ITT_EFUNC, NULL, SCSkill, sk_medium, MENU_NONE },
+ { ITT_EFUNC, NULL, SCSkill, sk_hard, MENU_NONE },
+ { ITT_EFUNC, NULL, SCSkill, sk_nightmare, MENU_NONE }
+};
+
+static Menu_t SkillMenu =
+{
+ 120, 44,
+ DrawSkillMenu,
+ 5, SkillItems,
+ 2,
+ ITEM_HEIGHT,
+ MENU_CLASS
+};
+
+static MenuItem_t OptionsItems[] =
+{
+ { ITT_EFUNC, "END GAME", SCEndGame, 0, MENU_NONE },
+ { ITT_EFUNC, "MESSAGES : ", SCMessages, 0, MENU_NONE },
+ { ITT_LRFUNC, "MOUSE SENSITIVITY :", SCMouseSensi, 0, MENU_NONE },
+ { ITT_SETMENU, "CONTROL SETUP", NULL, 0, MENU_OPTIONS3 },
+ { ITT_LRFUNC, "MOUSELOOK : ", SCMouselook, 0, MENU_NONE },
+ { ITT_EFUNC, "ALWAYS RUN : ", SCAlwaysRun, 0, MENU_NONE },
+ { ITT_SETMENU, "MORE...", NULL, 0, MENU_OPTIONS2 }
+};
+
+static Menu_t OptionsMenu =
+{
+ 88, 30,
+ DrawOptionsMenu,
+ 7,
+ OptionsItems,
+ 0,
+ ITEM_HEIGHT,
+ MENU_MAIN
+};
+
+static MenuItem_t Options2Items[] =
+{
+ { ITT_LRFUNC, "SCREEN SIZE", SCScreenSize, 0, MENU_NONE },
+ { ITT_EMPTY, NULL, NULL, 0, MENU_NONE },
+ { ITT_LRFUNC, "SFX VOLUME", SCSfxVolume, 0, MENU_NONE },
+ { ITT_EMPTY, NULL, NULL, 0, MENU_NONE },
+ { ITT_LRFUNC, "MUSIC VOLUME", SCMusicVolume, 0, MENU_NONE },
+ { ITT_EMPTY, NULL, NULL, 0, MENU_NONE },
+ { ITT_EFUNC, "CD AUDIO :", SCCDAudio, 0, MENU_NONE }
+};
+
+static Menu_t Options2Menu =
+{
+ 90, 20,
+ DrawOptions2Menu,
+ 7,
+ Options2Items,
+ 0,
+ ITEM_HEIGHT,
+ MENU_OPTIONS
+};
+
+static MenuItem_t Options3Items[] =
+{
+/* see defaults[] in m_misc.c for the correct option number:
+ * key_right corresponds to defaults[3], which means that we
+ * are using the (index_number - 3) here.
+ */
+ { ITT_SETKEY, "TURN RIGHT :", SCSetKey, 0, MENU_NONE },
+ { ITT_SETKEY, "TURN LEFT :", SCSetKey, 1, MENU_NONE },
+ { ITT_SETKEY, "MOVE FORWARD :", SCSetKey, 2, MENU_NONE },
+ { ITT_SETKEY, "MOVE BACK :" , SCSetKey, 3, MENU_NONE },
+ { ITT_SETKEY, "STRAFE LEFT :", SCSetKey, 4, MENU_NONE },
+ { ITT_SETKEY, "STRAFE RIGHT :", SCSetKey, 5, MENU_NONE },
+ { ITT_SETKEY, "FLY UP :", SCSetKey, 6, MENU_NONE },
+ { ITT_SETKEY, "FLY DOWN :", SCSetKey, 7, MENU_NONE },
+ { ITT_SETKEY, "FLY CENTER :", SCSetKey, 8, MENU_NONE },
+ { ITT_SETKEY, "LOOK UP :", SCSetKey, 9, MENU_NONE },
+ { ITT_SETKEY, "LOOK DOWN :", SCSetKey, 10, MENU_NONE },
+ { ITT_SETKEY, "LOOK CENTER :", SCSetKey, 11, MENU_NONE },
+ { ITT_SETKEY, "INVENTORY LEFT :", SCSetKey, 12, MENU_NONE },
+ { ITT_SETKEY, "INVENTORY RIGHT :", SCSetKey, 13, MENU_NONE },
+ { ITT_SETKEY, "USE ARTIFACT :", SCSetKey, 14, MENU_NONE },
+ { ITT_SETKEY, "FIRE :", SCSetKey, 15, MENU_NONE },
+ { ITT_SETKEY, "USE :", SCSetKey, 16, MENU_NONE },
+ { ITT_SETKEY, "STRAFE :", SCSetKey, 17, MENU_NONE },
+ { ITT_SETKEY, "SPEED :", SCSetKey, 18, MENU_NONE },
+ { ITT_SETKEY, "JUMP :", SCSetKey, 19, MENU_NONE }
+};
+
+/* Many items in Options3Items[], only 15 can be drawn on a page:
+ * So, FirstKey changes between 0 and FIRSTKEY_MAX. This menu is
+ * way too fragile. Should we adapt from Quake's M_Menu_Keys and
+ * bindnames?? */
+#define FIRSTKEY_MAX 5
+static Menu_t Options3Menu =
+{
+ 70, 20,
+ DrawOptions3Menu,
+ 15, /* actually 20 */
+ Options3Items,
+ 0,
+ SMALL_ITEM_HEIGHT,
+ MENU_OPTIONS
+};
+
+static Menu_t *Menus[] =
+{
+ &MainMenu,
+ &ClassMenu,
+ &SkillMenu,
+ &OptionsMenu,
+ &Options2Menu,
+ &Options3Menu,
+ &FilesMenu,
+ &LoadgameMenu,
+ &SavegameMenu
+};
+
+static const char *mlooktext[] =
+{
+ "OFF",
+ "NORMAL",
+ "INVERSE"
+};
+
+static const char *stupidtable[] =
+{
+ "A","B","C","D","E",
+ "F","G","H","I","J",
+ "K","L","M","N","O",
+ "P","Q","R","S","T",
+ "U","V","W","X","Y",
+ "Z"
+};
+
+static const char *GammaText[] =
+{
+ TXT_GAMMA_LEVEL_OFF,
+ TXT_GAMMA_LEVEL_1,
+ TXT_GAMMA_LEVEL_2,
+ TXT_GAMMA_LEVEL_3,
+ TXT_GAMMA_LEVEL_4
+};
+
+// CODE --------------------------------------------------------------------
+
+static const char *Key2String (int key)
+{
+/* S.A.: return "[" or "]" or "\"" doesn't work
+ * because there are no lumps for these chars,
+ * therefore we have to go with "RIGHT BRACKET"
+ * and similar for much punctuation. Probably
+ * won't work with international keyboards and
+ * dead keys, either.
+ */
+ switch (key)
+ {
+ case KEY_LEFTBRACKET: return "LEFT BRACK";
+ case KEY_RIGHTBRACKET: return "RIGHT BRACK";
+ case KEY_BACKQUOTE: return "BACK QUOTE";
+ case KEY_QUOTE: return "'";
+ case KEY_QUOTEDBL: return "DOUBLE QUOTE";
+ case KEY_SEMICOLON: return ";";
+ case KEY_MINUS: return "-";
+ case KEY_PERIOD: return ".";
+ case KEY_COMMA: return ",";
+ case KEY_SLASH: return "/";
+ case KEY_BACKSLASH: return "BACKSLASH";
+ case KEY_TAB: return "TAB";
+ case KEY_EQUALS: return "=";
+
+ case KEY_RIGHTARROW: return "RIGHT ARROW";
+ case KEY_LEFTARROW: return "LEFT ARROW";
+ case KEY_DOWNARROW: return "DOWN ARROW";
+ case KEY_UPARROW: return "UP ARROW";
+ case KEY_ENTER: return "ENTER";
+ case KEY_PGUP: return "PAGE UP";
+ case KEY_PGDN: return "PAGE DOWN";
+ case KEY_INS: return "INSERT";
+ case KEY_HOME: return "HOME";
+ case KEY_END: return "END";
+ case KEY_DEL: return "DELETE";
+ case ' ': return "SPACE";
+ case KEY_RSHIFT: return "SHIFT";
+ case KEY_RALT: return "ALT";
+ case KEY_RCTRL: return "CTRL";
+ }
+ /* Handle letter keys */
+ /* S.A.: could also be done with toupper */
+ if (key >= 'a' && key <= 'z')
+ return stupidtable[(key - 'a')];
+
+ return "?"; /* Everything else */
+}
+
+static void ClearControls (int key)
+{
+ int i;
+
+ for (i = 3; i < 24; i++)
+ {
+ if (*defaults[i].location == key)
+ *defaults[i].location = 0;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Init
+//
+//---------------------------------------------------------------------------
+
+void MN_Init(void)
+{
+ InitFonts();
+ MenuActive = false;
+// messageson = 1; // Set by defaults in .CFG
+ MauloBaseLump = W_GetNumForName("FBULA0"); // ("M_SKL00");
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC InitFonts
+//
+//---------------------------------------------------------------------------
+
+static void InitFonts(void)
+{
+ FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+ FontAYellowBaseLump = W_GetNumForName("FONTAY_S") + 1;
+ FontBBaseLump = W_GetNumForName("FONTB_S") + 1;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrTextA
+//
+// Draw text using font A.
+//
+//---------------------------------------------------------------------------
+
+void MN_DrTextA(const char *text, int x, int y)
+{
+ char c;
+ patch_t *p;
+
+#ifdef RENDER3D
+ OGL_SetColorAndAlpha(1, 1, 1, 1);
+#endif
+
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ x += 5;
+ }
+ else
+ {
+ p = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+#ifdef RENDER3D
+ OGL_DrawPatch_CS(x, y, FontABaseLump + c - 33);
+#else
+ V_DrawPatch(x, y, p);
+#endif
+ x += SHORT(p->width) - 1;
+ }
+ }
+}
+
+//==========================================================================
+//
+// MN_DrTextAYellow
+//
+//==========================================================================
+
+void MN_DrTextAYellow(const char *text, int x, int y)
+{
+ char c;
+ patch_t *p;
+
+#ifdef RENDER3D
+ OGL_SetColorAndAlpha(1, 1, 1, 1);
+#endif
+
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ x += 5;
+ }
+ else
+ {
+ p = (patch_t *) W_CacheLumpNum(FontAYellowBaseLump + c - 33, PU_CACHE);
+#ifdef RENDER3D
+ OGL_DrawPatch_CS(x, y, FontAYellowBaseLump + c - 33);
+#else
+ V_DrawPatch(x, y, p);
+#endif
+ x += SHORT(p->width) - 1;
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_TextAWidth
+//
+// Returns the pixel width of a string using font A.
+//
+//---------------------------------------------------------------------------
+
+int MN_TextAWidth(const char *text)
+{
+ char c;
+ int width;
+ patch_t *p;
+
+ width = 0;
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ width += 5;
+ }
+ else
+ {
+ p = (patch_t *) W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);
+ width += SHORT(p->width) - 1;
+ }
+ }
+ return (width);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrTextB
+//
+// Draw text using font B.
+//
+//---------------------------------------------------------------------------
+
+void MN_DrTextB(const char *text, int x, int y)
+{
+ char c;
+ patch_t *p;
+
+#ifdef RENDER3D
+ OGL_SetColorAndAlpha(1, 1, 1, 1);
+#endif
+
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ x += 8;
+ }
+ else
+ {
+ p = (patch_t *) W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE);
+#ifdef RENDER3D
+ OGL_DrawPatch_CS(x, y, FontBBaseLump + c - 33);
+#else
+ V_DrawPatch(x, y, p);
+#endif
+ x += SHORT(p->width) - 1;
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_TextBWidth
+//
+// Returns the pixel width of a string using font B.
+//
+//---------------------------------------------------------------------------
+
+int MN_TextBWidth(const char *text)
+{
+ char c;
+ int width;
+ patch_t *p;
+
+ width = 0;
+ while ((c = *text++) != 0)
+ {
+ if (c < 33)
+ {
+ width += 5;
+ }
+ else
+ {
+ p = (patch_t *) W_CacheLumpNum(FontBBaseLump + c - 33, PU_CACHE);
+ width += SHORT(p->width) - 1;
+ }
+ }
+ return (width);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Ticker
+//
+//---------------------------------------------------------------------------
+
+void MN_Ticker(void)
+{
+ if (MenuActive == false)
+ {
+#ifdef RENDER3D
+ if (bgAlpha > 0)
+ {
+ bgAlpha -= .5 / (float)menuDarkTicks;
+ if (bgAlpha < 0)
+ bgAlpha = 0;
+ }
+ if (fadingOut)
+ {
+ outFade += 1 / (float)slamInTicks;
+ if (outFade > 1)
+ fadingOut = false;
+ }
+#endif
+ return;
+ }
+ MenuTime++;
+}
+
+
+#ifdef RENDER3D
+static void MN_OGL_SetupState(float time)
+{
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+
+ if (time > 1 && time <= 2)
+ {
+ time = 2 - time;
+ glTranslatef(160, 100, 0);
+ glScalef(.9 + time*.1, .9 + time*.1, 1);
+ glTranslatef(-160, -100, 0);
+ glColor4f(1, 1, 1, time);
+ return;
+ }
+
+ glTranslatef(160, 100, 0);
+ glScalef(2-time, 2-time, 1);
+ glTranslatef(-160, -100, 0);
+ glColor4f(1, 1, 1, time*time);
+}
+
+static void MN_OGL_RestoreState(void)
+{
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+}
+#endif
+
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_Drawer
+//
+//---------------------------------------------------------------------------
+
+static const char *QuitEndMsg[] =
+{
+ "ARE YOU SURE YOU WANT TO QUIT?",
+ "ARE YOU SURE YOU WANT TO END THE GAME?",
+ "DO YOU WANT TO QUICKSAVE THE GAME NAMED",
+ "DO YOU WANT TO QUICKLOAD THE GAME NAMED",
+ "ARE YOU SURE YOU WANT TO SUICIDE?"
+};
+
+
+void MN_Drawer(void)
+{
+ int i;
+ int x;
+ int y;
+ MenuItem_t *item;
+ const char *selName;
+
+ if (MenuActive == false)
+ {
+#ifdef RENDER3D
+ if (bgAlpha > 0)
+ {
+ UpdateState |= I_FULLSCRN;
+ BorderNeedRefresh = true;
+ // OGL_SetNoTexture();
+ glDisable(GL_TEXTURE_2D);
+ OGL_DrawRect(0, 0, 320, 200, 0, 0, 0, bgAlpha);
+ glEnable(GL_TEXTURE_2D);
+ }
+#endif
+ if (askforquit)
+ {
+ MN_DrTextA(QuitEndMsg[typeofask-1], 160 - MN_TextAWidth(QuitEndMsg[typeofask-1])/2, 80);
+ if (typeofask == 3)
+ {
+ MN_DrTextA(SlotText[quicksave-1], 160 - MN_TextAWidth(SlotText[quicksave-1])/2, 90);
+ MN_DrTextA("?", 160 + MN_TextAWidth(SlotText[quicksave-1])/2, 90);
+ }
+ if (typeofask == 4)
+ {
+ MN_DrTextA(SlotText[quickload-1], 160 - MN_TextAWidth(SlotText[quickload-1])/2, 90);
+ MN_DrTextA("?", 160 + MN_TextAWidth(SlotText[quicksave-1])/2, 90);
+ }
+ UpdateState |= I_FULLSCRN;
+ }
+ }
+#ifdef RENDER3D
+ if (MenuActive || fadingOut)
+ {
+ int effTime = (MenuTime > menuDarkTicks) ? menuDarkTicks : MenuTime;
+ float temp = .5 * effTime / (float)menuDarkTicks;
+
+ UpdateState |= I_FULLSCRN;
+
+ if (!fadingOut)
+ {
+ if (temp > bgAlpha)
+ bgAlpha = temp;
+ effTime = (MenuTime>slamInTicks) ? slamInTicks : MenuTime;
+ temp = effTime / (float)slamInTicks;
+
+ // Draw a dark background. It makes it easier to read the menus.
+ //OGL_SetNoTexture();
+ glDisable(GL_TEXTURE_2D);
+ OGL_DrawRect(0, 0, 320, 200, 0, 0, 0, bgAlpha);
+ glEnable(GL_TEXTURE_2D);
+ }
+ else
+ temp = outFade + 1;
+ MN_OGL_SetupState(temp);
+
+ if (InfoType)
+ {
+ MN_DrawInfo();
+ MN_OGL_RestoreState();
+ return;
+ }
+ // if (screenblocks < 10)
+ // {
+ BorderNeedRefresh = true;
+ // }
+ if (CurrentMenu->drawFunc != NULL)
+ {
+ CurrentMenu->drawFunc();
+ }
+ x = CurrentMenu->x;
+ y = CurrentMenu->y;
+ item = CurrentMenu->items;
+ if (item->type == ITT_SETKEY)
+ item += FirstKey;
+ for (i = 0; i < CurrentMenu->itemCount; i++)
+ {
+ switch (item->type)
+ {
+ case (ITT_EMPTY):
+ break;
+ case (ITT_SETKEY):
+ if (item->text)
+ MN_DrTextA(item->text, x, y+6);
+ break;
+ default:
+ if (item->text)
+ MN_DrTextB(item->text, x, y);
+ }
+ y += CurrentMenu->step;
+ item++;
+ }
+ y = CurrentMenu->y + (CurrentItPos * CurrentMenu->step) + SELECTOR_YOFFSET;
+ selName = (MenuTime & 16) ? "M_SLCTR1" : "M_SLCTR2";
+ OGL_DrawPatch_CS(x + SELECTOR_XOFFSET, y, W_GetNumForName(selName));
+
+ MN_OGL_RestoreState();
+ }
+#else
+ else
+ {
+ UpdateState |= I_FULLSCRN;
+ if (InfoType)
+ {
+ MN_DrawInfo();
+ return;
+ }
+ if (screenblocks < 10)
+ {
+ BorderNeedRefresh = true;
+ }
+ if (CurrentMenu->drawFunc != NULL)
+ {
+ CurrentMenu->drawFunc();
+ }
+ x = CurrentMenu->x;
+ y = CurrentMenu->y;
+ item = CurrentMenu->items;
+ if (item->type == ITT_SETKEY)
+ item += FirstKey;
+ for (i = 0; i < CurrentMenu->itemCount; i++)
+ {
+ switch (item->type)
+ {
+ case (ITT_EMPTY):
+ break;
+ case (ITT_SETKEY):
+ if (item->text)
+ MN_DrTextA(item->text, x, y+6);
+ break;
+ default:
+ if (item->text)
+ MN_DrTextB(item->text, x, y);
+ }
+ y += CurrentMenu->step;
+ item++;
+ }
+ y = CurrentMenu->y + (CurrentItPos * CurrentMenu->step) + SELECTOR_YOFFSET;
+ selName = (MenuTime & 16) ? "M_SLCTR1" : "M_SLCTR2";
+ V_DrawPatch(x + SELECTOR_XOFFSET, y, (patch_t *)W_CacheLumpName(selName, PU_CACHE));
+ }
+#endif
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawMainMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawMainMenu(void)
+{
+ int frame;
+
+ frame = (MenuTime / 5) % 7;
+
+#ifdef RENDER3D
+ OGL_DrawPatch_CS(88, 0, W_GetNumForName("M_HTIC") );
+ OGL_DrawPatch_CS(37, 80, MauloBaseLump + (frame + 2) % 7);
+ OGL_DrawPatch_CS(278, 80, MauloBaseLump + frame);
+#else
+ V_DrawPatch(88, 0, (patch_t *)W_CacheLumpName("M_HTIC", PU_CACHE));
+// Old Gold skull positions: (40, 10) and (232, 10)
+ V_DrawPatch(37, 80, (patch_t *)W_CacheLumpNum(MauloBaseLump + (frame + 2) % 7, PU_CACHE));
+ V_DrawPatch(278, 80, (patch_t *)W_CacheLumpNum(MauloBaseLump + frame, PU_CACHE));
+#endif
+}
+
+//==========================================================================
+//
+// DrawClassMenu
+//
+//==========================================================================
+
+static void DrawClassMenu(void)
+{
+ pclass_t pClass;
+ static const char *boxLumpName[4] =
+ {
+ "m_fbox",
+ "m_cbox",
+ "m_mbox",
+ "m_abox"
+ };
+ static const char *walkLumpName[4] =
+ {
+ "m_fwalk1",
+ "m_cwalk1",
+ "m_mwalk1",
+ "m_awalk1"
+ };
+
+ MN_DrTextB("CHOOSE CLASS:", 34, 24);
+ pClass = (pclass_t)CurrentMenu->items[CurrentItPos].option;
+#ifdef RENDER3D
+ OGL_DrawPatch_CS(174, 8, W_GetNumForName(boxLumpName[pClass]));
+ OGL_DrawPatch_CS(174+24, 8+12,
+ W_GetNumForName(walkLumpName[pClass]) + ((MenuTime>>3) & 3));
+#else
+ V_DrawPatch(174, 8, (patch_t *)W_CacheLumpName(boxLumpName[pClass], PU_CACHE));
+ V_DrawPatch(174+24, 8+12,
+ (patch_t *)W_CacheLumpNum(W_GetNumForName(walkLumpName[pClass]) + ((MenuTime>>3) & 3), PU_CACHE));
+#endif
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSkillMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawSkillMenu(void)
+{
+ MN_DrTextB("CHOOSE SKILL LEVEL:", 74, 16);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawFilesMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawFilesMenu(void)
+{
+// clear out the quicksave/quickload stuff
+ quicksave = 0;
+ quickload = 0;
+ P_ClearMessage(&players[consoleplayer]);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawLoadMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawLoadMenu(void)
+{
+ MN_DrTextB("LOAD GAME", 160 - MN_TextBWidth("LOAD GAME")/2, 10);
+ if (!slottextloaded)
+ {
+ MN_LoadSlotText();
+ }
+ DrawFileSlots(&LoadgameMenu);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSaveMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawSaveMenu(void)
+{
+ MN_DrTextB("SAVE GAME", 160 - MN_TextBWidth("SAVE GAME")/2, 10);
+ if (!slottextloaded)
+ {
+ MN_LoadSlotText();
+ }
+ DrawFileSlots(&SavegameMenu);
+}
+
+//===========================================================================
+//
+// MN_LoadSlotText
+//
+// For each slot, looks for save games and reads the description field.
+//
+//===========================================================================
+
+static void MN_LoadSlotText(void)
+{
+ int slot;
+ FILE *fp;
+ char name[MAX_OSPATH];
+ char versionText[HXS_VERSION_TEXT_LENGTH];
+ char description[HXS_DESCRIPTION_LENGTH];
+ boolean found;
+
+ for (slot = 0; slot < 6; slot++)
+ {
+ found = false;
+ snprintf(name, sizeof(name), "%shex%d.hxs", basePath, slot);
+ fp = fopen(name, "rb");
+ if (fp)
+ {
+ fread(description, HXS_DESCRIPTION_LENGTH, 1, fp);
+ fread(versionText, HXS_VERSION_TEXT_LENGTH, 1, fp);
+ fclose(fp);
+ if (!strcmp(versionText, HXS_VERSION_TEXT))
+ {
+ found = true;
+ }
+ }
+ if (found)
+ {
+ memcpy(SlotText[slot], description, SLOTTEXTLEN);
+ SlotStatus[slot] = 1;
+ }
+ else
+ {
+ memset(SlotText[slot], 0, SLOTTEXTLEN);
+ SlotStatus[slot] = 0;
+ }
+ }
+ slottextloaded = true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawFileSlots
+//
+//---------------------------------------------------------------------------
+
+static void DrawFileSlots(Menu_t *menu)
+{
+ int i;
+ int x;
+ int y;
+
+ x = menu->x;
+ y = menu->y;
+ for (i = 0; i < 6; i++)
+ {
+#ifdef RENDER3D
+ OGL_DrawPatch_CS(x, y, W_GetNumForName("M_FSLOT"));
+#else
+ V_DrawPatch(x, y, (patch_t *)W_CacheLumpName("M_FSLOT", PU_CACHE));
+#endif
+ if (SlotStatus[i])
+ {
+ MN_DrTextA(SlotText[i], x+5, y+5);
+ }
+ y += ITEM_HEIGHT;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawOptionsMenu
+//
+//---------------------------------------------------------------------------
+
+static void DrawOptionsMenu(void)
+{
+ char num[5];
+
+ if (messageson)
+ {
+ MN_DrTextB("ON", 196, 50);
+ }
+ else
+ {
+ MN_DrTextB("OFF", 196, 50);
+ }
+
+ MN_DrTextB(mlooktext[mouselook], 208, 110);
+
+ snprintf(num, sizeof(num), "%d", mouseSensitivity);
+ MN_DrTextB(num, 265, 71);
+
+ if (alwaysrun)
+ {
+ MN_DrTextB("ON", 208, 130);
+ }
+ else
+ {
+ MN_DrTextB("OFF", 208,130);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawOptions2Menu
+//
+//---------------------------------------------------------------------------
+
+static void DrawOptions2Menu(void)
+{
+ DrawSlider(&Options2Menu, 1, 9, screenblocks-3);
+ DrawSlider(&Options2Menu, 3, 16, snd_MaxVolume);
+ DrawSlider(&Options2Menu, 5, 16, snd_MusicVolume);
+ if (cdaudio)
+ {
+ MN_DrTextB("ON", 196, 140);
+ }
+ else
+ {
+ MN_DrTextB("OFF", 196, 140);
+ }
+}
+
+static void DrawOptions3Menu(void)
+{
+ int i;
+
+ for (i = 0; i < 15; i++)
+ {
+ if (askforkey && keyaskedfor == i)
+ {
+ MN_DrTextAYellow("???", 195, (i*SMALL_ITEM_HEIGHT+26));
+ }
+ else
+ {
+ MN_DrTextA(Key2String(*(defaults[i+FirstKey+3].location)),
+ 195, (i*SMALL_ITEM_HEIGHT+26));
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCQuitGame
+//
+//---------------------------------------------------------------------------
+
+static void SCQuitGame(int option)
+{
+ MenuActive = false;
+ askforquit = true;
+ typeofask = 1; //quit game
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCEndGame
+//
+//---------------------------------------------------------------------------
+
+static void SCEndGame(int option)
+{
+ if (demoplayback)
+ {
+ return;
+ }
+ if (SCNetCheck(3))
+ {
+ MenuActive = false;
+ askforquit = true;
+ typeofask = 2; //endgame
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMessages
+//
+//---------------------------------------------------------------------------
+
+static void SCMessages(int option)
+{
+ if (messageson)
+ {
+ messageson = 0;
+ P_SetMessage(&players[consoleplayer], "MESSAGES OFF", true);
+ }
+ else
+ {
+ messageson = 1;
+ P_SetMessage(&players[consoleplayer], "MESSAGES ON", true);
+ }
+ S_StartSound(NULL, SFX_CHAT);
+}
+
+//===========================================================================
+//
+// SCNetCheck
+//
+//===========================================================================
+
+static boolean SCNetCheck(int option)
+{
+ if (!netgame)
+ {
+ return true;
+ }
+ switch (option)
+ {
+ case 1: // new game
+ P_SetMessage(&players[consoleplayer],
+ "YOU CAN'T START A NEW GAME IN NETPLAY!", true);
+ break;
+ case 2: // load game
+ P_SetMessage(&players[consoleplayer],
+ "YOU CAN'T LOAD A GAME IN NETPLAY!", true);
+ break;
+ case 3: // end game
+ P_SetMessage(&players[consoleplayer],
+ "YOU CAN'T END A GAME IN NETPLAY!", true);
+ break;
+ }
+ MenuActive = false;
+ S_StartSound(NULL, SFX_CHAT);
+ return false;
+}
+
+//===========================================================================
+//
+// SCNetCheck2
+//
+//===========================================================================
+
+static void SCNetCheck2(int option)
+{
+ SCNetCheck(option);
+ return;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCLoadGame
+//
+//---------------------------------------------------------------------------
+
+static void SCLoadGame(int option)
+{
+ if (!SlotStatus[option])
+ { // Don't try to load from an empty slot
+ return;
+ }
+ G_LoadGame(option);
+ MN_DeactivateMenu();
+ BorderNeedRefresh = true;
+ if (quickload == -1)
+ {
+ quickload = option+1;
+ P_ClearMessage(&players[consoleplayer]);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSaveGame
+//
+//---------------------------------------------------------------------------
+
+static void SCSaveGame(int option)
+{
+ char *ptr;
+ player_t *player = &players[consoleplayer];
+
+ if (gamestate != GS_LEVEL || demoplayback
+ || player->playerstate == PST_DEAD)
+ {
+ FileMenuKeySteal = false;
+ return;
+ }
+
+ if (!FileMenuKeySteal)
+ {
+ FileMenuKeySteal = true;
+ strcpy(oldSlotText, SlotText[option]);
+ ptr = SlotText[option];
+ while (*ptr)
+ {
+ ptr++;
+ }
+ *ptr = '[';
+ *(ptr+1) = 0;
+ SlotStatus[option]++;
+ currentSlot = option;
+ slotptr = ptr-SlotText[option];
+ return;
+ }
+ else
+ {
+ G_SaveGame(option, SlotText[option]);
+ FileMenuKeySteal = false;
+ MN_DeactivateMenu();
+ }
+ BorderNeedRefresh = true;
+ if (quicksave == -1)
+ {
+ quicksave = option+1;
+ P_ClearMessage(&players[consoleplayer]);
+ }
+}
+
+//==========================================================================
+//
+// SCClass
+//
+//==========================================================================
+
+static void SCClass(int option)
+{
+ if (netgame)
+ {
+ P_SetMessage(&players[consoleplayer],
+ "YOU CAN'T START A NEW GAME FROM WITHIN A NETGAME!", true);
+ return;
+ }
+ MenuPClass = option;
+ switch (MenuPClass)
+ {
+ case PCLASS_FIGHTER:
+ SkillMenu.x = 120;
+ SkillItems[0].text = "SQUIRE";
+ SkillItems[1].text = "KNIGHT";
+ SkillItems[2].text = "WARRIOR";
+ SkillItems[3].text = "BERSERKER";
+ SkillItems[4].text = "TITAN";
+ break;
+ case PCLASS_CLERIC:
+ SkillMenu.x = 116;
+ SkillItems[0].text = "ALTAR BOY";
+ SkillItems[1].text = "ACOLYTE";
+ SkillItems[2].text = "PRIEST";
+ SkillItems[3].text = "CARDINAL";
+ SkillItems[4].text = "POPE";
+ break;
+ case PCLASS_MAGE:
+ SkillMenu.x = 112;
+ SkillItems[0].text = "APPRENTICE";
+ SkillItems[1].text = "ENCHANTER";
+ SkillItems[2].text = "SORCERER";
+ SkillItems[3].text = "WARLOCK";
+ SkillItems[4].text = "ARCHIMAGE";
+ break;
+#ifdef ASSASSIN
+ case PCLASS_ASS:
+ SkillMenu.x = 116;
+ SkillItems[0].text = "KNAVE";
+ SkillItems[1].text = "ROUGE";
+ SkillItems[2].text = "CUTTHROAT";
+ SkillItems[3].text = "EXECUTIONER";
+ SkillItems[4].text = "WIDOW MAKER";
+ break;
+#endif
+ }
+ SetTheMenu(MENU_SKILL);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSkill
+//
+//---------------------------------------------------------------------------
+
+static void SCSkill(int option)
+{
+ extern int SB_state;
+
+ PlayerClasses[consoleplayer] = MenuPClass;
+ G_DeferredNewGame(option);
+ SB_SetClassData();
+ SB_state = -1;
+ MN_DeactivateMenu();
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMouseSensi
+//
+//---------------------------------------------------------------------------
+
+static void SCMouseSensi(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (mouseSensitivity < MENU_MAX_MOUSE_SENS)
+ {
+ mouseSensitivity++;
+ }
+ }
+ else if (mouseSensitivity)
+ {
+ mouseSensitivity--;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSfxVolume
+//
+//---------------------------------------------------------------------------
+
+static void SCSfxVolume(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (snd_MaxVolume < 15)
+ {
+ snd_MaxVolume++;
+ }
+ }
+ else if (snd_MaxVolume)
+ {
+ snd_MaxVolume--;
+ }
+ soundchanged = true; // we'll set it when we leave the menu
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMusicVolume
+//
+//---------------------------------------------------------------------------
+
+static void SCMusicVolume(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (snd_MusicVolume < 15)
+ {
+ snd_MusicVolume++;
+ }
+ }
+ else if (snd_MusicVolume)
+ {
+ snd_MusicVolume--;
+ }
+ S_SetMusicVolume();
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCScreenSize
+//
+//---------------------------------------------------------------------------
+
+static void SCScreenSize(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (screenblocks < 11)
+ {
+ screenblocks++;
+ }
+ }
+ else if (screenblocks > 3)
+ {
+ screenblocks--;
+ }
+ R_SetViewSize(screenblocks, detailLevel);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCInfo
+//
+//---------------------------------------------------------------------------
+
+static void SCInfo(int option)
+{
+ InfoType = 1;
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCSetKey
+//
+//---------------------------------------------------------------------------
+
+static void SCSetKey(int option)
+{
+ askforkey = true;
+ keyaskedfor = option;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC SCMouslook(int option)
+//
+//---------------------------------------------------------------------------
+
+static void SCMouselook(int option)
+{
+ if (option == RIGHT_DIR)
+ {
+ if (mouselook < 2)
+ mouselook++;
+ }
+ else if (mouselook)
+ mouselook--;
+}
+
+static void SCAlwaysRun(int option)
+{
+ if (alwaysrun)
+ alwaysrun = 0;
+ else alwaysrun = 1;
+}
+
+static void SCCDAudio(int option)
+{
+ if (cdaudio)
+ {
+ cdaudio = 0;
+ I_CDMusStop();
+ // FIXME: start ordinary music here
+ }
+ else
+ {
+ cdaudio = 1;
+ if (i_CDMusic)
+ {
+ // FIXME: start cdaudio here
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC MN_Responder
+//
+//---------------------------------------------------------------------------
+
+boolean MN_Responder(event_t *event)
+{
+ int key;
+ int i;
+ MenuItem_t *item;
+ static boolean shiftdown;
+ extern void H2_StartTitle(void);
+ extern void G_CheckDemoStatus(void);
+ char *textBuffer;
+
+ if (askforkey && event->type == ev_keydown)
+ {
+ ClearControls(event->data1);
+ *defaults[keyaskedfor + 3 + FirstKey].location = event->data1;
+ askforkey = false;
+ return true;
+ }
+ if (askforkey && event->type == ev_mouse)
+ {
+ if (event->data1 & 1)
+ return true;
+ if (event->data1 & 2)
+ return true;
+ if (event->data1 & 4)
+ return true;
+ return false;
+ }
+ if (event->data1 == KEY_RSHIFT)
+ {
+ shiftdown = (event->type == ev_keydown);
+ }
+ if (event->type != ev_keydown)
+ {
+ return false;
+ }
+ key = event->data1;
+ if (InfoType)
+ {
+ InfoType = (InfoType + 1) % 4;
+ if (key == KEY_ESCAPE)
+ {
+ InfoType = 0;
+ }
+ if (!InfoType)
+ {
+ if (!netgame && !demoplayback)
+ {
+ paused = false;
+ }
+ MN_DeactivateMenu();
+ SB_state = -1; //refresh the statbar
+ BorderNeedRefresh = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ return true; //make the info screen eat the keypress
+ }
+
+ if (ravpic && key == KEY_F1)
+ {
+ // F12 is screenshot now. This
+ // is here for reference, only.
+ G_ScreenShot();
+ return true;
+ }
+
+ if (askforquit)
+ {
+ switch (key)
+ {
+ case KEY_ENTER:
+ case 'y':
+ if (askforquit)
+ {
+ switch (typeofask)
+ {
+ case 1:
+ G_CheckDemoStatus();
+ I_Quit();
+ break;
+ case 2:
+ P_ClearMessage(&players[consoleplayer]);
+ typeofask = 0;
+ askforquit = false;
+ paused = false;
+ V_SetPaletteBase();
+ H2_StartTitle(); // go to intro/demo mode.
+ break;
+ case 3:
+ P_SetMessage(&players[consoleplayer],
+ "QUICKSAVING....", false);
+ FileMenuKeySteal = true;
+ SCSaveGame(quicksave-1);
+ askforquit = false;
+ typeofask = 0;
+ BorderNeedRefresh = true;
+ return true;
+ case 4:
+ P_SetMessage(&players[consoleplayer],
+ "QUICKLOADING....", false);
+ SCLoadGame(quickload-1);
+ askforquit = false;
+ typeofask = 0;
+ BorderNeedRefresh = true;
+ return true;
+ case 5:
+ askforquit = false;
+ typeofask = 0;
+ BorderNeedRefresh = true;
+ mn_SuicideConsole = true;
+ return true;
+ default:
+ return true; // eat the 'y' keypress
+ }
+ }
+ return false;
+
+ case 'n':
+ case KEY_ESCAPE:
+ if (askforquit)
+ {
+ players[consoleplayer].messageTics = 0;
+ askforquit = false;
+ typeofask = 0;
+ paused = false;
+ UpdateState |= I_FULLSCRN;
+ BorderNeedRefresh = true;
+ return true;
+ }
+ return false;
+ }
+ return false; // don't let the keys filter thru
+ }
+ if (MenuActive == false && !chatmodeon)
+ {
+ switch (key)
+ {
+ case KEY_MINUS:
+ if (automapactive)
+ { // Don't screen size in automap
+ return false;
+ }
+ SCScreenSize(LEFT_DIR);
+ S_StartSound(NULL, SFX_PICKUP_KEY);
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ return true;
+ case KEY_EQUALS:
+ if (automapactive)
+ { // Don't screen size in automap
+ return false;
+ }
+ SCScreenSize(RIGHT_DIR);
+ S_StartSound(NULL, SFX_PICKUP_KEY);
+ BorderNeedRefresh = true;
+ UpdateState |= I_FULLSCRN;
+ return true;
+#ifdef __NeXT__
+ case 'q':
+ MenuActive = false;
+ askforquit = true;
+ typeofask = 5; // suicide
+ return true;
+#endif
+ case KEY_F1: // help screen
+ SCInfo(0); // start up info screens
+ MenuActive = true;
+ return true;
+ case KEY_F2: // save game
+ if (gamestate == GS_LEVEL && !demoplayback)
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &SavegameMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ slottextloaded = false; //reload the slot text, when needed
+ }
+ return true;
+ case KEY_F3: // load game
+ if (SCNetCheck(2))
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &LoadgameMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ slottextloaded = false; //reload the slot text, when needed
+ }
+ return true;
+ case KEY_F4: // S.A.: made F4 Controls. was Volume, before.
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &OptionsMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ slottextloaded = false; //reload the slot text, when needed
+ return true;
+ case KEY_F5: // volume
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &Options2Menu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ slottextloaded = false; //reload the slot text, when needed
+ return true;
+ case KEY_F6: // quicksave
+ if (gamestate == GS_LEVEL && !demoplayback)
+ {
+ if (!quicksave || quicksave == -1)
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &SavegameMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ slottextloaded = false; //reload the slot text
+ quicksave = -1;
+ P_SetMessage(&players[consoleplayer],
+ "CHOOSE A QUICKSAVE SLOT", true);
+ }
+ else
+ {
+ askforquit = true;
+ typeofask = 3;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_CHAT);
+ }
+ }
+ return true;
+ case KEY_F7: // endgame
+ if (SCNetCheck(3))
+ {
+ if (gamestate == GS_LEVEL && !demoplayback)
+ {
+ S_StartSound(NULL, SFX_CHAT);
+ SCEndGame(0);
+ }
+ }
+ return true;
+ case KEY_F8: // toggle messages
+ SCMessages(0);
+ return true;
+ case KEY_F9: // quickload
+ if (SCNetCheck(2))
+ {
+ if (!quickload || quickload == -1)
+ {
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &LoadgameMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ slottextloaded = false; // reload the slot text
+ quickload = -1;
+ P_SetMessage(&players[consoleplayer],
+ "CHOOSE A QUICKLOAD SLOT", true);
+ }
+ else
+ {
+ askforquit = true;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ typeofask = 4;
+ S_StartSound(NULL, SFX_CHAT);
+ }
+ }
+ return true;
+ case KEY_F10: // quit
+ // S.A.: allowed quit to work when not in a level
+ // if (!(gamestate == GS_LEVEL || gamestate == GS_FINALE))
+ // return true;
+ SCQuitGame(0);
+ S_StartSound(NULL, SFX_CHAT);
+ return true;
+ case KEY_F11: // F11 - gamma mode correction
+ usegamma++;
+ if (usegamma > 4)
+ {
+ usegamma = 0;
+ }
+ SB_PaletteFlash(true); // force change
+ P_SetMessage(&players[consoleplayer], GammaText[usegamma], false);
+ return true;
+ /*
+ case KEY_F12: // F12 - reload current map (devmaps mode)
+ if (netgame || DevMaps == false)
+ {
+ return false;
+ }
+ if (gamekeydown[key_speed])
+ { // Monsters ON
+ nomonsters = false;
+ }
+ if (gamekeydown[key_strafe])
+ { // Monsters OFF
+ nomonsters = true;
+ }
+ G_DeferedInitNew(gameskill, gameepisode, gamemap);
+ P_SetMessage(&players[consoleplayer], TXT_CHEATWARP,
+ false);
+ return true;
+ */
+ case KEY_F12: // S.A.: made F12 Screenshot
+ G_ScreenShot();
+ return true;
+ }
+ }
+
+ if (MenuActive == false)
+ {
+ if (key == KEY_ESCAPE || gamestate == GS_DEMOSCREEN || demoplayback)
+ {
+ MN_ActivateMenu();
+ return true;
+ }
+ return false;
+ }
+ if (!FileMenuKeySteal)
+ {
+ item = &CurrentMenu->items[CurrentItPos];
+ switch (key)
+ {
+ case KEY_DOWNARROW:
+ do
+ {
+ if (CurrentMenu->items[CurrentItPos].type == ITT_SETKEY
+ && CurrentItPos+1 > CurrentMenu->itemCount-1)
+ {
+ if (FirstKey == FIRSTKEY_MAX)
+ {
+ CurrentItPos = 0; // End of Key menu
+ FirstKey = 0;
+ }
+ else
+ {
+ FirstKey++;
+ }
+ }
+ else if (CurrentItPos+1 > CurrentMenu->itemCount-1)
+ {
+ CurrentItPos = 0;
+ }
+ else
+ {
+ CurrentItPos++;
+ }
+ }
+ while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
+ S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL);
+ return true;
+ case KEY_UPARROW:
+ do
+ {
+ if (CurrentMenu->items[CurrentItPos].type == ITT_SETKEY && CurrentItPos == 0)
+ {
+ if (FirstKey == 0)
+ {
+ CurrentItPos = 14; // End of Key menu
+ // 14 == 15 (max lines on a page) - 1
+ FirstKey = FIRSTKEY_MAX;
+ }
+ else
+ {
+ FirstKey--;
+ }
+ }
+ else if (CurrentItPos == 0)
+ {
+ CurrentItPos = CurrentMenu->itemCount-1;
+ }
+ else
+ {
+ CurrentItPos--;
+ }
+ }
+ while (CurrentMenu->items[CurrentItPos].type == ITT_EMPTY);
+ S_StartSound(NULL, SFX_FIGHTER_HAMMER_HITWALL);
+ return true;
+ case KEY_LEFTARROW:
+ if (item->type == ITT_LRFUNC && item->func != NULL)
+ {
+ item->func(LEFT_DIR);
+ S_StartSound(NULL, SFX_PICKUP_KEY);
+ }
+ return true;
+ case KEY_RIGHTARROW:
+ if (item->type == ITT_LRFUNC && item->func != NULL)
+ {
+ item->func(RIGHT_DIR);
+ S_StartSound(NULL, SFX_PICKUP_KEY);
+ }
+ return true;
+ case KEY_ENTER:
+ if (item->type == ITT_SETMENU)
+ {
+ if (item->func != NULL)
+ {
+ item->func(item->option);
+ }
+ SetTheMenu(item->menu);
+ }
+ else if (item->func != NULL)
+ {
+ CurrentMenu->oldItPos = CurrentItPos;
+ if (item->type == ITT_LRFUNC)
+ {
+ item->func(RIGHT_DIR);
+ }
+ else if (item->type == ITT_EFUNC)
+ {
+ item->func(item->option);
+ }
+ else if (item->type == ITT_SETKEY)
+ {
+ item->func(item->option);
+ }
+ }
+ S_StartSound(NULL, SFX_DOOR_LIGHT_CLOSE);
+ return true;
+ case KEY_ESCAPE:
+ MN_DeactivateMenu();
+ return true;
+ case KEY_BACKSPACE:
+ S_StartSound(NULL, SFX_PICKUP_KEY);
+ if (CurrentMenu->prevMenu == MENU_NONE)
+ {
+ MN_DeactivateMenu();
+ }
+ else
+ {
+ SetTheMenu(CurrentMenu->prevMenu);
+ }
+ return true;
+ default:
+ for (i = 0; i < CurrentMenu->itemCount; i++)
+ {
+ if (CurrentMenu->items[i].text)
+ {
+ if (toupper(key)
+ == toupper(CurrentMenu->items[i].text[0]))
+ {
+ CurrentItPos = i;
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ return false;
+ }
+ else
+ { // Editing file names
+ textBuffer = &SlotText[currentSlot][slotptr];
+ if (key == KEY_BACKSPACE)
+ {
+ if (slotptr)
+ {
+ *textBuffer-- = 0;
+ *textBuffer = ASCII_CURSOR;
+ slotptr--;
+ }
+ return true;
+ }
+ if (key == KEY_ESCAPE)
+ {
+ memset(SlotText[currentSlot], 0, SLOTTEXTLEN+2);
+ strcpy(SlotText[currentSlot], oldSlotText);
+ SlotStatus[currentSlot]--;
+ MN_DeactivateMenu();
+ return true;
+ }
+ if (key == KEY_ENTER)
+ {
+ SlotText[currentSlot][slotptr] = 0; // clear the cursor
+ item = &CurrentMenu->items[CurrentItPos];
+ CurrentMenu->oldItPos = CurrentItPos;
+ if (item->type == ITT_EFUNC)
+ {
+ item->func(item->option);
+ if (item->menu != MENU_NONE)
+ {
+ SetTheMenu(item->menu);
+ }
+ }
+ return true;
+ }
+ if (slotptr < SLOTTEXTLEN && key != KEY_BACKSPACE)
+ {
+ if ((key >= 'a' && key <= 'z'))
+ {
+ *textBuffer++ = key-32;
+ *textBuffer = ASCII_CURSOR;
+ slotptr++;
+ return true;
+ }
+ if (((key >= '0' && key <= '9') || key == ' '
+ || key == ',' || key == '.' || key == '-')
+ && !shiftdown)
+ {
+ *textBuffer++ = key;
+ *textBuffer = ASCII_CURSOR;
+ slotptr++;
+ return true;
+ }
+ if (shiftdown && key == '1')
+ {
+ *textBuffer++ = '!';
+ *textBuffer = ASCII_CURSOR;
+ slotptr++;
+ return true;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_ActivateMenu
+//
+//---------------------------------------------------------------------------
+
+void MN_ActivateMenu(void)
+{
+ if (MenuActive)
+ {
+ return;
+ }
+ if (paused)
+ {
+ S_ResumeSound();
+ }
+ MenuActive = true;
+ FileMenuKeySteal = false;
+ MenuTime = 0;
+ CurrentMenu = &MainMenu;
+ CurrentItPos = CurrentMenu->oldItPos;
+ if (!netgame && !demoplayback)
+ {
+ paused = true;
+ }
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ slottextloaded = false; //reload the slot text, when needed
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DeactivateMenu
+//
+//---------------------------------------------------------------------------
+
+void MN_DeactivateMenu(void)
+{
+ if (CurrentMenu)
+ CurrentMenu->oldItPos = CurrentItPos;
+ MenuActive = false;
+ if (!netgame)
+ {
+ paused = false;
+ }
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ P_ClearMessage(&players[consoleplayer]);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC MN_DrawInfo
+//
+//---------------------------------------------------------------------------
+
+void MN_DrawInfo(void)
+{
+ V_SetPaletteBase();
+ V_DrawRawScreen((BYTE_REF) WR_CacheLumpNum(W_GetNumForName("TITLE")+InfoType, PU_CACHE));
+}
+
+
+//---------------------------------------------------------------------------
+//
+// PROC SetMenu
+//
+//---------------------------------------------------------------------------
+
+static void SetTheMenu(MenuType_t menu)
+{
+ CurrentMenu->oldItPos = CurrentItPos;
+ CurrentMenu = Menus[menu];
+ CurrentItPos = CurrentMenu->oldItPos;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC DrawSlider
+//
+//---------------------------------------------------------------------------
+
+static void DrawSlider(Menu_t *menu, int item, int width, int slot)
+{
+ int x;
+ int y;
+ int x2;
+ int count;
+
+ x = menu->x + 24;
+ y = menu->y + 2 + (item*ITEM_HEIGHT);
+
+#ifdef RENDER3D
+ OGL_DrawPatch_CS(x-32, y, W_GetNumForName("M_SLDLT"));
+ for (x2 = x, count = width; count--; x2 += 8)
+ {
+ OGL_DrawPatch_CS(x2, y, W_GetNumForName((count & 1) ? "M_SLDMD1" : "M_SLDMD2"));
+ }
+ OGL_DrawPatch_CS(x2, y, W_GetNumForName("M_SLDRT"));
+ OGL_DrawPatch_CS(x + 4 + slot*8, y + 7, W_GetNumForName("M_SLDKB"));
+#else
+ V_DrawPatch(x-32, y, (patch_t *)W_CacheLumpName("M_SLDLT", PU_CACHE));
+ for (x2 = x, count = width; count--; x2 += 8)
+ {
+ V_DrawPatch(x2, y, (patch_t *)W_CacheLumpName((count & 1) ? "M_SLDMD1" : "M_SLDMD2", PU_CACHE));
+ }
+ V_DrawPatch(x2, y, (patch_t *)W_CacheLumpName("M_SLDRT", PU_CACHE));
+ V_DrawPatch(x + 4 + slot*8, y + 7, (patch_t *)W_CacheLumpName("M_SLDKB", PU_CACHE));
+#endif
+}
+
--- /dev/null
+++ b/ogl_def.h
@@ -1,0 +1,199 @@
+//**************************************************************************
+//**
+//** ogl_def.h
+//**
+//** $Revision: 499 $
+//** $Date: 2009-06-02 20:50:47 +0300 (Tue, 02 Jun 2009) $
+//**
+//**************************************************************************
+
+#ifndef __H2OPENGL__
+#define __H2OPENGL__
+
+#include "r_local.h"
+#include <GL/gl.h>
+
+/* whether to printf devel debug messages */
+#define OPENGL_DEBUGGING 0
+
+#if (OPENGL_DEBUGGING)
+#define OGL_DEBUG printf
+#else /* no debug msg : */
+#if defined (__GNUC__) && !(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
+#define OGL_DEBUG(fmt, args...) do {} while (0)
+#else
+#define OGL_DEBUG(fmt, ...) do {} while (0)
+#endif
+#endif
+
+
+enum { VX, VY }; /* Vertex indices. */
+
+typedef struct /* For dynamic lighting. */
+{
+ int use;
+ mobj_t *thing;
+ float top, height;
+} lumobj_t;
+
+/* ScreenBits is currently unused. */
+extern int screenWidth, screenHeight, screenBits;
+
+void I_InitGraphics(void);
+void I_ShutdownGraphics(void);
+
+void OGL_InitRenderer(void);
+void OGL_InitData(void);
+void OGL_ResetData(void);
+
+void OGL_SwitchTo3DState(void);
+void OGL_Restore2DState(int step); /* Step 1: matrices, 2: attributes. */
+void OGL_UseWhiteFog(int yes);
+
+float PointDist2D(float c[2]);
+
+void R_RenderSprite(vissprite_t *spr);
+
+/* 2D drawing routines. */
+void OGL_DrawPatch_CS(int x, int y, int lumpnum);
+void OGL_DrawPatch(int x, int y, int lumpnum);
+void OGL_DrawFuzzPatch(int x, int y, int lumpnum);
+void OGL_DrawAltFuzzPatch(int x, int y, int lumpnum);
+void OGL_DrawShadowedPatch(int x, int y, int lumpnum);
+void OGL_DrawRawScreen(int lump); /* Raw screens are 320 x 200. */
+void OGL_DrawRawScreenOfs(int lump, float offx, float offy);
+void OGL_DrawLine(float x1, float y1, float x2, float y2, float r, float g, float b, float a);
+void OGL_DrawRect(float x, float y, float w, float h, float r, float g, float b, float a);
+void OGL_DrawRectTiled(int x, int y, int w, int h, int tw, int th);
+void OGL_DrawCutRectTiled(int x, int y, int w, int h, int tw, int th, int cx, int cy, int cw, int ch);
+void OGL_SetColor(int palidx);
+void OGL_SetColorAndAlpha(float r, float g, float b, float a);
+void OGL_DrawPSprite(int x, int y, float scale, int flip, int lump);
+
+/* Filters. */
+void OGL_SetFilter(int filter);
+int OGL_DrawFilter(void);
+
+void OGL_ShadeRect(int x, int y, int w, int h, float darkening);
+
+/* ogl_tex.c */
+typedef struct
+{
+ unsigned short w, h;
+ short offx, offy;
+ unsigned short w2; /* For split textures, width of the other part. */
+} texsize_t;
+
+extern texsize_t *lumptexsizes; /* Sizes for all the lumps. */
+extern unsigned short *spriteheights;
+
+extern float texw, texh;
+extern int texmask;
+extern unsigned int curtex;
+extern int pallump;
+
+int FindNextPower2(int num);
+float NextPower2Ratio(int num);
+void OGL_TexInit(void);
+void OGL_TexReset(void);
+void OGL_ResetLumpTexData(void);
+void OGL_SetPaletteLump(const char *palname);
+void PalToRGB(byte *palidx, byte *rgb);
+void PalIdxToRGB(byte *pal, int idx, byte *rgb);
+unsigned int OGL_BindTexFlat(int lump);
+void OGL_SetFlat(int idx);
+void OGL_BindTexture(GLuint texname);
+
+/* Returns the OpenGL texture name. */
+GLuint OGL_PrepareTexture(int idx);
+GLuint OGL_PrepareFlat(int idx); /* Returns the OpenGL name of the texture. */
+GLuint OGL_PrepareLightTexture(void); /* The dynamic light map. */
+
+void OGL_SetTexture(int idx);
+unsigned int OGL_PrepareSky(int idx, boolean zeroMask);
+
+void OGL_SetSprite(int pnum);
+unsigned int OGL_PrepareSprite(int pnum);
+void OGL_NewSplitTex(int lump, GLuint part2name);
+GLuint OGL_GetOtherPart(int lump);
+
+/* Part is either 1 or 2. Part 0 means only the left side is loaded.
+ * No splittex is created in that case. Once a raw image is loaded
+ * as part 0 it must be deleted before the other part is loaded at the
+ * next loading.
+ */
+void OGL_SetRawImage(int lump, int part);
+void OGL_SetPatch(int lump); /* No mipmaps are generated. */
+void OGL_SetNoTexture(void);
+
+int OGL_GetLumpTexWidth(int lump);
+int OGL_GetLumpTexHeight(int lump);
+int OGL_ValidTexHeight2(int width, int height);
+
+void OGL_UpdateTexParams(int mipmode);
+void OGL_UpdateRawScreenParams(int smoothing);
+
+
+/* ogl_scr.c */
+typedef struct _TargaHeader
+{
+ unsigned char id_length, colormap_type, image_type;
+ unsigned short colormap_index, colormap_length;
+ unsigned char colormap_size;
+ unsigned short x_origin, y_origin, width, height;
+ unsigned char pixel_size, attributes;
+} TargaHeader;
+
+void OGL_GrabScreen(void);
+
+
+#include "m_bams.h"
+
+/* ogl_clip.c */
+typedef struct clipnode_s
+{
+ int used; /* 1 if the node is in use. */
+ struct clipnode_s *prev, *next; /* Previous and and nodes. */
+ binangle start, end; /* The start and end angles (start < end). */
+} clipnode_t;
+
+extern clipnode_t *clipnodes; /* The list of clipnodes. */
+extern clipnode_t *cliphead; /* The head node. */
+
+void C_Init(void);
+void C_Ranger(void);
+void C_ClearRanges(void);
+void C_SafeAddRange(binangle startAngle, binangle endAngle);
+
+/* Add a segment relative to the current viewpoint. */
+void C_AddViewRelSeg(float x1, float y1, float x2, float y2);
+
+/* Check a segment relative to the current viewpoint. */
+int C_CheckViewRelSeg(float x1, float y1, float x2, float y2);
+
+/* Returns 1 if the specified angle is visible. */
+int C_IsAngleVisible(binangle bang);
+
+clipnode_t *C_AngleClippedBy(binangle bang);
+
+/* Returns 1 if the subsector might be visible. */
+int C_CheckSubsector(subsector_t *ssec);
+
+
+/* ogl_sky.c */
+
+/* Sky hemispheres. */
+#define SKYHEMI_UPPER 0x1
+#define SKYHEMI_LOWER 0x2
+#define SKYHEMI_JUST_CAP 0x4 /* Just draw the top or bottom cap. */
+
+typedef struct
+{
+ float rgb[3]; /* The RGB values. */
+ short set, use; /* Is this set? Should be used? */
+} fadeout_t;
+
+void R_RenderSkyHemispheres(int hemis);
+
+#endif /* __H2OPENGL__ */
+
--- /dev/null
+++ b/ogl_rl.h
@@ -1,0 +1,63 @@
+//**************************************************************************
+//**
+//** ogl_rl.h
+//**
+//** $Revision: 584 $
+//** $Date: 2012-02-17 12:01:51 +0200 (Fri, 17 Feb 2012) $
+//**
+//**************************************************************************
+
+#ifndef __OGL_REND_LIST_H__
+#define __OGL_REND_LIST_H__
+
+/* Rendquad flags. */
+#define RQF_FLAT 0x1 /* This is a flat triangle. */
+#define RQF_MASKED 0x2 /* Use the special list for masked textures. */
+#define RQF_MISSING_WALL 0x4 /* Originally this surface had no texture. */
+#define RQF_SKY_MASK 0x8 /* A sky mask triangle. */
+#define RQF_SKY_MASK_WALL 0x10 /* A sky mask wall (with skyfix). */
+#define RQF_LIGHT 0x20 /* A dynamic light. */
+#define RQF_FLOOR_FACING 0x40 /* Used for flats, the quad faces upwards. */
+
+typedef struct
+{
+ float v1[2], v2[2]; /* Two vertices. */
+ float top; /* Top height. */
+ union _quadTri {
+ struct _quad {
+ float bottom; /* Bottom height. */
+ float len; /* Length of the quad. */
+ } q;
+ float v3[2]; /* Third vertex for flats. */
+ } u;
+ float light; /* Light level, as in 0 = black, 1 = fullbright. */
+ float texoffx; /* Texture coordinates for left/top (in real texcoords). */
+ float texoffy;
+ short flags; /* RQF_*. */
+ GLuint masktex; /* Texture name for masked textures. */
+ unsigned short texw, texh; /* Size of the texture. */
+ float dist[3]; /* Distances to the vertices. */
+} rendquad_t; /* Or flat triangle. */
+
+typedef struct
+{
+ GLuint tex; /* The name of the texture for this list. */
+ int numquads; /* Number of quads in the list. */
+ int listsize; /* Absolute size of the list. */
+ rendquad_t *quads; /* The list of quads. */
+} rendlist_t;
+
+
+/* ogl_rl.c */
+
+void RL_Init(void);
+void RL_ClearLists(void);
+void RL_DeleteLists(void);
+void RL_AddQuad(rendquad_t *quad, GLuint quadtex);
+void RL_AddFlatQuads(rendquad_t *base, /* GLuint */ uintptr_t quadtex,
+ int numvrts, fvertex_t *vrts, int dir);
+void RL_RenderAllLists(void);
+void SetVertexColor(float light, float dist, float alpha);
+
+#endif /* __OGL_REND_LIST_H__ */
+
--- /dev/null
+++ b/oss.h
@@ -1,0 +1,38 @@
+/* XMMS - Cross-platform multimedia player
+ * Copyright (C) 1998-1999 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _SNDOSS_H
+#define _SNDOSS_H
+
+
+#include "config.h"
+#include "audio_plugin.h"
+
+
+typedef struct
+{
+ int audio_device;
+ int mixer_device;
+ int buffer_size;
+ int prebuffer;
+ int fragment_count;
+}
+OSSConfig;
+
+#endif /* _SNDOSS_H */
+
--- /dev/null
+++ b/p_acs.c
@@ -1,0 +1,1805 @@
+
+//**************************************************************************
+//**
+//** p_acs.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define SCRIPT_CONTINUE 0
+#define SCRIPT_STOP 1
+#define SCRIPT_TERMINATE 2
+
+#define OPEN_SCRIPTS_BASE 1000
+#define PRINT_BUFFER_SIZE 256
+
+#define GAME_SINGLE_PLAYER 0
+#define GAME_NET_COOPERATIVE 1
+#define GAME_NET_DEATHMATCH 2
+
+#define TEXTURE_TOP 0
+#define TEXTURE_MIDDLE 1
+#define TEXTURE_BOTTOM 2
+
+#define S_DROP ACScript->stackPtr--
+#define S_POP ACScript->stack[--ACScript->stackPtr]
+#define S_PUSH(x) ACScript->stack[ACScript->stackPtr++] = (x)
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct
+{
+ int marker;
+ int infoOffset;
+ int code;
+} acsHeader_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void StartOpenACS(int number, int infoIndex, byte *address);
+static void ScriptFinished(int number);
+static boolean TagBusy(int tag);
+static boolean AddToACSStore(int map, int number, byte *args);
+static int GetACSIndex(int number);
+static void Push(int value);
+static int Pop(void);
+static int Top(void);
+static void Drop(void);
+
+static int CmdNOP(void);
+static int CmdTerminate(void);
+static int CmdSuspend(void);
+static int CmdPushNumber(void);
+static int CmdLSpec1(void);
+static int CmdLSpec2(void);
+static int CmdLSpec3(void);
+static int CmdLSpec4(void);
+static int CmdLSpec5(void);
+static int CmdLSpec1Direct(void);
+static int CmdLSpec2Direct(void);
+static int CmdLSpec3Direct(void);
+static int CmdLSpec4Direct(void);
+static int CmdLSpec5Direct(void);
+static int CmdAdd(void);
+static int CmdSubtract(void);
+static int CmdMultiply(void);
+static int CmdDivide(void);
+static int CmdModulus(void);
+static int CmdEQ(void);
+static int CmdNE(void);
+static int CmdLT(void);
+static int CmdGT(void);
+static int CmdLE(void);
+static int CmdGE(void);
+static int CmdAssignScriptVar(void);
+static int CmdAssignMapVar(void);
+static int CmdAssignWorldVar(void);
+static int CmdPushScriptVar(void);
+static int CmdPushMapVar(void);
+static int CmdPushWorldVar(void);
+static int CmdAddScriptVar(void);
+static int CmdAddMapVar(void);
+static int CmdAddWorldVar(void);
+static int CmdSubScriptVar(void);
+static int CmdSubMapVar(void);
+static int CmdSubWorldVar(void);
+static int CmdMulScriptVar(void);
+static int CmdMulMapVar(void);
+static int CmdMulWorldVar(void);
+static int CmdDivScriptVar(void);
+static int CmdDivMapVar(void);
+static int CmdDivWorldVar(void);
+static int CmdModScriptVar(void);
+static int CmdModMapVar(void);
+static int CmdModWorldVar(void);
+static int CmdIncScriptVar(void);
+static int CmdIncMapVar(void);
+static int CmdIncWorldVar(void);
+static int CmdDecScriptVar(void);
+static int CmdDecMapVar(void);
+static int CmdDecWorldVar(void);
+static int CmdGoto(void);
+static int CmdIfGoto(void);
+static int CmdDrop(void);
+static int CmdDelay(void);
+static int CmdDelayDirect(void);
+static int CmdRandom(void);
+static int CmdRandomDirect(void);
+static int CmdThingCount(void);
+static int CmdThingCountDirect(void);
+static int CmdTagWait(void);
+static int CmdTagWaitDirect(void);
+static int CmdPolyWait(void);
+static int CmdPolyWaitDirect(void);
+static int CmdChangeFloor(void);
+static int CmdChangeFloorDirect(void);
+static int CmdChangeCeiling(void);
+static int CmdChangeCeilingDirect(void);
+static int CmdRestart(void);
+static int CmdAndLogical(void);
+static int CmdOrLogical(void);
+static int CmdAndBitwise(void);
+static int CmdOrBitwise(void);
+static int CmdEorBitwise(void);
+static int CmdNegateLogical(void);
+static int CmdLShift(void);
+static int CmdRShift(void);
+static int CmdUnaryMinus(void);
+static int CmdIfNotGoto(void);
+static int CmdLineSide(void);
+static int CmdScriptWait(void);
+static int CmdScriptWaitDirect(void);
+static int CmdClearLineSpecial(void);
+static int CmdCaseGoto(void);
+static int CmdBeginPrint(void);
+static int CmdEndPrint(void);
+static int CmdPrintString(void);
+static int CmdPrintNumber(void);
+static int CmdPrintCharacter(void);
+static int CmdPlayerCount(void);
+static int CmdGameType(void);
+static int CmdGameSkill(void);
+static int CmdTimer(void);
+static int CmdSectorSound(void);
+static int CmdAmbientSound(void);
+static int CmdSoundSequence(void);
+static int CmdSetLineTexture(void);
+static int CmdSetLineBlocking(void);
+static int CmdSetLineSpecial(void);
+static int CmdThingSound(void);
+static int CmdEndPrintBold(void);
+
+static void ThingCount(int type, int tid);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern const char *TextKeyMessages[11];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int ACScriptCount;
+byte *ActionCodeBase;
+acsInfo_t *ACSInfo;
+int MapVars[MAX_ACS_MAP_VARS];
+int WorldVars[MAX_ACS_WORLD_VARS];
+acsstore_t ACSStore[MAX_ACS_STORE + 1]; // +1 for termination marker
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static acs_t *ACScript;
+static byte *PCodePtr;
+static byte SpecArgs[8];
+static int ACStringCount;
+static char **ACStrings;
+static char PrintBuffer[PRINT_BUFFER_SIZE];
+static acs_t *NewScript;
+
+static int (*PCodeCmds[])(void) =
+{
+ CmdNOP,
+ CmdTerminate,
+ CmdSuspend,
+ CmdPushNumber,
+ CmdLSpec1,
+ CmdLSpec2,
+ CmdLSpec3,
+ CmdLSpec4,
+ CmdLSpec5,
+ CmdLSpec1Direct,
+ CmdLSpec2Direct,
+ CmdLSpec3Direct,
+ CmdLSpec4Direct,
+ CmdLSpec5Direct,
+ CmdAdd,
+ CmdSubtract,
+ CmdMultiply,
+ CmdDivide,
+ CmdModulus,
+ CmdEQ,
+ CmdNE,
+ CmdLT,
+ CmdGT,
+ CmdLE,
+ CmdGE,
+ CmdAssignScriptVar,
+ CmdAssignMapVar,
+ CmdAssignWorldVar,
+ CmdPushScriptVar,
+ CmdPushMapVar,
+ CmdPushWorldVar,
+ CmdAddScriptVar,
+ CmdAddMapVar,
+ CmdAddWorldVar,
+ CmdSubScriptVar,
+ CmdSubMapVar,
+ CmdSubWorldVar,
+ CmdMulScriptVar,
+ CmdMulMapVar,
+ CmdMulWorldVar,
+ CmdDivScriptVar,
+ CmdDivMapVar,
+ CmdDivWorldVar,
+ CmdModScriptVar,
+ CmdModMapVar,
+ CmdModWorldVar,
+ CmdIncScriptVar,
+ CmdIncMapVar,
+ CmdIncWorldVar,
+ CmdDecScriptVar,
+ CmdDecMapVar,
+ CmdDecWorldVar,
+ CmdGoto,
+ CmdIfGoto,
+ CmdDrop,
+ CmdDelay,
+ CmdDelayDirect,
+ CmdRandom,
+ CmdRandomDirect,
+ CmdThingCount,
+ CmdThingCountDirect,
+ CmdTagWait,
+ CmdTagWaitDirect,
+ CmdPolyWait,
+ CmdPolyWaitDirect,
+ CmdChangeFloor,
+ CmdChangeFloorDirect,
+ CmdChangeCeiling,
+ CmdChangeCeilingDirect,
+ CmdRestart,
+ CmdAndLogical,
+ CmdOrLogical,
+ CmdAndBitwise,
+ CmdOrBitwise,
+ CmdEorBitwise,
+ CmdNegateLogical,
+ CmdLShift,
+ CmdRShift,
+ CmdUnaryMinus,
+ CmdIfNotGoto,
+ CmdLineSide,
+ CmdScriptWait,
+ CmdScriptWaitDirect,
+ CmdClearLineSpecial,
+ CmdCaseGoto,
+ CmdBeginPrint,
+ CmdEndPrint,
+ CmdPrintString,
+ CmdPrintNumber,
+ CmdPrintCharacter,
+ CmdPlayerCount,
+ CmdGameType,
+ CmdGameSkill,
+ CmdTimer,
+ CmdSectorSound,
+ CmdAmbientSound,
+ CmdSoundSequence,
+ CmdSetLineTexture,
+ CmdSetLineBlocking,
+ CmdSetLineSpecial,
+ CmdThingSound,
+ CmdEndPrintBold
+};
+
+// CODE --------------------------------------------------------------------
+
+static inline int32_t ReadCodePtr (void)
+{
+ uint32_t val = READ_INT32(PCodePtr);
+ return (int32_t) val;
+}
+
+static inline void IncrCodePtr (void)
+{
+ INCR_INT32(PCodePtr);
+}
+
+static inline int32_t ReadAndIncrCodePtr (void)
+{
+ uint32_t val = READ_INT32(PCodePtr);
+ INCR_INT32(PCodePtr);
+ return (int32_t) val;
+}
+
+//==========================================================================
+//
+// P_LoadACScripts
+//
+//==========================================================================
+
+void P_LoadACScripts(int lump)
+{
+ int i;
+ int *buffer;
+ acsHeader_t *header;
+ acsInfo_t *info;
+
+ header = (acsHeader_t *) W_CacheLumpNum(lump, PU_LEVEL);
+ ActionCodeBase = (byte *)header;
+ buffer = (int *)((byte *)header + LONG(header->infoOffset));
+ ACScriptCount = LONG(*buffer++);
+ if (ACScriptCount == 0)
+ { // Empty behavior lump
+ return;
+ }
+ ACSInfo = (acsInfo_t *) Z_Malloc(ACScriptCount*sizeof(acsInfo_t), PU_LEVEL, NULL);
+ memset(ACSInfo, 0, ACScriptCount*sizeof(acsInfo_t));
+ for (i = 0, info = ACSInfo; i < ACScriptCount; i++, info++)
+ {
+ info->number = LONG(*buffer++);
+ info->address = ActionCodeBase + LONG(*buffer++);
+ info->argCount = LONG(*buffer++);
+ if (info->number >= OPEN_SCRIPTS_BASE)
+ { // Auto-activate
+ info->number -= OPEN_SCRIPTS_BASE;
+ StartOpenACS(info->number, i, info->address);
+ info->state = ASTE_RUNNING;
+ }
+ else
+ {
+ info->state = ASTE_INACTIVE;
+ }
+ }
+ ACStringCount = LONG(*buffer++);
+ ACStrings = (char **) Z_Malloc(ACStringCount*sizeof(char *), PU_LEVEL, NULL);
+ for (i = 0; i < ACStringCount; i++)
+ {
+ ACStrings[i] = (char *)ActionCodeBase + LONG(buffer[i]);
+ }
+ memset(MapVars, 0, sizeof(MapVars));
+}
+
+//==========================================================================
+//
+// StartOpenACS
+//
+//==========================================================================
+
+static void StartOpenACS(int number, int infoIndex, byte *address)
+{
+ acs_t *script;
+
+ script = (acs_t *) Z_Malloc(sizeof(acs_t), PU_LEVSPEC, NULL);
+ memset(script, 0, sizeof(acs_t));
+ script->number = number;
+
+ // World objects are allotted 1 second for initialization
+ script->delayCount = 35;
+
+ script->infoIndex = infoIndex;
+ script->ip = address;
+ script->thinker.function = T_InterpretACS;
+ P_AddThinker(&script->thinker);
+}
+
+//==========================================================================
+//
+// P_CheckACSStore
+//
+// Scans the ACS store and executes all scripts belonging to the current
+// map.
+//
+//==========================================================================
+
+void P_CheckACSStore(void)
+{
+ acsstore_t *store;
+
+ for (store = ACSStore; store->map != 0; store++)
+ {
+ if (store->map == gamemap)
+ {
+ P_StartACS(store->script, 0, store->args, NULL, NULL, 0);
+ if (NewScript)
+ {
+ NewScript->delayCount = 35;
+ }
+ store->map = -1;
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_StartACS
+//
+//==========================================================================
+
+static char ErrorMsg[128];
+
+boolean P_StartACS(int number, int map, byte *args, mobj_t *activator,
+ line_t *line, int side)
+{
+ int i;
+ acs_t *script;
+ int infoIndex;
+ aste_t *statePtr;
+
+ NewScript = NULL;
+ if (map && map != gamemap)
+ { // Add to the script store
+ return AddToACSStore(map, number, args);
+ }
+ infoIndex = GetACSIndex(number);
+ if (infoIndex == -1)
+ { // Script not found
+ //I_Error("P_StartACS: Unknown script number %d", number);
+ snprintf(ErrorMsg, sizeof(ErrorMsg), "P_STARTACS ERROR: UNKNOWN SCRIPT %d", number);
+ P_SetMessage(&players[consoleplayer], ErrorMsg, true);
+ }
+ statePtr = &ACSInfo[infoIndex].state;
+ if (*statePtr == ASTE_SUSPENDED)
+ { // Resume a suspended script
+ *statePtr = ASTE_RUNNING;
+ return true;
+ }
+ if (*statePtr != ASTE_INACTIVE)
+ { // Script is already executing
+ return false;
+ }
+ script = (acs_t *) Z_Malloc(sizeof(acs_t), PU_LEVSPEC, NULL);
+ memset(script, 0, sizeof(acs_t));
+ script->number = number;
+ script->infoIndex = infoIndex;
+ script->activator = activator;
+ script->line = line;
+ script->side = side;
+ script->ip = ACSInfo[infoIndex].address;
+ script->thinker.function = T_InterpretACS;
+ for (i = 0; i < ACSInfo[infoIndex].argCount; i++)
+ {
+ script->vars[i] = args[i];
+ }
+ *statePtr = ASTE_RUNNING;
+ P_AddThinker(&script->thinker);
+ NewScript = script;
+ return true;
+}
+
+//==========================================================================
+//
+// AddToACSStore
+//
+//==========================================================================
+
+static boolean AddToACSStore(int map, int number, byte *args)
+{
+ int i;
+ int idx;
+
+ idx = -1;
+ for (i = 0; ACSStore[i].map != 0; i++)
+ {
+ if (ACSStore[i].script == number && ACSStore[i].map == map)
+ { // Don't allow duplicates
+ return false;
+ }
+ if (idx == -1 && ACSStore[i].map == -1)
+ { // Remember first empty slot
+ idx = i;
+ }
+ }
+ if (idx == -1)
+ { // Append required
+ if (i == MAX_ACS_STORE)
+ {
+ I_Error("AddToACSStore: MAX_ACS_STORE (%d) exceeded.",
+ MAX_ACS_STORE);
+ }
+ idx = i;
+ ACSStore[idx + 1].map = 0;
+ }
+ ACSStore[idx].map = map;
+ ACSStore[idx].script = number;
+// *((int *)ACSStore[idx].args) = *((int *)args);
+ ACSStore[idx].args[0] = args[0];
+ ACSStore[idx].args[1] = args[1];
+ ACSStore[idx].args[2] = args[2];
+ ACSStore[idx].args[3] = 0; /* unused */
+ return true;
+}
+
+//==========================================================================
+//
+// P_StartLockedACS
+//
+//==========================================================================
+
+boolean P_StartLockedACS(line_t *line, byte *args, mobj_t *mo, int side)
+{
+ int i;
+ int lock;
+ byte newArgs[5];
+ char LockedBuffer[80];
+
+ lock = args[4];
+ if (!mo->player)
+ {
+ return false;
+ }
+ if (lock)
+ {
+ if (!(mo->player->keys & (1<<(lock-1))))
+ {
+ snprintf(LockedBuffer, sizeof(LockedBuffer),
+ "YOU NEED THE %s\n", TextKeyMessages[lock-1]);
+ P_SetMessage(mo->player, LockedBuffer, true);
+ S_StartSound(mo, SFX_DOOR_LOCKED);
+ return false;
+ }
+ }
+ for (i = 0; i < 4; i++)
+ {
+ newArgs[i] = args[i];
+ }
+ newArgs[4] = 0;
+ return P_StartACS(newArgs[0], newArgs[1], &newArgs[2], mo, line, side);
+}
+
+//==========================================================================
+//
+// P_TerminateACS
+//
+//==========================================================================
+
+boolean P_TerminateACS(int number, int map)
+{
+ int infoIndex;
+
+ infoIndex = GetACSIndex(number);
+ if (infoIndex == -1)
+ { // Script not found
+ return false;
+ }
+ if (ACSInfo[infoIndex].state == ASTE_INACTIVE
+ || ACSInfo[infoIndex].state == ASTE_TERMINATING)
+ { // States that disallow termination
+ return false;
+ }
+ ACSInfo[infoIndex].state = ASTE_TERMINATING;
+ return true;
+}
+
+//==========================================================================
+//
+// P_SuspendACS
+//
+//==========================================================================
+
+boolean P_SuspendACS(int number, int map)
+{
+ int infoIndex;
+
+ infoIndex = GetACSIndex(number);
+ if (infoIndex == -1)
+ { // Script not found
+ return false;
+ }
+ if (ACSInfo[infoIndex].state == ASTE_INACTIVE
+ || ACSInfo[infoIndex].state == ASTE_SUSPENDED
+ || ACSInfo[infoIndex].state == ASTE_TERMINATING)
+ { // States that disallow suspension
+ return false;
+ }
+ ACSInfo[infoIndex].state = ASTE_SUSPENDED;
+ return true;
+}
+
+//==========================================================================
+//
+// P_Init
+//
+//==========================================================================
+
+void P_ACSInitNewGame(void)
+{
+ memset(WorldVars, 0, sizeof(WorldVars));
+ memset(ACSStore, 0, sizeof(ACSStore));
+}
+
+//==========================================================================
+//
+// T_InterpretACS
+//
+//==========================================================================
+
+void T_InterpretACS(acs_t *script)
+{
+ int cmd;
+ int action;
+
+ if (ACSInfo[script->infoIndex].state == ASTE_TERMINATING)
+ {
+ ACSInfo[script->infoIndex].state = ASTE_INACTIVE;
+ ScriptFinished(ACScript->number);
+ P_RemoveThinker(&ACScript->thinker);
+ return;
+ }
+ if (ACSInfo[script->infoIndex].state != ASTE_RUNNING)
+ {
+ return;
+ }
+ if (script->delayCount)
+ {
+ script->delayCount--;
+ return;
+ }
+ ACScript = script;
+ PCodePtr = ACScript->ip;
+ do
+ {
+ cmd = ReadAndIncrCodePtr();
+ action = PCodeCmds[cmd]();
+ } while (action == SCRIPT_CONTINUE);
+ ACScript->ip = PCodePtr;
+ if (action == SCRIPT_TERMINATE)
+ {
+ ACSInfo[script->infoIndex].state = ASTE_INACTIVE;
+ ScriptFinished(ACScript->number);
+ P_RemoveThinker(&ACScript->thinker);
+ }
+}
+
+//==========================================================================
+//
+// P_TagFinished
+//
+//==========================================================================
+
+void P_TagFinished(int tag)
+{
+ int i;
+
+ if (TagBusy(tag) == true)
+ {
+ return;
+ }
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ if (ACSInfo[i].state == ASTE_WAITINGFORTAG
+ && ACSInfo[i].waitValue == tag)
+ {
+ ACSInfo[i].state = ASTE_RUNNING;
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_PolyobjFinished
+//
+//==========================================================================
+
+void P_PolyobjFinished(int po)
+{
+ int i;
+
+ if (PO_Busy(po) == true)
+ {
+ return;
+ }
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ if (ACSInfo[i].state == ASTE_WAITINGFORPOLY
+ && ACSInfo[i].waitValue == po)
+ {
+ ACSInfo[i].state = ASTE_RUNNING;
+ }
+ }
+}
+
+//==========================================================================
+//
+// ScriptFinished
+//
+//==========================================================================
+
+static void ScriptFinished(int number)
+{
+ int i;
+
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ if (ACSInfo[i].state == ASTE_WAITINGFORSCRIPT
+ && ACSInfo[i].waitValue == number)
+ {
+ ACSInfo[i].state = ASTE_RUNNING;
+ }
+ }
+}
+
+//==========================================================================
+//
+// TagBusy
+//
+//==========================================================================
+
+static boolean TagBusy(int tag)
+{
+ int sectorIndex;
+
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ if (sectors[sectorIndex].specialdata)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+//==========================================================================
+//
+// GetACSIndex
+//
+// Returns the index of a script number. Returns -1 if the script number
+// is not found.
+//
+//==========================================================================
+
+static int GetACSIndex(int number)
+{
+ int i;
+
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ if (ACSInfo[i].number == number)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+//==========================================================================
+//
+// Push
+//
+//==========================================================================
+
+static void Push(int value)
+{
+ ACScript->stack[ACScript->stackPtr++] = value;
+}
+
+//==========================================================================
+//
+// Pop
+//
+//==========================================================================
+
+static int Pop(void)
+{
+ return ACScript->stack[--ACScript->stackPtr];
+}
+
+//==========================================================================
+//
+// Top
+//
+//==========================================================================
+
+static int Top(void)
+{
+ return ACScript->stack[ACScript->stackPtr - 1];
+}
+
+//==========================================================================
+//
+// Drop
+//
+//==========================================================================
+
+static void Drop(void)
+{
+ ACScript->stackPtr--;
+}
+
+//==========================================================================
+//
+// P-Code Commands
+//
+//==========================================================================
+
+static int CmdNOP(void)
+{
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdTerminate(void)
+{
+ return SCRIPT_TERMINATE;
+}
+
+static int CmdSuspend(void)
+{
+ ACSInfo[ACScript->infoIndex].state = ASTE_SUSPENDED;
+ return SCRIPT_STOP;
+}
+
+static int CmdPushNumber(void)
+{
+ Push(ReadAndIncrCodePtr());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec1(void)
+{
+ int special;
+
+ special = ReadAndIncrCodePtr();
+ SpecArgs[0] = Pop();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec2(void)
+{
+ int special;
+
+ special = ReadAndIncrCodePtr();
+ SpecArgs[1] = Pop();
+ SpecArgs[0] = Pop();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec3(void)
+{
+ int special;
+
+ special = ReadAndIncrCodePtr();
+ SpecArgs[2] = Pop();
+ SpecArgs[1] = Pop();
+ SpecArgs[0] = Pop();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec4(void)
+{
+ int special;
+
+ special = ReadAndIncrCodePtr();
+ SpecArgs[3] = Pop();
+ SpecArgs[2] = Pop();
+ SpecArgs[1] = Pop();
+ SpecArgs[0] = Pop();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec5(void)
+{
+ int special;
+
+ special = ReadAndIncrCodePtr();
+ SpecArgs[4] = Pop();
+ SpecArgs[3] = Pop();
+ SpecArgs[2] = Pop();
+ SpecArgs[1] = Pop();
+ SpecArgs[0] = Pop();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec1Direct(void)
+{
+ int special;
+
+ special = ReadAndIncrCodePtr();
+ SpecArgs[0] = ReadAndIncrCodePtr();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec2Direct(void)
+{
+ int special;
+
+ special = ReadAndIncrCodePtr();
+ SpecArgs[0] = ReadAndIncrCodePtr();
+ SpecArgs[1] = ReadAndIncrCodePtr();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec3Direct(void)
+{
+ int special;
+
+ special = ReadAndIncrCodePtr();
+ SpecArgs[0] = ReadAndIncrCodePtr();
+ SpecArgs[1] = ReadAndIncrCodePtr();
+ SpecArgs[2] = ReadAndIncrCodePtr();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec4Direct(void)
+{
+ int special;
+
+ special = ReadAndIncrCodePtr();
+ SpecArgs[0] = ReadAndIncrCodePtr();
+ SpecArgs[1] = ReadAndIncrCodePtr();
+ SpecArgs[2] = ReadAndIncrCodePtr();
+ SpecArgs[3] = ReadAndIncrCodePtr();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLSpec5Direct(void)
+{
+ int special;
+
+ special = ReadAndIncrCodePtr();
+ SpecArgs[0] = ReadAndIncrCodePtr();
+ SpecArgs[1] = ReadAndIncrCodePtr();
+ SpecArgs[2] = ReadAndIncrCodePtr();
+ SpecArgs[3] = ReadAndIncrCodePtr();
+ SpecArgs[4] = ReadAndIncrCodePtr();
+ P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
+ ACScript->side, ACScript->activator);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAdd(void)
+{
+ Push (Pop() + Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSubtract(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push (Pop() - operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdMultiply(void)
+{
+ Push (Pop() * Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDivide(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push (Pop() / operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdModulus(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push (Pop() % operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdEQ(void)
+{
+ Push (Pop() == Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdNE(void)
+{
+ Push (Pop() != Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLT(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push (Pop() < operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdGT(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push (Pop() > operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLE(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push (Pop() <= operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdGE(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push (Pop() >= operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAssignScriptVar(void)
+{
+ ACScript->vars[ReadAndIncrCodePtr()] = Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAssignMapVar(void)
+{
+ MapVars[ReadAndIncrCodePtr()] = Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAssignWorldVar(void)
+{
+ WorldVars[ReadAndIncrCodePtr()] = Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPushScriptVar(void)
+{
+ Push(ACScript->vars[ReadAndIncrCodePtr()]);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPushMapVar(void)
+{
+ Push(MapVars[ReadAndIncrCodePtr()]);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPushWorldVar(void)
+{
+ Push(WorldVars[ReadAndIncrCodePtr()]);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAddScriptVar(void)
+{
+ ACScript->vars[ReadAndIncrCodePtr()] += Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAddMapVar(void)
+{
+ MapVars[ReadAndIncrCodePtr()] += Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAddWorldVar(void)
+{
+ WorldVars[ReadAndIncrCodePtr()] += Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSubScriptVar(void)
+{
+ ACScript->vars[ReadAndIncrCodePtr()] -= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSubMapVar(void)
+{
+ MapVars[ReadAndIncrCodePtr()] -= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSubWorldVar(void)
+{
+ WorldVars[ReadAndIncrCodePtr()] -= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdMulScriptVar(void)
+{
+ ACScript->vars[ReadAndIncrCodePtr()] *= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdMulMapVar(void)
+{
+ MapVars[ReadAndIncrCodePtr()] *= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdMulWorldVar(void)
+{
+ WorldVars[ReadAndIncrCodePtr()] *= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDivScriptVar(void)
+{
+ ACScript->vars[ReadAndIncrCodePtr()] /= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDivMapVar(void)
+{
+ MapVars[ReadAndIncrCodePtr()] /= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDivWorldVar(void)
+{
+ WorldVars[ReadAndIncrCodePtr()] /= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdModScriptVar(void)
+{
+ ACScript->vars[ReadAndIncrCodePtr()] %= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdModMapVar(void)
+{
+ MapVars[ReadAndIncrCodePtr()] %= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdModWorldVar(void)
+{
+ WorldVars[ReadAndIncrCodePtr()] %= Pop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdIncScriptVar(void)
+{
+ ACScript->vars[ReadAndIncrCodePtr()]++;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdIncMapVar(void)
+{
+ MapVars[ReadAndIncrCodePtr()]++;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdIncWorldVar(void)
+{
+ WorldVars[ReadAndIncrCodePtr()]++;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDecScriptVar(void)
+{
+ ACScript->vars[ReadAndIncrCodePtr()]--;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDecMapVar(void)
+{
+ MapVars[ReadAndIncrCodePtr()]--;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDecWorldVar(void)
+{
+ WorldVars[ReadAndIncrCodePtr()]--;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdGoto(void)
+{
+ PCodePtr = ActionCodeBase + ReadCodePtr();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdIfGoto(void)
+{
+ if (Pop())
+ {
+ PCodePtr = ActionCodeBase + ReadCodePtr();
+ }
+ else
+ {
+ IncrCodePtr();
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDrop(void)
+{
+ Drop();
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdDelay(void)
+{
+ ACScript->delayCount = Pop();
+ return SCRIPT_STOP;
+}
+
+static int CmdDelayDirect(void)
+{
+ ACScript->delayCount = ReadAndIncrCodePtr();
+ return SCRIPT_STOP;
+}
+
+static int CmdRandom(void)
+{
+ int low;
+ int high;
+
+ high = Pop();
+ low = Pop();
+ Push (low + (P_Random() % (high - low + 1)));
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdRandomDirect(void)
+{
+ int low;
+ int high;
+
+ low = ReadAndIncrCodePtr();
+ high = ReadAndIncrCodePtr();
+ Push (low + (P_Random() % (high - low + 1)));
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdThingCount(void)
+{
+ int tid;
+
+ tid = Pop();
+ ThingCount(Pop(), tid);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdThingCountDirect(void)
+{
+ int type;
+
+ type = ReadAndIncrCodePtr();
+ ThingCount(type, ReadAndIncrCodePtr());
+ return SCRIPT_CONTINUE;
+}
+
+static void ThingCount(int type, int tid)
+{
+ int count;
+ int searcher;
+ mobj_t *mobj;
+ mobjtype_t moType;
+ thinker_t *think;
+
+ if (!(type + tid))
+ { // Nothing to count
+ return;
+ }
+ moType = TranslateThingType[type];
+ count = 0;
+ searcher = -1;
+ if (tid)
+ { // Count TID things
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (type == 0)
+ { // Just count TIDs
+ count++;
+ }
+ else if (moType == mobj->type)
+ {
+ if (mobj->flags & MF_COUNTKILL && mobj->health <= 0)
+ { // Don't count dead monsters
+ continue;
+ }
+ count++;
+ }
+ }
+ }
+ else
+ { // Count only types
+ for (think = thinkercap.next; think != &thinkercap;
+ think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mobj = (mobj_t *)think;
+ if (mobj->type != moType)
+ { // Doesn't match
+ continue;
+ }
+ if (mobj->flags & MF_COUNTKILL && mobj->health <= 0)
+ { // Don't count dead monsters
+ continue;
+ }
+ count++;
+ }
+ }
+ Push(count);
+}
+
+static int CmdTagWait(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = Pop();
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG;
+ return SCRIPT_STOP;
+}
+
+static int CmdTagWaitDirect(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = ReadAndIncrCodePtr();
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG;
+ return SCRIPT_STOP;
+}
+
+static int CmdPolyWait(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = Pop();
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY;
+ return SCRIPT_STOP;
+}
+
+static int CmdPolyWaitDirect(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = ReadAndIncrCodePtr();
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY;
+ return SCRIPT_STOP;
+}
+
+static int CmdChangeFloor(void)
+{
+ int tag;
+ int flat;
+ int sectorIndex;
+
+ flat = R_FlatNumForName(ACStrings[Pop()]);
+ tag = Pop();
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ sectors[sectorIndex].floorpic = flat;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdChangeFloorDirect(void)
+{
+ int tag;
+ int flat;
+ int sectorIndex;
+
+ tag = ReadAndIncrCodePtr();
+ flat = R_FlatNumForName(ACStrings[ReadAndIncrCodePtr()]);
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ sectors[sectorIndex].floorpic = flat;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdChangeCeiling(void)
+{
+ int tag;
+ int flat;
+ int sectorIndex;
+
+ flat = R_FlatNumForName(ACStrings[Pop()]);
+ tag = Pop();
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ sectors[sectorIndex].ceilingpic = flat;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdChangeCeilingDirect(void)
+{
+ int tag;
+ int flat;
+ int sectorIndex;
+
+ tag = ReadAndIncrCodePtr();
+ flat = R_FlatNumForName(ACStrings[ReadAndIncrCodePtr()]);
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ sectors[sectorIndex].ceilingpic = flat;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdRestart(void)
+{
+ PCodePtr = ACSInfo[ACScript->infoIndex].address;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAndLogical(void)
+{
+ Push (Pop() && Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdOrLogical(void)
+{
+ Push (Pop() || Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAndBitwise(void)
+{
+ Push (Pop() & Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdOrBitwise(void)
+{
+ Push (Pop() | Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdEorBitwise(void)
+{
+ Push (Pop() ^ Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdNegateLogical(void)
+{
+ Push (!Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLShift(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push (Pop() << operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdRShift(void)
+{
+ int operand2;
+
+ operand2 = Pop();
+ Push (Pop() >> operand2);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdUnaryMinus(void)
+{
+ Push (-Pop());
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdIfNotGoto(void)
+{
+ if (Pop())
+ {
+ IncrCodePtr();
+ }
+ else
+ {
+ PCodePtr = ActionCodeBase + ReadCodePtr();
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdLineSide(void)
+{
+ Push(ACScript->side);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdScriptWait(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = Pop();
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT;
+ return SCRIPT_STOP;
+}
+
+static int CmdScriptWaitDirect(void)
+{
+ ACSInfo[ACScript->infoIndex].waitValue = ReadAndIncrCodePtr();
+ ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT;
+ return SCRIPT_STOP;
+}
+
+static int CmdClearLineSpecial(void)
+{
+ if (ACScript->line)
+ {
+ ACScript->line->special = 0;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdCaseGoto(void)
+{
+ if (Top() == ReadAndIncrCodePtr())
+ {
+ PCodePtr = ActionCodeBase + ReadCodePtr();
+ Drop();
+ }
+ else
+ {
+ IncrCodePtr();
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdBeginPrint(void)
+{
+ *PrintBuffer = 0;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdEndPrint(void)
+{
+ player_t *player;
+
+ if (ACScript->activator && ACScript->activator->player)
+ {
+ player = ACScript->activator->player;
+ }
+ else
+ {
+ player = &players[consoleplayer];
+ }
+ P_SetMessage(player, PrintBuffer, true);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdEndPrintBold(void)
+{
+ int i;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ P_SetYellowMessage(&players[i], PrintBuffer, true);
+ }
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPrintString(void)
+{
+ strcat(PrintBuffer, ACStrings[Pop()]);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPrintNumber(void)
+{
+ char tempStr[16];
+
+ snprintf(tempStr, sizeof(tempStr), "%d", Pop());
+ strcat(PrintBuffer, tempStr);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPrintCharacter(void)
+{
+ char *bufferEnd;
+
+ bufferEnd = PrintBuffer + strlen(PrintBuffer);
+ *bufferEnd++ = Pop();
+ *bufferEnd = 0;
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdPlayerCount(void)
+{
+ int i;
+ int count;
+
+ count = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ count += playeringame[i];
+ }
+ Push(count);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdGameType(void)
+{
+ int gametype;
+
+ if (netgame == false)
+ {
+ gametype = GAME_SINGLE_PLAYER;
+ }
+ else if (deathmatch)
+ {
+ gametype = GAME_NET_DEATHMATCH;
+ }
+ else
+ {
+ gametype = GAME_NET_COOPERATIVE;
+ }
+ Push(gametype);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdGameSkill(void)
+{
+ Push(gameskill);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdTimer(void)
+{
+ Push(leveltime);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSectorSound(void)
+{
+ int volume;
+ mobj_t *mobj;
+
+ mobj = NULL;
+ if (ACScript->line)
+ {
+ mobj = (mobj_t *)(void *)&ACScript->line->frontsector->soundorg;
+ }
+ volume = Pop();
+ S_StartSoundAtVolume(mobj, S_GetSoundID(ACStrings[Pop()]), volume);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdThingSound(void)
+{
+ int tid;
+ int sound;
+ int volume;
+ mobj_t *mobj;
+ int searcher;
+
+ volume = Pop();
+ sound = S_GetSoundID(ACStrings[Pop()]);
+ tid = Pop();
+ searcher = -1;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ S_StartSoundAtVolume(mobj, sound, volume);
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdAmbientSound(void)
+{
+ int volume;
+
+ volume = Pop();
+ S_StartSoundAtVolume(NULL, S_GetSoundID(ACStrings[Pop()]), volume);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSoundSequence(void)
+{
+ mobj_t *mobj;
+
+ mobj = NULL;
+ if (ACScript->line)
+ {
+ mobj = (mobj_t *)(void *)&ACScript->line->frontsector->soundorg;
+ }
+ SN_StartSequenceName(mobj, ACStrings[Pop()]);
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSetLineTexture(void)
+{
+ line_t *line;
+ int lineTag;
+ int side;
+ int position;
+ int texture;
+ int searcher;
+
+ texture = R_TextureNumForName(ACStrings[Pop()]);
+ position = Pop();
+ side = Pop();
+ lineTag = Pop();
+ searcher = -1;
+ while ((line = P_FindLine(lineTag, &searcher)) != NULL)
+ {
+ if (position == TEXTURE_MIDDLE)
+ {
+ sides[line->sidenum[side]].midtexture = texture;
+ }
+ else if (position == TEXTURE_BOTTOM)
+ {
+ sides[line->sidenum[side]].bottomtexture = texture;
+ }
+ else
+ { // TEXTURE_TOP
+ sides[line->sidenum[side]].toptexture = texture;
+ }
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSetLineBlocking(void)
+{
+ line_t *line;
+ int lineTag;
+ boolean blocking;
+ int searcher;
+
+ blocking = Pop() ? ML_BLOCKING : 0;
+ lineTag = Pop();
+ searcher = -1;
+ while ((line = P_FindLine(lineTag, &searcher)) != NULL)
+ {
+ line->flags = (line->flags & ~ML_BLOCKING) | blocking;
+ }
+ return SCRIPT_CONTINUE;
+}
+
+static int CmdSetLineSpecial(void)
+{
+ line_t *line;
+ int lineTag;
+ int special, arg1, arg2, arg3, arg4, arg5;
+ int searcher;
+
+ arg5 = Pop();
+ arg4 = Pop();
+ arg3 = Pop();
+ arg2 = Pop();
+ arg1 = Pop();
+ special = Pop();
+ lineTag = Pop();
+ searcher = -1;
+ while ((line = P_FindLine(lineTag, &searcher)) != NULL)
+ {
+ line->special = special;
+ line->arg1 = arg1;
+ line->arg2 = arg2;
+ line->arg3 = arg3;
+ line->arg4 = arg4;
+ line->arg5 = arg5;
+ }
+ return SCRIPT_CONTINUE;
+}
+
--- /dev/null
+++ b/p_anim.c
@@ -1,0 +1,476 @@
+
+//**************************************************************************
+//**
+//** p_anim.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define ANIM_SCRIPT_NAME "ANIMDEFS"
+
+#define MAX_ANIM_DEFS 20
+#define MAX_FRAME_DEFS 96
+
+#define ANIM_FLAT 0
+#define ANIM_TEXTURE 1
+
+#define SCI_FLAT "flat"
+#define SCI_TEXTURE "texture"
+#define SCI_PIC "pic"
+#define SCI_TICS "tics"
+#define SCI_RAND "rand"
+
+#define LIGHTNING_SPECIAL 198
+#define LIGHTNING_SPECIAL2 199
+#define SKYCHANGE_SPECIAL 200
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct
+{
+ int index;
+ int tics;
+} frameDef_t;
+
+typedef struct
+{
+ int type;
+ int index;
+ int tics;
+ int currentFrameDef;
+ int startFrameDef;
+ int endFrameDef;
+} animDef_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void P_LightningFlash(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern fixed_t Sky1ColumnOffset;
+extern fixed_t Sky2ColumnOffset;
+extern int Sky1Texture;
+extern boolean DoubleSky;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+fixed_t Sky1ScrollDelta;
+fixed_t Sky2ScrollDelta;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static animDef_t AnimDefs[MAX_ANIM_DEFS];
+static frameDef_t FrameDefs[MAX_FRAME_DEFS];
+static int AnimDefCount;
+static boolean LevelHasLightning;
+static int NextLightningFlash;
+static int LightningFlash;
+static int *LightningLightLevels;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_AnimateSurfaces
+//
+//==========================================================================
+
+void P_AnimateSurfaces(void)
+{
+ int i;
+ animDef_t *ad;
+ line_t *line;
+
+ // Animate flats and textures
+ for (i = 0; i < AnimDefCount; i++)
+ {
+ ad = &AnimDefs[i];
+ ad->tics--;
+ if (ad->tics == 0)
+ {
+ if (ad->currentFrameDef == ad->endFrameDef)
+ {
+ ad->currentFrameDef = ad->startFrameDef;
+ }
+ else
+ {
+ ad->currentFrameDef++;
+ }
+ ad->tics = FrameDefs[ad->currentFrameDef].tics;
+ if (ad->tics > 255)
+ { // Random tics
+ ad->tics = (ad->tics>>16)
+ + P_Random() % ((ad->tics & 0xff00)>>8);
+ }
+ if (ad->type == ANIM_FLAT)
+ {
+ flattranslation[ad->index] =
+ FrameDefs[ad->currentFrameDef].index;
+ }
+ else
+ { // Texture
+ texturetranslation[ad->index] =
+ FrameDefs[ad->currentFrameDef].index;
+ }
+ }
+ }
+
+ // Update scrolling textures
+ for (i = 0; i < numlinespecials; i++)
+ {
+ line = linespeciallist[i];
+ switch (line->special)
+ {
+ case 100: // Scroll_Texture_Left
+ sides[line->sidenum[0]].textureoffset += line->arg1<<10;
+ break;
+ case 101: // Scroll_Texture_Right
+ sides[line->sidenum[0]].textureoffset -= line->arg1<<10;
+ break;
+ case 102: // Scroll_Texture_Up
+ sides[line->sidenum[0]].rowoffset += line->arg1<<10;
+ break;
+ case 103: // Scroll_Texture_Down
+ sides[line->sidenum[0]].rowoffset -= line->arg1<<10;
+ break;
+ }
+ }
+
+ // Update sky column offsets
+ Sky1ColumnOffset += Sky1ScrollDelta;
+ Sky2ColumnOffset += Sky2ScrollDelta;
+
+ if (LevelHasLightning)
+ {
+ if (!NextLightningFlash || LightningFlash)
+ {
+ P_LightningFlash();
+ }
+ else
+ {
+ NextLightningFlash--;
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_LightningFlash
+//
+//==========================================================================
+
+static void P_LightningFlash(void)
+{
+ int i;
+ sector_t *tempSec;
+ int *tempLight;
+ boolean foundSec;
+ int flashLight;
+
+ if (LightningFlash)
+ {
+ LightningFlash--;
+ if (LightningFlash)
+ {
+ tempLight = LightningLightLevels;
+ tempSec = sectors;
+ for (i = 0; i < numsectors; i++, tempSec++)
+ {
+ if (tempSec->ceilingpic == skyflatnum
+ || tempSec->special == LIGHTNING_SPECIAL
+ || tempSec->special == LIGHTNING_SPECIAL2)
+ {
+ if (*tempLight < tempSec->lightlevel - 4)
+ {
+ tempSec->lightlevel -= 4;
+ }
+ tempLight++;
+ }
+ }
+ }
+ else
+ { // remove the alternate lightning flash special
+ tempLight = LightningLightLevels;
+ tempSec = sectors;
+ for (i = 0; i < numsectors; i++, tempSec++)
+ {
+ if (tempSec->ceilingpic == skyflatnum
+ || tempSec->special == LIGHTNING_SPECIAL
+ || tempSec->special == LIGHTNING_SPECIAL2)
+ {
+ tempSec->lightlevel = *tempLight;
+ tempLight++;
+ }
+ }
+ Sky1Texture = P_GetMapSky1Texture(gamemap);
+ }
+ return;
+ }
+ LightningFlash = (P_Random() & 7) + 8;
+ flashLight = 200 + (P_Random() & 31);
+ tempSec = sectors;
+ tempLight = LightningLightLevels;
+ foundSec = false;
+ for (i = 0; i < numsectors; i++, tempSec++)
+ {
+ if (tempSec->ceilingpic == skyflatnum
+ || tempSec->special == LIGHTNING_SPECIAL
+ || tempSec->special == LIGHTNING_SPECIAL2)
+ {
+ *tempLight = tempSec->lightlevel;
+ if (tempSec->special == LIGHTNING_SPECIAL)
+ {
+ tempSec->lightlevel += 64;
+ if (tempSec->lightlevel > flashLight)
+ {
+ tempSec->lightlevel = flashLight;
+ }
+ }
+ else if (tempSec->special == LIGHTNING_SPECIAL2)
+ {
+ tempSec->lightlevel += 32;
+ if (tempSec->lightlevel > flashLight)
+ {
+ tempSec->lightlevel = flashLight;
+ }
+ }
+ else
+ {
+ tempSec->lightlevel = flashLight;
+ }
+ if (tempSec->lightlevel < *tempLight)
+ {
+ tempSec->lightlevel = *tempLight;
+ }
+ tempLight++;
+ foundSec = true;
+ }
+ }
+ if (foundSec)
+ {
+ Sky1Texture = P_GetMapSky2Texture(gamemap); // set alternate sky
+ S_StartSound(NULL, SFX_THUNDER_CRASH);
+ }
+ // Calculate the next lighting flash
+ if (!NextLightningFlash)
+ {
+ if (P_Random() < 50)
+ { // Immediate Quick flash
+ NextLightningFlash = (P_Random() & 15) + 16;
+ }
+ else
+ {
+ if (P_Random() < 128 && !(leveltime & 32))
+ {
+ NextLightningFlash = ((P_Random() & 7) + 2)*35;
+ }
+ else
+ {
+ NextLightningFlash = ((P_Random() & 15) + 5)*35;
+ }
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_ForceLightning
+//
+//==========================================================================
+
+void P_ForceLightning(void)
+{
+ NextLightningFlash = 0;
+}
+
+//==========================================================================
+//
+// P_InitLightning
+//
+//==========================================================================
+
+void P_InitLightning(void)
+{
+ int i;
+ int secCount;
+
+ if (!P_GetMapLightning(gamemap))
+ {
+ LevelHasLightning = false;
+ LightningFlash = 0;
+ return;
+ }
+ LightningFlash = 0;
+ secCount = 0;
+ for (i = 0; i < numsectors; i++)
+ {
+ if (sectors[i].ceilingpic == skyflatnum
+ || sectors[i].special == LIGHTNING_SPECIAL
+ || sectors[i].special == LIGHTNING_SPECIAL2)
+ {
+ secCount++;
+ }
+ }
+ if (secCount)
+ {
+ LevelHasLightning = true;
+ }
+ else
+ {
+ LevelHasLightning = false;
+ return;
+ }
+ LightningLightLevels = (int *)Z_Malloc(secCount*sizeof(int), PU_LEVEL, NULL);
+ NextLightningFlash = ((P_Random() & 15) + 5)*35; // don't flash at level start
+}
+
+//==========================================================================
+//
+// P_InitFTAnims
+//
+// Initialize flat and texture animation lists.
+//
+//==========================================================================
+
+void P_InitFTAnims(void)
+{
+ int base;
+ int mod;
+ int fd;
+ animDef_t *ad;
+ boolean ignore;
+ boolean done;
+
+ fd = 0;
+ ad = AnimDefs;
+ AnimDefCount = 0;
+ SC_Open(ANIM_SCRIPT_NAME);
+ while (SC_GetString())
+ {
+ if (AnimDefCount == MAX_ANIM_DEFS)
+ {
+ I_Error("P_InitFTAnims: too many AnimDefs.");
+ }
+ if (SC_Compare(SCI_FLAT))
+ {
+ ad->type = ANIM_FLAT;
+ }
+ else if (SC_Compare(SCI_TEXTURE))
+ {
+ ad->type = ANIM_TEXTURE;
+ }
+ else
+ {
+ SC_ScriptError(NULL);
+ }
+ SC_MustGetString(); // Name
+ ignore = false;
+ if (ad->type == ANIM_FLAT)
+ {
+ if (W_CheckNumForName(sc_String) == -1)
+ {
+ ignore = true;
+ }
+ else
+ {
+ ad->index = R_FlatNumForName(sc_String);
+ }
+ }
+ else
+ { // Texture
+ if (R_CheckTextureNumForName(sc_String) == -1)
+ {
+ ignore = true;
+ }
+ else
+ {
+ ad->index = R_TextureNumForName(sc_String);
+ }
+ }
+ ad->startFrameDef = fd;
+ done = false;
+ while (done == false)
+ {
+ if (SC_GetString())
+ {
+ if (SC_Compare(SCI_PIC))
+ {
+ if (fd == MAX_FRAME_DEFS)
+ {
+ I_Error("P_InitFTAnims: too many FrameDefs.");
+ }
+ SC_MustGetNumber();
+ if (ignore == false)
+ {
+ FrameDefs[fd].index = ad->index + sc_Number - 1;
+ }
+ SC_MustGetString();
+ if (SC_Compare(SCI_TICS))
+ {
+ SC_MustGetNumber();
+ if (ignore == false)
+ {
+ FrameDefs[fd].tics = sc_Number;
+ fd++;
+ }
+ }
+ else if (SC_Compare(SCI_RAND))
+ {
+ SC_MustGetNumber();
+ base = sc_Number;
+ SC_MustGetNumber();
+ if (ignore == false)
+ {
+ mod = sc_Number-base + 1;
+ FrameDefs[fd].tics = (base<<16) + (mod<<8);
+ fd++;
+ }
+ }
+ else
+ {
+ SC_ScriptError(NULL);
+ }
+ }
+ else
+ {
+ SC_UnGet();
+ done = true;
+ }
+ }
+ else
+ {
+ done = true;
+ }
+ }
+ if ((ignore == false) && (fd - ad->startFrameDef < 2))
+ {
+ I_Error("P_InitFTAnims: AnimDef has framecount < 2.");
+ }
+ if (ignore == false)
+ {
+ ad->endFrameDef = fd - 1;
+ ad->currentFrameDef = ad->endFrameDef;
+ ad->tics = 1; // Force 1st game tic to animate
+ AnimDefCount++;
+ ad++;
+ }
+ }
+
+ SC_Close();
+}
+
--- /dev/null
+++ b/p_ceilng.c
@@ -1,0 +1,303 @@
+
+//**************************************************************************
+//**
+//** p_ceilng.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 472 $
+//** $Date: 2009-05-26 15:45:18 +0300 (Tue, 26 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+//==================================================================
+//
+// CEILINGS
+//
+//==================================================================
+
+ceiling_t *activeceilings[MAXCEILINGS];
+
+//==================================================================
+//
+// T_MoveCeiling
+//
+//==================================================================
+
+void T_MoveCeiling (ceiling_t *ceiling)
+{
+ result_e res;
+
+ switch (ceiling->direction)
+ {
+// case 0: // IN STASIS
+// break;
+
+ case 1: // UP
+ res = T_MovePlane(ceiling->sector, ceiling->speed,
+ ceiling->topheight, false, 1, ceiling->direction);
+ if (res == RES_PASTDEST)
+ {
+ SN_StopSequence((mobj_t *)(void *)&ceiling->sector->soundorg);
+ switch (ceiling->type)
+ {
+ case CLEV_CRUSHANDRAISE:
+ ceiling->direction = -1;
+ ceiling->speed = ceiling->speed*2;
+ break;
+ default:
+ P_RemoveActiveCeiling(ceiling);
+ break;
+ }
+ }
+ break;
+
+ case -1: // DOWN
+ res = T_MovePlane(ceiling->sector, ceiling->speed,
+ ceiling->bottomheight, ceiling->crush, 1, ceiling->direction);
+ if (res == RES_PASTDEST)
+ {
+ SN_StopSequence((mobj_t *)(void *)&ceiling->sector->soundorg);
+ switch (ceiling->type)
+ {
+ case CLEV_CRUSHANDRAISE:
+ case CLEV_CRUSHRAISEANDSTAY:
+ ceiling->direction = 1;
+ ceiling->speed = ceiling->speed/2;
+ break;
+ default:
+ P_RemoveActiveCeiling(ceiling);
+ break;
+ }
+ }
+ else if (res == RES_CRUSHED)
+ {
+ switch (ceiling->type)
+ {
+ case CLEV_CRUSHANDRAISE:
+ case CLEV_LOWERANDCRUSH:
+ case CLEV_CRUSHRAISEANDSTAY:
+ //ceiling->speed = ceiling->speed/4;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+}
+
+//==================================================================
+//
+// EV_DoCeiling
+// Move a ceiling up/down and all around!
+//
+//==================================================================
+
+int EV_DoCeiling (line_t *line, byte *arg, ceiling_e type)
+{
+ int secnum, rtn;
+ sector_t *sec;
+ ceiling_t *ceiling;
+
+ secnum = -1;
+ rtn = 0;
+
+/* Old Ceiling stasis code
+ //
+ // Reactivate in-stasis ceilings...for certain types.
+ //
+ switch (type)
+ {
+ case CLEV_CRUSHANDRAISE:
+ P_ActivateInStasisCeiling(line);
+ default:
+ break;
+ }
+*/
+ while ((secnum = P_FindSectorFromTag(arg[0], secnum)) >= 0)
+ {
+ sec = §ors[secnum];
+ if (sec->specialdata)
+ continue;
+
+ //
+ // new door thinker
+ //
+ rtn = 1;
+ ceiling = (ceiling_t *) Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, NULL);
+ P_AddThinker (&ceiling->thinker);
+ sec->specialdata = ceiling;
+ ceiling->thinker.function = T_MoveCeiling;
+ ceiling->sector = sec;
+ ceiling->crush = 0;
+ ceiling->speed = arg[1]*(FRACUNIT/8);
+ switch (type)
+ {
+ case CLEV_CRUSHRAISEANDSTAY:
+ ceiling->crush = arg[2]; // arg[2] = crushing value
+ ceiling->topheight = sec->ceilingheight;
+ ceiling->bottomheight = sec->floorheight + (8*FRACUNIT);
+ ceiling->direction = -1;
+ break;
+ case CLEV_CRUSHANDRAISE:
+ ceiling->topheight = sec->ceilingheight;
+ case CLEV_LOWERANDCRUSH:
+ ceiling->crush = arg[2]; // arg[2] = crushing value
+ case CLEV_LOWERTOFLOOR:
+ ceiling->bottomheight = sec->floorheight;
+ if (type != CLEV_LOWERTOFLOOR)
+ {
+ ceiling->bottomheight += 8*FRACUNIT;
+ }
+ ceiling->direction = -1;
+ break;
+ case CLEV_RAISETOHIGHEST:
+ ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
+ ceiling->direction = 1;
+ break;
+ case CLEV_LOWERBYVALUE:
+ ceiling->bottomheight = sec->ceilingheight-arg[2]*FRACUNIT;
+ ceiling->direction = -1;
+ break;
+ case CLEV_RAISEBYVALUE:
+ ceiling->topheight = sec->ceilingheight+arg[2]*FRACUNIT;
+ ceiling->direction = 1;
+ break;
+ case CLEV_MOVETOVALUETIMES8:
+ { int destHeight = arg[2]*FRACUNIT*8;
+ if (arg[3])
+ {
+ destHeight = -destHeight;
+ }
+ if (sec->ceilingheight <= destHeight)
+ {
+ ceiling->direction = 1;
+ ceiling->topheight = destHeight;
+ if (sec->ceilingheight == destHeight)
+ {
+ rtn = 0;
+ }
+ }
+ else if (sec->ceilingheight > destHeight)
+ {
+ ceiling->direction = -1;
+ ceiling->bottomheight = destHeight;
+ }
+ break;
+ }
+ default:
+ rtn = 0;
+ break;
+ }
+ ceiling->tag = sec->tag;
+ ceiling->type = type;
+ P_AddActiveCeiling(ceiling);
+ if (rtn)
+ {
+ SN_StartSequence((mobj_t *)(void *)&ceiling->sector->soundorg,
+ SEQ_PLATFORM + ceiling->sector->seqType);
+ }
+ }
+ return rtn;
+}
+
+//==================================================================
+//
+// Add an active ceiling
+//
+//==================================================================
+
+void P_AddActiveCeiling(ceiling_t *c)
+{
+ int i;
+ for (i = 0; i < MAXCEILINGS; i++)
+ {
+ if (activeceilings[i] == NULL)
+ {
+ activeceilings[i] = c;
+ return;
+ }
+ }
+}
+
+//==================================================================
+//
+// Remove a ceiling's thinker
+//
+//==================================================================
+
+void P_RemoveActiveCeiling(ceiling_t *c)
+{
+ int i;
+
+ for (i = 0; i < MAXCEILINGS; i++)
+ {
+ if (activeceilings[i] == c)
+ {
+ activeceilings[i]->sector->specialdata = NULL;
+ P_RemoveThinker (&activeceilings[i]->thinker);
+ P_TagFinished(activeceilings[i]->sector->tag);
+ activeceilings[i] = NULL;
+ break;
+ }
+ }
+}
+
+#if 0
+//==================================================================
+//
+// Restart a ceiling that's in-stasis
+//
+//==================================================================
+
+void P_ActivateInStasisCeiling(line_t *line)
+{
+ int i;
+
+ for (i = 0; i < MAXCEILINGS; i++)
+ {
+ if (activeceilings[i] && (activeceilings[i]->tag == line->arg1) &&
+ (activeceilings[i]->direction == 0))
+ {
+ activeceilings[i]->direction = activeceilings[i]->olddirection;
+ activeceilings[i]->thinker.function = T_MoveCeiling;
+ SN_StartSequence((mobj_t *)(void *)&activeceilings[i]->sector->soundorg,
+ SEQ_PLATFORM + activeceilings[i]->sector->seqType);
+ }
+ }
+}
+#endif
+
+//==================================================================
+//
+// EV_CeilingCrushStop
+// Stop a ceiling from crushing!
+//
+//==================================================================
+
+int EV_CeilingCrushStop(line_t *line, byte *args)
+{
+ int i;
+ int rtn;
+
+ rtn = 0;
+ for (i = 0; i < MAXCEILINGS; i++)
+ {
+ if (activeceilings[i] && activeceilings[i]->tag == args[0])
+ {
+ rtn = 1;
+ SN_StopSequence((mobj_t*)(void *)&activeceilings[i]->sector->soundorg);
+ activeceilings[i]->sector->specialdata = NULL;
+ P_RemoveThinker (&activeceilings[i]->thinker);
+ P_TagFinished(activeceilings[i]->sector->tag);
+ activeceilings[i] = NULL;
+ break;
+ }
+ }
+ return rtn;
+}
+
--- /dev/null
+++ b/p_doors.c
@@ -1,0 +1,314 @@
+
+//**************************************************************************
+//**
+//** p_doors.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+//==================================================================
+//
+// VERTICAL DOORS
+//
+//==================================================================
+
+//==================================================================
+//
+// T_VerticalDoor
+//
+//==================================================================
+
+void T_VerticalDoor(vldoor_t *door)
+{
+ result_e res;
+
+ switch (door->direction)
+ {
+ case 0: // WAITING
+ if (!--door->topcountdown)
+ {
+ switch (door->type)
+ {
+ case DREV_NORMAL:
+ door->direction = -1; // time to go back down
+ SN_StartSequence((mobj_t *)(void *)&door->sector->soundorg,
+ SEQ_DOOR_STONE + door->sector->seqType);
+ break;
+ case DREV_CLOSE30THENOPEN:
+ door->direction = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case 2: // INITIAL WAIT
+ if (!--door->topcountdown)
+ {
+ switch (door->type)
+ {
+ case DREV_RAISEIN5MINS:
+ door->direction = 1;
+ door->type = DREV_NORMAL;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case -1: // DOWN
+ res = T_MovePlane(door->sector, door->speed,
+ door->sector->floorheight, false, 1, door->direction);
+ if (res == RES_PASTDEST)
+ {
+ SN_StopSequence((mobj_t *)(void *)&door->sector->soundorg);
+ switch (door->type)
+ {
+ case DREV_NORMAL:
+ case DREV_CLOSE:
+ door->sector->specialdata = NULL;
+ P_TagFinished(door->sector->tag);
+ P_RemoveThinker(&door->thinker); // unlink and free
+ break;
+ case DREV_CLOSE30THENOPEN:
+ door->direction = 0;
+ door->topcountdown = 35*30;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (res == RES_CRUSHED)
+ {
+ switch (door->type)
+ {
+ case DREV_CLOSE: // DON'T GO BACK UP!
+ break;
+ default:
+ door->direction = 1;
+ break;
+ }
+ }
+ break;
+ case 1: // UP
+ res = T_MovePlane(door->sector, door->speed,
+ door->topheight, false, 1, door->direction);
+ if (res == RES_PASTDEST)
+ {
+ SN_StopSequence((mobj_t *)(void *)&door->sector->soundorg);
+ switch (door->type)
+ {
+ case DREV_NORMAL:
+ door->direction = 0; // wait at top
+ door->topcountdown = door->topwait;
+ break;
+ case DREV_CLOSE30THENOPEN:
+ case DREV_OPEN:
+ door->sector->specialdata = NULL;
+ P_TagFinished(door->sector->tag);
+ P_RemoveThinker (&door->thinker); // unlink and free
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// EV_DoDoor
+//
+// Move a door up/down
+//
+//----------------------------------------------------------------------------
+
+int EV_DoDoor(line_t *line, byte *args, vldoor_e type)
+{
+ int secnum;
+ int retcode;
+ sector_t *sec;
+ vldoor_t *door;
+ fixed_t speed;
+
+ speed = args[1]*FRACUNIT/8;
+ secnum = -1;
+ retcode = 0;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = §ors[secnum];
+ if (sec->specialdata)
+ {
+ continue;
+ }
+ // Add new door thinker
+ retcode = 1;
+ door = (vldoor_t *) Z_Malloc(sizeof(*door), PU_LEVSPEC, NULL);
+ P_AddThinker(&door->thinker);
+ sec->specialdata = door;
+ door->thinker.function = T_VerticalDoor;
+ door->sector = sec;
+ switch (type)
+ {
+ case DREV_CLOSE:
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ door->direction = -1;
+ break;
+ case DREV_CLOSE30THENOPEN:
+ door->topheight = sec->ceilingheight;
+ door->direction = -1;
+ break;
+ case DREV_NORMAL:
+ case DREV_OPEN:
+ door->direction = 1;
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ break;
+ default:
+ break;
+ }
+ door->type = type;
+ door->speed = speed;
+ door->topwait = args[2]; // line->arg3
+ SN_StartSequence((mobj_t *)(void *)&door->sector->soundorg,
+ SEQ_DOOR_STONE + door->sector->seqType);
+ }
+ return retcode;
+}
+
+//==================================================================
+//
+// EV_VerticalDoor : open a door manually, no tag value
+//
+//==================================================================
+
+boolean EV_VerticalDoor(line_t *line, mobj_t *thing)
+{
+ sector_t *sec;
+ vldoor_t *door;
+ int side;
+
+ side = 0; // only front sides can be used
+
+ // if the sector has an active thinker, use it
+ sec = sides[line->sidenum[side^1]].sector;
+ if (sec->specialdata)
+ {
+ return false;
+ /*
+ door = sec->specialdata;
+ switch (line->special)
+ { // only for raise doors
+ case 12:
+ if (door->direction == -1)
+ {
+ door->direction = 1; // go back up
+ }
+ else
+ {
+ if (!thing->player)
+ { // Monsters don't close doors
+ return;
+ }
+ door->direction = -1; // start going down immediately
+ }
+ return;
+ }
+ */
+ }
+ //
+ // new door thinker
+ //
+ door = (vldoor_t *) Z_Malloc (sizeof(*door), PU_LEVSPEC, NULL);
+ P_AddThinker(&door->thinker);
+ sec->specialdata = door;
+ door->thinker.function = T_VerticalDoor;
+ door->sector = sec;
+ door->direction = 1;
+ switch (line->special)
+ {
+ case 11:
+ door->type = DREV_OPEN;
+ line->special = 0;
+ break;
+ case 12:
+ case 13:
+ door->type = DREV_NORMAL;
+ break;
+ default:
+ door->type = DREV_NORMAL;
+ break;
+ }
+ door->speed = line->arg2*(FRACUNIT/8);
+ door->topwait = line->arg3;
+
+ //
+ // find the top and bottom of the movement range
+ //
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ SN_StartSequence((mobj_t *)(void *)&door->sector->soundorg,
+ SEQ_DOOR_STONE + door->sector->seqType);
+ return true;
+}
+
+//==================================================================
+//
+// Spawn a door that closes after 30 seconds
+//
+//==================================================================
+
+/*
+void P_SpawnDoorCloseIn30(sector_t *sec)
+{
+ vldoor_t *door;
+
+ door = (vldoor_t *) Z_Malloc(sizeof(*door), PU_LEVSPEC, NULL);
+ P_AddThinker(&door->thinker);
+ sec->specialdata = door;
+ sec->special = 0;
+ door->thinker.function = T_VerticalDoor;
+ door->sector = sec;
+ door->direction = 0;
+ door->type = DREV_NORMAL;
+ door->speed = VDOORSPEED;
+ door->topcountdown = 30*35;
+}
+*/
+
+//==================================================================
+//
+// Spawn a door that opens after 5 minutes
+//
+//==================================================================
+
+/*
+void P_SpawnDoorRaiseIn5Mins(sector_t *sec, int secnum)
+{
+ vldoor_t *door;
+
+ door = (vldoor_t *) Z_Malloc(sizeof(*door), PU_LEVSPEC, NULL);
+ P_AddThinker(&door->thinker);
+ sec->specialdata = door;
+ sec->special = 0;
+ door->thinker.function = T_VerticalDoor;
+ door->sector = sec;
+ door->direction = 2;
+ door->type = DREV_RAISEIN5MINS;
+ door->speed = VDOORSPEED;
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ door->topwait = VDOORWAIT;
+ door->topcountdown = 5*60*35;
+}
+*/
+
--- /dev/null
+++ b/p_enemy.c
@@ -1,0 +1,5264 @@
+
+//**************************************************************************
+//**
+//** p_enemy.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 596 $
+//** $Date: 2013-03-16 02:24:28 +0200 (Sat, 16 Mar 2013) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+// Macros
+// Types
+// Private Data
+static mobj_t *soundtarget;
+// External Data
+extern fixed_t FloatBobOffsets[64];
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_RecursiveSound
+//
+//----------------------------------------------------------------------------
+
+static void P_RecursiveSound(sector_t *sec, int soundblocks)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+
+ // Wake up all monsters in this sector
+ if (sec->validcount == validcount && sec->soundtraversed <= soundblocks + 1)
+ { // Already flooded
+ return;
+ }
+ sec->validcount = validcount;
+ sec->soundtraversed = soundblocks + 1;
+ sec->soundtarget = soundtarget;
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ if (!(check->flags & ML_TWOSIDED))
+ {
+ continue;
+ }
+ P_LineOpening(check);
+ if (openrange <= 0)
+ { // Closed door
+ continue;
+ }
+ if (sides[check->sidenum[0]].sector == sec)
+ {
+ other = sides[check->sidenum[1]].sector;
+ }
+ else
+ {
+ other = sides[check->sidenum[0]].sector;
+ }
+ if (check->flags & ML_SOUNDBLOCK)
+ {
+ if (!soundblocks)
+ {
+ P_RecursiveSound(other, 1);
+ }
+ }
+ else
+ {
+ P_RecursiveSound(other, soundblocks);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_NoiseAlert
+//
+// If a monster yells at a player, it will alert other monsters to the
+// player.
+//
+//----------------------------------------------------------------------------
+
+void P_NoiseAlert(mobj_t *target, mobj_t *emmiter)
+{
+ soundtarget = target;
+ validcount++;
+ P_RecursiveSound(emmiter->subsector->sector, 0);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_CheckMeleeRange
+//
+//----------------------------------------------------------------------------
+
+static boolean P_CheckMeleeRange(mobj_t *actor)
+{
+ mobj_t *mo;
+ fixed_t dist;
+
+ if (!actor->target)
+ {
+ return false;
+ }
+ mo = actor->target;
+ dist = P_AproxDistance(mo->x - actor->x, mo->y - actor->y);
+ if (dist >= MELEERANGE)
+ {
+ return false;
+ }
+ if (!P_CheckSight(actor, mo))
+ {
+ return false;
+ }
+ if (mo->z > actor->z + actor->height)
+ { // Target is higher than the attacker
+ return false;
+ }
+ else if (actor->z > mo->z + mo->height)
+ { // Attacker is higher
+ return false;
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_CheckMeleeRange2
+//
+//----------------------------------------------------------------------------
+
+static boolean P_CheckMeleeRange2(mobj_t *actor)
+{
+ mobj_t *mo;
+ fixed_t dist;
+
+ if (!actor->target)
+ {
+ return false;
+ }
+ mo = actor->target;
+ dist = P_AproxDistance(mo->x - actor->x, mo->y - actor->y);
+ if (dist >= MELEERANGE*2 || dist < MELEERANGE)
+ {
+ return false;
+ }
+ if (!P_CheckSight(actor, mo))
+ {
+ return false;
+ }
+ if (mo->z > actor->z + actor->height)
+ { // Target is higher than the attacker
+ return false;
+ }
+ else if (actor->z > mo->z + mo->height)
+ { // Attacker is higher
+ return false;
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_CheckMissileRange
+//
+//----------------------------------------------------------------------------
+
+static boolean P_CheckMissileRange(mobj_t *actor)
+{
+ fixed_t dist;
+
+ if (!P_CheckSight(actor, actor->target))
+ {
+ return false;
+ }
+ if (actor->flags & MF_JUSTHIT)
+ { // The target just hit the enemy, so fight back!
+ actor->flags &= ~MF_JUSTHIT;
+ return true;
+ }
+ if (actor->reactiontime)
+ { // Don't attack yet
+ return false;
+ }
+ dist = (P_AproxDistance(actor->x - actor->target->x,
+ actor->y - actor->target->y)>>FRACBITS) - 64;
+ if (!actor->info->meleestate)
+ { // No melee attack, so fire more frequently
+ dist -= 128;
+ }
+ if (dist > 200)
+ {
+ dist = 200;
+ }
+ if (P_Random() < dist)
+ {
+ return false;
+ }
+ return true;
+}
+
+/*
+================
+=
+= P_Move
+=
+= Move in the current direction
+= returns false if the move is blocked
+================
+*/
+
+static fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
+static fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
+
+#define MAXSPECIALCROSS 8
+extern line_t *spechit[MAXSPECIALCROSS];
+extern int numspechit;
+
+static boolean P_Move(mobj_t *actor)
+{
+ fixed_t tryx, tryy;
+ line_t *ld;
+ boolean good;
+
+ if (actor->flags2 & MF2_BLASTED)
+ return true;
+ if (actor->movedir == DI_NODIR)
+ {
+ return false;
+ }
+ tryx = actor->x + actor->info->speed * xspeed[actor->movedir];
+ tryy = actor->y + actor->info->speed * yspeed[actor->movedir];
+ if (!P_TryMove(actor, tryx, tryy))
+ { // open any specials
+ if (actor->flags & MF_FLOAT && floatok)
+ { // must adjust height
+ if (actor->z < tmfloorz)
+ {
+ actor->z += FLOATSPEED;
+ }
+ else
+ {
+ actor->z -= FLOATSPEED;
+ }
+ actor->flags |= MF_INFLOAT;
+ return true;
+ }
+ if (!numspechit)
+ {
+ return false;
+ }
+ actor->movedir = DI_NODIR;
+ good = false;
+ while (numspechit--)
+ {
+ ld = spechit[numspechit];
+ // if the special isn't a door that can be opened, return false
+ if (P_ActivateLine(ld, actor, 0, SPAC_USE))
+ {
+ good = true;
+ }
+/* Old version before use/cross/impact specials were combined
+ if (P_UseSpecialLine(actor, ld))
+ {
+ good = true;
+ }
+*/
+ }
+ return good;
+ }
+ else
+ {
+ actor->flags &= ~MF_INFLOAT;
+ }
+ if (!(actor->flags & MF_FLOAT))
+ {
+ if (actor->z > actor->floorz)
+ {
+ P_HitFloor(actor);
+ }
+ actor->z = actor->floorz;
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_TryWalk
+//
+// Attempts to move actor in its current (ob->moveangle) direction.
+// If blocked by either a wall or an actor returns FALSE.
+// If move is either clear of block only by a door, returns TRUE and sets.
+// If a door is in the way, an OpenDoor call is made to start it opening.
+//
+//----------------------------------------------------------------------------
+
+static boolean P_TryWalk(mobj_t *actor)
+{
+ if (!P_Move(actor))
+ {
+ return false;
+ }
+ actor->movecount = P_Random() & 15;
+ return true;
+}
+
+/*
+================
+=
+= P_NewChaseDir
+=
+================
+*/
+
+static dirtype_t opposite[] =
+{
+ DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
+ DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST,
+ DI_NODIR
+};
+
+static dirtype_t diags[] =
+{
+ DI_NORTHWEST,
+ DI_NORTHEAST,
+ DI_SOUTHWEST,
+ DI_SOUTHEAST
+};
+
+static void P_NewChaseDir (mobj_t *actor)
+{
+ fixed_t deltax, deltay;
+ dirtype_t d[3];
+ dirtype_t tdir, olddir, turnaround;
+
+ if (!actor->target)
+ I_Error ("P_NewChaseDir: called with no target");
+
+ olddir = actor->movedir;
+ turnaround = opposite[olddir];
+
+ deltax = actor->target->x - actor->x;
+ deltay = actor->target->y - actor->y;
+ if (deltax > 10*FRACUNIT)
+ d[1] = DI_EAST;
+ else if (deltax < -10*FRACUNIT)
+ d[1] = DI_WEST;
+ else
+ d[1] = DI_NODIR;
+ if (deltay < -10*FRACUNIT)
+ d[2] = DI_SOUTH;
+ else if (deltay > 10*FRACUNIT)
+ d[2] = DI_NORTH;
+ else
+ d[2] = DI_NODIR;
+
+// try direct route
+ if (d[1] != DI_NODIR && d[2] != DI_NODIR)
+ {
+ actor->movedir = diags[((deltay < 0)<<1) + (deltax > 0)];
+ if (actor->movedir != turnaround && P_TryWalk(actor))
+ return;
+ }
+
+// try other directions
+ if (P_Random() > 200 || abs(deltay) > abs(deltax))
+ {
+ tdir = d[1];
+ d[1] = d[2];
+ d[2] = tdir;
+ }
+
+ if (d[1] == turnaround)
+ d[1] = DI_NODIR;
+ if (d[2] == turnaround)
+ d[2] = DI_NODIR;
+
+ if (d[1] != DI_NODIR)
+ {
+ actor->movedir = d[1];
+ if (P_TryWalk(actor))
+ return; /* either moved forward or attacked */
+ }
+
+ if (d[2] != DI_NODIR)
+ {
+ actor->movedir = d[2];
+ if (P_TryWalk(actor))
+ return;
+ }
+
+/* there is no direct path to the player, so pick another direction */
+
+ if (olddir != DI_NODIR)
+ {
+ actor->movedir = olddir;
+ if (P_TryWalk(actor))
+ return;
+ }
+
+ if (P_Random() & 1) /* randomly determine direction of search */
+ {
+ for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++)
+ {
+ if (tdir != turnaround)
+ {
+ actor->movedir = tdir;
+ if (P_TryWalk(actor))
+ return;
+ }
+ }
+ }
+ else
+ {
+ for (tdir = DI_SOUTHEAST; (int)tdir >= DI_EAST; tdir--)
+ {
+ if (tdir != turnaround)
+ {
+ actor->movedir = tdir;
+ if (P_TryWalk(actor))
+ return;
+ }
+ }
+ }
+
+ if (turnaround != DI_NODIR)
+ {
+ actor->movedir = turnaround;
+ if (P_TryWalk(actor))
+ return;
+ }
+
+ actor->movedir = DI_NODIR; // can't move
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_LookForMonsters
+//
+//---------------------------------------------------------------------------
+
+#define MONS_LOOK_RANGE (16 * 64 * FRACUNIT)
+#define MONS_LOOK_LIMIT 64
+
+static boolean P_LookForMonsters(mobj_t *actor)
+{
+ int count;
+ mobj_t *mo;
+ thinker_t *think;
+
+ if (!P_CheckSight(players[0].mo, actor))
+ { // Player can't see monster
+ return false;
+ }
+ count = 0;
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mo = (mobj_t *)think;
+ if (!(mo->flags & MF_COUNTKILL) || (mo == actor) || (mo->health <= 0))
+ { // Not a valid monster
+ continue;
+ }
+ if (P_AproxDistance(actor->x - mo->x, actor->y - mo->y) > MONS_LOOK_RANGE)
+ { // Out of range
+ continue;
+ }
+ if (P_Random() < 16)
+ { // Skip
+ continue;
+ }
+ if (count++ > MONS_LOOK_LIMIT)
+ { // Stop searching
+ return false;
+ }
+ if (!P_CheckSight(actor, mo))
+ { // Out of sight
+ continue;
+ }
+ if (actor->type == MT_MINOTAUR)
+ {
+ if ((mo->type == MT_MINOTAUR) &&
+ (mo->target != ((player_t *)actor->special1)->mo))
+ {
+ continue;
+ }
+ }
+ // Found a target monster
+ actor->target = mo;
+ return true;
+ }
+ return false;
+}
+
+/*
+================
+=
+= P_LookForPlayers
+=
+= If allaround is false, only look 180 degrees in front
+= returns true if a player is targeted
+================
+*/
+
+static boolean P_LookForPlayers(mobj_t *actor, boolean allaround)
+{
+ int c;
+ int stop;
+ player_t *player;
+ angle_t an;
+ fixed_t dist;
+
+ if (!netgame && players[0].health <= 0)
+ { // Single player game and player is dead, look for monsters
+ return(P_LookForMonsters(actor));
+ }
+ c = 0;
+ // O.S. - lastlook mask was 3 here, but it should have been
+ // a leftover from hexen-1.0 where MAXPLAYERS was 4..
+ // also see p_mobj.c :: P_SpawnMobj() where it is set.
+ stop = (actor->lastlook - 1) & (MAXPLAYERS - 1);
+ for ( ; ; actor->lastlook = (actor->lastlook + 1) & (MAXPLAYERS - 1))
+ {
+ if (!playeringame[actor->lastlook])
+ continue;
+
+ if (c++ == 2 || actor->lastlook == stop)
+ return false; // done looking
+
+ player = &players[actor->lastlook];
+ if (player->health <= 0)
+ continue; // dead
+ if (!P_CheckSight (actor, player->mo))
+ continue; // out of sight
+
+ if (!allaround)
+ {
+ an = R_PointToAngle2 (actor->x, actor->y, player->mo->x, player->mo->y)
+ - actor->angle;
+ if (an > ANG90 && an < ANG270)
+ {
+ dist = P_AproxDistance (player->mo->x - actor->x, player->mo->y - actor->y);
+ // if real close, react anyway
+ if (dist > MELEERANGE)
+ continue; // behind back
+ }
+ }
+ if (player->mo->flags & MF_SHADOW)
+ { // Player is invisible
+ if ((P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y) > 2*MELEERANGE)
+ && P_AproxDistance(player->mo->momx, player->mo->momy) < 5*FRACUNIT)
+ { // Player is sneaking - can't detect
+ return false;
+ }
+ if (P_Random() < 225)
+ { // Player isn't sneaking, but still didn't detect
+ return false;
+ }
+ }
+ if (actor->type == MT_MINOTAUR)
+ {
+ if (((player_t *)(actor->special1)) == player)
+ {
+ continue; // Don't target master
+ }
+ }
+
+ actor->target = player->mo;
+ return true;
+ }
+ return false;
+}
+
+/*
+===============================================================================
+
+ ACTION ROUTINES
+
+===============================================================================
+*/
+
+/*
+==============
+=
+= A_Look
+=
+= Stay in state until a player is sighted
+=
+==============
+*/
+
+void A_Look (mobj_t *actor)
+{
+ mobj_t *targ;
+
+ actor->threshold = 0; // any shot will wake up
+ targ = actor->subsector->sector->soundtarget;
+ if (targ && (targ->flags & MF_SHOOTABLE))
+ {
+ actor->target = targ;
+ if (actor->flags & MF_AMBUSH)
+ {
+ if (P_CheckSight (actor, actor->target))
+ goto seeyou;
+ }
+ else
+ goto seeyou;
+ }
+
+ if (!P_LookForPlayers (actor, false))
+ return;
+
+// go into chase state
+seeyou:
+ if (actor->info->seesound)
+ {
+ int sound;
+
+ sound = actor->info->seesound;
+ if (actor->flags2 & MF2_BOSS)
+ { // Full volume
+ S_StartSound(NULL, sound);
+ }
+ else
+ {
+ S_StartSound(actor, sound);
+ }
+ }
+ P_SetMobjState(actor, actor->info->seestate);
+}
+
+
+/*
+==============
+=
+= A_Chase
+=
+= Actor has a melee attack, so it tries to close as fast as possible
+=
+==============
+*/
+
+void A_Chase(mobj_t *actor)
+{
+ int delta;
+
+ if (actor->reactiontime)
+ {
+ actor->reactiontime--;
+ }
+
+ // Modify target threshold
+ if (actor->threshold)
+ {
+ actor->threshold--;
+ }
+
+ if (gameskill == sk_nightmare)
+ { // Monsters move faster in nightmare mode
+ actor->tics -= actor->tics/2;
+ if (actor->tics < 3)
+ {
+ actor->tics = 3;
+ }
+ }
+
+//
+// turn towards movement direction if not there yet
+//
+ if (actor->movedir < 8)
+ {
+ actor->angle &= (7 << 29);
+ delta = actor->angle - (actor->movedir << 29);
+ if (delta > 0)
+ {
+ actor->angle -= ANG90/2;
+ }
+ else if (delta < 0)
+ {
+ actor->angle += ANG90/2;
+ }
+ }
+
+ if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+ { // look for a new target
+ if (P_LookForPlayers(actor, true))
+ { // got a new target
+ return;
+ }
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+
+//
+// don't attack twice in a row
+//
+ if (actor->flags & MF_JUSTATTACKED)
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ if (gameskill != sk_nightmare)
+ P_NewChaseDir (actor);
+ return;
+ }
+
+//
+// check for melee attack
+//
+ if (actor->info->meleestate && P_CheckMeleeRange (actor))
+ {
+ if (actor->info->attacksound)
+ {
+ S_StartSound (actor, actor->info->attacksound);
+ }
+ P_SetMobjState (actor, actor->info->meleestate);
+ return;
+ }
+
+//
+// check for missile attack
+//
+ if (actor->info->missilestate)
+ {
+ if (gameskill < sk_nightmare && actor->movecount)
+ goto nomissile;
+ if (!P_CheckMissileRange (actor))
+ goto nomissile;
+ P_SetMobjState (actor, actor->info->missilestate);
+ actor->flags |= MF_JUSTATTACKED;
+ return;
+ }
+
+nomissile:
+//
+// possibly choose another target
+//
+ if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target))
+ {
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+ }
+
+//
+// chase towards player
+//
+ if (--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewChaseDir (actor);
+ }
+
+//
+// make active sound
+//
+ if (actor->info->activesound && P_Random() < 3)
+ {
+ if (actor->type == MT_BISHOP && P_Random() < 128)
+ {
+ S_StartSound(actor, actor->info->seesound);
+ }
+ else if (actor->type == MT_PIG)
+ {
+ S_StartSound(actor, SFX_PIG_ACTIVE1 + (P_Random() & 1));
+ }
+ else if (actor->flags2 & MF2_BOSS)
+ {
+ S_StartSound(NULL, actor->info->activesound);
+ }
+ else
+ {
+ S_StartSound(actor, actor->info->activesound);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FaceTarget
+//
+//----------------------------------------------------------------------------
+
+void A_FaceTarget(mobj_t *actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ actor->flags &= ~MF_AMBUSH;
+ actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+ if (actor->target->flags & MF_SHADOW)
+ { // Target is a ghost
+ actor->angle += (P_Random() - P_Random()) << 21;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Pain
+//
+//----------------------------------------------------------------------------
+
+void A_Pain(mobj_t *actor)
+{
+ if (actor->info->painsound)
+ {
+ S_StartSound(actor, actor->info->painsound);
+ }
+}
+
+//============================================================================
+//
+// A_SetInvulnerable
+//
+//============================================================================
+
+void A_SetInvulnerable(mobj_t *actor)
+{
+ actor->flags2 |= MF2_INVULNERABLE;
+}
+
+//============================================================================
+//
+// A_UnSetInvulnerable
+//
+//============================================================================
+
+void A_UnSetInvulnerable(mobj_t *actor)
+{
+ actor->flags2 &= ~MF2_INVULNERABLE;
+}
+
+//============================================================================
+//
+// A_SetReflective
+//
+//============================================================================
+
+void A_SetReflective(mobj_t *actor)
+{
+ actor->flags2 |= MF2_REFLECTIVE;
+
+ if ((actor->type == MT_CENTAUR) ||
+ (actor->type == MT_CENTAURLEADER))
+ {
+ A_SetInvulnerable(actor);
+ }
+}
+
+//============================================================================
+//
+// A_UnSetReflective
+//
+//============================================================================
+
+void A_UnSetReflective(mobj_t *actor)
+{
+ actor->flags2 &= ~MF2_REFLECTIVE;
+
+ if ((actor->type == MT_CENTAUR) ||
+ (actor->type == MT_CENTAURLEADER))
+ {
+ A_UnSetInvulnerable(actor);
+ }
+}
+
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_UpdateMorphedMonster
+//
+// Returns true if the pig morphs.
+//
+//----------------------------------------------------------------------------
+
+static boolean P_UpdateMorphedMonster(mobj_t *actor, int tics)
+{
+ mobj_t *fog;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ mobjtype_t moType;
+ mobj_t *mo;
+ mobj_t oldMonster;
+
+ actor->special1 -= tics;
+ if (actor->special1 > 0)
+ {
+ return false;
+ }
+ moType = actor->special2;
+ switch (moType)
+ {
+ case MT_WRAITHB: // These must remain morphed
+ case MT_SERPENT:
+ case MT_SERPENTLEADER:
+ case MT_MINOTAUR:
+ return false;
+ default:
+ break;
+ }
+ x = actor->x;
+ y = actor->y;
+ z = actor->z;
+ oldMonster = *actor; // Save pig vars
+
+ P_RemoveMobjFromTIDList(actor);
+ P_SetMobjState(actor, S_FREETARGMOBJ);
+ mo = P_SpawnMobj(x, y, z, moType);
+
+ if (P_TestMobjLocation(mo) == false)
+ { // Didn't fit
+ P_RemoveMobj(mo);
+ mo = P_SpawnMobj(x, y, z, oldMonster.type);
+ mo->angle = oldMonster.angle;
+ mo->flags = oldMonster.flags;
+ mo->health = oldMonster.health;
+ mo->target = oldMonster.target;
+ mo->special = oldMonster.special;
+ mo->special1 = 5*35; // Next try in 5 seconds
+ mo->special2 = moType;
+ mo->tid = oldMonster.tid;
+ memcpy(mo->args, oldMonster.args, 5);
+ P_InsertMobjIntoTIDList(mo, oldMonster.tid);
+ return false;
+ }
+ mo->angle = oldMonster.angle;
+ mo->target = oldMonster.target;
+ mo->tid = oldMonster.tid;
+ mo->special = oldMonster.special;
+ memcpy(mo->args, oldMonster.args, 5);
+ P_InsertMobjIntoTIDList(mo, oldMonster.tid);
+ fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_PigLook
+//
+//----------------------------------------------------------------------------
+
+void A_PigLook(mobj_t *actor)
+{
+ if (P_UpdateMorphedMonster(actor, 10))
+ {
+ return;
+ }
+ A_Look(actor);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_PigChase
+//
+//----------------------------------------------------------------------------
+
+void A_PigChase(mobj_t *actor)
+{
+ if (P_UpdateMorphedMonster(actor, 3))
+ {
+ return;
+ }
+ A_Chase(actor);
+}
+
+//============================================================================
+//
+// A_PigAttack
+//
+//============================================================================
+
+void A_PigAttack(mobj_t *actor)
+{
+ if (P_UpdateMorphedMonster(actor, 18))
+ {
+ return;
+ }
+ if (!actor->target)
+ {
+ return;
+ }
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, 2+(P_Random() & 1));
+ S_StartSound(actor, SFX_PIG_ATTACK);
+ }
+}
+
+//============================================================================
+//
+// A_PigPain
+//
+//============================================================================
+
+void A_PigPain(mobj_t *actor)
+{
+ A_Pain(actor);
+ if (actor->z <= actor->floorz)
+ {
+ actor->momz = 3.5*FRACUNIT;
+ }
+}
+
+
+static void FaceMovementDirection(mobj_t *actor)
+{
+ switch (actor->movedir)
+ {
+ case DI_EAST:
+ actor->angle = 0<<24;
+ break;
+ case DI_NORTHEAST:
+ actor->angle = 32<<24;
+ break;
+ case DI_NORTH:
+ actor->angle = 64<<24;
+ break;
+ case DI_NORTHWEST:
+ actor->angle = 96<<24;
+ break;
+ case DI_WEST:
+ actor->angle = 128<<24;
+ break;
+ case DI_SOUTHWEST:
+ actor->angle = 160<<24;
+ break;
+ case DI_SOUTH:
+ actor->angle = 192<<24;
+ break;
+ case DI_SOUTHEAST:
+ actor->angle = 224<<24;
+ break;
+ }
+}
+
+
+//----------------------------------------------------------------------------
+//
+// Minotaur variables
+//
+// special1 pointer to player that spawned it (mobj_t)
+// special2 internal to minotaur AI
+// args[0] args[0]-args[3] together make up minotaur start time
+// args[1] |
+// args[2] |
+// args[3] V
+// args[4] charge duration countdown
+//----------------------------------------------------------------------------
+
+void A_MinotaurFade0(mobj_t *actor)
+{
+ actor->flags &= ~MF_ALTSHADOW;
+ actor->flags |= MF_SHADOW;
+}
+
+void A_MinotaurFade1(mobj_t *actor)
+{
+ // Second level of transparency
+ actor->flags &= ~MF_SHADOW;
+ actor->flags |= MF_ALTSHADOW;
+}
+
+void A_MinotaurFade2(mobj_t *actor)
+{
+ // Make fully visible
+ actor->flags &= ~MF_SHADOW;
+ actor->flags &= ~MF_ALTSHADOW;
+}
+
+
+//----------------------------------------------------------------------------
+//
+// A_MinotaurRoam -
+//
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurLook(mobj_t *actor);
+
+void A_MinotaurRoam(mobj_t *actor)
+{
+ int summontime;
+
+ actor->flags &= ~MF_SHADOW; // In case pain caused him to
+ actor->flags &= ~MF_ALTSHADOW; // skip his fade in.
+
+ summontime = READ_INT32(actor->args);
+ if ((leveltime - summontime) >= MAULATORTICS)
+ {
+ P_DamageMobj(actor, NULL, NULL, 10000);
+ return;
+ }
+
+ if (P_Random() < 30)
+ A_MinotaurLook(actor); // adjust to closest target
+
+ if (P_Random() < 6)
+ {
+ //Choose new direction
+ actor->movedir = P_Random() % 8;
+ FaceMovementDirection(actor);
+ }
+ if (!P_Move(actor))
+ {
+ // Turn
+ if (P_Random() & 1)
+ {
+ // actor->movedir = (++actor->movedir) % 8;
+ ++actor->movedir;
+ actor->movedir = actor->movedir % 8;
+ }
+ else
+ {
+ actor->movedir = (actor->movedir + 7) % 8;
+ }
+ FaceMovementDirection(actor);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurLook
+//
+// Look for enemy of player
+//----------------------------------------------------------------------------
+#define MINOTAUR_LOOK_DIST (16 * 54 * FRACUNIT)
+
+void A_MinotaurLook(mobj_t *actor)
+{
+ mobj_t *mo = NULL;
+ player_t *player;
+ thinker_t *think;
+ fixed_t dist;
+ int i;
+ mobj_t *master = (mobj_t *)(actor->special1);
+
+ actor->target = NULL;
+ if (deathmatch) // Quick search for players
+ {
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ continue;
+ player = &players[i];
+ mo = player->mo;
+ if (mo == master)
+ continue;
+ if (mo->health <= 0)
+ continue;
+ dist = P_AproxDistance(actor->x - mo->x, actor->y - mo->y);
+ if (dist > MINOTAUR_LOOK_DIST)
+ continue;
+ actor->target = mo;
+ break;
+ }
+ }
+
+ if (!actor->target) // Near player monster search
+ {
+ if (master && (master->health > 0) && (master->player))
+ mo = P_RoughMonsterSearch(master, 20);
+ else
+ mo = P_RoughMonsterSearch(actor, 20);
+ actor->target = mo;
+ }
+
+ if (!actor->target) // Normal monster search
+ {
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ continue;
+ mo = (mobj_t *)think;
+ if (!(mo->flags & MF_COUNTKILL))
+ continue;
+ if (mo->health <= 0)
+ continue;
+ if (!(mo->flags & MF_SHOOTABLE))
+ continue;
+ dist = P_AproxDistance(actor->x - mo->x, actor->y - mo->y);
+ if (dist > MINOTAUR_LOOK_DIST)
+ continue;
+ if ((mo == master) || (mo == actor))
+ continue;
+ if ((mo->type == MT_MINOTAUR) && (mo->special1 == actor->special1))
+ continue;
+ actor->target = mo;
+ break; // Found mobj to attack
+ }
+ }
+
+ if (actor->target)
+ {
+ P_SetMobjStateNF(actor, S_MNTR_WALK1);
+ }
+ else
+ {
+ P_SetMobjStateNF(actor, S_MNTR_ROAM1);
+ }
+}
+
+
+void A_MinotaurChase(mobj_t *actor)
+{
+ int summontime;
+
+ actor->flags &= ~MF_SHADOW; // In case pain caused him to
+ actor->flags &= ~MF_ALTSHADOW; // skip his fade in.
+
+ summontime = READ_INT32(actor->args);
+ if ((leveltime - summontime) >= MAULATORTICS)
+ {
+ P_DamageMobj(actor, NULL, NULL, 10000);
+ return;
+ }
+
+ if (P_Random() < 30)
+ A_MinotaurLook(actor); // adjust to closest target
+
+ if (!actor->target || (actor->target->health <= 0) ||
+ !(actor->target->flags&MF_SHOOTABLE))
+ { // look for a new target
+ P_SetMobjState(actor, S_MNTR_LOOK1);
+ return;
+ }
+
+ FaceMovementDirection(actor);
+ actor->reactiontime = 0;
+
+ // Melee attack
+ if (actor->info->meleestate && P_CheckMeleeRange(actor))
+ {
+ if (actor->info->attacksound)
+ {
+ S_StartSound (actor, actor->info->attacksound);
+ }
+ P_SetMobjState (actor, actor->info->meleestate);
+ return;
+ }
+
+ // Missile attack
+ if (actor->info->missilestate && P_CheckMissileRange(actor))
+ {
+ P_SetMobjState (actor, actor->info->missilestate);
+ return;
+ }
+
+ // chase towards target
+ if (!P_Move(actor))
+ {
+ P_NewChaseDir(actor);
+ }
+
+ // Active sound
+ if (actor->info->activesound && P_Random() < 6)
+ {
+ S_StartSound(actor, actor->info->activesound);
+ }
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk1
+//
+// Melee attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk1(mobj_t *actor)
+{
+ if (!actor->target)
+ return;
+
+ S_StartSound(actor, SFX_MAULATOR_HAMMER_SWING);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(4));
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurDecide
+//
+// Choose a missile attack.
+//
+//----------------------------------------------------------------------------
+
+#define MNTR_CHARGE_SPEED (23 * FRACUNIT)
+
+void A_MinotaurDecide(mobj_t *actor)
+{
+ angle_t angle;
+ mobj_t *target = actor->target;
+ int dist;
+
+ if (!target)
+ return;
+ dist = P_AproxDistance(actor->x - target->x, actor->y - target->y);
+
+ if (target->z + target->height > actor->z
+ && target->z + target->height < actor->z + actor->height
+ && dist < 16*64*FRACUNIT
+ && dist > 1*64*FRACUNIT
+ && P_Random() < 230)
+ { // Charge attack
+ // Don't call the state function right away
+ P_SetMobjStateNF(actor, S_MNTR_ATK4_1);
+ actor->flags |= MF_SKULLFLY;
+ A_FaceTarget(actor);
+ angle = actor->angle>>ANGLETOFINESHIFT;
+ actor->momx = FixedMul(MNTR_CHARGE_SPEED, finecosine[angle]);
+ actor->momy = FixedMul(MNTR_CHARGE_SPEED, finesine[angle]);
+ actor->args[4] = 35/2; // Charge duration
+ }
+ else if (target->z == target->floorz
+ && dist < 9*64*FRACUNIT
+ && P_Random() < 100)
+ { // Floor fire attack
+ P_SetMobjState(actor, S_MNTR_ATK3_1);
+ actor->special2 = 0;
+ }
+ else
+ { // Swing attack
+ A_FaceTarget(actor);
+ // Don't need to call P_SetMobjState because the current state
+ // falls through to the swing attack
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurCharge
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurCharge(mobj_t *actor)
+{
+ mobj_t *puff;
+
+ if (!actor->target)
+ return;
+
+ if (actor->args[4] > 0)
+ {
+ puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PUNCHPUFF);
+ puff->momz = 2*FRACUNIT;
+ actor->args[4]--;
+ }
+ else
+ {
+ actor->flags &= ~MF_SKULLFLY;
+ P_SetMobjState(actor, actor->info->seestate);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk2
+//
+// Swing attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk2(mobj_t *actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+ fixed_t momz;
+
+ if (!actor->target)
+ return;
+
+ S_StartSound(actor, SFX_MAULATOR_HAMMER_SWING);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(3));
+ return;
+ }
+ mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX1);
+ if (mo)
+ {
+ //S_StartSound(mo, sfx_minat2);
+ momz = mo->momz;
+ angle = mo->angle;
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 / 8), momz);
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 / 8), momz);
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle - (ANG45 /16), momz);
+ P_SpawnMissileAngle(actor, MT_MNTRFX1, angle + (ANG45 /16), momz);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MinotaurAtk3
+//
+// Floor fire attack.
+//
+//----------------------------------------------------------------------------
+
+void A_MinotaurAtk3(mobj_t *actor)
+{
+ mobj_t *mo;
+ player_t *player;
+
+ if (!actor->target)
+ {
+ return;
+ }
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(3));
+ if ((player = actor->target->player) != NULL)
+ { // Squish the player
+ player->deltaviewheight = -16*FRACUNIT;
+ }
+ }
+ else
+ {
+ mo = P_SpawnMissile(actor, actor->target, MT_MNTRFX2);
+ if (mo != NULL)
+ {
+ S_StartSound(mo, SFX_MAULATOR_HAMMER_HIT);
+ }
+ }
+ if (P_Random() < 192 && actor->special2 == 0)
+ {
+ P_SetMobjState(actor, S_MNTR_ATK3_4);
+ actor->special2 = 1;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MntrFloorFire
+//
+//----------------------------------------------------------------------------
+
+void A_MntrFloorFire(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ actor->z = actor->floorz;
+ mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 10),
+ actor->y + ((P_Random() - P_Random()) << 10), ONFLOORZ, MT_MNTRFX3);
+ mo->target = actor->target;
+ mo->momx = 1; // Force block checking
+ P_CheckMissileSpawn(mo);
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Scream
+//
+//----------------------------------------------------------------------------
+
+void A_Scream(mobj_t *actor)
+{
+ int sound;
+
+ S_StopSound(actor);
+ if (actor->player)
+ {
+ if (actor->player->morphTics)
+ {
+ S_StartSound(actor, actor->info->deathsound);
+ }
+ else
+ {
+ // Handle the different player death screams
+ if (actor->momz <= -39*FRACUNIT)
+ { // Falling splat
+ sound = SFX_PLAYER_FALLING_SPLAT;
+ }
+ else if (actor->health > -50)
+ { // Normal death sound
+ switch (actor->player->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PLAYER_FIGHTER_NORMAL_DEATH;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PLAYER_CLERIC_NORMAL_DEATH;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PLAYER_MAGE_NORMAL_DEATH;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ }
+ else if (actor->health > -100)
+ { // Crazy death sound
+ switch (actor->player->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PLAYER_FIGHTER_CRAZY_DEATH;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PLAYER_CLERIC_CRAZY_DEATH;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PLAYER_MAGE_CRAZY_DEATH;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ }
+ else
+ { // Extreme death sound
+ switch (actor->player->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PLAYER_FIGHTER_EXTREME1_DEATH;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PLAYER_CLERIC_EXTREME1_DEATH;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PLAYER_MAGE_EXTREME1_DEATH;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ sound += P_Random() % 3; // Three different extreme deaths
+ }
+ S_StartSound(actor, sound);
+ }
+ }
+ else
+ {
+ S_StartSound(actor, actor->info->deathsound);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_DropItem
+//
+//---------------------------------------------------------------------------
+
+/*
+void P_DropItem(mobj_t *source, mobjtype_t type, int special, int chance)
+{
+ mobj_t *mo;
+
+ if (P_Random() > chance)
+ {
+ return;
+ }
+ mo = P_SpawnMobj(source->x, source->y, source->z + (source->height>>1), type);
+ mo->momx = (P_Random() - P_Random()) << 8;
+ mo->momy = (P_Random() - P_Random()) << 8;
+ mo->momz = FRACUNIT*5 + (P_Random() << 10);
+ mo->flags2 |= MF2_DROPPED;
+ mo->health = special;
+}
+*/
+
+//----------------------------------------------------------------------------
+//
+// PROC A_NoBlocking
+//
+//----------------------------------------------------------------------------
+
+void A_NoBlocking(mobj_t *actor)
+{
+ actor->flags &= ~MF_SOLID;
+
+// Check for monsters dropping things
+/* switch (actor->type)
+ {
+ // Add the monster dropped items here
+ case MT_MUMMYLEADERGHOST:
+ P_DropItem(actor, MT_AMGWNDWIMPY, 3, 84);
+ break;
+ default:
+ break;
+ }
+*/
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_Explode
+//
+// Handles a bunch of exploding things.
+//
+//----------------------------------------------------------------------------
+
+void A_Explode(mobj_t *actor)
+{
+ int damage;
+ int distance;
+ boolean damageSelf;
+
+ damage = 128;
+ distance = 128;
+ damageSelf = true;
+ switch (actor->type)
+ {
+ case MT_FIREBOMB: // Time Bombs
+ actor->z += 32*FRACUNIT;
+ actor->flags &= ~MF_SHADOW;
+ break;
+ case MT_MNTRFX2: // Minotaur floor fire
+ damage = 24;
+ break;
+ case MT_BISHOP: // Bishop radius death
+ damage = 25 + (P_Random() & 15);
+ break;
+ case MT_HAMMER_MISSILE: // Fighter Hammer
+ damage = 128;
+ damageSelf = false;
+ break;
+ case MT_FSWORD_MISSILE: // Fighter Runesword
+ damage = 64;
+ damageSelf = false;
+ break;
+ case MT_CIRCLEFLAME: // Cleric Flame secondary flames
+ damage = 20;
+ damageSelf = false;
+ break;
+ case MT_SORCBALL1: // Sorcerer balls
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ distance = 255;
+ damage = 255;
+ actor->args[0] = 1; // don't play bounce
+ break;
+ case MT_SORCFX1: // Sorcerer spell 1
+ damage = 30;
+ break;
+ case MT_SORCFX4: // Sorcerer spell 4
+ damage = 20;
+ break;
+ case MT_TREEDESTRUCTIBLE:
+ damage = 10;
+ break;
+ case MT_DRAGON_FX2:
+ damage = 80;
+ damageSelf = false;
+ break;
+ case MT_MSTAFF_FX:
+ damage = 64;
+ distance = 192;
+ damageSelf = false;
+ break;
+ case MT_MSTAFF_FX2:
+ damage = 80;
+ distance = 192;
+ damageSelf = false;
+ break;
+ case MT_POISONCLOUD:
+ damage = 4;
+ distance = 40;
+ break;
+ case MT_ZXMAS_TREE:
+ case MT_ZSHRUB2:
+ damage = 30;
+ distance = 64;
+ break;
+ default:
+ break;
+ }
+
+ P_RadiusAttack(actor, actor->target, damage, distance, damageSelf);
+ if (actor->z <= actor->floorz + (distance<<FRACBITS)
+ && actor->type != MT_POISONCLOUD)
+ {
+ P_HitFloor(actor);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_Massacre
+//
+// Kills all monsters.
+//
+//----------------------------------------------------------------------------
+
+int P_Massacre(void)
+{
+ int count;
+ mobj_t *mo;
+ thinker_t *think;
+
+ count = 0;
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mo = (mobj_t *)think;
+ if ((mo->flags & MF_COUNTKILL) && (mo->health > 0))
+ {
+ mo->flags2 &= ~(MF2_NONSHOOTABLE+MF2_INVULNERABLE);
+ mo->flags |= MF_SHOOTABLE;
+ P_DamageMobj(mo, NULL, NULL, 10000);
+ count++;
+ }
+ }
+ return count;
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SkullPop
+//
+//----------------------------------------------------------------------------
+
+void A_SkullPop(mobj_t *actor)
+{
+ mobj_t *mo;
+ player_t *player;
+
+ if (!actor->player)
+ {
+ return;
+ }
+ actor->flags &= ~MF_SOLID;
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 48*FRACUNIT, MT_BLOODYSKULL);
+ //mo->target = actor;
+ mo->momx = (P_Random() - P_Random()) << 9;
+ mo->momy = (P_Random() - P_Random()) << 9;
+ mo->momz = FRACUNIT*2 + (P_Random() << 6);
+ // Attach player mobj to bloody skull
+ player = actor->player;
+ actor->player = NULL;
+ actor->special1 = player->playerclass;
+ mo->player = player;
+ mo->health = actor->health;
+ mo->angle = actor->angle;
+ player->mo = mo;
+ player->lookdir = 0;
+ player->damagecount = 32;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckSkullFloor
+//
+//----------------------------------------------------------------------------
+
+void A_CheckSkullFloor(mobj_t *actor)
+{
+ if (actor->z <= actor->floorz)
+ {
+ P_SetMobjState(actor, S_BLOODYSKULLX1);
+ S_StartSound(actor, SFX_DRIP);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckSkullDone
+//
+//----------------------------------------------------------------------------
+
+void A_CheckSkullDone(mobj_t *actor)
+{
+ if (actor->special2 == 666)
+ {
+ P_SetMobjState(actor, S_BLOODYSKULLX2);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_CheckBurnGone
+//
+//----------------------------------------------------------------------------
+
+void A_CheckBurnGone(mobj_t *actor)
+{
+ if (actor->special2 == 666)
+ {
+ P_SetMobjState(actor, S_PLAY_FDTH20);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FreeTargMobj
+//
+//----------------------------------------------------------------------------
+
+void A_FreeTargMobj(mobj_t *mo)
+{
+ mo->momx = mo->momy = mo->momz = 0;
+ mo->z = mo->ceilingz + 4*FRACUNIT;
+ mo->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_SOLID|MF_COUNTKILL);
+ mo->flags |= MF_CORPSE|MF_DROPOFF|MF_NOGRAVITY;
+ mo->flags2 &= ~(MF2_PASSMOBJ|MF2_LOGRAV);
+ mo->flags2 |= MF2_DONTDRAW;
+ mo->player = NULL;
+ mo->health = -1000; // Don't resurrect
+}
+
+
+//----------------------------------------------------------------------------
+//
+// CorpseQueue Routines
+//
+//----------------------------------------------------------------------------
+
+// Corpse queue for monsters - this should be saved out
+#define CORPSEQUEUESIZE 64
+static mobj_t *corpseQueue[CORPSEQUEUESIZE];
+static int corpseQueueSlot;
+
+// throw another corpse on the queue
+void A_QueueCorpse(mobj_t *actor)
+{
+ mobj_t *corpse;
+
+ if (corpseQueueSlot >= CORPSEQUEUESIZE)
+ { // Too many corpses - remove an old one
+ corpse = corpseQueue[corpseQueueSlot % CORPSEQUEUESIZE];
+ if (corpse)
+ P_RemoveMobj(corpse);
+ }
+ corpseQueue[corpseQueueSlot % CORPSEQUEUESIZE] = actor;
+ corpseQueueSlot++;
+}
+
+// Remove a mobj from the queue (for resurrection)
+void A_DeQueueCorpse(mobj_t *actor)
+{
+ int slot;
+
+ for (slot = 0; slot < CORPSEQUEUESIZE; slot++)
+ {
+ if (corpseQueue[slot] == actor)
+ {
+ corpseQueue[slot] = NULL;
+ break;
+ }
+ }
+}
+
+void P_InitCreatureCorpseQueue(boolean corpseScan)
+{
+ thinker_t *think;
+ mobj_t *mo;
+
+ // Initialize queue
+ corpseQueueSlot = 0;
+ memset(corpseQueue, 0, sizeof(mobj_t *)*CORPSEQUEUESIZE);
+
+ if (!corpseScan)
+ return;
+
+ // Search mobj list for corpses and place them in this queue
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ continue;
+ mo = (mobj_t *)think;
+ if (!(mo->flags & MF_CORPSE))
+ continue; // Must be a corpse
+ if (mo->flags & MF_ICECORPSE)
+ continue; // Not ice corpses
+ // Only corpses that call A_QueueCorpse from death routine
+ switch (mo->type)
+ {
+ case MT_CENTAUR:
+ case MT_CENTAURLEADER:
+ case MT_DEMON:
+ case MT_DEMON2:
+ case MT_WRAITH:
+ case MT_WRAITHB:
+ case MT_BISHOP:
+ case MT_ETTIN:
+ case MT_PIG:
+ case MT_CENTAUR_SHIELD:
+ case MT_CENTAUR_SWORD:
+ case MT_DEMONCHUNK1:
+ case MT_DEMONCHUNK2:
+ case MT_DEMONCHUNK3:
+ case MT_DEMONCHUNK4:
+ case MT_DEMONCHUNK5:
+ case MT_DEMON2CHUNK1:
+ case MT_DEMON2CHUNK2:
+ case MT_DEMON2CHUNK3:
+ case MT_DEMON2CHUNK4:
+ case MT_DEMON2CHUNK5:
+ case MT_FIREDEMON_SPLOTCH1:
+ case MT_FIREDEMON_SPLOTCH2:
+ A_QueueCorpse(mo); // Add corpse to queue
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC A_AddPlayerCorpse
+//
+//----------------------------------------------------------------------------
+
+#define BODYQUESIZE 32
+static mobj_t *bodyque[BODYQUESIZE];
+int bodyqueslot;
+
+void A_AddPlayerCorpse(mobj_t *actor)
+{
+ if (bodyqueslot >= BODYQUESIZE)
+ { // Too many player corpses - remove an old one
+ P_RemoveMobj(bodyque[bodyqueslot % BODYQUESIZE]);
+ }
+ bodyque[bodyqueslot % BODYQUESIZE] = actor;
+ bodyqueslot++;
+}
+
+//============================================================================
+//
+// A_SerpentUnHide
+//
+//============================================================================
+
+void A_SerpentUnHide(mobj_t *actor)
+{
+ actor->flags2 &= ~MF2_DONTDRAW;
+ actor->floorclip = 24*FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SerpentHide
+//
+//============================================================================
+
+void A_SerpentHide(mobj_t *actor)
+{
+ actor->flags2 |= MF2_DONTDRAW;
+ actor->floorclip = 0;
+}
+
+//============================================================================
+//
+// A_SerpentChase
+//
+//============================================================================
+
+void A_SerpentChase(mobj_t *actor)
+{
+ int delta;
+ int oldX, oldY, oldFloor;
+
+ if (actor->reactiontime)
+ {
+ actor->reactiontime--;
+ }
+
+ // Modify target threshold
+ if (actor->threshold)
+ {
+ actor->threshold--;
+ }
+
+ if (gameskill == sk_nightmare)
+ { // Monsters move faster in nightmare mode
+ actor->tics -= actor->tics/2;
+ if (actor->tics < 3)
+ {
+ actor->tics = 3;
+ }
+ }
+
+//
+// turn towards movement direction if not there yet
+//
+ if (actor->movedir < 8)
+ {
+ actor->angle &= (7 << 29);
+ delta = actor->angle - (actor->movedir << 29);
+ if (delta > 0)
+ {
+ actor->angle -= ANG90/2;
+ }
+ else if (delta < 0)
+ {
+ actor->angle += ANG90/2;
+ }
+ }
+
+ if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+ { // look for a new target
+ if (P_LookForPlayers(actor, true))
+ { // got a new target
+ return;
+ }
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+
+//
+// don't attack twice in a row
+//
+ if (actor->flags & MF_JUSTATTACKED)
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ if (gameskill != sk_nightmare)
+ P_NewChaseDir (actor);
+ return;
+ }
+
+//
+// check for melee attack
+//
+ if (actor->info->meleestate && P_CheckMeleeRange (actor))
+ {
+ if (actor->info->attacksound)
+ {
+ S_StartSound (actor, actor->info->attacksound);
+ }
+ P_SetMobjState (actor, actor->info->meleestate);
+ return;
+ }
+
+//
+// possibly choose another target
+//
+ if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target))
+ {
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+ }
+
+//
+// chase towards player
+//
+ oldX = actor->x;
+ oldY = actor->y;
+ oldFloor = actor->subsector->sector->floorpic;
+ if (--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewChaseDir (actor);
+ }
+ if (actor->subsector->sector->floorpic != oldFloor)
+ {
+ P_TryMove(actor, oldX, oldY);
+ P_NewChaseDir (actor);
+ }
+
+//
+// make active sound
+//
+ if (actor->info->activesound && P_Random() < 3)
+ {
+ S_StartSound(actor, actor->info->activesound);
+ }
+}
+
+//============================================================================
+//
+// A_SerpentRaiseHump
+//
+// Raises the hump above the surface by raising the floorclip level
+//============================================================================
+
+void A_SerpentRaiseHump(mobj_t *actor)
+{
+ actor->floorclip -= 4*FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SerpentLowerHump
+//
+//============================================================================
+
+void A_SerpentLowerHump(mobj_t *actor)
+{
+ actor->floorclip += 4*FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SerpentHumpDecide
+//
+// Decided whether to hump up, or if the mobj is a serpent leader,
+// to missile attack
+//============================================================================
+
+void A_SerpentHumpDecide(mobj_t *actor)
+{
+ if (actor->type == MT_SERPENTLEADER)
+ {
+ if (P_Random() > 30)
+ {
+ return;
+ }
+ else if (P_Random() < 40)
+ { // Missile attack
+ P_SetMobjState(actor, S_SERPENT_SURFACE1);
+ return;
+ }
+ }
+ else if (P_Random() > 3)
+ {
+ return;
+ }
+ if (!P_CheckMeleeRange(actor))
+ { // The hump shouldn't occur when within melee range
+ if (actor->type == MT_SERPENTLEADER && P_Random() < 128)
+ {
+ P_SetMobjState(actor, S_SERPENT_SURFACE1);
+ }
+ else
+ {
+ P_SetMobjState(actor, S_SERPENT_HUMP1);
+ S_StartSound(actor, SFX_SERPENT_ACTIVE);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_SerpentBirthScream
+//
+//============================================================================
+
+void A_SerpentBirthScream(mobj_t *actor)
+{
+ S_StartSound(actor, SFX_SERPENT_BIRTH);
+}
+
+//============================================================================
+//
+// A_SerpentDiveSound
+//
+//============================================================================
+
+void A_SerpentDiveSound(mobj_t *actor)
+{
+ S_StartSound(actor, SFX_SERPENT_ACTIVE);
+}
+
+//============================================================================
+//
+// A_SerpentWalk
+//
+// Similar to A_Chase, only has a hardcoded entering of meleestate
+//============================================================================
+
+void A_SerpentWalk(mobj_t *actor)
+{
+ int delta;
+
+ if (actor->reactiontime)
+ {
+ actor->reactiontime--;
+ }
+
+ // Modify target threshold
+ if (actor->threshold)
+ {
+ actor->threshold--;
+ }
+
+ if (gameskill == sk_nightmare)
+ { // Monsters move faster in nightmare mode
+ actor->tics -= actor->tics/2;
+ if (actor->tics < 3)
+ {
+ actor->tics = 3;
+ }
+ }
+
+//
+// turn towards movement direction if not there yet
+//
+ if (actor->movedir < 8)
+ {
+ actor->angle &= (7 << 29);
+ delta = actor->angle-(actor->movedir << 29);
+ if (delta > 0)
+ {
+ actor->angle -= ANG90/2;
+ }
+ else if (delta < 0)
+ {
+ actor->angle += ANG90/2;
+ }
+ }
+
+ if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+ { // look for a new target
+ if (P_LookForPlayers(actor, true))
+ { // got a new target
+ return;
+ }
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+
+//
+// don't attack twice in a row
+//
+ if (actor->flags & MF_JUSTATTACKED)
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ if (gameskill != sk_nightmare)
+ P_NewChaseDir (actor);
+ return;
+ }
+
+//
+// check for melee attack
+//
+ if (actor->info->meleestate && P_CheckMeleeRange (actor))
+ {
+ if (actor->info->attacksound)
+ {
+ S_StartSound (actor, actor->info->attacksound);
+ }
+ P_SetMobjState(actor, S_SERPENT_ATK1);
+ return;
+ }
+//
+// possibly choose another target
+//
+ if (netgame && !actor->threshold && !P_CheckSight(actor, actor->target))
+ {
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+ }
+
+//
+// chase towards player
+//
+ if (--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewChaseDir (actor);
+ }
+}
+
+//============================================================================
+//
+// A_SerpentCheckForAttack
+//
+//============================================================================
+
+void A_SerpentCheckForAttack(mobj_t *actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ if (actor->type == MT_SERPENTLEADER)
+ {
+ if (!P_CheckMeleeRange(actor))
+ {
+ P_SetMobjState(actor, S_SERPENT_ATK1);
+ return;
+ }
+ }
+ if (P_CheckMeleeRange2(actor))
+ {
+ P_SetMobjState(actor, S_SERPENT_WALK1);
+ }
+ else if (P_CheckMeleeRange(actor))
+ {
+ if (P_Random() < 32)
+ {
+ P_SetMobjState(actor, S_SERPENT_WALK1);
+ }
+ else
+ {
+ P_SetMobjState(actor, S_SERPENT_ATK1);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_SerpentChooseAttack
+//
+//============================================================================
+
+void A_SerpentChooseAttack(mobj_t *actor)
+{
+ if (!actor->target || P_CheckMeleeRange(actor))
+ {
+ return;
+ }
+ if (actor->type == MT_SERPENTLEADER)
+ {
+ P_SetMobjState(actor, S_SERPENT_MISSILE1);
+ }
+}
+
+//============================================================================
+//
+// A_SerpentMeleeAttack
+//
+//============================================================================
+
+void A_SerpentMeleeAttack(mobj_t *actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(5));
+ S_StartSound(actor, SFX_SERPENT_MELEEHIT);
+ }
+ if (P_Random() < 96)
+ {
+ A_SerpentCheckForAttack(actor);
+ }
+}
+
+//============================================================================
+//
+// A_SerpentMissileAttack
+//
+//============================================================================
+
+void A_SerpentMissileAttack(mobj_t *actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ P_SpawnMissile(actor, actor->target, MT_SERPENTFX);
+}
+
+//============================================================================
+//
+// A_SerpentHeadPop
+//
+//============================================================================
+
+void A_SerpentHeadPop(mobj_t *actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_SERPENT_HEAD);
+}
+
+//============================================================================
+//
+// A_SerpentSpawnGibs
+//
+//============================================================================
+
+void A_SerpentSpawnGibs(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+ actor->y + ((P_Random() - 128) << 12),
+ actor->floorz + FRACUNIT, MT_SERPENT_GIB1);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 6;
+ mo->momy = (P_Random() - 128) << 6;
+ mo->floorclip = 6*FRACUNIT;
+ }
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+ actor->y + ((P_Random() - 128) << 12),
+ actor->floorz + FRACUNIT, MT_SERPENT_GIB2);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 6;
+ mo->momy = (P_Random() - 128) << 6;
+ mo->floorclip = 6*FRACUNIT;
+ }
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+ actor->y + ((P_Random() - 128) << 12),
+ actor->floorz + FRACUNIT, MT_SERPENT_GIB3);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 6;
+ mo->momy = (P_Random() - 128) << 6;
+ mo->floorclip = 6*FRACUNIT;
+ }
+}
+
+//============================================================================
+//
+// A_FloatGib
+//
+//============================================================================
+
+void A_FloatGib(mobj_t *actor)
+{
+ actor->floorclip -= FRACUNIT;
+}
+
+//============================================================================
+//
+// A_SinkGib
+//
+//============================================================================
+
+void A_SinkGib(mobj_t *actor)
+{
+ actor->floorclip += FRACUNIT;
+}
+
+//============================================================================
+//
+// A_DelayGib
+//
+//============================================================================
+
+void A_DelayGib(mobj_t *actor)
+{
+ actor->tics -= P_Random()>>2;
+}
+
+//============================================================================
+//
+// A_SerpentHeadCheck
+//
+//============================================================================
+
+void A_SerpentHeadCheck(mobj_t *actor)
+{
+ if (actor->z <= actor->floorz)
+ {
+ if (P_GetThingFloorType(actor) >= FLOOR_LIQUID)
+ {
+ P_HitFloor(actor);
+ P_SetMobjState(actor, S_NULL);
+ }
+ else
+ {
+ P_SetMobjState(actor, S_SERPENT_HEAD_X1);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_CentaurAttack
+//
+//============================================================================
+
+void A_CentaurAttack(mobj_t *actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, (P_Random() % 7) + 3);
+ }
+}
+
+//============================================================================
+//
+// A_CentaurAttack2
+//
+//============================================================================
+
+void A_CentaurAttack2(mobj_t *actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ P_SpawnMissile(actor, actor->target, MT_CENTAUR_FX);
+ S_StartSound(actor, SFX_CENTAURLEADER_ATTACK);
+}
+
+//============================================================================
+//
+// A_CentaurDropStuff
+//
+// Spawn shield/sword sprites when the centaur pulps
+//============================================================================
+
+void A_CentaurDropStuff(mobj_t *actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_CENTAUR_SHIELD);
+ if (mo)
+ {
+ angle = actor->angle + ANG90;
+ mo->momz = FRACUNIT*8 + (P_Random() << 10);
+ mo->momx = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+ finesine[angle >> ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_CENTAUR_SWORD);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = FRACUNIT*8 + (P_Random() << 10);
+ mo->momx = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+ finecosine[angle >> ANGLETOFINESHIFT]);
+ mo->momy = FixedMul(((P_Random() - 128) << 11) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+}
+
+//============================================================================
+//
+// A_CentaurDefend
+//
+//============================================================================
+
+void A_CentaurDefend(mobj_t *actor)
+{
+ A_FaceTarget(actor);
+ if (P_CheckMeleeRange(actor) && P_Random() < 32)
+ {
+ A_UnSetInvulnerable(actor);
+ P_SetMobjState(actor, actor->info->meleestate);
+ }
+}
+
+//============================================================================
+//
+// A_BishopAttack
+//
+//============================================================================
+
+void A_BishopAttack(mobj_t *actor)
+{
+ if (!actor->target)
+ {
+ return;
+ }
+ S_StartSound(actor, actor->info->attacksound);
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(4));
+ return;
+ }
+ actor->special1 = (P_Random() & 3) + 5;
+}
+
+//============================================================================
+//
+// A_BishopAttack2
+//
+// Spawns one of a string of bishop missiles
+//============================================================================
+
+void A_BishopAttack2(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ if (!actor->target || !actor->special1)
+ {
+ actor->special1 = 0;
+ P_SetMobjState(actor, S_BISHOP_WALK1);
+ return;
+ }
+ mo = P_SpawnMissile(actor, actor->target, MT_BISH_FX);
+ if (mo)
+ {
+ mo->special1 = (intptr_t)actor->target;
+ mo->special2 = 16; // High word == x/y, Low word == z
+ }
+ actor->special1--;
+}
+
+//============================================================================
+//
+// A_BishopMissileWeave
+//
+//============================================================================
+
+void A_BishopMissileWeave(mobj_t *actor)
+{
+ fixed_t newX, newY;
+ int weaveXY, weaveZ;
+ int angle;
+
+ weaveXY = actor->special2 >> 16;
+ weaveZ = actor->special2 & 0xFFFF;
+ angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<1);
+ newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<1);
+ weaveXY = (weaveXY + 2) & 63;
+ newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<1);
+ newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<1);
+ P_TryMove(actor, newX, newY);
+ actor->z -= FloatBobOffsets[weaveZ];
+ weaveZ = (weaveZ + 2) & 63;
+ actor->z += FloatBobOffsets[weaveZ];
+ actor->special2 = weaveZ + (weaveXY<<16);
+}
+
+//============================================================================
+//
+// A_BishopMissileSeek
+//
+//============================================================================
+
+void A_BishopMissileSeek(mobj_t *actor)
+{
+ P_SeekerMissile(actor, ANGLE_1*2, ANGLE_1*3);
+}
+
+//============================================================================
+//
+// A_BishopDecide
+//
+//============================================================================
+
+void A_BishopDecide(mobj_t *actor)
+{
+ if (P_Random() < 220)
+ {
+ return;
+ }
+ else
+ {
+ P_SetMobjState(actor, S_BISHOP_BLUR1);
+ }
+}
+
+//============================================================================
+//
+// A_BishopDoBlur
+//
+//============================================================================
+
+void A_BishopDoBlur(mobj_t *actor)
+{
+ actor->special1 = (P_Random() & 3) + 3; // Random number of blurs
+ if (P_Random() < 120)
+ {
+ P_ThrustMobj(actor, actor->angle + ANG90, 11*FRACUNIT);
+ }
+ else if (P_Random() > 125)
+ {
+ P_ThrustMobj(actor, actor->angle - ANG90, 11*FRACUNIT);
+ }
+ else
+ { // Thrust forward
+ P_ThrustMobj(actor, actor->angle, 11*FRACUNIT);
+ }
+ S_StartSound(actor, SFX_BISHOP_BLUR);
+}
+
+//============================================================================
+//
+// A_BishopSpawnBlur
+//
+//============================================================================
+
+void A_BishopSpawnBlur(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ if (!--actor->special1)
+ {
+ actor->momx = 0;
+ actor->momy = 0;
+ if (P_Random() > 96)
+ {
+ P_SetMobjState(actor, S_BISHOP_WALK1);
+ }
+ else
+ {
+ P_SetMobjState(actor, S_BISHOP_ATK1);
+ }
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BISHOPBLUR);
+ if (mo)
+ {
+ mo->angle = actor->angle;
+ }
+}
+
+//============================================================================
+//
+// A_BishopChase
+//
+//============================================================================
+
+void A_BishopChase(mobj_t *actor)
+{
+ actor->z -= FloatBobOffsets[actor->special2]>>1;
+ actor->special2 = (actor->special2 + 4) & 63;
+ actor->z += FloatBobOffsets[actor->special2]>>1;
+}
+
+//============================================================================
+//
+// A_BishopPuff
+//
+//============================================================================
+
+void A_BishopPuff(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 40*FRACUNIT, MT_BISHOP_PUFF);
+ if (mo)
+ {
+ mo->momz = FRACUNIT/2;
+ }
+}
+
+//============================================================================
+//
+// A_BishopPainBlur
+//
+//============================================================================
+
+void A_BishopPainBlur(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ if (P_Random() < 64)
+ {
+ P_SetMobjState(actor, S_BISHOP_BLUR1);
+ return;
+ }
+ mo = P_SpawnMobj(actor->x + ((P_Random() - P_Random()) << 12),
+ actor->y + ((P_Random() - P_Random()) << 12),
+ actor->z + ((P_Random() - P_Random()) << 11),
+ MT_BISHOPPAINBLUR);
+ if (mo)
+ {
+ mo->angle = actor->angle;
+ }
+}
+
+//============================================================================
+//
+// DragonSeek
+//
+//============================================================================
+
+static void DragonSeek(mobj_t *actor, angle_t thresh, angle_t turnMax)
+{
+ int dir;
+ int dist;
+ angle_t delta;
+ angle_t angle;
+ mobj_t *target;
+ int search;
+ int i;
+ int bestArg;
+ angle_t bestAngle;
+ angle_t angleToSpot, angleToTarget;
+ mobj_t *mo;
+
+ target = (mobj_t *)actor->special1;
+ if (target == NULL)
+ {
+ return;
+ }
+ dir = P_FaceMobj(actor, target, &delta);
+ if (delta > thresh)
+ {
+ delta >>= 1;
+ if (delta > turnMax)
+ {
+ delta = turnMax;
+ }
+ }
+ if (dir)
+ { // Turn clockwise
+ actor->angle += delta;
+ }
+ else
+ { // Turn counter clockwise
+ actor->angle -= delta;
+ }
+ angle = actor->angle >> ANGLETOFINESHIFT;
+ actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+ actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+ if (actor->z + actor->height < target->z ||
+ target->z + target->height < actor->z)
+ {
+ dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+ dist = dist / actor->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ actor->momz = (target->z - actor->z) / dist;
+ }
+ else
+ {
+ dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+ dist = dist / actor->info->speed;
+ }
+ if (target->flags & MF_SHOOTABLE && P_Random() < 64)
+ { // attack the destination mobj if it's attackable
+ mobj_t *oldTarget;
+
+ if (abs(actor->angle - R_PointToAngle2(actor->x, actor->y, target->x, target->y)) < ANGLE_45/2)
+ {
+ oldTarget = actor->target;
+ actor->target = target;
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(10));
+ S_StartSound(actor, SFX_DRAGON_ATTACK);
+ }
+ else if (P_Random() < 128 && P_CheckMissileRange(actor))
+ {
+ P_SpawnMissile(actor, target, MT_DRAGON_FX);
+ S_StartSound(actor, SFX_DRAGON_ATTACK);
+ }
+ actor->target = oldTarget;
+ }
+ }
+ if (dist < 4)
+ { // Hit the target thing
+ if (actor->target && P_Random() < 200)
+ {
+ bestArg = -1;
+ bestAngle = ANGLE_MAX;
+ angleToTarget = R_PointToAngle2(actor->x, actor->y,
+ actor->target->x, actor->target->y);
+ for (i = 0; i < 5; i++)
+ {
+ if (!target->args[i])
+ {
+ continue;
+ }
+ search = -1;
+ mo = P_FindMobjFromTID(target->args[i], &search);
+ angleToSpot = R_PointToAngle2(actor->x, actor->y, mo->x, mo->y);
+ if (abs(angleToSpot - angleToTarget) < bestAngle)
+ {
+ bestAngle = abs(angleToSpot - angleToTarget);
+ bestArg = i;
+ }
+ }
+ if (bestArg != -1)
+ {
+ search = -1;
+ actor->special1 = (intptr_t)P_FindMobjFromTID(target->args[bestArg], &search);
+ }
+ }
+ else
+ {
+ do
+ {
+ i = (P_Random() >> 2) % 5;
+ } while (!target->args[i]);
+ search = -1;
+ actor->special1 = (intptr_t)P_FindMobjFromTID(target->args[i], &search);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_DragonInitFlight
+//
+//============================================================================
+
+void A_DragonInitFlight(mobj_t *actor)
+{
+ int search;
+
+ search = -1;
+ do
+ { // find the first tid identical to the dragon's tid
+ actor->special1 = (intptr_t)P_FindMobjFromTID(actor->tid, &search);
+ if (search == -1)
+ {
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+ } while (actor->special1 == (intptr_t)actor);
+ P_RemoveMobjFromTIDList(actor);
+}
+
+//============================================================================
+//
+// A_DragonFlight
+//
+//============================================================================
+
+void A_DragonFlight(mobj_t *actor)
+{
+ angle_t angle;
+
+ DragonSeek(actor, 4*ANGLE_1, 8*ANGLE_1);
+ if (actor->target)
+ {
+ if (!(actor->target->flags & MF_SHOOTABLE))
+ { // target died
+ actor->target = NULL;
+ return;
+ }
+ angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y);
+ if (abs(actor->angle - angle) < ANGLE_45/2 && P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(8));
+ S_StartSound(actor, SFX_DRAGON_ATTACK);
+ }
+ else if (abs(actor->angle - angle) <= ANGLE_1*20)
+ {
+ P_SetMobjState(actor, actor->info->missilestate);
+ S_StartSound(actor, SFX_DRAGON_ATTACK);
+ }
+ }
+ else
+ {
+ P_LookForPlayers(actor, true);
+ }
+}
+
+//============================================================================
+//
+// A_DragonFlap
+//
+//============================================================================
+
+void A_DragonFlap(mobj_t *actor)
+{
+ A_DragonFlight(actor);
+ if (P_Random() < 240)
+ {
+ S_StartSound(actor, SFX_DRAGON_WINGFLAP);
+ }
+ else
+ {
+ S_StartSound(actor, actor->info->activesound);
+ }
+}
+
+//============================================================================
+//
+// A_DragonAttack
+//
+//============================================================================
+
+void A_DragonAttack(mobj_t *actor)
+{
+ P_SpawnMissile(actor, actor->target, MT_DRAGON_FX);
+}
+
+//============================================================================
+//
+// A_DragonFX2
+//
+//============================================================================
+
+void A_DragonFX2(mobj_t *actor)
+{
+ mobj_t *mo;
+ int i;
+ int delay;
+
+ delay = 16 + (P_Random() >> 3);
+ for (i = 1 + (P_Random() & 3); i; i--)
+ {
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) << 14),
+ actor->y + ((P_Random() - 128) << 14),
+ actor->z + ((P_Random() - 128) << 12),
+ MT_DRAGON_FX2);
+ if (mo)
+ {
+ mo->tics = delay + (P_Random() & 3) * i * 2;
+ mo->target = actor->target;
+ }
+ }
+}
+
+//============================================================================
+//
+// A_DragonPain
+//
+//============================================================================
+
+void A_DragonPain(mobj_t *actor)
+{
+ A_Pain(actor);
+ if (!actor->special1)
+ { // no destination spot yet
+ P_SetMobjState(actor, S_DRAGON_INIT);
+ }
+}
+
+//============================================================================
+//
+// A_DragonCheckCrash
+//
+//============================================================================
+
+void A_DragonCheckCrash(mobj_t *actor)
+{
+ if (actor->z <= actor->floorz)
+ {
+ P_SetMobjState(actor, S_DRAGON_CRASH1);
+ }
+}
+
+//============================================================================
+// Demon AI
+//============================================================================
+
+//
+// A_DemonAttack1 (melee)
+//
+void A_DemonAttack1(mobj_t *actor)
+{
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(2));
+ }
+}
+
+//
+// A_DemonAttack2 (missile)
+//
+void A_DemonAttack2(mobj_t *actor)
+{
+ mobj_t *mo;
+ int fireBall;
+
+ if (actor->type == MT_DEMON)
+ {
+ fireBall = MT_DEMONFX1;
+ }
+ else
+ {
+ fireBall = MT_DEMON2FX1;
+ }
+ mo = P_SpawnMissile(actor, actor->target, fireBall);
+ if (mo)
+ {
+ mo->z += 30*FRACUNIT;
+ S_StartSound(actor, SFX_DEMON_MISSILE_FIRE);
+ }
+}
+
+//
+// A_DemonDeath
+//
+void A_DemonDeath(mobj_t *actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMONCHUNK1);
+ if (mo)
+ {
+ angle = actor->angle + ANG90;
+ mo->momz = 8*FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMONCHUNK2);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8*FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMONCHUNK3);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8*FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMONCHUNK4);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8*FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMONCHUNK5);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8*FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+}
+
+//===========================================================================
+//
+// A_Demon2Death
+//
+//===========================================================================
+
+void A_Demon2Death(mobj_t *actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMON2CHUNK1);
+ if (mo)
+ {
+ angle = actor->angle + ANG90;
+ mo->momz = 8*FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMON2CHUNK2);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8*FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMON2CHUNK3);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8*FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMON2CHUNK4);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8*FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 45*FRACUNIT, MT_DEMON2CHUNK5);
+ if (mo)
+ {
+ angle = actor->angle - ANG90;
+ mo->momz = 8*FRACUNIT;
+ mo->momx = FixedMul((P_Random() << 10) + FRACUNIT,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 10) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ }
+}
+
+
+//
+// A_SinkMobj
+// Sink a mobj incrementally into the floor
+//
+
+boolean A_SinkMobj(mobj_t *actor)
+{
+ if (actor->floorclip < actor->info->height)
+ {
+ switch (actor->type)
+ {
+ case MT_THRUSTFLOOR_DOWN:
+ case MT_THRUSTFLOOR_UP:
+ actor->floorclip += 6*FRACUNIT;
+ break;
+ default:
+ actor->floorclip += FRACUNIT;
+ break;
+ }
+ return false;
+ }
+ return true;
+}
+
+//
+// A_RaiseMobj
+// Raise a mobj incrementally from the floor to
+//
+
+boolean A_RaiseMobj(mobj_t *actor)
+{
+ int done = true;
+
+ // Raise a mobj from the ground
+ if (actor->floorclip > 0)
+ {
+ switch (actor->type)
+ {
+ case MT_WRAITHB:
+ actor->floorclip -= 2*FRACUNIT;
+ break;
+ case MT_THRUSTFLOOR_DOWN:
+ case MT_THRUSTFLOOR_UP:
+ actor->floorclip -= actor->special2*FRACUNIT;
+ break;
+ default:
+ actor->floorclip -= 2*FRACUNIT;
+ break;
+ }
+ if (actor->floorclip <= 0)
+ {
+ actor->floorclip = 0;
+ done = true;
+ }
+ else
+ {
+ done = false;
+ }
+ }
+ return done; // Reached target height
+}
+
+
+//============================================================================
+// Wraith Variables
+//
+// special1 Internal index into floatbob
+// special2
+//============================================================================
+
+//
+// A_WraithInit
+//
+
+void A_WraithInit(mobj_t *actor)
+{
+ actor->z += 48<<FRACBITS;
+ actor->special1 = 0; // index into floatbob
+}
+
+void A_WraithRaiseInit(mobj_t *actor)
+{
+ actor->flags2 &= ~MF2_DONTDRAW;
+ actor->flags2 &= ~MF2_NONSHOOTABLE;
+ actor->flags |= MF_SHOOTABLE|MF_SOLID;
+ actor->floorclip = actor->info->height;
+}
+
+void A_WraithRaise(mobj_t *actor)
+{
+ if (A_RaiseMobj(actor))
+ {
+ // Reached it's target height
+ P_SetMobjState(actor,S_WRAITH_CHASE1);
+ }
+
+ P_SpawnDirt(actor, actor->radius);
+}
+
+void A_WraithMelee(mobj_t *actor)
+{
+ int amount;
+
+ // Steal health from target and give to player
+ if (P_CheckMeleeRange(actor) && (P_Random() < 220))
+ {
+ amount = HITDICE(2);
+ P_DamageMobj(actor->target, actor, actor, amount);
+ actor->health += amount;
+ }
+}
+
+void A_WraithMissile(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMissile(actor, actor->target, MT_WRAITHFX1);
+ if (mo)
+ {
+ S_StartSound(actor, SFX_WRAITH_MISSILE_FIRE);
+ }
+}
+
+//
+// A_WraithFX2 - spawns sparkle tail of missile
+//
+void A_WraithFX2(mobj_t *actor)
+{
+ mobj_t *mo;
+ angle_t angle;
+ int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX2);
+ if (mo)
+ {
+ if (P_Random() < 128)
+ {
+ angle = actor->angle + (P_Random() << 22);
+ }
+ else
+ {
+ angle = actor->angle - (P_Random() << 22);
+ }
+ mo->momz = 0;
+ mo->momx = FixedMul((P_Random() << 7) + FRACUNIT,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = FixedMul((P_Random() << 7) + FRACUNIT,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->target = actor;
+ mo->floorclip = 10*FRACUNIT;
+ }
+ }
+}
+
+// Spawn an FX3 around the actor during attacks
+void A_WraithFX3(mobj_t *actor)
+{
+ mobj_t *mo;
+ int numdropped = P_Random() % 15;
+ int i;
+
+ for (i = 0; i < numdropped; i++)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX3);
+ if (mo)
+ {
+ mo->x += (P_Random() - 128) << 11;
+ mo->y += (P_Random() - 128) << 11;
+ mo->z += (P_Random() << 10);
+ mo->target = actor;
+ }
+ }
+}
+
+// Spawn an FX4 during movement
+void A_WraithFX4(mobj_t *actor)
+{
+ mobj_t *mo;
+ int chance = P_Random();
+ int spawn4, spawn5;
+
+ if (chance < 10)
+ {
+ spawn4 = true;
+ spawn5 = false;
+ }
+ else if (chance < 20)
+ {
+ spawn4 = false;
+ spawn5 = true;
+ }
+ else if (chance < 25)
+ {
+ spawn4 = true;
+ spawn5 = true;
+ }
+ else
+ {
+ spawn4 = false;
+ spawn5 = false;
+ }
+
+ if (spawn4)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX4);
+ if (mo)
+ {
+ mo->x += (P_Random() - 128) << 12;
+ mo->y += (P_Random() - 128) << 12;
+ mo->z += (P_Random() << 10);
+ mo->target = actor;
+ }
+ }
+ if (spawn5)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_WRAITHFX5);
+ if (mo)
+ {
+ mo->x += (P_Random() - 128) << 11;
+ mo->y += (P_Random() - 128) << 11;
+ mo->z += (P_Random() << 10);
+ mo->target = actor;
+ }
+ }
+}
+
+void A_WraithLook(mobj_t *actor)
+{
+// A_WraithFX4(actor); // too expensive
+ A_Look(actor);
+}
+
+void A_WraithChase(mobj_t *actor)
+{
+ int weaveindex = actor->special1;
+ actor->z += FloatBobOffsets[weaveindex];
+ actor->special1 = (weaveindex + 2) & 63;
+// if (actor->floorclip > 0)
+// {
+// P_SetMobjState(actor, S_WRAITH_RAISE2);
+// return;
+// }
+ A_Chase(actor);
+ A_WraithFX4(actor);
+}
+
+
+//============================================================================
+// Ettin AI
+//============================================================================
+
+void A_EttinAttack(mobj_t *actor)
+{
+ if (P_CheckMeleeRange(actor))
+ {
+ P_DamageMobj(actor->target, actor, actor, HITDICE(2));
+ }
+}
+
+void A_DropMace(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height>>1), MT_ETTIN_MACE);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 11;
+ mo->momy = (P_Random() - 128) << 11;
+ mo->momz = FRACUNIT*10 + (P_Random() << 10);
+ mo->target = actor;
+ }
+}
+
+
+//============================================================================
+// Fire Demon AI
+//
+// special1 index into floatbob
+// special2 whether strafing or not
+//============================================================================
+
+void A_FiredSpawnRock(mobj_t *actor)
+{
+ mobj_t *mo;
+ int x, y, z;
+ int rtype = 0;
+
+ switch (P_Random() % 5)
+ {
+ case 0:
+ rtype = MT_FIREDEMON_FX1;
+ break;
+ case 1:
+ rtype = MT_FIREDEMON_FX2;
+ break;
+ case 2:
+ rtype = MT_FIREDEMON_FX3;
+ break;
+ case 3:
+ rtype = MT_FIREDEMON_FX4;
+ break;
+ case 4:
+ rtype = MT_FIREDEMON_FX5;
+ break;
+ }
+
+ x = actor->x + ((P_Random() - 128) << 12);
+ y = actor->y + ((P_Random() - 128) << 12);
+ z = actor->z + ((P_Random()) << 11);
+ mo = P_SpawnMobj(x, y, z, rtype);
+ if (mo)
+ {
+ mo->target = actor;
+ mo->momx = (P_Random() - 128) << 10;
+ mo->momy = (P_Random() - 128) << 10;
+ mo->momz = (P_Random() << 10);
+ mo->special1 = 2; // Number bounces
+ }
+
+ // Initialize fire demon
+ actor->special2 = 0;
+ actor->flags &= ~MF_JUSTATTACKED;
+}
+
+void A_FiredRocks(mobj_t *actor)
+{
+ A_FiredSpawnRock(actor);
+ A_FiredSpawnRock(actor);
+ A_FiredSpawnRock(actor);
+ A_FiredSpawnRock(actor);
+ A_FiredSpawnRock(actor);
+}
+
+void A_FiredAttack(mobj_t *actor)
+{
+ mobj_t *mo;
+ mo = P_SpawnMissile(actor, actor->target, MT_FIREDEMON_FX6);
+ if (mo)
+ S_StartSound(actor, SFX_FIRED_ATTACK);
+}
+
+void A_SmBounce(mobj_t *actor)
+{
+ // give some more momentum (x,y,&z)
+ actor->z = actor->floorz + FRACUNIT;
+ actor->momz = (2*FRACUNIT) + (P_Random()<<10);
+ actor->momx = (P_Random() % 3) << FRACBITS;
+ actor->momy = (P_Random() % 3) << FRACBITS;
+}
+
+
+#define FIREDEMON_ATTACK_RANGE (64 * 8 * FRACUNIT)
+
+void A_FiredChase(mobj_t *actor)
+{
+ int weaveindex = actor->special1;
+ mobj_t *target = actor->target;
+ angle_t ang;
+ fixed_t dist;
+
+ if (actor->reactiontime)
+ actor->reactiontime--;
+ if (actor->threshold)
+ actor->threshold--;
+
+ // Float up and down
+ actor->z += FloatBobOffsets[weaveindex];
+ actor->special1 = (weaveindex + 2) & 63;
+
+ // Insure it stays above certain height
+ if (actor->z < actor->floorz + (64*FRACUNIT))
+ {
+ actor->z += 2*FRACUNIT;
+ }
+
+ if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+ { // Invalid target
+ P_LookForPlayers(actor, true);
+ return;
+ }
+
+ // Strafe
+ if (actor->special2 > 0)
+ {
+ actor->special2--;
+ }
+ else
+ {
+ actor->special2 = 0;
+ actor->momx = actor->momy = 0;
+ dist = P_AproxDistance(actor->x - target->x, actor->y - target->y);
+ if (dist < FIREDEMON_ATTACK_RANGE)
+ {
+ if (P_Random() < 30)
+ {
+ ang = R_PointToAngle2(actor->x, actor->y, target->x, target->y);
+ if (P_Random() < 128)
+ ang += ANGLE_90;
+ else
+ ang -= ANGLE_90;
+ ang >>= ANGLETOFINESHIFT;
+ actor->momx = FixedMul(8*FRACUNIT, finecosine[ang]);
+ actor->momy = FixedMul(8*FRACUNIT, finesine[ang]);
+ actor->special2 = 3; // strafe time
+ }
+ }
+ }
+
+ FaceMovementDirection(actor);
+
+ // Normal movement
+ if (!actor->special2)
+ {
+ if (--actor->movecount < 0 || !P_Move (actor))
+ {
+ P_NewChaseDir (actor);
+ }
+ }
+
+ // Do missile attack
+ if (!(actor->flags & MF_JUSTATTACKED))
+ {
+ if (P_CheckMissileRange(actor) && (P_Random() < 20))
+ {
+ P_SetMobjState (actor, actor->info->missilestate);
+ actor->flags |= MF_JUSTATTACKED;
+ return;
+ }
+ }
+ else
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ }
+
+ // make active sound
+ if (actor->info->activesound && P_Random() < 3)
+ {
+ S_StartSound(actor, actor->info->activesound);
+ }
+}
+
+void A_FiredSplotch(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FIREDEMON_SPLOTCH1);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 11;
+ mo->momy = (P_Random() - 128) << 11;
+ mo->momz = FRACUNIT*3 + (P_Random() << 10);
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FIREDEMON_SPLOTCH2);
+ if (mo)
+ {
+ mo->momx = (P_Random() - 128) << 11;
+ mo->momy = (P_Random() - 128) << 11;
+ mo->momz = FRACUNIT*3 + (P_Random() << 10);
+ }
+}
+
+
+//============================================================================
+//
+// A_IceGuyLook
+//
+//============================================================================
+
+void A_IceGuyLook(mobj_t *actor)
+{
+ fixed_t dist;
+ fixed_t an;
+
+ A_Look(actor);
+ if (P_Random() < 64)
+ {
+ dist = ((P_Random() - 128) * actor->radius) >> 7;
+ an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+
+ P_SpawnMobj(actor->x + FixedMul(dist, finecosine[an]),
+ actor->y + FixedMul(dist, finesine[an]),
+ actor->z + 60*FRACUNIT,
+ MT_ICEGUY_WISP1 + (P_Random() & 1));
+ }
+}
+
+//============================================================================
+//
+// A_IceGuyChase
+//
+//============================================================================
+
+void A_IceGuyChase(mobj_t *actor)
+{
+ fixed_t dist;
+ fixed_t an;
+ mobj_t *mo;
+
+ A_Chase(actor);
+ if (P_Random() < 128)
+ {
+ dist = ((P_Random() - 128) * actor->radius) >> 7;
+ an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+
+ mo = P_SpawnMobj(actor->x + FixedMul(dist, finecosine[an]),
+ actor->y + FixedMul(dist, finesine[an]),
+ actor->z + 60*FRACUNIT,
+ MT_ICEGUY_WISP1 + (P_Random() & 1));
+ if (mo)
+ {
+ mo->momx = actor->momx;
+ mo->momy = actor->momy;
+ mo->momz = actor->momz;
+ mo->target = actor;
+ }
+ }
+}
+
+//============================================================================
+//
+// A_IceGuyAttack
+//
+//============================================================================
+
+void A_IceGuyAttack(mobj_t *actor)
+{
+ fixed_t an;
+
+ if (!actor->target)
+ {
+ return;
+ }
+ an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ P_SpawnMissileXYZ(actor->x + FixedMul(actor->radius >> 1, finecosine[an]),
+ actor->y + FixedMul(actor->radius >> 1, finesine[an]),
+ actor->z + 40*FRACUNIT, actor, actor->target, MT_ICEGUY_FX);
+ an = (actor->angle - ANG90) >> ANGLETOFINESHIFT;
+ P_SpawnMissileXYZ(actor->x + FixedMul(actor->radius >> 1, finecosine[an]),
+ actor->y + FixedMul(actor->radius >> 1, finesine[an]),
+ actor->z + 40*FRACUNIT, actor, actor->target, MT_ICEGUY_FX);
+ S_StartSound(actor, actor->info->attacksound);
+}
+
+//============================================================================
+//
+// A_IceGuyMissilePuff
+//
+//============================================================================
+
+void A_IceGuyMissilePuff(mobj_t *actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z + 2*FRACUNIT, MT_ICEFX_PUFF);
+}
+
+//============================================================================
+//
+// A_IceGuyDie
+//
+//============================================================================
+
+void A_FreezeDeathChunks(mobj_t *actor);
+
+void A_IceGuyDie(mobj_t *actor)
+{
+ actor->momx = 0;
+ actor->momy = 0;
+ actor->momz = 0;
+ actor->height <<= 2;
+ A_FreezeDeathChunks(actor);
+}
+
+//============================================================================
+//
+// A_IceGuyMissileExplode
+//
+//============================================================================
+
+void A_IceGuyMissileExplode(mobj_t *actor)
+{
+ mobj_t *mo;
+ unsigned int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ mo = P_SpawnMissileAngle(actor, MT_ICEGUY_FX2, i*ANG45, -0.3*FRACUNIT);
+ if (mo)
+ {
+ mo->target = actor->target;
+ }
+ }
+}
+
+
+//============================================================================
+//
+// Sorcerer stuff
+//
+// Sorcerer Variables
+// special1 Angle of ball 1 (all others relative to that)
+// special2 which ball to stop at in stop mode (MT_???)
+// args[0] Denfense time
+// args[1] Number of full rotations since stopping mode
+// args[2] Target orbit speed for acceleration/deceleration
+// args[3] Movement mode (see SORC_ macros)
+// args[4] Current ball orbit speed
+// Sorcerer Ball Variables
+// special1 Previous angle of ball (for woosh)
+// special2 Countdown of rapid fire (FX4)
+// args[0] If set, don't play the bounce sound when bouncing
+//============================================================================
+
+#define SORCBALL_INITIAL_SPEED 7
+#define SORCBALL_TERMINAL_SPEED 25
+#define SORCBALL_SPEED_ROTATIONS 5
+
+#define SORC_DEFENSE_TIME 255
+#define SORC_DEFENSE_HEIGHT 45
+
+#define BOUNCE_TIME_UNIT (35/2)
+
+#define SORCFX4_RAPIDFIRE_TIME (6*3) /* 3 seconds */
+#define SORCFX4_SPREAD_ANGLE 20
+
+#define SORC_DECELERATE 0
+#define SORC_ACCELERATE 1
+#define SORC_STOPPING 2
+#define SORC_FIRESPELL 3
+#define SORC_STOPPED 4
+#define SORC_NORMAL 5
+#define SORC_FIRING_SPELL 6
+
+#define BALL1_ANGLEOFFSET 0
+#define BALL2_ANGLEOFFSET (ANGLE_MAX / 3)
+#define BALL3_ANGLEOFFSET ((ANGLE_MAX / 3) * 2)
+
+void A_SorcBallOrbit(mobj_t *actor);
+void A_SorcSpinBalls(mobj_t *actor);
+void A_SpeedBalls(mobj_t *actor);
+void A_SlowBalls(mobj_t *actor);
+void A_StopBalls(mobj_t *actor);
+void A_AccelBalls(mobj_t *actor);
+void A_DecelBalls(mobj_t *actor);
+void A_SorcBossAttack(mobj_t *actor);
+void A_SpawnFizzle(mobj_t *actor);
+void A_CastSorcererSpell(mobj_t *actor);
+void A_SorcUpdateBallAngle(mobj_t *actor);
+void A_BounceCheck(mobj_t *actor);
+void A_SorcFX1Seek(mobj_t *actor);
+void A_SorcOffense1(mobj_t *actor);
+void A_SorcOffense2(mobj_t *actor);
+
+// Spawn spinning balls above head - actor is sorcerer
+void A_SorcSpinBalls(mobj_t *actor)
+{
+ mobj_t *mo;
+ fixed_t z;
+
+ A_SlowBalls(actor);
+ actor->args[0] = 0; // Currently no defense
+ actor->args[3] = SORC_NORMAL;
+ actor->args[4] = SORCBALL_INITIAL_SPEED; // Initial orbit speed
+ actor->special1 = ANGLE_1;
+ z = actor->z - actor->floorclip + actor->info->height;
+
+ mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL1);
+ if (mo)
+ {
+ mo->target = actor;
+ mo->special2 = SORCFX4_RAPIDFIRE_TIME;
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL2);
+ if (mo)
+ mo->target = actor;
+ mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCBALL3);
+ if (mo)
+ mo->target = actor;
+}
+
+//
+// A_SorcBallOrbit() ==========================================
+//
+void A_SorcBallOrbit(mobj_t *actor)
+{
+ int x,y;
+ angle_t angle = 0, baseangle;
+ int mode = actor->target->args[3];
+ mobj_t *parent = (mobj_t *)actor->target;
+ int dist = parent->radius - (actor->radius<<1);
+ angle_t prevangle = actor->special1;
+
+ if (actor->target->health <= 0)
+ P_SetMobjState(actor, actor->info->painstate);
+
+ baseangle = (angle_t)parent->special1;
+ switch (actor->type)
+ {
+ case MT_SORCBALL1:
+ angle = baseangle + BALL1_ANGLEOFFSET;
+ break;
+ case MT_SORCBALL2:
+ angle = baseangle + BALL2_ANGLEOFFSET;
+ break;
+ case MT_SORCBALL3:
+ angle = baseangle + BALL3_ANGLEOFFSET;
+ break;
+ default:
+ I_Error("corrupted sorcerer");
+ break;
+ }
+ actor->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+
+ switch (mode)
+ {
+ case SORC_NORMAL: // Balls rotating normally
+ A_SorcUpdateBallAngle(actor);
+ break;
+ case SORC_DECELERATE: // Balls decelerating
+ A_DecelBalls(actor);
+ A_SorcUpdateBallAngle(actor);
+ break;
+ case SORC_ACCELERATE: // Balls accelerating
+ A_AccelBalls(actor);
+ A_SorcUpdateBallAngle(actor);
+ break;
+ case SORC_STOPPING: // Balls stopping
+ if ((parent->special2 == actor->type) &&
+ (parent->args[1] > SORCBALL_SPEED_ROTATIONS) &&
+ (abs(angle - (parent->angle>>ANGLETOFINESHIFT)) < (30<<5)))
+ {
+ // Can stop now
+ actor->target->args[3] = SORC_FIRESPELL;
+ actor->target->args[4] = 0;
+ // Set angle so ball angle == sorcerer angle
+ switch (actor->type)
+ {
+ case MT_SORCBALL1:
+ parent->special1 = (int)(parent->angle - BALL1_ANGLEOFFSET);
+ break;
+ case MT_SORCBALL2:
+ parent->special1 = (int)(parent->angle - BALL2_ANGLEOFFSET);
+ break;
+ case MT_SORCBALL3:
+ parent->special1 = (int)(parent->angle - BALL3_ANGLEOFFSET);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ A_SorcUpdateBallAngle(actor);
+ }
+ break;
+ case SORC_FIRESPELL: // Casting spell
+ if (parent->special2 == actor->type)
+ {
+ // Put sorcerer into special throw spell anim
+ if (parent->health > 0)
+ P_SetMobjStateNF(parent, S_SORC_ATTACK1);
+
+ if (actor->type == MT_SORCBALL1 && P_Random()<200)
+ {
+ S_StartSound(NULL, SFX_SORCERER_SPELLCAST);
+ actor->special2 = SORCFX4_RAPIDFIRE_TIME;
+ actor->args[4] = 128;
+ parent->args[3] = SORC_FIRING_SPELL;
+ }
+ else
+ {
+ A_CastSorcererSpell(actor);
+ parent->args[3] = SORC_STOPPED;
+ }
+ }
+ break;
+ case SORC_FIRING_SPELL:
+ if (parent->special2 == actor->type)
+ {
+ if (actor->special2-- <= 0)
+ {
+ // Done rapid firing
+ parent->args[3] = SORC_STOPPED;
+ // Back to orbit balls
+ if (parent->health > 0)
+ P_SetMobjStateNF(parent, S_SORC_ATTACK4);
+ }
+ else
+ {
+ // Do rapid fire spell
+ A_SorcOffense2(actor);
+ }
+ }
+ break;
+ case SORC_STOPPED: // Balls stopped
+ default:
+ break;
+ }
+
+ if ((angle < prevangle) && (parent->args[4] == SORCBALL_TERMINAL_SPEED))
+ {
+ parent->args[1]++; // Bump rotation counter
+ // Completed full rotation - make woosh sound
+ S_StartSound(actor, SFX_SORCERER_BALLWOOSH);
+ }
+ actor->special1 = angle; // Set previous angle
+ x = parent->x + FixedMul(dist, finecosine[angle]);
+ y = parent->y + FixedMul(dist, finesine[angle]);
+ actor->x = x;
+ actor->y = y;
+ actor->z = parent->z - parent->floorclip + parent->info->height;
+}
+
+//
+// Set balls to speed mode - actor is sorcerer
+//
+void A_SpeedBalls(mobj_t *actor)
+{
+ actor->args[3] = SORC_ACCELERATE; // speed mode
+ actor->args[2] = SORCBALL_TERMINAL_SPEED; // target speed
+}
+
+//
+// Set balls to slow mode - actor is sorcerer
+//
+void A_SlowBalls(mobj_t *actor)
+{
+ actor->args[3] = SORC_DECELERATE; // slow mode
+ actor->args[2] = SORCBALL_INITIAL_SPEED; // target speed
+}
+
+//
+// Instant stop when rotation gets to ball in special2
+// actor is sorcerer
+//
+void A_StopBalls(mobj_t *actor)
+{
+ int chance = P_Random();
+ actor->args[3] = SORC_STOPPING; // stopping mode
+ actor->args[1] = 0; // Reset rotation counter
+
+ if ((actor->args[0] <= 0) && (chance < 200))
+ {
+ actor->special2 = MT_SORCBALL2; // Blue
+ }
+ else if ((actor->health < (actor->info->spawnhealth >> 1)) &&
+ (chance < 200))
+ {
+ actor->special2 = MT_SORCBALL3; // Green
+ }
+ else
+ {
+ actor->special2 = MT_SORCBALL1; // Yellow
+ }
+}
+
+//
+// Increase ball orbit speed - actor is ball
+//
+void A_AccelBalls(mobj_t *actor)
+{
+ mobj_t *sorc = actor->target;
+
+ if (sorc->args[4] < sorc->args[2])
+ {
+ sorc->args[4]++;
+ }
+ else
+ {
+ sorc->args[3] = SORC_NORMAL;
+ if (sorc->args[4] >= SORCBALL_TERMINAL_SPEED)
+ {
+ // Reached terminal velocity - stop balls
+ A_StopBalls(sorc);
+ }
+ }
+}
+
+// Decrease ball orbit speed - actor is ball
+void A_DecelBalls(mobj_t *actor)
+{
+ mobj_t *sorc = actor->target;
+
+ if (sorc->args[4] > sorc->args[2])
+ {
+ sorc->args[4]--;
+ }
+ else
+ {
+ sorc->args[3] = SORC_NORMAL;
+ }
+}
+
+// Update angle if first ball - actor is ball
+void A_SorcUpdateBallAngle(mobj_t *actor)
+{
+ if (actor->type == MT_SORCBALL1)
+ {
+ actor->target->special1 += ANGLE_1*actor->target->args[4];
+ }
+}
+
+// actor is ball
+void A_CastSorcererSpell(mobj_t *actor)
+{
+ mobj_t *mo;
+ int spell = actor->type;
+ angle_t ang1, ang2;
+ fixed_t z;
+ mobj_t *parent = actor->target;
+
+ S_StartSound(NULL, SFX_SORCERER_SPELLCAST);
+
+ // Put sorcerer into throw spell animation
+ if (parent->health > 0)
+ P_SetMobjStateNF(parent, S_SORC_ATTACK4);
+
+ switch (spell)
+ {
+ case MT_SORCBALL1: // Offensive
+ A_SorcOffense1(actor);
+ break;
+ case MT_SORCBALL2: // Defensive
+ z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT;
+ mo = P_SpawnMobj(actor->x, actor->y, z, MT_SORCFX2);
+ parent->flags2 |= MF2_REFLECTIVE|MF2_INVULNERABLE;
+ parent->args[0] = SORC_DEFENSE_TIME;
+ if (mo)
+ mo->target = parent;
+ break;
+ case MT_SORCBALL3: // Reinforcements
+ ang1 = actor->angle - ANGLE_45;
+ ang2 = actor->angle + ANGLE_45;
+ if (actor->health < (actor->info->spawnhealth/3))
+ { // Spawn 2 at a time
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang1, 4*FRACUNIT);
+ if (mo)
+ mo->target = parent;
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang2, 4*FRACUNIT);
+ if (mo)
+ mo->target = parent;
+ }
+ else
+ {
+ if (P_Random() < 128)
+ ang1 = ang2;
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX3, ang1, 4*FRACUNIT);
+ if (mo)
+ mo->target = parent;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+void A_SpawnReinforcements(mobj_t *actor)
+{
+ mobj_t *parent = actor->target;
+ mobj_t *mo;
+ angle_t ang;
+
+ ang = ANGLE_1 * P_Random();
+ mo = P_SpawnMissileAngle(actor, MT_SORCFX3, ang, 5*FRACUNIT);
+ if (mo)
+ mo->target = parent;
+}
+*/
+
+// actor is ball
+void A_SorcOffense1(mobj_t *actor)
+{
+ mobj_t *mo;
+ angle_t ang1,ang2;
+ mobj_t *parent = (mobj_t *)actor->target;
+
+ ang1 = actor->angle + ANGLE_1*70;
+ ang2 = actor->angle - ANGLE_1*70;
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX1, ang1, 0);
+ if (mo)
+ {
+ mo->target = parent;
+ mo->special1 = (intptr_t)parent->target;
+ mo->args[4] = BOUNCE_TIME_UNIT;
+ mo->args[3] = 15; // Bounce time in seconds
+ }
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX1, ang2, 0);
+ if (mo)
+ {
+ mo->target = parent;
+ mo->special1 = (intptr_t)parent->target;
+ mo->args[4] = BOUNCE_TIME_UNIT;
+ mo->args[3] = 15; // Bounce time in seconds
+ }
+}
+
+// Actor is ball
+void A_SorcOffense2(mobj_t *actor)
+{
+ angle_t ang1;
+ mobj_t *mo;
+ int delta, idx;
+ mobj_t *parent = actor->target;
+ mobj_t *dest = parent->target;
+ int dist;
+
+ idx = actor->args[4] << 5;
+ actor->args[4] += 15;
+ delta = (finesine[idx])*SORCFX4_SPREAD_ANGLE;
+ delta = (delta>>FRACBITS)*ANGLE_1;
+ ang1 = actor->angle + delta;
+ mo = P_SpawnMissileAngle(parent, MT_SORCFX4, ang1, 0);
+ if (mo)
+ {
+ mo->special2 = 35*5/2; // 5 seconds
+ dist = P_AproxDistance(dest->x - mo->x, dest->y - mo->y);
+ dist = dist / mo->info->speed;
+ if (dist < 1)
+ dist = 1;
+ mo->momz = (dest->z-mo->z) / dist;
+ }
+}
+
+// Resume ball spinning
+void A_SorcBossAttack(mobj_t *actor)
+{
+ actor->args[3] = SORC_ACCELERATE;
+ actor->args[2] = SORCBALL_INITIAL_SPEED;
+}
+
+// spell cast magic fizzle
+void A_SpawnFizzle(mobj_t *actor)
+{
+ fixed_t x, y, z;
+ fixed_t dist = 5*FRACUNIT;
+ angle_t angle = actor->angle >> ANGLETOFINESHIFT;
+ fixed_t speed = actor->info->speed;
+ angle_t rangle;
+ mobj_t *mo;
+ int ix;
+
+ x = actor->x + FixedMul(dist, finecosine[angle]);
+ y = actor->y + FixedMul(dist, finesine[angle]);
+ z = actor->z - actor->floorclip + (actor->height>>1);
+ for (ix = 0; ix < 5; ix++)
+ {
+ mo = P_SpawnMobj(x, y, z, MT_SORCSPARK1);
+ if (mo)
+ {
+ rangle = angle + ((P_Random() % 5) << 1);
+ mo->momx = FixedMul(P_Random() % speed, finecosine[rangle]);
+ mo->momy = FixedMul(P_Random() % speed, finesine[rangle]);
+ mo->momz = FRACUNIT*2;
+ }
+ }
+}
+
+//============================================================================
+// Yellow spell - offense
+//============================================================================
+
+void A_SorcFX1Seek(mobj_t *actor)
+{
+ A_BounceCheck(actor);
+ P_SeekerMissile(actor, ANGLE_1*2, ANGLE_1*6);
+}
+
+//============================================================================
+// Blue spell - defense
+//============================================================================
+//
+// FX2 Variables
+// special1 current angle
+// special2
+// args[0] 0 = CW, 1 = CCW
+// args[1]
+//============================================================================
+
+// Split ball in two
+void A_SorcFX2Split(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX2);
+ if (mo)
+ {
+ mo->target = actor->target;
+ mo->args[0] = 0; // CW
+ mo->special1 = actor->angle; // Set angle
+ P_SetMobjStateNF(mo, S_SORCFX2_ORBIT1);
+ }
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX2);
+ if (mo)
+ {
+ mo->target = actor->target;
+ mo->args[0] = 1; // CCW
+ mo->special1 = actor->angle; // Set angle
+ P_SetMobjStateNF(mo, S_SORCFX2_ORBIT1);
+ }
+ P_SetMobjStateNF(actor, S_NULL);
+}
+
+// Orbit FX2 about sorcerer
+void A_SorcFX2Orbit(mobj_t *actor)
+{
+ angle_t angle;
+ fixed_t x, y, z;
+ mobj_t *parent = actor->target;
+ fixed_t dist = parent->info->radius;
+
+ if ((parent->health <= 0) || // Sorcerer is dead
+ (!parent->args[0])) // Time expired
+ {
+ P_SetMobjStateNF(actor, actor->info->deathstate);
+ parent->args[0] = 0;
+ parent->flags2 &= ~MF2_REFLECTIVE;
+ parent->flags2 &= ~MF2_INVULNERABLE;
+ }
+
+ if (actor->args[0] && (parent->args[0]-- <= 0)) // Time expired
+ {
+ P_SetMobjStateNF(actor, actor->info->deathstate);
+ parent->args[0] = 0;
+ parent->flags2 &= ~MF2_REFLECTIVE;
+ }
+
+ // Move to new position based on angle
+ if (actor->args[0]) // Counter clock-wise
+ {
+ actor->special1 += ANGLE_1*10;
+ angle = ((angle_t)actor->special1) >> ANGLETOFINESHIFT;
+ x = parent->x + FixedMul(dist, finecosine[angle]);
+ y = parent->y + FixedMul(dist, finesine[angle]);
+ z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT;
+ z += FixedMul(15*FRACUNIT, finecosine[angle]);
+ // Spawn trailer
+ P_SpawnMobj(x, y, z, MT_SORCFX2_T1);
+ }
+ else // Clock wise
+ {
+ actor->special1 -= ANGLE_1*10;
+ angle = ((angle_t)actor->special1) >> ANGLETOFINESHIFT;
+ x = parent->x + FixedMul(dist, finecosine[angle]);
+ y = parent->y + FixedMul(dist, finesine[angle]);
+ z = parent->z - parent->floorclip + SORC_DEFENSE_HEIGHT*FRACUNIT;
+ z += FixedMul(20*FRACUNIT, finesine[angle]);
+ // Spawn trailer
+ P_SpawnMobj(x, y, z, MT_SORCFX2_T1);
+ }
+
+ actor->x = x;
+ actor->y = y;
+ actor->z = z;
+}
+
+//============================================================================
+// Green spell - spawn bishops
+//============================================================================
+
+void A_SpawnBishop(mobj_t *actor)
+{
+ mobj_t *mo;
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BISHOP);
+ if (mo)
+ {
+ if (!P_TestMobjLocation(mo))
+ {
+ P_SetMobjState(mo, S_NULL);
+ }
+ }
+ P_SetMobjState(actor, S_NULL);
+}
+
+/*
+void A_SmokePuffEntry(mobj_t *actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKE);
+}
+*/
+
+void A_SmokePuffExit(mobj_t *actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKEEXIT);
+}
+
+void A_SorcererBishopEntry(mobj_t *actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_SORCFX3_EXPLOSION);
+ S_StartSound(actor, actor->info->seesound);
+}
+
+//============================================================================
+// FX4 - rapid fire balls
+//============================================================================
+
+void A_SorcFX4Check(mobj_t *actor)
+{
+ if (actor->special2-- <= 0)
+ {
+ P_SetMobjStateNF(actor, actor->info->deathstate);
+ }
+}
+
+//============================================================================
+// Ball death - spawn stuff
+//============================================================================
+
+void A_SorcBallPop(mobj_t *actor)
+{
+ S_StartSound(NULL, SFX_SORCERER_BALLPOP);
+ actor->flags &= ~MF_NOGRAVITY;
+ actor->flags2 |= MF2_LOGRAV;
+ actor->momx = ((P_Random() % 10) - 5) << FRACBITS;
+ actor->momy = ((P_Random() % 10) - 5) << FRACBITS;
+ actor->momz = (2 + (P_Random() % 3)) << FRACBITS;
+ actor->special2 = 4*FRACUNIT; // Initial bounce factor
+ actor->args[4] = BOUNCE_TIME_UNIT; // Bounce time unit
+ actor->args[3] = 5; // Bounce time in seconds
+}
+
+void A_BounceCheck(mobj_t *actor)
+{
+ if (actor->args[4]-- <= 0)
+ {
+ if (actor->args[3]-- <= 0)
+ {
+ P_SetMobjState(actor, actor->info->deathstate);
+ switch (actor->type)
+ {
+ case MT_SORCBALL1:
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ S_StartSound(NULL, SFX_SORCERER_BIGBALLEXPLODE);
+ break;
+ case MT_SORCFX1:
+ S_StartSound(NULL, SFX_SORCERER_HEADSCREAM);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ actor->args[4] = BOUNCE_TIME_UNIT;
+ }
+ }
+}
+
+
+//============================================================================
+// Class Bosses
+//============================================================================
+#define CLASS_BOSS_STRAFE_RANGE (64 * 10 * FRACUNIT)
+
+void A_FastChase(mobj_t *actor)
+{
+ int delta;
+ fixed_t dist;
+ angle_t ang;
+ mobj_t *target;
+
+ if (actor->reactiontime)
+ {
+ actor->reactiontime--;
+ }
+
+ // Modify target threshold
+ if (actor->threshold)
+ {
+ actor->threshold--;
+ }
+
+ if (gameskill == sk_nightmare)
+ { // Monsters move faster in nightmare mode
+ actor->tics -= actor->tics/2;
+ if (actor->tics < 3)
+ {
+ actor->tics = 3;
+ }
+ }
+
+//
+// turn towards movement direction if not there yet
+//
+ if (actor->movedir < 8)
+ {
+ actor->angle &= (7 << 29);
+ delta = actor->angle - (actor->movedir << 29);
+ if (delta > 0)
+ {
+ actor->angle -= ANG90/2;
+ }
+ else if (delta < 0)
+ {
+ actor->angle += ANG90/2;
+ }
+ }
+
+ if (!actor->target || !(actor->target->flags & MF_SHOOTABLE))
+ { // look for a new target
+ if (P_LookForPlayers(actor, true))
+ { // got a new target
+ return;
+ }
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+
+//
+// don't attack twice in a row
+//
+ if (actor->flags & MF_JUSTATTACKED)
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ if (gameskill != sk_nightmare)
+ P_NewChaseDir (actor);
+ return;
+ }
+
+ // Strafe
+ if (actor->special2 > 0)
+ {
+ actor->special2--;
+ }
+ else
+ {
+ target = actor->target;
+ actor->special2 = 0;
+ actor->momx = actor->momy = 0;
+ dist = P_AproxDistance (actor->x - target->x,
+ actor->y - target->y);
+ if (dist < CLASS_BOSS_STRAFE_RANGE)
+ {
+ if (P_Random() < 100)
+ {
+ ang = R_PointToAngle2(actor->x, actor->y,
+ target->x, target->y);
+ if (P_Random() < 128)
+ ang += ANGLE_90;
+ else
+ ang -= ANGLE_90;
+ ang >>= ANGLETOFINESHIFT;
+ actor->momx = FixedMul(13*FRACUNIT, finecosine[ang]);
+ actor->momy = FixedMul(13*FRACUNIT, finesine[ang]);
+ actor->special2 = 3; // strafe time
+ }
+ }
+ }
+
+//
+// check for missile attack
+//
+ if (actor->info->missilestate)
+ {
+ if (gameskill < sk_nightmare && actor->movecount)
+ goto nomissile;
+ if (!P_CheckMissileRange (actor))
+ goto nomissile;
+ P_SetMobjState (actor, actor->info->missilestate);
+ actor->flags |= MF_JUSTATTACKED;
+ return;
+ }
+
+nomissile:
+//
+// possibly choose another target
+//
+ if (netgame && !actor->threshold && !P_CheckSight (actor, actor->target) )
+ {
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+ }
+
+//
+// chase towards player
+//
+ if (!actor->special2)
+ {
+ if (--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewChaseDir (actor);
+ }
+ }
+}
+
+void A_FighterAttack(mobj_t *actor)
+{
+ extern void A_FSwordAttack2(mobj_t *actor);
+
+ if (!actor->target)
+ return;
+ A_FSwordAttack2(actor);
+}
+
+void A_ClericAttack(mobj_t *actor)
+{
+ extern void A_CHolyAttack3(mobj_t *actor);
+
+ if (!actor->target)
+ return;
+ A_CHolyAttack3(actor);
+}
+
+void A_MageAttack(mobj_t *actor)
+{
+ extern void A_MStaffAttack2(mobj_t *actor);
+
+ if (!actor->target)
+ return;
+ A_MStaffAttack2(actor);
+}
+
+void A_ClassBossHealth(mobj_t *actor)
+{
+ if (netgame && !deathmatch) // co-op only
+ {
+ if (!actor->special1)
+ {
+ actor->health *= 5;
+ actor->special1 = true; // has been initialized
+ }
+ }
+}
+
+
+//===========================================================================
+//
+// A_CheckFloor - Checks if an object hit the floor
+//
+//===========================================================================
+
+void A_CheckFloor(mobj_t *actor)
+{
+ if (actor->z <= actor->floorz)
+ {
+ actor->z = actor->floorz;
+ actor->flags2 &= ~MF2_LOGRAV;
+ P_SetMobjState(actor, actor->info->deathstate);
+ }
+}
+
+//============================================================================
+//
+// A_FreezeDeath
+//
+//============================================================================
+
+void A_FreezeDeath(mobj_t *actor)
+{
+ actor->tics = 75 + P_Random() + P_Random();
+ actor->flags |= MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD;
+ actor->flags2 |= MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ|MF2_SLIDE;
+ actor->height <<= 2;
+ S_StartSound(actor, SFX_FREEZE_DEATH);
+
+ if (actor->player)
+ {
+ actor->player->damagecount = 0;
+ actor->player->poisoncount = 0;
+ actor->player->bonuscount = 0;
+ if (actor->player == &players[consoleplayer])
+ {
+ SB_PaletteFlash(false);
+ }
+ }
+ else if (actor->flags&MF_COUNTKILL && actor->special)
+ { // Initiate monster death actions
+ P_ExecuteLineSpecial(actor->special, actor->args, NULL, 0, actor);
+ }
+}
+
+//============================================================================
+//
+// A_IceSetTics
+//
+//============================================================================
+
+void A_IceSetTics(mobj_t *actor)
+{
+ int floor;
+
+ actor->tics = 70 + (P_Random() & 63);
+ floor = P_GetThingFloorType(actor);
+ if (floor == FLOOR_LAVA)
+ {
+ actor->tics >>= 2;
+ }
+ else if (floor == FLOOR_ICE)
+ {
+ actor->tics <<= 1;
+ }
+}
+
+//============================================================================
+//
+// A_IceCheckHeadDone
+//
+//============================================================================
+
+void A_IceCheckHeadDone(mobj_t *actor)
+{
+ if (actor->special2 == 666)
+ {
+ P_SetMobjState(actor, S_ICECHUNK_HEAD2);
+ }
+}
+
+//============================================================================
+//
+// A_FreezeDeathChunks
+//
+//============================================================================
+
+void A_FreezeDeathChunks(mobj_t *actor)
+{
+ int i;
+ mobj_t *mo;
+
+ if (actor->momx || actor->momy || actor->momz)
+ {
+ actor->tics = 105;
+ return;
+ }
+ S_StartSound(actor, SFX_FREEZE_SHATTER);
+
+ for (i = 12 + (P_Random() & 15); i >= 0; i--)
+ {
+ mo = P_SpawnMobj(actor->x + (((P_Random() - 128) * actor->radius) >> 7),
+ actor->y + (((P_Random() - 128) * actor->radius) >> 7),
+ actor->z + (P_Random() * actor->height / 255), MT_ICECHUNK);
+ P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 3));
+ if (mo)
+ {
+ mo->momz = FixedDiv(mo->z - actor->z, actor->height)<<2;
+ mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7);
+ mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7);
+ A_IceSetTics(mo); // set a random tic wait
+ }
+ }
+ for (i = 12 + (P_Random() & 15); i >= 0; i--)
+ {
+ mo = P_SpawnMobj(actor->x + (((P_Random() - 128) * actor->radius) >> 7),
+ actor->y + (((P_Random() - 128) * actor->radius) >> 7),
+ actor->z + (P_Random() * actor->height / 255), MT_ICECHUNK);
+ P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 3));
+ if (mo)
+ {
+ mo->momz = FixedDiv(mo->z - actor->z, actor->height)<<2;
+ mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7);
+ mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7);
+ A_IceSetTics(mo); // set a random tic wait
+ }
+ }
+ if (actor->player)
+ { // attach the player's view to a chunk of ice
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + VIEWHEIGHT, MT_ICECHUNK);
+ P_SetMobjState(mo, S_ICECHUNK_HEAD);
+ mo->momz = FixedDiv(mo->z - actor->z, actor->height)<<2;
+ mo->momx = (P_Random() - P_Random()) << (FRACBITS - 7);
+ mo->momy = (P_Random() - P_Random()) << (FRACBITS - 7);
+ mo->flags2 |= MF2_ICEDAMAGE; // used to force blue palette
+ mo->flags2 &= ~MF2_FLOORCLIP;
+ mo->player = actor->player;
+ actor->player = NULL;
+ mo->health = actor->health;
+ mo->angle = actor->angle;
+ mo->player->mo = mo;
+ mo->player->lookdir = 0;
+ }
+ P_RemoveMobjFromTIDList(actor);
+ P_SetMobjState(actor, S_FREETARGMOBJ);
+ actor->flags2 |= MF2_DONTDRAW;
+}
+
+//===========================================================================
+// Korax Variables
+// special1 last teleport destination
+// special2 set if "below half" script not yet run
+//
+// Korax Scripts (reserved)
+// 249 Tell scripts that we are below half health
+// 250-254 Control scripts
+// 255 Death script
+//
+// Korax TIDs (reserved)
+// 245 Reserved for Korax himself
+// 248 Initial teleport destination
+// 249 Teleport destination
+// 250-254 For use in respective control scripts
+// 255 For use in death script (spawn spots)
+//===========================================================================
+#define KORAX_SPIRIT_LIFETIME (5 * (35 / 5)) /* 5 seconds */
+#define KORAX_COMMAND_HEIGHT (120 * FRACUNIT)
+#define KORAX_COMMAND_OFFSET (27 * FRACUNIT)
+
+void KoraxFire1(mobj_t *actor, int type);
+void KoraxFire2(mobj_t *actor, int type);
+void KoraxFire3(mobj_t *actor, int type);
+void KoraxFire4(mobj_t *actor, int type);
+void KoraxFire5(mobj_t *actor, int type);
+void KoraxFire6(mobj_t *actor, int type);
+void KSpiritInit(mobj_t *spirit, mobj_t *korax);
+
+#define KORAX_TID (245)
+#define KORAX_FIRST_TELEPORT_TID (248)
+#define KORAX_TELEPORT_TID (249)
+
+void A_KoraxChase(mobj_t *actor)
+{
+ mobj_t *spot;
+ int lastfound;
+ byte args[3] = {0, 0, 0};
+
+ if ((!actor->special2) &&
+ (actor->health <= (actor->info->spawnhealth/2)))
+ {
+ lastfound = 0;
+ spot = P_FindMobjFromTID(KORAX_FIRST_TELEPORT_TID, &lastfound);
+ if (spot)
+ {
+ P_Teleport(actor, spot->x, spot->y, spot->angle, true);
+ }
+
+ P_StartACS(249, 0, args, actor, NULL, 0);
+ actor->special2 = 1; // Don't run again
+
+ return;
+ }
+
+ if (!actor->target)
+ return;
+ if (P_Random() < 30)
+ {
+ P_SetMobjState(actor, actor->info->missilestate);
+ }
+ else if (P_Random() < 30)
+ {
+ S_StartSound(NULL, SFX_KORAX_ACTIVE);
+ }
+
+ // Teleport away
+ if (actor->health < (actor->info->spawnhealth>>1))
+ {
+ if (P_Random() < 10)
+ {
+ lastfound = actor->special1;
+ spot = P_FindMobjFromTID(KORAX_TELEPORT_TID, &lastfound);
+ actor->special1 = lastfound;
+ if (spot)
+ {
+ P_Teleport(actor, spot->x, spot->y, spot->angle, true);
+ }
+ }
+ }
+}
+
+void A_KoraxStep(mobj_t *actor)
+{
+ A_Chase(actor);
+}
+
+void A_KoraxStep2(mobj_t *actor)
+{
+ S_StartSound(NULL, SFX_KORAX_STEP);
+ A_Chase(actor);
+}
+
+void A_KoraxBonePop(mobj_t *actor)
+{
+ mobj_t *mo;
+ byte args[5];
+
+ args[0] = args[1] = args[2] = args[3] = args[4] = 0;
+
+ // Spawn 6 spirits equalangularly
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT1, ANGLE_60*0, 5*FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT2, ANGLE_60*1, 5*FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT3, ANGLE_60*2, 5*FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT4, ANGLE_60*3, 5*FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT5, ANGLE_60*4, 5*FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+ mo = P_SpawnMissileAngle(actor, MT_KORAX_SPIRIT6, ANGLE_60*5, 5*FRACUNIT);
+ if (mo)
+ KSpiritInit(mo, actor);
+
+ P_StartACS(255, 0, args, actor, NULL, 0); // Death script
+}
+
+void KSpiritInit(mobj_t *spirit, mobj_t *korax)
+{
+ int i;
+ mobj_t *tail, *next;
+
+ spirit->health = KORAX_SPIRIT_LIFETIME;
+
+ spirit->special1 = (intptr_t)korax; // Swarm around korax
+ spirit->special2 = 32+(P_Random()&7); // Float bob index
+ spirit->args[0] = 10; // initial turn value
+ spirit->args[1] = 0; // initial look angle
+
+ // Spawn a tail for spirit
+ tail = P_SpawnMobj(spirit->x, spirit->y, spirit->z, MT_HOLY_TAIL);
+ tail->special2 = (intptr_t)spirit; // parent
+ for (i = 1; i < 3; i++)
+ {
+ next = P_SpawnMobj(spirit->x, spirit->y, spirit->z, MT_HOLY_TAIL);
+ P_SetMobjState(next, next->info->spawnstate + 1);
+ tail->special1 = (intptr_t)next;
+ tail = next;
+ }
+ tail->special1 = 0; // last tail bit
+}
+
+void A_KoraxDecide(mobj_t *actor)
+{
+ if (P_Random() < 220)
+ {
+ P_SetMobjState(actor, S_KORAX_MISSILE1);
+ }
+ else
+ {
+ P_SetMobjState(actor, S_KORAX_COMMAND1);
+ }
+}
+
+void A_KoraxMissile(mobj_t *actor)
+{
+ int type = P_Random() % 6;
+ int sound = SFX_NONE;
+
+ S_StartSound(actor, SFX_KORAX_ATTACK);
+
+ switch (type)
+ {
+ case 0:
+ type = MT_WRAITHFX1;
+ sound = SFX_WRAITH_MISSILE_FIRE;
+ break;
+ case 1:
+ type = MT_DEMONFX1;
+ sound = SFX_DEMON_MISSILE_FIRE;
+ break;
+ case 2:
+ type = MT_DEMON2FX1;
+ sound = SFX_DEMON_MISSILE_FIRE;
+ break;
+ case 3:
+ type = MT_FIREDEMON_FX6;
+ sound = SFX_FIRED_ATTACK;
+ break;
+ case 4:
+ type = MT_CENTAUR_FX;
+ sound = SFX_CENTAURLEADER_ATTACK;
+ break;
+ case 5:
+ type = MT_SERPENTFX;
+ sound = SFX_CENTAURLEADER_ATTACK;
+ break;
+ }
+
+ // Fire all 6 missiles at once
+ S_StartSound(NULL, sound);
+ KoraxFire1(actor, type);
+ KoraxFire2(actor, type);
+ KoraxFire3(actor, type);
+ KoraxFire4(actor, type);
+ KoraxFire5(actor, type);
+ KoraxFire6(actor, type);
+}
+
+// Call action code scripts (250-254)
+void A_KoraxCommand(mobj_t *actor)
+{
+ byte args[5];
+ fixed_t x, y, z;
+ angle_t ang;
+ int numcommands;
+
+ S_StartSound(actor, SFX_KORAX_COMMAND);
+
+ // Shoot stream of lightning to ceiling
+ ang = (actor->angle - ANGLE_90) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_COMMAND_OFFSET, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_COMMAND_OFFSET, finesine[ang]);
+ z = actor->z + KORAX_COMMAND_HEIGHT;
+ P_SpawnMobj(x, y, z, MT_KORAX_BOLT);
+
+ args[0] = args[1] = args[2] = args[3] = args[4] = 0;
+
+ if (actor->health <= (actor->info->spawnhealth >> 1))
+ {
+ numcommands = 5;
+ }
+ else
+ {
+ numcommands = 4;
+ }
+
+ switch (P_Random() % numcommands)
+ {
+ case 0:
+ P_StartACS(250, 0, args, actor, NULL, 0);
+ break;
+ case 1:
+ P_StartACS(251, 0, args, actor, NULL, 0);
+ break;
+ case 2:
+ P_StartACS(252, 0, args, actor, NULL, 0);
+ break;
+ case 3:
+ P_StartACS(253, 0, args, actor, NULL, 0);
+ break;
+ case 4:
+ P_StartACS(254, 0, args, actor, NULL, 0);
+ break;
+ }
+}
+
+
+#define KORAX_DELTAANGLE (85 * ANGLE_1)
+#define KORAX_ARM_EXTENSION_SHORT (40 * FRACUNIT)
+#define KORAX_ARM_EXTENSION_LONG (55 * FRACUNIT)
+
+#define KORAX_ARM1_HEIGHT (108* FRACUNIT)
+#define KORAX_ARM2_HEIGHT (82 * FRACUNIT)
+#define KORAX_ARM3_HEIGHT (54 * FRACUNIT)
+#define KORAX_ARM4_HEIGHT (104* FRACUNIT)
+#define KORAX_ARM5_HEIGHT (86 * FRACUNIT)
+#define KORAX_ARM6_HEIGHT (53 * FRACUNIT)
+
+// Arm projectiles
+// arm positions numbered:
+// 1 top left
+// 2 middle left
+// 3 lower left
+// 4 top right
+// 5 middle right
+// 6 lower right
+
+// Arm 1 projectile
+void KoraxFire1(mobj_t *actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_SHORT, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_SHORT, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM1_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 2 projectile
+void KoraxFire2(mobj_t *actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM2_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 3 projectile
+void KoraxFire3(mobj_t *actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle - KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM3_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 4 projectile
+void KoraxFire4(mobj_t *actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_SHORT, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_SHORT, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM4_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 5 projectile
+void KoraxFire5(mobj_t *actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM5_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+// Arm 6 projectile
+void KoraxFire6(mobj_t *actor, int type)
+{
+ angle_t ang;
+ fixed_t x, y, z;
+
+ ang = (actor->angle + KORAX_DELTAANGLE) >> ANGLETOFINESHIFT;
+ x = actor->x + FixedMul(KORAX_ARM_EXTENSION_LONG, finecosine[ang]);
+ y = actor->y + FixedMul(KORAX_ARM_EXTENSION_LONG, finesine[ang]);
+ z = actor->z - actor->floorclip + KORAX_ARM6_HEIGHT;
+ P_SpawnKoraxMissile(x, y, z, actor, actor->target, type);
+}
+
+
+void A_KSpiritWeave(mobj_t *actor)
+{
+ fixed_t newX, newY;
+ int weaveXY, weaveZ;
+ int angle;
+
+ weaveXY = actor->special2 >> 16;
+ weaveZ = actor->special2 & 0xFFFF;
+ angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2);
+ newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2);
+ weaveXY = (weaveXY + (P_Random() % 5)) & 63;
+ newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY] << 2);
+ newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY] << 2);
+ P_TryMove(actor, newX, newY);
+ actor->z -= FloatBobOffsets[weaveZ] << 1;
+ weaveZ = (weaveZ + (P_Random() % 5)) & 63;
+ actor->z += FloatBobOffsets[weaveZ] << 1;
+ actor->special2 = weaveZ + (weaveXY << 16);
+}
+
+void A_KSpiritSeeker(mobj_t *actor, angle_t thresh, angle_t turnMax)
+{
+ int dir;
+ int dist;
+ angle_t delta;
+ angle_t angle;
+ mobj_t *target;
+ fixed_t newZ;
+ fixed_t deltaZ;
+
+ target = (mobj_t *)actor->special1;
+ if (target == NULL)
+ {
+ return;
+ }
+ dir = P_FaceMobj(actor, target, &delta);
+ if (delta > thresh)
+ {
+ delta >>= 1;
+ if (delta > turnMax)
+ {
+ delta = turnMax;
+ }
+ }
+ if (dir)
+ { // Turn clockwise
+ actor->angle += delta;
+ }
+ else
+ { // Turn counter clockwise
+ actor->angle -= delta;
+ }
+ angle = actor->angle >> ANGLETOFINESHIFT;
+ actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+ actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+
+ if (!(leveltime & 15)
+ || actor->z > target->z + (target->info->height)
+ || actor->z + actor->height < target->z)
+ {
+ newZ = target->z + ((P_Random() * target->info->height) >> 8);
+ deltaZ = newZ - actor->z;
+ if (abs(deltaZ) > 15*FRACUNIT)
+ {
+ if (deltaZ > 0)
+ {
+ deltaZ = 15*FRACUNIT;
+ }
+ else
+ {
+ deltaZ = -15*FRACUNIT;
+ }
+ }
+ dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+ dist = dist / actor->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ actor->momz = deltaZ / dist;
+ }
+ return;
+}
+
+void A_KSpiritRoam(mobj_t *actor)
+{
+ if (actor->health-- <= 0)
+ {
+ S_StartSound(actor, SFX_SPIRIT_DIE);
+ P_SetMobjState(actor, S_KSPIRIT_DEATH1);
+ }
+ else
+ {
+ if (actor->special1)
+ {
+ A_KSpiritSeeker(actor, actor->args[0]*ANGLE_1,
+ actor->args[0]*ANGLE_1*2);
+ }
+ A_KSpiritWeave(actor);
+ if (P_Random() < 50)
+ {
+ S_StartSound(NULL, SFX_SPIRIT_ACTIVE);
+ }
+ }
+}
+
+void A_KBolt(mobj_t *actor)
+{
+ // Countdown lifetime
+ if (actor->special1-- <= 0)
+ {
+ P_SetMobjState(actor, S_NULL);
+ }
+}
+
+
+#define KORAX_BOLT_HEIGHT 48*FRACUNIT
+#define KORAX_BOLT_LIFETIME 3
+
+void A_KBoltRaise(mobj_t *actor)
+{
+ mobj_t *mo;
+ fixed_t z;
+
+ // Spawn a child upward
+ z = actor->z + KORAX_BOLT_HEIGHT;
+
+ if ((z + KORAX_BOLT_HEIGHT) < actor->ceilingz)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, z, MT_KORAX_BOLT);
+ if (mo)
+ {
+ mo->special1 = KORAX_BOLT_LIFETIME;
+ }
+ }
+ else
+ {
+ // Maybe cap it off here
+ }
+}
+
--- /dev/null
+++ b/p_floor.c
@@ -1,0 +1,924 @@
+
+//**************************************************************************
+//**
+//** p_floor.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 472 $
+//** $Date: 2009-05-26 15:45:18 +0300 (Tue, 26 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+//==================================================================
+//
+// FLOORS
+//
+//==================================================================
+
+extern fixed_t FloatBobOffsets[64];
+
+
+//==================================================================
+//
+// Move a plane (floor or ceiling) and check for crushing
+//
+//==================================================================
+
+result_e T_MovePlane(sector_t *sector,fixed_t speed, fixed_t dest,
+ int crush, int floorOrCeiling, int direction)
+{
+ boolean flag;
+ fixed_t lastpos;
+
+ switch (floorOrCeiling)
+ {
+ case 0: // FLOOR
+ switch (direction)
+ {
+ case -1: // DOWN
+ if (sector->floorheight - speed < dest)
+ {
+ lastpos = sector->floorheight;
+ sector->floorheight = dest;
+ flag = P_ChangeSector(sector,crush);
+ if (flag == true)
+ {
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector, crush);
+ //return RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else
+ {
+ lastpos = sector->floorheight;
+ sector->floorheight -= speed;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_CRUSHED;
+ }
+ }
+ break;
+
+ case 1: // UP
+ if (sector->floorheight + speed > dest)
+ {
+ lastpos = sector->floorheight;
+ sector->floorheight = dest;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector, crush);
+ //return RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else // COULD GET CRUSHED
+ {
+ lastpos = sector->floorheight;
+ sector->floorheight += speed;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ //if (crush == true)
+ //{
+ // return RES_CRUSHED;
+ //}
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_CRUSHED;
+ }
+ }
+ break;
+ }
+ break; /* END OF THE FLOOR CASE */
+
+ case 1: // CEILING
+ switch (direction)
+ {
+ case -1: // DOWN
+ if (sector->ceilingheight - speed < dest)
+ {
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight = dest;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector, crush);
+ //return RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else // COULD GET CRUSHED
+ {
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight -= speed;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ //if (crush == true)
+ //{
+ // return RES_CRUSHED;
+ //}
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_CRUSHED;
+ }
+ }
+ break;
+
+ case 1: // UP
+ if (sector->ceilingheight + speed > dest)
+ {
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight = dest;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector, crush);
+ //return RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else
+ {
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight += speed;
+ flag = P_ChangeSector(sector, crush);
+ #if 0
+ if (flag == true)
+ {
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_CRUSHED;
+ }
+ #endif
+ }
+ break;
+ }
+ break; /* END OF THE CEILING CASE */
+ }
+
+ return RES_OK;
+}
+
+//==================================================================
+//
+// MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
+//
+//==================================================================
+
+void T_MoveFloor(floormove_t *floor)
+{
+ result_e res;
+
+ if (floor->resetDelayCount)
+ {
+ floor->resetDelayCount--;
+ if (!floor->resetDelayCount)
+ {
+ floor->floordestheight = floor->resetHeight;
+ floor->direction = -floor->direction;
+ floor->resetDelay = 0;
+ floor->delayCount = 0;
+ floor->delayTotal = 0;
+ }
+ }
+ if (floor->delayCount)
+ {
+ floor->delayCount--;
+ if (!floor->delayCount && floor->textureChange)
+ {
+ floor->sector->floorpic += floor->textureChange;
+ }
+ return;
+ }
+
+ res = T_MovePlane(floor->sector,floor->speed,
+ floor->floordestheight, floor->crush, 0, floor->direction);
+
+ if (floor->type == FLEV_RAISEBUILDSTEP)
+ {
+ if ((floor->direction == 1 && floor->sector->floorheight >= floor->stairsDelayHeight) ||
+ (floor->direction == -1 && floor->sector->floorheight <= floor->stairsDelayHeight))
+ {
+ floor->delayCount = floor->delayTotal;
+ floor->stairsDelayHeight += floor->stairsDelayHeightDelta;
+ }
+ }
+ if (res == RES_PASTDEST)
+ {
+ SN_StopSequence((mobj_t *)(void *)&floor->sector->soundorg);
+ if (floor->delayTotal)
+ {
+ floor->delayTotal = 0;
+ }
+ if (floor->resetDelay)
+ {
+ // floor->resetDelayCount = floor->resetDelay;
+ // floor->resetDelay = 0;
+ return;
+ }
+ floor->sector->specialdata = NULL;
+ /*
+ if (floor->direction == 1)
+ {
+ switch (floor->type)
+ {
+ case donutRaise:
+ floor->sector->special = floor->newspecial;
+ floor->sector->floorpic = floor->texture;
+ default:
+ break;
+ }
+ }
+ else if (floor->direction == -1)
+ {
+ switch (floor->type)
+ {
+ case lowerAndChange:
+ floor->sector->special = floor->newspecial;
+ floor->sector->floorpic = floor->texture;
+ default:
+ break;
+ }
+ }
+ */
+ if (floor->textureChange)
+ {
+ floor->sector->floorpic -= floor->textureChange;
+ }
+ P_TagFinished(floor->sector->tag);
+ P_RemoveThinker(&floor->thinker);
+ }
+}
+
+//==================================================================
+//
+// HANDLE FLOOR TYPES
+//
+//==================================================================
+
+int EV_DoFloor(line_t *line, byte *args, floor_e floortype)
+{
+ int secnum;
+ int rtn;
+ sector_t *sec;
+ floormove_t *floor = NULL;
+
+ secnum = -1;
+ rtn = 0;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = §ors[secnum];
+
+ // ALREADY MOVING? IF SO, KEEP GOING...
+ if (sec->specialdata)
+ continue;
+
+ //
+ // new floor thinker
+ //
+ rtn = 1;
+ floor = (floormove_t *) Z_Malloc (sizeof(*floor), PU_LEVSPEC, NULL);
+ memset(floor, 0, sizeof(*floor));
+ P_AddThinker (&floor->thinker);
+ sec->specialdata = floor;
+ floor->thinker.function = T_MoveFloor;
+ floor->type = floortype;
+ floor->crush = 0;
+ floor->speed = args[1]*(FRACUNIT/8);
+ if (floortype == FLEV_LOWERTIMES8INSTANT ||
+ floortype == FLEV_RAISETIMES8INSTANT)
+ {
+ floor->speed = 2000<<FRACBITS;
+ }
+ switch (floortype)
+ {
+ case FLEV_LOWERFLOOR:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = P_FindHighestFloorSurrounding(sec);
+ break;
+ case FLEV_LOWERFLOORTOLOWEST:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = P_FindLowestFloorSurrounding(sec);
+ break;
+ case FLEV_LOWERFLOORBYVALUE:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight - args[2]*FRACUNIT;
+ break;
+ case FLEV_LOWERTIMES8INSTANT:
+ case FLEV_LOWERBYVALUETIMES8:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight - args[2]*FRACUNIT*8;
+ break;
+ case FLEV_RAISEFLOORCRUSH:
+ floor->crush = args[2]; // arg[2] = crushing value
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = sec->ceilingheight - 8*FRACUNIT;
+ break;
+ case FLEV_RAISEFLOOR:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = P_FindLowestCeilingSurrounding(sec);
+ if (floor->floordestheight > sec->ceilingheight)
+ floor->floordestheight = sec->ceilingheight;
+ break;
+ case FLEV_RAISEFLOORTONEAREST:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = P_FindNextHighestFloor(sec, sec->floorheight);
+ break;
+ case FLEV_RAISEFLOORBYVALUE:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight + args[2]*FRACUNIT;
+ break;
+ case FLEV_RAISETIMES8INSTANT:
+ case FLEV_RAISEBYVALUETIMES8:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight + args[2]*FRACUNIT*8;
+ break;
+ case FLEV_MOVETOVALUETIMES8:
+ floor->sector = sec;
+ floor->floordestheight = args[2]*FRACUNIT*8;
+ if (args[3])
+ {
+ floor->floordestheight = -floor->floordestheight;
+ }
+ if (floor->floordestheight > floor->sector->floorheight)
+ {
+ floor->direction = 1;
+ }
+ else if (floor->floordestheight < floor->sector->floorheight)
+ {
+ floor->direction = -1;
+ }
+ else
+ { // already at lowest position
+ rtn = 0;
+ }
+ break;
+ default:
+ rtn = 0;
+ break;
+ }
+ }
+ if (rtn)
+ {
+ SN_StartSequence((mobj_t *)(void *)&floor->sector->soundorg,
+ SEQ_PLATFORM + floor->sector->seqType);
+ }
+ return rtn;
+}
+
+//============================================================================
+//
+// EV_DoFloorAndCeiling
+//
+//============================================================================
+
+int EV_DoFloorAndCeiling(line_t *line, byte *args, boolean raise)
+{
+ boolean floor, ceiling;
+ int secnum;
+ sector_t *sec;
+
+ if (raise)
+ {
+ floor = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE);
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = §ors[secnum];
+ sec->specialdata = NULL;
+ }
+ ceiling = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE);
+ }
+ else
+ {
+ floor = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE);
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = §ors[secnum];
+ sec->specialdata = NULL;
+ }
+ ceiling = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE);
+ }
+ return (floor|ceiling);
+}
+
+// ===== Build Stairs Private Data =====
+
+#define STAIR_SECTOR_TYPE 26
+#define STAIR_QUEUE_SIZE 32
+
+static struct
+{
+ sector_t *sector;
+ int type;
+ int height;
+} StairQueue[STAIR_QUEUE_SIZE];
+
+static int QueueHead;
+static int QueueTail;
+
+static int StepDelta;
+static int Direction;
+static int Speed;
+static int Texture;
+static int StartDelay;
+static int StartDelayDelta;
+static int TextureChange;
+static int StartHeight;
+
+//==========================================================================
+//
+// QueueStairSector
+//
+//==========================================================================
+
+static void QueueStairSector(sector_t *sec, int type, int height)
+{
+ if ((QueueTail + 1) % STAIR_QUEUE_SIZE == QueueHead)
+ {
+ I_Error("BuildStairs: Too many branches located.\n");
+ }
+ StairQueue[QueueTail].sector = sec;
+ StairQueue[QueueTail].type = type;
+ StairQueue[QueueTail].height = height;
+
+ QueueTail = (QueueTail + 1) % STAIR_QUEUE_SIZE;
+}
+
+//==========================================================================
+//
+// DequeueStairSector
+//
+//==========================================================================
+
+static sector_t *DequeueStairSector(int *type, int *height)
+{
+ sector_t *sec;
+
+ if (QueueHead == QueueTail)
+ { // queue is empty
+ return NULL;
+ }
+ *type = StairQueue[QueueHead].type;
+ *height = StairQueue[QueueHead].height;
+ sec = StairQueue[QueueHead].sector;
+ QueueHead = (QueueHead + 1) % STAIR_QUEUE_SIZE;
+
+ return sec;
+}
+
+//==========================================================================
+//
+// ProcessStairSector
+//
+//==========================================================================
+
+static void ProcessStairSector(sector_t *sec, int type, int height,
+ stairs_e stairsType, int delay, int resetDelay)
+{
+ int i;
+ sector_t *tsec;
+ floormove_t *floor;
+
+ //
+ // new floor thinker
+ //
+ height += StepDelta;
+ floor = (floormove_t *) Z_Malloc(sizeof(*floor), PU_LEVSPEC, NULL);
+ memset(floor, 0, sizeof(*floor));
+ P_AddThinker(&floor->thinker);
+ sec->specialdata = floor;
+ floor->thinker.function = T_MoveFloor;
+ floor->type = FLEV_RAISEBUILDSTEP;
+ floor->direction = Direction;
+ floor->sector = sec;
+ floor->floordestheight = height;
+ switch (stairsType)
+ {
+ case STAIRS_NORMAL:
+ floor->speed = Speed;
+ if (delay)
+ {
+ floor->delayTotal = delay;
+ floor->stairsDelayHeight = sec->floorheight + StepDelta;
+ floor->stairsDelayHeightDelta = StepDelta;
+ }
+ floor->resetDelay = resetDelay;
+ floor->resetDelayCount = resetDelay;
+ floor->resetHeight = sec->floorheight;
+ break;
+ case STAIRS_SYNC:
+ floor->speed = FixedMul(Speed, FixedDiv(height - StartHeight, StepDelta));
+ floor->resetDelay = delay; //arg4
+ floor->resetDelayCount = delay;
+ floor->resetHeight = sec->floorheight;
+ break;
+ /*
+ case STAIRS_PHASED:
+ floor->floordestheight = sec->floorheight + StepDelta;
+ floor->speed = Speed;
+ floor->delayCount = StartDelay;
+ StartDelay += StartDelayDelta;
+ floor->textureChange = TextureChange;
+ floor->resetDelayCount = StartDelay;
+ break;
+ */
+ default:
+ break;
+ }
+ SN_StartSequence((mobj_t *)(void *)&sec->soundorg, SEQ_PLATFORM + sec->seqType);
+ //
+ // Find next sector to raise
+ // Find nearby sector with sector special equal to type
+ //
+ for (i = 0; i < sec->linecount; i++)
+ {
+ if (!((sec->lines[i])->flags & ML_TWOSIDED))
+ {
+ continue;
+ }
+ tsec = (sec->lines[i])->frontsector;
+ if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata
+ && tsec->floorpic == Texture && tsec->validcount != validcount)
+ {
+ QueueStairSector(tsec, type^1, height);
+ tsec->validcount = validcount;
+ //tsec->special = 0;
+ }
+ tsec = (sec->lines[i])->backsector;
+ if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata
+ && tsec->floorpic == Texture && tsec->validcount != validcount)
+ {
+ QueueStairSector(tsec, type^1, height);
+ tsec->validcount = validcount;
+ //tsec->special = 0;
+ }
+ }
+}
+
+//==================================================================
+//
+// BUILD A STAIRCASE!
+//
+// Direction is either positive or negative, denoting build stairs
+// up or down.
+//==================================================================
+
+int EV_BuildStairs(line_t *line, byte *args, int direction,
+ stairs_e stairsType)
+{
+ int secnum;
+ int height;
+ int delay;
+ int resetDelay;
+ sector_t *sec;
+ sector_t *qSec;
+ int type;
+
+ // Set global stairs variables
+ TextureChange = 0;
+ Direction = direction;
+ StepDelta = Direction*(args[2]*FRACUNIT);
+ Speed = args[1]*(FRACUNIT/8);
+ resetDelay = args[4];
+ delay = args[3];
+ if (stairsType == STAIRS_PHASED)
+ {
+ StartDelayDelta = args[3];
+ StartDelay = StartDelayDelta;
+ resetDelay = StartDelayDelta;
+ delay = 0;
+ TextureChange = args[4];
+ }
+
+ secnum = -1;
+
+ validcount++;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = §ors[secnum];
+
+ Texture = sec->floorpic;
+ StartHeight = sec->floorheight;
+
+ // ALREADY MOVING? IF SO, KEEP GOING...
+ if (sec->specialdata)
+ continue;
+
+ QueueStairSector(sec, 0, sec->floorheight);
+ sec->special = 0;
+ }
+ while ((qSec = DequeueStairSector(&type, &height)) != NULL)
+ {
+ ProcessStairSector(qSec, type, height, stairsType, delay, resetDelay);
+ }
+ return 1;
+}
+
+//=========================================================================
+//
+// T_BuildPillar
+//
+//=========================================================================
+
+void T_BuildPillar(pillar_t *pillar)
+{
+ result_e res1;
+ result_e res2;
+
+ // First, raise the floor
+ res1 = T_MovePlane(pillar->sector, pillar->floorSpeed,
+ pillar->floordest, pillar->crush, 0,
+ pillar->direction); // floorOrCeiling, direction
+ // Then, lower the ceiling
+ res2 = T_MovePlane(pillar->sector, pillar->ceilingSpeed,
+ pillar->ceilingdest, pillar->crush, 1,
+ -pillar->direction);
+ if (res1 == RES_PASTDEST && res2 == RES_PASTDEST)
+ {
+ pillar->sector->specialdata = NULL;
+ SN_StopSequence((mobj_t *)(void *)&pillar->sector->soundorg);
+ P_TagFinished(pillar->sector->tag);
+ P_RemoveThinker(&pillar->thinker);
+ }
+}
+
+//=========================================================================
+//
+// EV_BuildPillar
+//
+//=========================================================================
+
+int EV_BuildPillar(line_t *line, byte *args, boolean crush)
+{
+ int secnum;
+ sector_t *sec;
+ pillar_t *pillar;
+ int newHeight;
+ int rtn;
+
+ rtn = 0;
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = §ors[secnum];
+ if (sec->specialdata)
+ continue; // already moving
+ if (sec->floorheight == sec->ceilingheight)
+ { // pillar is already closed
+ continue;
+ }
+ rtn = 1;
+ if (!args[2])
+ {
+ newHeight = sec->floorheight +
+ ((sec->ceilingheight - sec->floorheight)/2);
+ }
+ else
+ {
+ newHeight = sec->floorheight + (args[2]<<FRACBITS);
+ }
+
+ pillar = (pillar_t *) Z_Malloc(sizeof(*pillar), PU_LEVSPEC, NULL);
+ sec->specialdata = pillar;
+ P_AddThinker(&pillar->thinker);
+ pillar->thinker.function = T_BuildPillar;
+ pillar->sector = sec;
+ if (!args[2])
+ {
+ pillar->ceilingSpeed = pillar->floorSpeed = args[1]*(FRACUNIT/8);
+ }
+ else if (newHeight-sec->floorheight > sec->ceilingheight - newHeight)
+ {
+ pillar->floorSpeed = args[1]*(FRACUNIT/8);
+ pillar->ceilingSpeed = FixedMul(sec->ceilingheight - newHeight,
+ FixedDiv(pillar->floorSpeed, newHeight - sec->floorheight));
+ }
+ else
+ {
+ pillar->ceilingSpeed = args[1]*(FRACUNIT/8);
+ pillar->floorSpeed = FixedMul(newHeight - sec->floorheight,
+ FixedDiv(pillar->ceilingSpeed, sec->ceilingheight - newHeight));
+ }
+ pillar->floordest = newHeight;
+ pillar->ceilingdest = newHeight;
+ pillar->direction = 1;
+ pillar->crush = crush*args[3];
+ SN_StartSequence((mobj_t *)(void *)&pillar->sector->soundorg,
+ SEQ_PLATFORM + pillar->sector->seqType);
+ }
+ return rtn;
+}
+
+//=========================================================================
+//
+// EV_OpenPillar
+//
+//=========================================================================
+
+int EV_OpenPillar(line_t *line, byte *args)
+{
+ int secnum;
+ sector_t *sec;
+ pillar_t *pillar;
+ int rtn;
+
+ rtn = 0;
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = §ors[secnum];
+ if (sec->specialdata)
+ continue; // already moving
+ if (sec->floorheight != sec->ceilingheight)
+ { // pillar isn't closed
+ continue;
+ }
+ rtn = 1;
+ pillar = (pillar_t *) Z_Malloc(sizeof(*pillar), PU_LEVSPEC, NULL);
+ sec->specialdata = pillar;
+ P_AddThinker(&pillar->thinker);
+ pillar->thinker.function = T_BuildPillar;
+ pillar->sector = sec;
+ if (!args[2])
+ {
+ pillar->floordest = P_FindLowestFloorSurrounding(sec);
+ }
+ else
+ {
+ pillar->floordest = sec->floorheight - (args[2]<<FRACBITS);
+ }
+ if (!args[3])
+ {
+ pillar->ceilingdest = P_FindHighestCeilingSurrounding(sec);
+ }
+ else
+ {
+ pillar->ceilingdest = sec->ceilingheight + (args[3]<<FRACBITS);
+ }
+ if (sec->floorheight - pillar->floordest >=
+ pillar->ceilingdest - sec->ceilingheight)
+ {
+ pillar->floorSpeed = args[1]*(FRACUNIT/8);
+ pillar->ceilingSpeed = FixedMul(sec->ceilingheight - pillar->ceilingdest,
+ FixedDiv(pillar->floorSpeed, pillar->floordest - sec->floorheight));
+ }
+ else
+ {
+ pillar->ceilingSpeed = args[1]*(FRACUNIT/8);
+ pillar->floorSpeed = FixedMul(pillar->floordest - sec->floorheight,
+ FixedDiv(pillar->ceilingSpeed, sec->ceilingheight - pillar->ceilingdest));
+ }
+ pillar->direction = -1; // open the pillar
+ SN_StartSequence((mobj_t *)(void *)&pillar->sector->soundorg,
+ SEQ_PLATFORM + pillar->sector->seqType);
+ }
+ return rtn;
+}
+
+//=========================================================================
+//
+// EV_FloorCrushStop
+//
+//=========================================================================
+
+int EV_FloorCrushStop(line_t *line, byte *args)
+{
+ thinker_t *think;
+ floormove_t *floor;
+ boolean rtn;
+
+ rtn = 0;
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != T_MoveFloor)
+ {
+ continue;
+ }
+ floor = (floormove_t *)think;
+ if (floor->type != FLEV_RAISEFLOORCRUSH)
+ {
+ continue;
+ }
+ // Completely remove the crushing floor
+ SN_StopSequence((mobj_t *)(void *)&floor->sector->soundorg);
+ floor->sector->specialdata = NULL;
+ P_TagFinished(floor->sector->tag);
+ P_RemoveThinker(&floor->thinker);
+ rtn = 1;
+ }
+ return rtn;
+}
+
+//==========================================================================
+//
+// T_FloorWaggle
+//
+//==========================================================================
+
+#define WGLSTATE_EXPAND 1
+#define WGLSTATE_STABLE 2
+#define WGLSTATE_REDUCE 3
+
+void T_FloorWaggle(floorWaggle_t *waggle)
+{
+ switch (waggle->state)
+ {
+ case WGLSTATE_EXPAND:
+ if ((waggle->scale += waggle->scaleDelta) >= waggle->targetScale)
+ {
+ waggle->scale = waggle->targetScale;
+ waggle->state = WGLSTATE_STABLE;
+ }
+ break;
+ case WGLSTATE_REDUCE:
+ if ((waggle->scale -= waggle->scaleDelta) <= 0)
+ { // Remove
+ waggle->sector->floorheight = waggle->originalHeight;
+ P_ChangeSector(waggle->sector, true);
+ waggle->sector->specialdata = NULL;
+ P_TagFinished(waggle->sector->tag);
+ P_RemoveThinker(&waggle->thinker);
+ return;
+ }
+ break;
+ case WGLSTATE_STABLE:
+ if (waggle->ticker != -1)
+ {
+ if (!--waggle->ticker)
+ {
+ waggle->state = WGLSTATE_REDUCE;
+ }
+ }
+ break;
+ }
+ waggle->accumulator += waggle->accDelta;
+ waggle->sector->floorheight = waggle->originalHeight +
+ FixedMul(FloatBobOffsets[(waggle->accumulator>>FRACBITS) & 63], waggle->scale);
+ P_ChangeSector(waggle->sector, true);
+}
+
+//==========================================================================
+//
+// EV_StartFloorWaggle
+//
+//==========================================================================
+
+boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset,
+ int timer)
+{
+ int sectorIndex;
+ sector_t *sector;
+ floorWaggle_t *waggle;
+ boolean retCode;
+
+ retCode = false;
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ sector = §ors[sectorIndex];
+ if (sector->specialdata)
+ { // Already busy with another thinker
+ continue;
+ }
+ retCode = true;
+ waggle = (floorWaggle_t *) Z_Malloc(sizeof(*waggle), PU_LEVSPEC, NULL);
+ sector->specialdata = waggle;
+ waggle->thinker.function = T_FloorWaggle;
+ waggle->sector = sector;
+ waggle->originalHeight = sector->floorheight;
+ waggle->accumulator = offset*FRACUNIT;
+ waggle->accDelta = speed<<10;
+ waggle->scale = 0;
+ waggle->targetScale = height<<10;
+ waggle->scaleDelta = waggle->targetScale / (35 + ((3*35)*height)/255);
+ waggle->ticker = timer ? timer*35 : -1;
+ waggle->state = WGLSTATE_EXPAND;
+ P_AddThinker(&waggle->thinker);
+ }
+ return retCode;
+}
+
--- /dev/null
+++ b/p_inter.c
@@ -1,0 +1,2276 @@
+
+//**************************************************************************
+//**
+//** p_inter.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+extern int messageson;
+
+#define BONUSADD 6
+
+int ArmorIncrement[NUMCLASSES][NUMARMOR] =
+{
+ { 25*FRACUNIT, 20*FRACUNIT, 15*FRACUNIT, 5*FRACUNIT },
+ { 10*FRACUNIT, 25*FRACUNIT, 5*FRACUNIT, 20*FRACUNIT },
+ { 5*FRACUNIT, 15*FRACUNIT, 10*FRACUNIT, 25*FRACUNIT },
+#ifdef ASSASSIN
+ { 20*FRACUNIT, 10*FRACUNIT, 25*FRACUNIT, 5*FRACUNIT },
+#endif
+ { 0, 0, 0, 0 }
+};
+
+int AutoArmorSave[NUMCLASSES] =
+{
+ 15*FRACUNIT,
+ 10*FRACUNIT,
+ 5*FRACUNIT,
+#ifdef ASSASSIN
+ 10*FRACUNIT,
+#endif
+ 0
+};
+
+const char *TextKeyMessages[] =
+{
+ TXT_KEY_STEEL,
+ TXT_KEY_CAVE,
+ TXT_KEY_AXE,
+ TXT_KEY_FIRE,
+ TXT_KEY_EMERALD,
+ TXT_KEY_DUNGEON,
+ TXT_KEY_SILVER,
+ TXT_KEY_RUSTED,
+ TXT_KEY_HORN,
+ TXT_KEY_SWAMP,
+ TXT_KEY_CASTLE
+};
+
+static void SetDormantArtifact(mobj_t *arti);
+static void TryPickupArtifact(player_t *player, artitype_t artifactType, mobj_t *artifact);
+static void TryPickupWeapon(player_t *player, pclass_t weaponClass, weapontype_t weaponType, mobj_t *weapon, const char *message);
+static void TryPickupWeaponPiece(player_t *player, pclass_t matchClass, int pieceValue, mobj_t *pieceMobj);
+
+//--------------------------------------------------------------------------
+//
+// PROC P_SetMessage
+//
+//--------------------------------------------------------------------------
+
+void P_SetMessage(player_t *player, const char *message, boolean ultmsg)
+{
+ if ((player->ultimateMessage || !messageson) && !ultmsg)
+ {
+ return;
+ }
+ if (strlen(message) > 79)
+ {
+ memcpy(player->message, message, 79);
+ player->message[79] = 0;
+ }
+ else
+ {
+ strcpy(player->message, message);
+ }
+ strupr(player->message);
+ player->messageTics = MESSAGETICS;
+ player->yellowMessage = false;
+ if (ultmsg)
+ {
+ player->ultimateMessage = true;
+ }
+ if (player == &players[consoleplayer])
+ {
+ BorderTopRefresh = true;
+ }
+}
+
+//==========================================================================
+//
+// P_SetYellowMessage
+//
+//==========================================================================
+
+void P_SetYellowMessage(player_t *player, const char *message, boolean ultmsg)
+{
+ if ((player->ultimateMessage || !messageson) && !ultmsg)
+ {
+ return;
+ }
+ if (strlen(message) > 79)
+ {
+ memcpy(player->message, message, 79);
+ player->message[79] = 0;
+ }
+ else
+ {
+ strcpy(player->message, message);
+ }
+ player->messageTics = 5*MESSAGETICS; // Bold messages last longer
+ player->yellowMessage = true;
+ if (ultmsg)
+ {
+ player->ultimateMessage = true;
+ }
+ if (player == &players[consoleplayer])
+ {
+ BorderTopRefresh = true;
+ }
+}
+
+//==========================================================================
+//
+// P_ClearMessage
+//
+//==========================================================================
+
+void P_ClearMessage(player_t *player)
+{
+ player->messageTics = 0;
+ if (player == &players[consoleplayer])
+ {
+ BorderTopRefresh = true;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_HideSpecialThing
+//
+//----------------------------------------------------------------------------
+
+static void P_HideSpecialThing(mobj_t *thing)
+{
+ thing->flags &= ~MF_SPECIAL;
+ thing->flags2 |= MF2_DONTDRAW;
+ P_SetMobjState(thing, S_HIDESPECIAL1);
+}
+
+//--------------------------------------------------------------------------
+//
+// FUNC P_GiveMana
+//
+// Returns true if the player accepted the mana, false if it was
+// refused (player has MAX_MANA).
+//
+//--------------------------------------------------------------------------
+
+boolean P_GiveMana(player_t *player, manatype_t mana, int count)
+{
+ int prevMana;
+ //weapontype_t changeWeapon;
+
+ if (mana == MANA_NONE || mana == MANA_BOTH)
+ {
+ return false;
+ }
+ if (mana < 0 || mana > NUMMANA)
+ {
+ I_Error("P_GiveMana: bad type %i", mana);
+ }
+ if (player->mana[mana] == MAX_MANA)
+ {
+ return false;
+ }
+ if (gameskill == sk_baby || gameskill == sk_nightmare)
+ { // extra mana in baby mode and nightmare mode
+ count += count>>1;
+ }
+ prevMana = player->mana[mana];
+
+ player->mana[mana] += count;
+ if (player->mana[mana] > MAX_MANA)
+ {
+ player->mana[mana] = MAX_MANA;
+ }
+ if (player->playerclass == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
+ && mana == MANA_1 && prevMana <= 0)
+ {
+ P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// TryPickupWeapon
+//
+//==========================================================================
+
+static void TryPickupWeapon(player_t *player, pclass_t weaponClass,
+ weapontype_t weaponType, mobj_t *weapon, const char *message)
+{
+ boolean removeit;
+ boolean gaveMana;
+ boolean gaveWeapon;
+
+ removeit = true;
+ if (player->playerclass != weaponClass
+#ifdef ASSASSIN
+ && player->playerclass != PCLASS_ASS
+#endif
+ )
+ { // Wrong class, but try to pick up for mana
+ if (netgame && !deathmatch)
+ { // Can't pick up weapons for other classes in coop netplay
+ return;
+ }
+ if (weaponType == WP_SECOND)
+ {
+ if (!P_GiveMana(player, MANA_1, 25))
+ {
+ return;
+ }
+ }
+ else
+ {
+ if (!P_GiveMana(player, MANA_2, 25))
+ {
+ return;
+ }
+ }
+ }
+ else if (netgame && !deathmatch)
+ { // Cooperative net-game
+ if (player->weaponowned[weaponType])
+ {
+ return;
+ }
+ player->weaponowned[weaponType] = true;
+ if (weaponType == WP_SECOND)
+ {
+ P_GiveMana(player, MANA_1, 25);
+ }
+ else
+ {
+ P_GiveMana(player, MANA_2, 25);
+ }
+ player->pendingweapon = weaponType;
+ removeit = false;
+ }
+ else
+ { // Deathmatch or single player game
+ if (weaponType == WP_SECOND)
+ {
+ gaveMana = P_GiveMana(player, MANA_1, 25);
+ }
+ else
+ {
+ gaveMana = P_GiveMana(player, MANA_2, 25);
+ }
+ if (player->weaponowned[weaponType])
+ {
+ gaveWeapon = false;
+ }
+ else
+ {
+ gaveWeapon = true;
+ player->weaponowned[weaponType] = true;
+ if (weaponType > player->readyweapon)
+ { // Only switch to more powerful weapons
+ player->pendingweapon = weaponType;
+ }
+ }
+ if (!(gaveWeapon || gaveMana))
+ { // Player didn't need the weapon or any mana
+ return;
+ }
+ }
+
+ P_SetMessage(player, message, false);
+ if (weapon->special)
+ {
+ P_ExecuteLineSpecial(weapon->special, weapon->args,
+ NULL, 0, player->mo);
+ weapon->special = 0;
+ }
+
+ if (removeit)
+ {
+ if (deathmatch && !(weapon->flags2 & MF2_DROPPED))
+ {
+ P_HideSpecialThing(weapon);
+ }
+ else
+ {
+ P_RemoveMobj(weapon);
+ }
+ }
+
+ player->bonuscount += BONUSADD;
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, SFX_PICKUP_WEAPON);
+ SB_PaletteFlash(false);
+ }
+}
+
+//--------------------------------------------------------------------------
+//
+// FUNC P_GiveWeapon
+//
+// Returns true if the weapon or its mana was accepted.
+//
+//--------------------------------------------------------------------------
+
+/*
+static boolean P_GiveWeapon(player_t *player, pclass_t pClass, weapontype_t weapon)
+{
+ boolean gaveMana;
+ boolean gaveWeapon;
+
+ if (player->playerclass != pClass)
+ { // player cannot use this weapon, take it anyway, and get mana
+ if (netgame && !deathmatch)
+ { // Can't pick up weapons for other classes in coop netplay
+ return false;
+ }
+ if (weapon == WP_SECOND)
+ {
+ return P_GiveMana(player, MANA_1, 25);
+ }
+ else
+ {
+ return P_GiveMana(player, MANA_2, 25);
+ }
+ }
+ if (netgame && !deathmatch)
+ { // Cooperative net-game
+ if (player->weaponowned[weapon])
+ {
+ return false;
+ }
+ player->bonuscount += BONUSADD;
+ player->weaponowned[weapon] = true;
+ if (weapon == WP_SECOND)
+ {
+ P_GiveMana(player, MANA_1, 25);
+ }
+ else
+ {
+ P_GiveMana(player, MANA_2, 25);
+ }
+ player->pendingweapon = weapon;
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, SFX_PICKUP_WEAPON);
+ }
+ return false;
+ }
+ if (weapon == WP_SECOND)
+ {
+ gaveMana = P_GiveMana(player, MANA_1, 25);
+ }
+ else
+ {
+ gaveMana = P_GiveMana(player, MANA_2, 25);
+ }
+ if (player->weaponowned[weapon])
+ {
+ gaveWeapon = false;
+ }
+ else
+ {
+ gaveWeapon = true;
+ player->weaponowned[weapon] = true;
+ if (weapon > player->readyweapon)
+ { // Only switch to more powerful weapons
+ player->pendingweapon = weapon;
+ }
+ }
+ return(gaveWeapon || gaveMana);
+}
+*/
+
+//===========================================================================
+//
+// P_GiveWeaponPiece
+//
+//===========================================================================
+
+/*
+static boolean P_GiveWeaponPiece(player_t *player, pclass_t pClass, int piece)
+{
+ P_GiveMana(player, MANA_1, 20);
+ P_GiveMana(player, MANA_2, 20);
+ if (player->playerclass != pClass)
+ {
+ return true;
+ }
+ else if (player->pieces & piece)
+ { // player already has that weapon piece
+ return true;
+ }
+ player->pieces |= piece;
+ if (player->pieces == 7)
+ { // player has built the fourth weapon!
+ P_GiveWeapon(player, pClass, WP_FOURTH);
+ S_StartSound(player->mo, SFX_WEAPON_BUILD);
+ }
+ return true;
+}
+*/
+
+//==========================================================================
+//
+// TryPickupWeaponPiece
+//
+//==========================================================================
+
+static void TryPickupWeaponPiece(player_t *player, pclass_t matchClass,
+ int pieceValue, mobj_t *pieceMobj)
+{
+ boolean removeit;
+ boolean checkAssembled;
+ boolean gaveWeapon;
+ int gaveMana;
+ static const char *fourthWeaponText[] =
+ {
+ TXT_WEAPON_F4,
+ TXT_WEAPON_C4,
+ TXT_WEAPON_M4,
+#ifdef ASSASSIN
+ TXT_WEAPON_A4
+#endif
+ };
+ static const char *weaponPieceText[] =
+ {
+ TXT_QUIETUS_PIECE,
+ TXT_WRAITHVERGE_PIECE,
+ TXT_BLOODSCOURGE_PIECE,
+#ifdef ASSASSIN
+ TXT_STAFFOFSET_PIECE
+#endif
+ };
+ static int pieceValueTrans[] =
+ {
+ 0, // 0: never
+ WPIECE1|WPIECE2|WPIECE3, // WPIECE1 (1)
+ WPIECE2|WPIECE3, // WPIECE2 (2)
+ 0, // 3: never
+ WPIECE3 // WPIECE3 (4)
+ };
+
+ removeit = true;
+ checkAssembled = true;
+ gaveWeapon = false;
+ // Allow assassin to pick up any weapons
+ if (player->playerclass != matchClass
+#ifdef ASSASSIN
+ && player->playerclass != PCLASS_ASS
+#endif
+ )
+ { // Wrong class, but try to pick up for mana
+ if (netgame && !deathmatch)
+ { // Can't pick up wrong-class weapons in coop netplay
+ return;
+ }
+ checkAssembled = false;
+ gaveMana = P_GiveMana(player, MANA_1, 20) +
+ P_GiveMana(player, MANA_2, 20);
+ if (!gaveMana)
+ { // Didn't need the mana, so don't pick it up
+ return;
+ }
+ }
+ else if (netgame && !deathmatch)
+ { // Cooperative net-game
+ if (player->pieces & pieceValue)
+ { // Already has the piece
+ return;
+ }
+ pieceValue = pieceValueTrans[pieceValue];
+ P_GiveMana(player, MANA_1, 20);
+ P_GiveMana(player, MANA_2, 20);
+ removeit = false;
+ }
+ else
+ { // Deathmatch or single player game
+ gaveMana = P_GiveMana(player, MANA_1, 20) +
+ P_GiveMana(player, MANA_2, 20);
+ if (player->pieces & pieceValue)
+ { // Already has the piece, check if mana needed
+ if (!gaveMana)
+ { // Didn't need the mana, so don't pick it up
+ return;
+ }
+ checkAssembled = false;
+ }
+ }
+
+ // Pick up the weapon piece
+ if (pieceMobj->special)
+ {
+ P_ExecuteLineSpecial(pieceMobj->special, pieceMobj->args,
+ NULL, 0, player->mo);
+ pieceMobj->special = 0;
+ }
+ if (removeit)
+ {
+ if (deathmatch && !(pieceMobj->flags2 & MF2_DROPPED))
+ {
+ P_HideSpecialThing(pieceMobj);
+ }
+ else
+ {
+ P_RemoveMobj(pieceMobj);
+ }
+ }
+ player->bonuscount += BONUSADD;
+ if (player == &players[consoleplayer])
+ {
+ SB_PaletteFlash(false);
+ }
+
+ // Check if fourth weapon assembled
+ if (checkAssembled)
+ {
+ player->pieces |= pieceValue;
+ if (player->pieces == (WPIECE1|WPIECE2|WPIECE3))
+ {
+ gaveWeapon = true;
+ player->weaponowned[WP_FOURTH] = true;
+ player->pendingweapon = WP_FOURTH;
+ }
+ }
+
+ if (gaveWeapon)
+ {
+ P_SetMessage(player, fourthWeaponText[matchClass], false);
+ // Play the build-sound full volume for all players
+ S_StartSound(NULL, SFX_WEAPON_BUILD);
+ }
+ else
+ {
+ P_SetMessage(player, weaponPieceText[matchClass], false);
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, SFX_PICKUP_WEAPON);
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveBody
+//
+// Returns false if the body isn't needed at all.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveBody(player_t *player, int num)
+{
+ int max;
+
+ max = MAXHEALTH;
+ if (player->morphTics)
+ {
+ max = MAXMORPHHEALTH;
+ }
+ if (player->health >= max)
+ {
+ return false;
+ }
+ player->health += num;
+ if (player->health > max)
+ {
+ player->health = max;
+ }
+ player->mo->health = player->health;
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveArmor
+//
+// Returns false if the armor is worse than the current armor.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveArmor(player_t *player, armortype_t armortype, int amount)
+{
+ int hits;
+ int totalArmor;
+
+ extern int ArmorMax[NUMCLASSES];
+
+ if (amount == -1)
+ {
+ hits = ArmorIncrement[player->playerclass][armortype];
+ if (player->armorpoints[armortype] >= hits)
+ {
+ return false;
+ }
+ else
+ {
+ player->armorpoints[armortype] = hits;
+ }
+ }
+ else
+ {
+ hits = amount * 5 * FRACUNIT;
+ totalArmor = player->armorpoints[ARMOR_ARMOR]
+ + player->armorpoints[ARMOR_SHIELD]
+ + player->armorpoints[ARMOR_HELMET]
+ + player->armorpoints[ARMOR_AMULET]
+ + AutoArmorSave[player->playerclass];
+ if (totalArmor < ArmorMax[player->playerclass]*5*FRACUNIT)
+ {
+ player->armorpoints[armortype] += hits;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_GiveKey
+//
+//---------------------------------------------------------------------------
+
+static boolean P_GiveKey(player_t *player, keytype_t key)
+{
+ if (player->keys & (1<<key))
+ {
+ return false;
+ }
+ player->bonuscount += BONUSADD;
+ player->keys |= 1<<key;
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GivePower
+//
+// Returns true if power accepted.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GivePower(player_t *player, powertype_t power)
+{
+ if (power == pw_invulnerability)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return false;
+ }
+ player->powers[power] = INVULNTICS;
+ player->mo->flags2 |= MF2_INVULNERABLE;
+ if (player->playerclass == PCLASS_MAGE)
+ {
+ player->mo->flags2 |= MF2_REFLECTIVE;
+ }
+ return true;
+ }
+ if (power == pw_flight)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return false;
+ }
+ player->powers[power] = FLIGHTTICS;
+ player->mo->flags2 |= MF2_FLY;
+ player->mo->flags |= MF_NOGRAVITY;
+ if (player->mo->z <= player->mo->floorz)
+ {
+ player->flyheight = 10; // thrust the player in the air a bit
+ }
+ return true;
+ }
+ if (power == pw_infrared)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return false;
+ }
+ player->powers[power] = INFRATICS;
+ return true;
+ }
+ if (power == pw_speed)
+ {
+ if (player->powers[power] > BLINKTHRESHOLD)
+ { // Already have it
+ return false;
+ }
+ player->powers[power] = SPEEDTICS;
+ return true;
+ }
+ if (power == pw_minotaur)
+ {
+ // Doesn't matter if already have power, renew ticker
+ player->powers[power] = MAULATORTICS;
+ return true;
+ }
+ /*
+ if (power == pw_ironfeet)
+ {
+ player->powers[power] = IRONTICS;
+ return true;
+ }
+ if (power == pw_strength)
+ {
+ P_GiveBody(player, 100);
+ player->powers[power] = 1;
+ return true;
+ }
+ */
+ if (player->powers[power])
+ {
+ return false; // already got it
+ }
+ player->powers[power] = 1;
+ return true;
+}
+
+//==========================================================================
+//
+// TryPickupArtifact
+//
+//==========================================================================
+
+static void TryPickupArtifact(player_t *player, artitype_t artifactType,
+ mobj_t *artifact)
+{
+ static const char *artifactMessages[NUMARTIFACTS] =
+ {
+ NULL,
+ TXT_ARTIINVULNERABILITY,
+ TXT_ARTIHEALTH,
+ TXT_ARTISUPERHEALTH,
+ TXT_ARTIHEALINGRADIUS,
+ TXT_ARTISUMMON,
+ TXT_ARTITORCH,
+ TXT_ARTIEGG,
+ TXT_ARTIFLY,
+ TXT_ARTIBLASTRADIUS,
+ TXT_ARTIPOISONBAG,
+ TXT_ARTITELEPORTOTHER,
+ TXT_ARTISPEED,
+ TXT_ARTIBOOSTMANA,
+ TXT_ARTIBOOSTARMOR,
+ TXT_ARTITELEPORT,
+ TXT_ARTIPUZZSKULL,
+ TXT_ARTIPUZZGEMBIG,
+ TXT_ARTIPUZZGEMRED,
+ TXT_ARTIPUZZGEMGREEN1,
+ TXT_ARTIPUZZGEMGREEN2,
+ TXT_ARTIPUZZGEMBLUE1,
+ TXT_ARTIPUZZGEMBLUE2,
+ TXT_ARTIPUZZBOOK1,
+ TXT_ARTIPUZZBOOK2,
+ TXT_ARTIPUZZSKULL2,
+ TXT_ARTIPUZZFWEAPON,
+ TXT_ARTIPUZZCWEAPON,
+ TXT_ARTIPUZZMWEAPON,
+ TXT_ARTIPUZZGEAR, // All gear pickups use the same text
+ TXT_ARTIPUZZGEAR,
+ TXT_ARTIPUZZGEAR,
+ TXT_ARTIPUZZGEAR
+ };
+
+ if (P_GiveArtifact(player, artifactType, artifact))
+ {
+ if (artifact->special)
+ {
+ P_ExecuteLineSpecial(artifact->special, artifact->args,
+ NULL, 0, NULL);
+ artifact->special = 0;
+ }
+ player->bonuscount += BONUSADD;
+ if (artifactType < arti_firstpuzzitem)
+ {
+ SetDormantArtifact(artifact);
+ S_StartSound(artifact, SFX_PICKUP_ARTIFACT);
+ P_SetMessage(player, artifactMessages[artifactType], false);
+ }
+ else
+ { // Puzzle item
+ S_StartSound(NULL, SFX_PICKUP_ITEM);
+ P_SetMessage(player, artifactMessages[artifactType], true);
+ if (!netgame || deathmatch)
+ { // Remove puzzle items if not cooperative netplay
+ P_RemoveMobj(artifact);
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GiveArtifact
+//
+// Returns true if artifact accepted.
+//
+//---------------------------------------------------------------------------
+
+boolean P_GiveArtifact(player_t *player, artitype_t arti, mobj_t *mo)
+{
+ int i;
+ int j;
+ boolean slidePointer;
+
+ slidePointer = false;
+ i = 0;
+ while (player->inventory[i].type != arti && i < player->inventorySlotNum)
+ {
+ i++;
+ }
+ if (i == player->inventorySlotNum)
+ {
+ if (arti < arti_firstpuzzitem)
+ {
+ i = 0;
+ while (player->inventory[i].type < arti_firstpuzzitem &&
+ i < player->inventorySlotNum)
+ {
+ i++;
+ }
+ if (i != player->inventorySlotNum)
+ {
+ for (j = player->inventorySlotNum; j > i; j--)
+ {
+ player->inventory[j].count = player->inventory[j-1].count;
+ player->inventory[j].type = player->inventory[j-1].type;
+ slidePointer = true;
+ }
+ }
+ }
+ player->inventory[i].count = 1;
+ player->inventory[i].type = arti;
+ player->inventorySlotNum++;
+ }
+ else
+ {
+ if (arti >= arti_firstpuzzitem && netgame && !deathmatch)
+ { // Can't carry more than 1 puzzle item in coop netplay
+ return false;
+ }
+ if (player->inventory[i].count >= 25)
+ { // Player already has 25 of this item
+ return false;
+ }
+ player->inventory[i].count++;
+ }
+ if (!player->artifactCount)
+ {
+ player->readyArtifact = arti;
+ }
+ else if (player == &players[consoleplayer] && slidePointer
+ && i <= inv_ptr)
+ {
+ inv_ptr++;
+ curpos++;
+ if (curpos > 6)
+ {
+ curpos = 6;
+ }
+ }
+ player->artifactCount++;
+ return true;
+}
+
+//==========================================================================
+//
+// SetDormantArtifact
+//
+// Removes the MF_SPECIAL flag and initiates the artifact pickup
+// animation.
+//
+//==========================================================================
+
+static void SetDormantArtifact(mobj_t *arti)
+{
+ arti->flags &= ~MF_SPECIAL;
+ if (deathmatch && !(arti->flags2 & MF2_DROPPED))
+ {
+ if (arti->type == MT_ARTIINVULNERABILITY)
+ {
+ P_SetMobjState(arti, S_DORMANTARTI3_1);
+ }
+ else if (arti->type == MT_SUMMONMAULATOR ||
+ arti->type == MT_ARTIFLY)
+ {
+ P_SetMobjState(arti, S_DORMANTARTI2_1);
+ }
+ else
+ {
+ P_SetMobjState(arti, S_DORMANTARTI1_1);
+ }
+ }
+ else
+ { // Don't respawn
+ P_SetMobjState(arti, S_DEADARTI1);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreArtifact
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreArtifact(mobj_t *arti)
+{
+ arti->flags |= MF_SPECIAL;
+ P_SetMobjState(arti, arti->info->spawnstate);
+ S_StartSound(arti, SFX_RESPAWN);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreSpecialThing1
+//
+// Make a special thing visible again.
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreSpecialThing1(mobj_t *thing)
+{
+ thing->flags2 &= ~MF2_DONTDRAW;
+ S_StartSound(thing, SFX_RESPAWN);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_RestoreSpecialThing2
+//
+//---------------------------------------------------------------------------
+
+void A_RestoreSpecialThing2(mobj_t *thing)
+{
+ thing->flags |= MF_SPECIAL;
+ P_SetMobjState(thing, thing->info->spawnstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_TouchSpecialThing
+//
+//---------------------------------------------------------------------------
+
+void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher)
+{
+ player_t *player;
+ fixed_t delta;
+ int sound;
+ boolean respawn;
+
+ delta = special->z-toucher->z;
+ if (delta > toucher->height || delta < -32*FRACUNIT)
+ { // Out of reach
+ return;
+ }
+ if (toucher->health <= 0)
+ { // Toucher is dead
+ return;
+ }
+ sound = SFX_PICKUP_ITEM;
+ player = toucher->player;
+ respawn = true;
+ switch (special->sprite)
+ {
+ // Items
+ case SPR_PTN1: // Item_HealingPotion
+ if (!P_GiveBody(player, 10))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_ITEMHEALTH, false);
+ break;
+ case SPR_ARM1:
+ if (!P_GiveArmor(player, ARMOR_ARMOR, -1))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_ARMOR1, false);
+ break;
+ case SPR_ARM2:
+ if (!P_GiveArmor(player, ARMOR_SHIELD, -1))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_ARMOR2, false);
+ break;
+ case SPR_ARM3:
+ if (!P_GiveArmor(player, ARMOR_HELMET, -1))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_ARMOR3, false);
+ break;
+ case SPR_ARM4:
+ if (!P_GiveArmor(player, ARMOR_AMULET, -1))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_ARMOR4, false);
+ break;
+
+ // Keys
+ case SPR_KEY1:
+ case SPR_KEY2:
+ case SPR_KEY3:
+ case SPR_KEY4:
+ case SPR_KEY5:
+ case SPR_KEY6:
+ case SPR_KEY7:
+ case SPR_KEY8:
+ case SPR_KEY9:
+ case SPR_KEYA:
+ case SPR_KEYB:
+ if (!P_GiveKey(player, special->sprite-SPR_KEY1))
+ {
+ return;
+ }
+ P_SetMessage(player, TextKeyMessages[special->sprite-SPR_KEY1], true);
+ sound = SFX_PICKUP_KEY;
+
+ // Check and process the special now in case the key doesn't
+ // get removed for coop netplay
+ if (special->special)
+ {
+ P_ExecuteLineSpecial(special->special, special->args,
+ NULL, 0, toucher);
+ special->special = 0;
+ }
+
+ if (!netgame)
+ { // Only remove keys in single player game
+ break;
+ }
+ player->bonuscount += BONUSADD;
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, sound);
+ SB_PaletteFlash(false);
+ }
+ return;
+
+ // Artifacts
+ case SPR_PTN2:
+ TryPickupArtifact(player, arti_health, special);
+ return;
+ case SPR_SOAR:
+ TryPickupArtifact(player, arti_fly, special);
+ return;
+ case SPR_INVU:
+ TryPickupArtifact(player, arti_invulnerability, special);
+ return;
+ case SPR_SUMN:
+ TryPickupArtifact(player, arti_summon, special);
+ return;
+ case SPR_PORK:
+ TryPickupArtifact(player, arti_egg, special);
+ return;
+ case SPR_SPHL:
+ TryPickupArtifact(player, arti_superhealth, special);
+ return;
+ case SPR_HRAD:
+ TryPickupArtifact(player, arti_healingradius, special);
+ return;
+ case SPR_TRCH:
+ TryPickupArtifact(player, arti_torch, special);
+ return;
+ case SPR_ATLP:
+ TryPickupArtifact(player, arti_teleport, special);
+ return;
+ case SPR_TELO:
+ TryPickupArtifact(player, arti_teleportother, special);
+ return;
+ case SPR_PSBG:
+ TryPickupArtifact(player, arti_poisonbag, special);
+ return;
+ case SPR_SPED:
+ TryPickupArtifact(player, arti_speed, special);
+ return;
+ case SPR_BMAN:
+ TryPickupArtifact(player, arti_boostmana, special);
+ return;
+ case SPR_BRAC:
+ TryPickupArtifact(player, arti_boostarmor, special);
+ return;
+ case SPR_BLST:
+ TryPickupArtifact(player, arti_blastradius, special);
+ return;
+
+ // Puzzle artifacts
+ case SPR_ASKU:
+ TryPickupArtifact(player, arti_puzzskull, special);
+ return;
+ case SPR_ABGM:
+ TryPickupArtifact(player, arti_puzzgembig, special);
+ return;
+ case SPR_AGMR:
+ TryPickupArtifact(player, arti_puzzgemred, special);
+ return;
+ case SPR_AGMG:
+ TryPickupArtifact(player, arti_puzzgemgreen1, special);
+ return;
+ case SPR_AGG2:
+ TryPickupArtifact(player, arti_puzzgemgreen2, special);
+ return;
+ case SPR_AGMB:
+ TryPickupArtifact(player, arti_puzzgemblue1, special);
+ return;
+ case SPR_AGB2:
+ TryPickupArtifact(player, arti_puzzgemblue2, special);
+ return;
+ case SPR_ABK1:
+ TryPickupArtifact(player, arti_puzzbook1, special);
+ return;
+ case SPR_ABK2:
+ TryPickupArtifact(player, arti_puzzbook2, special);
+ return;
+ case SPR_ASK2:
+ TryPickupArtifact(player, arti_puzzskull2, special);
+ return;
+ case SPR_AFWP:
+ TryPickupArtifact(player, arti_puzzfweapon, special);
+ return;
+ case SPR_ACWP:
+ TryPickupArtifact(player, arti_puzzcweapon, special);
+ return;
+ case SPR_AMWP:
+ TryPickupArtifact(player, arti_puzzmweapon, special);
+ return;
+ case SPR_AGER:
+ TryPickupArtifact(player, arti_puzzgear1, special);
+ return;
+ case SPR_AGR2:
+ TryPickupArtifact(player, arti_puzzgear2, special);
+ return;
+ case SPR_AGR3:
+ TryPickupArtifact(player, arti_puzzgear3, special);
+ return;
+ case SPR_AGR4:
+ TryPickupArtifact(player, arti_puzzgear4, special);
+ return;
+
+ // Mana
+ case SPR_MAN1:
+ if (!P_GiveMana(player, MANA_1, 15))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_MANA_1, false);
+ break;
+ case SPR_MAN2:
+ if (!P_GiveMana(player, MANA_2, 15))
+ {
+ return;
+ }
+ P_SetMessage(player, TXT_MANA_2, false);
+ break;
+ case SPR_MAN3: // Double Mana Dodecahedron
+ if (!P_GiveMana(player, MANA_1, 20))
+ {
+ if (!P_GiveMana(player, MANA_2, 20))
+ {
+ return;
+ }
+ }
+ else
+ {
+ P_GiveMana(player, MANA_2, 20);
+ }
+ P_SetMessage(player, TXT_MANA_BOTH, false);
+ break;
+
+ // 2nd and 3rd Mage Weapons
+ case SPR_WMCS: // Frost Shards
+ TryPickupWeapon(player, PCLASS_MAGE, WP_SECOND,
+ special, TXT_WEAPON_M2);
+ return;
+ case SPR_WMLG: // Arc of Death
+ TryPickupWeapon(player, PCLASS_MAGE, WP_THIRD,
+ special, TXT_WEAPON_M3);
+ return;
+
+ // 2nd and 3rd Fighter Weapons
+ case SPR_WFAX: // Timon's Axe
+ TryPickupWeapon(player, PCLASS_FIGHTER, WP_SECOND,
+ special, TXT_WEAPON_F2);
+ return;
+ case SPR_WFHM: // Hammer of Retribution
+ TryPickupWeapon(player, PCLASS_FIGHTER, WP_THIRD,
+ special, TXT_WEAPON_F3);
+ return;
+
+ // 2nd and 3rd Cleric Weapons
+ case SPR_WCSS: // Serpent Staff
+ TryPickupWeapon(player, PCLASS_CLERIC, WP_SECOND,
+ special, TXT_WEAPON_C2);
+ return;
+ case SPR_WCFM: // Firestorm
+ TryPickupWeapon(player, PCLASS_CLERIC, WP_THIRD,
+ special, TXT_WEAPON_C3);
+ return;
+
+ // Fourth Weapon Pieces
+ case SPR_WFR1:
+ TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE1, special);
+ return;
+ case SPR_WFR2:
+ TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE2, special);
+ return;
+ case SPR_WFR3:
+ TryPickupWeaponPiece(player, PCLASS_FIGHTER, WPIECE3, special);
+ return;
+ case SPR_WCH1:
+ TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE1, special);
+ return;
+ case SPR_WCH2:
+ TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE2, special);
+ return;
+ case SPR_WCH3:
+ TryPickupWeaponPiece(player, PCLASS_CLERIC, WPIECE3, special);
+ return;
+ case SPR_WMS1:
+ TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE1, special);
+ return;
+ case SPR_WMS2:
+ TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE2, special);
+ return;
+ case SPR_WMS3:
+ TryPickupWeaponPiece(player, PCLASS_MAGE, WPIECE3, special);
+ return;
+#ifdef ASSASSIN
+ /*
+ // Don't forget to fix this
+ case SPR_WAS1:
+ TryPickupWeaponPiece(player, PCLASS_ASS, WPIECE1, special);
+ return;
+ case SPR_WAS2:
+ TryPickupWeaponPiece(player, PCLASS_ASS, WPIECE2, special);
+ return;
+ case SPR_WAS3:
+ TryPickupWeaponPiece(player,PCLASS_ASS, WPIECE3, special);
+ return;
+ */
+#endif
+ default:
+ I_Error("P_SpecialThing: Unknown gettable thing");
+ }
+ if (special->special)
+ {
+ P_ExecuteLineSpecial(special->special, special->args, NULL,
+ 0, toucher);
+ special->special = 0;
+ }
+ if (deathmatch && respawn && !(special->flags2 & MF2_DROPPED))
+ {
+ P_HideSpecialThing(special);
+ }
+ else
+ {
+ P_RemoveMobj(special);
+ }
+ player->bonuscount += BONUSADD;
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, sound);
+ SB_PaletteFlash(false);
+ }
+}
+
+// Search thinker list for minotaur
+static mobj_t *ActiveMinotaur(player_t *master)
+{
+ mobj_t *mo;
+ player_t *plr;
+ thinker_t *think;
+ int summontime;
+
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ continue;
+ mo = (mobj_t *)think;
+ if (mo->type != MT_MINOTAUR)
+ continue;
+ if (mo->health <= 0)
+ continue;
+ if (!(mo->flags & MF_COUNTKILL))
+ continue; // for morphed minotaurs
+ if (mo->flags & MF_CORPSE)
+ continue;
+ summontime = READ_INT32(mo->args);
+ if ((leveltime - summontime) >= MAULATORTICS)
+ continue;
+ plr = ((mobj_t *)mo->special1)->player;
+ if (plr == master)
+ return mo;
+ }
+ return NULL;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// PROC P_KillMobj
+//
+//---------------------------------------------------------------------------
+
+static void P_KillMobj(mobj_t *source, mobj_t *target)
+{
+ int dummy;
+ mobj_t *master;
+
+ target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY|MF_NOGRAVITY);
+ target->flags |= MF_CORPSE|MF_DROPOFF;
+ target->flags2 &= ~MF2_PASSMOBJ;
+ target->height >>= 2;
+ if ((target->flags & MF_COUNTKILL || target->type == MT_ZBELL) && target->special)
+ { // Initiate monster death actions
+ if (target->type == MT_SORCBOSS)
+ {
+ dummy = 0;
+ P_StartACS(target->special, 0, (byte *)&dummy, target, NULL, 0);
+ }
+ else
+ {
+ P_ExecuteLineSpecial(target->special, target->args, NULL, 0, target);
+ }
+ }
+ if (source && source->player)
+ { // Check for frag changes
+ if (target->player)
+ {
+ if (target == source)
+ { // Self-frag
+ target->player->frags[target->player-players]--;
+ if (cmdfrag && netgame &&
+ source->player == &players[consoleplayer])
+ { // Send out a frag count packet
+ NET_SendFrags(source->player);
+ }
+ }
+ else
+ {
+ source->player->frags[target->player-players]++;
+ if (cmdfrag && netgame &&
+ source->player == &players[consoleplayer])
+ { // Send out a frag count packet
+ NET_SendFrags(source->player);
+ }
+ }
+ }
+ }
+ if (target->player)
+ { // Player death
+ if (!source)
+ { // Self-frag
+ target->player->frags[target->player-players]--;
+ if (cmdfrag && netgame &&
+ target->player == &players[consoleplayer])
+ { // Send out a frag count packet
+ NET_SendFrags(target->player);
+ }
+ }
+ target->flags &= ~MF_SOLID;
+ target->flags2 &= ~MF2_FLY;
+ target->player->powers[pw_flight] = 0;
+ target->player->playerstate = PST_DEAD;
+ P_DropWeapon(target->player);
+ if (target->flags2 & MF2_FIREDAMAGE)
+ { // Player flame death
+ switch (target->player->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_F_FDTH1);
+ return;
+ case PCLASS_CLERIC:
+ S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_C_FDTH1);
+ return;
+ case PCLASS_MAGE:
+ S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_M_FDTH1);
+ return;
+ default:
+ break;
+ }
+ }
+ if (target->flags2 & MF2_ICEDAMAGE)
+ { // Player ice death
+ target->flags &= ~(7<<MF_TRANSSHIFT); //no translation
+ target->flags |= MF_ICECORPSE;
+ switch (target->player->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ P_SetMobjState(target, S_FPLAY_ICE);
+ return;
+ case PCLASS_CLERIC:
+ P_SetMobjState(target, S_CPLAY_ICE);
+ return;
+ case PCLASS_MAGE:
+ P_SetMobjState(target, S_MPLAY_ICE);
+ return;
+ case PCLASS_PIG:
+ P_SetMobjState(target, S_PIG_ICE);
+ return;
+ default:
+ break;
+ }
+ }
+ }
+ if (target->flags2 & MF2_FIREDAMAGE)
+ {
+ if (target->type == MT_FIGHTER_BOSS
+ || target->type == MT_CLERIC_BOSS
+ || target->type == MT_MAGE_BOSS)
+ {
+ switch (target->type)
+ {
+ case MT_FIGHTER_BOSS:
+ S_StartSound(target, SFX_PLAYER_FIGHTER_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_F_FDTH1);
+ return;
+ case MT_CLERIC_BOSS:
+ S_StartSound(target, SFX_PLAYER_CLERIC_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_C_FDTH1);
+ return;
+ case MT_MAGE_BOSS:
+ S_StartSound(target, SFX_PLAYER_MAGE_BURN_DEATH);
+ P_SetMobjState(target, S_PLAY_M_FDTH1);
+ return;
+ default:
+ break;
+ }
+ }
+ else if (target->type == MT_TREEDESTRUCTIBLE)
+ {
+ P_SetMobjState(target, S_ZTREEDES_X1);
+ target->height = 24*FRACUNIT;
+ S_StartSound(target, SFX_TREE_EXPLODE);
+ return;
+ }
+ }
+ if (target->flags2 & MF2_ICEDAMAGE)
+ {
+ target->flags |= MF_ICECORPSE;
+ switch (target->type)
+ {
+ case MT_BISHOP:
+ P_SetMobjState(target, S_BISHOP_ICE);
+ return;
+ case MT_CENTAUR:
+ case MT_CENTAURLEADER:
+ P_SetMobjState(target, S_CENTAUR_ICE);
+ return;
+ case MT_DEMON:
+ case MT_DEMON2:
+ P_SetMobjState(target, S_DEMON_ICE);
+ return;
+ case MT_SERPENT:
+ case MT_SERPENTLEADER:
+ P_SetMobjState(target, S_SERPENT_ICE);
+ return;
+ case MT_WRAITH:
+ case MT_WRAITHB:
+ P_SetMobjState(target, S_WRAITH_ICE);
+ return;
+ case MT_ETTIN:
+ P_SetMobjState(target, S_ETTIN_ICE1);
+ return;
+ case MT_FIREDEMON:
+ P_SetMobjState(target, S_FIRED_ICE1);
+ return;
+ case MT_FIGHTER_BOSS:
+ P_SetMobjState(target, S_FIGHTER_ICE);
+ return;
+ case MT_CLERIC_BOSS:
+ P_SetMobjState(target, S_CLERIC_ICE);
+ return;
+ case MT_MAGE_BOSS:
+ P_SetMobjState(target, S_MAGE_ICE);
+ return;
+ case MT_PIG:
+ P_SetMobjState(target, S_PIG_ICE);
+ return;
+ default:
+ target->flags &= ~MF_ICECORPSE;
+ break;
+ }
+ }
+
+ if (target->type == MT_MINOTAUR)
+ {
+ master = (mobj_t *)target->special1;
+ if (master->health > 0)
+ {
+ if (!ActiveMinotaur(master->player))
+ {
+ master->player->powers[pw_minotaur] = 0;
+ }
+ }
+ }
+ else if (target->type == MT_TREEDESTRUCTIBLE)
+ {
+ target->height = 24*FRACUNIT;
+ }
+ if (target->health < -(target->info->spawnhealth>>1)
+ && target->info->xdeathstate)
+ { // Extreme death
+ P_SetMobjState(target, target->info->xdeathstate);
+ }
+ else
+ { // Normal death
+ if ((target->type==MT_FIREDEMON) &&
+ (target->z <= target->floorz + 2*FRACUNIT) &&
+ (target->info->xdeathstate))
+ {
+ // This is to fix the imps' staying in fall state
+ P_SetMobjState(target, target->info->xdeathstate);
+ }
+ else
+ {
+ P_SetMobjState(target, target->info->deathstate);
+ }
+ }
+ target->tics -= P_Random() & 3;
+// I_StartSound(&actor->r, actor->info->deathsound);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_MinotaurSlam
+//
+//---------------------------------------------------------------------------
+
+static void P_MinotaurSlam(mobj_t *source, mobj_t *target)
+{
+ angle_t angle;
+ fixed_t thrust;
+
+ angle = R_PointToAngle2(source->x, source->y, target->x, target->y);
+ angle >>= ANGLETOFINESHIFT;
+ thrust = 16*FRACUNIT + (P_Random()<<10);
+ target->momx += FixedMul(thrust, finecosine[angle]);
+ target->momy += FixedMul(thrust, finesine[angle]);
+ P_DamageMobj(target, NULL, source, HITDICE(4));
+ if (target->player)
+ {
+ target->reactiontime = 14 + (P_Random() & 7);
+ }
+ source->args[0] = 0; // Stop charging
+}
+
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_MorphPlayer
+//
+// Returns true if the player gets turned into a pig
+//
+//---------------------------------------------------------------------------
+
+boolean P_MorphPlayer(player_t *player)
+{
+ mobj_t *pmo;
+ mobj_t *fog;
+ mobj_t *beastMo;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ angle_t angle;
+ int oldFlags2;
+
+ if (player->powers[pw_invulnerability])
+ { // Immune when invulnerable
+ return false;
+ }
+ if (player->morphTics)
+ { // Player is already a beast
+ return false;
+ }
+ pmo = player->mo;
+ x = pmo->x;
+ y = pmo->y;
+ z = pmo->z;
+ angle = pmo->angle;
+ oldFlags2 = pmo->flags2;
+ P_SetMobjState(pmo, S_FREETARGMOBJ);
+ fog = P_SpawnMobj(x, y, z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ beastMo = P_SpawnMobj(x, y, z, MT_PIGPLAYER);
+ beastMo->special1 = player->readyweapon;
+ beastMo->angle = angle;
+ beastMo->player = player;
+ player->health = beastMo->health = MAXMORPHHEALTH;
+ player->mo = beastMo;
+ memset(&player->armorpoints[0], 0, NUMARMOR*sizeof(int));
+ player->playerclass = PCLASS_PIG;
+ if (oldFlags2 & MF2_FLY)
+ {
+ beastMo->flags2 |= MF2_FLY;
+ }
+ player->morphTics = MORPHTICS;
+ P_ActivateMorphWeapon(player);
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_MorphMonster
+//
+//---------------------------------------------------------------------------
+
+static boolean P_MorphMonster(mobj_t *actor)
+{
+ mobj_t *master, *monster, *fog;
+ mobjtype_t moType;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ mobj_t oldMonster;
+
+ if (actor->player)
+ return false;
+ if (!(actor->flags & MF_COUNTKILL))
+ return false;
+ if (actor->flags2 & MF2_BOSS)
+ return false;
+ moType = actor->type;
+ switch (moType)
+ {
+ case MT_PIG:
+ return false;
+ case MT_FIGHTER_BOSS:
+ case MT_CLERIC_BOSS:
+ case MT_MAGE_BOSS:
+ return false;
+ default:
+ break;
+ }
+
+ oldMonster = *actor;
+ x = oldMonster.x;
+ y = oldMonster.y;
+ z = oldMonster.z;
+ P_RemoveMobjFromTIDList(actor);
+ P_SetMobjState(actor, S_FREETARGMOBJ);
+ fog = P_SpawnMobj(x, y, z+TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ monster = P_SpawnMobj(x, y, z, MT_PIG);
+ monster->special2 = moType;
+ monster->special1 = MORPHTICS + P_Random();
+ monster->flags |= (oldMonster.flags & MF_SHADOW);
+ monster->target = oldMonster.target;
+ monster->angle = oldMonster.angle;
+ monster->tid = oldMonster.tid;
+ monster->special = oldMonster.special;
+ P_InsertMobjIntoTIDList(monster, oldMonster.tid);
+ memcpy(monster->args, oldMonster.args, 5);
+
+ // check for turning off minotaur power for active icon
+ if (moType == MT_MINOTAUR)
+ {
+ master = (mobj_t *)oldMonster.special1;
+ if (master->health > 0)
+ {
+ if (!ActiveMinotaur(master->player))
+ {
+ master->player->powers[pw_minotaur] = 0;
+ }
+ }
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_AutoUseHealth
+//
+//---------------------------------------------------------------------------
+
+static void P_AutoUseHealth(player_t *player, int saveHealth)
+{
+ int i;
+ int count;
+ int normalCount;
+ int normalSlot = 0;
+ int superCount;
+ int superSlot = 0;
+
+ normalCount = superCount = 0;
+ for (i = 0; i < player->inventorySlotNum; i++)
+ {
+ if (player->inventory[i].type == arti_health)
+ {
+ normalSlot = i;
+ normalCount = player->inventory[i].count;
+ }
+ else if (player->inventory[i].type == arti_superhealth)
+ {
+ superSlot = i;
+ superCount = player->inventory[i].count;
+ }
+ }
+ if ((gameskill == sk_baby) && (normalCount*25 >= saveHealth))
+ { // Use quartz flasks
+ count = (saveHealth + 24) / 25;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 25;
+ P_PlayerRemoveArtifact(player, normalSlot);
+ }
+ }
+ else if (superCount*100 >= saveHealth)
+ { // Use mystic urns
+ count = (saveHealth + 99) / 100;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 100;
+ P_PlayerRemoveArtifact(player, superSlot);
+ }
+ }
+ else if ((gameskill == sk_baby) &&
+ (superCount*100 + normalCount*25 >= saveHealth))
+ { // Use mystic urns and quartz flasks
+ count = (saveHealth + 24) / 25;
+ saveHealth -= count * 25;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 25;
+ P_PlayerRemoveArtifact(player, normalSlot);
+ }
+ count = (saveHealth + 99) / 100;
+ for (i = 0; i < count; i++)
+ {
+ player->health += 100;
+ P_PlayerRemoveArtifact(player, normalSlot);
+ }
+ }
+ player->mo->health = player->health;
+}
+
+/*
+=================
+=
+= P_DamageMobj
+=
+= Damages both enemies and players
+= inflictor is the thing that caused the damage
+= creature or missile, can be NULL (slime, etc)
+= source is the thing to target after taking damage
+= creature or NULL
+= Source and inflictor are the same for melee attacks
+= source can be null for barrel explosions and other environmental stuff
+==================
+*/
+
+void P_DamageMobj (mobj_t *target, mobj_t *inflictor, mobj_t *source, int damage)
+{
+ unsigned int ang;
+ int saved;
+ fixed_t savedPercent;
+ player_t *player;
+ mobj_t *master;
+ fixed_t thrust;
+ int i;
+
+ if (!(target->flags & MF_SHOOTABLE))
+ {
+ // Shouldn't happen
+ return;
+ }
+ if (target->health <= 0)
+ {
+ if (inflictor && inflictor->flags2 & MF2_ICEDAMAGE)
+ {
+ return;
+ }
+ else if (target->flags & MF_ICECORPSE) // frozen
+ {
+ target->tics = 1;
+ target->momx = target->momy = 0;
+ }
+ return;
+ }
+ if ((target->flags2 & MF2_INVULNERABLE) && damage < 10000)
+ { // mobj is invulnerable
+ if (target->player)
+ return; // for player, no exceptions
+ if (inflictor)
+ {
+ switch (inflictor->type)
+ {
+ // These inflictors aren't foiled by invulnerability
+ case MT_HOLY_FX:
+ case MT_POISONCLOUD:
+ case MT_FIREBOMB:
+ break;
+ default:
+ return;
+ }
+ }
+ else
+ {
+ return;
+ }
+ }
+ if (target->player)
+ {
+ if (damage < 1000 &&
+ ((target->player->cheats & CF_GODMODE) ||
+ target->player->powers[pw_invulnerability]))
+ {
+ return;
+ }
+ }
+ if (target->flags & MF_SKULLFLY)
+ {
+ target->momx = target->momy = target->momz = 0;
+ }
+ if (target->flags2 & MF2_DORMANT)
+ {
+ // Invulnerable, and won't wake up
+ return;
+ }
+ player = target->player;
+ if (player && gameskill == sk_baby)
+ {
+ // Take half damage in trainer mode
+ damage >>= 1;
+ }
+ // Special damage types
+ if (inflictor)
+ {
+ switch (inflictor->type)
+ {
+ case MT_EGGFX:
+ if (player)
+ {
+ P_MorphPlayer(player);
+ }
+ else
+ {
+ P_MorphMonster(target);
+ }
+ return; // Always return
+ case MT_TELOTHER_FX1:
+ case MT_TELOTHER_FX2:
+ case MT_TELOTHER_FX3:
+ case MT_TELOTHER_FX4:
+ case MT_TELOTHER_FX5:
+ if ((target->flags & MF_COUNTKILL) &&
+ (target->type != MT_SERPENT) &&
+ (target->type != MT_SERPENTLEADER) &&
+ (!(target->flags2 & MF2_BOSS)))
+ {
+ P_TeleportOther(target);
+ }
+ return;
+ case MT_MINOTAUR:
+ if (inflictor->flags & MF_SKULLFLY)
+ { // Slam only when in charge mode
+ P_MinotaurSlam(inflictor, target);
+ return;
+ }
+ break;
+ case MT_BISH_FX:
+ // Bishops are just too nasty
+ damage >>= 1;
+ break;
+ case MT_SHARDFX1:
+ switch (inflictor->special2)
+ {
+ case 3:
+ damage <<= 3;
+ break;
+ case 2:
+ damage <<= 2;
+ break;
+ case 1:
+ damage <<= 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case MT_CSTAFF_MISSILE:
+ // Cleric Serpent Staff does poison damage
+ if (target->player)
+ {
+ P_PoisonPlayer(target->player, source, 20);
+ damage >>= 1;
+ }
+ break;
+ case MT_ICEGUY_FX2:
+ damage >>= 1;
+ break;
+ case MT_POISONDART:
+ if (target->player)
+ {
+ P_PoisonPlayer(target->player, source, 20);
+ damage >>= 1;
+ }
+ break;
+ case MT_POISONCLOUD:
+ if (target->player)
+ {
+ if (target->player->poisoncount < 4)
+ {
+ P_PoisonDamage(target->player, source,
+ 15 + (P_Random() & 15), false); // Don't play painsound
+ P_PoisonPlayer(target->player, source, 50);
+ S_StartSound(target, SFX_PLAYER_POISONCOUGH);
+ }
+ return;
+ }
+ else if (!(target->flags & MF_COUNTKILL))
+ { // only damage monsters/players with the poison cloud
+ return;
+ }
+ break;
+ case MT_FSWORD_MISSILE:
+ if (target->player)
+ {
+ damage -= damage>>2;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ // Push the target unless source is using the gauntlets
+ if (inflictor && (!source || !source->player) &&
+ !(inflictor->flags2 & MF2_NODMGTHRUST))
+ {
+ ang = R_PointToAngle2(inflictor->x, inflictor->y, target->x, target->y);
+ //thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
+ thrust = damage*(FRACUNIT>>3)*150/target->info->mass;
+ // make fall forwards sometimes
+ if ((damage < 40) && (damage > target->health) &&
+ (target->z-inflictor->z > 64*FRACUNIT) && (P_Random() & 1))
+ {
+ ang += ANG180;
+ thrust *= 4;
+ }
+ ang >>= ANGLETOFINESHIFT;
+ target->momx += FixedMul(thrust, finecosine[ang]);
+ target->momy += FixedMul(thrust, finesine[ang]);
+ }
+
+ //
+ // player specific
+ //
+ if (player)
+ {
+ savedPercent = AutoArmorSave[player->playerclass]
+ + player->armorpoints[ARMOR_ARMOR]
+ + player->armorpoints[ARMOR_SHIELD]
+ + player->armorpoints[ARMOR_HELMET]
+ + player->armorpoints[ARMOR_AMULET];
+ if (savedPercent)
+ { // armor absorbed some damage
+ if (savedPercent > 100*FRACUNIT)
+ {
+ savedPercent = 100*FRACUNIT;
+ }
+ for (i = 0; i < NUMARMOR; i++)
+ {
+ if (player->armorpoints[i])
+ {
+ player->armorpoints[i] -=
+ FixedDiv(FixedMul(damage<<FRACBITS,
+ ArmorIncrement[player->playerclass][i]),
+ 300 * FRACUNIT);
+ if (player->armorpoints[i] < 2*FRACUNIT)
+ {
+ player->armorpoints[i] = 0;
+ }
+ }
+ }
+ saved = FixedDiv(FixedMul(damage<<FRACBITS, savedPercent), 100 * FRACUNIT);
+ if (saved > savedPercent * 2)
+ {
+ saved = savedPercent * 2;
+ }
+ damage -= saved>>FRACBITS;
+ }
+ if (damage >= player->health &&
+ ((gameskill == sk_baby) || deathmatch) &&
+ !player->morphTics)
+ { // Try to use some inventory health
+ P_AutoUseHealth(player, damage-player->health + 1);
+ }
+ player->health -= damage; // mirror mobj health here for Dave
+ if (player->health < 0)
+ {
+ player->health = 0;
+ }
+ player->attacker = source;
+ player->damagecount += damage; // add damage after armor / invuln
+ if (player->damagecount > 100)
+ {
+ player->damagecount = 100; // teleport stomp does 10k points...
+ }
+ if (player == &players[consoleplayer])
+ {
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+ int temp = damage < 100 ? damage : 100;
+ I_Tactile(40, 10, 40 + temp*2);
+#endif /* externdriver, DOS */
+ SB_PaletteFlash(false);
+ }
+ }
+
+ //
+ // do the damage
+ //
+ target->health -= damage;
+ if (target->health <= 0)
+ { // Death
+ if (inflictor)
+ { // check for special fire damage or ice damage deaths
+ if (inflictor->flags2 & MF2_FIREDAMAGE)
+ {
+ if (player && !player->morphTics)
+ { // Check for flame death
+ if (target->health > -50 && damage > 25)
+ {
+ target->flags2 |= MF2_FIREDAMAGE;
+ }
+ }
+ else
+ {
+ target->flags2 |= MF2_FIREDAMAGE;
+ }
+ }
+ else if (inflictor->flags2 & MF2_ICEDAMAGE)
+ {
+ target->flags2 |= MF2_ICEDAMAGE;
+ }
+ }
+ if (source && (source->type == MT_MINOTAUR))
+ { // Minotaur's kills go to his master
+ master = (mobj_t *)(source->special1);
+ // Make sure still alive and not a pointer to fighter head
+ if (master->player && (master->player->mo == master))
+ {
+ source = master;
+ }
+ }
+ if (source && (source->player) &&
+ (source->player->readyweapon == WP_FOURTH))
+ {
+ // Always extreme death from fourth weapon
+ target->health = -5000;
+ }
+ P_KillMobj(source, target);
+ return;
+ }
+ if ((P_Random() < target->info->painchance)
+ && !(target->flags & MF_SKULLFLY))
+ {
+ if (inflictor && (inflictor->type >= MT_LIGHTNING_FLOOR
+ && inflictor->type <= MT_LIGHTNING_ZAP))
+ {
+ if (P_Random() < 96)
+ {
+ target->flags |= MF_JUSTHIT; // fight back!
+ P_SetMobjState(target, target->info->painstate);
+ }
+ else
+ { // "electrocute" the target
+ target->frame |= FF_FULLBRIGHT;
+ if (target->flags & MF_COUNTKILL && P_Random() < 128 &&
+ !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT))
+ {
+ if ((target->type == MT_CENTAUR) ||
+ (target->type == MT_CENTAURLEADER) ||
+ (target->type == MT_ETTIN))
+ {
+ S_StartSound(target, SFX_PUPPYBEAT);
+ }
+ }
+ }
+ }
+ else
+ {
+ target->flags |= MF_JUSTHIT; // fight back!
+ P_SetMobjState(target, target->info->painstate);
+ if (inflictor && inflictor->type == MT_POISONCLOUD)
+ {
+ if (target->flags & MF_COUNTKILL && P_Random() < 128 &&
+ !S_GetSoundPlayingInfo(target, SFX_PUPPYBEAT))
+ {
+ if ((target->type == MT_CENTAUR) ||
+ (target->type == MT_CENTAURLEADER) ||
+ (target->type == MT_ETTIN))
+ {
+ S_StartSound(target, SFX_PUPPYBEAT);
+ }
+ }
+ }
+ }
+ }
+ target->reactiontime = 0; // we're awake now...
+ if (!target->threshold && source && !(source->flags2 & MF2_BOSS) &&
+ !(target->type == MT_BISHOP) && !(target->type == MT_MINOTAUR))
+ {
+ // Target actor is not intent on another actor,
+ // so make him chase after source
+ if ((target->type == MT_CENTAUR && source->type == MT_CENTAURLEADER) ||
+ (target->type == MT_CENTAURLEADER && source->type == MT_CENTAUR))
+ {
+ return;
+ }
+ target->target = source;
+ target->threshold = BASETHRESHOLD;
+ if (target->state == &states[target->info->spawnstate]
+ && target->info->seestate != S_NULL)
+ {
+ P_SetMobjState(target, target->info->seestate);
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_FallingDamage
+//
+//==========================================================================
+
+void P_FallingDamage(player_t *player)
+{
+ int damage;
+ int mom;
+ int dist;
+
+ mom = abs(player->mo->momz);
+ dist = FixedMul(mom, 16*FRACUNIT/23);
+
+ if (mom >= 63*FRACUNIT)
+ { // automatic death
+ P_DamageMobj(player->mo, NULL, NULL, 10000);
+ return;
+ }
+ damage = ((FixedMul(dist, dist)/10)>>FRACBITS) - 24;
+ if (player->mo->momz > -39*FRACUNIT && damage > player->mo->health
+ && player->mo->health != 1)
+ { // No-death threshold
+ damage = player->mo->health - 1;
+ }
+ S_StartSound(player->mo, SFX_PLAYER_LAND);
+ P_DamageMobj(player->mo, NULL, NULL, damage);
+}
+
+//==========================================================================
+//
+// P_PoisonPlayer - Sets up all data concerning poisoning
+//
+//==========================================================================
+
+void P_PoisonPlayer(player_t *player, mobj_t *poisoner, int poison)
+{
+ if ((player->cheats&CF_GODMODE) || player->powers[pw_invulnerability])
+ {
+ return;
+ }
+ player->poisoncount += poison;
+ player->poisoner = poisoner;
+ if (player->poisoncount > 100)
+ {
+ player->poisoncount = 100;
+ }
+}
+
+//==========================================================================
+//
+// P_PoisonDamage - Similar to P_DamageMobj
+//
+//==========================================================================
+
+void P_PoisonDamage(player_t *player, mobj_t *source, int damage,
+ boolean playPainSound)
+{
+ mobj_t *target;
+ mobj_t *inflictor;
+
+ target = player->mo;
+ inflictor = source;
+ if (target->health <= 0)
+ {
+ return;
+ }
+ if (target->flags2 & MF2_INVULNERABLE && damage < 10000)
+ { // mobj is invulnerable
+ return;
+ }
+ if (player && gameskill == sk_baby)
+ {
+ // Take half damage in trainer mode
+ damage >>= 1;
+ }
+ if (damage < 1000 && ((player->cheats & CF_GODMODE)
+ || player->powers[pw_invulnerability]))
+ {
+ return;
+ }
+ if (damage >= player->health
+ && ((gameskill == sk_baby) || deathmatch)
+ && !player->morphTics)
+ { // Try to use some inventory health
+ P_AutoUseHealth(player, damage-player->health + 1);
+ }
+ player->health -= damage; // mirror mobj health here for Dave
+ if (player->health < 0)
+ {
+ player->health = 0;
+ }
+ player->attacker = source;
+
+ //
+ // do the damage
+ //
+ target->health -= damage;
+ if (target->health <= 0)
+ { // Death
+ target->special1 = damage;
+ if (player && inflictor && !player->morphTics)
+ { // Check for flame death
+ if ((inflictor->flags2 & MF2_FIREDAMAGE)
+ && (target->health > -50) && (damage > 25))
+ {
+ target->flags2 |= MF2_FIREDAMAGE;
+ }
+ if (inflictor->flags2 & MF2_ICEDAMAGE)
+ {
+ target->flags2 |= MF2_ICEDAMAGE;
+ }
+ }
+ P_KillMobj(source, target);
+ return;
+ }
+ if (!(leveltime & 63) && playPainSound)
+ {
+ P_SetMobjState(target, target->info->painstate);
+ }
+ /*
+ if ((P_Random() < target->info->painchance)
+ && !(target->flags & MF_SKULLFLY))
+ {
+ target->flags |= MF_JUSTHIT; // fight back!
+ P_SetMobjState(target, target->info->painstate);
+ }
+ */
+}
+
--- /dev/null
+++ b/p_lights.c
@@ -1,0 +1,345 @@
+
+//**************************************************************************
+//**
+//** p_lights.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+//============================================================================
+//
+// T_Light
+//
+//============================================================================
+
+void T_Light(light_t *light)
+{
+ if (light->count)
+ {
+ light->count--;
+ return;
+ }
+ switch (light->type)
+ {
+ case LITE_FADE:
+ light->sector->lightlevel = ((light->sector->lightlevel<<FRACBITS)
+ + light->value2)>>FRACBITS;
+ if (light->tics2 == 1)
+ {
+ if (light->sector->lightlevel >= light->value1)
+ {
+ light->sector->lightlevel = light->value1;
+ P_RemoveThinker(&light->thinker);
+ }
+ }
+ else if (light->sector->lightlevel <= light->value1)
+ {
+ light->sector->lightlevel = light->value1;
+ P_RemoveThinker(&light->thinker);
+ }
+ break;
+ case LITE_GLOW:
+ light->sector->lightlevel = ((light->sector->lightlevel<<FRACBITS)
+ + light->tics1)>>FRACBITS;
+ if (light->tics2 == 1)
+ {
+ if (light->sector->lightlevel >= light->value1)
+ {
+ light->sector->lightlevel = light->value1;
+ light->tics1 = -light->tics1;
+ light->tics2 = -1; // reverse direction
+ }
+ }
+ else if (light->sector->lightlevel <= light->value2)
+ {
+ light->sector->lightlevel = light->value2;
+ light->tics1 = -light->tics1;
+ light->tics2 = 1; // reverse direction
+ }
+ break;
+ case LITE_FLICKER:
+ if (light->sector->lightlevel == light->value1)
+ {
+ light->sector->lightlevel = light->value2;
+ light->count = (P_Random() & 7) + 1;
+ }
+ else
+ {
+ light->sector->lightlevel = light->value1;
+ light->count = (P_Random() & 31) + 1;
+ }
+ break;
+ case LITE_STROBE:
+ if (light->sector->lightlevel == light->value1)
+ {
+ light->sector->lightlevel = light->value2;
+ light->count = light->tics2;
+ }
+ else
+ {
+ light->sector->lightlevel = light->value1;
+ light->count = light->tics1;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+//============================================================================
+//
+// EV_SpawnLight
+//
+//============================================================================
+
+boolean EV_SpawnLight(line_t *line, byte *arg, lighttype_t type)
+{
+ light_t *light;
+ sector_t *sec;
+ int secNum;
+ int arg1, arg2, arg3, arg4;
+ boolean think;
+ boolean rtn;
+
+ arg1 = arg[1];
+ arg2 = arg[2];
+ arg3 = arg[3];
+ arg4 = arg[4];
+
+ secNum = -1;
+ rtn = false;
+ think = false;
+ while ((secNum = P_FindSectorFromTag(arg[0], secNum)) >= 0)
+ {
+ think = false;
+ sec = §ors[secNum];
+
+ light = (light_t *)Z_Malloc(sizeof(light_t), PU_LEVSPEC, NULL);
+ light->type = type;
+ light->sector = sec;
+ light->count = 0;
+ rtn = true;
+ switch (type)
+ {
+ case LITE_RAISEBYVALUE:
+ sec->lightlevel += arg1;
+ if (sec->lightlevel > 255)
+ {
+ sec->lightlevel = 255;
+ }
+ break;
+ case LITE_LOWERBYVALUE:
+ sec->lightlevel -= arg1;
+ if (sec->lightlevel < 0)
+ {
+ sec->lightlevel = 0;
+ }
+ break;
+ case LITE_CHANGETOVALUE:
+ sec->lightlevel = arg1;
+ if (sec->lightlevel < 0)
+ {
+ sec->lightlevel = 0;
+ }
+ else if (sec->lightlevel > 255)
+ {
+ sec->lightlevel = 255;
+ }
+ break;
+ case LITE_FADE:
+ think = true;
+ light->value1 = arg1; // destination lightlevel
+ light->value2 = FixedDiv((arg1 - sec->lightlevel)<<FRACBITS, arg2<<FRACBITS); // delta lightlevel
+ if (sec->lightlevel <= arg1)
+ {
+ light->tics2 = 1; // get brighter
+ }
+ else
+ {
+ light->tics2 = -1;
+ }
+ break;
+ case LITE_GLOW:
+ think = true;
+ light->value1 = arg1; // upper lightlevel
+ light->value2 = arg2; // lower lightlevel
+ light->tics1 = FixedDiv((arg1 - sec->lightlevel)<<FRACBITS, arg3<<FRACBITS); // lightlevel delta
+ if (sec->lightlevel <= arg1)
+ {
+ light->tics2 = 1; // get brighter
+ }
+ else
+ {
+ light->tics2 = -1;
+ }
+ break;
+ case LITE_FLICKER:
+ think = true;
+ light->value1 = arg1; // upper lightlevel
+ light->value2 = arg2; // lower lightlevel
+ sec->lightlevel = light->value1;
+ light->count = (P_Random() & 64) + 1;
+ break;
+ case LITE_STROBE:
+ think = true;
+ light->value1 = arg1; // upper lightlevel
+ light->value2 = arg2; // lower lightlevel
+ light->tics1 = arg3; // upper tics
+ light->tics2 = arg4; // lower tics
+ light->count = arg3;
+ sec->lightlevel = light->value1;
+ break;
+ default:
+ rtn = false;
+ break;
+ }
+ if (think)
+ {
+ P_AddThinker(&light->thinker);
+ light->thinker.function = T_Light;
+ }
+ else
+ {
+ Z_Free(light);
+ }
+ }
+ return rtn;
+}
+
+//============================================================================
+//
+// T_Phase
+//
+//============================================================================
+
+static int PhaseTable[64] =
+{
+ 128, 112, 96, 80, 64, 48, 32, 32,
+ 16, 16, 16, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 16, 16, 16,
+ 32, 32, 48, 64, 80, 96, 112, 128
+};
+
+void T_Phase(phase_t *phase)
+{
+ phase->index = (phase->index + 1) & 63;
+ phase->sector->lightlevel = phase->base + PhaseTable[phase->index];
+}
+
+//==========================================================================
+//
+// P_SpawnPhasedLight
+//
+//==========================================================================
+
+void P_SpawnPhasedLight(sector_t *sector, int base, int idx)
+{
+ phase_t *phase;
+
+ phase = (phase_t *) Z_Malloc(sizeof(*phase), PU_LEVSPEC, NULL);
+ P_AddThinker(&phase->thinker);
+ phase->sector = sector;
+ if (idx == -1)
+ { // sector->lightlevel as the index
+ phase->index = sector->lightlevel & 63;
+ }
+ else
+ {
+ phase->index = idx & 63;
+ }
+ phase->base = base & 255;
+ sector->lightlevel = phase->base + PhaseTable[phase->index];
+ phase->thinker.function = T_Phase;
+
+ sector->special = 0;
+}
+
+//==========================================================================
+//
+// P_SpawnLightSequence
+//
+//==========================================================================
+
+void P_SpawnLightSequence(sector_t *sector, int indexStep)
+{
+ sector_t *sec;
+ sector_t *nextSec;
+ sector_t *tempSec;
+ int seqSpecial;
+ int i;
+ int count;
+ fixed_t idx;
+ fixed_t indexDelta;
+ int base;
+
+ seqSpecial = LIGHT_SEQUENCE; // look for Light_Sequence, first
+ sec = sector;
+ count = 1;
+ do
+ {
+ nextSec = NULL;
+ sec->special = LIGHT_SEQUENCE_START; // make sure that the search doesn't back up.
+ for (i = 0; i < sec->linecount; i++)
+ {
+ tempSec = getNextSector(sec->lines[i], sec);
+ if (!tempSec)
+ {
+ continue;
+ }
+ if (tempSec->special == seqSpecial)
+ {
+ if (seqSpecial == LIGHT_SEQUENCE)
+ {
+ seqSpecial = LIGHT_SEQUENCE_ALT;
+ }
+ else
+ {
+ seqSpecial = LIGHT_SEQUENCE;
+ }
+ nextSec = tempSec;
+ count++;
+ }
+ }
+ sec = nextSec;
+ } while (sec);
+
+ sec = sector;
+ count *= indexStep;
+ idx = 0;
+ indexDelta = FixedDiv(64*FRACUNIT, count*FRACUNIT);
+ base = sector->lightlevel;
+ do
+ {
+ nextSec = NULL;
+ if (sec->lightlevel)
+ {
+ base = sec->lightlevel;
+ }
+ P_SpawnPhasedLight(sec, base, idx>>FRACBITS);
+ idx += indexDelta;
+ for (i = 0; i < sec->linecount; i++)
+ {
+ tempSec = getNextSector(sec->lines[i], sec);
+ if (!tempSec)
+ {
+ continue;
+ }
+ if (tempSec->special == LIGHT_SEQUENCE_START)
+ {
+ nextSec = tempSec;
+ }
+ }
+ sec = nextSec;
+ } while (sec);
+}
+
--- /dev/null
+++ b/p_local.h
@@ -1,0 +1,378 @@
+
+//**************************************************************************
+//**
+//** p_local.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __P_LOCAL__
+#define __P_LOCAL__
+
+#ifndef __R_LOCAL__
+#include "r_local.h"
+#endif
+
+#define STARTREDPALS 1
+#define STARTBONUSPALS 9
+#define STARTPOISONPALS 13
+#define STARTICEPAL 21
+#define STARTHOLYPAL 22
+#define STARTSCOURGEPAL 25
+#define NUMREDPALS 8
+#define NUMBONUSPALS 4
+#define NUMPOISONPALS 8
+
+#define TOCENTER -8
+#define FLOATSPEED (FRACUNIT * 4)
+
+#define MAXHEALTH 100
+#define MAXMORPHHEALTH 30
+#define VIEWHEIGHT (48 * FRACUNIT)
+
+/* mapblocks are used to check movement against lines and things */
+#define MAPBLOCKUNITS 128
+#define MAPBLOCKSIZE (MAPBLOCKUNITS * FRACUNIT)
+#define MAPBLOCKSHIFT (FRACBITS + 7)
+#define MAPBMASK (MAPBLOCKSIZE - 1)
+#define MAPBTOFRAC (MAPBLOCKSHIFT - FRACBITS)
+
+/* player radius for movement checking */
+#define PLAYERRADIUS (16 * FRACUNIT)
+
+/* MAXRADIUS is for precalculated sector block boxes
+ * the spider demon is larger, but we don't have any
+ * moving sectors nearby
+ */
+#define MAXRADIUS (32 * FRACUNIT)
+
+#define GRAVITY FRACUNIT
+#define MAXMOVE (30 * FRACUNIT)
+
+#define USERANGE (64 * FRACUNIT)
+#define MELEERANGE (64 * FRACUNIT)
+#define MISSILERANGE (32 * 64 * FRACUNIT)
+
+typedef enum
+{
+ DI_EAST,
+ DI_NORTHEAST,
+ DI_NORTH,
+ DI_NORTHWEST,
+ DI_WEST,
+ DI_SOUTHWEST,
+ DI_SOUTH,
+ DI_SOUTHEAST,
+ DI_NODIR,
+ NUMDIRS
+} dirtype_t;
+
+#define BASETHRESHOLD 100 /* follow a player exlusively for 3 seconds */
+
+
+/* ---- P_TICK ---- */
+
+extern thinker_t thinkercap; /* both the head and tail of the thinker list */
+extern int TimerGame; /* tic countdown for deathmatch */
+
+void P_InitThinkers(void);
+void P_AddThinker(thinker_t *thinker);
+void P_RemoveThinker(thinker_t *thinker);
+
+
+/* ---- P_PSPR ---- */
+
+#define USE_MANA1 1
+#define USE_MANA2 1
+
+void P_SetPsprite(player_t *player, int position, statenum_t stnum);
+void P_SetPspriteNF(player_t *player, int position, statenum_t stnum);
+void P_SetupPsprites(player_t *curplayer);
+void P_MovePsprites(player_t *curplayer);
+void P_DropWeapon(player_t *player);
+void P_ActivateMorphWeapon(player_t *player);
+void P_PostMorphWeapon(player_t *player, weapontype_t weapon);
+
+
+/* ---- P_USER ---- */
+
+extern int PStateNormal[NUMCLASSES];
+extern int PStateRun[NUMCLASSES];
+extern int PStateAttack[NUMCLASSES];
+extern int PStateAttackEnd[NUMCLASSES];
+
+void P_PlayerThink(player_t *player);
+void P_Thrust(player_t *player, angle_t angle, fixed_t move);
+void P_PlayerRemoveArtifact(player_t *player, int slot);
+void P_PlayerUseArtifact(player_t *player, artitype_t arti);
+boolean P_UseArtifact(player_t *player, artitype_t arti);
+int P_GetPlayerNum(player_t *player);
+void P_TeleportOther(mobj_t *victim);
+void ResetBlasted(mobj_t *mo);
+
+
+/* ---- P_MOBJ ---- */
+
+/* Any floor type >= FLOOR_LIQUID will floorclip sprites */
+enum
+{
+ FLOOR_SOLID,
+ FLOOR_ICE,
+ FLOOR_LIQUID,
+ FLOOR_WATER,
+ FLOOR_LAVA,
+ FLOOR_SLUDGE
+};
+
+#define ONFLOORZ H2MININT
+#define ONCEILINGZ H2MAXINT
+#define FLOATRANDZ (H2MAXINT - 1)
+#define FROMCEILINGZ128 (H2MAXINT - 2)
+
+extern mobjtype_t PuffType;
+extern mobj_t *MissileMobj;
+
+mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
+void P_RemoveMobj(mobj_t *th);
+boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
+boolean P_SetMobjStateNF(mobj_t *mobj, statenum_t state);
+void P_ThrustMobj(mobj_t *mo, angle_t angle, fixed_t move);
+int P_FaceMobj(mobj_t *source, mobj_t *target, angle_t *delta);
+boolean P_SeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax);
+void P_MobjThinker(mobj_t *mobj);
+void P_BlasterMobjThinker(mobj_t *mobj);
+void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z);
+void P_SpawnBlood(fixed_t x, fixed_t y, fixed_t z, int damage);
+void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator);
+void P_BloodSplatter2(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator);
+void P_RipperBlood(mobj_t *mo);
+int P_GetThingFloorType(mobj_t *thing);
+int P_HitFloor(mobj_t *thing);
+boolean P_CheckMissileSpawn(mobj_t *missile);
+mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type);
+mobj_t *P_SpawnMissileXYZ(fixed_t x, fixed_t y, fixed_t z, mobj_t *source, mobj_t *dest, mobjtype_t type);
+mobj_t *P_SpawnMissileAngle(mobj_t *source, mobjtype_t type, angle_t angle, fixed_t momz);
+mobj_t *P_SpawnMissileAngleSpeed(mobj_t *source, mobjtype_t type, angle_t angle, fixed_t momz, fixed_t speed);
+mobj_t *P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type);
+mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle);
+mobj_t *P_SPMAngleXYZ(mobj_t *source, fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, angle_t angle);
+void P_CreateTIDList(void);
+void P_RemoveMobjFromTIDList(mobj_t *mobj);
+void P_InsertMobjIntoTIDList(mobj_t *mobj, int tid);
+mobj_t *P_FindMobjFromTID(int tid, int *searchPosition);
+mobj_t *P_SpawnKoraxMissile(fixed_t x, fixed_t y, fixed_t z, mobj_t *source, mobj_t *dest, mobjtype_t type);
+
+
+/* ---- P_ENEMY ---- */
+
+void P_NoiseAlert (mobj_t *target, mobj_t *emmiter);
+int P_Massacre(void);
+boolean A_RaiseMobj(mobj_t *actor);
+boolean A_SinkMobj(mobj_t *actor);
+void A_NoBlocking(mobj_t *actor);
+void P_InitCreatureCorpseQueue(boolean corpseScan);
+void A_DeQueueCorpse(mobj_t *actor);
+
+
+/* ---- P_MAPUTL ---- */
+
+typedef struct
+{
+ fixed_t x, y, dx, dy;
+} divline_t;
+
+#ifdef RENDER3D
+typedef struct
+{
+ float x, y, dx, dy;
+} fdivline_t;
+#endif
+
+typedef struct
+{
+ fixed_t frac; /* along trace line */
+ boolean isaline;
+ union {
+ mobj_t *thing;
+ line_t *line;
+ } d;
+} intercept_t;
+
+#define MAXINTERCEPTS 128
+extern intercept_t intercepts[MAXINTERCEPTS], *intercept_p;
+
+typedef boolean (*traverser_t) (intercept_t *in);
+
+fixed_t P_AproxDistance (fixed_t dx, fixed_t dy);
+int P_PointOnLineSide (fixed_t x, fixed_t y, line_t *line);
+int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t *line);
+void P_MakeDivline (line_t *li, divline_t *dl);
+fixed_t P_InterceptVector (divline_t *v2, divline_t *v1);
+int P_BoxOnLineSide (fixed_t *tmbox, line_t *ld);
+
+extern fixed_t opentop, openbottom, openrange;
+extern fixed_t lowfloor;
+
+void P_LineOpening (line_t *ld);
+
+boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*));
+boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*));
+
+#define PT_ADDLINES 1
+#define PT_ADDTHINGS 2
+#define PT_EARLYOUT 4
+
+extern divline_t trace;
+
+boolean P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, boolean (*trav) (intercept_t *));
+void P_UnsetThingPosition (mobj_t *thing);
+void P_SetThingPosition (mobj_t *thing);
+mobj_t *P_RoughMonsterSearch(mobj_t *mo, int distance);
+
+
+/* ---- P_MAP ---- */
+
+extern boolean floatok; /* if true, move would be ok if */
+extern fixed_t tmfloorz, tmceilingz; /* within tmfloorz - tmceilingz */
+extern int tmfloorpic;
+extern mobj_t *BlockingMobj;
+extern line_t *ceilingline;
+extern mobj_t *PuffSpawned; /* true if a puff was spawned */
+extern mobj_t *linetarget; /* who got hit (or NULL) */
+
+boolean P_TestMobjLocation(mobj_t *mobj);
+boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y);
+mobj_t *P_CheckOnmobj(mobj_t *thing);
+void P_FakeZMovement(mobj_t *mo);
+boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y);
+boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y);
+void P_SlideMove(mobj_t *mo);
+void P_BounceWall(mobj_t *mo);
+boolean P_CheckSight(mobj_t *t1, mobj_t *t2);
+void P_UseLines(player_t *player);
+boolean P_UsePuzzleItem(player_t *player, int itemType);
+void PIT_ThrustSpike(mobj_t *actor);
+boolean P_ChangeSector (sector_t *sector, int crunch);
+fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance);
+void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage);
+void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage, int distance, boolean damageSource);
+
+
+/* ---- P_SETUP ---- */
+
+extern byte *rejectmatrix; /* for fast sight rejection */
+extern short *blockmaplump; /* offsets in blockmap are from here */
+extern short *blockmap;
+extern int bmapwidth, bmapheight; /* in mapblocks */
+extern fixed_t bmaporgx, bmaporgy; /* origin of block map */
+extern mobj_t **blocklinks; /* for thing chains */
+
+
+/* ---- P_INTER ---- */
+
+extern int clipmana[NUMMANA];
+
+void P_SetMessage(player_t *player, const char *message, boolean ultmsg);
+void P_SetYellowMessage(player_t *player, const char *message, boolean ultmsg);
+void P_ClearMessage(player_t *player);
+void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher);
+void P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, int damage);
+void P_FallingDamage(player_t *player);
+void P_PoisonPlayer(player_t *player, mobj_t *poisoner, int poison);
+void P_PoisonDamage(player_t *player, mobj_t *source, int damage, boolean playPainSound);
+boolean P_GiveMana(player_t *player, manatype_t mana, int count);
+boolean P_GiveArtifact(player_t *player, artitype_t arti, mobj_t *mo);
+boolean P_GiveArmor(player_t *player, armortype_t armortype, int amount);
+boolean P_GiveBody(player_t *player, int num);
+boolean P_GivePower(player_t *player, powertype_t power);
+boolean P_MorphPlayer(player_t *player);
+
+
+/* ---- AM_MAP ---- */
+
+boolean AM_Responder(event_t *ev);
+void AM_Ticker(void);
+void AM_Drawer(void);
+
+
+/* ---- A_ACTION ---- */
+
+boolean A_LocalQuake(byte *args, mobj_t *victim);
+void P_SpawnDirt(mobj_t *actor, fixed_t radius);
+void A_BridgeRemove(mobj_t *actor);
+
+
+/* ---- SB_BAR ---- */
+
+extern int SB_state;
+extern int ArtifactFlash;
+
+void SB_PaletteFlash(boolean forceChange);
+
+
+/* ---- PO_MAN ---- */
+
+typedef enum
+{
+ PODOOR_NONE,
+ PODOOR_SLIDE,
+ PODOOR_SWING
+} podoortype_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ int polyobj;
+ int speed;
+ unsigned int dist;
+ int angle;
+ fixed_t xSpeed; /* for sliding walls */
+ fixed_t ySpeed;
+} polyevent_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ int polyobj;
+ int speed;
+ int dist;
+ int totalDist;
+ int direction;
+ fixed_t xSpeed, ySpeed;
+ int tics;
+ int waitTics;
+ podoortype_t type;
+ boolean close;
+} polydoor_t;
+
+enum
+{
+ PO_ANCHOR_TYPE = 3000,
+ PO_SPAWN_TYPE,
+ PO_SPAWNCRUSH_TYPE
+};
+
+#define PO_LINE_START 1 /* polyobj line start special */
+#define PO_LINE_EXPLICIT 5
+
+extern polyobj_t *polyobjs; /* list of all poly-objects on the level */
+extern int po_NumPolyobjs;
+
+void T_PolyDoor(polydoor_t *pd);
+void T_RotatePoly(polyevent_t *pe);
+boolean EV_RotatePoly(line_t *line, byte *args, int direction, boolean overRide);
+void T_MovePoly(polyevent_t *pe);
+boolean EV_MovePoly(line_t *line, byte *args, boolean timesEight, boolean overRide);
+boolean EV_OpenPolyDoor(line_t *line, byte *args, podoortype_t type);
+
+boolean PO_MovePolyobj(int num, int x, int y);
+boolean PO_RotatePolyobj(int num, angle_t angle);
+void PO_Init(int lump);
+boolean PO_Busy(int polyobj);
+
+#include "p_spec.h"
+
+#endif /* __P_LOCAL__ */
+
--- /dev/null
+++ b/p_map.c
@@ -1,0 +1,2325 @@
+
+//**************************************************************************
+//**
+//** p_map.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+/*
+===============================================================================
+
+NOTES:
+
+===============================================================================
+*/
+
+/*
+===============================================================================
+
+mobj_t NOTES
+
+mobj_ts are used to tell the refresh where to draw an image, tell the world
+simulation when objects are contacted, and tell the sound driver how to
+position a sound.
+
+The refresh uses the next and prev links to follow lists of things in sectors
+as they are being drawn. The sprite, frame, and angle elements determine
+which patch_t is used to draw the sprite if it is visible. The sprite and
+frame values are allmost allways set from state_t structures.
+The statescr.exe utility generates the states.h and states.c files that contain
+the sprite/frame numbers from the statescr.txt source file. The xyz origin
+point represents a point at the bottom middle of the sprite (between the feet
+of a biped). This is the default origin position for patch_ts grabbed with
+lumpy.exe. A walking creature will have its z equal to the floor it is standing
+on.
+
+The sound code uses the x,y, and subsector fields to do stereo positioning of
+any sound effited by the mobj_t.
+
+The play simulation uses the blocklinks, x,y,z, radius, height to determine
+when mobj_ts are touching each other, touching lines in the map, or hit by
+trace lines (gunshots, lines of sight, etc). The mobj_t->flags element has
+various bit flags used by the simulation.
+
+Every mobj_t is linked into a single sector based on it's origin coordinates.
+The subsector_t is found with R_PointInSubsector(x,y), and the sector_t can be
+found with subsector->sector. The sector links are only used by the rendering
+code, the play simulation does not care about them at all.
+
+Any mobj_t that needs to be acted upon be something else in the play world
+(block movement, be shot, etc) will also need to be linked into the blockmap.
+If the thing has the MF_NOBLOCK flag set, it will not use the block links.
+It can still interact with other things, but only as the instigator (missiles
+will run into other things, but nothing can run into a missile). Each block
+in the grid is 128*128 units, and knows about every line_t that it contains a
+piece of, and every interactable mobj_t that has it's origin contained.
+
+A valid mobj_t is a mobj_t that has the proper subsector_t filled in for it's
+xy coordinates and is linked into the subsector's sector or has the MF_NOSECTOR
+flag set (the subsector_t needs to be valid even if MF_NOSECTOR is set), and is
+linked into a blockmap block or has the MF_NOBLOCKMAP flag set. Links should
+only be modified by the P_[Un]SetThingPosition () functions. Do not change the
+MF_NO? flags while a thing is valid.
+
+===============================================================================
+*/
+
+extern mobj_t LavaInflictor;
+
+extern fixed_t topslope, bottomslope; /* slopes to top and bottom of target */
+
+static fixed_t tmbbox[4];
+static mobj_t *tmthing;
+static mobj_t *tsthing;
+static int tmflags;
+static fixed_t tmx, tmy;
+
+static mobj_t *onmobj; /* used for landing on pods/players */
+
+mobj_t *BlockingMobj;
+
+boolean floatok; /* if true, move would be ok if */
+ /* within tmfloorz - tmceilingz */
+
+fixed_t tmfloorz, tmceilingz, tmdropoffz;
+int tmfloorpic;
+
+line_t *ceilingline; /* keep track of the line that lowers the ceiling, */
+ /* so missiles don't explode against sky hack walls */
+
+#define MAXSPECIALCROSS 8
+line_t *spechit[MAXSPECIALCROSS]; /* keep track of special lines as they are hit, */
+int numspechit; /* but don't process them until the move is proven valid */
+
+
+static void CheckForPushSpecial(line_t *line, int side, mobj_t *mobj);
+
+
+/*
+===============================================================================
+
+ TELEPORT MOVE
+
+===============================================================================
+*/
+
+/*
+==================
+=
+= PIT_StompThing
+=
+==================
+*/
+
+static boolean PIT_StompThing (mobj_t *thing)
+{
+ fixed_t blockdist;
+
+ if (!(thing->flags & MF_SHOOTABLE) )
+ return true;
+
+ blockdist = thing->radius + tmthing->radius;
+ if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist )
+ return true; // didn't hit it
+
+ if (thing == tmthing)
+ return true; // don't clip against self
+
+ if (!(tmthing->flags2 & MF2_TELESTOMP))
+ { // Not allowed to stomp things
+ return false;
+ }
+
+ P_DamageMobj (thing, tmthing, tmthing, 10000);
+
+ return true;
+}
+
+
+/*
+===================
+=
+= P_TeleportMove
+=
+===================
+*/
+
+boolean P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y)
+{
+ int xl, xh, yl, yh, bx, by;
+ subsector_t *newsubsec;
+
+//
+// kill anything occupying the position
+//
+
+ tmthing = thing;
+ tmflags = thing->flags;
+
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ newsubsec = R_PointInSubsector (x, y);
+ ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point. Any contacted lines the step closer together will adjust them
+//
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+ tmfloorpic = newsubsec->sector->floorpic;
+
+ validcount++;
+ numspechit = 0;
+
+//
+// stomp on any things contacted
+//
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+ for (bx = xl; bx <= xh; bx++)
+ {
+ for (by = yl; by <= yh; by++)
+ {
+ if (!P_BlockThingsIterator(bx, by, PIT_StompThing))
+ return false;
+ }
+ }
+
+//
+// the move is ok, so link the thing into its new position
+//
+ P_UnsetThingPosition (thing);
+
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->x = x;
+ thing->y = y;
+
+ P_SetThingPosition (thing);
+
+ return true;
+}
+
+
+static boolean PIT_ThrustStompThing (mobj_t *thing)
+{
+ fixed_t blockdist;
+
+ if (!(thing->flags & MF_SHOOTABLE) )
+ return true;
+
+ blockdist = thing->radius + tsthing->radius;
+ if ( abs(thing->x - tsthing->x) >= blockdist ||
+ abs(thing->y - tsthing->y) >= blockdist ||
+ (thing->z > tsthing->z + tsthing->height) )
+ return true; // didn't hit it
+
+ if (thing == tsthing)
+ return true; // don't clip against self
+
+ P_DamageMobj (thing, tsthing, tsthing, 10001);
+ tsthing->args[1] = 1; // Mark thrust thing as bloody
+
+ return true;
+}
+
+
+void PIT_ThrustSpike(mobj_t *actor)
+{
+ int xl, xh, yl, yh, bx, by;
+ int x0, x2, y0, y2;
+
+ tsthing = actor;
+
+ x0 = actor->x - actor->info->radius;
+ x2 = actor->x + actor->info->radius;
+ y0 = actor->y - actor->info->radius;
+ y2 = actor->y + actor->info->radius;
+
+ xl = (x0 - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+ xh = (x2 - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+ yl = (y0 - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+ yh = (y2 - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+ // stomp on any things contacted
+ for (bx = xl; bx <= xh; bx++)
+ {
+ for (by = yl; by <= yh; by++)
+ P_BlockThingsIterator(bx, by, PIT_ThrustStompThing);
+ }
+}
+
+
+/*
+===============================================================================
+
+ MOVEMENT ITERATOR FUNCTIONS
+
+===============================================================================
+*/
+
+/*
+==================
+=
+= PIT_CheckLine
+=
+= Adjusts tmfloorz and tmceilingz as lines are contacted
+==================
+*/
+
+static boolean PIT_CheckLine(line_t *ld)
+{
+ if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
+ || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+ || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
+ || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
+ {
+ return true;
+ }
+ if (P_BoxOnLineSide(tmbbox, ld) != -1)
+ {
+ return true;
+ }
+
+// a line has been hit
+/*
+= The moving thing's destination position will cross the given line.
+= If this should not be allowed, return false.
+= If the line is special, keep track of it to process later if the move
+= is proven ok. NOTE: specials are NOT sorted by order, so two special
+= lines that are only 8 pixels apart could be crossed in either order.
+*/
+ if (!ld->backsector)
+ { // One sided line
+ if (tmthing->flags2 & MF2_BLASTED)
+ {
+ P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
+ }
+ CheckForPushSpecial(ld, 0, tmthing);
+ return false;
+ }
+ if (!(tmthing->flags & MF_MISSILE))
+ {
+ if (ld->flags & ML_BLOCKING)
+ { // Explicitly blocking everything
+ if (tmthing->flags2 & MF2_BLASTED)
+ {
+ P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
+ }
+ CheckForPushSpecial(ld, 0, tmthing);
+ return false;
+ }
+ if (!tmthing->player && ld->flags & ML_BLOCKMONSTERS)
+ { // Block monsters only
+ if (tmthing->flags2 & MF2_BLASTED)
+ {
+ P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
+ }
+ return false;
+ }
+ }
+ P_LineOpening(ld); // set openrange, opentop, openbottom
+ // adjust floor / ceiling heights
+ if (opentop < tmceilingz)
+ {
+ tmceilingz = opentop;
+ ceilingline = ld;
+ }
+ if (openbottom > tmfloorz)
+ {
+ tmfloorz = openbottom;
+ }
+ if (lowfloor < tmdropoffz)
+ {
+ tmdropoffz = lowfloor;
+ }
+ if (ld->special)
+ { // Contacted a special line, add it to the list
+ spechit[numspechit] = ld;
+ numspechit++;
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC PIT_CheckThing
+//
+//---------------------------------------------------------------------------
+
+static boolean PIT_CheckThing(mobj_t *thing)
+{
+ fixed_t blockdist;
+ boolean solid;
+ int damage;
+
+ if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
+ { // Can't hit thing
+ return true;
+ }
+ blockdist = thing->radius + tmthing->radius;
+ if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
+ { // Didn't hit thing
+ return true;
+ }
+ if (thing == tmthing)
+ { // Don't clip against self
+ return true;
+ }
+ BlockingMobj = thing;
+ if (tmthing->flags2 & MF2_PASSMOBJ)
+ { // check if a mobj passed over/under another object
+ if (tmthing->type == MT_BISHOP && thing->type == MT_BISHOP)
+ { // don't let bishops fly over other bishops
+ return false;
+ }
+ if (tmthing->z >= thing->z + thing->height
+ && !(thing->flags & MF_SPECIAL))
+ {
+ return true;
+ }
+ else if (tmthing->z + tmthing->height < thing->z
+ && !(thing->flags & MF_SPECIAL))
+ { // under thing
+ return true;
+ }
+ }
+ // Check for skulls slamming into things
+ if (tmthing->flags & MF_SKULLFLY)
+ {
+ if (tmthing->type == MT_MINOTAUR)
+ {
+ // Slamming minotaurs shouldn't move non-creatures
+ if (!(thing->flags & MF_COUNTKILL))
+ {
+ return false;
+ }
+ }
+ else if (tmthing->type == MT_HOLY_FX)
+ {
+ if (thing->flags & MF_SHOOTABLE && thing != tmthing->target)
+ {
+ if (netgame && !deathmatch && thing->player)
+ { // don't attack other co-op players
+ return true;
+ }
+ if (thing->flags2 & MF2_REFLECTIVE
+ && (thing->player || thing->flags2 & MF2_BOSS))
+ {
+ tmthing->special1 = (intptr_t)tmthing->target;
+ tmthing->target = thing;
+ return true;
+ }
+ if (thing->flags & MF_COUNTKILL || thing->player)
+ {
+ tmthing->special1 = (intptr_t)thing;
+ }
+ if (P_Random() < 96)
+ {
+ damage = 12;
+ if (thing->player || thing->flags2 & MF2_BOSS)
+ {
+ damage = 3;
+ // ghost burns out faster when attacking players/bosses
+ tmthing->health -= 6;
+ }
+ P_DamageMobj(thing, tmthing, tmthing->target, damage);
+ if (P_Random() < 128)
+ {
+ P_SpawnMobj(tmthing->x, tmthing->y, tmthing->z,
+ MT_HOLY_PUFF);
+ S_StartSound(tmthing, SFX_SPIRIT_ATTACK);
+ if (thing->flags & MF_COUNTKILL && P_Random() < 128
+ && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT))
+ {
+ if ((thing->type == MT_CENTAUR) ||
+ (thing->type == MT_CENTAURLEADER) ||
+ (thing->type == MT_ETTIN))
+ {
+ S_StartSound(thing, SFX_PUPPYBEAT);
+ }
+ }
+ }
+ }
+ if (thing->health <= 0)
+ {
+ tmthing->special1 = 0;
+ }
+ }
+ return true;
+ }
+ damage = ((P_Random() % 8) + 1) * tmthing->damage;
+ P_DamageMobj(thing, tmthing, tmthing, damage);
+ tmthing->flags &= ~MF_SKULLFLY;
+ tmthing->momx = tmthing->momy = tmthing->momz = 0;
+ P_SetMobjState(tmthing, tmthing->info->seestate);
+ return false;
+ }
+ // Check for blasted thing running into another
+ if (tmthing->flags2 & MF2_BLASTED && thing->flags & MF_SHOOTABLE)
+ {
+ if (!(thing->flags2 & MF2_BOSS) &&
+ (thing->flags & MF_COUNTKILL))
+ {
+ thing->momx += tmthing->momx;
+ thing->momy += tmthing->momy;
+ if ((thing->momx + thing->momy) > 3*FRACUNIT)
+ {
+ damage = (tmthing->info->mass/100) + 1;
+ P_DamageMobj(thing, tmthing, tmthing, damage);
+ damage = (thing->info->mass/100) + 1;
+ P_DamageMobj(tmthing, thing, thing, damage>>2);
+ }
+ return false;
+ }
+ }
+ // Check for missile
+ if (tmthing->flags & MF_MISSILE)
+ {
+ // Check for a non-shootable mobj
+ if (thing->flags2 & MF2_NONSHOOTABLE)
+ {
+ return true;
+ }
+ // Check if it went over / under
+ if (tmthing->z > thing->z + thing->height)
+ { // Over thing
+ return true;
+ }
+ if (tmthing->z + tmthing->height < thing->z)
+ { // Under thing
+ return true;
+ }
+ if (tmthing->flags2 & MF2_FLOORBOUNCE)
+ {
+ if (tmthing->target == thing || !(thing->flags & MF_SOLID))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ if (tmthing->type == MT_LIGHTNING_FLOOR
+ || tmthing->type == MT_LIGHTNING_CEILING)
+ {
+ if (thing->flags & MF_SHOOTABLE && thing != tmthing->target)
+ {
+ if (thing->info->mass != H2MAXINT)
+ {
+ thing->momx += tmthing->momx>>4;
+ thing->momy += tmthing->momy>>4;
+ }
+ if ((!thing->player && !(thing->flags2 & MF2_BOSS))
+ || !(leveltime & 1))
+ {
+ if (thing->type == MT_CENTAUR || thing->type == MT_CENTAURLEADER)
+ { // Lightning does more damage to centaurs
+ P_DamageMobj(thing, tmthing, tmthing->target, 9);
+ }
+ else
+ {
+ P_DamageMobj(thing, tmthing, tmthing->target, 3);
+ }
+ if (!(S_GetSoundPlayingInfo(tmthing, SFX_MAGE_LIGHTNING_ZAP)))
+ {
+ S_StartSound(tmthing, SFX_MAGE_LIGHTNING_ZAP);
+ }
+ if (thing->flags & MF_COUNTKILL && P_Random() < 64
+ && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT))
+ {
+ if ((thing->type == MT_CENTAUR) ||
+ (thing->type == MT_CENTAURLEADER) ||
+ (thing->type == MT_ETTIN))
+ {
+ S_StartSound(thing, SFX_PUPPYBEAT);
+ }
+ }
+ }
+ tmthing->health--;
+ if (tmthing->health <= 0 || thing->health <= 0)
+ {
+ return false;
+ }
+ if (tmthing->type == MT_LIGHTNING_FLOOR)
+ {
+ if (tmthing->special2
+ && !((mobj_t *)tmthing->special2)->special1)
+ {
+ ((mobj_t *)tmthing->special2)->special1 = (intptr_t)thing;
+ }
+ }
+ else if (!tmthing->special1)
+ {
+ tmthing->special1 = (intptr_t)thing;
+ }
+ }
+ return true; // lightning zaps through all sprites
+ }
+ else if (tmthing->type == MT_LIGHTNING_ZAP)
+ {
+ mobj_t *lmo;
+
+ if (thing->flags & MF_SHOOTABLE && thing != tmthing->target)
+ {
+ lmo = (mobj_t *)tmthing->special2;
+ if (lmo)
+ {
+ if (lmo->type == MT_LIGHTNING_FLOOR)
+ {
+ if (lmo->special2
+ && !((mobj_t *)lmo->special2)->special1)
+ {
+ ((mobj_t *)lmo->special2)->special1 = (intptr_t)thing;
+ }
+ }
+ else if (!lmo->special1)
+ {
+ lmo->special1 = (intptr_t)thing;
+ }
+ if (!(leveltime & 3))
+ {
+ lmo->health--;
+ }
+ }
+ }
+ }
+ else if (tmthing->type == MT_MSTAFF_FX2 && thing != tmthing->target)
+ {
+ if (!thing->player && !(thing->flags2 & MF2_BOSS))
+ {
+ switch (thing->type)
+ {
+ case MT_FIGHTER_BOSS: // these not flagged boss
+ case MT_CLERIC_BOSS: // so they can be blasted
+ case MT_MAGE_BOSS:
+ break;
+ default:
+ P_DamageMobj(thing, tmthing, tmthing->target, 10);
+ return true;
+ }
+ }
+ }
+ if (tmthing->target && tmthing->target->type == thing->type)
+ { // Don't hit same species as originator
+ if (thing == tmthing->target)
+ { // Don't missile self
+ return true;
+ }
+ if (!thing->player)
+ { // Hit same species as originator, explode, no damage
+ return false;
+ }
+ }
+ if (!(thing->flags & MF_SHOOTABLE))
+ { // Didn't do any damage
+ return !(thing->flags & MF_SOLID);
+ }
+ if (tmthing->flags2 & MF2_RIP)
+ {
+ if (!(thing->flags & MF_NOBLOOD) &&
+ !(thing->flags2 & MF2_REFLECTIVE) &&
+ !(thing->flags2 & MF2_INVULNERABLE))
+ { // Ok to spawn some blood
+ P_RipperBlood(tmthing);
+ }
+ //S_StartSound(tmthing, sfx_ripslop);
+ damage = ((P_Random() & 3) + 2) * tmthing->damage;
+ P_DamageMobj(thing, tmthing, tmthing->target, damage);
+ if (thing->flags2 & MF2_PUSHABLE
+ && !(tmthing->flags2 & MF2_CANNOTPUSH))
+ { // Push thing
+ thing->momx += tmthing->momx>>2;
+ thing->momy += tmthing->momy>>2;
+ }
+ numspechit = 0;
+ return true;
+ }
+ // Do damage
+ damage = ((P_Random() % 8) + 1) * tmthing->damage;
+ if (damage)
+ {
+ if (!(thing->flags & MF_NOBLOOD) &&
+ !(thing->flags2 & MF2_REFLECTIVE) &&
+ !(thing->flags2 & MF2_INVULNERABLE) &&
+ !(tmthing->type == MT_TELOTHER_FX1) &&
+ !(tmthing->type == MT_TELOTHER_FX2) &&
+ !(tmthing->type == MT_TELOTHER_FX3) &&
+ !(tmthing->type == MT_TELOTHER_FX4) &&
+ !(tmthing->type == MT_TELOTHER_FX5) &&
+ (P_Random() < 192))
+ {
+ P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing);
+ }
+ P_DamageMobj(thing, tmthing, tmthing->target, damage);
+ }
+ return false;
+ }
+ if (thing->flags2 & MF2_PUSHABLE && !(tmthing->flags2 & MF2_CANNOTPUSH))
+ { // Push thing
+ thing->momx += tmthing->momx>>2;
+ thing->momy += tmthing->momy>>2;
+ }
+ // Check for special thing
+ if (thing->flags & MF_SPECIAL)
+ {
+ solid = thing->flags & MF_SOLID;
+ if (tmflags & MF_PICKUP)
+ { // Can be picked up by tmthing
+ P_TouchSpecialThing(thing, tmthing); // Can remove thing
+ }
+ return !solid;
+ }
+ return !(thing->flags & MF_SOLID);
+}
+
+//---------------------------------------------------------------------------
+//
+// PIT_CheckOnmobjZ
+//
+//---------------------------------------------------------------------------
+
+static boolean PIT_CheckOnmobjZ(mobj_t *thing)
+{
+ fixed_t blockdist;
+
+ if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
+ { // Can't hit thing
+ return true;
+ }
+ blockdist = thing->radius + tmthing->radius;
+ if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
+ { // Didn't hit thing
+ return true;
+ }
+ if (thing == tmthing)
+ { // Don't clip against self
+ return true;
+ }
+ if (tmthing->z > thing->z + thing->height)
+ {
+ return true;
+ }
+ else if (tmthing->z + tmthing->height < thing->z)
+ { // under thing
+ return true;
+ }
+ if (thing->flags & MF_SOLID)
+ {
+ onmobj = thing;
+ }
+ return !(thing->flags & MF_SOLID);
+}
+
+/*
+===============================================================================
+
+ MOVEMENT CLIPPING
+
+===============================================================================
+*/
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_TestMobjLocation
+//
+// Returns true if the mobj is not blocked by anything at its current
+// location, otherwise returns false.
+//
+//----------------------------------------------------------------------------
+
+boolean P_TestMobjLocation(mobj_t *mobj)
+{
+ int flags;
+
+ flags = mobj->flags;
+ mobj->flags &= ~MF_PICKUP;
+ if (P_CheckPosition(mobj, mobj->x, mobj->y))
+ { // XY is ok, now check Z
+ mobj->flags = flags;
+ if ((mobj->z < mobj->floorz)
+ || (mobj->z + mobj->height > mobj->ceilingz))
+ { // Bad Z
+ return false;
+ }
+ return true;
+ }
+ mobj->flags = flags;
+ return false;
+}
+
+/*
+==================
+=
+= P_CheckPosition
+=
+= This is purely informative, nothing is modified (except things picked up)
+
+in:
+a mobj_t (can be valid or invalid)
+a position to be checked (doesn't need to be related to the mobj_t->x,y)
+
+during:
+special things are touched if MF_PICKUP
+early out on solid lines?
+
+out:
+newsubsec
+floorz
+ceilingz
+tmdropoffz = the lowest point contacted (monsters won't move to a dropoff)
+speciallines[]
+numspeciallines
+mobj_t *BlockingMobj = pointer to thing that blocked position (NULL if not
+blocked, or blocked by a line).
+
+==================
+*/
+
+boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y)
+{
+ int xl, xh, yl, yh, bx, by;
+ subsector_t *newsubsec;
+
+ tmthing = thing;
+ tmflags = thing->flags;
+
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ newsubsec = R_PointInSubsector (x, y);
+ ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point. Any contacted lines the step closer together will adjust them
+//
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+ tmfloorpic = newsubsec->sector->floorpic;
+
+ validcount++;
+ numspechit = 0;
+
+ if (tmflags & MF_NOCLIP && !(tmflags & MF_SKULLFLY))
+ {
+ return true;
+ }
+
+//
+// check things first, possibly picking things up
+// the bounding box is extended by MAXRADIUS because mobj_ts are grouped
+// into mapblocks based on their origin point, and can overlap into adjacent
+// blocks by up to MAXRADIUS units
+//
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+ BlockingMobj = NULL;
+ for (bx = xl; bx <= xh; bx++)
+ {
+ for (by = yl; by <= yh; by++)
+ {
+ if (!P_BlockThingsIterator(bx, by, PIT_CheckThing))
+ return false;
+ }
+ }
+//
+// check lines
+//
+ if (tmflags & MF_NOCLIP)
+ {
+ return true;
+ }
+
+ BlockingMobj = NULL;
+ xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
+
+ for (bx = xl; bx <= xh; bx++)
+ {
+ for (by = yl; by <= yh; by++)
+ {
+ if (!P_BlockLinesIterator (bx, by, PIT_CheckLine))
+ return false;
+ }
+ }
+ return true;
+}
+
+//=============================================================================
+//
+// P_CheckOnmobj(mobj_t *thing)
+//
+// Checks if the new Z position is legal
+//=============================================================================
+
+mobj_t *P_CheckOnmobj(mobj_t *thing)
+{
+ int xl, xh, yl, yh, bx, by;
+ subsector_t *newsubsec;
+ fixed_t x;
+ fixed_t y;
+ mobj_t oldmo;
+
+ x = thing->x;
+ y = thing->y;
+ tmthing = thing;
+ tmflags = thing->flags;
+ oldmo = *thing; // save the old mobj before the fake zmovement
+ P_FakeZMovement(tmthing);
+
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ newsubsec = R_PointInSubsector (x, y);
+ ceilingline = NULL;
+
+//
+// the base floor / ceiling is from the subsector that contains the
+// point. Any contacted lines the step closer together will adjust them
+//
+ tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
+ tmceilingz = newsubsec->sector->ceilingheight;
+ tmfloorpic = newsubsec->sector->floorpic;
+
+ validcount++;
+ numspechit = 0;
+
+ if (tmflags & MF_NOCLIP)
+ return NULL;
+
+//
+// check things first, possibly picking things up
+// the bounding box is extended by MAXRADIUS because mobj_ts are grouped
+// into mapblocks based on their origin point, and can overlap into adjacent
+// blocks by up to MAXRADIUS units
+//
+ xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+ xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+ yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+ yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+ for (bx = xl; bx <= xh; bx++)
+ {
+ for (by = yl; by <= yh; by++)
+ {
+ if (!P_BlockThingsIterator(bx, by, PIT_CheckOnmobjZ))
+ {
+ *tmthing = oldmo;
+ return onmobj;
+ }
+ }
+ }
+ *tmthing = oldmo;
+ return NULL;
+}
+
+//=============================================================================
+//
+// P_FakeZMovement
+//
+// Fake the zmovement so that we can check if a move is legal
+//=============================================================================
+
+void P_FakeZMovement(mobj_t *mo)
+{
+ int dist;
+ int delta;
+//
+// adjust height
+//
+ mo->z += mo->momz;
+ if (mo->flags & MF_FLOAT && mo->target)
+ { // float down towards target if too close
+ if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT))
+ {
+ dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y);
+ delta = (mo->target->z + (mo->height >> 1) ) - mo->z;
+ if (delta < 0 && dist < -(delta*3))
+ mo->z -= FLOATSPEED;
+ else if (delta > 0 && dist < (delta*3))
+ mo->z += FLOATSPEED;
+ }
+ }
+ if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+ && leveltime & 2)
+ {
+ mo->z += finesine[(FINEANGLES/20*leveltime>>2) & FINEMASK];
+ }
+
+//
+// clip movement
+//
+ if (mo->z <= mo->floorz)
+ { // Hit the floor
+ mo->z = mo->floorz;
+ if (mo->momz < 0)
+ {
+ mo->momz = 0;
+ }
+ if (mo->flags & MF_SKULLFLY)
+ { // The skull slammed into something
+ mo->momz = -mo->momz;
+ }
+ if (mo->info->crashstate && (mo->flags & MF_CORPSE))
+ {
+ return;
+ }
+ }
+ else if (mo->flags2 & MF2_LOGRAV)
+ {
+ if (mo->momz == 0)
+ mo->momz = -(GRAVITY>>3)*2;
+ else
+ mo->momz -= GRAVITY>>3;
+ }
+ else if (! (mo->flags & MF_NOGRAVITY) )
+ {
+ if (mo->momz == 0)
+ mo->momz = -GRAVITY*2;
+ else
+ mo->momz -= GRAVITY;
+ }
+
+ if (mo->z + mo->height > mo->ceilingz)
+ { // hit the ceiling
+ if (mo->momz > 0)
+ mo->momz = 0;
+ mo->z = mo->ceilingz - mo->height;
+ if (mo->flags & MF_SKULLFLY)
+ { // the skull slammed into something
+ mo->momz = -mo->momz;
+ }
+ }
+}
+
+//===========================================================================
+//
+// CheckForPushSpecial
+//
+//===========================================================================
+
+static void CheckForPushSpecial(line_t *line, int side, mobj_t *mobj)
+{
+ if (line->special)
+ {
+ if (mobj->flags2 & MF2_PUSHWALL)
+ {
+ P_ActivateLine(line, mobj, side, SPAC_PUSH);
+ }
+ else if (mobj->flags2 & MF2_IMPACT)
+ {
+ P_ActivateLine(line, mobj, side, SPAC_IMPACT);
+ }
+ }
+}
+
+/*
+===================
+=
+= P_TryMove
+=
+= Attempt to move to a new position, crossing special lines unless MF_TELEPORT
+= is set
+=
+===================
+*/
+
+boolean P_TryMove (mobj_t *thing, fixed_t x, fixed_t y)
+{
+ fixed_t oldx, oldy;
+ int side, oldside;
+ line_t *ld;
+
+ floatok = false;
+ if (!P_CheckPosition(thing, x, y))
+ { // Solid wall or thing
+ if (!BlockingMobj || BlockingMobj->player || !thing->player)
+ {
+ goto pushline;
+ }
+ else if (BlockingMobj->z + BlockingMobj->height - thing->z > 24*FRACUNIT
+ || (BlockingMobj->subsector->sector->ceilingheight -
+ (BlockingMobj->z + BlockingMobj->height) < thing->height)
+ || (tmceilingz - (BlockingMobj->z + BlockingMobj->height) < thing->height))
+ {
+ goto pushline;
+ }
+ }
+ if (!(thing->flags & MF_NOCLIP))
+ {
+ if (tmceilingz - tmfloorz < thing->height)
+ { // Doesn't fit
+ goto pushline;
+ }
+ floatok = true;
+ if (!(thing->flags & MF_TELEPORT)
+ && tmceilingz - thing->z < thing->height
+ && thing->type != MT_LIGHTNING_CEILING
+ && !(thing->flags2 & MF2_FLY))
+ { // mobj must lower itself to fit
+ goto pushline;
+ }
+ if (thing->flags2 & MF2_FLY)
+ {
+ if (thing->z + thing->height > tmceilingz)
+ {
+ thing->momz = -8*FRACUNIT;
+ goto pushline;
+ }
+ else if (thing->z < tmfloorz && tmfloorz - tmdropoffz > 24*FRACUNIT)
+ {
+ thing->momz = 8*FRACUNIT;
+ goto pushline;
+ }
+ }
+ if (!(thing->flags & MF_TELEPORT)
+ // The Minotaur floor fire (MT_MNTRFX2) can step up any amount
+ && thing->type != MT_MNTRFX2 && thing->type != MT_LIGHTNING_FLOOR
+ && tmfloorz - thing->z > 24*FRACUNIT)
+ {
+ goto pushline;
+ }
+ if (!(thing->flags & (MF_DROPOFF|MF_FLOAT)) &&
+ (tmfloorz - tmdropoffz > 24*FRACUNIT) &&
+ !(thing->flags2 & MF2_BLASTED))
+ { // Can't move over a dropoff unless it's been blasted
+ return false;
+ }
+ if (thing->flags2 & MF2_CANTLEAVEFLOORPIC &&
+ (tmfloorpic != thing->subsector->sector->floorpic || tmfloorz-thing->z != 0))
+ { // must stay within a sector of a certain floor type
+ return false;
+ }
+ }
+
+//
+// the move is ok, so link the thing into its new position
+//
+ P_UnsetThingPosition (thing);
+
+ oldx = thing->x;
+ oldy = thing->y;
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->floorpic = tmfloorpic;
+ thing->x = x;
+ thing->y = y;
+
+ P_SetThingPosition (thing);
+
+ if (thing->flags2 & MF2_FLOORCLIP)
+ {
+ if (thing->z == thing->subsector->sector->floorheight
+ && P_GetThingFloorType(thing) >= FLOOR_LIQUID)
+ {
+ thing->floorclip = 10*FRACUNIT;
+ }
+ else
+ {
+ thing->floorclip = 0;
+ }
+ }
+
+//
+// if any special lines were hit, do the effect
+//
+ if (! (thing->flags & (MF_TELEPORT|MF_NOCLIP)) )
+ {
+ while (numspechit > 0)
+ {
+ numspechit--;
+ // see if the line was crossed
+ ld = spechit[numspechit];
+ side = P_PointOnLineSide (thing->x, thing->y, ld);
+ oldside = P_PointOnLineSide (oldx, oldy, ld);
+ if (side != oldside)
+ {
+ if (ld->special)
+ {
+ if (thing->player)
+ {
+ P_ActivateLine(ld, thing, oldside, SPAC_CROSS);
+ }
+ else if (thing->flags2 & MF2_MCROSS)
+ {
+ P_ActivateLine(ld, thing, oldside, SPAC_MCROSS);
+ }
+ else if (thing->flags2 & MF2_PCROSS)
+ {
+ P_ActivateLine(ld, thing, oldside, SPAC_PCROSS);
+ }
+ }
+ }
+ }
+ }
+ return true;
+
+pushline:
+ if (!(thing->flags & (MF_TELEPORT|MF_NOCLIP)))
+ {
+ int numSpecHitTemp;
+
+ if (tmthing->flags2 & MF2_BLASTED)
+ {
+ P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
+ }
+ numSpecHitTemp = numspechit;
+ while (numSpecHitTemp > 0)
+ {
+ numSpecHitTemp--;
+ // see if the line was crossed
+ ld = spechit[numSpecHitTemp];
+ side = P_PointOnLineSide (thing->x, thing->y, ld);
+ CheckForPushSpecial(ld, side, thing);
+ }
+ }
+ return false;
+}
+
+/*
+==================
+=
+= P_ThingHeightClip
+=
+= Takes a valid thing and adjusts the thing->floorz, thing->ceilingz,
+= anf possibly thing->z
+=
+= This is called for all nearby monsters whenever a sector changes height
+=
+= If the thing doesn't fit, the z will be set to the lowest value and
+= false will be returned
+==================
+*/
+
+static boolean P_ThingHeightClip (mobj_t *thing)
+{
+ boolean onfloor;
+
+ onfloor = (thing->z == thing->floorz);
+
+ P_CheckPosition (thing, thing->x, thing->y);
+ // what about stranding a monster partially off an edge?
+
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->floorpic = tmfloorpic;
+
+ if (onfloor)
+ { // walking monsters rise and fall with the floor
+ if ((thing->z-thing->floorz < 9*FRACUNIT)
+ || (thing->flags & MF_NOGRAVITY))
+ {
+ thing->z = thing->floorz;
+ }
+ }
+ else
+ { // don't adjust a floating monster unless forced to
+ if (thing->z + thing->height > thing->ceilingz)
+ thing->z = thing->ceilingz - thing->height;
+ }
+
+ if (thing->ceilingz - thing->floorz < thing->height)
+ return false;
+
+ return true;
+}
+
+
+/*
+==============================================================================
+
+ SLIDE MOVE
+
+Allows the player to slide along any angled walls
+
+==============================================================================
+*/
+
+static fixed_t bestslidefrac, secondslidefrac;
+static line_t *bestslideline, *secondslideline;
+static mobj_t *slidemo;
+
+static fixed_t tmxmove, tmymove;
+
+/*
+==================
+=
+= P_HitSlideLine
+=
+= Adjusts the xmove / ymove so that the next move will slide along the wall
+==================
+*/
+
+static void P_HitSlideLine (line_t *ld)
+{
+ int side;
+ angle_t lineangle, moveangle, deltaangle;
+ fixed_t movelen, newlen;
+
+ if (ld->slopetype == ST_HORIZONTAL)
+ {
+ tmymove = 0;
+ return;
+ }
+ if (ld->slopetype == ST_VERTICAL)
+ {
+ tmxmove = 0;
+ return;
+ }
+
+ side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
+
+ lineangle = R_PointToAngle2 (0, 0, ld->dx, ld->dy);
+ if (side == 1)
+ lineangle += ANG180;
+ moveangle = R_PointToAngle2 (0, 0, tmxmove, tmymove);
+ deltaangle = moveangle - lineangle;
+ if (deltaangle > ANG180)
+ deltaangle += ANG180;
+// I_Error ("SlideLine: ang>ANG180");
+
+ lineangle >>= ANGLETOFINESHIFT;
+ deltaangle >>= ANGLETOFINESHIFT;
+
+ movelen = P_AproxDistance (tmxmove, tmymove);
+ newlen = FixedMul (movelen, finecosine[deltaangle]);
+ tmxmove = FixedMul (newlen, finecosine[lineangle]);
+ tmymove = FixedMul (newlen, finesine[lineangle]);
+}
+
+/*
+==============
+=
+= PTR_SlideTraverse
+=
+==============
+*/
+
+static boolean PTR_SlideTraverse (intercept_t *in)
+{
+ line_t *li;
+
+ if (!in->isaline)
+ I_Error ("PTR_SlideTraverse: not a line?");
+
+ li = in->d.line;
+ if (! (li->flags & ML_TWOSIDED))
+ {
+ if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
+ return true; // don't hit the back side
+ goto isblocking;
+ }
+
+ P_LineOpening (li); // set openrange, opentop, openbottom
+ if (openrange < slidemo->height)
+ goto isblocking; // doesn't fit
+
+ if (opentop - slidemo->z < slidemo->height)
+ goto isblocking; // mobj is too high
+
+ if (openbottom - slidemo->z > 24*FRACUNIT )
+ goto isblocking; // too big a step up
+
+ return true; // this line doesn't block movement
+
+// the line does block movement, see if it is closer than best so far
+isblocking:
+ if (in->frac < bestslidefrac)
+ {
+ secondslidefrac = bestslidefrac;
+ secondslideline = bestslideline;
+ bestslidefrac = in->frac;
+ bestslideline = li;
+ }
+
+ return false; // stop
+}
+
+
+/*
+==================
+=
+= P_SlideMove
+=
+= The momx / momy move is bad, so try to slide along a wall
+=
+= Find the first line hit, move flush to it, and slide along it
+=
+= This is a kludgy mess.
+==================
+*/
+
+void P_SlideMove (mobj_t *mo)
+{
+ fixed_t leadx, leady;
+ fixed_t trailx, traily;
+ fixed_t newx, newy;
+ int hitcount;
+
+ slidemo = mo;
+ hitcount = 0;
+retry:
+ if (++hitcount == 3)
+ goto stairstep; // don't loop forever
+
+//
+// trace along the three leading corners
+//
+ if (mo->momx > 0)
+ {
+ leadx = mo->x + mo->radius;
+ trailx = mo->x - mo->radius;
+ }
+ else
+ {
+ leadx = mo->x - mo->radius;
+ trailx = mo->x + mo->radius;
+ }
+
+ if (mo->momy > 0)
+ {
+ leady = mo->y + mo->radius;
+ traily = mo->y - mo->radius;
+ }
+ else
+ {
+ leady = mo->y - mo->radius;
+ traily = mo->y + mo->radius;
+ }
+
+ bestslidefrac = FRACUNIT + 1;
+
+ P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse);
+ P_PathTraverse(trailx, leady, trailx + mo->momx, leady + mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse);
+ P_PathTraverse(leadx, traily, leadx + mo->momx, traily + mo->momy,
+ PT_ADDLINES, PTR_SlideTraverse);
+
+//
+// move up to the wall
+//
+ if (bestslidefrac == FRACUNIT + 1)
+ { // the move must have hit the middle, so stairstep
+stairstep:
+ if (!P_TryMove(mo, mo->x, mo->y + mo->momy))
+ {
+ P_TryMove(mo, mo->x + mo->momx, mo->y);
+ }
+ return;
+ }
+
+ bestslidefrac -= 0x800; // fudge a bit to make sure it doesn't hit
+ if (bestslidefrac > 0)
+ {
+ newx = FixedMul (mo->momx, bestslidefrac);
+ newy = FixedMul (mo->momy, bestslidefrac);
+ if (!P_TryMove (mo, mo->x + newx, mo->y + newy))
+ goto stairstep;
+ }
+
+//
+// now continue along the wall
+//
+ bestslidefrac = FRACUNIT - (bestslidefrac + 0x800); // remainder
+ if (bestslidefrac > FRACUNIT)
+ bestslidefrac = FRACUNIT;
+ if (bestslidefrac <= 0)
+ return;
+
+ tmxmove = FixedMul (mo->momx, bestslidefrac);
+ tmymove = FixedMul (mo->momy, bestslidefrac);
+
+ P_HitSlideLine (bestslideline); // clip the moves
+
+ mo->momx = tmxmove;
+ mo->momy = tmymove;
+
+ if (!P_TryMove (mo, mo->x + tmxmove, mo->y + tmymove))
+ {
+ goto retry;
+ }
+}
+
+//============================================================================
+//
+// PTR_BounceTraverse
+//
+//============================================================================
+
+static boolean PTR_BounceTraverse(intercept_t *in)
+{
+ line_t *li;
+
+ if (!in->isaline)
+ I_Error ("PTR_BounceTraverse: not a line?");
+
+ li = in->d.line;
+ if (!(li->flags & ML_TWOSIDED))
+ {
+ if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
+ return true; // don't hit the back side
+ goto bounceblocking;
+ }
+
+ P_LineOpening (li); // set openrange, opentop, openbottom
+ if (openrange < slidemo->height)
+ goto bounceblocking; // doesn't fit
+
+ if (opentop - slidemo->z < slidemo->height)
+ goto bounceblocking; // mobj is too high
+ return true; // this line doesn't block movement
+
+// the line does block movement, see if it is closer than best so far
+bounceblocking:
+ if (in->frac < bestslidefrac)
+ {
+ secondslidefrac = bestslidefrac;
+ secondslideline = bestslideline;
+ bestslidefrac = in->frac;
+ bestslideline = li;
+ }
+ return false; // stop
+}
+
+//============================================================================
+//
+// P_BounceWall
+//
+//============================================================================
+
+void P_BounceWall(mobj_t *mo)
+{
+ fixed_t leadx, leady;
+ int side;
+ angle_t lineangle, moveangle, deltaangle;
+ fixed_t movelen;
+
+ slidemo = mo;
+
+//
+// trace along the three leading corners
+//
+ if (mo->momx > 0)
+ {
+ leadx = mo->x + mo->radius;
+ }
+ else
+ {
+ leadx = mo->x - mo->radius;
+ }
+ if (mo->momy > 0)
+ {
+ leady = mo->y + mo->radius;
+ }
+ else
+ {
+ leady = mo->y - mo->radius;
+ }
+ bestslidefrac = FRACUNIT+1;
+ P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy,
+ PT_ADDLINES, PTR_BounceTraverse);
+
+ side = P_PointOnLineSide(mo->x, mo->y, bestslideline);
+ lineangle = R_PointToAngle2(0, 0, bestslideline->dx, bestslideline->dy);
+ if (side == 1)
+ lineangle += ANG180;
+ moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy);
+ deltaangle = (2*lineangle) - moveangle;
+// if (deltaangle > ANG180)
+// deltaangle += ANG180;
+//// I_Error ("SlideLine: ang>ANG180");
+
+ lineangle >>= ANGLETOFINESHIFT;
+ deltaangle >>= ANGLETOFINESHIFT;
+
+ movelen = P_AproxDistance(mo->momx, mo->momy);
+ movelen = FixedMul(movelen, 0.75*FRACUNIT); // friction
+ if (movelen < FRACUNIT)
+ movelen = 2*FRACUNIT;
+ mo->momx = FixedMul(movelen, finecosine[deltaangle]);
+ mo->momy = FixedMul(movelen, finesine[deltaangle]);
+}
+
+
+/*
+==============================================================================
+
+ P_LineAttack
+
+==============================================================================
+*/
+
+
+mobj_t *PuffSpawned;
+mobj_t *linetarget; /* who got hit (or NULL) */
+
+fixed_t attackrange;
+static fixed_t aimslope;
+static int la_damage;
+
+static mobj_t *shootthing;
+static fixed_t shootz; /* height if not aiming up or down */
+ /* ???: use slope for monsters? */
+
+
+/*
+===============================================================================
+=
+= PTR_AimTraverse
+=
+= Sets linetaget and aimslope when a target is aimed at
+===============================================================================
+*/
+
+static boolean PTR_AimTraverse (intercept_t *in)
+{
+ line_t *li;
+ mobj_t *th;
+ fixed_t slope, thingtopslope, thingbottomslope;
+ fixed_t dist;
+
+ if (in->isaline)
+ {
+ li = in->d.line;
+ if (!(li->flags & ML_TWOSIDED))
+ return false; // stop
+//
+// crosses a two sided line
+// a two sided line will restrict the possible target ranges
+ P_LineOpening (li);
+
+ if (openbottom >= opentop)
+ return false; // stop
+
+ dist = FixedMul (attackrange, in->frac);
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv (openbottom - shootz , dist);
+ if (slope > bottomslope)
+ bottomslope = slope;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv (opentop - shootz, dist);
+ if (slope < topslope)
+ topslope = slope;
+ }
+
+ if (topslope <= bottomslope)
+ return false; // stop
+
+ return true; // shot continues
+ }
+
+//
+// shoot a thing
+//
+ th = in->d.thing;
+ if (th == shootthing)
+ return true; // can't shoot self
+ if (!(th->flags & MF_SHOOTABLE))
+ { // corpse or something
+ return true;
+ }
+ if (th->player && netgame && !deathmatch)
+ { // don't aim at fellow co-op players
+ return true;
+ }
+
+// check angles to see if the thing can be aimed at
+
+ dist = FixedMul (attackrange, in->frac);
+ thingtopslope = FixedDiv (th->z + th->height - shootz, dist);
+ if (thingtopslope < bottomslope)
+ return true; // shot over the thing
+ thingbottomslope = FixedDiv (th->z - shootz, dist);
+ if (thingbottomslope > topslope)
+ return true; // shot under the thing
+
+//
+// this thing can be hit!
+//
+ if (thingtopslope > topslope)
+ thingtopslope = topslope;
+ if (thingbottomslope < bottomslope)
+ thingbottomslope = bottomslope;
+
+ aimslope = (thingtopslope + thingbottomslope) / 2;
+ linetarget = th;
+
+ return false; // don't go any farther
+}
+
+
+/*
+==============================================================================
+=
+= PTR_ShootTraverse
+=
+==============================================================================
+*/
+
+static boolean PTR_ShootTraverse (intercept_t *in)
+{
+ fixed_t x, y, z;
+ fixed_t frac;
+ line_t *li;
+ mobj_t *th;
+ fixed_t slope;
+ fixed_t dist;
+ fixed_t thingtopslope, thingbottomslope;
+
+ if (in->isaline)
+ {
+ li = in->d.line;
+ if (li->special)
+ {
+ P_ActivateLine(li, shootthing, 0, SPAC_IMPACT);
+ // P_ShootSpecialLine (shootthing, li);
+ }
+ if (!(li->flags & ML_TWOSIDED))
+ goto hitline;
+
+//
+// crosses a two sided line
+//
+ P_LineOpening (li);
+
+ dist = FixedMul (attackrange, in->frac);
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv (openbottom - shootz, dist);
+ if (slope > aimslope)
+ goto hitline;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv (opentop - shootz , dist);
+ if (slope < aimslope)
+ goto hitline;
+ }
+
+ return true; // shot continues
+//
+// hit line
+//
+hitline:
+ // position a bit closer
+ frac = in->frac - FixedDiv(4*FRACUNIT, attackrange);
+ x = trace.x + FixedMul(trace.dx, frac);
+ y = trace.y + FixedMul(trace.dy, frac);
+ z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
+
+ if (li->frontsector->ceilingpic == skyflatnum)
+ {
+ if (z > li->frontsector->ceilingheight)
+ return false; // don't shoot the sky!
+ if (li->backsector && li->backsector->ceilingpic == skyflatnum)
+ return false; // it's a sky hack wall
+ }
+
+ P_SpawnPuff (x, y, z);
+ return false; // don't go any farther
+ }
+
+//
+// shoot a thing
+//
+ th = in->d.thing;
+ if (th == shootthing)
+ return true; // can't shoot self
+ if (!(th->flags & MF_SHOOTABLE))
+ return true; // corpse or something
+
+//
+// check for physical attacks on a ghost
+//
+/* FIX: Impliment Heretic 2 weapons here
+ if (th->flags & MF_SHADOW && shootthing->player->readyweapon == wp_staff)
+ {
+ return true;
+ }
+*/
+
+// check angles to see if the thing can be aimed at
+ dist = FixedMul (attackrange, in->frac);
+ thingtopslope = FixedDiv (th->z + th->height - shootz, dist);
+ if (thingtopslope < aimslope)
+ return true; // shot over the thing
+ thingbottomslope = FixedDiv (th->z - shootz, dist);
+ if (thingbottomslope > aimslope)
+ return true; // shot under the thing
+
+//
+// hit thing
+//
+ // position a bit closer
+ frac = in->frac - FixedDiv(10*FRACUNIT, attackrange);
+ x = trace.x + FixedMul(trace.dx, frac);
+ y = trace.y + FixedMul(trace.dy, frac);
+ z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
+ P_SpawnPuff(x, y, z);
+ if (la_damage)
+ {
+ if (!(in->d.thing->flags & MF_NOBLOOD) &&
+ !(in->d.thing->flags2 & MF2_INVULNERABLE))
+ {
+ if (PuffType == MT_AXEPUFF || PuffType == MT_AXEPUFF_GLOW)
+ {
+ P_BloodSplatter2(x, y, z, in->d.thing);
+ }
+ if (P_Random() < 192)
+ {
+ P_BloodSplatter(x, y, z, in->d.thing);
+ }
+ }
+ if (PuffType == MT_FLAMEPUFF2)
+ { // Cleric FlameStrike does fire damage
+ P_DamageMobj(th, &LavaInflictor, shootthing, la_damage);
+ }
+ else
+ {
+ P_DamageMobj(th, shootthing, shootthing, la_damage);
+ }
+ }
+ return false; // don't go any farther
+}
+
+/*
+=================
+=
+= P_AimLineAttack
+=
+=================
+*/
+
+fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance)
+{
+ fixed_t x2, y2;
+
+ angle >>= ANGLETOFINESHIFT;
+ shootthing = t1;
+ x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
+ y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
+ shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
+ topslope = 100*FRACUNIT/160; // can't shoot outside view angles
+ bottomslope = -100*FRACUNIT/160;
+ attackrange = distance;
+ linetarget = NULL;
+
+ P_PathTraverse (t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse);
+
+ if (linetarget)
+ return aimslope;
+ return 0;
+}
+
+
+/*
+=================
+=
+= P_LineAttack
+=
+= if damage == 0, it is just a test trace that will leave linetarget set
+=
+=================
+*/
+
+void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage)
+{
+ fixed_t x2, y2;
+
+ angle >>= ANGLETOFINESHIFT;
+ shootthing = t1;
+ la_damage = damage;
+ x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
+ y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
+ shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
+ shootz -= t1->floorclip;
+ attackrange = distance;
+ aimslope = slope;
+
+ if (P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS,
+ PTR_ShootTraverse))
+ {
+ switch (PuffType)
+ {
+ case MT_PUNCHPUFF:
+ S_StartSound(t1, SFX_FIGHTER_PUNCH_MISS);
+ break;
+ case MT_HAMMERPUFF:
+ case MT_AXEPUFF:
+ case MT_AXEPUFF_GLOW:
+ S_StartSound(t1, SFX_FIGHTER_HAMMER_MISS);
+ break;
+ case MT_FLAMEPUFF:
+ P_SpawnPuff(x2, y2, shootz + FixedMul(slope, distance));
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+==============================================================================
+
+ USE LINES
+
+==============================================================================
+*/
+
+static mobj_t *usething;
+
+static boolean PTR_UseTraverse (intercept_t *in)
+{
+ int sound;
+ fixed_t pheight;
+
+ if (!in->d.line->special)
+ {
+ P_LineOpening (in->d.line);
+ if (openrange <= 0)
+ {
+ if (usething->player)
+ {
+ switch (usething->player->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PLAYER_FIGHTER_FAILED_USE;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PLAYER_CLERIC_FAILED_USE;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PLAYER_MAGE_FAILED_USE;
+ break;
+ case PCLASS_PIG:
+ sound = SFX_PIG_ACTIVE1;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ S_StartSound(usething, sound);
+ }
+ return false; // can't use through a wall
+ }
+ if (usething->player)
+ {
+ pheight = usething->z + (usething->height/2);
+ if ((opentop < pheight) || (openbottom > pheight))
+ {
+ switch (usething->player->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PLAYER_FIGHTER_FAILED_USE;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PLAYER_CLERIC_FAILED_USE;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PLAYER_MAGE_FAILED_USE;
+ break;
+ case PCLASS_PIG:
+ sound = SFX_PIG_ACTIVE1;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ S_StartSound(usething, sound);
+ }
+ }
+ return true; // not a special line, but keep checking
+ }
+
+ if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
+ return false; // don't use back sides
+
+// P_UseSpecialLine (usething, in->d.line);
+ P_ActivateLine(in->d.line, usething, 0, SPAC_USE);
+
+ return false; // can't use for than one special line in a row
+}
+
+
+/*
+================
+=
+= P_UseLines
+=
+= Looks for special lines in front of the player to activate
+================
+*/
+
+void P_UseLines (player_t *player)
+{
+ int angle;
+ fixed_t x1, y1, x2, y2;
+
+ usething = player->mo;
+
+ angle = player->mo->angle >> ANGLETOFINESHIFT;
+ x1 = player->mo->x;
+ y1 = player->mo->y;
+ x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
+ y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
+
+ P_PathTraverse (x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse);
+}
+
+//==========================================================================
+//
+// PTR_PuzzleItemTraverse
+//
+//==========================================================================
+
+#define USE_PUZZLE_ITEM_SPECIAL 129
+
+static mobj_t *PuzzleItemUser;
+static int PuzzleItemType;
+static boolean PuzzleActivated;
+
+static boolean PTR_PuzzleItemTraverse(intercept_t *in)
+{
+ mobj_t *mobj;
+ int sound;
+
+ if (in->isaline)
+ { // Check line
+ if (in->d.line->special != USE_PUZZLE_ITEM_SPECIAL)
+ {
+ P_LineOpening(in->d.line);
+ if (openrange <= 0)
+ {
+ sound = SFX_NONE;
+ if (PuzzleItemUser->player)
+ {
+ switch (PuzzleItemUser->player->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ sound = SFX_PUZZLE_FAIL_FIGHTER;
+ break;
+ case PCLASS_CLERIC:
+ sound = SFX_PUZZLE_FAIL_CLERIC;
+ break;
+ case PCLASS_MAGE:
+ sound = SFX_PUZZLE_FAIL_MAGE;
+ break;
+ default:
+ sound = SFX_NONE;
+ break;
+ }
+ }
+ S_StartSound(PuzzleItemUser, sound);
+ return false; // can't use through a wall
+ }
+ return true; // Continue searching
+ }
+ if (P_PointOnLineSide(PuzzleItemUser->x, PuzzleItemUser->y,
+ in->d.line) == 1)
+ { // Don't use back sides
+ return false;
+ }
+ if (PuzzleItemType != in->d.line->arg1)
+ { // Item type doesn't match
+ return false;
+ }
+ P_StartACS(in->d.line->arg2, 0, &in->d.line->arg3,
+ PuzzleItemUser, in->d.line, 0);
+ in->d.line->special = 0;
+ PuzzleActivated = true;
+ return false; // Stop searching
+ }
+ // Check thing
+ mobj = in->d.thing;
+ if (mobj->special != USE_PUZZLE_ITEM_SPECIAL)
+ { // Wrong special
+ return true;
+ }
+ if (PuzzleItemType != mobj->args[0])
+ { // Item type doesn't match
+ return true;
+ }
+ P_StartACS(mobj->args[1], 0, &mobj->args[2], PuzzleItemUser, NULL, 0);
+ mobj->special = 0;
+ PuzzleActivated = true;
+ return false; // Stop searching
+}
+
+//==========================================================================
+//
+// P_UsePuzzleItem
+//
+// Returns true if the puzzle item was used on a line or a thing.
+//
+//==========================================================================
+
+boolean P_UsePuzzleItem(player_t *player, int itemType)
+{
+ int angle;
+ fixed_t x1, y1, x2, y2;
+
+ PuzzleItemType = itemType;
+ PuzzleItemUser = player->mo;
+ PuzzleActivated = false;
+ angle = player->mo->angle>>ANGLETOFINESHIFT;
+ x1 = player->mo->x;
+ y1 = player->mo->y;
+ x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
+ y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
+ P_PathTraverse(x1, y1, x2, y2, PT_ADDLINES|PT_ADDTHINGS,
+ PTR_PuzzleItemTraverse);
+ return PuzzleActivated;
+}
+
+/*
+==============================================================================
+
+ RADIUS ATTACK
+
+==============================================================================
+*/
+
+static mobj_t *bombsource;
+static mobj_t *bombspot;
+static int bombdamage;
+static int bombdistance;
+static boolean DamageSource;
+
+/*
+=================
+=
+= PIT_RadiusAttack
+=
+= Source is the creature that casued the explosion at spot
+=================
+*/
+
+static boolean PIT_RadiusAttack (mobj_t *thing)
+{
+ fixed_t dx, dy, dist;
+ int damage;
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ {
+ return true;
+ }
+// if (thing->flags2 & MF2_BOSS)
+// { // Bosses take no damage from PIT_RadiusAttack
+// return true;
+// }
+ if (!DamageSource && thing == bombsource)
+ { // don't damage the source of the explosion
+ return true;
+ }
+ if (abs((thing->z - bombspot->z)>>FRACBITS) > 2*bombdistance)
+ { // too high/low
+ return true;
+ }
+ dx = abs(thing->x - bombspot->x);
+ dy = abs(thing->y - bombspot->y);
+ dist = dx > dy ? dx : dy;
+ dist = (dist - thing->radius)>>FRACBITS;
+ if (dist < 0)
+ {
+ dist = 0;
+ }
+ if (dist >= bombdistance)
+ { // Out of range
+ return true;
+ }
+ if (P_CheckSight(thing, bombspot))
+ { // OK to damage, target is in direct path
+ damage = (bombdamage * (bombdistance - dist) / bombdistance) + 1;
+ if (thing->player)
+ {
+ damage >>= 2;
+ }
+ P_DamageMobj(thing, bombspot, bombsource, damage);
+ }
+ return true;
+}
+
+/*
+=================
+=
+= P_RadiusAttack
+=
+= Source is the creature that caused the explosion at spot
+=================
+*/
+
+void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage, int distance,
+ boolean damageSource)
+{
+ int x, y, xl, xh, yl, yh;
+ fixed_t dist;
+
+ dist = (distance + MAXRADIUS)<<FRACBITS;
+ yh = (spot->y + dist-bmaporgy)>>MAPBLOCKSHIFT;
+ yl = (spot->y - dist-bmaporgy)>>MAPBLOCKSHIFT;
+ xh = (spot->x + dist-bmaporgx)>>MAPBLOCKSHIFT;
+ xl = (spot->x - dist-bmaporgx)>>MAPBLOCKSHIFT;
+ bombspot = spot;
+ bombsource = source;
+ bombdamage = damage;
+ bombdistance = distance;
+ DamageSource = damageSource;
+ for (y = yl; y <= yh; y++)
+ {
+ for (x = xl; x <= xh; x++)
+ {
+ P_BlockThingsIterator(x, y, PIT_RadiusAttack);
+ }
+ }
+}
+
+/*
+==============================================================================
+
+ SECTOR HEIGHT CHANGING
+
+= After modifying a sectors floor or ceiling height, call this
+= routine to adjust the positions of all things that touch the
+= sector.
+=
+= If anything doesn't fit anymore, true will be returned.
+= If crunch is true, they will take damage as they are being crushed
+= If Crunch is false, you should set the sector height back the way it
+= was and call P_ChangeSector again to undo the changes
+==============================================================================
+*/
+
+static int crushchange;
+static boolean nofit;
+
+/*
+===============
+=
+= PIT_ChangeSector
+=
+===============
+*/
+
+static boolean PIT_ChangeSector (mobj_t *thing)
+{
+ mobj_t *mo;
+
+ if (P_ThingHeightClip (thing))
+ return true; // keep checking
+
+ // crunch bodies to giblets
+ if ((thing->flags & MF_CORPSE) && (thing->health <= 0))
+ {
+ if (thing->flags & MF_NOBLOOD)
+ {
+ P_RemoveMobj (thing);
+ }
+ else
+ {
+ if (thing->state != &states[S_GIBS1])
+ {
+ P_SetMobjState (thing, S_GIBS1);
+ thing->height = 0;
+ thing->radius = 0;
+ S_StartSound(thing, SFX_PLAYER_FALLING_SPLAT);
+ }
+ }
+ return true; // keep checking
+ }
+
+ // crunch dropped items
+ if (thing->flags2 & MF2_DROPPED)
+ {
+ P_RemoveMobj (thing);
+ return true; // keep checking
+ }
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ return true; // assume it is bloody gibs or something
+
+ nofit = true;
+ if (crushchange && !(leveltime & 3))
+ {
+ P_DamageMobj(thing, NULL, NULL, crushchange);
+ // spray blood in a random direction
+ if ((!(thing->flags & MF_NOBLOOD)) &&
+ (!(thing->flags2 & MF2_INVULNERABLE)))
+ {
+ mo = P_SpawnMobj (thing->x, thing->y, thing->z + thing->height/2,
+ MT_BLOOD);
+ mo->momx = (P_Random() - P_Random())<<12;
+ mo->momy = (P_Random() - P_Random())<<12;
+ }
+ }
+
+ return true; // keep checking (crush other things)
+}
+
+/*
+===============
+=
+= P_ChangeSector
+=
+===============
+*/
+
+boolean P_ChangeSector (sector_t *sector, int crunch)
+{
+ int x, y;
+
+ nofit = false;
+ crushchange = crunch;
+
+// recheck heights for all things near the moving sector
+ for (x = sector->blockbox[BOXLEFT]; x <= sector->blockbox[BOXRIGHT]; x++)
+ {
+ for (y = sector->blockbox[BOXBOTTOM]; y <= sector->blockbox[BOXTOP]; y++)
+ P_BlockThingsIterator (x, y, PIT_ChangeSector);
+ }
+
+ return nofit;
+}
+
--- /dev/null
+++ b/p_maputl.c
@@ -1,0 +1,1059 @@
+
+//**************************************************************************
+//**
+//** p_maputl.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+
+extern polyblock_t **PolyBlockMap;
+
+static mobj_t *RoughBlockCheck(mobj_t *mo, int idx);
+
+//===========================================================================
+
+
+/*
+===================
+=
+= P_AproxDistance
+=
+= Gives an estimation of distance (not exact)
+=
+===================
+*/
+
+fixed_t P_AproxDistance (fixed_t dx, fixed_t dy)
+{
+ dx = abs(dx);
+ dy = abs(dy);
+ if (dx < dy)
+ return dx + dy - (dx>>1);
+ return dx + dy - (dy>>1);
+}
+
+
+/*
+==================
+=
+= P_PointOnLineSide
+=
+= Returns 0 or 1
+==================
+*/
+
+int P_PointOnLineSide (fixed_t x, fixed_t y, line_t *line)
+{
+ fixed_t dx, dy;
+ fixed_t left, right;
+
+ if (!line->dx)
+ {
+ if (x <= line->v1->x)
+ return line->dy > 0;
+ return line->dy < 0;
+ }
+ if (!line->dy)
+ {
+ if (y <= line->v1->y)
+ return line->dx < 0;
+ return line->dx > 0;
+ }
+
+ dx = (x - line->v1->x);
+ dy = (y - line->v1->y);
+
+ left = FixedMul (line->dy>>FRACBITS, dx);
+ right = FixedMul (dy, line->dx>>FRACBITS);
+
+ if (right < left)
+ return 0; // front side
+ return 1; // back side
+}
+
+
+/*
+=================
+=
+= P_BoxOnLineSide
+=
+= Considers the line to be infinite
+= Returns side 0 or 1, -1 if box crosses the line
+=================
+*/
+
+int P_BoxOnLineSide (fixed_t *tmbox, line_t *ld)
+{
+ int p1 = 0, p2 = 0;
+
+ switch (ld->slopetype)
+ {
+ case ST_HORIZONTAL:
+ p1 = tmbox[BOXTOP] > ld->v1->y;
+ p2 = tmbox[BOXBOTTOM] > ld->v1->y;
+ if (ld->dx < 0)
+ {
+ p1 ^= 1;
+ p2 ^= 1;
+ }
+ break;
+ case ST_VERTICAL:
+ p1 = tmbox[BOXRIGHT] < ld->v1->x;
+ p2 = tmbox[BOXLEFT] < ld->v1->x;
+ if (ld->dy < 0)
+ {
+ p1 ^= 1;
+ p2 ^= 1;
+ }
+ break;
+ case ST_POSITIVE:
+ p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld);
+ p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
+ break;
+ case ST_NEGATIVE:
+ p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
+ p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
+ break;
+ }
+
+ if (p1 == p2)
+ return p1;
+ return -1;
+}
+
+/*
+==================
+=
+= P_PointOnDivlineSide
+=
+= Returns 0 or 1
+==================
+*/
+
+int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t *line)
+{
+ fixed_t dx, dy;
+ fixed_t left, right;
+
+ if (!line->dx)
+ {
+ if (x <= line->x)
+ return line->dy > 0;
+ return line->dy < 0;
+ }
+ if (!line->dy)
+ {
+ if (y <= line->y)
+ return line->dx < 0;
+ return line->dx > 0;
+ }
+
+ dx = (x - line->x);
+ dy = (y - line->y);
+
+// try to quickly decide by looking at sign bits
+ if ((line->dy ^ line->dx ^ dx ^ dy) & 0x80000000)
+ {
+ if ((line->dy ^ dx) & 0x80000000)
+ return 1; // (left is negative)
+ return 0;
+ }
+
+ left = FixedMul (line->dy>>8, dx>>8);
+ right = FixedMul (dy>>8, line->dx>>8);
+
+ if (right < left)
+ return 0; // front side
+ return 1; // back side
+}
+
+
+/*
+==============
+=
+= P_MakeDivline
+=
+==============
+*/
+
+void P_MakeDivline (line_t *li, divline_t *dl)
+{
+ dl->x = li->v1->x;
+ dl->y = li->v1->y;
+ dl->dx = li->dx;
+ dl->dy = li->dy;
+}
+
+
+/*
+===============
+=
+= P_InterceptVector
+=
+= Returns the fractional intercept point along the first divline
+=
+= This is only called by the addthings and addlines traversers
+===============
+*/
+
+fixed_t P_InterceptVector (divline_t *v2, divline_t *v1)
+{
+#if 1
+ fixed_t frac, num, den;
+
+ den = FixedMul(v1->dy>>8, v2->dx) - FixedMul(v1->dx>>8, v2->dy);
+ if (den == 0)
+ return 0;
+// I_Error ("P_InterceptVector: parallel");
+ num = FixedMul((v1->x - v2->x)>>8, v1->dy) +
+ FixedMul ((v2->y - v1->y)>>8, v1->dx);
+ frac = FixedDiv (num , den);
+
+ return frac;
+#else
+ float frac, num, den, v1x, v1y, v1dx, v1dy, v2x, v2y, v2dx, v2dy;
+
+ v1x = (float)v1->x/FRACUNIT;
+ v1y = (float)v1->y/FRACUNIT;
+ v1dx = (float)v1->dx/FRACUNIT;
+ v1dy = (float)v1->dy/FRACUNIT;
+ v2x = (float)v2->x/FRACUNIT;
+ v2y = (float)v2->y/FRACUNIT;
+ v2dx = (float)v2->dx/FRACUNIT;
+ v2dy = (float)v2->dy/FRACUNIT;
+
+ den = v1dy*v2dx - v1dx*v2dy;
+ if (den == 0)
+ return 0; // parallel
+ num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
+ frac = num / den;
+
+ return frac*FRACUNIT;
+#endif
+}
+
+/*
+==================
+=
+= P_LineOpening
+=
+= Sets opentop and openbottom to the window through a two sided line
+= OPTIMIZE: keep this precalculated
+==================
+*/
+
+fixed_t opentop, openbottom, openrange;
+fixed_t lowfloor;
+
+void P_LineOpening (line_t *ld)
+{
+ sector_t *front, *back;
+
+ if (ld->sidenum[1] == -1)
+ { // single sided line
+ openrange = 0;
+ return;
+ }
+
+ front = ld->frontsector;
+ back = ld->backsector;
+
+ if (front->ceilingheight < back->ceilingheight)
+ opentop = front->ceilingheight;
+ else
+ opentop = back->ceilingheight;
+ if (front->floorheight > back->floorheight)
+ {
+ openbottom = front->floorheight;
+ lowfloor = back->floorheight;
+ tmfloorpic = front->floorpic;
+ }
+ else
+ {
+ openbottom = back->floorheight;
+ lowfloor = front->floorheight;
+ tmfloorpic = back->floorpic;
+ }
+
+ openrange = opentop - openbottom;
+}
+
+/*
+===============================================================================
+
+ THING POSITION SETTING
+
+===============================================================================
+*/
+
+/*
+===================
+=
+= P_UnsetThingPosition
+=
+= Unlinks a thing from block map and sectors
+=
+===================
+*/
+
+void P_UnsetThingPosition (mobj_t *thing)
+{
+ int blockx, blocky;
+
+ if (! (thing->flags & MF_NOSECTOR))
+ { // inert things don't need to be in blockmap
+ // unlink from subsector
+ if (thing->snext)
+ thing->snext->sprev = thing->sprev;
+ if (thing->sprev)
+ thing->sprev->snext = thing->snext;
+ else
+ thing->subsector->sector->thinglist = thing->snext;
+ }
+
+ if (! (thing->flags & MF_NOBLOCKMAP))
+ { // inert things don't need to be in blockmap
+ // unlink from block map
+ if (thing->bnext)
+ thing->bnext->bprev = thing->bprev;
+ if (thing->bprev)
+ thing->bprev->bnext = thing->bnext;
+ else
+ {
+ blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
+ blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
+ if (blockx >= 0 && blockx < bmapwidth &&
+ blocky >= 0 && blocky < bmapheight)
+ {
+ blocklinks[blocky*bmapwidth+blockx] = thing->bnext;
+ }
+ }
+ }
+}
+
+
+/*
+===================
+=
+= P_SetThingPosition
+=
+= Links a thing into both a block and a subsector based on it's x y
+= Sets thing->subsector properly
+=
+===================
+*/
+
+void P_SetThingPosition (mobj_t *thing)
+{
+ subsector_t *ss;
+ sector_t *sec;
+ int blockx, blocky;
+ mobj_t **link;
+
+//
+// link into subsector
+//
+ ss = R_PointInSubsector (thing->x, thing->y);
+ thing->subsector = ss;
+ if (! (thing->flags & MF_NOSECTOR))
+ { // invisible things don't go into the sector links
+ sec = ss->sector;
+
+ thing->sprev = NULL;
+ thing->snext = sec->thinglist;
+ if (sec->thinglist)
+ sec->thinglist->sprev = thing;
+ sec->thinglist = thing;
+ }
+
+//
+// link into blockmap
+//
+ if (! (thing->flags & MF_NOBLOCKMAP))
+ { // inert things don't need to be in blockmap
+ blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
+ blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
+ if (blockx >= 0 && blockx < bmapwidth && blocky >= 0 && blocky < bmapheight)
+ {
+ link = &blocklinks[blocky*bmapwidth + blockx];
+ thing->bprev = NULL;
+ thing->bnext = *link;
+ if (*link)
+ (*link)->bprev = thing;
+ *link = thing;
+ }
+ else
+ { // thing is off the map
+ thing->bnext = thing->bprev = NULL;
+ }
+ }
+}
+
+
+/*
+===============================================================================
+
+ BLOCK MAP ITERATORS
+
+For each line/thing in the given mapblock, call the passed function.
+If the function returns false, exit with false without checking anything else.
+
+===============================================================================
+*/
+
+/*
+==================
+=
+= P_BlockLinesIterator
+=
+= The validcount flags are used to avoid checking lines
+= that are marked in multiple mapblocks, so increment validcount before
+= the first call to P_BlockLinesIterator, then make one or more calls to it
+===================
+*/
+
+boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*) )
+{
+ int offset;
+ short *list;
+ line_t *ld;
+
+ int i;
+ polyblock_t *polyLink;
+ seg_t **tempSeg;
+
+ if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
+ return true;
+ offset = y*bmapwidth + x;
+
+ polyLink = PolyBlockMap[offset];
+ while (polyLink)
+ {
+ if (polyLink->polyobj)
+ {
+ if (polyLink->polyobj->validcount != validcount)
+ {
+ polyLink->polyobj->validcount = validcount;
+ tempSeg = polyLink->polyobj->segs;
+ for (i = 0; i < polyLink->polyobj->numsegs; i++, tempSeg++)
+ {
+ if ((*tempSeg)->linedef->validcount == validcount)
+ {
+ continue;
+ }
+ (*tempSeg)->linedef->validcount = validcount;
+ if (!func((*tempSeg)->linedef))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ polyLink = polyLink->next;
+ }
+
+ offset = *(blockmap+offset);
+
+ for (list = blockmaplump + offset; *list != -1; list++)
+ {
+ ld = &lines[*list];
+ if (ld->validcount == validcount)
+ continue; // line has already been checked
+ ld->validcount = validcount;
+
+ if ( !func(ld) )
+ return false;
+ }
+
+ return true; // everything was checked
+}
+
+
+/*
+==================
+=
+= P_BlockThingsIterator
+=
+==================
+*/
+
+boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*) )
+{
+ mobj_t *mobj;
+
+ if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
+ return true;
+
+ for (mobj = blocklinks[y*bmapwidth + x]; mobj; mobj = mobj->bnext)
+ {
+ if (!func( mobj ) )
+ return false;
+ }
+
+ return true;
+}
+
+/*
+===============================================================================
+
+ INTERCEPT ROUTINES
+
+===============================================================================
+*/
+
+intercept_t intercepts[MAXINTERCEPTS], *intercept_p;
+divline_t trace;
+static boolean earlyout;
+
+/*
+==================
+=
+= PIT_AddLineIntercepts
+=
+= Looks for lines in the given block that intercept the given trace
+= to add to the intercepts list
+= A line is crossed if its endpoints are on opposite sides of the trace
+= Returns true if earlyout and a solid line hit
+==================
+*/
+
+static boolean PIT_AddLineIntercepts (line_t *ld)
+{
+ int s1, s2;
+ fixed_t frac;
+ divline_t dl;
+
+// avoid precision problems with two routines
+ if (trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16 ||
+ trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16)
+ {
+ s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
+ s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
+ }
+ else
+ {
+ s1 = P_PointOnLineSide (trace.x, trace.y, ld);
+ s2 = P_PointOnLineSide (trace.x + trace.dx, trace.y + trace.dy, ld);
+ }
+ if (s1 == s2)
+ return true; // line isn't crossed
+
+//
+// hit the line
+//
+ P_MakeDivline (ld, &dl);
+ frac = P_InterceptVector (&trace, &dl);
+ if (frac < 0)
+ return true; // behind source
+
+// try to early out the check
+ if (earlyout && frac < FRACUNIT && !ld->backsector)
+ return false; // stop checking
+
+ intercept_p->frac = frac;
+ intercept_p->isaline = true;
+ intercept_p->d.line = ld;
+ intercept_p++;
+
+ return true; // continue
+}
+
+
+/*
+==================
+=
+= PIT_AddThingIntercepts
+=
+==================
+*/
+
+static boolean PIT_AddThingIntercepts (mobj_t *thing)
+{
+ fixed_t x1, y1, x2, y2;
+ int s1, s2;
+ boolean tracepositive;
+ divline_t dl;
+ fixed_t frac;
+
+ tracepositive = (trace.dx ^ trace.dy) > 0;
+
+ // check a corner to corner crossection for hit
+
+ if (tracepositive)
+ {
+ x1 = thing->x - thing->radius;
+ y1 = thing->y + thing->radius;
+
+ x2 = thing->x + thing->radius;
+ y2 = thing->y - thing->radius;
+ }
+ else
+ {
+ x1 = thing->x - thing->radius;
+ y1 = thing->y - thing->radius;
+
+ x2 = thing->x + thing->radius;
+ y2 = thing->y + thing->radius;
+ }
+ s1 = P_PointOnDivlineSide (x1, y1, &trace);
+ s2 = P_PointOnDivlineSide (x2, y2, &trace);
+ if (s1 == s2)
+ return true; // line isn't crossed
+
+ dl.x = x1;
+ dl.y = y1;
+ dl.dx = x2 - x1;
+ dl.dy = y2 - y1;
+ frac = P_InterceptVector (&trace, &dl);
+ if (frac < 0)
+ return true; // behind source
+ intercept_p->frac = frac;
+ intercept_p->isaline = false;
+ intercept_p->d.thing = thing;
+ intercept_p++;
+
+ return true; // keep going
+}
+
+
+/*
+====================
+=
+= P_TraverseIntercepts
+=
+= Returns true if the traverser function returns true for all lines
+====================
+*/
+
+boolean P_TraverseIntercepts (traverser_t func, fixed_t maxfrac)
+{
+ int count;
+ fixed_t dist;
+ intercept_t *scan, *in;
+
+ count = intercept_p - intercepts;
+ in = NULL; // shut up compiler warning
+
+ while (count--)
+ {
+ dist = H2MAXINT;
+ for (scan = intercepts; scan < intercept_p; scan++)
+ {
+ if (scan->frac < dist)
+ {
+ dist = scan->frac;
+ in = scan;
+ }
+ }
+
+ if (dist > maxfrac)
+ return true; // checked everything in range
+#if 0
+ { // don't check these yet, ther may be others inserted
+ in = scan = intercepts;
+ for (scan = intercepts; scan < intercept_p; scan++)
+ {
+ if (scan->frac > maxfrac)
+ *in++ = *scan;
+ }
+ intercept_p = in;
+ return false;
+ }
+#endif
+
+ if ( !func (in) )
+ return false; // don't bother going farther
+ in->frac = H2MAXINT;
+ }
+
+ return true; // everything was traversed
+}
+
+
+/*
+==================
+=
+= P_PathTraverse
+=
+= Traces a line from x1,y1 to x2,y2, calling the traverser function for each
+= Returns true if the traverser function returns true for all lines
+==================
+*/
+
+boolean P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
+ int flags, boolean (*trav) (intercept_t *))
+{
+ fixed_t xt1,yt1,xt2,yt2;
+ fixed_t xstep,ystep;
+ fixed_t partial;
+ fixed_t xintercept, yintercept;
+ int mapx, mapy, mapxstep, mapystep;
+ int count;
+
+ earlyout = flags & PT_EARLYOUT;
+
+ validcount++;
+ intercept_p = intercepts;
+
+ if (((x1 - bmaporgx) & (MAPBLOCKSIZE - 1)) == 0)
+ x1 += FRACUNIT; // don't side exactly on a line
+ if (((y1 - bmaporgy) & (MAPBLOCKSIZE - 1)) == 0)
+ y1 += FRACUNIT; // don't side exactly on a line
+ trace.x = x1;
+ trace.y = y1;
+ trace.dx = x2 - x1;
+ trace.dy = y2 - y1;
+
+ x1 -= bmaporgx;
+ y1 -= bmaporgy;
+ xt1 = x1>>MAPBLOCKSHIFT;
+ yt1 = y1>>MAPBLOCKSHIFT;
+
+ x2 -= bmaporgx;
+ y2 -= bmaporgy;
+ xt2 = x2>>MAPBLOCKSHIFT;
+ yt2 = y2>>MAPBLOCKSHIFT;
+
+ if (xt2 > xt1)
+ {
+ mapxstep = 1;
+ partial = FRACUNIT - ((x1>>MAPBTOFRAC) & (FRACUNIT - 1));
+ ystep = FixedDiv (y2 - y1, abs(x2 - x1));
+ }
+ else if (xt2 < xt1)
+ {
+ mapxstep = -1;
+ partial = (x1>>MAPBTOFRAC) & (FRACUNIT - 1);
+ ystep = FixedDiv (y2 - y1, abs(x2 - x1));
+ }
+ else
+ {
+ mapxstep = 0;
+ partial = FRACUNIT;
+ ystep = 256*FRACUNIT;
+ }
+ yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
+
+ if (yt2 > yt1)
+ {
+ mapystep = 1;
+ partial = FRACUNIT - ((y1>>MAPBTOFRAC) & (FRACUNIT - 1));
+ xstep = FixedDiv (x2 - x1, abs(y2 - y1));
+ }
+ else if (yt2 < yt1)
+ {
+ mapystep = -1;
+ partial = (y1>>MAPBTOFRAC) & (FRACUNIT - 1);
+ xstep = FixedDiv (x2 - x1, abs(y2 - y1));
+ }
+ else
+ {
+ mapystep = 0;
+ partial = FRACUNIT;
+ xstep = 256*FRACUNIT;
+ }
+ xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
+
+//
+// step through map blocks
+// Count is present to prevent a round off error from skipping the break
+ mapx = xt1;
+ mapy = yt1;
+
+ for (count = 0; count < 64; count++)
+ {
+ if (flags & PT_ADDLINES)
+ {
+ if (!P_BlockLinesIterator (mapx, mapy, PIT_AddLineIntercepts))
+ return false; // early out
+ }
+ if (flags & PT_ADDTHINGS)
+ {
+ if (!P_BlockThingsIterator (mapx, mapy, PIT_AddThingIntercepts))
+ return false; // early out
+ }
+
+ if (mapx == xt2 && mapy == yt2)
+ break;
+
+ if ((yintercept >> FRACBITS) == mapy)
+ {
+ yintercept += ystep;
+ mapx += mapxstep;
+ }
+ else if ((xintercept >> FRACBITS) == mapx)
+ {
+ xintercept += xstep;
+ mapy += mapystep;
+ }
+ }
+
+//
+// go through the sorted list
+//
+ return P_TraverseIntercepts (trav, FRACUNIT);
+}
+
+//===========================================================================
+//
+// P_RoughMonsterSearch
+//
+// Searches though the surrounding mapblocks for monsters/players
+// distance is in MAPBLOCKUNITS
+//===========================================================================
+
+mobj_t *P_RoughMonsterSearch(mobj_t *mo, int distance)
+{
+ int blockX;
+ int blockY;
+ int startX, startY;
+ int blockIndex;
+ int firstStop;
+ int secondStop;
+ int thirdStop;
+ int finalStop;
+ int count;
+ mobj_t *target;
+
+ startX = (mo->x - bmaporgx)>>MAPBLOCKSHIFT;
+ startY = (mo->y - bmaporgy)>>MAPBLOCKSHIFT;
+
+ if (startX >= 0 && startX < bmapwidth && startY >= 0 && startY < bmapheight)
+ {
+ if ((target = RoughBlockCheck(mo, startY*bmapwidth + startX)))
+ { // found a target right away
+ return target;
+ }
+ }
+ for (count = 1; count <= distance; count++)
+ {
+ blockX = startX - count;
+ blockY = startY - count;
+
+ if (blockY < 0)
+ {
+ blockY = 0;
+ }
+ else if (blockY >= bmapheight)
+ {
+ blockY = bmapheight - 1;
+ }
+ if (blockX < 0)
+ {
+ blockX = 0;
+ }
+ else if (blockX >= bmapwidth)
+ {
+ blockX = bmapwidth - 1;
+ }
+ blockIndex = blockY*bmapwidth + blockX;
+ firstStop = startX + count;
+ if (firstStop < 0)
+ {
+ continue;
+ }
+ if (firstStop >= bmapwidth)
+ {
+ firstStop = bmapwidth - 1;
+ }
+ secondStop = startY + count;
+ if (secondStop < 0)
+ {
+ continue;
+ }
+ if (secondStop >= bmapheight)
+ {
+ secondStop = bmapheight - 1;
+ }
+ thirdStop = secondStop*bmapwidth + blockX;
+ secondStop = secondStop*bmapwidth + firstStop;
+ firstStop += blockY*bmapwidth;
+ finalStop = blockIndex;
+
+ // Trace the first block section (along the top)
+ for ( ; blockIndex <= firstStop; blockIndex++)
+ {
+ if ((target = RoughBlockCheck(mo, blockIndex)))
+ {
+ return target;
+ }
+ }
+ // Trace the second block section (right edge)
+ for (blockIndex--; blockIndex <= secondStop; blockIndex += bmapwidth)
+ {
+ if ((target = RoughBlockCheck(mo, blockIndex)))
+ {
+ return target;
+ }
+ }
+ // Trace the third block section (bottom edge)
+ for (blockIndex -= bmapwidth; blockIndex >= thirdStop; blockIndex--)
+ {
+ if ((target = RoughBlockCheck(mo, blockIndex)))
+ {
+ return target;
+ }
+ }
+ // Trace the final block section (left edge)
+ for (blockIndex++; blockIndex > finalStop; blockIndex -= bmapwidth)
+ {
+ if ((target = RoughBlockCheck(mo, blockIndex)))
+ {
+ return target;
+ }
+ }
+ }
+ return NULL;
+}
+
+//===========================================================================
+//
+// RoughBlockCheck
+//
+//===========================================================================
+
+static mobj_t *RoughBlockCheck(mobj_t *mo, int idx)
+{
+ mobj_t *link;
+ mobj_t *master;
+ angle_t angle;
+
+ link = blocklinks[idx];
+ while (link)
+ {
+ if (mo->player) // Minotaur looking around player
+ {
+ if ((link->flags & MF_COUNTKILL) ||
+ (link->player && (link != mo)))
+ {
+ if (!(link->flags & MF_SHOOTABLE))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (link->flags2 & MF2_DORMANT)
+ {
+ link = link->bnext;
+ continue;
+ }
+ if ((link->type == MT_MINOTAUR) &&
+ (((mobj_t *)link->special1) == mo))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (netgame && !deathmatch && link->player)
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (P_CheckSight(mo, link))
+ {
+ return link;
+ }
+ }
+ link = link->bnext;
+ }
+ else if (mo->type == MT_MINOTAUR) // looking around minotaur
+ {
+ master = (mobj_t *)mo->special1;
+ if ((link->flags & MF_COUNTKILL) ||
+ (link->player && (link != master)))
+ {
+ if (!(link->flags & MF_SHOOTABLE))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (link->flags2 & MF2_DORMANT)
+ {
+ link = link->bnext;
+ continue;
+ }
+ if ((link->type == MT_MINOTAUR) &&
+ (link->special1 == mo->special1))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (netgame && !deathmatch && link->player)
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (P_CheckSight(mo, link))
+ {
+ return link;
+ }
+ }
+ link = link->bnext;
+ }
+ else if (mo->type == MT_MSTAFF_FX2) // bloodscourge
+ {
+ if ((link->flags & MF_COUNTKILL ||
+ (link->player && link != mo->target))
+ && !(link->flags2 & MF2_DORMANT))
+ {
+ if (!(link->flags & MF_SHOOTABLE))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (netgame && !deathmatch && link->player)
+ {
+ link = link->bnext;
+ continue;
+ }
+ else if (P_CheckSight(mo, link))
+ {
+ master = mo->target;
+ angle = R_PointToAngle2(master->x, master->y,
+ link->x, link->y) - master->angle;
+ angle >>= 24;
+ if (angle > 226 || angle < 30)
+ {
+ return link;
+ }
+ }
+ }
+ link = link->bnext;
+ }
+ else // spirits
+ {
+ if ((link->flags & MF_COUNTKILL ||
+ (link->player && link != mo->target))
+ && !(link->flags2 & MF2_DORMANT))
+ {
+ if (!(link->flags & MF_SHOOTABLE))
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (netgame && !deathmatch && link->player)
+ {
+ link = link->bnext;
+ continue;
+ }
+ if (link == mo->target)
+ {
+ link = link->bnext;
+ continue;
+ }
+ else if (P_CheckSight(mo, link))
+ {
+ return link;
+ }
+ }
+ link = link->bnext;
+ }
+ }
+ return NULL;
+}
+
--- /dev/null
+++ b/p_mobj.c
@@ -1,0 +1,2491 @@
+
+//**************************************************************************
+//**
+//** p_mobj.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "sounds.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_TID_COUNT 200
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void G_PlayerReborn(int player);
+void P_MarkAsLeaving(mobj_t *corpse);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+void P_SpawnMapThing(mapthing_t *mthing);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void PlayerLandedOnThing(mobj_t *mo, mobj_t *onmobj);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern boolean demorecording;
+extern boolean demoplayback;
+extern mobj_t LavaInflictor;
+
+extern fixed_t attackrange;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+mobjtype_t PuffType;
+mobj_t *MissileMobj;
+
+fixed_t FloatBobOffsets[64] =
+{
+ 0, 51389, 102283, 152192,
+ 200636, 247147, 291278, 332604,
+ 370727, 405280, 435929, 462380,
+ 484378, 501712, 514213, 521763,
+ 524287, 521763, 514213, 501712,
+ 484378, 462380, 435929, 405280,
+ 370727, 332604, 291278, 247147,
+ 200636, 152192, 102283, 51389,
+ -1, -51390, -102284, -152193,
+ -200637, -247148, -291279, -332605,
+ -370728, -405281, -435930, -462381,
+ -484380, -501713, -514215, -521764,
+ -524288, -521764, -514214, -501713,
+ -484379, -462381, -435930, -405280,
+ -370728, -332605, -291279, -247148,
+ -200637, -152193, -102284, -51389
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int TIDList[MAX_TID_COUNT + 1]; /* +1 for termination marker */
+static mobj_t *TIDMobj[MAX_TID_COUNT];
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_SetMobjState
+//
+// Returns true if the mobj is still present.
+//
+//==========================================================================
+
+boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
+{
+ state_t *st;
+
+ if (state == S_NULL)
+ { // Remove mobj
+ mobj->state = NULL;
+ P_RemoveMobj(mobj);
+ return false;
+ }
+ st = &states[state];
+ mobj->state = st;
+ mobj->tics = st->tics;
+ mobj->sprite = st->sprite;
+ mobj->frame = st->frame;
+ if (st->action)
+ { // Call action function
+ st->action(mobj, nil);
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// P_SetMobjStateNF
+//
+// Same as P_SetMobjState, but does not call the state function.
+//
+//==========================================================================
+
+boolean P_SetMobjStateNF(mobj_t *mobj, statenum_t state)
+{
+ state_t *st;
+
+ if (state == S_NULL)
+ { // Remove mobj
+ mobj->state = NULL;
+ P_RemoveMobj(mobj);
+ return false;
+ }
+ st = &states[state];
+ mobj->state = st;
+ mobj->tics = st->tics;
+ mobj->sprite = st->sprite;
+ mobj->frame = st->frame;
+ return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ExplodeMissile
+//
+//----------------------------------------------------------------------------
+
+void P_ExplodeMissile(mobj_t *mo)
+{
+ mo->momx = mo->momy = mo->momz = 0;
+ P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
+ //mo->tics -= P_Random() & 3;
+ mo->flags &= ~MF_MISSILE;
+
+ switch (mo->type)
+ {
+ case MT_SORCBALL1:
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ S_StartSound(NULL, SFX_SORCERER_BIGBALLEXPLODE);
+ break;
+ case MT_SORCFX1:
+ S_StartSound(NULL, SFX_SORCERER_HEADSCREAM);
+ break;
+ default:
+ if (mo->info->deathsound)
+ {
+ S_StartSound(mo, mo->info->deathsound);
+ }
+ break;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_FloorBounceMissile
+//
+//----------------------------------------------------------------------------
+
+static void P_FloorBounceMissile(mobj_t *mo)
+{
+ if (P_HitFloor(mo) >= FLOOR_LIQUID)
+ {
+ switch (mo->type)
+ {
+ case MT_SORCFX1:
+ case MT_SORCBALL1:
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ break;
+ default:
+ P_RemoveMobj(mo);
+ return;
+ }
+ }
+ switch (mo->type)
+ {
+ case MT_SORCFX1:
+ mo->momz = -mo->momz; // no energy absorbed
+ break;
+ case MT_SGSHARD1:
+ case MT_SGSHARD2:
+ case MT_SGSHARD3:
+ case MT_SGSHARD4:
+ case MT_SGSHARD5:
+ case MT_SGSHARD6:
+ case MT_SGSHARD7:
+ case MT_SGSHARD8:
+ case MT_SGSHARD9:
+ case MT_SGSHARD0:
+ mo->momz = FixedMul(mo->momz, -0.3*FRACUNIT);
+ if (abs(mo->momz) < (FRACUNIT/2))
+ {
+ P_SetMobjState(mo, S_NULL);
+ return;
+ }
+ break;
+ default:
+ mo->momz = FixedMul(mo->momz, -0.7*FRACUNIT);
+ break;
+ }
+ mo->momx = 2*mo->momx/3;
+ mo->momy = 2*mo->momy/3;
+ if (mo->info->seesound)
+ {
+ switch (mo->type)
+ {
+ case MT_SORCBALL1:
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ if (!mo->args[0])
+ S_StartSound(mo, mo->info->seesound);
+ break;
+ default:
+ S_StartSound(mo, mo->info->seesound);
+ break;
+ }
+ S_StartSound(mo, mo->info->seesound);
+ }
+// P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ThrustMobj
+//
+//----------------------------------------------------------------------------
+
+void P_ThrustMobj(mobj_t *mo, angle_t angle, fixed_t move)
+{
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx += FixedMul(move, finecosine[angle]);
+ mo->momy += FixedMul(move, finesine[angle]);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_FaceMobj
+//
+// Returns 1 if 'source' needs to turn clockwise, or 0 if 'source' needs
+// to turn counter clockwise. 'delta' is set to the amount 'source'
+// needs to turn.
+//
+//----------------------------------------------------------------------------
+
+int P_FaceMobj(mobj_t *source, mobj_t *target, angle_t *delta)
+{
+ angle_t diff;
+ angle_t angle1;
+ angle_t angle2;
+
+ angle1 = source->angle;
+ angle2 = R_PointToAngle2(source->x, source->y, target->x, target->y);
+ if (angle2 > angle1)
+ {
+ diff = angle2 - angle1;
+ if (diff > ANGLE_180)
+ {
+ *delta = ANGLE_MAX - diff;
+ return 0;
+ }
+ else
+ {
+ *delta = diff;
+ return 1;
+ }
+ }
+ else
+ {
+ diff = angle1 - angle2;
+ if (diff > ANGLE_180)
+ {
+ *delta = ANGLE_MAX - diff;
+ return 1;
+ }
+ else
+ {
+ *delta = diff;
+ return 0;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+//
+// The missile special1 field must be mobj_t *target. Returns true if
+// target was tracked, false if not.
+//
+//----------------------------------------------------------------------------
+
+boolean P_SeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax)
+{
+ int dir;
+ int dist;
+ angle_t delta;
+ angle_t angle;
+ mobj_t *target;
+
+ target = (mobj_t *)actor->special1;
+ if (target == NULL)
+ {
+ return false;
+ }
+ if (!(target->flags & MF_SHOOTABLE))
+ { // Target died
+ actor->special1 = 0;
+ return false;
+ }
+ dir = P_FaceMobj(actor, target, &delta);
+ if (delta > thresh)
+ {
+ delta >>= 1;
+ if (delta > turnMax)
+ {
+ delta = turnMax;
+ }
+ }
+ if (dir)
+ { // Turn clockwise
+ actor->angle += delta;
+ }
+ else
+ { // Turn counter clockwise
+ actor->angle -= delta;
+ }
+ angle = actor->angle>>ANGLETOFINESHIFT;
+ actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+ actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+ if (actor->z + actor->height < target->z
+ || target->z + target->height < actor->z)
+ { // Need to seek vertically
+ dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+ dist = dist/actor->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ actor->momz = (target->z + (target->height>>1)
+ - (actor->z + (actor->height>>1)))/dist;
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_XYMovement
+//
+//----------------------------------------------------------------------------
+
+#define STOPSPEED 0x1000
+#define FRICTION_NORMAL 0xe800
+#define FRICTION_LOW 0xf900
+#define FRICTION_FLY 0xeb00
+
+static void P_XYMovement(mobj_t *mo)
+{
+ fixed_t ptryx, ptryy;
+ player_t *player;
+ fixed_t xmove, ymove;
+ int special;
+ angle_t angle;
+ static int windTab[3] = {2048*5, 2048*10, 2048*25};
+
+ if (!mo->momx && !mo->momy)
+ {
+ if (mo->flags & MF_SKULLFLY)
+ { // A flying mobj slammed into something
+ mo->flags &= ~MF_SKULLFLY;
+ mo->momx = mo->momy = mo->momz = 0;
+ P_SetMobjState(mo, mo->info->seestate);
+ }
+ return;
+ }
+ special = mo->subsector->sector->special;
+ if (mo->flags2 & MF2_WINDTHRUST)
+ {
+ switch (special)
+ {
+ case 40: case 41: case 42: // Wind_East
+ P_ThrustMobj(mo, 0, windTab[special-40]);
+ break;
+ case 43: case 44: case 45: // Wind_North
+ P_ThrustMobj(mo, ANG90, windTab[special-43]);
+ break;
+ case 46: case 47: case 48: // Wind_South
+ P_ThrustMobj(mo, ANG270, windTab[special-46]);
+ break;
+ case 49: case 50: case 51: // Wind_West
+ P_ThrustMobj(mo, ANG180, windTab[special-49]);
+ break;
+ }
+ }
+ player = mo->player;
+ if (mo->momx > MAXMOVE)
+ {
+ mo->momx = MAXMOVE;
+ }
+ else if (mo->momx < -MAXMOVE)
+ {
+ mo->momx = -MAXMOVE;
+ }
+ if (mo->momy > MAXMOVE)
+ {
+ mo->momy = MAXMOVE;
+ }
+ else if (mo->momy < -MAXMOVE)
+ {
+ mo->momy = -MAXMOVE;
+ }
+ xmove = mo->momx;
+ ymove = mo->momy;
+ do
+ {
+ if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2)
+ {
+ ptryx = mo->x + xmove/2;
+ ptryy = mo->y + ymove/2;
+ xmove >>= 1;
+ ymove >>= 1;
+ }
+ else
+ {
+ ptryx = mo->x + xmove;
+ ptryy = mo->y + ymove;
+ xmove = ymove = 0;
+ }
+ if (!P_TryMove(mo, ptryx, ptryy))
+ { // Blocked move
+ if (mo->flags2 & MF2_SLIDE)
+ { // Try to slide along it
+ if (BlockingMobj == NULL)
+ { // Slide against wall
+ P_SlideMove(mo);
+ }
+ else
+ { // Slide against mobj
+ //if (P_TryMove(mo, mo->x, mo->y + mo->momy))
+ if (P_TryMove(mo, mo->x, ptryy))
+ {
+ mo->momx = 0;
+ }
+ //else if (P_TryMove(mo, mo->x + mo->momx, mo->y))
+ else if (P_TryMove(mo, ptryx, mo->y))
+ {
+ mo->momy = 0;
+ }
+ else
+ {
+ mo->momx = mo->momy = 0;
+ }
+ }
+ }
+ else if (mo->flags & MF_MISSILE)
+ {
+ if (mo->flags2 & MF2_FLOORBOUNCE)
+ {
+ if (BlockingMobj)
+ {
+ if ((BlockingMobj->flags2 & MF2_REFLECTIVE) ||
+ ((!BlockingMobj->player) &&
+ (!(BlockingMobj->flags & MF_COUNTKILL))))
+ {
+ fixed_t speed;
+
+ angle = R_PointToAngle2(BlockingMobj->x,
+ BlockingMobj->y, mo->x, mo->y)
+ + ANGLE_1*((P_Random() % 16) - 8);
+ speed = P_AproxDistance(mo->momx, mo->momy);
+ speed = FixedMul(speed, 0.75*FRACUNIT);
+ mo->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx = FixedMul(speed, finecosine[angle]);
+ mo->momy = FixedMul(speed, finesine[angle]);
+ if (mo->info->seesound)
+ {
+ S_StartSound(mo, mo->info->seesound);
+ }
+ return;
+ }
+ else
+ { // Struck a player/creature
+ P_ExplodeMissile(mo);
+ }
+ }
+ else
+ { // Struck a wall
+ P_BounceWall(mo);
+ switch (mo->type)
+ {
+ case MT_SORCBALL1:
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ case MT_SORCFX1:
+ break;
+ default:
+ if (mo->info->seesound)
+ {
+ S_StartSound(mo, mo->info->seesound);
+ }
+ break;
+ }
+ return;
+ }
+ }
+ if (BlockingMobj &&
+ (BlockingMobj->flags2 & MF2_REFLECTIVE))
+ {
+ angle = R_PointToAngle2(BlockingMobj->x,
+ BlockingMobj->y,
+ mo->x, mo->y);
+
+ // Change angle for delflection/reflection
+ switch (BlockingMobj->type)
+ {
+ case MT_CENTAUR:
+ case MT_CENTAURLEADER:
+ if (abs(angle - BlockingMobj->angle)>>24 > 45)
+ goto explode;
+ if (mo->type == MT_HOLY_FX)
+ goto explode;
+ // Drop through to sorcerer full reflection
+ case MT_SORCBOSS:
+ // Deflection
+ if (P_Random() < 128)
+ angle += ANGLE_45;
+ else
+ angle -= ANGLE_45;
+ break;
+ default:
+ // Reflection
+ angle += ANGLE_1 * ((P_Random() % 16) - 8);
+ break;
+ }
+
+ // Reflect the missile along angle
+ mo->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx = FixedMul(mo->info->speed>>1, finecosine[angle]);
+ mo->momy = FixedMul(mo->info->speed>>1, finesine[angle]);
+ // mo->momz = -mo->momz;
+ if (mo->flags2 & MF2_SEEKERMISSILE)
+ {
+ mo->special1 = (intptr_t)(mo->target);
+ }
+ mo->target = BlockingMobj;
+ return;
+ }
+explode:
+ // Explode a missile
+ if (ceilingline && ceilingline->backsector
+ && ceilingline->backsector->ceilingpic == skyflatnum)
+ { // Hack to prevent missiles exploding against the sky
+ if (mo->type == MT_BLOODYSKULL)
+ {
+ mo->momx = mo->momy = 0;
+ mo->momz = -FRACUNIT;
+ }
+ else if (mo->type == MT_HOLY_FX)
+ {
+ P_ExplodeMissile(mo);
+ }
+ else
+ {
+ P_RemoveMobj(mo);
+ }
+ return;
+ }
+ P_ExplodeMissile(mo);
+ }
+ //else if (mo->info->crashstate)
+ //{
+ // mo->momx = mo->momy = 0;
+ // P_SetMobjState(mo, mo->info->crashstate);
+ // return;
+ //}
+ else
+ {
+ mo->momx = mo->momy = 0;
+ }
+ }
+ } while (xmove || ymove);
+
+ // Friction
+
+ if (player && player->cheats & CF_NOMOMENTUM)
+ { // Debug option for no sliding at all
+ mo->momx = mo->momy = 0;
+ return;
+ }
+ if (mo->flags & (MF_MISSILE|MF_SKULLFLY))
+ { // No friction for missiles
+ return;
+ }
+ if (mo->z > mo->floorz && !(mo->flags2 & MF2_FLY) && !(mo->flags2 & MF2_ONMOBJ))
+ { // No friction when falling
+ if (mo->type != MT_BLASTEFFECT)
+ return;
+ }
+ if (mo->flags & MF_CORPSE)
+ { // Don't stop sliding if halfway off a step with some momentum
+ if (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4
+ || mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4)
+ {
+ if (mo->floorz != mo->subsector->sector->floorheight)
+ {
+ return;
+ }
+ }
+ }
+ if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED
+ && mo->momy > -STOPSPEED && mo->momy < STOPSPEED
+ && (!player || (player->cmd.forwardmove == 0
+ && player->cmd.sidemove == 0)) )
+ { // If in a walking frame, stop moving
+ if (player)
+ {
+ if ((unsigned)((player->mo->state - states)
+ - PStateRun[player->playerclass]) < 4)
+ {
+ P_SetMobjState(player->mo, PStateNormal[player->playerclass]);
+ }
+ }
+ mo->momx = 0;
+ mo->momy = 0;
+ }
+ else
+ {
+ if (mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+ && !(mo->flags2 & MF2_ONMOBJ))
+ {
+ mo->momx = FixedMul(mo->momx, FRICTION_FLY);
+ mo->momy = FixedMul(mo->momy, FRICTION_FLY);
+ }
+ else if (P_GetThingFloorType(mo) == FLOOR_ICE)
+ {
+ mo->momx = FixedMul(mo->momx, FRICTION_LOW);
+ mo->momy = FixedMul(mo->momy, FRICTION_LOW);
+ }
+ else
+ {
+ mo->momx = FixedMul(mo->momx, FRICTION_NORMAL);
+ mo->momy = FixedMul(mo->momy, FRICTION_NORMAL);
+ }
+ }
+}
+
+
+// Move this to p_inter ***
+static void P_MonsterFallingDamage(mobj_t *mo)
+{
+ int damage;
+ int mom;
+
+ mom = abs(mo->momz);
+ if (mom > 35*FRACUNIT)
+ { // automatic death
+ damage = 10000;
+ }
+ else
+ {
+ damage = ((mom - (23*FRACUNIT) )*6)>>FRACBITS;
+ }
+ damage = 10000; // always kill 'em
+ P_DamageMobj(mo, NULL, NULL, damage);
+}
+
+
+/*
+===============
+=
+= P_ZMovement
+=
+===============
+*/
+
+static void P_ZMovement(mobj_t *mo)
+{
+ int dist;
+ int delta;
+//
+// check for smooth step up
+//
+ if (mo->player && mo->z < mo->floorz)
+ {
+ mo->player->viewheight -= mo->floorz-mo->z;
+ mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3;
+ }
+//
+// adjust height
+//
+ mo->z += mo->momz;
+ if (mo->flags & MF_FLOAT && mo->target)
+ { // float down towards target if too close
+ if (!(mo->flags & MF_SKULLFLY) && !(mo->flags & MF_INFLOAT))
+ {
+ dist = P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y);
+ delta = (mo->target->z + (mo->height>>1)) - mo->z;
+ if (delta < 0 && dist < -(delta*3))
+ mo->z -= FLOATSPEED;
+ else if (delta > 0 && dist < (delta*3))
+ mo->z += FLOATSPEED;
+ }
+ }
+ if (mo->player && mo->flags2 & MF2_FLY && !(mo->z <= mo->floorz)
+ && leveltime & 2)
+ {
+ mo->z += finesine[(FINEANGLES/20*leveltime>>2) & FINEMASK];
+ }
+
+//
+// clip movement
+//
+ if (mo->z <= mo->floorz)
+ { // Hit the floor
+ if (mo->flags & MF_MISSILE)
+ {
+ mo->z = mo->floorz;
+ if (mo->flags2 & MF2_FLOORBOUNCE)
+ {
+ P_FloorBounceMissile(mo);
+ return;
+ }
+ else if (mo->type == MT_HOLY_FX)
+ { // The spirit struck the ground
+ mo->momz = 0;
+ P_HitFloor(mo);
+ return;
+ }
+ else if (mo->type == MT_MNTRFX2 || mo->type == MT_LIGHTNING_FLOOR)
+ { // Minotaur floor fire can go up steps
+ return;
+ }
+ else
+ {
+ P_HitFloor(mo);
+ P_ExplodeMissile(mo);
+ return;
+ }
+ }
+ if (mo->flags & MF_COUNTKILL) // Blasted mobj falling
+ {
+ if (mo->momz < -(23*FRACUNIT))
+ {
+ P_MonsterFallingDamage(mo);
+ }
+ }
+ if (mo->z-mo->momz > mo->floorz)
+ { // Spawn splashes, etc.
+ P_HitFloor(mo);
+ }
+ mo->z = mo->floorz;
+ if (mo->momz < 0)
+ {
+ if (mo->flags2 & MF2_ICEDAMAGE && mo->momz < -GRAVITY*8)
+ {
+ mo->tics = 1;
+ mo->momx = 0;
+ mo->momy = 0;
+ mo->momz = 0;
+ return;
+ }
+ if (mo->player)
+ {
+ mo->player->jumpTics = 7;// delay any jumping for a short time
+ if (mo->momz < -GRAVITY*8 && !(mo->flags2 & MF2_FLY))
+ { // squat down
+ mo->player->deltaviewheight = mo->momz>>3;
+ if (mo->momz < -23*FRACUNIT)
+ {
+ P_FallingDamage(mo->player);
+ P_NoiseAlert(mo, mo);
+ }
+ else if (mo->momz < -GRAVITY*12 && !mo->player->morphTics)
+ {
+ S_StartSound(mo, SFX_PLAYER_LAND);
+ switch (mo->player->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ S_StartSound(mo, SFX_PLAYER_FIGHTER_GRUNT);
+ break;
+ case PCLASS_CLERIC:
+ S_StartSound(mo, SFX_PLAYER_CLERIC_GRUNT);
+ break;
+ case PCLASS_MAGE:
+ S_StartSound(mo, SFX_PLAYER_MAGE_GRUNT);
+ break;
+ default:
+ break;
+ }
+ }
+ else if ((P_GetThingFloorType(mo) < FLOOR_LIQUID) &&
+ (!mo->player->morphTics) )
+ {
+ S_StartSound(mo, SFX_PLAYER_LAND);
+ }
+ if (mouselook && !demorecording && !demoplayback)
+ {
+ mo->player->centering = false;
+ }
+ else
+ {
+ mo->player->centering = true;
+ }
+ }
+ }
+ else if (mo->type >= MT_POTTERY1 &&
+ mo->type <= MT_POTTERY3)
+ {
+ P_DamageMobj(mo, NULL, NULL, 25);
+ }
+ else if (mo->flags & MF_COUNTKILL)
+ {
+ if (mo->momz < -23*FRACUNIT)
+ {
+ // Doesn't get here
+ }
+ }
+ mo->momz = 0;
+ }
+ if (mo->flags & MF_SKULLFLY)
+ { // The skull slammed into something
+ mo->momz = -mo->momz;
+ }
+ if (mo->info->crashstate &&
+ (mo->flags & MF_CORPSE) &&
+ !(mo->flags2 & MF2_ICEDAMAGE))
+ {
+ P_SetMobjState(mo, mo->info->crashstate);
+ return;
+ }
+ }
+ else if (mo->flags2 & MF2_LOGRAV)
+ {
+ if (mo->momz == 0)
+ mo->momz = -(GRAVITY>>3)*2;
+ else
+ mo->momz -= GRAVITY>>3;
+ }
+ else if (! (mo->flags & MF_NOGRAVITY))
+ {
+ if (mo->momz == 0)
+ mo->momz = -GRAVITY*2;
+ else
+ mo->momz -= GRAVITY;
+ }
+
+ if (mo->z + mo->height > mo->ceilingz)
+ { // hit the ceiling
+ if (mo->momz > 0)
+ mo->momz = 0;
+ mo->z = mo->ceilingz - mo->height;
+ if (mo->flags2 & MF2_FLOORBOUNCE)
+ {
+ // Maybe reverse momentum here for ceiling bounce
+ // Currently won't happen
+ if (mo->info->seesound)
+ {
+ S_StartSound(mo, mo->info->seesound);
+ }
+ return;
+ }
+ if (mo->flags & MF_SKULLFLY)
+ { // the skull slammed into something
+ mo->momz = -mo->momz;
+ }
+ if (mo->flags & MF_MISSILE)
+ {
+ if (mo->type == MT_LIGHTNING_CEILING)
+ {
+ return;
+ }
+ if (mo->subsector->sector->ceilingpic == skyflatnum)
+ {
+ if (mo->type == MT_BLOODYSKULL)
+ {
+ mo->momx = mo->momy = 0;
+ mo->momz = -FRACUNIT;
+ }
+ else if (mo->type == MT_HOLY_FX)
+ {
+ P_ExplodeMissile(mo);
+ }
+ else
+ {
+ P_RemoveMobj(mo);
+ }
+ return;
+ }
+ P_ExplodeMissile(mo);
+ return;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_BlasterMobjThinker
+//
+//
+//----------------------------------------------------------------------------
+
+void P_BlasterMobjThinker(mobj_t *mobj)
+{
+ int i;
+ fixed_t xfrac;
+ fixed_t yfrac;
+ fixed_t zfrac;
+ fixed_t z;
+ boolean changexy;
+ mobj_t *mo;
+
+ // Handle movement
+ if (mobj->momx || mobj->momy ||
+ (mobj->z != mobj->floorz) || mobj->momz)
+ {
+ xfrac = mobj->momx>>3;
+ yfrac = mobj->momy>>3;
+ zfrac = mobj->momz>>3;
+ changexy = xfrac || yfrac;
+ for (i = 0; i < 8; i++)
+ {
+ if (changexy)
+ {
+ if (!P_TryMove(mobj, mobj->x + xfrac, mobj->y + yfrac))
+ { // Blocked move
+ P_ExplodeMissile(mobj);
+ return;
+ }
+ }
+ mobj->z += zfrac;
+ if (mobj->z <= mobj->floorz)
+ { // Hit the floor
+ mobj->z = mobj->floorz;
+ P_HitFloor(mobj);
+ P_ExplodeMissile(mobj);
+ return;
+ }
+ if (mobj->z+mobj->height > mobj->ceilingz)
+ { // Hit the ceiling
+ mobj->z = mobj->ceilingz-mobj->height;
+ P_ExplodeMissile(mobj);
+ return;
+ }
+ if (changexy)
+ {
+ if (mobj->type == MT_MWAND_MISSILE && (P_Random() < 128))
+ {
+ z = mobj->z - 8*FRACUNIT;
+ if (z < mobj->floorz)
+ {
+ z = mobj->floorz;
+ }
+ P_SpawnMobj(mobj->x, mobj->y, z, MT_MWANDSMOKE);
+ }
+ /*
+ else if (!--mobj->special1)
+
+ jim- allow other things to have BlasterMobjThinker()s (crossbow)
+
+ O.S- FIXME --- I DON'T NEED AN #ifdef ASSASSIN here, YES ???
+ (also see jim's note in P_CheckMissileSpawn down below.)
+ */
+ else if ((mobj->type == MT_CFLAME_MISSILE) && !--mobj->special1)
+ {
+ mobj->special1 = 4;
+ z = mobj->z-12*FRACUNIT;
+ if (z < mobj->floorz)
+ {
+ z = mobj->floorz;
+ }
+ mo = P_SpawnMobj(mobj->x, mobj->y, z, MT_CFLAMEFLOOR);
+ if (mo)
+ {
+ mo->angle = mobj->angle;
+ }
+ }
+ }
+ }
+ }
+ // Advance the state
+ if (mobj->tics != -1)
+ {
+ mobj->tics--;
+ while (!mobj->tics)
+ {
+ if (!P_SetMobjState(mobj, mobj->state->nextstate))
+ { // mobj was removed
+ return;
+ }
+ }
+ }
+}
+
+//===========================================================================
+//
+// PlayerLandedOnThing
+//
+//===========================================================================
+
+static void PlayerLandedOnThing(mobj_t *mo, mobj_t *onmobj)
+{
+ mo->player->deltaviewheight = mo->momz>>3;
+ if (mo->momz < -23*FRACUNIT)
+ {
+ P_FallingDamage(mo->player);
+ P_NoiseAlert(mo, mo);
+ }
+ else if (mo->momz < -GRAVITY*12 &&
+ !mo->player->morphTics)
+ {
+ S_StartSound(mo, SFX_PLAYER_LAND);
+ switch (mo->player->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ S_StartSound(mo, SFX_PLAYER_FIGHTER_GRUNT);
+ break;
+ case PCLASS_CLERIC:
+ S_StartSound(mo, SFX_PLAYER_CLERIC_GRUNT);
+ break;
+ case PCLASS_MAGE:
+ S_StartSound(mo, SFX_PLAYER_MAGE_GRUNT);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (!mo->player->morphTics)
+ {
+ S_StartSound(mo, SFX_PLAYER_LAND);
+ }
+ if (mouselook && !demorecording && !demoplayback)
+ {
+ mo->player->centering = false;
+ }
+ else
+ {
+ mo->player->centering = true;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_MobjThinker
+//
+//----------------------------------------------------------------------------
+
+void P_MobjThinker(mobj_t *mobj)
+{
+ mobj_t *onmo;
+
+ /*
+ // Reset to not blasted when momentums are gone
+ if ((mobj->flags2 & MF2_BLASTED) && (!(mobj->momx)) && (!(mobj->momy)))
+ ResetBlasted(mobj);
+ */
+
+ // Handle X and Y momentums
+ BlockingMobj = NULL;
+ if (mobj->momx || mobj->momy || (mobj->flags & MF_SKULLFLY))
+ {
+ P_XYMovement(mobj);
+ if (mobj->thinker.function == (think_t)-1)
+ { // mobj was removed
+ return;
+ }
+ }
+ else if (mobj->flags2 & MF2_BLASTED)
+ { // Reset to not blasted when momentums are gone
+ ResetBlasted(mobj);
+ }
+ if (mobj->flags2 & MF2_FLOATBOB)
+ { // Floating item bobbing motion (special1 is height)
+ mobj->z = mobj->floorz + mobj->special1 +
+ FloatBobOffsets[(mobj->health++) & 63];
+ }
+ else if ((mobj->z != mobj->floorz) || mobj->momz || BlockingMobj)
+ { // Handle Z momentum and gravity
+ if (mobj->flags2 & MF2_PASSMOBJ)
+ {
+ if (!(onmo = P_CheckOnmobj(mobj)))
+ {
+ P_ZMovement(mobj);
+ if (mobj->player && mobj->flags & MF2_ONMOBJ)
+ {
+ mobj->flags2 &= ~MF2_ONMOBJ;
+ }
+ }
+ else
+ {
+ if (mobj->player)
+ {
+ if (mobj->momz < -GRAVITY*8 && !(mobj->flags2 & MF2_FLY))
+ {
+ PlayerLandedOnThing(mobj, onmo);
+ }
+ if (onmo->z + onmo->height - mobj->z <= 24*FRACUNIT)
+ {
+ mobj->player->viewheight -= onmo->z + onmo->height
+ - mobj->z;
+ mobj->player->deltaviewheight =
+ (VIEWHEIGHT - mobj->player->viewheight)>>3;
+ mobj->z = onmo->z + onmo->height;
+ mobj->flags2 |= MF2_ONMOBJ;
+ mobj->momz = 0;
+ }
+ else
+ { // hit the bottom of the blocking mobj
+ mobj->momz = 0;
+ }
+ }
+ /* Landing on another player, and mimicking his movements
+ if (mobj->player && onmo->player)
+ {
+ mobj->momx = onmo->momx;
+ mobj->momy = onmo->momy;
+ if (onmo->z < onmo->floorz)
+ {
+ mobj->z += onmo->floorz-onmo->z;
+ if (onmo->player)
+ {
+ onmo->player->viewheight -= onmo->floorz - onmo->z;
+ onmo->player->deltaviewheight =
+ (VIEWHEIGHT - onmo->player->viewheight)>>3;
+ }
+ onmo->z = onmo->floorz;
+ }
+ }
+ */
+ }
+ }
+ else
+ {
+ P_ZMovement(mobj);
+ }
+ if (mobj->thinker.function == (think_t)-1)
+ { // mobj was removed
+ return;
+ }
+ }
+
+ // Cycle through states, calling action functions at transitions
+ if (mobj->tics != -1)
+ {
+ mobj->tics--;
+ // you can cycle through multiple states in a tic
+ while (!mobj->tics)
+ {
+ if (!P_SetMobjState(mobj, mobj->state->nextstate))
+ { // mobj was removed
+ return;
+ }
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_SpawnMobj
+//
+//==========================================================================
+
+mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
+{
+ mobj_t *mobj;
+ state_t *st;
+ mobjinfo_t *info;
+ fixed_t space;
+
+ mobj = (mobj_t *) Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
+ memset(mobj, 0, sizeof(*mobj));
+ info = &mobjinfo[type];
+ mobj->type = type;
+ mobj->info = info;
+ mobj->x = x;
+ mobj->y = y;
+ mobj->radius = info->radius;
+ mobj->height = info->height;
+ mobj->flags = info->flags;
+ mobj->flags2 = info->flags2;
+ mobj->damage = info->damage;
+ mobj->health = info->spawnhealth;
+ if (gameskill != sk_nightmare)
+ {
+ mobj->reactiontime = info->reactiontime;
+ }
+ mobj->lastlook = P_Random() % MAXPLAYERS;
+
+ // Set the state, but do not use P_SetMobjState, because action
+ // routines can't be called yet. If the spawnstate has an action
+ // routine, it will not be called.
+ st = &states[info->spawnstate];
+ mobj->state = st;
+ mobj->tics = st->tics;
+ mobj->sprite = st->sprite;
+ mobj->frame = st->frame;
+
+ // Set subsector and/or block links.
+ P_SetThingPosition(mobj);
+ mobj->floorz = mobj->subsector->sector->floorheight;
+ mobj->ceilingz = mobj->subsector->sector->ceilingheight;
+ if (z == ONFLOORZ)
+ {
+ mobj->z = mobj->floorz;
+ }
+ else if (z == ONCEILINGZ)
+ {
+ mobj->z = mobj->ceilingz-mobj->info->height;
+ }
+ else if (z == FLOATRANDZ)
+ {
+ space = ((mobj->ceilingz)-(mobj->info->height))-mobj->floorz;
+ if (space > 48*FRACUNIT)
+ {
+ space -= 40*FRACUNIT;
+ mobj->z = ((space*P_Random())>>8) + mobj->floorz + 40*FRACUNIT;
+ }
+ else
+ {
+ mobj->z = mobj->floorz;
+ }
+ }
+ else if (mobj->flags2 & MF2_FLOATBOB)
+ {
+ mobj->z = mobj->floorz + z; // artifact z passed in as height
+ }
+ else
+ {
+ mobj->z = z;
+ }
+ if (mobj->flags2 & MF2_FLOORCLIP && P_GetThingFloorType(mobj) >= FLOOR_LIQUID
+ && mobj->z == mobj->subsector->sector->floorheight)
+ {
+ mobj->floorclip = 10*FRACUNIT;
+ }
+ else
+ {
+ mobj->floorclip = 0;
+ }
+
+ mobj->thinker.function = P_MobjThinker;
+ P_AddThinker(&mobj->thinker);
+ return (mobj);
+}
+
+//==========================================================================
+//
+// P_RemoveMobj
+//
+//==========================================================================
+
+void P_RemoveMobj(mobj_t *mobj)
+{
+ // Remove from creature queue
+ if (mobj->flags & MF_COUNTKILL &&
+ mobj->flags & MF_CORPSE)
+ {
+ A_DeQueueCorpse(mobj);
+ }
+
+ if (mobj->tid)
+ { // Remove from TID list
+ P_RemoveMobjFromTIDList(mobj);
+ }
+
+ // Unlink from sector and block lists
+ P_UnsetThingPosition(mobj);
+
+ // Stop any playing sound
+ S_StopSound(mobj);
+
+ // Free block
+ P_RemoveThinker((thinker_t *)mobj);
+}
+
+//==========================================================================
+//
+// P_SpawnPlayer
+//
+// Called when a player is spawned on the level. Most of the player
+// structure stays unchanged between levels.
+//
+//==========================================================================
+
+void P_SpawnPlayer(mapthing_t *mthing)
+{
+ player_t *p;
+ fixed_t x, y, z;
+ mobj_t *mobj;
+
+ if (!playeringame[mthing->type - 1])
+ { // Not playing
+ return;
+ }
+ p = &players[mthing->type - 1];
+ if (p->playerstate == PST_REBORN)
+ {
+ G_PlayerReborn(mthing->type - 1);
+ }
+ x = mthing->x << FRACBITS;
+ y = mthing->y << FRACBITS;
+ z = ONFLOORZ;
+ if (randomclass && deathmatch)
+ {
+ p->playerclass = P_Random() % NUMCLASSES_HUMAN;
+ if (p->playerclass == PlayerClasses[mthing->type - 1])
+ {
+ p->playerclass = (p->playerclass + 1) % NUMCLASSES_HUMAN;
+ }
+ PlayerClasses[mthing->type - 1] = p->playerclass;
+ SB_SetClassData();
+ }
+ else
+ {
+ p->playerclass = PlayerClasses[mthing->type - 1];
+ }
+ switch (p->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ mobj = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
+ break;
+ case PCLASS_CLERIC:
+ mobj = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
+ break;
+ case PCLASS_MAGE:
+ mobj = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
+ break;
+#ifdef ASSASSIN
+ case PCLASS_ASS:
+ mobj = P_SpawnMobj(x, y, z, MT_PLAYER_ASS);
+ break;
+#endif
+ default:
+ I_Error("P_SpawnPlayer: Unknown class type");
+ mobj = NULL; /* avoid compiler warning */
+ break;
+ }
+
+ // Set translation table data
+ if (p->playerclass == PCLASS_FIGHTER && (mthing->type == 1 || mthing->type == 3))
+ {
+ // The first type should be blue, and the third should be the
+ // Fighter's original gold color
+ if (mthing->type == 1)
+ {
+ mobj->flags |= 2<<MF_TRANSSHIFT;
+ }
+ }
+ else if (mthing->type > 1)
+ { // Set color translation bits for player sprites
+ mobj->flags |= (mthing->type - 1)<<MF_TRANSSHIFT;
+ }
+
+ mobj->angle = ANG45 * (mthing->angle/45);
+ mobj->player = p;
+ mobj->health = p->health;
+ p->mo = mobj;
+ p->playerstate = PST_LIVE;
+ p->refire = 0;
+ P_ClearMessage(p);
+ p->damagecount = 0;
+ p->bonuscount = 0;
+ p->poisoncount = 0;
+ p->morphTics = 0;
+ p->extralight = 0;
+ p->fixedcolormap = 0;
+ p->viewheight = VIEWHEIGHT;
+ P_SetupPsprites(p);
+ if (deathmatch)
+ { // Give all keys in death match mode
+ p->keys = 2047;
+ }
+}
+
+//==========================================================================
+//
+// P_SpawnMapThing
+//
+// The fields of the mapthing should already be in host byte order.
+//
+//==========================================================================
+
+void P_SpawnMapThing(mapthing_t *mthing)
+{
+ int i;
+ unsigned int spawnMask;
+ mobj_t *mobj;
+ fixed_t x, y, z;
+ // Put in Cleric twice, since we can't have an assassin flag.
+ static unsigned int classFlags[] =
+ {
+ MTF_FIGHTER,
+ MTF_CLERIC,
+ MTF_MAGE,
+#ifdef ASSASSIN
+ MTF_CLERIC
+#endif
+ };
+
+ // Count deathmatch start positions
+ if (mthing->type == 11)
+ {
+ if (deathmatch_p < &deathmatchstarts[MAXDEATHMATCHSTARTS])
+ {
+ memcpy(deathmatch_p, mthing, sizeof(*mthing));
+ deathmatch_p++;
+ }
+ return;
+ }
+ if (mthing->type == PO_ANCHOR_TYPE)
+ { // Polyobj Anchor Pt.
+ return;
+ }
+ else if (mthing->type == PO_SPAWN_TYPE ||
+ mthing->type == PO_SPAWNCRUSH_TYPE)
+ { // Polyobj Anchor Pt.
+ po_NumPolyobjs++;
+ return;
+ }
+
+ // Check for player starts 1 to 4
+ if (mthing->type <= 4)
+ {
+ playerstarts[mthing->arg1][mthing->type - 1] = *mthing;
+ if (!deathmatch && !mthing->arg1)
+ {
+ P_SpawnPlayer(mthing);
+ }
+ return;
+ }
+ // Check for player starts 5 to 8
+ if (mthing->type >= 9100 && mthing->type <= 9103)
+ {
+ mthing->type = 5 + mthing->type - 9100; // Translate to 5 - 8
+ playerstarts[mthing->arg1][mthing->type - 1] = *mthing;
+ if (!deathmatch && !mthing->arg1)
+ {
+ P_SpawnPlayer(mthing);
+ }
+ return;
+ }
+
+ if (mthing->type >= 1400 && mthing->type < 1410)
+ {
+ R_PointInSubsector(mthing->x<<FRACBITS,
+ mthing->y<<FRACBITS)->sector->seqType = mthing->type - 1400;
+ return;
+ }
+
+ // Check current game type with spawn flags
+ if (netgame == false)
+ {
+ spawnMask = MTF_GSINGLE;
+ }
+ else if (deathmatch)
+ {
+ spawnMask = MTF_GDEATHMATCH;
+ }
+ else
+ {
+ spawnMask = MTF_GCOOP;
+ }
+ if (!(mthing->options&spawnMask))
+ {
+ return;
+ }
+
+ // Check current skill with spawn flags
+ if (gameskill == sk_baby || gameskill == sk_easy)
+ {
+ spawnMask = MTF_EASY;
+ }
+ else if (gameskill == sk_hard || gameskill == sk_nightmare)
+ {
+ spawnMask = MTF_HARD;
+ }
+ else
+ {
+ spawnMask = MTF_NORMAL;
+ }
+ if (!(mthing->options&spawnMask))
+ {
+ return;
+ }
+
+ // Check current character classes with spawn flags
+ if (netgame == false)
+ { // Single player
+ if ((mthing->options&classFlags[PlayerClasses[0]]) == 0)
+ { // Not for current class
+ return;
+ }
+ }
+ else if (deathmatch == false)
+ { // Cooperative
+ spawnMask = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ spawnMask |= classFlags[PlayerClasses[i]];
+ }
+ }
+ if ((mthing->options&spawnMask) == 0)
+ {
+ return;
+ }
+ }
+
+ // Find which type to spawn
+ for (i = 0; i < NUMMOBJTYPES; i++)
+ {
+ if (mthing->type == mobjinfo[i].doomednum)
+ {
+ break;
+ }
+ }
+
+ if (i == NUMMOBJTYPES)
+ { // Can't find thing type
+ I_Error("P_SpawnMapThing: Unknown type %i at (%i, %i)",
+ mthing->type, mthing->x, mthing->y);
+ }
+
+ // Don't spawn keys and players in deathmatch
+ if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
+ {
+ return;
+ }
+
+ // Don't spawn monsters if -nomonsters
+ if (nomonsters && (mobjinfo[i].flags & MF_COUNTKILL))
+ {
+ return;
+ }
+
+ x = mthing->x<<FRACBITS;
+ y = mthing->y<<FRACBITS;
+ if (mobjinfo[i].flags & MF_SPAWNCEILING)
+ {
+ z = ONCEILINGZ;
+ }
+ else if (mobjinfo[i].flags2 & MF2_SPAWNFLOAT)
+ {
+ z = FLOATRANDZ;
+ }
+ else if (mobjinfo[i].flags2 & MF2_FLOATBOB)
+ {
+ z = mthing->height<<FRACBITS;
+ }
+ else
+ {
+ z = ONFLOORZ;
+ }
+ switch (i)
+ { // Special stuff
+ case MT_ZLYNCHED_NOHEART:
+ P_SpawnMobj(x, y, ONFLOORZ, MT_BLOODPOOL);
+ break;
+ default:
+ break;
+ }
+ mobj = P_SpawnMobj(x, y, z, i);
+ if (z == ONFLOORZ)
+ {
+ mobj->z += mthing->height<<FRACBITS;
+ }
+ else if (z == ONCEILINGZ)
+ {
+ mobj->z -= mthing->height<<FRACBITS;
+ }
+ mobj->tid = mthing->tid;
+ mobj->special = mthing->special;
+ mobj->args[0] = mthing->arg1;
+ mobj->args[1] = mthing->arg2;
+ mobj->args[2] = mthing->arg3;
+ mobj->args[3] = mthing->arg4;
+ mobj->args[4] = mthing->arg5;
+ if (mobj->flags2 & MF2_FLOATBOB)
+ { // Seed random starting index for bobbing motion
+ mobj->health = P_Random();
+ mobj->special1 = mthing->height<<FRACBITS;
+ }
+ if (mobj->tics > 0)
+ {
+ mobj->tics = 1 + (P_Random() % mobj->tics);
+ }
+// if (mobj->flags & MF_COUNTITEM)
+// {
+// totalitems++;
+// }
+ if (mobj->flags & MF_COUNTKILL)
+ {
+ // Quantize angle to 45 degree increments
+ mobj->angle = ANG45*(mthing->angle/45);
+ }
+ else
+ {
+ // Scale angle correctly (source is 0..359)
+ mobj->angle = ((mthing->angle<<8)/360)<<24;
+ }
+ if (mthing->options & MTF_AMBUSH)
+ {
+ mobj->flags |= MF_AMBUSH;
+ }
+ if (mthing->options & MTF_DORMANT)
+ {
+ mobj->flags2 |= MF2_DORMANT;
+ if (mobj->type == MT_ICEGUY)
+ {
+ P_SetMobjState(mobj, S_ICEGUY_DORMANT);
+ }
+ mobj->tics = -1;
+ }
+}
+
+//==========================================================================
+//
+// P_CreateTIDList
+//
+//==========================================================================
+
+void P_CreateTIDList(void)
+{
+ int i;
+ mobj_t *mobj;
+ thinker_t *t;
+
+ i = 0;
+ for (t = thinkercap.next; t != &thinkercap; t = t->next)
+ { // Search all current thinkers
+ if (t->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mobj = (mobj_t *)t;
+ if (mobj->tid != 0)
+ { // Add to list
+ if (i == MAX_TID_COUNT)
+ {
+ I_Error("P_CreateTIDList: MAX_TID_COUNT (%d) exceeded.",
+ MAX_TID_COUNT);
+ }
+ TIDList[i] = mobj->tid;
+ TIDMobj[i++] = mobj;
+ }
+ }
+ // Add termination marker
+ TIDList[i] = 0;
+}
+
+//==========================================================================
+//
+// P_InsertMobjIntoTIDList
+//
+//==========================================================================
+
+void P_InsertMobjIntoTIDList(mobj_t *mobj, int tid)
+{
+ int i;
+ int idx;
+
+ idx = -1;
+ for (i = 0; TIDList[i] != 0; i++)
+ {
+ if (TIDList[i] == -1)
+ { // Found empty slot
+ idx = i;
+ break;
+ }
+ }
+ if (idx == -1)
+ { // Append required
+ if (i == MAX_TID_COUNT)
+ {
+ I_Error("P_InsertMobjIntoTIDList: MAX_TID_COUNT (%d)"
+ "exceeded.", MAX_TID_COUNT);
+ }
+ idx = i;
+ TIDList[idx + 1] = 0;
+ }
+ mobj->tid = tid;
+ TIDList[idx] = tid;
+ TIDMobj[idx] = mobj;
+}
+
+//==========================================================================
+//
+// P_RemoveMobjFromTIDList
+//
+//==========================================================================
+
+void P_RemoveMobjFromTIDList(mobj_t *mobj)
+{
+ int i;
+
+ for (i = 0; TIDList[i] != 0; i++)
+ {
+ if (TIDMobj[i] == mobj)
+ {
+ TIDList[i] = -1;
+ TIDMobj[i] = NULL;
+ mobj->tid = 0;
+ return;
+ }
+ }
+ mobj->tid = 0;
+}
+
+//==========================================================================
+//
+// P_FindMobjFromTID
+//
+//==========================================================================
+
+mobj_t *P_FindMobjFromTID(int tid, int *searchPosition)
+{
+ int i;
+
+ for (i = *searchPosition + 1; TIDList[i] != 0; i++)
+ {
+ if (TIDList[i] == tid)
+ {
+ *searchPosition = i;
+ return TIDMobj[i];
+ }
+ }
+ *searchPosition = -1;
+ return NULL;
+}
+
+/*
+===============================================================================
+
+ GAME SPAWN FUNCTIONS
+
+===============================================================================
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SpawnPuff
+//
+//---------------------------------------------------------------------------
+
+void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z)
+{
+ mobj_t *puff;
+
+ z += ((P_Random() - P_Random()) << 10);
+ puff = P_SpawnMobj(x, y, z, PuffType);
+ if (linetarget && puff->info->seesound)
+ { // Hit thing sound
+ S_StartSound(puff, puff->info->seesound);
+ }
+ else if (puff->info->attacksound)
+ {
+ S_StartSound(puff, puff->info->attacksound);
+ }
+ switch (PuffType)
+ {
+ case MT_PUNCHPUFF:
+ puff->momz = FRACUNIT;
+ break;
+ case MT_HAMMERPUFF:
+ puff->momz = .8*FRACUNIT;
+ break;
+ default:
+ break;
+ }
+ PuffSpawned = puff;
+}
+
+/*
+================
+=
+= P_SpawnBlood
+=
+================
+*/
+
+/*
+void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, int damage)
+{
+ mobj_t *th;
+
+ z += ((P_Random() - P_Random()) << 10);
+ th = P_SpawnMobj (x, y, z, MT_BLOOD);
+ th->momz = FRACUNIT*2;
+ th->tics -= P_Random() & 3;
+
+ if (damage <= 12 && damage >= 9)
+ P_SetMobjState (th, S_BLOOD2);
+ else if (damage < 9)
+ P_SetMobjState (th, S_BLOOD3);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_BloodSplatter
+//
+//---------------------------------------------------------------------------
+
+void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(x, y, z, MT_BLOODSPLATTER);
+ mo->target = originator;
+ mo->momx = (P_Random() - P_Random()) << 10;
+ mo->momy = (P_Random() - P_Random()) << 10;
+ mo->momz = 3*FRACUNIT;
+}
+
+//===========================================================================
+//
+// P_BloodSplatter2
+//
+//===========================================================================
+
+void P_BloodSplatter2(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(x + ((P_Random() - 128) <<11),
+ y + ((P_Random() - 128) <<11),
+ z, MT_AXEBLOOD);
+ mo->target = originator;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_RipperBlood
+//
+//---------------------------------------------------------------------------
+
+void P_RipperBlood(mobj_t *mo)
+{
+ mobj_t *th;
+ fixed_t x, y, z;
+
+ x = mo->x + ((P_Random() - P_Random()) <<12);
+ y = mo->y + ((P_Random() - P_Random()) <<12);
+ z = mo->z + ((P_Random() - P_Random()) <<12);
+ th = P_SpawnMobj(x, y, z, MT_BLOOD);
+// th->flags |= MF_NOGRAVITY;
+ th->momx = mo->momx>>1;
+ th->momy = mo->momy>>1;
+ th->tics += P_Random() & 3;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_GetThingFloorType
+//
+//---------------------------------------------------------------------------
+
+int P_GetThingFloorType(mobj_t *thing)
+{
+ if (thing->floorpic)
+ {
+ return(TerrainTypes[thing->floorpic]);
+ }
+ else
+ {
+ return(TerrainTypes[thing->subsector->sector->floorpic]);
+ }
+ /*
+ if (thing->subsector->sector->floorpic
+ == W_GetNumForName("FLTWAWA1") - firstflat)
+ {
+ return FLOOR_WATER;
+ }
+ else
+ {
+ return FLOOR_SOLID;
+ }
+ */
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_HitFloor
+//
+//---------------------------------------------------------------------------
+
+#define SMALLSPLASHCLIP (12 << FRACBITS)
+
+int P_HitFloor(mobj_t *thing)
+{
+ mobj_t *mo;
+ int smallsplash = false;
+
+ if (thing->floorz != thing->subsector->sector->floorheight)
+ { // don't splash if landing on the edge above water/lava/etc....
+ return FLOOR_SOLID;
+ }
+
+ // Things that don't splash go here
+ switch (thing->type)
+ {
+ case MT_LEAF1:
+ case MT_LEAF2:
+// case MT_BLOOD: // I set these to low mass -- pm
+// case MT_BLOODSPLATTER:
+ case MT_SPLASH:
+ case MT_SLUDGECHUNK:
+ return FLOOR_SOLID;
+ default:
+ break;
+ }
+
+ // Small splash for small masses
+ if (thing->info->mass < 10)
+ smallsplash = true;
+
+ switch (P_GetThingFloorType(thing))
+ {
+ case FLOOR_WATER:
+ if (smallsplash)
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
+ if (mo)
+ mo->floorclip += SMALLSPLASHCLIP;
+ S_StartSound(mo, SFX_AMBIENT10); // small drip
+ }
+ else
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASH);
+ mo->target = thing;
+ mo->momx = (P_Random() - P_Random()) <<8;
+ mo->momy = (P_Random() - P_Random()) <<8;
+ mo->momz = 2*FRACUNIT + (P_Random() <<8);
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
+ if (thing->player)
+ P_NoiseAlert(thing, thing);
+ S_StartSound(mo, SFX_WATER_SPLASH);
+ }
+ return FLOOR_WATER;
+
+ case FLOOR_LAVA:
+ if (smallsplash)
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
+ if (mo)
+ mo->floorclip += SMALLSPLASHCLIP;
+ }
+ else
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASMOKE);
+ mo->momz = FRACUNIT + (P_Random() << 7);
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
+ if (thing->player)
+ P_NoiseAlert(thing, thing);
+ }
+ S_StartSound(mo, SFX_LAVA_SIZZLE);
+ if (thing->player && leveltime & 31)
+ {
+ P_DamageMobj(thing, &LavaInflictor, NULL, 5);
+ }
+ return FLOOR_LAVA;
+
+ case FLOOR_SLUDGE:
+ if (smallsplash)
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGESPLASH);
+ if (mo)
+ mo->floorclip += SMALLSPLASHCLIP;
+ }
+ else
+ {
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGECHUNK);
+ mo->target = thing;
+ mo->momx = (P_Random() - P_Random()) <<8;
+ mo->momy = (P_Random() - P_Random()) <<8;
+ mo->momz = FRACUNIT + (P_Random() <<8);
+ mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGESPLASH);
+ if (thing->player)
+ P_NoiseAlert(thing, thing);
+ }
+ S_StartSound(mo, SFX_SLUDGE_GLOOP);
+ return FLOOR_SLUDGE;
+ }
+
+ return FLOOR_SOLID;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_CheckMissileSpawn
+//
+// Returns true if the missile is at a valid spawn point, otherwise
+// explodes it and returns false.
+//
+//---------------------------------------------------------------------------
+
+boolean P_CheckMissileSpawn(mobj_t *missile)
+{
+ //missile->tics -= P_Random() & 3;
+
+ // move a little forward so an angle can be computed if it
+ // immediately explodes
+
+#if 0 /* original */
+ missile->x += (missile->momx>>1);
+ missile->y += (missile->momy>>1);
+ missile->z += (missile->momz>>1);
+#else
+/*
+ * jim - handle fast missiles with BlasterMobjThinker()s
+ * assume so if momentum > MAXMOVE
+ * this is a horrible kludge, but to be honest so is the BlasterMobjThinker
+ * stuff in the first place
+ */
+/* O.S- FIXME --- THIS SEEMS TO HAVE BEEN DONE FOR the ASSASSIN */
+ if ((missile->momx > MAXMOVE) || (missile->momy > MAXMOVE))
+ {
+ missile->x += (missile->momx>>3);
+ missile->y += (missile->momy>>3);
+ missile->z += (missile->momz>>3);
+ }
+ else
+ {
+ missile->x += (missile->momx>>1);
+ missile->y += (missile->momy>>1);
+ missile->z += (missile->momz>>1);
+ }
+#endif /* jim */
+
+ if (!P_TryMove(missile, missile->x, missile->y))
+ {
+ P_ExplodeMissile(missile);
+ return false;
+ }
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissile
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type)
+{
+ fixed_t z;
+ mobj_t *th;
+ angle_t an;
+ int dist;
+
+ switch (type)
+ {
+ case MT_MNTRFX1: // Minotaur swing attack missile
+ z = source->z + 40*FRACUNIT;
+ break;
+ case MT_MNTRFX2: // Minotaur floor fire missile
+ z = ONFLOORZ + source->floorclip;
+ break;
+ case MT_CENTAUR_FX:
+ z = source->z + 45*FRACUNIT;
+ break;
+ case MT_ICEGUY_FX:
+ z = source->z + 40*FRACUNIT;
+ break;
+ case MT_HOLY_MISSILE:
+ z = source->z + 40*FRACUNIT;
+ break;
+ default:
+ z = source->z + 32*FRACUNIT;
+ break;
+ }
+ z -= source->floorclip;
+ th = P_SpawnMobj(source->x, source->y, z, type);
+ if (th->info->seesound)
+ {
+ S_StartSound(th, th->info->seesound);
+ }
+ th->target = source; // Originator
+ an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
+ if (dest->flags & MF_SHADOW)
+ { // Invisible target
+ an += (P_Random() - P_Random()) <<21;
+ }
+ th->angle = an;
+ an >>= ANGLETOFINESHIFT;
+ th->momx = FixedMul(th->info->speed, finecosine[an]);
+ th->momy = FixedMul(th->info->speed, finesine[an]);
+ dist = P_AproxDistance(dest->x - source->x, dest->y - source->y);
+ dist = dist/th->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ th->momz = (dest->z - source->z)/dist;
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissileXYZ
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissileXYZ(fixed_t x, fixed_t y, fixed_t z,
+ mobj_t *source, mobj_t *dest, mobjtype_t type)
+{
+ mobj_t *th;
+ angle_t an;
+ int dist;
+
+ z -= source->floorclip;
+ th = P_SpawnMobj(x, y, z, type);
+ if (th->info->seesound)
+ {
+ S_StartSound(th, th->info->seesound);
+ }
+ th->target = source; // Originator
+ an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
+ if (dest->flags & MF_SHADOW)
+ { // Invisible target
+ an += (P_Random() - P_Random()) <<21;
+ }
+ th->angle = an;
+ an >>= ANGLETOFINESHIFT;
+ th->momx = FixedMul(th->info->speed, finecosine[an]);
+ th->momy = FixedMul(th->info->speed, finesine[an]);
+ dist = P_AproxDistance(dest->x - source->x, dest->y - source->y);
+ dist = dist/th->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ th->momz = (dest->z - source->z)/dist;
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissileAngle
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissileAngle(mobj_t *source, mobjtype_t type,
+ angle_t angle, fixed_t momz)
+{
+ fixed_t z;
+ mobj_t *mo;
+
+ switch (type)
+ {
+ case MT_MNTRFX1: // Minotaur swing attack missile
+ z = source->z + 40*FRACUNIT;
+ break;
+ case MT_MNTRFX2: // Minotaur floor fire missile
+ z = ONFLOORZ + source->floorclip;
+ break;
+ case MT_ICEGUY_FX2: // Secondary Projectiles of the Ice Guy
+ z = source->z + 3*FRACUNIT;
+ break;
+ case MT_MSTAFF_FX2:
+ z = source->z + 40*FRACUNIT;
+ break;
+ default:
+ z = source->z + 32*FRACUNIT;
+ break;
+ }
+ z -= source->floorclip;
+ mo = P_SpawnMobj(source->x, source->y, z, type);
+ if (mo->info->seesound)
+ {
+ S_StartSound(mo, mo->info->seesound);
+ }
+ mo->target = source; // Originator
+ mo->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx = FixedMul(mo->info->speed, finecosine[angle]);
+ mo->momy = FixedMul(mo->info->speed, finesine[angle]);
+ mo->momz = momz;
+ return (P_CheckMissileSpawn(mo) ? mo : NULL);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_SpawnMissileAngleSpeed
+//
+// Returns NULL if the missile exploded immediately, otherwise returns
+// a mobj_t pointer to the missile.
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SpawnMissileAngleSpeed(mobj_t *source, mobjtype_t type,
+ angle_t angle, fixed_t momz, fixed_t speed)
+{
+ fixed_t z;
+ mobj_t *mo;
+
+ z = source->z;
+ z -= source->floorclip;
+ mo = P_SpawnMobj(source->x, source->y, z, type);
+ if (mo->info->seesound)
+ {
+ //S_StartSound(mo, mo->info->seesound);
+ }
+ mo->target = source; // Originator
+ mo->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ mo->momx = FixedMul(speed, finecosine[angle]);
+ mo->momy = FixedMul(speed, finesine[angle]);
+ mo->momz = momz;
+ return (P_CheckMissileSpawn(mo) ? mo : NULL);
+}
+
+
+/*
+================
+=
+= P_SpawnPlayerMissile
+=
+= Tries to aim at a nearby monster
+================
+*/
+
+mobj_t *P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type)
+{
+ angle_t an;
+ fixed_t x, y, z, slope;
+
+ // Try to find a target
+ an = source->angle;
+ slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
+ if (!linetarget)
+ {
+ an += 1<<26;
+ slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
+ if (!linetarget)
+ {
+ an -= 2<<26;
+ slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
+ }
+ if (!linetarget)
+ {
+ an = source->angle;
+ slope = ((source->player->lookdir)<<FRACBITS)/173;
+ }
+ }
+ x = source->x;
+ y = source->y;
+ if (type == MT_LIGHTNING_FLOOR)
+ {
+ z = ONFLOORZ;
+ slope = 0;
+ }
+ else if (type == MT_LIGHTNING_CEILING)
+ {
+ z = ONCEILINGZ;
+ slope = 0;
+ }
+ else
+ {
+ z = source->z + 4*8*FRACUNIT + ((source->player->lookdir)<<FRACBITS)/173;
+ z -= source->floorclip;
+ }
+ MissileMobj = P_SpawnMobj(x, y, z, type);
+ if (MissileMobj->info->seesound)
+ {
+ //S_StartSound(MissileMobj, MissileMobj->info->seesound);
+ }
+ MissileMobj->target = source;
+ MissileMobj->angle = an;
+ MissileMobj->momx = FixedMul(MissileMobj->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
+ MissileMobj->momy = FixedMul(MissileMobj->info->speed, finesine[an>>ANGLETOFINESHIFT]);
+ MissileMobj->momz = FixedMul(MissileMobj->info->speed, slope);
+ if (MissileMobj->type == MT_MWAND_MISSILE
+ || MissileMobj->type == MT_CFLAME_MISSILE)
+ { // Ultra-fast ripper spawning missile
+ MissileMobj->x += (MissileMobj->momx>>3);
+ MissileMobj->y += (MissileMobj->momy>>3);
+ MissileMobj->z += (MissileMobj->momz>>3);
+ }
+ else
+ { // Normal missile
+ MissileMobj->x += (MissileMobj->momx>>1);
+ MissileMobj->y += (MissileMobj->momy>>1);
+ MissileMobj->z += (MissileMobj->momz>>1);
+ }
+ if (!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
+ { // Exploded immediately
+ P_ExplodeMissile(MissileMobj);
+ return NULL;
+ }
+ return (MissileMobj);
+}
+
+
+//----------------------------------------------------------------------------
+//
+// P_SpawnPlayerMinotaur -
+//
+// Special missile that has larger blocking than player
+//----------------------------------------------------------------------------
+
+/*
+mobj_t *P_SpawnPlayerMinotaur(mobj_t *source, mobjtype_t type)
+{
+ angle_t an;
+ fixed_t x, y, z;
+ fixed_t dist=0 *FRACUNIT;
+
+ an = source->angle;
+ x = source->x + FixedMul(dist, finecosine[an>>ANGLETOFINESHIFT]);
+ y = source->y + FixedMul(dist, finesine[an>>ANGLETOFINESHIFT]);
+ z = source->z + 4*8*FRACUNIT + ((source->player->lookdir)<<FRACBITS)/173;
+ z -= source->floorclip;
+ MissileMobj = P_SpawnMobj(x, y, z, type);
+ if (MissileMobj->info->seesound)
+ {
+ //S_StartSound(MissileMobj, MissileMobj->info->seesound);
+ }
+ MissileMobj->target = source;
+ MissileMobj->angle = an;
+ MissileMobj->momx = FixedMul(MissileMobj->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
+ MissileMobj->momy = FixedMul(MissileMobj->info->speed, finesine[an>>ANGLETOFINESHIFT]);
+ MissileMobj->momz = 0;
+
+// MissileMobj->x += (MissileMobj->momx>>3);
+// MissileMobj->y += (MissileMobj->momy>>3);
+// MissileMobj->z += (MissileMobj->momz>>3);
+
+ if (!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
+ { // Wouln't fit
+
+ return NULL;
+ }
+ return (MissileMobj);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SPMAngle
+//
+//---------------------------------------------------------------------------
+
+mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle)
+{
+ mobj_t *th;
+ angle_t an;
+ fixed_t x, y, z, slope;
+
+//
+// see which target is to be aimed at
+//
+ an = angle;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+ if (!linetarget)
+ {
+ an += 1<<26;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+ if (!linetarget)
+ {
+ an -= 2<<26;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+ }
+ if (!linetarget)
+ {
+ an = angle;
+ slope = ((source->player->lookdir)<<FRACBITS)/173;
+ }
+ }
+ x = source->x;
+ y = source->y;
+ z = source->z + 4*8*FRACUNIT + ((source->player->lookdir)<<FRACBITS)/173;
+ z -= source->floorclip;
+ th = P_SpawnMobj(x, y, z, type);
+// if (th->info->seesound)
+// {
+// S_StartSound(th, th->info->seesound);
+// }
+ th->target = source;
+ th->angle = an;
+ th->momx = FixedMul(th->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
+ th->momy = FixedMul(th->info->speed, finesine[an>>ANGLETOFINESHIFT]);
+ th->momz = FixedMul(th->info->speed, slope);
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+//===========================================================================
+//
+// P_SPMAngleXYZ
+//
+//===========================================================================
+
+mobj_t *P_SPMAngleXYZ(mobj_t *source, fixed_t x, fixed_t y,
+ fixed_t z, mobjtype_t type, angle_t angle)
+{
+ mobj_t *th;
+ angle_t an;
+ fixed_t slope;
+
+//
+// see which target is to be aimed at
+//
+ an = angle;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+ if (!linetarget)
+ {
+ an += 1<<26;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+ if (!linetarget)
+ {
+ an -= 2<<26;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+ }
+ if (!linetarget)
+ {
+ an = angle;
+ slope = ((source->player->lookdir)<<FRACBITS)/173;
+ }
+ }
+ z += 4*8*FRACUNIT + ((source->player->lookdir)<<FRACBITS)/173;
+ z -= source->floorclip;
+ th = P_SpawnMobj(x, y, z, type);
+// if (th->info->seesound)
+// {
+// S_StartSound(th, th->info->seesound);
+// }
+ th->target = source;
+ th->angle = an;
+ th->momx = FixedMul(th->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
+ th->momy = FixedMul(th->info->speed, finesine[an>>ANGLETOFINESHIFT]);
+ th->momz = FixedMul(th->info->speed, slope);
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
+mobj_t *P_SpawnKoraxMissile(fixed_t x, fixed_t y, fixed_t z,
+ mobj_t *source, mobj_t *dest, mobjtype_t type)
+{
+ mobj_t *th;
+ angle_t an;
+ int dist;
+
+ z -= source->floorclip;
+ th = P_SpawnMobj(x, y, z, type);
+ if (th->info->seesound)
+ {
+ S_StartSound(th, th->info->seesound);
+ }
+ th->target = source; // Originator
+ an = R_PointToAngle2(x, y, dest->x, dest->y);
+ if (dest->flags & MF_SHADOW)
+ { // Invisible target
+ an += (P_Random() - P_Random()) <<21;
+ }
+ th->angle = an;
+ an >>= ANGLETOFINESHIFT;
+ th->momx = FixedMul(th->info->speed, finecosine[an]);
+ th->momy = FixedMul(th->info->speed, finesine[an]);
+ dist = P_AproxDistance(dest->x - x, dest->y - y);
+ dist = dist/th->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ th->momz = (dest->z - z + (30*FRACUNIT))/dist;
+ return (P_CheckMissileSpawn(th) ? th : NULL);
+}
+
--- /dev/null
+++ b/p_plats.c
@@ -1,0 +1,276 @@
+
+//**************************************************************************
+//**
+//** p_plats.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 472 $
+//** $Date: 2009-05-26 15:45:18 +0300 (Tue, 26 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+plat_t *activeplats[MAXPLATS];
+
+//==================================================================
+//
+// Move a plat up and down
+//
+//==================================================================
+
+void T_PlatRaise(plat_t *plat)
+{
+ result_e res;
+
+ switch (plat->status)
+ {
+ case PLAT_UP:
+ res = T_MovePlane(plat->sector, plat->speed, plat->high, plat->crush, 0, 1);
+ if (res == RES_CRUSHED && (!plat->crush))
+ {
+ plat->count = plat->wait;
+ plat->status = PLAT_DOWN;
+ SN_StartSequence((mobj_t *)(void *)&plat->sector->soundorg,
+ SEQ_PLATFORM + plat->sector->seqType);
+ }
+ else
+ if (res == RES_PASTDEST)
+ {
+ plat->count = plat->wait;
+ plat->status = PLAT_WAITING;
+ SN_StopSequence((mobj_t *)(void *)&plat->sector->soundorg);
+ switch (plat->type)
+ {
+ case PLAT_DOWNWAITUPSTAY:
+ case PLAT_DOWNBYVALUEWAITUPSTAY:
+ P_RemoveActivePlat(plat);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case PLAT_DOWN:
+ res = T_MovePlane(plat->sector, plat->speed, plat->low, false, 0, -1);
+ if (res == RES_PASTDEST)
+ {
+ plat->count = plat->wait;
+ plat->status = PLAT_WAITING;
+ switch (plat->type)
+ {
+ case PLAT_UPWAITDOWNSTAY:
+ case PLAT_UPBYVALUEWAITDOWNSTAY:
+ P_RemoveActivePlat(plat);
+ break;
+ default:
+ break;
+ }
+ SN_StopSequence((mobj_t *)(void *)&plat->sector->soundorg);
+ }
+ break;
+
+ case PLAT_WAITING:
+ if (!--plat->count)
+ {
+ if (plat->sector->floorheight == plat->low)
+ plat->status = PLAT_UP;
+ else
+ plat->status = PLAT_DOWN;
+ SN_StartSequence((mobj_t *)(void *)&plat->sector->soundorg,
+ SEQ_PLATFORM + plat->sector->seqType);
+ }
+
+// case PLAT_IN_STASIS:
+// break;
+ }
+}
+
+//==================================================================
+//
+// Do Platforms
+// "amount" is only used for SOME platforms.
+//
+//==================================================================
+
+int EV_DoPlat(line_t *line, byte *args, plattype_e type, int amount)
+{
+ plat_t *plat;
+ int secnum;
+ int rtn;
+ sector_t *sec;
+
+ secnum = -1;
+ rtn = 0;
+
+ /*
+ //
+ // Activate all <type> plats that are in_stasis
+ //
+ switch (type)
+ {
+ case PLAT_PERPETUALRAISE:
+ P_ActivateInStasis(args[0]);
+ break;
+ default:
+ break;
+ }
+ */
+
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = §ors[secnum];
+ if (sec->specialdata)
+ continue;
+
+ //
+ // Find lowest & highest floors around sector
+ //
+ rtn = 1;
+ plat = (plat_t *) Z_Malloc( sizeof(*plat), PU_LEVSPEC, NULL);
+ P_AddThinker(&plat->thinker);
+
+ plat->type = type;
+ plat->sector = sec;
+ plat->sector->specialdata = plat;
+ plat->thinker.function = T_PlatRaise;
+ plat->crush = false;
+ plat->tag = args[0];
+ plat->speed = args[1]*(FRACUNIT/8);
+ switch (type)
+ {
+ case PLAT_DOWNWAITUPSTAY:
+ plat->low = P_FindLowestFloorSurrounding(sec) + 8*FRACUNIT;
+ if (plat->low > sec->floorheight)
+ plat->low = sec->floorheight;
+ plat->high = sec->floorheight;
+ plat->wait = args[2];
+ plat->status = PLAT_DOWN;
+ break;
+ case PLAT_DOWNBYVALUEWAITUPSTAY:
+ plat->low = sec->floorheight-args[3]*8*FRACUNIT;
+ if (plat->low > sec->floorheight)
+ plat->low = sec->floorheight;
+ plat->high = sec->floorheight;
+ plat->wait = args[2];
+ plat->status = PLAT_DOWN;
+ break;
+ case PLAT_UPWAITDOWNSTAY:
+ plat->high = P_FindHighestFloorSurrounding(sec);
+ if (plat->high < sec->floorheight)
+ plat->high = sec->floorheight;
+ plat->low = sec->floorheight;
+ plat->wait = args[2];
+ plat->status = PLAT_UP;
+ break;
+ case PLAT_UPBYVALUEWAITDOWNSTAY:
+ plat->high = sec->floorheight+args[3]*8*FRACUNIT;
+ if (plat->high < sec->floorheight)
+ plat->high = sec->floorheight;
+ plat->low = sec->floorheight;
+ plat->wait = args[2];
+ plat->status = PLAT_UP;
+ break;
+ case PLAT_PERPETUALRAISE:
+ plat->low = P_FindLowestFloorSurrounding(sec) + 8*FRACUNIT;
+ if (plat->low > sec->floorheight)
+ plat->low = sec->floorheight;
+ plat->high = P_FindHighestFloorSurrounding(sec);
+ if (plat->high < sec->floorheight)
+ plat->high = sec->floorheight;
+ plat->wait = args[2];
+ plat->status = P_Random() & 1;
+ break;
+ }
+ P_AddActivePlat(plat);
+ SN_StartSequence((mobj_t *)(void *)&sec->soundorg, SEQ_PLATFORM + sec->seqType);
+ }
+ return rtn;
+}
+
+#if 0
+void P_ActivateInStasis(int tag)
+{
+ int i;
+
+ for (i = 0; i < MAXPLATS; i++)
+ {
+ if (activeplats[i] &&
+ (activeplats[i])->tag == tag &&
+ (activeplats[i])->status == PLAT_IN_STASIS)
+ {
+ (activeplats[i])->status = (activeplats[i])->oldstatus;
+ (activeplats[i])->thinker.function = T_PlatRaise;
+ }
+ }
+}
+#endif
+
+void EV_StopPlat(line_t *line, byte *args)
+{
+ int i;
+
+ for (i = 0; i < MAXPLATS; i++)
+ {
+ if ((activeplats[i])->tag == args[0])
+ {
+ (activeplats[i])->sector->specialdata = NULL;
+ P_TagFinished((activeplats[i])->sector->tag);
+ P_RemoveThinker(&(activeplats[i])->thinker);
+ activeplats[i] = NULL;
+
+ return;
+ }
+ }
+
+ /*
+ int j;
+
+ for (j = 0; j < MAXPLATS; j++)
+ {
+ if (activeplats[j] && ((activeplats[j])->status != PLAT_IN_STASIS) &&
+ ((activeplats[j])->tag == args[0]))
+ {
+ (activeplats[j])->oldstatus = (activeplats[j])->status;
+ (activeplats[j])->status = PLAT_IN_STASIS;
+ (activeplats[j])->thinker.function = NULL;
+ SN_StopSequence((mobj_t *)(void *)&(activeplats[j])->sector->soundorg);
+ }
+ }
+ */
+}
+
+void P_AddActivePlat(plat_t *plat)
+{
+ int i;
+ for (i = 0; i < MAXPLATS; i++)
+ {
+ if (activeplats[i] == NULL)
+ {
+ activeplats[i] = plat;
+ return;
+ }
+ }
+ I_Error ("P_AddActivePlat: no more plats!");
+}
+
+void P_RemoveActivePlat(plat_t *plat)
+{
+ int i;
+ for (i = 0; i < MAXPLATS; i++)
+ {
+ if (plat == activeplats[i])
+ {
+ (activeplats[i])->sector->specialdata = NULL;
+ P_TagFinished(plat->sector->tag);
+ P_RemoveThinker(&(activeplats[i])->thinker);
+ activeplats[i] = NULL;
+ return;
+ }
+ }
+ I_Error ("P_RemoveActivePlat: can't find plat!");
+}
+
--- /dev/null
+++ b/p_pspr.c
@@ -1,0 +1,2703 @@
+
+//**************************************************************************
+//**
+//** p_pspr.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+#include "v_compat.h" /* V_SetPaletteXXX() macros */
+
+// MACROS ------------------------------------------------------------------
+
+#define LOWERSPEED FRACUNIT*6
+#define RAISESPEED FRACUNIT*6
+
+#define WEAPONBOTTOM 128*FRACUNIT
+#define WEAPONTOP 32*FRACUNIT
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+extern void P_ExplodeMissile(mobj_t *mo);
+extern void A_UnHideThing(mobj_t *actor);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern fixed_t FloatBobOffsets[64];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+weaponinfo_t WeaponInfo[NUMWEAPONS][NUMCLASSES] =
+{
+ { // First Weapons
+ { // Fighter First Weapon - Punch
+ MANA_NONE, // mana
+ S_PUNCHUP, // upstate
+ S_PUNCHDOWN, // downstate
+ S_PUNCHREADY, // readystate
+ S_PUNCHATK1_1, // atkstate
+ S_PUNCHATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Cleric First Weapon - Mace
+ MANA_NONE, // mana
+ S_CMACEUP, // upstate
+ S_CMACEDOWN, // downstate
+ S_CMACEREADY, // readystate
+ S_CMACEATK_1, // atkstate
+ S_CMACEATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mage First Weapon - Wand
+ MANA_NONE,
+ S_MWANDUP,
+ S_MWANDDOWN,
+ S_MWANDREADY,
+ S_MWANDATK_1,
+ S_MWANDATK_1,
+ S_NULL
+ },
+#ifdef ASSASSIN
+ { // Assassin - Katar
+ MANA_NONE,
+ S_KATARUP,
+ S_KATARDOWN,
+ S_KATARREADY,
+ S_KATARATK1_1,
+ S_KATARATK1_1,
+ S_NULL
+ },
+#endif
+ { // Pig - Snout
+ MANA_NONE, // mana
+ S_SNOUTUP, // upstate
+ S_SNOUTDOWN, // downstate
+ S_SNOUTREADY, // readystate
+ S_SNOUTATK1, // atkstate
+ S_SNOUTATK1, // holdatkstate
+ S_NULL // flashstate
+ }
+ },
+
+ { // Second Weapons
+ { // Fighter - Axe
+ MANA_NONE, // mana
+ S_FAXEUP, // upstate
+ S_FAXEDOWN, // downstate
+ S_FAXEREADY, // readystate
+ S_FAXEATK_1, // atkstate
+ S_FAXEATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Cleric - Serpent Staff
+ MANA_1, // mana
+ S_CSTAFFUP, // upstate
+ S_CSTAFFDOWN, // downstate
+ S_CSTAFFREADY, // readystate
+ S_CSTAFFATK_1, // atkstate
+ S_CSTAFFATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mage - Cone of shards
+ MANA_1, // mana
+ S_CONEUP, // upstate
+ S_CONEDOWN, // downstate
+ S_CONEREADY, // readystate
+ S_CONEATK1_1, // atkstate
+ S_CONEATK1_3, // holdatkstate
+ S_NULL // flashstate
+ },
+#ifdef ASSASSIN
+ { // Assassin - Hand Crossbow
+ MANA_1,
+ S_ACROSSUP,
+ S_ACROSSDOWN,
+ S_ACROSSREADY,
+ S_ACROSSATK_1,
+ S_ACROSSATK_3,
+ S_NULL
+ },
+#endif
+ { // Pig - Snout
+ MANA_NONE, // mana
+ S_SNOUTUP, // upstate
+ S_SNOUTDOWN, // downstate
+ S_SNOUTREADY, // readystate
+ S_SNOUTATK1, // atkstate
+ S_SNOUTATK1, // holdatkstate
+ S_NULL // flashstate
+ }
+ },
+
+ { // Third Weapons
+ { // Fighter - Hammer
+ MANA_NONE, // mana
+ S_FHAMMERUP, // upstate
+ S_FHAMMERDOWN, // downstate
+ S_FHAMMERREADY, // readystate
+ S_FHAMMERATK_1, // atkstate
+ S_FHAMMERATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Cleric - Flame Strike
+ MANA_2, // mana
+ S_CFLAMEUP, // upstate
+ S_CFLAMEDOWN, // downstate
+ S_CFLAMEREADY1, // readystate
+ S_CFLAMEATK_1, // atkstate
+ S_CFLAMEATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mage - Lightning
+ MANA_2, // mana
+ S_MLIGHTNINGUP, // upstate
+ S_MLIGHTNINGDOWN, // downstate
+ S_MLIGHTNINGREADY, // readystate
+ S_MLIGHTNINGATK_1, // atkstate
+ S_MLIGHTNINGATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+#ifdef ASSASSIN
+ { // Assassin - Grenades
+ MANA_2,
+ S_AGRENUP,
+ S_AGRENDOWN,
+ S_AGRENREADY,
+ S_AGRENATK_1,
+ S_AGRENATK_1,
+ S_NULL
+ },
+#endif
+ { // Pig - Snout
+ MANA_NONE, // mana
+ S_SNOUTUP, // upstate
+ S_SNOUTDOWN, // downstate
+ S_SNOUTREADY, // readystate
+ S_SNOUTATK1, // atkstate
+ S_SNOUTATK1, // holdatkstate
+ S_NULL // flashstate
+ }
+ },
+
+ { // Fourth Weapons
+ { // Fighter - Rune Sword
+ MANA_BOTH, // mana
+ S_FSWORDUP, // upstate
+ S_FSWORDDOWN, // downstate
+ S_FSWORDREADY, // readystate
+ S_FSWORDATK_1, // atkstate
+ S_FSWORDATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Cleric - Holy Symbol
+ MANA_BOTH, // mana
+ S_CHOLYUP, // upstate
+ S_CHOLYDOWN, // downstate
+ S_CHOLYREADY, // readystate
+ S_CHOLYATK_1, // atkstate
+ S_CHOLYATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mage - Staff
+ MANA_BOTH, // mana
+ S_MSTAFFUP, // upstate
+ S_MSTAFFDOWN, // downstate
+ S_MSTAFFREADY, // readystate
+ S_MSTAFFATK_1, // atkstate
+ S_MSTAFFATK_1, // holdatkstate
+ S_NULL // flashstate
+ },
+#ifdef ASSASSIN
+ { // Assassin - Staff of Set
+ MANA_BOTH,
+ S_ASTAFFUP,
+ S_ASTAFFDOWN,
+ S_ASTAFFREADY,
+ S_ASTAFFATK_1,
+ S_ASTAFFATK_1,
+ S_NULL
+ },
+#endif
+ { // Pig - Snout
+ MANA_NONE, // mana
+ S_SNOUTUP, // upstate
+ S_SNOUTDOWN, // downstate
+ S_SNOUTREADY, // readystate
+ S_SNOUTATK1, // atkstate
+ S_SNOUTATK1, // holdatkstate
+ S_NULL // flashstate
+ }
+ }
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+//fixed_t bulletslope; // for P_BulletSlope()
+
+static int WeaponManaUse[NUMCLASSES][NUMWEAPONS] =
+{
+ { 0, 2, 3, 14 },
+ { 0, 1, 4, 18 },
+ { 0, 3, 5, 15 },
+#ifdef ASSASSIN
+ { 0, 3, 3, 1 }, // True to Hexen II
+#endif
+ { 0, 0, 0, 0 }
+};
+
+// CODE --------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SetPsprite
+//
+//---------------------------------------------------------------------------
+
+void P_SetPsprite(player_t *player, int position, statenum_t stnum)
+{
+ pspdef_t *psp;
+ state_t *state;
+
+ psp = &player->psprites[position];
+ do
+ {
+ if (!stnum)
+ { // Object removed itself.
+ psp->state = NULL;
+ break;
+ }
+ state = &states[stnum];
+ psp->state = state;
+ psp->tics = state->tics; // could be 0
+ if (state->misc1)
+ { // Set coordinates.
+ psp->sx = state->misc1<<FRACBITS;
+ }
+ if (state->misc2)
+ {
+ psp->sy = state->misc2<<FRACBITS;
+ }
+ if (state->action)
+ { // Call action routine.
+ state->action(player, psp);
+ if (!psp->state)
+ {
+ break;
+ }
+ }
+ stnum = psp->state->nextstate;
+ } while (!psp->tics); // An initial state of 0 could cycle through.
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SetPspriteNF
+//
+// Identical to P_SetPsprite, without calling the action function
+//---------------------------------------------------------------------------
+
+void P_SetPspriteNF(player_t *player, int position, statenum_t stnum)
+{
+ pspdef_t *psp;
+ state_t *state;
+
+ psp = &player->psprites[position];
+ do
+ {
+ if (!stnum)
+ { // Object removed itself.
+ psp->state = NULL;
+ break;
+ }
+ state = &states[stnum];
+ psp->state = state;
+ psp->tics = state->tics; // could be 0
+ if (state->misc1)
+ { // Set coordinates.
+ psp->sx = state->misc1<<FRACBITS;
+ }
+ if (state->misc2)
+ {
+ psp->sy = state->misc2<<FRACBITS;
+ }
+ stnum = psp->state->nextstate;
+ } while (!psp->tics); // An initial state of 0 could cycle through.
+}
+
+/*
+=================
+=
+= P_CalcSwing
+=
+=================
+*/
+
+/*
+fixed_t swingx, swingy;
+void P_CalcSwing (player_t *player)
+{
+ fixed_t swing;
+ int angle;
+
+// OPTIMIZE: tablify this
+
+ swing = player->bob;
+
+ angle = (FINEANGLES/70*leveltime) & FINEMASK;
+ swingx = FixedMul (swing, finesine[angle]);
+
+ angle = (FINEANGLES/70*leveltime + FINEANGLES/2) & FINEMASK;
+ swingy = -FixedMul (swingx, finesine[angle]);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_ActivateMorphWeapon
+//
+//---------------------------------------------------------------------------
+
+void P_ActivateMorphWeapon(player_t *player)
+{
+ player->pendingweapon = WP_NOCHANGE;
+ player->psprites[ps_weapon].sy = WEAPONTOP;
+ player->readyweapon = WP_FIRST; // Snout is the first weapon
+ P_SetPsprite(player, ps_weapon, S_SNOUTREADY);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_PostMorphWeapon
+//
+//---------------------------------------------------------------------------
+
+void P_PostMorphWeapon(player_t *player, weapontype_t weapon)
+{
+ player->pendingweapon = WP_NOCHANGE;
+ player->readyweapon = weapon;
+ player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+ P_SetPsprite(player, ps_weapon, WeaponInfo[weapon][player->playerclass].upstate);
+}
+
+
+//---------------------------------------------------------------------------
+//
+// PROC P_BringUpWeapon
+//
+// Starts bringing the pending weapon up from the bottom of the screen.
+//
+//---------------------------------------------------------------------------
+
+void P_BringUpWeapon(player_t *player)
+{
+ statenum_t newstate;
+
+ if (player->pendingweapon == WP_NOCHANGE)
+ {
+ player->pendingweapon = player->readyweapon;
+ }
+ if (player->playerclass == PCLASS_FIGHTER && player->pendingweapon == WP_SECOND
+ && player->mana[MANA_1])
+ {
+ newstate = S_FAXEUP_G;
+ }
+ else
+ {
+ newstate = WeaponInfo[player->pendingweapon][player->playerclass].upstate;
+ }
+ player->pendingweapon = WP_NOCHANGE;
+ player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+ P_SetPsprite(player, ps_weapon, newstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_CheckMana
+//
+// Returns true if there is enough mana to shoot. If not, selects the
+// next weapon to use.
+//
+//---------------------------------------------------------------------------
+
+static boolean P_CheckMana(player_t *player)
+{
+ manatype_t mana;
+ int count;
+
+ mana = WeaponInfo[player->readyweapon][player->playerclass].mana;
+ count = WeaponManaUse[player->playerclass][player->readyweapon];
+ if (mana == MANA_BOTH)
+ {
+ if (player->mana[MANA_1] >= count && player->mana[MANA_2] >= count)
+ {
+ return true;
+ }
+ }
+ else if (mana == MANA_NONE || player->mana[mana] >= count)
+ {
+ return true;
+ }
+ // out of mana, pick a weapon to change to
+ do
+ {
+ if (player->weaponowned[WP_THIRD]
+ && player->mana[MANA_2] >= WeaponManaUse[player->playerclass][WP_THIRD])
+ {
+ player->pendingweapon = WP_THIRD;
+ }
+ else if (player->weaponowned[WP_SECOND]
+ && player->mana[MANA_1] >= WeaponManaUse[player->playerclass][WP_SECOND])
+ {
+ player->pendingweapon = WP_SECOND;
+ }
+ else if (player->weaponowned[WP_FOURTH]
+ && player->mana[MANA_1] >= WeaponManaUse[player->playerclass][WP_FOURTH]
+ && player->mana[MANA_2] >= WeaponManaUse[player->playerclass][WP_FOURTH])
+ {
+ player->pendingweapon = WP_FOURTH;
+ }
+ else
+ {
+ player->pendingweapon = WP_FIRST;
+ }
+ } while (player->pendingweapon == WP_NOCHANGE);
+ P_SetPsprite(player, ps_weapon,
+ WeaponInfo[player->readyweapon][player->playerclass].downstate);
+ return false;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_FireWeapon
+//
+//---------------------------------------------------------------------------
+
+static void P_FireWeapon(player_t *player)
+{
+ statenum_t attackState;
+
+ if (!P_CheckMana(player))
+ {
+ return;
+ }
+ P_SetMobjState(player->mo, PStateAttack[player->playerclass]); // S_PLAY_ATK1);
+ if (player->playerclass == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
+ && player->mana[MANA_1] > 0)
+ { // Glowing axe
+ attackState = S_FAXEATK_G1;
+ }
+ else
+ {
+ attackState = player->refire ?
+ WeaponInfo[player->readyweapon][player->playerclass].holdatkstate
+ : WeaponInfo[player->readyweapon][player->playerclass].atkstate;
+ }
+ P_SetPsprite(player, ps_weapon, attackState);
+ P_NoiseAlert(player->mo, player->mo);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_DropWeapon
+//
+// The player died, so put the weapon away.
+//
+//---------------------------------------------------------------------------
+
+void P_DropWeapon(player_t *player)
+{
+ P_SetPsprite(player, ps_weapon,
+ WeaponInfo[player->readyweapon][player->playerclass].downstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_WeaponReady
+//
+// The player can fire the weapon or change to another weapon at this time.
+//
+//---------------------------------------------------------------------------
+
+void A_WeaponReady(player_t *player, pspdef_t *psp)
+{
+ int angle;
+
+ // Change player from attack state
+ if (player->mo->state >= &states[PStateAttack[player->playerclass]]
+ && player->mo->state <= &states[PStateAttackEnd[player->playerclass]])
+ {
+ P_SetMobjState(player->mo, PStateNormal[player->playerclass]);
+ }
+ // Put the weapon away if the player has a pending weapon or has
+ // died.
+ if (player->pendingweapon != WP_NOCHANGE || !player->health)
+ {
+ P_SetPsprite(player, ps_weapon,
+ WeaponInfo[player->readyweapon][player->playerclass].downstate);
+ return;
+ }
+
+ // Check for fire.
+ if (player->cmd.buttons & BT_ATTACK)
+ {
+ player->attackdown = true;
+ P_FireWeapon(player);
+ return;
+ }
+ else
+ {
+ player->attackdown = false;
+ }
+
+ if (!player->morphTics)
+ {
+ // Bob the weapon based on movement speed.
+ angle = (128*leveltime)&FINEMASK;
+ psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]);
+ angle &= FINEANGLES/2 - 1;
+ psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_ReFire
+//
+// The player can re fire the weapon without lowering it entirely.
+//
+//---------------------------------------------------------------------------
+
+void A_ReFire(player_t *player, pspdef_t *psp)
+{
+ if ((player->cmd.buttons&BT_ATTACK)
+ && player->pendingweapon == WP_NOCHANGE && player->health)
+ {
+ player->refire++;
+ P_FireWeapon(player);
+ }
+ else
+ {
+ player->refire = 0;
+ P_CheckMana(player);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_Lower
+//
+//---------------------------------------------------------------------------
+
+void A_Lower(player_t *player, pspdef_t *psp)
+{
+ if (player->morphTics)
+ {
+ psp->sy = WEAPONBOTTOM;
+ }
+ else
+ {
+ psp->sy += LOWERSPEED;
+ }
+ if (psp->sy < WEAPONBOTTOM)
+ { // Not lowered all the way yet
+ return;
+ }
+ if (player->playerstate == PST_DEAD)
+ { // Player is dead, so don't bring up a pending weapon
+ psp->sy = WEAPONBOTTOM;
+ return;
+ }
+ if (!player->health)
+ { // Player is dead, so keep the weapon off screen
+ P_SetPsprite(player, ps_weapon, S_NULL);
+ return;
+ }
+ player->readyweapon = player->pendingweapon;
+ P_BringUpWeapon(player);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_Raise
+//
+//---------------------------------------------------------------------------
+
+void A_Raise(player_t *player, pspdef_t *psp)
+{
+ psp->sy -= RAISESPEED;
+ if (psp->sy > WEAPONTOP)
+ { // Not raised all the way yet
+ return;
+ }
+ psp->sy = WEAPONTOP;
+ if (player->playerclass == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
+ && player->mana[MANA_1])
+ {
+ P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon,
+ WeaponInfo[player->readyweapon][player->playerclass].readystate);
+ }
+}
+
+/*
+===============
+=
+= P_BulletSlope
+=
+= Sets a slope so a near miss is at aproximately the height of the
+= intended target
+=
+===============
+*/
+
+/*
+static void P_BulletSlope (mobj_t *mo)
+{
+ angle_t an;
+
+//
+// see which target is to be aimed at
+//
+ an = mo->angle;
+ bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+ if (!linetarget)
+ {
+ an += 1<<26;
+ bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+ if (!linetarget)
+ {
+ an -= 2<<26;
+ bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+ }
+ if (!linetarget)
+ {
+ an += 1<<26;
+ bulletslope = (mo->player->lookdir<<FRACBITS)/173;
+ }
+ }
+}
+*/
+
+//****************************************************************************
+//
+// WEAPON ATTACKS
+//
+//****************************************************************************
+
+//============================================================================
+//
+// AdjustPlayerAngle
+//
+//============================================================================
+
+#define MAX_ANGLE_ADJUST (5*ANGLE_1)
+
+static void AdjustPlayerAngle(mobj_t *pmo)
+{
+ angle_t angle;
+ int difference;
+
+ angle = R_PointToAngle2(pmo->x, pmo->y, linetarget->x, linetarget->y);
+ difference = (int)angle - (int)pmo->angle;
+ if (abs(difference) > MAX_ANGLE_ADJUST)
+ {
+ pmo->angle += difference > 0 ? MAX_ANGLE_ADJUST : -MAX_ANGLE_ADJUST;
+ }
+ else
+ {
+ pmo->angle = angle;
+ }
+}
+
+//============================================================================
+//
+// A_SnoutAttack
+//
+//============================================================================
+
+void A_SnoutAttack(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+
+ damage = 3 + (P_Random() & 3);
+ angle = player->mo->angle;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ PuffType = MT_SNOUTPUFF;
+ PuffSpawned = NULL;
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+ S_StartSound(player->mo, SFX_PIG_ACTIVE1 + (P_Random() & 1));
+ if (linetarget)
+ {
+ AdjustPlayerAngle(player->mo);
+// player->mo->angle = R_PointToAngle2(player->mo->x,
+// player->mo->y, linetarget->x, linetarget->y);
+ if (PuffSpawned)
+ { // Bit something
+ S_StartSound(player->mo, SFX_PIG_ATTACK);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_FHammerAttack
+//
+//============================================================================
+
+#define HAMMER_RANGE (MELEERANGE+MELEERANGE/2)
+
+void A_FHammerAttack(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ mobj_t *pmo = player->mo;
+ int damage;
+ fixed_t power;
+ int slope;
+ int i;
+
+ damage = 60 + (P_Random() & 63);
+ power = 10*FRACUNIT;
+ PuffType = MT_HAMMERPUFF;
+ for (i = 0; i < 16; i++)
+ {
+ angle = pmo->angle + i*(ANG45/32);
+ slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
+ AdjustPlayerAngle(pmo);
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ pmo->special1 = false; // Don't throw a hammer
+ goto hammerdone;
+ }
+ angle = pmo->angle - i*(ANG45/32);
+ slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
+ AdjustPlayerAngle(pmo);
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ pmo->special1 = false; // Don't throw a hammer
+ goto hammerdone;
+ }
+ }
+ // didn't find any targets in meleerange, so set to throw out a hammer
+ PuffSpawned = NULL;
+ angle = pmo->angle;
+ slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
+ P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
+ if (PuffSpawned)
+ {
+ pmo->special1 = false;
+ }
+ else
+ {
+ pmo->special1 = true;
+ }
+hammerdone:
+ if (player->mana[MANA_2] <
+ WeaponManaUse[player->playerclass][player->readyweapon])
+ { // Don't spawn a hammer if the player doesn't have enough mana
+ pmo->special1 = false;
+ }
+ return;
+}
+
+//============================================================================
+//
+// A_FHammerThrow
+//
+//============================================================================
+
+void A_FHammerThrow(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+
+ if (!player->mo->special1)
+ {
+ return;
+ }
+ player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ mo = P_SpawnPlayerMissile(player->mo, MT_HAMMER_MISSILE);
+ if (mo)
+ {
+ mo->special1 = 0;
+ }
+}
+
+//============================================================================
+//
+// A_FSwordAttack
+//
+//============================================================================
+
+void A_FSwordAttack(player_t *player, pspdef_t *psp)
+{
+ mobj_t *pmo;
+
+ player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ pmo = player->mo;
+ P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z - 10*FRACUNIT, MT_FSWORD_MISSILE, pmo->angle + ANG45/4);
+ P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z - 5*FRACUNIT, MT_FSWORD_MISSILE, pmo->angle + ANG45/8);
+ P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z, MT_FSWORD_MISSILE, pmo->angle);
+ P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z + 5*FRACUNIT, MT_FSWORD_MISSILE, pmo->angle - ANG45/8);
+ P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z + 10*FRACUNIT, MT_FSWORD_MISSILE, pmo->angle - ANG45/4);
+ S_StartSound(pmo, SFX_FIGHTER_SWORD_FIRE);
+}
+
+//============================================================================
+//
+// A_FSwordAttack2
+//
+//============================================================================
+
+void A_FSwordAttack2(mobj_t *actor)
+{
+ angle_t angle = actor->angle;
+
+ P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle + ANG45/4, 0);
+ P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle + ANG45/8, 0);
+ P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle, 0);
+ P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle - ANG45/8, 0);
+ P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle - ANG45/4, 0);
+ S_StartSound(actor, SFX_FIGHTER_SWORD_FIRE);
+}
+
+//============================================================================
+//
+// A_FSwordFlames
+//
+//============================================================================
+
+void A_FSwordFlames(mobj_t *actor)
+{
+ int i;
+
+ for (i = 1 + (P_Random() & 3); i; i--)
+ {
+ P_SpawnMobj(actor->x + ((P_Random() - 128) << 12),
+ actor->y + ((P_Random() - 128) << 12),
+ actor->z + ((P_Random() - 128) << 11),
+ MT_FSWORD_FLAME);
+ }
+}
+
+//============================================================================
+//
+// A_MWandAttack
+//
+//============================================================================
+
+void A_MWandAttack(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnPlayerMissile(player->mo, MT_MWAND_MISSILE);
+ if (mo)
+ {
+ mo->thinker.function = P_BlasterMobjThinker;
+ }
+ S_StartSound(player->mo, SFX_MAGE_WAND_FIRE);
+}
+
+// ===== Mage Lightning Weapon =====
+
+//============================================================================
+//
+// A_LightningReady
+//
+//============================================================================
+
+void A_LightningReady(player_t *player, pspdef_t *psp)
+{
+ A_WeaponReady(player, psp);
+ if (P_Random() < 160)
+ {
+ S_StartSound(player->mo, SFX_MAGE_LIGHTNING_READY);
+ }
+}
+
+//============================================================================
+//
+// A_LightningClip
+//
+//============================================================================
+
+#define ZAGSPEED FRACUNIT
+
+void A_LightningClip(mobj_t *actor)
+{
+ mobj_t *cMo;
+ mobj_t *target = NULL; /* jim added initialiser */
+ int zigZag;
+
+ if (actor->type == MT_LIGHTNING_FLOOR)
+ {
+ actor->z = actor->floorz;
+ target = (mobj_t *)((mobj_t *)actor->special2)->special1;
+ }
+ else if (actor->type == MT_LIGHTNING_CEILING)
+ {
+ actor->z = actor->ceilingz - actor->height;
+ target = (mobj_t *)actor->special1;
+ }
+ if (actor->type == MT_LIGHTNING_FLOOR)
+ { // floor lightning zig-zags, and forces the ceiling lightning to mimic
+ cMo = (mobj_t *)actor->special2;
+ zigZag = P_Random();
+ if ((zigZag > 128 && actor->special1 < 2) || actor->special1 < -2)
+ {
+ P_ThrustMobj(actor, actor->angle + ANG90, ZAGSPEED);
+ if (cMo)
+ {
+ P_ThrustMobj(cMo, actor->angle + ANG90, ZAGSPEED);
+ }
+ actor->special1++;
+ }
+ else
+ {
+ P_ThrustMobj(actor, actor->angle - ANG90, ZAGSPEED);
+ if (cMo)
+ {
+ P_ThrustMobj(cMo, cMo->angle - ANG90, ZAGSPEED);
+ }
+ actor->special1--;
+ }
+ }
+ if (target)
+ {
+ if (target->health <= 0)
+ {
+ P_ExplodeMissile(actor);
+ }
+ else
+ {
+ actor->angle = R_PointToAngle2(actor->x, actor->y, target->x, target->y);
+ actor->momx = 0;
+ actor->momy = 0;
+ P_ThrustMobj(actor, actor->angle, actor->info->speed>>1);
+ }
+ }
+}
+
+//============================================================================
+//
+// A_LightningZap
+//
+//============================================================================
+
+void A_LightningZap(mobj_t *actor)
+{
+ mobj_t *mo;
+ fixed_t deltaZ;
+
+ A_LightningClip(actor);
+
+ actor->health -= 8;
+ if (actor->health <= 0)
+ {
+ P_SetMobjState(actor, actor->info->deathstate);
+ return;
+ }
+ if (actor->type == MT_LIGHTNING_FLOOR)
+ {
+ deltaZ = 10*FRACUNIT;
+ }
+ else
+ {
+ deltaZ = -10*FRACUNIT;
+ }
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) * actor->radius/256),
+ actor->y + ((P_Random() - 128) * actor->radius/256),
+ actor->z + deltaZ, MT_LIGHTNING_ZAP);
+ if (mo)
+ {
+ mo->special2 = (intptr_t)actor;
+ mo->momx = actor->momx;
+ mo->momy = actor->momy;
+ mo->target = actor->target;
+ if (actor->type == MT_LIGHTNING_FLOOR)
+ {
+ mo->momz = 20*FRACUNIT;
+ }
+ else
+ {
+ mo->momz = -20*FRACUNIT;
+ }
+ }
+ /*
+ mo = P_SpawnMobj(actor->x + ((P_Random() - 128) * actor->radius/256),
+ actor->y + ((P_Random() - 128) * actor->radius/256),
+ actor->z+deltaZ, MT_LIGHTNING_ZAP);
+ if (mo)
+ {
+ mo->special2 = (intptr_t)actor;
+ mo->momx = actor->momx;
+ mo->momy = actor->momy;
+ mo->target = actor->target;
+ if (actor->type == MT_LIGHTNING_FLOOR)
+ {
+ mo->momz = 16*FRACUNIT;
+ }
+ else
+ {
+ mo->momz = -16*FRACUNIT;
+ }
+ }
+ */
+ if (actor->type == MT_LIGHTNING_FLOOR && P_Random() < 160)
+ {
+ S_StartSound(actor, SFX_MAGE_LIGHTNING_CONTINUOUS);
+ }
+}
+
+//============================================================================
+//
+// A_MLightningAttack2
+//
+//============================================================================
+
+void A_MLightningAttack2(mobj_t *actor)
+{
+ mobj_t *fmo, *cmo;
+
+ fmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_FLOOR);
+ cmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_CEILING);
+ if (fmo)
+ {
+ fmo->special1 = 0;
+ fmo->special2 = (intptr_t)cmo;
+ A_LightningZap(fmo);
+ }
+ if (cmo)
+ {
+ cmo->special1 = 0; // mobj that it will track
+ cmo->special2 = (intptr_t)fmo;
+ A_LightningZap(cmo);
+ }
+ S_StartSound(actor, SFX_MAGE_LIGHTNING_FIRE);
+}
+
+//============================================================================
+//
+// A_MLightningAttack
+//
+//============================================================================
+
+void A_MLightningAttack(player_t *player, pspdef_t *psp)
+{
+ A_MLightningAttack2(player->mo);
+ player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+}
+
+//============================================================================
+//
+// A_ZapMimic
+//
+//============================================================================
+
+void A_ZapMimic(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = (mobj_t *)actor->special2;
+ if (mo)
+ {
+ if (mo->state >= &states[mo->info->deathstate]
+ || mo->state == &states[S_FREETARGMOBJ])
+ {
+ P_ExplodeMissile(actor);
+ }
+ else
+ {
+ actor->momx = mo->momx;
+ actor->momy = mo->momy;
+ }
+ }
+}
+
+//============================================================================
+//
+// A_LastZap
+//
+//============================================================================
+
+void A_LastZap(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_LIGHTNING_ZAP);
+ if (mo)
+ {
+ P_SetMobjState(mo, S_LIGHTNING_ZAP_X1);
+ mo->momz = 40*FRACUNIT;
+ }
+}
+
+//============================================================================
+//
+// A_LightningRemove
+//
+//============================================================================
+
+void A_LightningRemove(mobj_t *actor)
+{
+ mobj_t *mo;
+
+ mo = (mobj_t *)actor->special2;
+ if (mo)
+ {
+ mo->special2 = 0;
+ P_ExplodeMissile(mo);
+ }
+}
+
+
+//============================================================================
+//
+// MStaffSpawn
+//
+//============================================================================
+
+static void MStaffSpawn(mobj_t *pmo, angle_t angle)
+{
+ mobj_t *mo;
+
+ mo = P_SPMAngle(pmo, MT_MSTAFF_FX2, angle);
+ if (mo)
+ {
+ mo->target = pmo;
+ mo->special1 = (intptr_t)P_RoughMonsterSearch(mo, 10);
+ }
+}
+
+//============================================================================
+//
+// A_MStaffAttack
+//
+//============================================================================
+
+void A_MStaffAttack(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ mobj_t *pmo;
+
+ player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ pmo = player->mo;
+ angle = pmo->angle;
+
+ MStaffSpawn(pmo, angle);
+ MStaffSpawn(pmo, angle-ANGLE_1*5);
+ MStaffSpawn(pmo, angle+ANGLE_1*5);
+ S_StartSound(player->mo, SFX_MAGE_STAFF_FIRE);
+ if (player == &players[consoleplayer])
+ {
+ player->damagecount = 0;
+ player->bonuscount = 0;
+ V_SetPaletteShift(STARTSCOURGEPAL);
+ }
+}
+
+//============================================================================
+//
+// A_MStaffPalette
+//
+//============================================================================
+
+void A_MStaffPalette(player_t *player, pspdef_t *psp)
+{
+ int pal;
+
+ if (player == &players[consoleplayer])
+ {
+ pal = STARTSCOURGEPAL + psp->state - (&states[S_MSTAFFATK_2]);
+ if (pal == STARTSCOURGEPAL + 3)
+ { // reset back to original playpal
+ pal = 0;
+ }
+ V_SetPaletteShift(pal);
+ }
+}
+
+//============================================================================
+//
+// A_MStaffWeave
+//
+//============================================================================
+
+void A_MStaffWeave(mobj_t *actor)
+{
+ fixed_t newX, newY;
+ int weaveXY, weaveZ;
+ int angle;
+
+ weaveXY = actor->special2 >> 16;
+ weaveZ = actor->special2 & 0xFFFF;
+ angle = (actor->angle + ANG90)>>ANGLETOFINESHIFT;
+ newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<2);
+ newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<2);
+ weaveXY = (weaveXY + 6) & 63;
+ newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<2);
+ newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<2);
+ P_TryMove(actor, newX, newY);
+ actor->z -= FloatBobOffsets[weaveZ]<<1;
+ weaveZ = (weaveZ + 3) & 63;
+ actor->z += FloatBobOffsets[weaveZ]<<1;
+ if (actor->z <= actor->floorz)
+ {
+ actor->z = actor->floorz + FRACUNIT;
+ }
+ actor->special2 = weaveZ + (weaveXY<<16);
+}
+
+//============================================================================
+//
+// A_MStaffTrack
+//
+//============================================================================
+
+void A_MStaffTrack(mobj_t *actor)
+{
+ if ((actor->special1 == 0) && (P_Random() < 50))
+ {
+ actor->special1 = (intptr_t)P_RoughMonsterSearch(actor, 10);
+ }
+ P_SeekerMissile(actor, ANGLE_1*2, ANGLE_1*10);
+}
+
+//============================================================================
+//
+// MStaffSpawn2 - for use by mage class boss
+//
+//============================================================================
+
+static void MStaffSpawn2(mobj_t *actor, angle_t angle)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMissileAngle(actor, MT_MSTAFF_FX2, angle, 0);
+ if (mo)
+ {
+ mo->target = actor;
+ mo->special1 = (intptr_t)P_RoughMonsterSearch(mo, 10);
+ }
+}
+
+//============================================================================
+//
+// A_MStaffAttack2 - for use by mage class boss
+//
+//============================================================================
+
+void A_MStaffAttack2(mobj_t *actor)
+{
+ angle_t angle;
+ angle = actor->angle;
+ MStaffSpawn2(actor, angle);
+ MStaffSpawn2(actor, angle - ANGLE_1*5);
+ MStaffSpawn2(actor, angle + ANGLE_1*5);
+ S_StartSound(actor, SFX_MAGE_STAFF_FIRE);
+}
+
+//============================================================================
+//
+// A_FPunchAttack
+//
+//============================================================================
+
+void A_FPunchAttack(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+ mobj_t *pmo = player->mo;
+ fixed_t power;
+ int i;
+
+ damage = 40 + (P_Random() & 15);
+ power = 2*FRACUNIT;
+ PuffType = MT_PUNCHPUFF;
+ for (i = 0; i < 16; i++)
+ {
+ angle = pmo->angle + i*(ANG45/16);
+ slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
+ if (linetarget)
+ {
+ player->mo->special1++;
+ if (pmo->special1 == 3)
+ {
+ damage <<= 1;
+ power = 6*FRACUNIT;
+ PuffType = MT_HAMMERPUFF;
+ }
+ P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ AdjustPlayerAngle(pmo);
+ goto punchdone;
+ }
+ angle = pmo->angle - i*(ANG45/16);
+ slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
+ if (linetarget)
+ {
+ pmo->special1++;
+ if (pmo->special1 == 3)
+ {
+ damage <<= 1;
+ power = 6*FRACUNIT;
+ PuffType = MT_HAMMERPUFF;
+ }
+ P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ AdjustPlayerAngle(pmo);
+ goto punchdone;
+ }
+ }
+ // didn't find any creatures, so try to strike any walls
+ pmo->special1 = 0;
+
+ angle = pmo->angle;
+ slope = P_AimLineAttack(pmo, angle, MELEERANGE);
+ P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
+
+punchdone:
+ if (pmo->special1 == 3)
+ {
+ pmo->special1 = 0;
+ P_SetPsprite(player, ps_weapon, S_PUNCHATK2_1);
+ S_StartSound(pmo, SFX_FIGHTER_GRUNT);
+ }
+ return;
+}
+
+//============================================================================
+//
+// A_FAxeAttack
+//
+//============================================================================
+
+#define AXERANGE 2.25*MELEERANGE
+
+void A_FAxeAttack(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ mobj_t *pmo = player->mo;
+ fixed_t power;
+ int damage;
+ int slope;
+ int i;
+ int useMana;
+
+ damage = 40 + (P_Random() & 15) + (P_Random() & 7);
+ power = 0;
+ if (player->mana[MANA_1] > 0)
+ {
+ damage <<= 1;
+ power = 6*FRACUNIT;
+ PuffType = MT_AXEPUFF_GLOW;
+ useMana = 1;
+ }
+ else
+ {
+ PuffType = MT_AXEPUFF;
+ useMana = 0;
+ }
+ for (i = 0; i < 16; i++)
+ {
+ angle = pmo->angle + i*(ANG45/16);
+ slope = P_AimLineAttack(pmo, angle, AXERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, AXERANGE, slope, damage);
+ if (linetarget->flags&MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ AdjustPlayerAngle(pmo);
+ useMana++;
+ goto axedone;
+ }
+ angle = pmo->angle - i*(ANG45/16);
+ slope = P_AimLineAttack(pmo, angle, AXERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, AXERANGE, slope, damage);
+ if (linetarget->flags & MF_COUNTKILL)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ AdjustPlayerAngle(pmo);
+ useMana++;
+ goto axedone;
+ }
+ }
+ // didn't find any creatures, so try to strike any walls
+ pmo->special1 = 0;
+
+ angle = pmo->angle;
+ slope = P_AimLineAttack(pmo, angle, MELEERANGE);
+ P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
+
+axedone:
+ if (useMana == 2)
+ {
+ player->mana[MANA_1] -=
+ WeaponManaUse[player->playerclass][player->readyweapon];
+ if (player->mana[MANA_1] <= 0)
+ {
+ P_SetPsprite(player, ps_weapon, S_FAXEATK_5);
+ }
+ }
+ return;
+}
+
+//===========================================================================
+//
+// A_CMaceAttack
+//
+//===========================================================================
+
+void A_CMaceAttack(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+ int i;
+
+ damage = 25 + (P_Random() & 15);
+ PuffType = MT_HAMMERPUFF;
+ for (i = 0; i < 16; i++)
+ {
+ angle = player->mo->angle + i*(ANG45/16);
+ slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(player->mo, angle, 2*MELEERANGE, slope, damage);
+ AdjustPlayerAngle(player->mo);
+// player->mo->angle = R_PointToAngle2(player->mo->x,
+// player->mo->y, linetarget->x, linetarget->y);
+ goto macedone;
+ }
+ angle = player->mo->angle - i*(ANG45/16);
+ slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(player->mo, angle, 2*MELEERANGE, slope, damage);
+ AdjustPlayerAngle(player->mo);
+// player->mo->angle = R_PointToAngle2(player->mo->x,
+// player->mo->y, linetarget->x, linetarget->y);
+ goto macedone;
+ }
+ }
+ // didn't find any creatures, so try to strike any walls
+ player->mo->special1 = 0;
+
+ angle = player->mo->angle;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+
+macedone:
+ return;
+}
+
+//============================================================================
+//
+// A_CStaffCheck
+//
+//============================================================================
+
+void A_CStaffCheck(player_t *player, pspdef_t *psp)
+{
+ mobj_t *pmo;
+ int damage;
+ int newLife;
+ angle_t angle;
+ int slope;
+ int i;
+
+ pmo = player->mo;
+ damage = 20 + (P_Random() & 15);
+ PuffType = MT_CSTAFFPUFF;
+ for (i = 0; i < 3; i++)
+ {
+ angle = pmo->angle + i*(ANG45/16);
+ slope = P_AimLineAttack(pmo, angle, 1.5*MELEERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, 1.5*MELEERANGE, slope, damage);
+ pmo->angle = R_PointToAngle2(pmo->x, pmo->y,
+ linetarget->x, linetarget->y);
+ if ((linetarget->player || linetarget->flags & MF_COUNTKILL)
+ && (!(linetarget->flags2 & (MF2_DORMANT+MF2_INVULNERABLE))))
+ {
+ newLife = player->health + (damage>>3);
+ newLife = newLife > 100 ? 100 : newLife;
+ pmo->health = player->health = newLife;
+ P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
+ }
+ player->mana[MANA_1] -=
+ WeaponManaUse[player->playerclass][player->readyweapon];
+ break;
+ }
+ angle = pmo->angle - i*(ANG45/16);
+ slope = P_AimLineAttack(player->mo, angle, 1.5*MELEERANGE);
+ if (linetarget)
+ {
+ P_LineAttack(pmo, angle, 1.5*MELEERANGE, slope, damage);
+ pmo->angle = R_PointToAngle2(pmo->x, pmo->y,
+ linetarget->x, linetarget->y);
+ if (linetarget->player || linetarget->flags & MF_COUNTKILL)
+ {
+ newLife = player->health + (damage>>4);
+ newLife = newLife > 100 ? 100 : newLife;
+ pmo->health = player->health = newLife;
+ P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
+ }
+ player->mana[MANA_1] -=
+ WeaponManaUse[player->playerclass][player->readyweapon];
+ break;
+ }
+ }
+}
+
+//============================================================================
+//
+// A_CStaffAttack
+//
+//============================================================================
+
+void A_CStaffAttack(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+ mobj_t *pmo;
+
+ player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ pmo = player->mo;
+ mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle - (ANG45/15));
+ if (mo)
+ {
+ mo->special2 = 32;
+ }
+ mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle + (ANG45/15));
+ if (mo)
+ {
+ mo->special2 = 0;
+ }
+ S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
+}
+
+//============================================================================
+//
+// A_CStaffMissileSlither
+//
+//============================================================================
+
+void A_CStaffMissileSlither(mobj_t *actor)
+{
+ fixed_t newX, newY;
+ int weaveXY;
+ int angle;
+
+ weaveXY = actor->special2;
+ angle = (actor->angle + ANG90)>>ANGLETOFINESHIFT;
+ newX = actor->x - FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]);
+ newY = actor->y - FixedMul(finesine[angle], FloatBobOffsets[weaveXY]);
+ weaveXY = (weaveXY + 3) & 63;
+ newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]);
+ newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY]);
+ P_TryMove(actor, newX, newY);
+ actor->special2 = weaveXY;
+}
+
+//============================================================================
+//
+// A_CStaffInitBlink
+//
+//============================================================================
+
+void A_CStaffInitBlink(player_t *player, pspdef_t *psp)
+{
+ player->mo->special1 = (P_Random()>>1) + 20;
+}
+
+//============================================================================
+//
+// A_CStaffCheckBlink
+//
+//============================================================================
+
+void A_CStaffCheckBlink(player_t *player, pspdef_t *psp)
+{
+ if (!--player->mo->special1)
+ {
+ P_SetPsprite(player, ps_weapon, S_CSTAFFBLINK1);
+ player->mo->special1 = (P_Random() + 50)>>2;
+ }
+}
+
+//============================================================================
+//
+// A_CFlameAttack
+//
+//============================================================================
+
+#define FLAMESPEED (0.45*FRACUNIT)
+#define CFLAMERANGE (12*64*FRACUNIT)
+
+void A_CFlameAttack(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnPlayerMissile(player->mo, MT_CFLAME_MISSILE);
+ if (mo)
+ {
+ mo->thinker.function = P_BlasterMobjThinker;
+ mo->special1 = 2;
+ }
+
+ player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
+}
+
+//============================================================================
+//
+// A_CFlamePuff
+//
+//============================================================================
+
+void A_CFlamePuff(mobj_t *actor)
+{
+ A_UnHideThing(actor);
+ actor->momx = 0;
+ actor->momy = 0;
+ actor->momz = 0;
+ S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
+}
+
+//============================================================================
+//
+// A_CFlameMissile
+//
+//============================================================================
+
+void A_CFlameMissile(mobj_t *actor)
+{
+ int i;
+ int an;
+// int an90;
+ fixed_t dist;
+ mobj_t *mo;
+
+ A_UnHideThing(actor);
+ S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
+ if (BlockingMobj && BlockingMobj->flags & MF_SHOOTABLE)
+ { // Hit something, so spawn the flame circle around the thing
+ dist = BlockingMobj->radius + 18*FRACUNIT;
+ for (i = 0; i < 4; i++)
+ {
+ an = (i*ANG45)>>ANGLETOFINESHIFT;
+ // an90 = (i*ANG45 + ANG90)>>ANGLETOFINESHIFT;
+ mo = P_SpawnMobj(BlockingMobj->x + FixedMul(dist, finecosine[an]),
+ BlockingMobj->y + FixedMul(dist, finesine[an]),
+ BlockingMobj->z + 5*FRACUNIT, MT_CIRCLEFLAME);
+ if (mo)
+ {
+ mo->angle = an<<ANGLETOFINESHIFT;
+ mo->target = actor->target;
+ mo->momx = mo->special1 = FixedMul(finecosine[an], FLAMESPEED);
+ mo->momy = mo->special2 = FixedMul(finesine[an], FLAMESPEED);
+ mo->tics -= P_Random() & 3;
+ }
+ mo = P_SpawnMobj(BlockingMobj->x - FixedMul(dist, finecosine[an]),
+ BlockingMobj->y - FixedMul(dist, finesine[an]),
+ BlockingMobj->z + 5*FRACUNIT, MT_CIRCLEFLAME);
+ if (mo)
+ {
+ mo->angle = ANG180 + (an<<ANGLETOFINESHIFT);
+ mo->target = actor->target;
+ mo->momx = mo->special1 = FixedMul(finecosine[an], -FLAMESPEED);
+ mo->momy = mo->special2 = FixedMul(finesine[an], -FLAMESPEED);
+ mo->tics -= P_Random() & 3;
+ }
+ }
+ P_SetMobjState(actor, S_FLAMEPUFF2_1);
+ }
+}
+
+/*
+void A_CFlameAttack(player_t *player, pspdef_t *psp)
+{
+ mobj_t *pmo;
+ angle_t angle;
+ int damage;
+ int i;
+ int an;
+// int an90;
+ fixed_t dist;
+ mobj_t *mo;
+
+ pmo = player->mo;
+ P_BulletSlope(pmo);
+ damage = 25 + HITDICE(3);
+ angle = pmo->angle;
+ if (player->refire)
+ {
+ angle += (P_Random() - P_Random()) << 17;
+ }
+ P_AimLineAttack(pmo, angle, CFLAMERANGE); // Correctly set linetarget
+ if (!linetarget)
+ {
+ angle += ANGLE_1*2;
+ P_AimLineAttack(pmo, angle, CFLAMERANGE);
+ if (!linetarget)
+ {
+ angle -= ANGLE_1*4;
+ P_AimLineAttack(pmo, angle, CFLAMERANGE);
+ if (!linetarget)
+ {
+ angle += ANGLE_1*2;
+ }
+ }
+ }
+ if (linetarget)
+ {
+ PuffType = MT_FLAMEPUFF2;
+ }
+ else
+ {
+ PuffType = MT_FLAMEPUFF;
+ }
+ P_LineAttack(pmo, angle, CFLAMERANGE, bulletslope, damage);
+ if (linetarget)
+ { // Hit something, so spawn the flame circle around the thing
+ dist = linetarget->radius + 18*FRACUNIT;
+ for (i = 0; i < 4; i++)
+ {
+ an = (i*ANG45)>>ANGLETOFINESHIFT;
+ // an90 = (i*ANG45 + ANG90)>>ANGLETOFINESHIFT;
+ mo = P_SpawnMobj(linetarget->x + FixedMul(dist, finecosine[an]),
+ linetarget->y + FixedMul(dist, finesine[an]),
+ linetarget->z + 5*FRACUNIT, MT_CIRCLEFLAME);
+ if (mo)
+ {
+ mo->angle = an<<ANGLETOFINESHIFT;
+ mo->target = pmo;
+ mo->momx = mo->special1 = FixedMul(FLAMESPEED, finecosine[an]);
+ mo->momy = mo->special2 = FixedMul(FLAMESPEED, finesine[an]);
+ mo->tics -= P_Random() & 3;
+ }
+ mo = P_SpawnMobj(linetarget->x - FixedMul(dist, finecosine[an]),
+ linetarget->y - FixedMul(dist, finesine[an]),
+ linetarget->z + 5*FRACUNIT, MT_CIRCLEFLAME);
+ if (mo)
+ {
+ mo->angle = ANG180 + (an<<ANGLETOFINESHIFT);
+ mo->target = pmo;
+ mo->momx = mo->special1 = FixedMul(-FLAMESPEED, finecosine[an]);
+ mo->momy = mo->special2 = FixedMul(-FLAMESPEED, finesine[an]);
+ mo->tics -= P_Random() & 3;
+ }
+ }
+ }
+// Create a line of flames from the player to the flame puff
+ CFlameCreateFlames(player->mo);
+
+ player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
+}
+*/
+
+//============================================================================
+//
+// A_CFlameRotate
+//
+//============================================================================
+
+#define FLAMEROTSPEED 2*FRACUNIT
+
+void A_CFlameRotate(mobj_t *actor)
+{
+ int an;
+
+ an = (actor->angle + ANG90)>>ANGLETOFINESHIFT;
+ actor->momx = actor->special1 + FixedMul(FLAMEROTSPEED, finecosine[an]);
+ actor->momy = actor->special2 + FixedMul(FLAMEROTSPEED, finesine[an]);
+ actor->angle += ANG90/15;
+}
+
+
+//============================================================================
+//
+// A_CHolyAttack3
+//
+// Spawns the spirits
+//============================================================================
+
+void A_CHolyAttack3(mobj_t *actor)
+{
+ P_SpawnMissile(actor, actor->target, MT_HOLY_MISSILE);
+ S_StartSound(actor, SFX_CHOLY_FIRE);
+}
+
+
+//============================================================================
+//
+// A_CHolyAttack2
+//
+// Spawns the spirits
+//============================================================================
+
+void A_CHolyAttack2(mobj_t *actor)
+{
+ int j;
+ int i;
+ mobj_t *mo;
+ mobj_t *tail, *next;
+
+ for (j = 0; j < 4; j++)
+ {
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_FX);
+ if (!mo)
+ {
+ continue;
+ }
+ switch (j)
+ { // float bob index
+ case 0:
+ mo->special2 = P_Random() & 7; // upper-left
+ break;
+ case 1:
+ mo->special2 = 32 + (P_Random() & 7); // upper-right
+ break;
+ case 2:
+ mo->special2 = (32 + (P_Random() & 7)) << 16; // lower-left
+ break;
+ case 3:
+ mo->special2 = ((32 + (P_Random() & 7)) << 16) + 32 + (P_Random() & 7);
+ break;
+ }
+ mo->z = actor->z;
+ mo->angle = actor->angle + (ANGLE_45 + ANGLE_45/2) - ANGLE_45*j;
+ P_ThrustMobj(mo, mo->angle, mo->info->speed);
+ mo->target = actor->target;
+ mo->args[0] = 10; // initial turn value
+ mo->args[1] = 0; // initial look angle
+ if (deathmatch)
+ { // Ghosts last slightly less longer in DeathMatch
+ mo->health = 85;
+ }
+ if (linetarget)
+ {
+ mo->special1 = (intptr_t)linetarget;
+ mo->flags |= MF_NOCLIP|MF_SKULLFLY;
+ mo->flags &= ~MF_MISSILE;
+ }
+ tail = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
+ tail->special2 = (intptr_t)mo; // parent
+ for (i = 1; i < 3; i++)
+ {
+ next = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
+ P_SetMobjState(next, next->info->spawnstate + 1);
+ tail->special1 = (intptr_t)next;
+ tail = next;
+ }
+ tail->special1 = 0; // last tail bit
+ }
+}
+
+//============================================================================
+//
+// A_CHolyAttack
+//
+//============================================================================
+
+void A_CHolyAttack(player_t *player, pspdef_t *psp)
+{
+ player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ P_SpawnPlayerMissile(player->mo, MT_HOLY_MISSILE);
+ if (player == &players[consoleplayer])
+ {
+ player->damagecount = 0;
+ player->bonuscount = 0;
+ V_SetPaletteShift(STARTHOLYPAL);
+ }
+ S_StartSound(player->mo, SFX_CHOLY_FIRE);
+}
+
+//============================================================================
+//
+// A_CHolyPalette
+//
+//============================================================================
+
+void A_CHolyPalette(player_t *player, pspdef_t *psp)
+{
+ int pal;
+
+ if (player == &players[consoleplayer])
+ {
+ pal = STARTHOLYPAL+psp->state - (&states[S_CHOLYATK_6]);
+ if (pal == STARTHOLYPAL + 3)
+ { // reset back to original playpal
+ pal = 0;
+ }
+ V_SetPaletteShift(pal);
+ }
+}
+
+//============================================================================
+//
+// CHolyFindTarget
+//
+//============================================================================
+
+static void CHolyFindTarget(mobj_t *actor)
+{
+ mobj_t *target;
+
+ if ((target = P_RoughMonsterSearch(actor, 6)))
+ {
+ actor->special1 = (intptr_t)target;
+ actor->flags |= MF_NOCLIP|MF_SKULLFLY;
+ actor->flags &= ~MF_MISSILE;
+ }
+}
+
+//============================================================================
+//
+// CHolySeekerMissile
+//
+// Similar to P_SeekerMissile, but seeks to a random Z on the target
+//============================================================================
+
+static void CHolySeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax)
+{
+ int dir;
+ int dist;
+ angle_t delta;
+ angle_t angle;
+ mobj_t *target;
+ fixed_t newZ;
+ fixed_t deltaZ;
+
+ target = (mobj_t *)actor->special1;
+ if (target == NULL)
+ {
+ return;
+ }
+ if (!(target->flags & MF_SHOOTABLE) ||
+ (!(target->flags & MF_COUNTKILL) && !target->player))
+ { // Target died/target isn't a player or creature
+ actor->special1 = 0;
+ actor->flags &= ~(MF_NOCLIP|MF_SKULLFLY);
+ actor->flags |= MF_MISSILE;
+ CHolyFindTarget(actor);
+ return;
+ }
+ dir = P_FaceMobj(actor, target, &delta);
+ if (delta > thresh)
+ {
+ delta >>= 1;
+ if (delta > turnMax)
+ {
+ delta = turnMax;
+ }
+ }
+ if (dir)
+ { // Turn clockwise
+ actor->angle += delta;
+ }
+ else
+ { // Turn counter clockwise
+ actor->angle -= delta;
+ }
+ angle = actor->angle>>ANGLETOFINESHIFT;
+ actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
+ actor->momy = FixedMul(actor->info->speed, finesine[angle]);
+ if (!(leveltime & 15)
+ || actor->z > target->z + (target->height)
+ || actor->z + actor->height < target->z)
+ {
+ newZ = target->z + ((P_Random()*target->height)>>8);
+ deltaZ = newZ - actor->z;
+ if (abs(deltaZ) > 15*FRACUNIT)
+ {
+ if (deltaZ > 0)
+ {
+ deltaZ = 15*FRACUNIT;
+ }
+ else
+ {
+ deltaZ = -15*FRACUNIT;
+ }
+ }
+ dist = P_AproxDistance(target->x - actor->x, target->y - actor->y);
+ dist = dist / actor->info->speed;
+ if (dist < 1)
+ {
+ dist = 1;
+ }
+ actor->momz = deltaZ / dist;
+ }
+ return;
+}
+
+//============================================================================
+//
+// A_CHolyWeave
+//
+//============================================================================
+
+static void CHolyWeave(mobj_t *actor)
+{
+ fixed_t newX, newY;
+ int weaveXY, weaveZ;
+ int angle;
+
+ weaveXY = actor->special2 >> 16;
+ weaveZ = actor->special2 & 0xFFFF;
+ angle = (actor->angle + ANG90)>>ANGLETOFINESHIFT;
+ newX = actor->x-FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<2);
+ newY = actor->y-FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<2);
+ weaveXY = (weaveXY + (P_Random() % 5)) & 63;
+ newX += FixedMul(finecosine[angle], FloatBobOffsets[weaveXY]<<2);
+ newY += FixedMul(finesine[angle], FloatBobOffsets[weaveXY]<<2);
+ P_TryMove(actor, newX, newY);
+ actor->z -= FloatBobOffsets[weaveZ]<<1;
+ weaveZ = (weaveZ + (P_Random() % 5)) & 63;
+ actor->z += FloatBobOffsets[weaveZ]<<1;
+ actor->special2 = weaveZ + (weaveXY<<16);
+}
+
+//============================================================================
+//
+// A_CHolySeek
+//
+//============================================================================
+
+void A_CHolySeek(mobj_t *actor)
+{
+ actor->health--;
+ if (actor->health <= 0)
+ {
+ actor->momx >>= 2;
+ actor->momy >>= 2;
+ actor->momz = 0;
+ P_SetMobjState(actor, actor->info->deathstate);
+ actor->tics -= P_Random() & 3;
+ return;
+ }
+ if (actor->special1)
+ {
+ CHolySeekerMissile(actor, actor->args[0]*ANGLE_1,
+ actor->args[0]*ANGLE_1*2);
+ if (!((leveltime + 7) & 15))
+ {
+ actor->args[0] = 5 + (P_Random()/20);
+ }
+ }
+ CHolyWeave(actor);
+}
+
+//============================================================================
+//
+// CHolyTailFollow
+//
+//============================================================================
+
+static void CHolyTailFollow(mobj_t *actor, fixed_t dist)
+{
+ mobj_t *child;
+ int an;
+ fixed_t oldDistance, newDistance;
+
+ child = (mobj_t *)actor->special1;
+ if (child)
+ {
+ an = R_PointToAngle2(actor->x, actor->y, child->x, child->y)>>ANGLETOFINESHIFT;
+ oldDistance = P_AproxDistance(child->x - actor->x, child->y - actor->y);
+ if (P_TryMove(child,
+ actor->x + FixedMul(dist, finecosine[an]),
+ actor->y + FixedMul(dist, finesine[an])))
+ {
+ newDistance = P_AproxDistance(child->x-actor->x, child->y-actor->y) - FRACUNIT;
+ if (oldDistance < FRACUNIT)
+ {
+ if (child->z < actor->z)
+ {
+ child->z = actor->z - dist;
+ }
+ else
+ {
+ child->z = actor->z + dist;
+ }
+ }
+ else
+ {
+ child->z =
+ actor->z +
+ FixedMul(FixedDiv(newDistance, oldDistance), child->z - actor->z);
+ }
+ }
+ CHolyTailFollow(child, dist - FRACUNIT);
+ }
+}
+
+//============================================================================
+//
+// CHolyTailRemove
+//
+//============================================================================
+
+static void CHolyTailRemove(mobj_t *actor)
+{
+ mobj_t *child;
+
+ child = (mobj_t *)actor->special1;
+ if (child)
+ {
+ CHolyTailRemove(child);
+ }
+ P_RemoveMobj(actor);
+}
+
+//============================================================================
+//
+// A_CHolyTail
+//
+//============================================================================
+
+void A_CHolyTail(mobj_t *actor)
+{
+ mobj_t *parent;
+
+ parent = (mobj_t *)actor->special2;
+
+ if (parent)
+ {
+ if (parent->state >= &states[parent->info->deathstate])
+ { // Ghost removed, so remove all tail parts
+ CHolyTailRemove(actor);
+ return;
+ }
+ else if (P_TryMove(actor,
+ parent->x - FixedMul(14*FRACUNIT,
+ finecosine[parent->angle>>ANGLETOFINESHIFT]),
+ parent->y - FixedMul(14*FRACUNIT,
+ finesine[parent->angle>>ANGLETOFINESHIFT])))
+ {
+ actor->z = parent->z-5*FRACUNIT;
+ }
+ CHolyTailFollow(actor, 10*FRACUNIT);
+ }
+}
+//============================================================================
+//
+// A_CHolyCheckScream
+//
+//============================================================================
+
+void A_CHolyCheckScream(mobj_t *actor)
+{
+ A_CHolySeek(actor);
+ if (P_Random() < 20)
+ {
+ S_StartSound(actor, SFX_SPIRIT_ACTIVE);
+ }
+ if (!actor->special1)
+ {
+ CHolyFindTarget(actor);
+ }
+}
+
+//============================================================================
+//
+// A_CHolySpawnPuff
+//
+//============================================================================
+
+void A_CHolySpawnPuff(mobj_t *actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_MISSILE_PUFF);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireConePL1
+//
+//----------------------------------------------------------------------------
+
+#define SHARDSPAWN_LEFT 1
+#define SHARDSPAWN_RIGHT 2
+#define SHARDSPAWN_UP 4
+#define SHARDSPAWN_DOWN 8
+
+void A_FireConePL1(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+ int i;
+ mobj_t *pmo, *mo;
+ int conedone = false;
+
+ pmo = player->mo;
+ player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ S_StartSound(pmo, SFX_MAGE_SHARDS_FIRE);
+
+ damage = 90 + (P_Random() & 15);
+ for (i = 0; i < 16; i++)
+ {
+ angle = pmo->angle + i*(ANG45/16);
+ slope = P_AimLineAttack(pmo, angle, MELEERANGE);
+ (void) slope; /* variable set but not used */
+ if (linetarget)
+ {
+ pmo->flags2 |= MF2_ICEDAMAGE;
+ P_DamageMobj(linetarget, pmo, pmo, damage);
+ pmo->flags2 &= ~MF2_ICEDAMAGE;
+ conedone = true;
+ break;
+ }
+ }
+
+ // didn't find any creatures, so fire projectiles
+ if (!conedone)
+ {
+ mo = P_SpawnPlayerMissile(pmo, MT_SHARDFX1);
+ if (mo)
+ {
+ mo->special1 = SHARDSPAWN_LEFT|SHARDSPAWN_DOWN|SHARDSPAWN_UP
+ |SHARDSPAWN_RIGHT;
+ mo->special2 = 3; // Set sperm count (levels of reproductivity)
+ mo->target = pmo;
+ mo->args[0] = 3; // Mark Initial shard as super damage
+ }
+ }
+}
+
+void A_ShedShard(mobj_t *actor)
+{
+ mobj_t *mo;
+ int spawndir = actor->special1;
+ int spermcount = actor->special2;
+
+ if (spermcount <= 0)
+ return; // No sperm left
+ actor->special2 = 0;
+ spermcount--;
+
+ // every so many calls, spawn a new missile in it's set directions
+ if (spawndir & SHARDSPAWN_LEFT)
+ {
+ mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle + (ANG45/9),
+ 0, (20 + 2*spermcount)<<FRACBITS);
+ if (mo)
+ {
+ mo->special1 = SHARDSPAWN_LEFT;
+ mo->special2 = spermcount;
+ mo->momz = actor->momz;
+ mo->target = actor->target;
+ mo->args[0] = (spermcount == 3) ? 2 : 0;
+ }
+ }
+ if (spawndir & SHARDSPAWN_RIGHT)
+ {
+ mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle - (ANG45/9),
+ 0, (20 + 2*spermcount)<<FRACBITS);
+ if (mo)
+ {
+ mo->special1 = SHARDSPAWN_RIGHT;
+ mo->special2 = spermcount;
+ mo->momz = actor->momz;
+ mo->target = actor->target;
+ mo->args[0] = (spermcount == 3) ? 2 : 0;
+ }
+ }
+ if (spawndir & SHARDSPAWN_UP)
+ {
+ mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle,
+ 0, (15 + 2*spermcount)<<FRACBITS);
+ if (mo)
+ {
+ mo->momz = actor->momz;
+ mo->z += 8*FRACUNIT;
+ if (spermcount & 1) // Every other reproduction
+ mo->special1 = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
+ else
+ mo->special1 = SHARDSPAWN_UP;
+ mo->special2 = spermcount;
+ mo->target = actor->target;
+ mo->args[0] = (spermcount == 3) ? 2 : 0;
+ }
+ }
+ if (spawndir & SHARDSPAWN_DOWN)
+ {
+ mo = P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle,
+ 0, (15 + 2*spermcount)<<FRACBITS);
+ if (mo)
+ {
+ mo->momz = actor->momz;
+ mo->z -= 4*FRACUNIT;
+ if (spermcount & 1) // Every other reproduction
+ mo->special1 = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
+ else
+ mo->special1 = SHARDSPAWN_DOWN;
+ mo->special2 = spermcount;
+ mo->target = actor->target;
+ mo->args[0] = (spermcount == 3) ? 2 : 0;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_HideInCeiling
+//
+//----------------------------------------------------------------------------
+
+/*
+void A_HideInCeiling(mobj_t *actor)
+{
+ actor->z = actor->ceilingz + 4*FRACUNIT;
+}
+*/
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FloatPuff
+//
+//----------------------------------------------------------------------------
+
+/*
+void A_FloatPuff(mobj_t *puff)
+{
+ puff->momz += 1.8*FRACUNIT;
+}
+*/
+
+void A_Light0(player_t *player, pspdef_t *psp)
+{
+ player->extralight = 0;
+}
+
+/*
+void A_Light1(player_t *player, pspdef_t *psp)
+{
+ player->extralight = 1;
+}
+*/
+
+/*
+void A_Light2(player_t *player, pspdef_t *psp)
+{
+ player->extralight = 2;
+}
+*/
+
+//------------------------------------------------------------------------
+//
+// PROC P_SetupPsprites
+//
+// Called at start of level for each player
+//
+//------------------------------------------------------------------------
+
+void P_SetupPsprites(player_t *player)
+{
+ int i;
+
+ // Remove all psprites
+ for (i = 0; i < NUMPSPRITES; i++)
+ {
+ player->psprites[i].state = NULL;
+ }
+ // Spawn the ready weapon
+ player->pendingweapon = player->readyweapon;
+ P_BringUpWeapon(player);
+}
+
+//------------------------------------------------------------------------
+//
+// PROC P_MovePsprites
+//
+// Called every tic by player thinking routine
+//
+//------------------------------------------------------------------------
+
+void P_MovePsprites(player_t *player)
+{
+ int i;
+ pspdef_t *psp;
+ state_t *state;
+
+ psp = &player->psprites[0];
+ for (i = 0; i < NUMPSPRITES; i++, psp++)
+ {
+ if ((state = psp->state) != 0) // a null state means not active
+ {
+ // drop tic count and possibly change state
+ if (psp->tics != -1) // a -1 tic count never changes
+ {
+ psp->tics--;
+ if (!psp->tics)
+ {
+ P_SetPsprite(player, i, psp->state->nextstate);
+ }
+ }
+ }
+ }
+ player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
+ player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
+}
+
+
+//============================================================================
+//
+// ASSASSIN WEAPONS / ATTACKS (ADD-ON CLASS FROM HEXEN II)
+//
+//============================================================================
+
+#if defined(ASSASSIN)
+
+//============================================================================
+//
+// A_AKnifeAttack
+//
+// Jim Cameron did most of this one
+//============================================================================
+
+void A_AKnifeAttack(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+ mobj_t *pmo = player->mo;
+ fixed_t power;
+ int i;
+ boolean oof = false;
+
+ /* jim - the Katar should be a bit feebler */
+ damage = 20 + (P_Random() & 15);
+ power = 2*FRACUNIT;
+ PuffType = MT_PUNCHPUFF;
+
+ for (i = 0; i < 16; i++)
+ {
+ angle = pmo->angle + i*(ANG45/16);
+ slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
+ if (linetarget)
+ {
+ player->mo->special1++;
+ /*
+ * jim - this is the Mighty Blow for the fighter and is
+ * not useful here
+ */
+#if 0
+ if (pmo->special1 == 3)
+ {
+ damage <<= 1;
+ power = 6*FRACUNIT;
+ PuffType = MT_HAMMERPUFF;
+ }
+#endif
+ /*
+ * jim - instead of that we make the Katar deal more
+ * damage to a monster if struck from behind. Assume
+ * so if the angle of striking is within 45 degrees
+ * of the angle the target is facing in
+ * OOOPS! but only if it IS a monster! Striking trees from
+ * behind might be amusing but doesn't do much for realism 8-)
+ */
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ if ((angle - linetarget->angle < ANG45) ||
+ (linetarget->angle - angle < ANG45))
+ {
+ damage *= 15;
+ power = 6 * FRACUNIT;
+ PuffType = MT_HAMMERPUFF;
+ oof = true;
+ }
+ }
+ P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ AdjustPlayerAngle(pmo);
+ goto knifedone;
+ }
+
+ angle = pmo->angle - i*(ANG45/16);
+ slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
+ if (linetarget)
+ {
+ player->mo->special1++;
+ /*
+ * jim - this is the Mighty Blow for the fighter and is
+ * not useful here
+ */
+#if 0
+ if (pmo->special1 == 3)
+ {
+ damage <<= 1;
+ power = 6*FRACUNIT;
+ PuffType = MT_HAMMERPUFF;
+ }
+#endif
+ /*
+ * jim - instead of that we make the Katar deal more
+ * damage to a monster if struck from behind. Assume
+ * so if the angle of striking is within 45 degrees
+ * of the angle the target is facing in
+ * OOOPS! but only if it IS a monster! Striking trees from
+ * behind might be amusing but doesn't do much for realism 8-)
+ */
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ if ((angle - linetarget->angle < ANG45) ||
+ (linetarget->angle - angle < ANG45))
+ {
+ damage *= 15;
+ power = 6 * FRACUNIT;
+ PuffType = MT_HAMMERPUFF;
+ oof = true;
+ }
+ }
+
+ P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
+ if (linetarget->flags & MF_COUNTKILL || linetarget->player)
+ {
+ P_ThrustMobj(linetarget, angle, power);
+ }
+ AdjustPlayerAngle(pmo);
+ goto knifedone;
+ }
+ }
+
+ /* didn't find any creatures, so try to strike any walls*/
+ pmo->special1 = 0;
+
+ angle = pmo->angle;
+ slope = P_AimLineAttack(pmo, angle, MELEERANGE);
+ P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
+
+knifedone:
+ if (oof)
+ {
+ pmo->special1 = 0;
+ P_SetPsprite(player, ps_weapon, S_KATARATK2_1);
+ /* jim - come on, she's a girl! */
+ S_StartSound(pmo, SFX_PLAYER_MAGE_GRUNT);
+ }
+}
+
+
+void A_ACrossAttack(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+ mobj_t *pmo = player->mo;
+
+ player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+// pmo = player->mo;
+// P_SpawnPlayerMissile(pmo, MT_CSTAFF_MISSILE);
+
+ /*
+ * jim - special2 is used to control the serpent staff projectiles'
+ * `slither' and is not used here
+ * We do however want to give crossbow missiles BlasterMobjThinker()s
+ * instead of the ordinary ones because they are FAST.
+ */
+ mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle);
+ if (mo)
+ {
+ /* mo->special2 = 16; */
+ mo->thinker.function = P_BlasterMobjThinker;
+ }
+ mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle - (ANG45/10));
+ if (mo)
+ {
+ /* mo->special2 = 32; */
+ mo->thinker.function = P_BlasterMobjThinker;
+ }
+ mo = P_SPMAngle(pmo, MT_ACROSS_MISSILE, pmo->angle + (ANG45/10));
+ if (mo)
+ {
+ /* mo->special2 = 0; */
+ mo->thinker.function = P_BlasterMobjThinker;
+ }
+ S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
+}
+
+
+void A_AGrenAttack(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnMobj(player->mo->x, player->mo->y,
+ player->mo->z - player->mo->floorclip + 35*FRACUNIT,
+ MT_THROWINGBOMB);
+ if (mo)
+ {
+ mo->angle = player->mo->angle + (((P_Random() & 7) - 4)<<24);
+ mo->momz = 4*FRACUNIT + ((player->lookdir)<<(FRACBITS - 4));
+ mo->z += player->lookdir<<(FRACBITS - 4);
+ P_ThrustMobj(mo, mo->angle, mo->info->speed);
+ mo->momx += player->mo->momx>>1;
+ mo->momy += player->mo->momy>>1;
+ mo->target = player->mo;
+ mo->tics -= P_Random() & 3;
+ P_CheckMissileSpawn(mo);
+ }
+}
+
+void A_AStaffAttack(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ mobj_t *pmo;
+
+/* THIS ISN'T FINISHED YET!! */
+
+ player->mana[MANA_1] -= WeaponManaUse[player->playerclass][player->readyweapon];
+ player->mana[MANA_2] -= WeaponManaUse[player->playerclass][player->readyweapon];
+
+ pmo = player->mo;
+ angle = pmo->angle;
+
+}
+#endif /* ASSASSIN */
+
--- /dev/null
+++ b/p_setup.c
@@ -1,0 +1,1578 @@
+
+//**************************************************************************
+//**
+//** p_setup.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 590 $
+//** $Date: 2012-10-23 23:55:31 +0300 (Tue, 23 Oct 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "i_cdmus.h"
+#include "soundst.h"
+#ifdef RENDER3D
+#include "ogl_def.h"
+#endif
+
+
+// MACROS ------------------------------------------------------------------
+
+#define MAPINFO_SCRIPT_NAME "MAPINFO"
+#define MCMD_SKY1 1
+#define MCMD_SKY2 2
+#define MCMD_LIGHTNING 3
+#define MCMD_FADETABLE 4
+#define MCMD_DOUBLESKY 5
+#define MCMD_CLUSTER 6
+#define MCMD_WARPTRANS 7
+#define MCMD_NEXT 8
+#define MCMD_CDTRACK 9
+#define MCMD_CD_STARTTRACK 10
+#define MCMD_CD_END1TRACK 11
+#define MCMD_CD_END2TRACK 12
+#define MCMD_CD_END3TRACK 13
+#define MCMD_CD_INTERTRACK 14
+#define MCMD_CD_TITLETRACK 15
+
+#define UNKNOWN_MAP_NAME "DEVELOPMENT MAP"
+#define DEFAULT_SKY_NAME "SKY1"
+#define DEFAULT_SKY_DEMO "SKY2"
+#define DEFAULT_SONG_LUMP "DEFSONG"
+#define DEFAULT_FADE_TABLE "COLORMAP"
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct mapInfo_s mapInfo_t;
+struct mapInfo_s
+{
+ short cluster;
+ short warpTrans;
+ short nextMap;
+ short cdTrack;
+ char name[32];
+ short sky1Texture;
+ short sky2Texture;
+ fixed_t sky1ScrollDelta;
+ fixed_t sky2ScrollDelta;
+ boolean doubleSky;
+ boolean lightning;
+ int fadetable;
+ char songLump[10];
+};
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void P_SpawnMapThing(mapthing_t *mthing);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static int QualifyMap(int map);
+#ifdef RENDER3D
+static float P_AccurateDistance(fixed_t dx, fixed_t dy);
+#endif
+
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int MapCount;
+mapthing_t deathmatchstarts[MAXDEATHMATCHSTARTS], *deathmatch_p;
+mapthing_t playerstarts[MAX_PLAYER_STARTS][MAXPLAYERS];
+
+int numvertexes;
+vertex_t *vertexes;
+
+int numsegs;
+seg_t *segs;
+
+int numsectors;
+sector_t *sectors;
+
+int numsubsectors;
+subsector_t *subsectors;
+
+int numnodes;
+node_t *nodes;
+
+int numlines;
+line_t *lines;
+
+int numsides;
+side_t *sides;
+
+short *blockmaplump; // offsets in blockmap are from here
+short *blockmap;
+int bmapwidth, bmapheight; // in mapblocks
+fixed_t bmaporgx, bmaporgy; // origin of block map
+mobj_t **blocklinks; // for thing chains
+byte *rejectmatrix; // for fast sight rejection
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static mapInfo_t MapInfo[99];
+static const char *MapCmdNames[] =
+{
+ "SKY1",
+ "SKY2",
+ "DOUBLESKY",
+ "LIGHTNING",
+ "FADETABLE",
+ "CLUSTER",
+ "WARPTRANS",
+ "NEXT",
+ "CDTRACK",
+ "CD_START_TRACK",
+ "CD_END1_TRACK",
+ "CD_END2_TRACK",
+ "CD_END3_TRACK",
+ "CD_INTERMISSION_TRACK",
+ "CD_TITLE_TRACK",
+ NULL
+};
+
+static int MapCmdIDs[] =
+{
+ MCMD_SKY1,
+ MCMD_SKY2,
+ MCMD_DOUBLESKY,
+ MCMD_LIGHTNING,
+ MCMD_FADETABLE,
+ MCMD_CLUSTER,
+ MCMD_WARPTRANS,
+ MCMD_NEXT,
+ MCMD_CDTRACK,
+ MCMD_CD_STARTTRACK,
+ MCMD_CD_END1TRACK,
+ MCMD_CD_END2TRACK,
+ MCMD_CD_END3TRACK,
+ MCMD_CD_INTERTRACK,
+ MCMD_CD_TITLETRACK
+};
+
+static int cd_NonLevelTracks[6]; // Non-level specific song cd track numbers
+
+
+// CODE --------------------------------------------------------------------
+
+
+/*
+=================
+=
+= P_LoadVertexes
+=
+=================
+*/
+
+static void P_LoadVertexes (int lump)
+{
+ void *data;
+ int i;
+ mapvertex_t *ml;
+ vertex_t *li;
+
+ numvertexes = W_LumpLength (lump) / sizeof(mapvertex_t);
+ vertexes = (vertex_t *) Z_Malloc (numvertexes*sizeof(vertex_t), PU_LEVEL, NULL);
+ data = W_CacheLumpNum (lump, PU_STATIC);
+
+ ml = (mapvertex_t *)data;
+ li = vertexes;
+ for (i = 0; i < numvertexes; i++, li++, ml++)
+ {
+ li->x = SHORT(ml->x)<<FRACBITS;
+ li->y = SHORT(ml->y)<<FRACBITS;
+ }
+
+ Z_Free (data);
+}
+
+
+/*
+=================
+=
+= P_LoadSegs
+=
+=================
+*/
+
+static void P_LoadSegs (int lump)
+{
+ void *data;
+ int i;
+ mapseg_t *ml;
+ seg_t *li;
+ line_t *ldef;
+ int _linedef, side;
+
+ numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
+ segs = (seg_t *) Z_Malloc (numsegs*sizeof(seg_t), PU_LEVEL, NULL);
+ memset (segs, 0, numsegs*sizeof(seg_t));
+ data = W_CacheLumpNum (lump, PU_STATIC);
+
+ ml = (mapseg_t *)data;
+ li = segs;
+ for (i = 0; i < numsegs; i++, li++, ml++)
+ {
+ li->v1 = &vertexes[SHORT(ml->v1)];
+ li->v2 = &vertexes[SHORT(ml->v2)];
+
+ li->angle = (SHORT(ml->angle))<<16;
+ li->offset = (SHORT(ml->offset))<<16;
+ _linedef = SHORT(ml->linedef);
+ ldef = &lines[_linedef];
+ li->linedef = ldef;
+ side = SHORT(ml->side);
+ li->sidedef = &sides[ldef->sidenum[side]];
+ li->frontsector = sides[ldef->sidenum[side]].sector;
+ if (ldef-> flags & ML_TWOSIDED)
+ li->backsector = sides[ldef->sidenum[side^1]].sector;
+ else
+ li->backsector = 0;
+
+#ifdef RENDER3D
+ // Calculate the length of the segment. We need this for
+ // the texture coordinates. -jk
+ li->len = P_AccurateDistance(li->v2->x - li->v1->x, li->v2->y - li->v1->y);
+#endif
+ }
+
+ Z_Free (data);
+}
+
+
+/*
+=================
+=
+= P_LoadSubsectors
+=
+=================
+*/
+
+static void P_LoadSubsectors (int lump)
+{
+ void *data;
+ int i;
+ mapsubsector_t *ms;
+ subsector_t *ss;
+
+ numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t);
+ subsectors = (subsector_t *) Z_Malloc (numsubsectors*sizeof(subsector_t), PU_LEVEL, NULL);
+ data = W_CacheLumpNum (lump, PU_STATIC);
+
+ ms = (mapsubsector_t *)data;
+ memset (subsectors, 0, numsubsectors*sizeof(subsector_t));
+ ss = subsectors;
+ for (i = 0; i < numsubsectors; i++, ss++, ms++)
+ {
+ ss->numlines = SHORT(ms->numsegs);
+ ss->firstline = SHORT(ms->firstseg);
+ }
+
+ Z_Free (data);
+}
+
+
+/*
+=================
+=
+= P_LoadSectors
+=
+=================
+*/
+
+static void P_LoadSectors (int lump)
+{
+ void *data;
+ int i;
+ mapsector_t *ms;
+ sector_t *ss;
+
+ numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
+ sectors = (sector_t *) Z_Malloc (numsectors*sizeof(sector_t), PU_LEVEL, NULL);
+ memset (sectors, 0, numsectors*sizeof(sector_t));
+ data = W_CacheLumpNum (lump, PU_STATIC);
+
+ ms = (mapsector_t *)data;
+ ss = sectors;
+
+ // Make sure primary lumps are used for flat searching
+ W_UsePrimary();
+
+ for (i = 0; i < numsectors; i++, ss++, ms++)
+ {
+ ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
+ ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
+ ss->floorpic = R_FlatNumForName(ms->floorpic);
+ ss->ceilingpic = R_FlatNumForName(ms->ceilingpic);
+ ss->lightlevel = SHORT(ms->lightlevel);
+ ss->special = SHORT(ms->special);
+ ss->tag = SHORT(ms->tag);
+ ss->thinglist = NULL;
+ ss->seqType = SEQTYPE_STONE; // default seqType
+
+#ifdef RENDER3D
+ ss->flatoffx = ss->flatoffy = 0;// Flat scrolling.
+ ss->skyfix = 0; // Set if needed.
+#endif
+ }
+ if (DevMaps)
+ {
+ W_UseAuxiliary();
+ }
+ Z_Free(data);
+}
+
+
+/*
+=================
+=
+= P_LoadNodes
+=
+=================
+*/
+
+static void P_LoadNodes (int lump)
+{
+ void *data;
+ int i, j, k;
+ mapnode_t *mn;
+ node_t *no;
+
+ numnodes = W_LumpLength (lump) / sizeof(mapnode_t);
+ nodes = (node_t *) Z_Malloc (numnodes*sizeof(node_t), PU_LEVEL, NULL);
+ data = W_CacheLumpNum (lump, PU_STATIC);
+
+ mn = (mapnode_t *)data;
+ no = nodes;
+ for (i = 0; i < numnodes; i++, no++, mn++)
+ {
+ no->x = SHORT(mn->x)<<FRACBITS;
+ no->y = SHORT(mn->y)<<FRACBITS;
+ no->dx = SHORT(mn->dx)<<FRACBITS;
+ no->dy = SHORT(mn->dy)<<FRACBITS;
+ for (j = 0; j < 2; j++)
+ {
+ no->children[j] = SHORT(mn->children[j]);
+ for (k = 0; k < 4; k++)
+ no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
+ }
+ }
+ Z_Free (data);
+}
+
+//==========================================================================
+//
+// P_LoadThings
+//
+//==========================================================================
+
+static void P_LoadThings(int lump)
+{
+ void *data;
+ int i;
+ mapthing_t *mt;
+ int numthings;
+ int playerCount;
+ int deathSpotsCount;
+
+ data = W_CacheLumpNum(lump, PU_STATIC);
+ numthings = W_LumpLength(lump) / sizeof(mapthing_t);
+
+ mt = (mapthing_t *)data;
+ for (i = 0; i < numthings; i++, mt++)
+ {
+ mt->tid = SHORT(mt->tid);
+ mt->x = SHORT(mt->x);
+ mt->y = SHORT(mt->y);
+ mt->height = SHORT(mt->height);
+ mt->angle = SHORT(mt->angle);
+ mt->type = SHORT(mt->type);
+ mt->options = SHORT(mt->options);
+ P_SpawnMapThing(mt);
+ }
+ P_CreateTIDList();
+ P_InitCreatureCorpseQueue(false); // false = do NOT scan for corpses
+ Z_Free(data);
+
+ if (!deathmatch)
+ {
+ return; // Don't need to check deathmatch spots
+ }
+ playerCount = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ playerCount += playeringame[i];
+ }
+ deathSpotsCount = deathmatch_p - deathmatchstarts;
+ if (deathSpotsCount < playerCount)
+ {
+ I_Error("P_LoadThings: Player count (%d) exceeds deathmatch "
+ "spots (%d)", playerCount, deathSpotsCount);
+ }
+}
+
+/*
+=================
+=
+= P_LoadLineDefs
+=
+=================
+*/
+
+static void P_LoadLineDefs(int lump)
+{
+ void *data;
+ int i;
+ maplinedef_t *mld;
+ line_t *ld;
+ vertex_t *v1, *v2;
+
+ numlines = W_LumpLength(lump) / sizeof(maplinedef_t);
+ lines = (line_t *) Z_Malloc(numlines*sizeof(line_t), PU_LEVEL, NULL);
+ memset(lines, 0, numlines*sizeof(line_t));
+ data = W_CacheLumpNum(lump, PU_STATIC);
+
+ mld = (maplinedef_t *)data;
+ ld = lines;
+ for (i = 0; i < numlines; i++, mld++, ld++)
+ {
+ ld->flags = SHORT(mld->flags);
+
+ // Old line special info ...
+ //ld->special = SHORT(mld->special);
+ //ld->tag = SHORT(mld->tag);
+
+ // New line special info ...
+ ld->special = mld->special;
+ ld->arg1 = mld->arg1;
+ ld->arg2 = mld->arg2;
+ ld->arg3 = mld->arg3;
+ ld->arg4 = mld->arg4;
+ ld->arg5 = mld->arg5;
+
+ v1 = ld->v1 = &vertexes[SHORT(mld->v1)];
+ v2 = ld->v2 = &vertexes[SHORT(mld->v2)];
+ ld->dx = v2->x - v1->x;
+ ld->dy = v2->y - v1->y;
+ if (!ld->dx)
+ ld->slopetype = ST_VERTICAL;
+ else if (!ld->dy)
+ ld->slopetype = ST_HORIZONTAL;
+ else
+ {
+ if (FixedDiv (ld->dy , ld->dx) > 0)
+ ld->slopetype = ST_POSITIVE;
+ else
+ ld->slopetype = ST_NEGATIVE;
+ }
+
+ if (v1->x < v2->x)
+ {
+ ld->bbox[BOXLEFT] = v1->x;
+ ld->bbox[BOXRIGHT] = v2->x;
+ }
+ else
+ {
+ ld->bbox[BOXLEFT] = v2->x;
+ ld->bbox[BOXRIGHT] = v1->x;
+ }
+ if (v1->y < v2->y)
+ {
+ ld->bbox[BOXBOTTOM] = v1->y;
+ ld->bbox[BOXTOP] = v2->y;
+ }
+ else
+ {
+ ld->bbox[BOXBOTTOM] = v2->y;
+ ld->bbox[BOXTOP] = v1->y;
+ }
+ ld->sidenum[0] = SHORT(mld->sidenum[0]);
+ ld->sidenum[1] = SHORT(mld->sidenum[1]);
+ if (ld->sidenum[0] != -1)
+ ld->frontsector = sides[ld->sidenum[0]].sector;
+ else
+ ld->frontsector = 0;
+ if (ld->sidenum[1] != -1)
+ ld->backsector = sides[ld->sidenum[1]].sector;
+ else
+ ld->backsector = 0;
+ }
+
+ Z_Free (data);
+}
+
+
+/*
+=================
+=
+= P_LoadSideDefs
+=
+=================
+*/
+
+static void P_LoadSideDefs (int lump)
+{
+ void *data;
+ int i;
+ mapsidedef_t *msd;
+ side_t *sd;
+
+ numsides = W_LumpLength (lump) / sizeof(mapsidedef_t);
+ sides = (side_t *) Z_Malloc (numsides*sizeof(side_t), PU_LEVEL, NULL);
+ memset (sides, 0, numsides*sizeof(side_t));
+ data = W_CacheLumpNum (lump, PU_STATIC);
+
+ msd = (mapsidedef_t *)data;
+ sd = sides;
+
+ // Make sure primary lumps are used for texture searching
+ W_UsePrimary();
+
+ for (i = 0; i < numsides; i++, msd++, sd++)
+ {
+ sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS;
+ sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
+ sd->toptexture = R_TextureNumForName(msd->toptexture);
+ sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
+ sd->midtexture = R_TextureNumForName(msd->midtexture);
+ sd->sector = §ors[SHORT(msd->sector)];
+ }
+ if (DevMaps)
+ {
+ W_UseAuxiliary();
+ }
+ Z_Free(data);
+}
+
+/*
+=================
+=
+= P_LoadBlockMap
+=
+=================
+*/
+
+static void P_LoadBlockMap (int lump)
+{
+ int i, count;
+
+ blockmaplump = (short *) W_CacheLumpNum (lump, PU_LEVEL);
+ blockmap = blockmaplump + 4;
+ count = W_LumpLength (lump) / 2;
+ for (i = 0; i < count; i++)
+ blockmaplump[i] = SHORT(blockmaplump[i]);
+
+ bmaporgx = blockmaplump[0]<<FRACBITS;
+ bmaporgy = blockmaplump[1]<<FRACBITS;
+ bmapwidth = blockmaplump[2];
+ bmapheight = blockmaplump[3];
+
+// clear out mobj chains
+ count = sizeof(*blocklinks) * bmapwidth * bmapheight;
+ blocklinks = (mobj_t **) Z_Malloc (count, PU_LEVEL, NULL);
+ memset (blocklinks, 0, count);
+}
+
+
+/*
+=================
+=
+= P_GroupLines
+=
+= Builds sector line lists and subsector sector numbers
+= Finds block bounding boxes for sectors
+=================
+*/
+
+static void P_GroupLines (void)
+{
+ line_t **linebuffer;
+ int i, j, total;
+ line_t *li;
+ sector_t *sector;
+ subsector_t *ss;
+ seg_t *seg;
+ fixed_t bbox[4];
+ int block;
+
+// look up sector number for each subsector
+ ss = subsectors;
+ for (i = 0; i < numsubsectors; i++, ss++)
+ {
+ seg = &segs[ss->firstline];
+ ss->sector = seg->sidedef->sector;
+ }
+
+// count number of lines in each sector
+ li = lines;
+ total = 0;
+ for (i = 0; i < numlines; i++, li++)
+ {
+ total++;
+ li->frontsector->linecount++;
+ if (li->backsector && li->backsector != li->frontsector)
+ {
+ li->backsector->linecount++;
+ total++;
+ }
+ }
+
+// build line tables for each sector
+ linebuffer = (line_t **) Z_Malloc (total * sizeof(line_t *), PU_LEVEL, NULL);
+ sector = sectors;
+ for (i = 0; i < numsectors; i++, sector++)
+ {
+ M_ClearBox (bbox);
+ sector->lines = linebuffer;
+ li = lines;
+ for (j = 0; j < numlines; j++, li++)
+ {
+ if (li->frontsector == sector || li->backsector == sector)
+ {
+ *linebuffer++ = li;
+ M_AddToBox (bbox, li->v1->x, li->v1->y);
+ M_AddToBox (bbox, li->v2->x, li->v2->y);
+ }
+ }
+ if (linebuffer - sector->lines != sector->linecount)
+ I_Error ("P_GroupLines: miscounted");
+
+ // set the degenmobj_t to the middle of the bounding box
+ sector->soundorg.x = (bbox[BOXRIGHT] + bbox[BOXLEFT]) / 2;
+ sector->soundorg.y = (bbox[BOXTOP] + bbox[BOXBOTTOM]) / 2;
+
+ // adjust bounding box to map blocks
+ block = (bbox[BOXTOP] - bmaporgy + MAXRADIUS) >> MAPBLOCKSHIFT;
+ block = block >= bmapheight ? bmapheight - 1 : block;
+ sector->blockbox[BOXTOP] = block;
+
+ block = (bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS) >> MAPBLOCKSHIFT;
+ block = block < 0 ? 0 : block;
+ sector->blockbox[BOXBOTTOM] = block;
+
+ block = (bbox[BOXRIGHT] - bmaporgx + MAXRADIUS) >> MAPBLOCKSHIFT;
+ block = block >= bmapwidth ? bmapwidth - 1 : block;
+ sector->blockbox[BOXRIGHT] = block;
+
+ block = (bbox[BOXLEFT] - bmaporgx - MAXRADIUS) >> MAPBLOCKSHIFT;
+ block = block < 0 ? 0 : block;
+ sector->blockbox[BOXLEFT] = block;
+ }
+}
+
+
+#if defined(RENDER3D)
+
+#define MAX_CC_SIDES 64
+
+static float P_AccurateDistance(fixed_t dx, fixed_t dy)
+{
+ float fx = FIX2FLT(dx), fy = FIX2FLT(dy);
+ return (float)sqrt(fx*fx + fy*fy);
+}
+
+static int __no_optimize detSideFloat(fvertex_t *pnt, fdivline_t *dline)
+{
+ /*
+ (AY-CY)(BX-AX)-(AX-CX)(BY-AY)
+ s = -----------------------------
+ L**2
+
+ If s < 0 C is left of AB (you can just check the numerator)
+ If s > 0 C is right of AB
+ If s = 0 C is on AB
+
+ We'll return false if the point c is on the left side.
+ */
+ float s = (dline->y - pnt->y) * dline->dx - (dline->x - pnt->x) * dline->dy;
+ if (s < 0)
+ return 0;
+ return 1;
+}
+
+// Lines start-end and fdiv must intersect.
+static float __no_optimize findIntersectionVertex(fvertex_t *start, fvertex_t *end,
+ fdivline_t *fdiv, fvertex_t *inter)
+{
+ float ax = start->x, ay = start->y, bx = end->x, by = end->y;
+ float cx = fdiv->x, cy = fdiv->y, dx = cx + fdiv->dx, dy = cy + fdiv->dy;
+ /*
+ (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
+ r = ----------------------------- (eqn 1)
+ (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
+ */
+ float r = ((ay - cy) * (dx-cx) - (ax-cx) * (dy-cy)) /
+ ((bx - ax) * (dy - cy) - (by - ay) * (dx-cx));
+ /*
+ XI=XA+r(XB-XA)
+ YI=YA+r(YB-YA)
+ */
+ inter->x = ax + r * (bx - ax);
+ inter->y = ay + r * (by - ay);
+ return r;
+}
+
+static void P_ConvexCarver(subsector_t *ssec, int num, divline_t *list)
+{
+ int numclippers = num + ssec->numlines;
+ fdivline_t *clippers = (fdivline_t *) malloc(numclippers*sizeof(fdivline_t));
+ int i, k, numedgepoints;
+ fvertex_t *edgepoints;
+ unsigned char sidelist[MAX_CC_SIDES];
+
+// Convert the divlines to float, in reverse order.
+ OGL_DEBUG("%d clippers (%d pls, %d segs):\n", numclippers, num, ssec->numlines);
+ for (i = 0; i < numclippers; i++)
+ {
+ if (i < num)
+ {
+ clippers[i].x = FIX2FLT(list[num - i - 1].x);
+ clippers[i].y = FIX2FLT(list[num - i - 1].y);
+ clippers[i].dx = FIX2FLT(list[num - i - 1].dx);
+ clippers[i].dy = FIX2FLT(list[num - i - 1].dy);
+ }
+ else
+ {
+ seg_t *seg = segs + (ssec->firstline + i - num);
+ clippers[i].x = FIX2FLT(seg->v1->x);
+ clippers[i].y = FIX2FLT(seg->v1->y);
+ clippers[i].dx = FIX2FLT(seg->v2->x - seg->v1->x);
+ clippers[i].dy = FIX2FLT(seg->v2->y - seg->v1->y);
+ }
+ OGL_DEBUG(" %d: x=%f y=%f dx=%f dy=%f\n",
+ i, clippers[i].x, clippers[i].y, clippers[i].dx, clippers[i].dy);
+ }
+ OGL_DEBUG("\n");
+
+// Setup the 'worldwide' polygon.
+ numedgepoints = 4;
+ edgepoints = (fvertex_t *) malloc(numedgepoints*sizeof(fvertex_t));
+
+ edgepoints[0].x = -32768;
+ edgepoints[0].y = 32768;
+
+ edgepoints[1].x = 32768;
+ edgepoints[1].y = 32768;
+
+ edgepoints[2].x = 32768;
+ edgepoints[2].y = -32768;
+
+ edgepoints[3].x = -32768;
+ edgepoints[3].y = -32768;
+
+// We'll now clip the polygon with each of the divlines. The left side of
+// each divline is discarded.
+
+ OGL_DEBUG("carving (with %d clippers):\n", numclippers);
+ for (i = 0; i < numclippers; i++)
+ {
+ fdivline_t *curclip = clippers + i;
+
+ // First we'll determine the side of each vertex.
+ // Points are allowed to be on the line.
+ for (k = 0; k < numedgepoints; k++)
+ {
+ sidelist[k] = detSideFloat(edgepoints + k, curclip);
+ OGL_DEBUG( "%d: %d, ", k, sidelist[k]);
+ }
+ OGL_DEBUG("\n");
+
+ for (k = 0; k < numedgepoints; k++)
+ {
+ int startIdx = k, endIdx = k + 1;
+
+ // Check the end index.
+ if (endIdx == numedgepoints)
+ endIdx = 0; // Wrap-around.
+
+ // Clipping will happen when the ends are on different sides.
+ if (sidelist[startIdx] != sidelist[endIdx])
+ {
+ fvertex_t newvert;
+ OGL_DEBUG(" clipping %d - %d\n", startIdx, endIdx);
+ // Find the intersection point of intersecting lines.
+ findIntersectionVertex(edgepoints + startIdx, edgepoints + endIdx, curclip, &newvert);
+
+ // Add the new vertex. Also modify the sidelist.
+ edgepoints = (fvertex_t *) realloc(edgepoints, (++numedgepoints)*sizeof(fvertex_t));
+ if (numedgepoints >= MAX_CC_SIDES)
+ I_Error("Too many points in carver.\n");
+
+ // Make room for the new vertex.
+ memmove(edgepoints + endIdx + 1, edgepoints + endIdx,
+ (numedgepoints - endIdx - 1)*sizeof(fvertex_t));
+ memcpy (edgepoints + endIdx, &newvert, sizeof(newvert));
+
+ memmove(sidelist + endIdx + 1, sidelist + endIdx, numedgepoints - endIdx - 1);
+ sidelist[endIdx] = 1;
+
+ // Skip over the new vertex.
+ k++;
+ }
+ }
+
+ // Now we must discard the points that are on the wrong side.
+ for (k = 0; k < numedgepoints; k++)
+ {
+ if (!sidelist[k])
+ {
+ memmove(edgepoints + k, edgepoints + k + 1, (numedgepoints-k-1)*sizeof(fvertex_t));
+ memmove(sidelist + k, sidelist + k + 1, numedgepoints - k - 1);
+ numedgepoints--;
+ k--;
+ }
+ }
+ }
+
+ if (!numedgepoints)
+ {
+ // I_Error("All carved away!\n");
+ printf( "All carved away: subsector %p\n", ssec);
+ ssec->numedgeverts = 0;
+ ssec->edgeverts = 0;
+ ssec->origedgeverts = 0;
+ }
+ else
+ {
+ // Screen out consecutive identical points.
+ for (i = 0; i < numedgepoints; i++)
+ {
+ int previdx = i - 1;
+ if (previdx < 0)
+ previdx = numedgepoints - 1;
+ if (edgepoints[i].x == edgepoints[previdx].x &&
+ edgepoints[i].y == edgepoints[previdx].y)
+ {
+ // This point (i) must be removed.
+ memmove(edgepoints + i, edgepoints + i + 1,
+ sizeof(fvertex_t)*(numedgepoints - i - 1));
+ numedgepoints--;
+ i--;
+ }
+ }
+ // We need these with dynamic lights.
+ ssec->origedgeverts = (fvertex_t *) Z_Malloc(sizeof(fvertex_t)*numedgepoints, PU_LEVEL, NULL);
+ memcpy(ssec->origedgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
+
+ // Find the center point. Do this by first finding the bounding box.
+ ssec->bbox[0].x = ssec->bbox[1].x = edgepoints[0].x;
+ ssec->bbox[0].y = ssec->bbox[1].y = edgepoints[0].y;
+ for (i = 1; i < numedgepoints; i++)
+ {
+ OGL_DEBUG(" %i: (%f, %f)\n", i, edgepoints[i].x, edgepoints[i].y);
+ if (edgepoints[i].x < ssec->bbox[0].x)
+ ssec->bbox[0].x = edgepoints[i].x;
+ if (edgepoints[i].y < ssec->bbox[0].y)
+ ssec->bbox[0].y = edgepoints[i].y;
+ if (edgepoints[i].x > ssec->bbox[1].x)
+ ssec->bbox[1].x = edgepoints[i].x;
+ if (edgepoints[i].y > ssec->bbox[1].y)
+ ssec->bbox[1].y = edgepoints[i].y;
+ }
+ ssec->midpoint.x = (ssec->bbox[1].x + ssec->bbox[0].x) / 2;
+ ssec->midpoint.y = (ssec->bbox[1].y + ssec->bbox[0].y) / 2;
+
+ // Make slight adjustments to patch up those ugly, small gaps.
+ for (i = 0; i < numedgepoints; i++)
+ {
+ float dx = edgepoints[i].x - ssec->midpoint.x,
+ dy = edgepoints[i].y - ssec->midpoint.y;
+ float dlen = (float) sqrt(dx*dx + dy*dy) * 3;
+ if (dlen)
+ {
+ edgepoints[i].x += dx / dlen;
+ edgepoints[i].y += dy / dlen;
+ }
+ }
+
+ ssec->numedgeverts = numedgepoints;
+ ssec->edgeverts = (fvertex_t *) Z_Malloc(sizeof(fvertex_t)*numedgepoints, PU_LEVEL, NULL);
+ memcpy(ssec->edgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
+ }
+
+ // We're done, free the edgepoints memory.
+ free(clippers);
+ free(edgepoints);
+}
+
+static void P_CreateFloorsAndCeilings(int bspnode, int numdivlines, divline_t* divlines)
+{
+ node_t *nod;
+ divline_t *childlist, *dl;
+ int childlistsize = numdivlines + 1;
+
+ // If this is a subsector we are dealing with, begin carving with the
+ // given list.
+ if (bspnode & NF_SUBSECTOR)
+ {
+ // We have arrived at a subsector. The divline list contains all
+ // the partition lines that carve out the subsector.
+ int ssidx = bspnode & (~NF_SUBSECTOR);
+ OGL_DEBUG("subsector %d: %d divlines\n", ssidx, numdivlines);
+ // if (ssidx < 10)
+ P_ConvexCarver(subsectors+ssidx, numdivlines, divlines);
+
+ OGL_DEBUG("subsector %d: %d edgeverts\n", ssidx, subsectors[ssidx].numedgeverts);
+ return; // This leaf is done.
+ }
+
+ // Get a pointer to the node.
+ nod = nodes + bspnode;
+
+ // Allocate a new list for each child.
+ childlist = (divline_t *) malloc(childlistsize*sizeof(divline_t));
+
+ // Copy the previous lines.
+ if (divlines)
+ memcpy(childlist, divlines, numdivlines*sizeof(divline_t));
+
+ dl = childlist + numdivlines;
+ dl->x = nod->x;
+ dl->y = nod->y;
+ // The right child gets the original line (LEFT side clipped).
+ dl->dx = nod->dx;
+ dl->dy = nod->dy;
+ P_CreateFloorsAndCeilings(nod->children[0], childlistsize, childlist);
+
+ // The left side. We must reverse the line, otherwise the wrong
+ // side would get clipped.
+ dl->dx = -nod->dx;
+ dl->dy = -nod->dy;
+ P_CreateFloorsAndCeilings(nod->children[1], childlistsize, childlist);
+
+ // We are finishing with this node, free the allocated list.
+ free(childlist);
+}
+
+static void P_SkyFix(void)
+{
+ int i;
+
+ // We need to check all the linedefs.
+ for (i = 0; i < numlines; i++)
+ {
+ line_t *line = lines + i;
+ sector_t *front = line->frontsector, *back = line->backsector;
+ int fix = 0;
+ // The conditions!
+ if (!front || !back)
+ continue;
+ // Both the front and back sectors must have the sky ceiling.
+ if (front->ceilingpic != skyflatnum || back->ceilingpic != skyflatnum)
+ continue;
+ // Operate on the lower sector.
+ OGL_DEBUG("Line %d (f:%d, b:%d).\n", i, front->ceilingheight >> FRACBITS,
+ back->ceilingheight >> FRACBITS);
+ if (front->ceilingheight < back->ceilingheight)
+ {
+ fix = (back->ceilingheight - front->ceilingheight) >> FRACBITS;
+ if (fix > front->skyfix)
+ front->skyfix = fix;
+ }
+ else if (front->ceilingheight > back->ceilingheight)
+ {
+ fix = (front->ceilingheight - back->ceilingheight) >> FRACBITS;
+ if (fix > back->skyfix)
+ back->skyfix = fix;
+ }
+ }
+}
+#endif /* RENDER3D */
+
+//=============================================================================
+
+/*
+=================
+=
+= P_SetupLevel
+=
+=================
+*/
+
+void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
+{
+ int i;
+ int parm;
+ char lumpname[9];
+ char auxName[128];
+ int lumpnum;
+ mobj_t *mobj;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ players[i].killcount = players[i].secretcount = players[i].itemcount = 0;
+ }
+ players[consoleplayer].viewz = 1; // will be set by player think
+
+ if (!i_CDMusic || !cdaudio)
+ {
+ S_StartSongName("chess", true); // Waiting-for-level-load song
+ }
+
+ Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1);
+
+#ifdef RENDER3D
+ OGL_ResetData();
+#endif
+
+ P_InitThinkers();
+ leveltime = 0;
+
+ if (DevMaps)
+ {
+ snprintf(auxName, sizeof(auxName), "%smap%02d.wad", DevMapsDir, map);
+ W_OpenAuxiliary(auxName);
+ }
+ snprintf(lumpname, sizeof(lumpname), "MAP%02d", map);
+ lumpnum = W_GetNumForName(lumpname);
+ //
+ // Begin processing map lumps
+ // Note: most of this ordering is important
+ //
+ P_LoadBlockMap(lumpnum + ML_BLOCKMAP);
+ P_LoadVertexes(lumpnum + ML_VERTEXES);
+ P_LoadSectors(lumpnum + ML_SECTORS);
+ P_LoadSideDefs(lumpnum + ML_SIDEDEFS);
+ P_LoadLineDefs(lumpnum + ML_LINEDEFS);
+ P_LoadSubsectors(lumpnum + ML_SSECTORS);
+ P_LoadNodes(lumpnum + ML_NODES);
+ P_LoadSegs(lumpnum + ML_SEGS);
+
+#ifdef RENDER3D
+ // We need to carve out the floor/ceiling polygons of each subsector.
+ // Walk the tree to do this.
+ //OGL_DEBUG("Floor/ceiling creation: begin at %d, ", ticcount);
+ P_CreateFloorsAndCeilings(numnodes - 1, 0, 0);
+ // Also check if the sky needs a fix.
+ P_SkyFix();
+#endif
+
+ rejectmatrix = (byte *) W_CacheLumpNum(lumpnum + ML_REJECT, PU_LEVEL);
+ P_GroupLines();
+ bodyqueslot = 0;
+ po_NumPolyobjs = 0;
+ deathmatch_p = deathmatchstarts;
+ P_LoadThings(lumpnum + ML_THINGS);
+ PO_Init(lumpnum + ML_THINGS); // Initialize the polyobjs
+ P_LoadACScripts(lumpnum + ML_BEHAVIOR); // ACS object code
+ //
+ // End of map lump processing
+ //
+ if (DevMaps)
+ {
+ // Close the auxiliary file, but don't free its loaded lumps.
+ // The next call to W_OpenAuxiliary() will do a full shutdown
+ // of the current auxiliary WAD (free lumps and info lists).
+ W_CloseAuxiliaryFile();
+ W_UsePrimary();
+ }
+
+ // If deathmatch, randomly spawn the active players
+ TimerGame = 0;
+ if (deathmatch)
+ {
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ { // must give a player spot before deathmatchspawn
+ mobj = P_SpawnMobj (playerstarts[0][i].x<<16,
+ playerstarts[0][i].y<<16,
+ 0, MT_PLAYER_FIGHTER);
+ players[i].mo = mobj;
+ G_DeathMatchSpawnPlayer (i);
+ P_RemoveMobj (mobj);
+ }
+ }
+ parm = M_CheckParm("-timer");
+ if (parm && parm < myargc - 1)
+ {
+ TimerGame = atoi(myargv[parm + 1]) * 35 * 60;
+ }
+ }
+
+// set up world state
+ P_SpawnSpecials ();
+
+// build subsector connect matrix
+// P_ConnectSubsectors ();
+
+// Load colormap and set the fullbright flag
+ i = P_GetMapFadeTable(gamemap);
+ W_ReadLump(i, colormaps);
+ if (i == W_GetNumForName("COLORMAP"))
+ {
+ LevelUseFullBright = true;
+#ifdef RENDER3D
+ OGL_UseWhiteFog(false);
+#endif
+ }
+ else
+ { // Probably fog ... don't use fullbright sprites
+ LevelUseFullBright = false;
+#ifdef RENDER3D
+ if (i == W_GetNumForName("FOGMAP"))
+ {
+ // Tell the renderer to turn on the fog.
+ OGL_UseWhiteFog(true);
+ }
+#endif
+ }
+
+// preload graphics
+ if (precache)
+ R_PrecacheLevel ();
+
+ // Check if the level is a lightning level
+ P_InitLightning();
+
+ S_StopAllSound();
+ SN_StopAllSequences();
+ S_StartSong(gamemap, true);
+
+// printf ("free memory: 0x%x\n", Z_FreeMemory());
+}
+
+//==========================================================================
+//
+// InitMapInfo
+//
+//==========================================================================
+
+static void InitMapInfo(void)
+{
+ int map;
+ int mapMax;
+ int mcmdValue;
+ mapInfo_t *info;
+ char songMulch[10];
+
+ mapMax = 1;
+
+ // Put defaults into MapInfo[0]
+ info = MapInfo;
+ info->cluster = 0;
+ info->warpTrans = 0;
+ info->nextMap = 1; // Always go to map 1 if not specified
+ info->cdTrack = 1;
+ info->sky1Texture = R_TextureNumForName((shareware && oldwad_10) ? DEFAULT_SKY_DEMO : DEFAULT_SKY_NAME);
+ info->sky2Texture = info->sky1Texture;
+ info->sky1ScrollDelta = 0;
+ info->sky2ScrollDelta = 0;
+ info->doubleSky = false;
+ info->lightning = false;
+ info->fadetable = W_GetNumForName(DEFAULT_FADE_TABLE);
+ strcpy(info->name, UNKNOWN_MAP_NAME);
+
+// strcpy(info->songLump, DEFAULT_SONG_LUMP);
+ SC_Open(MAPINFO_SCRIPT_NAME);
+ while (SC_GetString())
+ {
+ if (SC_Compare("MAP") == false)
+ {
+ SC_ScriptError(NULL);
+ }
+ SC_MustGetNumber();
+ if (sc_Number < 1 || sc_Number > 99)
+ {
+ SC_ScriptError(NULL);
+ }
+ map = sc_Number;
+
+ info = &MapInfo[map];
+
+ // Save song lump name
+ strcpy(songMulch, info->songLump);
+
+ // Copy defaults to current map definition
+ memcpy(info, &MapInfo[0], sizeof(*info));
+
+ // Restore song lump name
+ strcpy(info->songLump, songMulch);
+
+ // The warp translation defaults to the map number
+ info->warpTrans = map;
+
+ // Map name must follow the number
+ SC_MustGetString();
+ strcpy(info->name, sc_String);
+
+ // Process optional tokens
+ while (SC_GetString())
+ {
+ if (SC_Compare("MAP"))
+ { // Start next map definition
+ SC_UnGet();
+ break;
+ }
+ mcmdValue = MapCmdIDs[SC_MustMatchString(MapCmdNames)];
+ switch (mcmdValue)
+ {
+ case MCMD_CLUSTER:
+ SC_MustGetNumber();
+ info->cluster = sc_Number;
+ break;
+ case MCMD_WARPTRANS:
+ SC_MustGetNumber();
+ info->warpTrans = sc_Number;
+ break;
+ case MCMD_NEXT:
+ SC_MustGetNumber();
+ info->nextMap = sc_Number;
+ break;
+ case MCMD_CDTRACK:
+ SC_MustGetNumber();
+ info->cdTrack = sc_Number;
+ break;
+ case MCMD_SKY1:
+ SC_MustGetString();
+ info->sky1Texture = R_TextureNumForName(sc_String);
+ SC_MustGetNumber();
+ info->sky1ScrollDelta = sc_Number<<8;
+ break;
+ case MCMD_SKY2:
+ SC_MustGetString();
+ info->sky2Texture = R_TextureNumForName(sc_String);
+ SC_MustGetNumber();
+ info->sky2ScrollDelta = sc_Number<<8;
+ break;
+ case MCMD_DOUBLESKY:
+ info->doubleSky = true;
+ break;
+ case MCMD_LIGHTNING:
+ info->lightning = true;
+ break;
+ case MCMD_FADETABLE:
+ SC_MustGetString();
+ info->fadetable = W_GetNumForName(sc_String);
+ break;
+ case MCMD_CD_STARTTRACK:
+ case MCMD_CD_END1TRACK:
+ case MCMD_CD_END2TRACK:
+ case MCMD_CD_END3TRACK:
+ case MCMD_CD_INTERTRACK:
+ case MCMD_CD_TITLETRACK:
+ SC_MustGetNumber();
+ cd_NonLevelTracks[mcmdValue - MCMD_CD_STARTTRACK] = sc_Number;
+ break;
+ }
+ }
+ mapMax = map > mapMax ? map : mapMax;
+ }
+ SC_Close();
+ MapCount = mapMax;
+}
+
+//==========================================================================
+//
+// P_GetMapCluster
+//
+//==========================================================================
+
+int P_GetMapCluster(int map)
+{
+ return MapInfo[QualifyMap(map)].cluster;
+}
+
+//==========================================================================
+//
+// P_GetMapCDTrack
+//
+//==========================================================================
+
+int P_GetMapCDTrack(int map)
+{
+ return MapInfo[QualifyMap(map)].cdTrack;
+}
+
+//==========================================================================
+//
+// P_GetMapWarpTrans
+//
+//==========================================================================
+
+int P_GetMapWarpTrans(int map)
+{
+ return MapInfo[QualifyMap(map)].warpTrans;
+}
+
+//==========================================================================
+//
+// P_GetMapNextMap
+//
+//==========================================================================
+
+int P_GetMapNextMap(int map)
+{
+ return MapInfo[QualifyMap(map)].nextMap;
+}
+
+//==========================================================================
+//
+// P_TranslateMap
+//
+// Returns the actual map number given a warp map number.
+//
+//==========================================================================
+
+int P_TranslateMap(int map)
+{
+ int i;
+
+ for (i = 1; i < 99; i++) // Make this a macro
+ {
+ if (MapInfo[i].warpTrans == map)
+ {
+ return i;
+ }
+ }
+ // Not found
+ return -1;
+}
+
+//==========================================================================
+//
+// P_GetMapSky1Texture
+//
+//==========================================================================
+
+int P_GetMapSky1Texture(int map)
+{
+ return MapInfo[QualifyMap(map)].sky1Texture;
+}
+
+//==========================================================================
+//
+// P_GetMapSky2Texture
+//
+//==========================================================================
+
+int P_GetMapSky2Texture(int map)
+{
+ return MapInfo[QualifyMap(map)].sky2Texture;
+}
+
+//==========================================================================
+//
+// P_GetMapName
+//
+//==========================================================================
+
+const char *P_GetMapName(int map)
+{
+ return MapInfo[QualifyMap(map)].name;
+}
+
+//==========================================================================
+//
+// P_GetMapSky1ScrollDelta
+//
+//==========================================================================
+
+fixed_t P_GetMapSky1ScrollDelta(int map)
+{
+ return MapInfo[QualifyMap(map)].sky1ScrollDelta;
+}
+
+//==========================================================================
+//
+// P_GetMapSky2ScrollDelta
+//
+//==========================================================================
+
+fixed_t P_GetMapSky2ScrollDelta(int map)
+{
+ return MapInfo[QualifyMap(map)].sky2ScrollDelta;
+}
+
+//==========================================================================
+//
+// P_GetMapDoubleSky
+//
+//==========================================================================
+
+boolean P_GetMapDoubleSky(int map)
+{
+ return MapInfo[QualifyMap(map)].doubleSky;
+}
+
+//==========================================================================
+//
+// P_GetMapLightning
+//
+//==========================================================================
+
+boolean P_GetMapLightning(int map)
+{
+ return MapInfo[QualifyMap(map)].lightning;
+}
+
+//==========================================================================
+//
+// P_GetMapFadeTable
+//
+//==========================================================================
+
+boolean P_GetMapFadeTable(int map)
+{
+ return MapInfo[QualifyMap(map)].fadetable;
+}
+
+//==========================================================================
+//
+// P_GetMapSongLump
+//
+//==========================================================================
+
+const char *P_GetMapSongLump(int map)
+{
+ if (!strcasecmp(MapInfo[QualifyMap(map)].songLump, DEFAULT_SONG_LUMP))
+ {
+ return NULL;
+ }
+ else
+ {
+ return MapInfo[QualifyMap(map)].songLump;
+ }
+}
+
+//==========================================================================
+//
+// P_PutMapSongLump
+//
+//==========================================================================
+
+void P_PutMapSongLump(int map, const char *lumpName)
+{
+ if (map < 1 || map > MapCount)
+ {
+ return;
+ }
+ strcpy(MapInfo[map].songLump, lumpName);
+}
+
+//==========================================================================
+//
+// P_GetCDStartTrack
+//
+//==========================================================================
+
+int P_GetCDStartTrack(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_STARTTRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDEnd1Track
+//
+//==========================================================================
+
+int P_GetCDEnd1Track(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_END1TRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDEnd2Track
+//
+//==========================================================================
+
+int P_GetCDEnd2Track(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_END2TRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDEnd3Track
+//
+//==========================================================================
+
+int P_GetCDEnd3Track(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_END3TRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDIntermissionTrack
+//
+//==========================================================================
+
+int P_GetCDIntermissionTrack(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_INTERTRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// P_GetCDTitleTrack
+//
+//==========================================================================
+
+int P_GetCDTitleTrack(void)
+{
+ return cd_NonLevelTracks[MCMD_CD_TITLETRACK - MCMD_CD_STARTTRACK];
+}
+
+//==========================================================================
+//
+// QualifyMap
+//
+//==========================================================================
+
+static int QualifyMap(int map)
+{
+ return (map < 1 || map > MapCount) ? 0 : map;
+}
+
+//==========================================================================
+//
+// P_Init
+//
+//==========================================================================
+
+void P_Init(void)
+{
+ InitMapInfo();
+ P_InitSwitchList();
+ P_InitFTAnims(); // Init flat and texture animations
+ P_InitTerrainTypes();
+ P_InitLava();
+ R_InitSprites(sprnames);
+}
+
+// Special early initializer needed to start sound before R_Init()
+void InitMapMusicInfo(void)
+{
+ int i;
+
+ for (i = 0; i < 99; i++)
+ {
+ strcpy(MapInfo[i].songLump, DEFAULT_SONG_LUMP);
+ }
+ MapCount = 98;
+}
+
+/*
+void My_Debug(void)
+{
+ int i;
+
+ printf("My debug stuff ----------------------\n");
+ printf("gamemap=%d\n", gamemap);
+ for (i = 0; i < 10; i++)
+ {
+ printf("i=%d songlump=%s\n", i, MapInfo[i].songLump);
+ }
+}
+*/
+
--- /dev/null
+++ b/p_sight.c
@@ -1,0 +1,388 @@
+
+//**************************************************************************
+//**
+//** p_sight.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+/*
+==============================================================================
+
+P_CheckSight
+
+This uses specialized forms of the maputils routines for optimized performance
+
+==============================================================================
+*/
+
+extern polyblock_t **PolyBlockMap;
+
+static int sightcounts[3];
+static fixed_t sightzstart; /* eye z of looker */
+
+fixed_t topslope, bottomslope;
+ /* slopes to top and bottom of target */
+
+
+/*
+==============
+=
+= PTR_SightTraverse
+=
+==============
+*/
+
+static boolean PTR_SightTraverse (intercept_t *in)
+{
+ line_t *li;
+ fixed_t slope;
+
+ li = in->d.line;
+
+//
+// crosses a two sided line
+//
+ P_LineOpening (li);
+
+ if (openbottom >= opentop) // quick test for totally closed doors
+ return false; // stop
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv (openbottom - sightzstart, in->frac);
+ if (slope > bottomslope)
+ bottomslope = slope;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv (opentop - sightzstart, in->frac);
+ if (slope < topslope)
+ topslope = slope;
+ }
+
+ if (topslope <= bottomslope)
+ return false; // stop
+
+ return true; // keep going
+}
+
+
+/*
+==================
+=
+= P_SightBlockLinesIterator
+=
+===================
+*/
+
+static boolean P_SightBlockLinesIterator (int x, int y)
+{
+ int offset;
+ short *list;
+ line_t *ld;
+ int s1, s2;
+ divline_t dl;
+
+ polyblock_t *polyLink;
+ seg_t **segList;
+ int i;
+
+ offset = y*bmapwidth + x;
+
+ polyLink = PolyBlockMap[offset];
+ while (polyLink)
+ {
+ if (polyLink->polyobj)
+ { // only check non-empty links
+ if (polyLink->polyobj->validcount != validcount)
+ {
+ segList = polyLink->polyobj->segs;
+ for (i = 0; i < polyLink->polyobj->numsegs; i++, segList++)
+ {
+ ld = (*segList)->linedef;
+ if (ld->validcount == validcount)
+ {
+ continue;
+ }
+ ld->validcount = validcount;
+ s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
+ s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
+ if (s1 == s2)
+ continue; // line isn't crossed
+ P_MakeDivline (ld, &dl);
+ s1 = P_PointOnDivlineSide (trace.x, trace.y, &dl);
+ s2 = P_PointOnDivlineSide (trace.x + trace.dx, trace.y + trace.dy, &dl);
+ if (s1 == s2)
+ continue; // line isn't crossed
+
+ // try to early out the check
+ if (!ld->backsector)
+ return false; // stop checking
+
+ // store the line for later intersection testing
+ intercept_p->d.line = ld;
+ intercept_p++;
+ }
+ polyLink->polyobj->validcount = validcount;
+ }
+ }
+ polyLink = polyLink->next;
+ }
+
+ offset = *(blockmap + offset);
+
+ for (list = blockmaplump+offset; *list != -1; list++)
+ {
+ ld = &lines[*list];
+ if (ld->validcount == validcount)
+ continue; // line has already been checked
+ ld->validcount = validcount;
+
+ s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
+ s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
+ if (s1 == s2)
+ continue; // line isn't crossed
+ P_MakeDivline (ld, &dl);
+ s1 = P_PointOnDivlineSide (trace.x, trace.y, &dl);
+ s2 = P_PointOnDivlineSide (trace.x + trace.dx, trace.y + trace.dy, &dl);
+ if (s1 == s2)
+ continue; // line isn't crossed
+
+ // try to early out the check
+ if (!ld->backsector)
+ return false; // stop checking
+
+ // store the line for later intersection testing
+ intercept_p->d.line = ld;
+ intercept_p++;
+ }
+
+ return true; // everything was checked
+}
+
+/*
+====================
+=
+= P_SightTraverseIntercepts
+=
+= Returns true if the traverser function returns true for all lines
+====================
+*/
+
+static boolean P_SightTraverseIntercepts (void)
+{
+ int count;
+ fixed_t dist;
+ intercept_t *scan, *in;
+ divline_t dl;
+
+ count = intercept_p - intercepts;
+//
+// calculate intercept distance
+//
+ for (scan = intercepts; scan < intercept_p; scan++)
+ {
+ P_MakeDivline (scan->d.line, &dl);
+ scan->frac = P_InterceptVector (&trace, &dl);
+ }
+
+//
+// go through in order
+//
+ in = NULL; // shut up compiler warning
+
+ while (count--)
+ {
+ dist = H2MAXINT;
+ for (scan = intercepts; scan < intercept_p; scan++)
+ {
+ if (scan->frac < dist)
+ {
+ dist = scan->frac;
+ in = scan;
+ }
+ }
+
+ if ( !PTR_SightTraverse (in) )
+ return false; // don't bother going farther
+ in->frac = H2MAXINT;
+ }
+
+ return true; // everything was traversed
+}
+
+
+/*
+==================
+=
+= P_SightPathTraverse
+=
+= Traces a line from x1,y1 to x2,y2, calling the traverser function for each
+= Returns true if the traverser function returns true for all lines
+==================
+*/
+
+static boolean P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
+{
+ fixed_t xt1,yt1,xt2,yt2;
+ fixed_t xstep,ystep;
+ fixed_t partial;
+ fixed_t xintercept, yintercept;
+ int mapx, mapy, mapxstep, mapystep;
+ int count;
+
+ validcount++;
+ intercept_p = intercepts;
+
+ if (((x1 - bmaporgx) & (MAPBLOCKSIZE - 1)) == 0)
+ x1 += FRACUNIT; // don't side exactly on a line
+ if (((y1 - bmaporgy) & (MAPBLOCKSIZE - 1)) == 0)
+ y1 += FRACUNIT; // don't side exactly on a line
+ trace.x = x1;
+ trace.y = y1;
+ trace.dx = x2 - x1;
+ trace.dy = y2 - y1;
+
+ x1 -= bmaporgx;
+ y1 -= bmaporgy;
+ xt1 = x1>>MAPBLOCKSHIFT;
+ yt1 = y1>>MAPBLOCKSHIFT;
+
+ x2 -= bmaporgx;
+ y2 -= bmaporgy;
+ xt2 = x2>>MAPBLOCKSHIFT;
+ yt2 = y2>>MAPBLOCKSHIFT;
+
+// points should never be out of bounds, but check once instead of
+// each block
+ if (xt1 < 0 || yt1 < 0 || xt1 >= bmapwidth || yt1 >= bmapheight ||
+ xt2 < 0 || yt2 < 0 || xt2 >= bmapwidth || yt2 >= bmapheight)
+ return false;
+
+ if (xt2 > xt1)
+ {
+ mapxstep = 1;
+ partial = FRACUNIT - ((x1>>MAPBTOFRAC) & (FRACUNIT - 1));
+ ystep = FixedDiv (y2 - y1, abs(x2 - x1));
+ }
+ else if (xt2 < xt1)
+ {
+ mapxstep = -1;
+ partial = (x1>>MAPBTOFRAC) & (FRACUNIT - 1);
+ ystep = FixedDiv (y2 - y1, abs(x2 - x1));
+ }
+ else
+ {
+ mapxstep = 0;
+ partial = FRACUNIT;
+ ystep = 256*FRACUNIT;
+ }
+ yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
+
+ if (yt2 > yt1)
+ {
+ mapystep = 1;
+ partial = FRACUNIT - ((y1>>MAPBTOFRAC) & (FRACUNIT - 1));
+ xstep = FixedDiv (x2 - x1, abs(y2 - y1));
+ }
+ else if (yt2 < yt1)
+ {
+ mapystep = -1;
+ partial = (y1>>MAPBTOFRAC) & (FRACUNIT - 1);
+ xstep = FixedDiv (x2 - x1, abs(y2 - y1));
+ }
+ else
+ {
+ mapystep = 0;
+ partial = FRACUNIT;
+ xstep = 256*FRACUNIT;
+ }
+ xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
+
+//
+// step through map blocks
+// Count is present to prevent a round off error from skipping the break
+ mapx = xt1;
+ mapy = yt1;
+
+ for (count = 0; count < 64; count++)
+ {
+ if (!P_SightBlockLinesIterator (mapx, mapy))
+ {
+ sightcounts[1]++;
+ return false; // early out
+ }
+
+ if (mapx == xt2 && mapy == yt2)
+ break;
+
+ if ((yintercept >> FRACBITS) == mapy)
+ {
+ yintercept += ystep;
+ mapx += mapxstep;
+ }
+ else if ((xintercept >> FRACBITS) == mapx)
+ {
+ xintercept += xstep;
+ mapy += mapystep;
+ }
+ }
+
+//
+// couldn't early out, so go through the sorted list
+//
+ sightcounts[2]++;
+
+ return P_SightTraverseIntercepts ();
+}
+
+
+/*
+=====================
+=
+= P_CheckSight
+=
+= Returns true if a straight line between t1 and t2 is unobstructed
+= look from eyes of t1 to any part of t2
+=
+=====================
+*/
+
+boolean P_CheckSight (mobj_t *t1, mobj_t *t2)
+{
+ int s1, s2;
+ int pnum, bytenum, bitnum;
+
+//
+// check for trivial rejection
+//
+ s1 = (t1->subsector->sector - sectors);
+ s2 = (t2->subsector->sector - sectors);
+ pnum = s1*numsectors + s2;
+ bytenum = pnum>>3;
+ bitnum = 1 << (pnum & 7);
+
+ if (rejectmatrix[bytenum] & bitnum)
+ {
+ sightcounts[0]++;
+ return false; // can't possibly be connected
+ }
+
+//
+// check precisely
+//
+ sightzstart = t1->z + t1->height - (t1->height>>2);
+ topslope = (t2->z + t2->height) - sightzstart;
+ bottomslope = (t2->z) - sightzstart;
+
+ return P_SightPathTraverse (t1->x, t1->y, t2->x, t2->y);
+}
+
--- /dev/null
+++ b/p_spec.c
@@ -1,0 +1,1176 @@
+
+//**************************************************************************
+//**
+//** p_spec.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 584 $
+//** $Date: 2012-02-17 12:01:51 +0200 (Fri, 17 Feb 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_TAGGED_LINES 64
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+extern const char *TextKeyMessages[11];
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static boolean CheckedLockedDoor(mobj_t *mo, byte lock);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int *TerrainTypes;
+mobj_t LavaInflictor;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static struct
+{
+ const char *name;
+ int type;
+} TerrainTypeDefs[] =
+{
+ { "X_005", FLOOR_WATER },
+ { "X_001", FLOOR_LAVA },
+ { "X_009", FLOOR_SLUDGE },
+ { "F_033", FLOOR_ICE },
+ { "END", -1 }
+};
+
+static struct
+{
+ line_t *line;
+ int lineTag;
+} TaggedLines[MAX_TAGGED_LINES];
+
+static int TaggedLineCount;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_InitLava
+//
+//==========================================================================
+
+void P_InitLava(void)
+{
+ memset(&LavaInflictor, 0, sizeof(mobj_t));
+ LavaInflictor.type = MT_CIRCLEFLAME;
+ LavaInflictor.flags2 = MF2_FIREDAMAGE|MF2_NODMGTHRUST;
+}
+
+//==========================================================================
+//
+// P_InitTerrainTypes
+//
+//==========================================================================
+
+void P_InitTerrainTypes(void)
+{
+ int i;
+ int lump;
+ int size;
+
+ size = (numflats + 1) * sizeof(int);
+ TerrainTypes = (int *) Z_Malloc(size, PU_STATIC, NULL);
+ memset(TerrainTypes, 0, size);
+ for (i = 0; TerrainTypeDefs[i].type != -1; i++)
+ {
+ lump = W_CheckNumForName(TerrainTypeDefs[i].name);
+ if (lump != -1)
+ {
+ TerrainTypes[lump - firstflat] = TerrainTypeDefs[i].type;
+ }
+ }
+}
+
+//==========================================================================
+//
+// getSide
+//
+// Will return a side_t* given the number of the current sector, the
+// line number, and the side (0/1) that you want.
+//
+//==========================================================================
+
+/*
+side_t *getSide(int currentSector, int line, int side)
+{
+ return &sides[ (sectors[currentSector].lines[line])->sidenum[side] ];
+}
+*/
+
+//==========================================================================
+//
+// getSector
+//
+// Will return a sector_t* given the number of the current sector, the
+// line number, and the side (0/1) that you want.
+//
+//==========================================================================
+
+/*
+sector_t *getSector(int currentSector, int line, int side)
+{
+ return sides[ (sectors[currentSector].lines[line])->sidenum[side] ].sector;
+}
+*/
+
+//==========================================================================
+//
+// twoSided
+//
+// Given the sector number and the line number, will tell you whether
+// the line is two-sided or not.
+//
+//==========================================================================
+
+/*
+int twoSided(int sector, int line)
+{
+ return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
+}
+*/
+
+//==================================================================
+//
+// Return sector_t * of sector next to current. NULL if not two-sided line
+//
+//==================================================================
+
+sector_t *getNextSector(line_t *line,sector_t *sec)
+{
+ if (!(line->flags & ML_TWOSIDED))
+ return NULL;
+
+ if (line->frontsector == sec)
+ return line->backsector;
+
+ return line->frontsector;
+}
+
+//==================================================================
+//
+// FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
+//
+//==================================================================
+
+fixed_t P_FindLowestFloorSurrounding(sector_t *sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t floor = sec->floorheight;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check,sec);
+ if (!other)
+ continue;
+ if (other->floorheight < floor)
+ floor = other->floorheight;
+ }
+ return floor;
+}
+
+//==================================================================
+//
+// FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
+//
+//==================================================================
+
+fixed_t P_FindHighestFloorSurrounding(sector_t *sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t floor = -500*FRACUNIT;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check,sec);
+ if (!other)
+ continue;
+ if (other->floorheight > floor)
+ floor = other->floorheight;
+ }
+ return floor;
+}
+
+//==================================================================
+//
+// FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
+//
+//==================================================================
+
+
+#define MAX_ADJOINING_SECTORS 20 /* 20 adjoining sectors max! */
+
+fixed_t P_FindNextHighestFloor(sector_t *sec,int currentheight)
+{
+ int i;
+ int h;
+ int min;
+ line_t *check;
+ sector_t *other;
+ fixed_t height = currentheight;
+ fixed_t heightlist[MAX_ADJOINING_SECTORS];
+
+ for (i = 0, h = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check,sec);
+ if (!other)
+ continue;
+ if (other->floorheight > height)
+ heightlist[h++] = other->floorheight;
+ if (h >= MAX_ADJOINING_SECTORS)
+ {
+ fprintf(stderr, "Sector with more than %d adjoining sectors\n",
+ MAX_ADJOINING_SECTORS);
+ break;
+ }
+ }
+
+ //
+ // Find lowest height in list
+ //
+ if(!h)
+ return currentheight;
+
+ min = heightlist[0];
+ for (i = 1; i < h; i++)
+ {
+ if (heightlist[i] < min)
+ min = heightlist[i];
+ }
+
+ return min;
+}
+
+//==================================================================
+//
+// FIND LOWEST CEILING IN THE SURROUNDING SECTORS
+//
+//==================================================================
+
+fixed_t P_FindLowestCeilingSurrounding(sector_t *sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t height = H2MAXINT;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check,sec);
+ if (!other)
+ continue;
+ if (other->ceilingheight < height)
+ height = other->ceilingheight;
+ }
+ return height;
+}
+
+//==================================================================
+//
+// FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
+//
+//==================================================================
+
+fixed_t P_FindHighestCeilingSurrounding(sector_t *sec)
+{
+ int i;
+ line_t *check;
+ sector_t *other;
+ fixed_t height = 0;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check,sec);
+ if (!other)
+ continue;
+ if (other->ceilingheight > height)
+ height = other->ceilingheight;
+ }
+ return height;
+}
+
+//==================================================================
+//
+// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
+//
+//==================================================================
+
+/*
+int P_FindSectorFromLineTag(line_t *line,int start)
+{
+ int i;
+
+ for (i = start + 1; i < numsectors; i++)
+ {
+ if (sectors[i].tag == line->arg1)
+ return i;
+ }
+ return -1;
+}
+*/
+
+//=========================================================================
+//
+// P_FindSectorFromTag
+//
+//=========================================================================
+
+int P_FindSectorFromTag(int tag, int start)
+{
+ int i;
+
+ for (i = start + 1; i < numsectors; i++)
+ {
+ if (sectors[i].tag == tag)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+//==================================================================
+//
+// Find minimum light from an adjacent sector
+//
+//==================================================================
+
+/*
+int P_FindMinSurroundingLight(sector_t *sector,int max)
+{
+ int i;
+ int min;
+ line_t *line;
+ sector_t *check;
+
+ min = max;
+ for (i = 0; i < sector->linecount; i++)
+ {
+ line = sector->lines[i];
+ check = getNextSector(line,sector);
+ if (!check)
+ continue;
+ if (check->lightlevel < min)
+ min = check->lightlevel;
+ }
+ return min;
+}
+*/
+
+//=========================================================================
+//
+// EV_SectorSoundChange
+//
+//=========================================================================
+
+static boolean EV_SectorSoundChange(byte *args)
+{
+ int secNum;
+ boolean rtn;
+
+ if (!args[0])
+ {
+ return false;
+ }
+ secNum = -1;
+ rtn = false;
+ while ((secNum = P_FindSectorFromTag(args[0], secNum)) >= 0)
+ {
+ sectors[secNum].seqType = args[1];
+ rtn = true;
+ }
+ return rtn;
+}
+
+//============================================================================
+//
+// CheckedLockedDoor
+//
+//============================================================================
+
+static boolean CheckedLockedDoor(mobj_t *mo, byte lock)
+{
+ char LockedBuffer[80];
+
+ if (!mo->player)
+ {
+ return false;
+ }
+ if (!lock)
+ {
+ return true;
+ }
+ if (!(mo->player->keys & (1<<(lock-1))))
+ {
+ snprintf(LockedBuffer, sizeof(LockedBuffer),
+ "YOU NEED THE %s\n", TextKeyMessages[lock-1]);
+ P_SetMessage(mo->player, LockedBuffer, true);
+ S_StartSound(mo, SFX_DOOR_LOCKED);
+ return false;
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// EV_LineSearchForPuzzleItem
+//
+//==========================================================================
+
+static boolean EV_LineSearchForPuzzleItem(line_t *line, byte *args, mobj_t *mo)
+{
+ player_t *player;
+ int i;
+ artitype_t type, arti;
+
+ if (!mo)
+ return false;
+ player = mo->player;
+ if (!player)
+ return false;
+
+ // Search player's inventory for puzzle items
+ for (i = 0; i < player->artifactCount; i++)
+ {
+ arti = player->inventory[i].type;
+ if (arti < arti_firstpuzzitem)
+ continue;
+ type = arti - arti_firstpuzzitem;
+ //if (type < 0)
+ // continue;
+ if (type == line->arg1)
+ {
+ // A puzzle item was found for the line
+ if (P_UseArtifact(player, arti))
+ {
+ // A puzzle item was found for the line
+ P_PlayerRemoveArtifact(player, i);
+ if (player == &players[consoleplayer])
+ {
+ if (arti < arti_firstpuzzitem)
+ {
+ S_StartSound(NULL, SFX_ARTIFACT_USE);
+ }
+ else
+ {
+ S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
+ }
+ ArtifactFlash = 4;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+/*
+==============================================================================
+
+EVENTS
+
+Events are operations triggered by using, crossing, or shooting special lines,
+or by timed thinkers
+
+==============================================================================
+*/
+
+//============================================================================
+//
+// P_ExecuteLineSpecial
+//
+//============================================================================
+
+boolean P_ExecuteLineSpecial(int special, byte *args, line_t *line, int side,
+ mobj_t *mo)
+{
+ boolean buttonSuccess;
+
+ buttonSuccess = false;
+ switch (special)
+ {
+ case 1: // Poly Start Line
+ break;
+ case 2: // Poly Rotate Left
+ buttonSuccess = EV_RotatePoly(line, args, 1, false);
+ break;
+ case 3: // Poly Rotate Right
+ buttonSuccess = EV_RotatePoly(line, args, -1, false);
+ break;
+ case 4: // Poly Move
+ buttonSuccess = EV_MovePoly(line, args, false, false);
+ break;
+ case 5: // Poly Explicit Line: Only used in initialization
+ break;
+ case 6: // Poly Move Times 8
+ buttonSuccess = EV_MovePoly(line, args, true, false);
+ break;
+ case 7: // Poly Door Swing
+ buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SWING);
+ break;
+ case 8: // Poly Door Slide
+ buttonSuccess = EV_OpenPolyDoor(line, args, PODOOR_SLIDE);
+ break;
+ case 10: // Door Close
+ buttonSuccess = EV_DoDoor(line, args, DREV_CLOSE);
+ break;
+ case 11: // Door Open
+ if (!args[0])
+ {
+ buttonSuccess = EV_VerticalDoor(line, mo);
+ }
+ else
+ {
+ buttonSuccess = EV_DoDoor(line, args, DREV_OPEN);
+ }
+ break;
+ case 12: // Door Raise
+ if (!args[0])
+ {
+ buttonSuccess = EV_VerticalDoor(line, mo);
+ }
+ else
+ {
+ buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL);
+ }
+ break;
+ case 13: // Door Locked_Raise
+ if (CheckedLockedDoor(mo, args[3]))
+ {
+ if (!args[0])
+ {
+ buttonSuccess = EV_VerticalDoor(line, mo);
+ }
+ else
+ {
+ buttonSuccess = EV_DoDoor(line, args, DREV_NORMAL);
+ }
+ }
+ break;
+ case 20: // Floor Lower by Value
+ buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE);
+ break;
+ case 21: // Floor Lower to Lowest
+ buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOORTOLOWEST);
+ break;
+ case 22: // Floor Lower to Nearest
+ buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERFLOOR);
+ break;
+ case 23: // Floor Raise by Value
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE);
+ break;
+ case 24: // Floor Raise to Highest
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOOR);
+ break;
+ case 25: // Floor Raise to Nearest
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORTONEAREST);
+ break;
+ case 26: // Stairs Build Down Normal
+ buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_NORMAL);
+ break;
+ case 27: // Build Stairs Up Normal
+ buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_NORMAL);
+ break;
+ case 28: // Floor Raise and Crush
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEFLOORCRUSH);
+ break;
+ case 29: // Build Pillar (no crushing)
+ buttonSuccess = EV_BuildPillar(line, args, false);
+ break;
+ case 30: // Open Pillar
+ buttonSuccess = EV_OpenPillar(line, args);
+ break;
+ case 31: // Stairs Build Down Sync
+ buttonSuccess = EV_BuildStairs(line, args, -1, STAIRS_SYNC);
+ break;
+ case 32: // Build Stairs Up Sync
+ buttonSuccess = EV_BuildStairs(line, args, 1, STAIRS_SYNC);
+ break;
+ case 35: // Raise Floor by Value Times 8
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISEBYVALUETIMES8);
+ break;
+ case 36: // Lower Floor by Value Times 8
+ buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERBYVALUETIMES8);
+ break;
+ case 40: // Ceiling Lower by Value
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE);
+ break;
+ case 41: // Ceiling Raise by Value
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE);
+ break;
+ case 42: // Ceiling Crush and Raise
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHANDRAISE);
+ break;
+ case 43: // Ceiling Lower and Crush
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_LOWERANDCRUSH);
+ break;
+ case 44: // Ceiling Crush Stop
+ buttonSuccess = EV_CeilingCrushStop(line, args);
+ break;
+ case 45: // Ceiling Crush Raise and Stay
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_CRUSHRAISEANDSTAY);
+ break;
+ case 46: // Floor Crush Stop
+ buttonSuccess = EV_FloorCrushStop(line, args);
+ break;
+ case 60: // Plat Perpetual Raise
+ buttonSuccess = EV_DoPlat(line, args, PLAT_PERPETUALRAISE, 0);
+ break;
+ case 61: // Plat Stop
+ EV_StopPlat(line, args);
+ break;
+ case 62: // Plat Down-Wait-Up-Stay
+ buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNWAITUPSTAY, 0);
+ break;
+ case 63: // Plat Down-by-Value*8-Wait-Up-Stay
+ buttonSuccess = EV_DoPlat(line, args, PLAT_DOWNBYVALUEWAITUPSTAY, 0);
+ break;
+ case 64: // Plat Up-Wait-Down-Stay
+ buttonSuccess = EV_DoPlat(line, args, PLAT_UPWAITDOWNSTAY, 0);
+ break;
+ case 65: // Plat Up-by-Value*8-Wait-Down-Stay
+ buttonSuccess = EV_DoPlat(line, args, PLAT_UPBYVALUEWAITDOWNSTAY, 0);
+ break;
+ case 66: // Floor Lower Instant * 8
+ buttonSuccess = EV_DoFloor(line, args, FLEV_LOWERTIMES8INSTANT);
+ break;
+ case 67: // Floor Raise Instant * 8
+ buttonSuccess = EV_DoFloor(line, args, FLEV_RAISETIMES8INSTANT);
+ break;
+ case 68: // Floor Move to Value * 8
+ buttonSuccess = EV_DoFloor(line, args, FLEV_MOVETOVALUETIMES8);
+ break;
+ case 69: // Ceiling Move to Value * 8
+ buttonSuccess = EV_DoCeiling(line, args, CLEV_MOVETOVALUETIMES8);
+ break;
+ case 70: // Teleport
+ if (side == 0)
+ { // Only teleport when crossing the front side of a line
+ buttonSuccess = EV_Teleport(args[0], mo, true);
+ }
+ break;
+ case 71: // Teleport, no fog
+ if (side == 0)
+ { // Only teleport when crossing the front side of a line
+ buttonSuccess = EV_Teleport(args[0], mo, false);
+ }
+ break;
+ case 72: // Thrust Mobj
+ if (!side) // Only thrust on side 0
+ {
+ P_ThrustMobj(mo, args[0]*(ANGLE_90/64), args[1]<<FRACBITS);
+ buttonSuccess = 1;
+ }
+ break;
+ case 73: // Damage Mobj
+ if (args[0])
+ {
+ P_DamageMobj(mo, NULL, NULL, args[0]);
+ }
+ else
+ { // If arg1 is zero, then guarantee a kill
+ P_DamageMobj(mo, NULL, NULL, 10000);
+ }
+ buttonSuccess = 1;
+ break;
+ case 74: // Teleport_NewMap
+ if (side == 0)
+ { // Only teleport when crossing the front side of a line
+ // Players must be alive to teleport
+ if (!(mo && mo->player && mo->player->playerstate == PST_DEAD))
+ {
+ G_Completed(args[0], args[1]);
+ buttonSuccess = true;
+ }
+ }
+ break;
+ case 75: // Teleport_EndGame
+ if (side == 0)
+ { // Only teleport when crossing the front side of a line
+ // Players must be alive to teleport
+ if (!(mo && mo->player && mo->player->playerstate == PST_DEAD))
+ {
+ buttonSuccess = true;
+ if (deathmatch)
+ { // Winning in deathmatch just goes back to map 1
+ G_Completed(1, 0);
+ }
+ else
+ { // Passing -1, -1 to G_Completed() starts the Finale
+ G_Completed(-1, -1);
+ }
+ }
+ }
+ break;
+ case 80: // ACS_Execute
+ buttonSuccess = P_StartACS(args[0], args[1], &args[2], mo, line, side);
+ break;
+ case 81: // ACS_Suspend
+ buttonSuccess = P_SuspendACS(args[0], args[1]);
+ break;
+ case 82: // ACS_Terminate
+ buttonSuccess = P_TerminateACS(args[0], args[1]);
+ break;
+ case 83: // ACS_LockedExecute
+ buttonSuccess = P_StartLockedACS(line, args, mo, side);
+ break;
+ case 90: // Poly Rotate Left Override
+ buttonSuccess = EV_RotatePoly(line, args, 1, true);
+ break;
+ case 91: // Poly Rotate Right Override
+ buttonSuccess = EV_RotatePoly(line, args, -1, true);
+ break;
+ case 92: // Poly Move Override
+ buttonSuccess = EV_MovePoly(line, args, false, true);
+ break;
+ case 93: // Poly Move Times 8 Override
+ buttonSuccess = EV_MovePoly(line, args, true, true);
+ break;
+ case 94: // Build Pillar Crush
+ buttonSuccess = EV_BuildPillar(line, args, true);
+ break;
+ case 95: // Lower Floor and Ceiling
+ buttonSuccess = EV_DoFloorAndCeiling(line, args, false);
+ break;
+ case 96: // Raise Floor and Ceiling
+ buttonSuccess = EV_DoFloorAndCeiling(line, args, true);
+ break;
+ case 109: // Force Lightning
+ buttonSuccess = true;
+ P_ForceLightning();
+ break;
+ case 110: // Light Raise by Value
+ buttonSuccess = EV_SpawnLight(line, args, LITE_RAISEBYVALUE);
+ break;
+ case 111: // Light Lower by Value
+ buttonSuccess = EV_SpawnLight(line, args, LITE_LOWERBYVALUE);
+ break;
+ case 112: // Light Change to Value
+ buttonSuccess = EV_SpawnLight(line, args, LITE_CHANGETOVALUE);
+ break;
+ case 113: // Light Fade
+ buttonSuccess = EV_SpawnLight(line, args, LITE_FADE);
+ break;
+ case 114: // Light Glow
+ buttonSuccess = EV_SpawnLight(line, args, LITE_GLOW);
+ break;
+ case 115: // Light Flicker
+ buttonSuccess = EV_SpawnLight(line, args, LITE_FLICKER);
+ break;
+ case 116: // Light Strobe
+ buttonSuccess = EV_SpawnLight(line, args, LITE_STROBE);
+ break;
+ case 120: // Quake Tremor
+ buttonSuccess = A_LocalQuake(args, mo);
+ break;
+ case 129: // UsePuzzleItem
+ buttonSuccess = EV_LineSearchForPuzzleItem(line, args, mo);
+ break;
+ case 130: // Thing_Activate
+ buttonSuccess = EV_ThingActivate(args[0]);
+ break;
+ case 131: // Thing_Deactivate
+ buttonSuccess = EV_ThingDeactivate(args[0]);
+ break;
+ case 132: // Thing_Remove
+ buttonSuccess = EV_ThingRemove(args[0]);
+ break;
+ case 133: // Thing_Destroy
+ buttonSuccess = EV_ThingDestroy(args[0]);
+ break;
+ case 134: // Thing_Projectile
+ buttonSuccess = EV_ThingProjectile(args, 0);
+ break;
+ case 135: // Thing_Spawn
+ buttonSuccess = EV_ThingSpawn(args, 1);
+ break;
+ case 136: // Thing_ProjectileGravity
+ buttonSuccess = EV_ThingProjectile(args, 1);
+ break;
+ case 137: // Thing_SpawnNoFog
+ buttonSuccess = EV_ThingSpawn(args, 0);
+ break;
+ case 138: // Floor_Waggle
+ buttonSuccess = EV_StartFloorWaggle(args[0], args[1], args[2],
+ args[3], args[4]);
+ break;
+ case 140: // Sector_SoundChange
+ buttonSuccess = EV_SectorSoundChange(args);
+ break;
+
+ // Line specials only processed during level initialization
+ // 100: Scroll_Texture_Left
+ // 101: Scroll_Texture_Right
+ // 102: Scroll_Texture_Up
+ // 103: Scroll_Texture_Down
+ // 121: Line_SetIdentification
+
+ // Inert Line specials
+ default:
+ break;
+ }
+ return buttonSuccess;
+}
+
+//============================================================================
+//
+// P_ActivateLine
+//
+//============================================================================
+
+boolean P_ActivateLine(line_t *line, mobj_t *mo, int side, int activationType)
+{
+ int lineActivation;
+ boolean repeat;
+ boolean buttonSuccess;
+
+ lineActivation = GET_SPAC(line->flags);
+ if (lineActivation != activationType)
+ {
+ return false;
+ }
+ if (!mo->player && !(mo->flags&MF_MISSILE))
+ {
+ if (lineActivation != SPAC_MCROSS)
+ { // currently, monsters can only activate the MCROSS activation type
+ return false;
+ }
+ if (line->flags & ML_SECRET)
+ return false; // never open secret doors
+ }
+ repeat = line->flags & ML_REPEAT_SPECIAL;
+ buttonSuccess = false;
+
+ buttonSuccess = P_ExecuteLineSpecial(line->special, &line->arg1, line, side, mo);
+ if (!repeat && buttonSuccess)
+ { // clear the special on non-retriggerable lines
+ line->special = 0;
+ }
+ if ((lineActivation == SPAC_USE || lineActivation == SPAC_IMPACT) && buttonSuccess)
+ {
+ P_ChangeSwitchTexture(line, repeat);
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerInSpecialSector
+//
+// Called every tic frame that the player origin is in a special sector.
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerInSpecialSector(player_t *player)
+{
+ sector_t *sector;
+ static int pushTab[3] =
+ {
+ 2048*5,
+ 2048*10,
+ 2048*25
+ };
+
+ sector = player->mo->subsector->sector;
+ if (player->mo->z != sector->floorheight)
+ { // Player is not touching the floor
+ return;
+ }
+ switch (sector->special)
+ {
+ case 9: // SecretArea
+ player->secretcount++;
+ sector->special = 0;
+ break;
+
+ case 201: case 202: case 203: // Scroll_North_xxx
+ P_Thrust(player, ANG90, pushTab[sector->special-201]);
+ break;
+ case 204: case 205: case 206: // Scroll_East_xxx
+ P_Thrust(player, 0, pushTab[sector->special-204]);
+ break;
+ case 207: case 208: case 209: // Scroll_South_xxx
+ P_Thrust(player, ANG270, pushTab[sector->special-207]);
+ break;
+ case 210: case 211: case 212: // Scroll_West_xxx
+ P_Thrust(player, ANG180, pushTab[sector->special-210]);
+ break;
+ case 213: case 214: case 215: // Scroll_NorthWest_xxx
+ P_Thrust(player, ANG90+ANG45, pushTab[sector->special-213]);
+ break;
+ case 216: case 217: case 218: // Scroll_NorthEast_xxx
+ P_Thrust(player, ANG45, pushTab[sector->special-216]);
+ break;
+ case 219: case 220: case 221: // Scroll_SouthEast_xxx
+ P_Thrust(player, ANG270+ANG45, pushTab[sector->special-219]);
+ break;
+ case 222: case 223: case 224: // Scroll_SouthWest_xxx
+ P_Thrust(player, ANG180+ANG45, pushTab[sector->special-222]);
+ break;
+
+ case 40: case 41: case 42: case 43: case 44: case 45:
+ case 46: case 47: case 48: case 49: case 50: case 51:
+ // Wind specials are handled in (P_mobj):P_XYMovement
+ break;
+
+ case 26: // Stairs_Special1
+ case 27: // Stairs_Special2
+ // Used in (P_floor):ProcessStairSector
+ break;
+
+ case 198: // Lightning Special
+ case 199: // Lightning Flash special
+ case 200: // Sky2
+ // Used in (R_plane):R_Drawplanes
+ break;
+
+ default:
+ I_Error("P_PlayerInSpecialSector: "
+ "unknown special %i", sector->special);
+ }
+}
+
+//============================================================================
+//
+// P_PlayerOnSpecialFlat
+//
+//============================================================================
+
+void P_PlayerOnSpecialFlat(player_t *player, int floorType)
+{
+ if (player->mo->z != player->mo->floorz)
+ { // Player is not touching the floor
+ return;
+ }
+ switch (floorType)
+ {
+ case FLOOR_LAVA:
+ if (!(leveltime & 31))
+ {
+ P_DamageMobj(player->mo, &LavaInflictor, NULL, 10);
+ S_StartSound(player->mo, SFX_LAVA_SIZZLE);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_UpdateSpecials
+//
+//----------------------------------------------------------------------------
+
+void P_UpdateSpecials(void)
+{
+ int i;
+
+ // Handle buttons
+ for (i = 0; i < MAXBUTTONS; i++)
+ {
+ if (buttonlist[i].btimer)
+ {
+ buttonlist[i].btimer--;
+ if (!buttonlist[i].btimer)
+ {
+ switch (buttonlist[i].where)
+ {
+ case SWTCH_TOP:
+ sides[buttonlist[i].line->sidenum[0]].toptexture =
+ buttonlist[i].btexture;
+ break;
+ case SWTCH_MIDDLE:
+ sides[buttonlist[i].line->sidenum[0]].midtexture =
+ buttonlist[i].btexture;
+ break;
+ case SWTCH_BOTTOM:
+ sides[buttonlist[i].line->sidenum[0]].bottomtexture =
+ buttonlist[i].btexture;
+ break;
+ }
+ //S_StartSound(buttonlist[i].soundorg, sfx_switch);
+ memset(&buttonlist[i], 0, sizeof(button_t));
+ }
+ }
+ }
+}
+
+/*
+==============================================================================
+
+ SPECIAL SPAWNING
+
+==============================================================================
+*/
+
+/*
+================================================================================
+= P_SpawnSpecials
+=
+= After the map has been loaded, scan for specials that
+= spawn thinkers
+=
+===============================================================================
+*/
+
+short numlinespecials;
+line_t *linespeciallist[MAXLINEANIMS];
+
+void P_SpawnSpecials (void)
+{
+ sector_t *sector;
+ int i;
+
+ //
+ // Init special SECTORs
+ //
+ sector = sectors;
+ for (i = 0; i < numsectors; i++, sector++)
+ {
+ if (!sector->special)
+ continue;
+ switch (sector->special)
+ {
+ case 1: // Phased light
+ // Hardcoded base, use sector->lightlevel as the index
+ P_SpawnPhasedLight(sector, 80, -1);
+ break;
+ case 2: // Phased light sequence start
+ P_SpawnLightSequence(sector, 1);
+ break;
+ // Specials 3 & 4 are used by the phased light sequences
+
+ /*
+ case 1: // FLICKERING LIGHTS
+ P_SpawnLightFlash (sector);
+ break;
+ case 2: // STROBE FAST
+ P_SpawnStrobeFlash(sector, FASTDARK, 0);
+ break;
+ case 3: // STROBE SLOW
+ P_SpawnStrobeFlash(sector, SLOWDARK, 0);
+ break;
+ case 4: // STROBE FAST/DEATH SLIME
+ P_SpawnStrobeFlash(sector, FASTDARK, 0);
+ sector->special = 4;
+ break;
+ case 8: // GLOWING LIGHT
+ P_SpawnGlowingLight(sector);
+ break;
+ case 9: // SECRET SECTOR
+ totalsecret++;
+ break;
+ case 10: // DOOR CLOSE IN 30 SECONDS
+ P_SpawnDoorCloseIn30 (sector);
+ break;
+ case 12: // SYNC STROBE SLOW
+ P_SpawnStrobeFlash(sector, SLOWDARK, 1);
+ break;
+ case 13: // SYNC STROBE FAST
+ P_SpawnStrobeFlash(sector, FASTDARK, 1);
+ break;
+ case 14: // DOOR RAISE IN 5 MINUTES
+ P_SpawnDoorRaiseIn5Mins (sector, i);
+ break;
+ */
+ }
+ }
+
+ //
+ // Init line EFFECTs
+ //
+ numlinespecials = 0;
+ TaggedLineCount = 0;
+ for (i = 0; i < numlines; i++)
+ {
+ switch (lines[i].special)
+ {
+ case 100: // Scroll_Texture_Left
+ case 101: // Scroll_Texture_Right
+ case 102: // Scroll_Texture_Up
+ case 103: // Scroll_Texture_Down
+ linespeciallist[numlinespecials] = &lines[i];
+ numlinespecials++;
+ break;
+ case 121: // Line_SetIdentification
+ if (lines[i].arg1)
+ {
+ if (TaggedLineCount == MAX_TAGGED_LINES)
+ {
+ I_Error("P_SpawnSpecials: MAX_TAGGED_LINES "
+ "(%d) exceeded.", MAX_TAGGED_LINES);
+ }
+ TaggedLines[TaggedLineCount].line = &lines[i];
+ TaggedLines[TaggedLineCount++].lineTag = lines[i].arg1;
+ }
+ lines[i].special = 0;
+ break;
+ }
+ }
+
+ //
+ // Init other misc stuff
+ //
+ for (i = 0; i < MAXCEILINGS; i++)
+ activeceilings[i] = NULL;
+ for (i = 0; i < MAXPLATS; i++)
+ activeplats[i] = NULL;
+ for (i = 0; i < MAXBUTTONS; i++)
+ memset(&buttonlist[i], 0, sizeof(button_t));
+
+ // Initialize flat and texture animations
+ P_InitFTAnims();
+}
+
+//==========================================================================
+//
+// P_FindLine
+//
+//==========================================================================
+
+line_t *P_FindLine(int lineTag, int *searchPosition)
+{
+ int i;
+
+ for (i = *searchPosition + 1; i < TaggedLineCount; i++)
+ {
+ if (TaggedLines[i].lineTag == lineTag)
+ {
+ *searchPosition = i;
+ return TaggedLines[i].line;
+ }
+ }
+ *searchPosition = -1;
+ return NULL;
+}
+
--- /dev/null
+++ b/p_spec.h
@@ -1,0 +1,529 @@
+
+//**************************************************************************
+//**
+//** p_spec.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __P_SPEC__
+#define __P_SPEC__
+
+extern int *TerrainTypes;
+
+
+/* scrolling line specials */
+
+#define MAXLINEANIMS 64
+
+extern short numlinespecials;
+extern line_t *linespeciallist[MAXLINEANIMS];
+
+/* Define values for map objects */
+#define MO_TELEPORTMAN 14
+
+/* at game start */
+void P_InitTerrainTypes(void);
+void P_InitLava(void);
+
+/* at map load */
+void P_SpawnSpecials(void);
+
+/* every tic */
+void P_UpdateSpecials(void);
+
+/* when needed */
+boolean P_ExecuteLineSpecial(int special, byte *args, line_t *line, int side, mobj_t *mo);
+boolean P_ActivateLine(line_t *ld, mobj_t *mo, int side, int activationType);
+/*
+boolean P_UseSpecialLine ( mobj_t *thing, line_t *line);
+void P_ShootSpecialLine ( mobj_t *thing, line_t *line);
+void P_CrossSpecialLine (int linenum, int side, mobj_t *thing);
+*/
+
+void P_PlayerInSpecialSector(player_t *player);
+void P_PlayerOnSpecialFlat(player_t *player, int floorType);
+
+/*
+int twoSided(int sector,int line);
+sector_t *getSector(int currentSector,int line,int side);
+side_t *getSide(int currentSector,int line, int side);
+*/
+fixed_t P_FindLowestFloorSurrounding(sector_t *sec);
+fixed_t P_FindHighestFloorSurrounding(sector_t *sec);
+fixed_t P_FindNextHighestFloor(sector_t *sec,int currentheight);
+fixed_t P_FindLowestCeilingSurrounding(sector_t *sec);
+fixed_t P_FindHighestCeilingSurrounding(sector_t *sec);
+int P_FindSectorFromTag(int tag, int start);
+/*
+int P_FindSectorFromLineTag(line_t *line,int start);
+int P_FindMinSurroundingLight(sector_t *sector,int max);
+*/
+sector_t *getNextSector(line_t *line,sector_t *sec);
+line_t *P_FindLine(int lineTag, int *searchPosition);
+
+
+/* ---- SPECIAL ---- */
+
+/*
+int EV_DoDonut(line_t *line);
+*/
+
+
+/* ---- P_anim.c ---- */
+
+void P_AnimateSurfaces(void);
+void P_InitFTAnims(void);
+void P_InitLightning(void);
+void P_ForceLightning(void);
+
+
+/* ---- P_LIGHTS ---- */
+
+typedef enum
+{
+ LITE_RAISEBYVALUE,
+ LITE_LOWERBYVALUE,
+ LITE_CHANGETOVALUE,
+ LITE_FADE,
+ LITE_GLOW,
+ LITE_FLICKER,
+ LITE_STROBE
+} lighttype_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ lighttype_t type;
+ int value1;
+ int value2;
+ int tics1;
+ int tics2;
+ int count;
+} light_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ int index;
+ int base;
+} phase_t;
+
+#define LIGHT_SEQUENCE_START 2
+#define LIGHT_SEQUENCE 3
+#define LIGHT_SEQUENCE_ALT 4
+
+void T_Phase(phase_t *phase);
+void T_Light(light_t *light);
+void P_SpawnPhasedLight(sector_t *sector, int base, int idx);
+void P_SpawnLightSequence(sector_t *sector, int indexStep);
+boolean EV_SpawnLight(line_t *line, byte *arg, lighttype_t type);
+
+#if 0
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ int count;
+ int maxlight;
+ int minlight;
+ int maxtime;
+ int mintime;
+} lightflash_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ int count;
+ int minlight;
+ int maxlight;
+ int darktime;
+ int brighttime;
+} strobe_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ int minlight;
+ int maxlight;
+ int direction;
+} glow_t;
+
+#define GLOWSPEED 8
+#define STROBEBRIGHT 5
+#define FASTDARK 15
+#define SLOWDARK 35
+
+void T_LightFlash (lightflash_t *flash);
+void P_SpawnLightFlash (sector_t *sector);
+void T_StrobeFlash (strobe_t *flash);
+void P_SpawnStrobeFlash (sector_t *sector, int fastOrSlow, int inSync);
+void EV_StartLightStrobing(line_t *line);
+void EV_TurnTagLightsOff(line_t *line);
+void EV_LightTurnOn(line_t *line, int bright);
+void T_Glow(glow_t *g);
+void P_SpawnGlowingLight(sector_t *sector);
+void T_Phase(phase_t *phase);
+void P_SpawnPhasedLight(sector_t *sector, int base, int idx);
+void P_SpawnLightSequence(sector_t *sector, int indexStep);
+#endif
+
+
+/* ---- P_SWITCH ---- */
+
+typedef struct
+{
+ const char name1[9];
+ const char name2[9];
+ int soundID;
+} switchlist_t;
+
+typedef enum
+{
+ SWTCH_TOP,
+ SWTCH_MIDDLE,
+ SWTCH_BOTTOM
+} bwhere_e;
+
+typedef struct
+{
+ line_t *line;
+ bwhere_e where;
+ int btexture;
+ int btimer;
+ mobj_t *soundorg;
+} button_t;
+
+#define MAXSWITCHES 50 /* max # of wall switches in a level */
+#define MAXBUTTONS 16 /* 4 players, 4 buttons each at once, max. */
+#define BUTTONTIME 35 /* 1 second */
+
+extern button_t buttonlist[MAXBUTTONS];
+
+void P_ChangeSwitchTexture(line_t *line, int useAgain);
+void P_InitSwitchList(void);
+
+
+/* ---- P_PLATS ---- */
+
+typedef enum
+{
+ PLAT_UP,
+ PLAT_DOWN,
+ PLAT_WAITING,
+ /*
+ PLAT_IN_STASIS
+ */
+} plat_e;
+
+typedef enum
+{
+ PLAT_PERPETUALRAISE,
+ PLAT_DOWNWAITUPSTAY,
+ PLAT_DOWNBYVALUEWAITUPSTAY,
+ PLAT_UPWAITDOWNSTAY,
+ PLAT_UPBYVALUEWAITDOWNSTAY,
+ /*
+ PLAT_RAISEANDCHANGE,
+ PLAT_RAISETONEARESTANDCHANGE
+ */
+} plattype_e;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ fixed_t speed;
+ fixed_t low;
+ fixed_t high;
+ int wait;
+ int count;
+ plat_e status;
+ plat_e oldstatus;
+ int crush;
+ int tag;
+ plattype_e type;
+} plat_t;
+
+#define PLATWAIT 3
+#define PLATSPEED FRACUNIT
+#define MAXPLATS 30
+
+extern plat_t *activeplats[MAXPLATS];
+
+void T_PlatRaise(plat_t *plat);
+int EV_DoPlat(line_t *line, byte *args, plattype_e type, int amount);
+void P_AddActivePlat(plat_t *plat);
+void P_RemoveActivePlat(plat_t *plat);
+void EV_StopPlat(line_t *line, byte *args);
+
+
+/* ---- P_DOORS ---- */
+
+typedef enum
+{
+ DREV_NORMAL,
+ DREV_CLOSE30THENOPEN,
+ DREV_CLOSE,
+ DREV_OPEN,
+ DREV_RAISEIN5MINS
+} vldoor_e;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ vldoor_e type;
+ fixed_t topheight;
+ fixed_t speed;
+ int direction; /* 1 = up, 0 = waiting at top, -1 = down */
+ int topwait; /* tics to wait at the top (keep in case a door going down is reset) */
+ int topcountdown; /* when it reaches 0, start going down */
+} vldoor_t;
+
+#define VDOORSPEED (FRACUNIT * 2)
+#define VDOORWAIT 150
+
+boolean EV_VerticalDoor(line_t *line, mobj_t *thing);
+int EV_DoDoor(line_t *line, byte *args, vldoor_e type);
+void T_VerticalDoor(vldoor_t *door);
+/*
+void P_SpawnDoorCloseIn30(sector_t *sec);
+void P_SpawnDoorRaiseIn5Mins(sector_t *sec, int secnum);
+*/
+
+
+/* ---- P_CEILNG ---- */
+
+typedef enum
+{
+ CLEV_LOWERTOFLOOR,
+ CLEV_RAISETOHIGHEST,
+ CLEV_LOWERANDCRUSH,
+ CLEV_CRUSHANDRAISE,
+ CLEV_LOWERBYVALUE,
+ CLEV_RAISEBYVALUE,
+ CLEV_CRUSHRAISEANDSTAY,
+ CLEV_MOVETOVALUETIMES8
+} ceiling_e;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ ceiling_e type;
+ fixed_t bottomheight, topheight;
+ fixed_t speed;
+ int crush;
+ int direction; /* 1 = up, 0 = waiting, -1 = down */
+ int tag; /* ID */
+ int olddirection;
+} ceiling_t;
+
+#define CEILSPEED FRACUNIT
+#define CEILWAIT 150
+#define MAXCEILINGS 30
+
+extern ceiling_t *activeceilings[MAXCEILINGS];
+
+int EV_DoCeiling(line_t *line, byte *args, ceiling_e type);
+void T_MoveCeiling(ceiling_t *ceiling);
+void P_AddActiveCeiling(ceiling_t *c);
+void P_RemoveActiveCeiling(ceiling_t *c);
+int EV_CeilingCrushStop(line_t *line, byte *args);
+
+
+/* ---- P_FLOOR ---- */
+
+typedef enum
+{
+ FLEV_LOWERFLOOR, /* lower floor to highest surrounding floor */
+ FLEV_LOWERFLOORTOLOWEST, /* lower floor to lowest surrounding floor */
+ FLEV_LOWERFLOORBYVALUE,
+ FLEV_RAISEFLOOR, /* raise floor to lowest surrounding CEILING */
+ FLEV_RAISEFLOORTONEAREST, /* raise floor to next highest surrounding floor */
+ FLEV_RAISEFLOORBYVALUE,
+ FLEV_RAISEFLOORCRUSH,
+ FLEV_RAISEBUILDSTEP, /* One step of a staircase */
+ FLEV_RAISEBYVALUETIMES8,
+ FLEV_LOWERBYVALUETIMES8,
+ FLEV_LOWERTIMES8INSTANT,
+ FLEV_RAISETIMES8INSTANT,
+ FLEV_MOVETOVALUETIMES8
+} floor_e;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ floor_e type;
+ int crush;
+ int direction;
+ int newspecial;
+ short texture;
+ fixed_t floordestheight;
+ fixed_t speed;
+ int delayCount;
+ int delayTotal;
+ fixed_t stairsDelayHeight;
+ fixed_t stairsDelayHeightDelta;
+ fixed_t resetHeight;
+ short resetDelay;
+ short resetDelayCount;
+ byte textureChange;
+} floormove_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ int ceilingSpeed;
+ int floorSpeed;
+ int floordest;
+ int ceilingdest;
+ int direction;
+ int crush;
+} pillar_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+ fixed_t originalHeight;
+ fixed_t accumulator;
+ fixed_t accDelta;
+ fixed_t targetScale;
+ fixed_t scale;
+ fixed_t scaleDelta;
+ int ticker;
+ int state;
+} floorWaggle_t;
+
+#define FLOORSPEED FRACUNIT
+
+typedef enum
+{
+ RES_OK,
+ RES_CRUSHED,
+ RES_PASTDEST
+} result_e;
+
+typedef enum
+{
+ STAIRS_NORMAL,
+ STAIRS_SYNC,
+ STAIRS_PHASED
+} stairs_e;
+
+result_e T_MovePlane(sector_t *sector, fixed_t speed,
+ fixed_t dest, int crush, int floorOrCeiling, int direction);
+
+int EV_BuildStairs(line_t *line, byte *args, int direction, stairs_e type);
+int EV_DoFloor(line_t *line, byte *args, floor_e floortype);
+void T_MoveFloor(floormove_t *floor);
+void T_BuildPillar(pillar_t *pillar);
+void T_FloorWaggle(floorWaggle_t *waggle);
+int EV_BuildPillar(line_t *line, byte *args, boolean crush);
+int EV_OpenPillar(line_t *line, byte *args);
+int EV_DoFloorAndCeiling(line_t *line, byte *args, boolean raise);
+int EV_FloorCrushStop(line_t *line, byte *args);
+boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset, int timer);
+
+
+/* ---- p_telept ---- */
+
+boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, angle_t angle, boolean useFog);
+boolean EV_Teleport(int tid, mobj_t *thing, boolean fog);
+
+
+/* ---- p_acs ---- */
+
+#define MAX_ACS_SCRIPT_VARS 10
+#define MAX_ACS_MAP_VARS 32
+#define MAX_ACS_WORLD_VARS 64
+#define ACS_STACK_DEPTH 32
+#define MAX_ACS_STORE 20
+
+typedef enum
+{
+ ASTE_INACTIVE,
+ ASTE_RUNNING,
+ ASTE_SUSPENDED,
+ ASTE_WAITINGFORTAG,
+ ASTE_WAITINGFORPOLY,
+ ASTE_WAITINGFORSCRIPT,
+ ASTE_TERMINATING
+} aste_t;
+
+typedef struct acs_s acs_t;
+typedef struct acsInfo_s acsInfo_t;
+
+struct acsInfo_s
+{
+ int number;
+ byte *address;
+ int argCount;
+ aste_t state;
+ int waitValue;
+};
+
+struct acs_s
+{
+ thinker_t thinker;
+ mobj_t *activator;
+ line_t *line;
+ int side;
+ int number;
+ int infoIndex;
+ int delayCount;
+ int stack[ACS_STACK_DEPTH];
+ int stackPtr;
+ int vars[MAX_ACS_SCRIPT_VARS];
+ byte *ip;
+};
+
+typedef struct
+{
+ int map; /* Target map */
+ int script; /* Script number on target map */
+ byte args[4]; /* Padded to 4 for alignment */
+} acsstore_t;
+
+void P_LoadACScripts(int lump);
+boolean P_StartACS(int number, int map, byte *args, mobj_t *activator, line_t *line, int side);
+boolean P_StartLockedACS(line_t *line, byte *args, mobj_t *mo, int side);
+boolean P_TerminateACS(int number, int map);
+boolean P_SuspendACS(int number, int map);
+void T_InterpretACS(acs_t *script);
+void P_TagFinished(int tag);
+void P_PolyobjFinished(int po);
+void P_ACSInitNewGame(void);
+void P_CheckACSStore(void);
+
+extern int ACScriptCount;
+extern byte *ActionCodeBase;
+extern acsInfo_t *ACSInfo;
+extern int MapVars[MAX_ACS_MAP_VARS];
+extern int WorldVars[MAX_ACS_WORLD_VARS];
+extern acsstore_t ACSStore[MAX_ACS_STORE + 1]; /* +1 for termination marker */
+
+
+/* ---- p_things ---- */
+
+extern mobjtype_t TranslateThingType[];
+
+boolean EV_ThingProjectile(byte *args, boolean gravity);
+boolean EV_ThingSpawn(byte *args, boolean fog);
+boolean EV_ThingActivate(int tid);
+boolean EV_ThingDeactivate(int tid);
+boolean EV_ThingRemove(int tid);
+boolean EV_ThingDestroy(int tid);
+
+#endif /* __P_SPEC__ */
+
--- /dev/null
+++ b/p_switch.c
@@ -1,0 +1,166 @@
+
+//**************************************************************************
+//**
+//** p_switch.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+//==================================================================
+//
+// CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE
+//
+//==================================================================
+
+static switchlist_t alphSwitchListDemo[] =
+{
+ { "SW_1_UP", "SW_1_DN", SFX_SWITCH1 },
+ { "SW_2_UP", "SW_2_DN", SFX_SWITCH1 },
+ { "SW52_OFF", "SW52_ON", SFX_SWITCH2 },
+ { "\0", "\0", 0}
+};
+
+static switchlist_t alphSwitchListFull[] =
+{
+ { "SW_1_UP", "SW_1_DN", SFX_SWITCH1 },
+ { "SW_2_UP", "SW_2_DN", SFX_SWITCH1 },
+ { "VALVE1", "VALVE2", SFX_VALVE_TURN },
+ { "SW51_OFF", "SW51_ON", SFX_SWITCH2 },
+ { "SW52_OFF", "SW52_ON", SFX_SWITCH2 },
+ { "SW53_UP", "SW53_DN", SFX_ROPE_PULL },
+ { "PUZZLE5", "PUZZLE9", SFX_SWITCH1 },
+ { "PUZZLE6", "PUZZLE10", SFX_SWITCH1 },
+ { "PUZZLE7", "PUZZLE11", SFX_SWITCH1 },
+ { "PUZZLE8", "PUZZLE12", SFX_SWITCH1 },
+ { "\0", "\0", 0}
+};
+
+static switchlist_t *alphSwitchList = NULL;
+
+static int switchlist[MAXSWITCHES * 2];
+static int numswitches;
+
+button_t buttonlist[MAXBUTTONS];
+
+
+/*
+===============
+=
+= P_InitSwitchList
+=
+= Only called at game initialization
+=
+===============
+*/
+
+void P_InitSwitchList(void)
+{
+ int i;
+ int idx;
+
+ if (alphSwitchList == NULL)
+ {
+ alphSwitchList = (shareware && oldwad_10) ? alphSwitchListDemo : alphSwitchListFull;
+ }
+
+ for (idx = 0, i = 0; i < MAXSWITCHES; i++)
+ {
+ if (!alphSwitchList[i].soundID)
+ {
+ numswitches = idx/2;
+ switchlist[idx] = -1;
+ break;
+ }
+ switchlist[idx++] = R_TextureNumForName(alphSwitchList[i].name1);
+ switchlist[idx++] = R_TextureNumForName(alphSwitchList[i].name2);
+ }
+}
+
+//==================================================================
+//
+// Start a button counting down till it turns off.
+//
+//==================================================================
+
+void P_StartButton(line_t *line, bwhere_e w, int texture, int timer)
+{
+ int i;
+
+ for (i = 0;i < MAXBUTTONS;i++)
+ {
+ if (!buttonlist[i].btimer)
+ {
+ buttonlist[i].line = line;
+ buttonlist[i].where = w;
+ buttonlist[i].btexture = texture;
+ buttonlist[i].btimer = timer;
+ buttonlist[i].soundorg = (mobj_t *)(void *)&line->frontsector->soundorg;
+ return;
+ }
+ }
+ I_Error("P_StartButton: no button slots left!");
+}
+
+//==================================================================
+//
+// Function that changes wall texture.
+// Tell it if switch is ok to use again (1=yes, it's a button).
+//
+//==================================================================
+
+void P_ChangeSwitchTexture(line_t *line, int useAgain)
+{
+ int texTop;
+ int texMid;
+ int texBot;
+ int i;
+
+ texTop = sides[line->sidenum[0]].toptexture;
+ texMid = sides[line->sidenum[0]].midtexture;
+ texBot = sides[line->sidenum[0]].bottomtexture;
+
+ for (i = 0; i < numswitches*2; i++)
+ {
+ if (switchlist[i] == texTop)
+ {
+ S_StartSound((mobj_t *)(void *)&line->frontsector->soundorg,
+ alphSwitchList[i/2].soundID);
+ sides[line->sidenum[0]].toptexture = switchlist[i^1];
+ if (useAgain)
+ {
+ P_StartButton(line, SWTCH_TOP, switchlist[i], BUTTONTIME);
+ }
+ return;
+ }
+ else if (switchlist[i] == texMid)
+ {
+ S_StartSound((mobj_t *)(void *)&line->frontsector->soundorg,
+ alphSwitchList[i/2].soundID);
+ sides[line->sidenum[0]].midtexture = switchlist[i^1];
+ if (useAgain)
+ {
+ P_StartButton(line, SWTCH_MIDDLE, switchlist[i], BUTTONTIME);
+ }
+ return;
+ }
+ else if (switchlist[i] == texBot)
+ {
+ S_StartSound((mobj_t *)(void *)&line->frontsector->soundorg,
+ alphSwitchList[i/2].soundID);
+ sides[line->sidenum[0]].bottomtexture = switchlist[i^1];
+ if (useAgain)
+ {
+ P_StartButton(line, SWTCH_BOTTOM, switchlist[i], BUTTONTIME);
+ }
+ return;
+ }
+ }
+}
+
--- /dev/null
+++ b/p_telept.c
@@ -1,0 +1,177 @@
+
+//**************************************************************************
+//**
+//** p_telept.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_Teleport
+//
+//==========================================================================
+
+boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, angle_t angle,
+ boolean useFog)
+{
+ fixed_t oldx;
+ fixed_t oldy;
+ fixed_t oldz;
+ fixed_t aboveFloor;
+ fixed_t fogDelta;
+ player_t *player;
+ unsigned int an;
+ mobj_t *fog;
+
+ oldx = thing->x;
+ oldy = thing->y;
+ oldz = thing->z;
+ aboveFloor = thing->z - thing->floorz;
+ if (!P_TeleportMove(thing, x, y))
+ {
+ return false;
+ }
+ if (thing->player)
+ {
+ player = thing->player;
+ if (player->powers[pw_flight] && aboveFloor)
+ {
+ thing->z = thing->floorz+aboveFloor;
+ if (thing->z + thing->height > thing->ceilingz)
+ {
+ thing->z = thing->ceilingz - thing->height;
+ }
+ player->viewz = thing->z + player->viewheight;
+ }
+ else
+ {
+ thing->z = thing->floorz;
+ player->viewz = thing->z + player->viewheight;
+ if (useFog)
+ {
+ player->lookdir = 0;
+ }
+ }
+ }
+ else if (thing->flags & MF_MISSILE)
+ {
+ thing->z = thing->floorz + aboveFloor;
+ if (thing->z + thing->height > thing->ceilingz)
+ {
+ thing->z = thing->ceilingz - thing->height;
+ }
+ }
+ else
+ {
+ thing->z = thing->floorz;
+ }
+ // Spawn teleport fog at source and destination
+ if (useFog)
+ {
+ fogDelta = (thing->flags & MF_MISSILE) ? 0 : TELEFOGHEIGHT;
+ fog = P_SpawnMobj(oldx, oldy, oldz + fogDelta, MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ an = angle >> ANGLETOFINESHIFT;
+ fog = P_SpawnMobj(x + 20*finecosine[an], y + 20*finesine[an], thing->z + fogDelta, MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ if (thing->player && !thing->player->powers[pw_speed])
+ { // Freeze player for about .5 sec
+ thing->reactiontime = 18;
+ }
+ thing->angle = angle;
+ }
+ if (thing->flags2 & MF2_FLOORCLIP)
+ {
+ if (thing->z == thing->subsector->sector->floorheight
+ && P_GetThingFloorType(thing) > FLOOR_SOLID)
+ {
+ thing->floorclip = 10*FRACUNIT;
+ }
+ else
+ {
+ thing->floorclip = 0;
+ }
+ }
+ if (thing->flags & MF_MISSILE)
+ {
+ angle >>= ANGLETOFINESHIFT;
+ thing->momx = FixedMul(thing->info->speed, finecosine[angle]);
+ thing->momy = FixedMul(thing->info->speed, finesine[angle]);
+ }
+ else if (useFog) // no fog doesn't alter the player's momentums
+ {
+ thing->momx = thing->momy = thing->momz = 0;
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// EV_Teleport
+//
+//==========================================================================
+
+boolean EV_Teleport(int tid, mobj_t *thing, boolean fog)
+{
+ int i;
+ int count;
+ mobj_t *mo = NULL;
+ int searcher;
+
+ if (!thing)
+ { // Teleport function called with an invalid mobj
+ return false;
+ }
+ if (thing->flags2 & MF2_NOTELEPORT)
+ {
+ return false;
+ }
+ count = 0;
+ searcher = -1;
+ while (P_FindMobjFromTID(tid, &searcher) != NULL)
+ {
+ count++;
+ }
+ if (count == 0)
+ {
+ return false;
+ }
+ count = 1 + (P_Random() % count);
+ searcher = -1;
+ for (i = 0; i < count; i++)
+ {
+ mo = P_FindMobjFromTID(tid, &searcher);
+ }
+ if (!mo)
+ I_Error("Can't find teleport mapspot\n");
+ return P_Teleport(thing, mo->x, mo->y, mo->angle, fog);
+}
+
--- /dev/null
+++ b/p_things.c
@@ -1,0 +1,530 @@
+
+//**************************************************************************
+//**
+//** p_things.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static boolean ActivateThing(mobj_t *mobj);
+static boolean DeactivateThing(mobj_t *mobj);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+mobjtype_t TranslateThingType[] =
+{
+ MT_MAPSPOT, /* T_NONE */
+ MT_CENTAUR, /* T_CENTAUR */
+ MT_CENTAURLEADER, /* T_CENTAURLEADER */
+ MT_DEMON, /* T_DEMON */
+ MT_ETTIN, /* T_ETTIN */
+ MT_FIREDEMON, /* T_FIREGARGOYLE */
+ MT_SERPENT, /* T_WATERLURKER */
+ MT_SERPENTLEADER, /* T_WATERLURKERLEADER */
+ MT_WRAITH, /* T_WRAITH */
+ MT_WRAITHB, /* T_WRAITHBURIED */
+ MT_FIREBALL1, /* T_FIREBALL1 */
+ MT_MANA1, /* T_MANA1 */
+ MT_MANA2, /* T_MANA2 */
+ MT_SPEEDBOOTS, /* T_ITEMBOOTS */
+ MT_ARTIEGG, /* T_ITEMEGG */
+ MT_ARTIFLY, /* T_ITEMFLIGHT */
+ MT_SUMMONMAULATOR, /* T_ITEMSUMMON */
+ MT_TELEPORTOTHER, /* T_ITEMTPORTOTHER */
+ MT_ARTITELEPORT, /* T_ITEMTELEPORT */
+ MT_BISHOP, /* T_BISHOP */
+ MT_ICEGUY, /* T_ICEGOLEM */
+ MT_BRIDGE, /* T_BRIDGE */
+ MT_BOOSTARMOR, /* T_DRAGONSKINBRACERS */
+ MT_HEALINGBOTTLE, /* T_ITEMHEALTHPOTION */
+ MT_HEALTHFLASK, /* T_ITEMHEALTHFLASK */
+ MT_ARTISUPERHEAL, /* T_ITEMHEALTHFULL */
+ MT_BOOSTMANA, /* T_ITEMBOOSTMANA */
+ MT_FW_AXE, /* T_FIGHTERAXE */
+ MT_FW_HAMMER, /* T_FIGHTERHAMMER */
+ MT_FW_SWORD1, /* T_FIGHTERSWORD1 */
+ MT_FW_SWORD2, /* T_FIGHTERSWORD2 */
+ MT_FW_SWORD3, /* T_FIGHTERSWORD3 */
+ MT_CW_SERPSTAFF, /* T_CLERICSTAFF */
+ MT_CW_HOLY1, /* T_CLERICHOLY1 */
+ MT_CW_HOLY2, /* T_CLERICHOLY2 */
+ MT_CW_HOLY3, /* T_CLERICHOLY3 */
+ MT_MW_CONE, /* T_MAGESHARDS */
+ MT_MW_STAFF1, /* T_MAGESTAFF1 */
+ MT_MW_STAFF2, /* T_MAGESTAFF2 */
+ MT_MW_STAFF3, /* T_MAGESTAFF3 */
+ MT_EGGFX, /* T_MORPHBLAST */
+ MT_ROCK1, /* T_ROCK1 */
+ MT_ROCK2, /* T_ROCK2 */
+ MT_ROCK3, /* T_ROCK3 */
+ MT_DIRT1, /* T_DIRT1 */
+ MT_DIRT2, /* T_DIRT2 */
+ MT_DIRT3, /* T_DIRT3 */
+ MT_DIRT4, /* T_DIRT4 */
+ MT_DIRT5, /* T_DIRT5 */
+ MT_DIRT6, /* T_DIRT6 */
+ MT_ARROW, /* T_ARROW */
+ MT_DART, /* T_DART */
+ MT_POISONDART, /* T_POISONDART */
+ MT_RIPPERBALL, /* T_RIPPERBALL */
+ MT_SGSHARD1, /* T_STAINEDGLASS1 */
+ MT_SGSHARD2, /* T_STAINEDGLASS2 */
+ MT_SGSHARD3, /* T_STAINEDGLASS3 */
+ MT_SGSHARD4, /* T_STAINEDGLASS4 */
+ MT_SGSHARD5, /* T_STAINEDGLASS5 */
+ MT_SGSHARD6, /* T_STAINEDGLASS6 */
+ MT_SGSHARD7, /* T_STAINEDGLASS7 */
+ MT_SGSHARD8, /* T_STAINEDGLASS8 */
+ MT_SGSHARD9, /* T_STAINEDGLASS9 */
+ MT_SGSHARD0, /* T_STAINEDGLASS0 */
+ MT_PROJECTILE_BLADE, /* T_BLADE */
+ MT_ICESHARD, /* T_ICESHARD */
+ MT_FLAME_SMALL, /* T_FLAME_SMALL */
+ MT_FLAME_LARGE, /* T_FLAME_LARGE */
+ MT_ARMOR_1, /* T_MESHARMOR */
+ MT_ARMOR_2, /* T_FALCONSHIELD */
+ MT_ARMOR_3, /* T_PLATINUMHELM */
+ MT_ARMOR_4, /* T_AMULETOFWARDING */
+ MT_ARTIPOISONBAG, /* T_ITEMFLECHETTE */
+ MT_ARTITORCH, /* T_ITEMTORCH */
+ MT_BLASTRADIUS, /* T_ITEMREPULSION */
+ MT_MANA3, /* T_MANA3 */
+ MT_ARTIPUZZSKULL, /* T_PUZZSKULL */
+ MT_ARTIPUZZGEMBIG, /* T_PUZZGEMBIG */
+ MT_ARTIPUZZGEMRED, /* T_PUZZGEMRED */
+ MT_ARTIPUZZGEMGREEN1, /* T_PUZZGEMGREEN1 */
+ MT_ARTIPUZZGEMGREEN2, /* T_PUZZGEMGREEN2 */
+ MT_ARTIPUZZGEMBLUE1, /* T_PUZZGEMBLUE1 */
+ MT_ARTIPUZZGEMBLUE2, /* T_PUZZGEMBLUE2 */
+ MT_ARTIPUZZBOOK1, /* T_PUZZBOOK1 */
+ MT_ARTIPUZZBOOK2, /* T_PUZZBOOK2 */
+ MT_KEY1, /* T_METALKEY */
+ MT_KEY2, /* T_SMALLMETALKEY */
+ MT_KEY3, /* T_AXEKEY */
+ MT_KEY4, /* T_FIREKEY */
+ MT_KEY5, /* T_GREENKEY */
+ MT_KEY6, /* T_MACEKEY */
+ MT_KEY7, /* T_SILVERKEY */
+ MT_KEY8, /* T_RUSTYKEY */
+ MT_KEY9, /* T_HORNKEY */
+ MT_KEYA, /* T_SERPENTKEY */
+ MT_WATER_DRIP, /* T_WATERDRIP */
+ MT_FLAME_SMALL_TEMP, /* T_TEMPSMALLFLAME */
+ MT_FLAME_SMALL, /* T_PERMSMALLFLAME */
+ MT_FLAME_LARGE_TEMP, /* T_TEMPLARGEFLAME */
+ MT_FLAME_LARGE, /* T_PERMLARGEFLAME */
+ MT_DEMON_MASH, /* T_DEMON_MASH */
+ MT_DEMON2_MASH, /* T_DEMON2_MASH */
+ MT_ETTIN_MASH, /* T_ETTIN_MASH */
+ MT_CENTAUR_MASH, /* T_CENTAUR_MASH */
+ MT_THRUSTFLOOR_UP, /* T_THRUSTSPIKEUP */
+ MT_THRUSTFLOOR_DOWN, /* T_THRUSTSPIKEDOWN */
+ MT_WRAITHFX4, /* T_FLESH_DRIP1 */
+ MT_WRAITHFX5, /* T_FLESH_DRIP2 */
+ MT_WRAITHFX2 /* T_SPARK_DRIP */
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// EV_ThingProjectile
+//
+//==========================================================================
+
+boolean EV_ThingProjectile(byte *args, boolean gravity)
+{
+ int tid;
+ angle_t angle;
+ int fineAngle;
+ fixed_t speed;
+ fixed_t vspeed;
+ mobjtype_t moType;
+ mobj_t *mobj;
+ mobj_t *newMobj;
+ int searcher;
+ boolean success;
+
+ success = false;
+ searcher = -1;
+ tid = args[0];
+ moType = TranslateThingType[args[1]];
+ if (nomonsters && (mobjinfo[moType].flags & MF_COUNTKILL))
+ { // Don't spawn monsters if -nomonsters
+ return false;
+ }
+ angle = (int)args[2]<<24;
+ fineAngle = angle>>ANGLETOFINESHIFT;
+ speed = (int)args[3]<<13;
+ vspeed = (int)args[4]<<13;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ newMobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, moType);
+ if (newMobj->info->seesound)
+ {
+ S_StartSound(newMobj, newMobj->info->seesound);
+ }
+ newMobj->target = mobj; // Originator
+ newMobj->angle = angle;
+ newMobj->momx = FixedMul(speed, finecosine[fineAngle]);
+ newMobj->momy = FixedMul(speed, finesine[fineAngle]);
+ newMobj->momz = vspeed;
+ newMobj->flags2 |= MF2_DROPPED; // Don't respawn
+ if (gravity == true)
+ {
+ newMobj->flags &= ~MF_NOGRAVITY;
+ newMobj->flags2 |= MF2_LOGRAV;
+ }
+ if (P_CheckMissileSpawn(newMobj) == true)
+ {
+ success = true;
+ }
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingSpawn
+//
+//==========================================================================
+
+boolean EV_ThingSpawn(byte *args, boolean fog)
+{
+ int tid;
+ angle_t angle;
+ mobj_t *mobj;
+ mobj_t *newMobj;
+ mobj_t *fogMobj;
+ mobjtype_t moType;
+ int searcher;
+ boolean success;
+ fixed_t z;
+
+ success = false;
+ searcher = -1;
+ tid = args[0];
+ moType = TranslateThingType[args[1]];
+ if (nomonsters && (mobjinfo[moType].flags & MF_COUNTKILL))
+ { // Don't spawn monsters if -nomonsters
+ return false;
+ }
+ angle = (int)args[2]<<24;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (mobjinfo[moType].flags2 & MF2_FLOATBOB)
+ {
+ z = mobj->z - mobj->floorz;
+ }
+ else
+ {
+ z = mobj->z;
+ }
+ newMobj = P_SpawnMobj(mobj->x, mobj->y, z, moType);
+ if (P_TestMobjLocation(newMobj) == false)
+ { // Didn't fit
+ P_RemoveMobj(newMobj);
+ }
+ else
+ {
+ newMobj->angle = angle;
+ if (fog == true)
+ {
+ fogMobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fogMobj, SFX_TELEPORT);
+ }
+ newMobj->flags2 |= MF2_DROPPED; // Don't respawn
+ if (newMobj->flags2 & MF2_FLOATBOB)
+ {
+ newMobj->special1 = newMobj->z - newMobj->floorz;
+ }
+ success = true;
+ }
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingActivate
+//
+//==========================================================================
+
+boolean EV_ThingActivate(int tid)
+{
+ mobj_t *mobj;
+ int searcher;
+ boolean success;
+
+ success = false;
+ searcher = -1;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (ActivateThing(mobj) == true)
+ {
+ success = true;
+ }
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingDeactivate
+//
+//==========================================================================
+
+boolean EV_ThingDeactivate(int tid)
+{
+ mobj_t *mobj;
+ int searcher;
+ boolean success;
+
+ success = false;
+ searcher = -1;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (DeactivateThing(mobj) == true)
+ {
+ success = true;
+ }
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingRemove
+//
+//==========================================================================
+
+boolean EV_ThingRemove(int tid)
+{
+ mobj_t *mobj;
+ int searcher;
+ boolean success;
+
+ success = false;
+ searcher = -1;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (mobj->type == MT_BRIDGE)
+ {
+ A_BridgeRemove(mobj);
+ return true;
+ }
+ P_RemoveMobj(mobj);
+ success = true;
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingDestroy
+//
+//==========================================================================
+
+boolean EV_ThingDestroy(int tid)
+{
+ mobj_t *mobj;
+ int searcher;
+ boolean success;
+
+ success = false;
+ searcher = -1;
+ while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
+ {
+ if (mobj->flags & MF_SHOOTABLE)
+ {
+ P_DamageMobj(mobj, NULL, NULL, 10000);
+ success = true;
+ }
+ }
+ return success;
+}
+
+//==========================================================================
+//
+// EV_ThingMove
+//
+// arg[0] = tid
+// arg[1] = speed
+// arg[2] = angle (255 = use mobj angle)
+// arg[3] = distance (pixels>>2)
+//
+//==========================================================================
+
+/*
+boolean EV_ThingMove(byte *args)
+{
+ return false;
+}
+*/
+
+//==========================================================================
+//
+// ActivateThing
+//
+//==========================================================================
+
+static boolean ActivateThing(mobj_t *mobj)
+{
+ if (mobj->flags & MF_COUNTKILL)
+ { // Monster
+ if (mobj->flags2 & MF2_DORMANT)
+ {
+ mobj->flags2 &= ~MF2_DORMANT;
+ mobj->tics = 1;
+ return true;
+ }
+ return false;
+ }
+ switch (mobj->type)
+ {
+ case MT_ZTWINEDTORCH:
+ case MT_ZTWINEDTORCH_UNLIT:
+ P_SetMobjState(mobj, S_ZTWINEDTORCH_1);
+ S_StartSound(mobj, SFX_IGNITE);
+ break;
+ case MT_ZWALLTORCH:
+ case MT_ZWALLTORCH_UNLIT:
+ P_SetMobjState(mobj, S_ZWALLTORCH1);
+ S_StartSound(mobj, SFX_IGNITE);
+ break;
+ case MT_ZGEMPEDESTAL:
+ P_SetMobjState(mobj, S_ZGEMPEDESTAL2);
+ break;
+ case MT_ZWINGEDSTATUENOSKULL:
+ P_SetMobjState(mobj, S_ZWINGEDSTATUENOSKULL2);
+ break;
+ case MT_THRUSTFLOOR_UP:
+ case MT_THRUSTFLOOR_DOWN:
+ if (mobj->args[0] == 0)
+ {
+ S_StartSound(mobj, SFX_THRUSTSPIKE_LOWER);
+ mobj->flags2 &= ~MF2_DONTDRAW;
+ if (mobj->args[1])
+ P_SetMobjState(mobj, S_BTHRUSTRAISE1);
+ else
+ P_SetMobjState(mobj, S_THRUSTRAISE1);
+ }
+ break;
+ case MT_ZFIREBULL:
+ case MT_ZFIREBULL_UNLIT:
+ P_SetMobjState(mobj, S_ZFIREBULL_BIRTH);
+ S_StartSound(mobj, SFX_IGNITE);
+ break;
+ case MT_ZBELL:
+ if (mobj->health > 0)
+ {
+ P_DamageMobj(mobj, NULL, NULL, 10); // 'ring' the bell
+ }
+ break;
+ case MT_ZCAULDRON:
+ case MT_ZCAULDRON_UNLIT:
+ P_SetMobjState(mobj, S_ZCAULDRON1);
+ S_StartSound(mobj, SFX_IGNITE);
+ break;
+ case MT_FLAME_SMALL:
+ S_StartSound(mobj, SFX_IGNITE);
+ P_SetMobjState(mobj, S_FLAME_SMALL1);
+ break;
+ case MT_FLAME_LARGE:
+ S_StartSound(mobj, SFX_IGNITE);
+ P_SetMobjState(mobj, S_FLAME_LARGE1);
+ break;
+ case MT_BAT_SPAWNER:
+ P_SetMobjState(mobj, S_SPAWNBATS1);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// DeactivateThing
+//
+//==========================================================================
+
+static boolean DeactivateThing(mobj_t *mobj)
+{
+ if (mobj->flags & MF_COUNTKILL)
+ { // Monster
+ if (!(mobj->flags2 & MF2_DORMANT))
+ {
+ mobj->flags2 |= MF2_DORMANT;
+ mobj->tics = -1;
+ return true;
+ }
+ return false;
+ }
+ switch (mobj->type)
+ {
+ case MT_ZTWINEDTORCH:
+ case MT_ZTWINEDTORCH_UNLIT:
+ P_SetMobjState(mobj, S_ZTWINEDTORCH_UNLIT);
+ break;
+ case MT_ZWALLTORCH:
+ case MT_ZWALLTORCH_UNLIT:
+ P_SetMobjState(mobj, S_ZWALLTORCH_U);
+ break;
+ case MT_THRUSTFLOOR_UP:
+ case MT_THRUSTFLOOR_DOWN:
+ if (mobj->args[0] == 1)
+ {
+ S_StartSound(mobj, SFX_THRUSTSPIKE_RAISE);
+ if (mobj->args[1])
+ P_SetMobjState(mobj, S_BTHRUSTLOWER);
+ else
+ P_SetMobjState(mobj, S_THRUSTLOWER);
+ }
+ break;
+ case MT_ZFIREBULL:
+ case MT_ZFIREBULL_UNLIT:
+ P_SetMobjState(mobj, S_ZFIREBULL_DEATH);
+ break;
+ case MT_ZCAULDRON:
+ case MT_ZCAULDRON_UNLIT:
+ P_SetMobjState(mobj, S_ZCAULDRON_U);
+ break;
+ case MT_FLAME_SMALL:
+ P_SetMobjState(mobj, S_FLAME_SDORM1);
+ break;
+ case MT_FLAME_LARGE:
+ P_SetMobjState(mobj, S_FLAME_LDORM1);
+ break;
+ case MT_BAT_SPAWNER:
+ P_SetMobjState(mobj, S_SPAWNBATS_OFF);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
--- /dev/null
+++ b/p_tick.c
@@ -1,0 +1,142 @@
+
+//**************************************************************************
+//**
+//** p_tick.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void RunThinkers(void);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int leveltime;
+int TimerGame;
+thinker_t thinkercap; /* The head and tail of the thinker list */
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// P_Ticker
+//
+//==========================================================================
+
+void P_Ticker(void)
+{
+ int i;
+
+ if (paused)
+ {
+ return;
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ P_PlayerThink(&players[i]);
+ }
+ }
+ if (TimerGame)
+ {
+ if (!--TimerGame)
+ {
+ G_Completed(P_TranslateMap(P_GetMapNextMap(gamemap)), 0);
+ }
+ }
+ RunThinkers();
+ P_UpdateSpecials();
+ P_AnimateSurfaces();
+ leveltime++;
+}
+
+//==========================================================================
+//
+// RunThinkers
+//
+//==========================================================================
+
+static void RunThinkers(void)
+{
+ thinker_t *currentthinker;
+
+ currentthinker = thinkercap.next;
+ while (currentthinker != &thinkercap)
+ {
+ if (currentthinker->function == (think_t)-1)
+ { // Time to remove it
+ currentthinker->next->prev = currentthinker->prev;
+ currentthinker->prev->next = currentthinker->next;
+ Z_Free(currentthinker);
+ }
+ else if (currentthinker->function)
+ {
+ currentthinker->function(currentthinker);
+ }
+ currentthinker = currentthinker->next;
+ }
+}
+
+//==========================================================================
+//
+// P_InitThinkers
+//
+//==========================================================================
+
+void P_InitThinkers(void)
+{
+ thinkercap.prev = thinkercap.next = &thinkercap;
+}
+
+//==========================================================================
+//
+// P_AddThinker
+//
+// Adds a new thinker at the end of the list.
+//
+//==========================================================================
+
+void P_AddThinker(thinker_t *thinker)
+{
+ thinkercap.prev->next = thinker;
+ thinker->next = &thinkercap;
+ thinker->prev = thinkercap.prev;
+ thinkercap.prev = thinker;
+}
+
+//==========================================================================
+//
+// P_RemoveThinker
+//
+// Deallocation is lazy -- it will not actually be freed until its
+// thinking turn comes up.
+//
+//==========================================================================
+
+void P_RemoveThinker(thinker_t *thinker)
+{
+ thinker->function = (think_t)-1;
+}
+
--- /dev/null
+++ b/p_user.c
@@ -1,0 +1,1690 @@
+
+//**************************************************************************
+//**
+//** p_user.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 458 $
+//** $Date: 2009-05-25 15:35:27 +0300 (Mon, 25 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+#include "v_compat.h" /* for the V_SetPaletteXXX() macros */
+
+// Macros
+
+#define MAXBOB 0x100000 /* 16 pixels of bob */
+
+// Extern Data
+
+extern int inv_ptr;
+extern int curpos;
+
+// Private Data
+
+static boolean onground;
+static int newtorch; /* used in the torch flicker effect. */
+static int newtorchdelta;
+
+// Global Data
+
+int PStateNormal[NUMCLASSES] =
+{
+ S_FPLAY,
+ S_CPLAY,
+ S_MPLAY,
+#ifdef ASSASSIN
+ S_APLAY,
+#endif
+ S_PIGPLAY
+};
+
+int PStateRun[NUMCLASSES] =
+{
+ S_FPLAY_RUN1,
+ S_CPLAY_RUN1,
+ S_MPLAY_RUN1,
+#ifdef ASSASSIN
+ S_APLAY_RUN1,
+#endif
+ S_PIGPLAY_RUN1
+};
+
+int PStateAttack[NUMCLASSES] =
+{
+ S_FPLAY_ATK1,
+ S_CPLAY_ATK1,
+ S_MPLAY_ATK1,
+#ifdef ASSASSIN
+ S_APLAY_ATK1,
+#endif
+ S_PIGPLAY_ATK1
+};
+
+int PStateAttackEnd[NUMCLASSES] =
+{
+ S_FPLAY_ATK2,
+ S_CPLAY_ATK3,
+ S_MPLAY_ATK2,
+#ifdef ASSASSIN
+ S_APLAY_ATK3,
+#endif
+ S_PIGPLAY_ATK1
+};
+
+int ArmorMax[NUMCLASSES] =
+{
+ 20,
+ 18,
+ 16,
+#ifdef ASSASSIN
+ 17,
+#endif
+ 1
+};
+
+// Global Functions
+
+void P_PlayerNextArtifact(player_t *player);
+
+
+//==========================================================================
+
+
+/*
+==================
+=
+= P_Thrust
+=
+= moves the given origin along a given angle
+=
+==================
+*/
+
+void P_Thrust(player_t *player, angle_t angle, fixed_t move)
+{
+ angle >>= ANGLETOFINESHIFT;
+ if (player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
+ {
+ player->mo->momx += FixedMul(move, finecosine[angle]);
+ player->mo->momy += FixedMul(move, finesine[angle]);
+ }
+ else if (P_GetThingFloorType(player->mo) == FLOOR_ICE) // Friction_Low
+ {
+ player->mo->momx += FixedMul(move>>1, finecosine[angle]);
+ player->mo->momy += FixedMul(move>>1, finesine[angle]);
+ }
+ else
+ {
+ player->mo->momx += FixedMul(move, finecosine[angle]);
+ player->mo->momy += FixedMul(move, finesine[angle]);
+ }
+}
+
+
+/*
+==================
+=
+= P_CalcHeight
+=
+Calculate the walking / running height adjustment
+=
+==================
+*/
+
+static void P_CalcHeight (player_t *player)
+{
+ int angle;
+ fixed_t bob;
+
+//
+// regular movement bobbing (needs to be calculated for gun swing even
+// if not on ground)
+// OPTIMIZE: tablify angle
+
+ player->bob = FixedMul (player->mo->momx, player->mo->momx) +
+ FixedMul (player->mo->momy,player->mo->momy);
+ player->bob >>= 2;
+ if (player->bob > MAXBOB)
+ player->bob = MAXBOB;
+ if (player->mo->flags2 & MF2_FLY && !onground)
+ {
+ player->bob = FRACUNIT/2;
+ }
+
+ if ((player->cheats & CF_NOMOMENTUM))
+ {
+ player->viewz = player->mo->z + VIEWHEIGHT;
+ if (player->viewz > player->mo->ceilingz - 4*FRACUNIT)
+ player->viewz = player->mo->ceilingz - 4*FRACUNIT;
+ player->viewz = player->mo->z + player->viewheight;
+ return;
+ }
+
+ angle = (FINEANGLES/20*leveltime) & FINEMASK;
+ bob = FixedMul (player->bob/2, finesine[angle]);
+
+//
+// move viewheight
+//
+ if (player->playerstate == PST_LIVE)
+ {
+ player->viewheight += player->deltaviewheight;
+ if (player->viewheight > VIEWHEIGHT)
+ {
+ player->viewheight = VIEWHEIGHT;
+ player->deltaviewheight = 0;
+ }
+ if (player->viewheight < VIEWHEIGHT/2)
+ {
+ player->viewheight = VIEWHEIGHT/2;
+ if (player->deltaviewheight <= 0)
+ player->deltaviewheight = 1;
+ }
+
+ if (player->deltaviewheight)
+ {
+ player->deltaviewheight += FRACUNIT/4;
+ if (!player->deltaviewheight)
+ player->deltaviewheight = 1;
+ }
+ }
+
+ if (player->morphTics)
+ {
+ player->viewz = player->mo->z + player->viewheight - (20*FRACUNIT);
+ }
+ else
+ {
+ player->viewz = player->mo->z + player->viewheight + bob;
+ }
+ if (player->mo->floorclip && player->playerstate != PST_DEAD
+ && player->mo->z <= player->mo->floorz)
+ {
+ player->viewz -= player->mo->floorclip;
+ }
+ if (player->viewz > player->mo->ceilingz - 4*FRACUNIT)
+ {
+ player->viewz = player->mo->ceilingz - 4*FRACUNIT;
+ }
+ if (player->viewz < player->mo->floorz + 4*FRACUNIT)
+ {
+ player->viewz = player->mo->floorz + 4*FRACUNIT;
+ }
+}
+
+/*
+=================
+=
+= P_MovePlayer
+=
+=================
+*/
+
+static void P_MovePlayer(player_t *player)
+{
+ int look;
+ int fly;
+ ticcmd_t *cmd;
+
+ cmd = &player->cmd;
+ player->mo->angle += (cmd->angleturn<<16);
+
+ onground = (player->mo->z <= player->mo->floorz
+ || (player->mo->flags2&MF2_ONMOBJ));
+
+ if (cmd->forwardmove)
+ {
+ if (onground || player->mo->flags2 & MF2_FLY)
+ {
+ P_Thrust(player, player->mo->angle, cmd->forwardmove*2048);
+ }
+ else
+ {
+ P_Thrust(player, player->mo->angle, FRACUNIT>>8);
+ }
+ }
+ if (cmd->sidemove)
+ {
+ if (onground || player->mo->flags2 & MF2_FLY)
+ {
+ P_Thrust(player, player->mo->angle - ANG90, cmd->sidemove*2048);
+ }
+ else
+ {
+ P_Thrust(player, player->mo->angle, FRACUNIT>>8);
+ }
+ }
+ if (cmd->forwardmove || cmd->sidemove)
+ {
+ if (player->mo->state == &states[PStateNormal[player->playerclass]])
+ {
+ P_SetMobjState(player->mo, PStateRun[player->playerclass]);
+ }
+ }
+
+ look = cmd->lookfly & 15;
+ if (look > 7)
+ {
+ look -= 16;
+ }
+ if (look)
+ {
+ if (look == TOCENTER)
+ {
+ player->centering = true;
+ }
+ else
+ {
+ player->lookdir += 5*look;
+ if (player->lookdir > 90 || player->lookdir < -110)
+ {
+ player->lookdir -= 5*look;
+ }
+ }
+ }
+ if (player->centering)
+ {
+ if (player->lookdir > 0)
+ {
+ player->lookdir -= 8;
+ }
+ else if (player->lookdir < 0)
+ {
+ player->lookdir += 8;
+ }
+ if (abs(player->lookdir) < 8)
+ {
+ player->lookdir = 0;
+ player->centering = false;
+ }
+ }
+ fly = cmd->lookfly>>4;
+ if (fly > 7)
+ {
+ fly -= 16;
+ }
+ if (fly && player->powers[pw_flight])
+ {
+ if (fly != TOCENTER)
+ {
+ player->flyheight = fly*2;
+ if (!(player->mo->flags2 & MF2_FLY))
+ {
+ player->mo->flags2 |= MF2_FLY;
+ player->mo->flags |= MF_NOGRAVITY;
+ if (player->mo->momz <= -39*FRACUNIT)
+ { // stop falling scream
+ S_StopSound(player->mo);
+ }
+ }
+ }
+ else
+ {
+ player->mo->flags2 &= ~MF2_FLY;
+ player->mo->flags &= ~MF_NOGRAVITY;
+ }
+ }
+ else if (fly > 0)
+ {
+ P_PlayerUseArtifact(player, arti_fly);
+ }
+ if (player->mo->flags2 & MF2_FLY)
+ {
+ player->mo->momz = player->flyheight*FRACUNIT;
+ if (player->flyheight)
+ {
+ player->flyheight /= 2;
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_DeathThink
+//
+//==========================================================================
+
+static void P_DeathThink(player_t *player)
+{
+ int dir;
+ angle_t delta;
+ int lookDelta;
+
+ P_MovePsprites(player);
+
+ onground = (player->mo->z <= player->mo->floorz);
+ if (player->mo->type == MT_BLOODYSKULL || player->mo->type == MT_ICECHUNK)
+ { // Flying bloody skull or flying ice chunk
+ player->viewheight = 6*FRACUNIT;
+ player->deltaviewheight = 0;
+ //player->damagecount = 20;
+ if (onground)
+ {
+ if (player->lookdir < 60)
+ {
+ lookDelta = (60 - player->lookdir)/8;
+ if (lookDelta < 1 && (leveltime & 1))
+ {
+ lookDelta = 1;
+ }
+ else if (lookDelta > 6)
+ {
+ lookDelta = 6;
+ }
+ player->lookdir += lookDelta;
+ }
+ }
+ }
+ else if (!(player->mo->flags2 & MF2_ICEDAMAGE))
+ { // Fall to ground (if not frozen)
+ player->deltaviewheight = 0;
+ if (player->viewheight > 6*FRACUNIT)
+ {
+ player->viewheight -= FRACUNIT;
+ }
+ if (player->viewheight < 6*FRACUNIT)
+ {
+ player->viewheight = 6*FRACUNIT;
+ }
+ if (player->lookdir > 0)
+ {
+ player->lookdir -= 6;
+ }
+ else if (player->lookdir < 0)
+ {
+ player->lookdir += 6;
+ }
+ if (abs(player->lookdir) < 6)
+ {
+ player->lookdir = 0;
+ }
+ }
+ P_CalcHeight(player);
+
+ if (player->attacker && player->attacker != player->mo)
+ { // Watch killer
+ dir = P_FaceMobj(player->mo, player->attacker, &delta);
+ if (delta < ANGLE_1*10)
+ { // Looking at killer, so fade damage and poison counters
+ if (player->damagecount)
+ {
+ player->damagecount--;
+ }
+ if (player->poisoncount)
+ {
+ player->poisoncount--;
+ }
+ }
+ delta = delta/8;
+ if (delta > ANGLE_1*5)
+ {
+ delta = ANGLE_1*5;
+ }
+ if (dir)
+ { // Turn clockwise
+ player->mo->angle += delta;
+ }
+ else
+ { // Turn counter clockwise
+ player->mo->angle -= delta;
+ }
+ }
+ else if (player->damagecount || player->poisoncount)
+ {
+ if (player->damagecount)
+ {
+ player->damagecount--;
+ }
+ else
+ {
+ player->poisoncount--;
+ }
+ }
+
+ if (player->cmd.buttons & BT_USE)
+ {
+ if (player == &players[consoleplayer])
+ {
+ V_SetPaletteBase();
+ inv_ptr = 0;
+ curpos = 0;
+ newtorch = 0;
+ newtorchdelta = 0;
+ }
+ player->playerstate = PST_REBORN;
+ player->mo->special1 = player->playerclass;
+ if (player->mo->special1 > 2)
+ {
+ // O.S. -- FIXME: HARDCODED NUMBER: 2 == PCLASS_MAGE
+ player->mo->special1 = 0;
+ }
+ // Let the mobj know the player has entered the reborn state.
+ // Some mobjs need to know when it's ok to remove themselves.
+ player->mo->special2 = 666;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_MorphPlayerThink
+//
+//----------------------------------------------------------------------------
+
+static void P_MorphPlayerThink(player_t *player)
+{
+ mobj_t *pmo;
+
+ if (player->morphTics & 15)
+ {
+ return;
+ }
+ pmo = player->mo;
+ if (!(pmo->momx + pmo->momy) && P_Random() < 64)
+ { // Snout sniff
+ P_SetPspriteNF(player, ps_weapon, S_SNOUTATK2);
+ S_StartSound(pmo, SFX_PIG_ACTIVE1); // snort
+ return;
+ }
+ if (P_Random() < 48)
+ {
+ if (P_Random() < 128)
+ {
+ S_StartSound(pmo, SFX_PIG_ACTIVE1);
+ }
+ else
+ {
+ S_StartSound(pmo, SFX_PIG_ACTIVE2);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_GetPlayerNum
+//
+//----------------------------------------------------------------------------
+
+int P_GetPlayerNum(player_t *player)
+{
+ int i;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (player == &players[i])
+ {
+ return i;
+ }
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_UndoPlayerMorph
+//
+//----------------------------------------------------------------------------
+
+boolean P_UndoPlayerMorph(player_t *player)
+{
+ mobj_t *fog;
+ mobj_t *mo;
+ mobj_t *pmo;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ angle_t angle;
+ int playerNum;
+ weapontype_t weapon;
+ int oldFlags;
+ int oldFlags2;
+ int oldBeast;
+
+ pmo = player->mo;
+ x = pmo->x;
+ y = pmo->y;
+ z = pmo->z;
+ angle = pmo->angle;
+ weapon = pmo->special1;
+ oldFlags = pmo->flags;
+ oldFlags2 = pmo->flags2;
+ oldBeast = pmo->type;
+ P_SetMobjState(pmo, S_FREETARGMOBJ);
+ playerNum = P_GetPlayerNum(player);
+ switch (PlayerClasses[playerNum])
+ {
+ case PCLASS_FIGHTER:
+ mo = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
+ break;
+ case PCLASS_CLERIC:
+ mo = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
+ break;
+ case PCLASS_MAGE:
+ mo = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
+ break;
+#ifdef ASSASSIN
+ case PCLASS_ASS:
+ mo = P_SpawnMobj(x, y, z, MT_PLAYER_ASS);
+ break;
+#endif
+ default:
+ I_Error("P_UndoPlayerMorph: Unknown player class %d\n", player->playerclass);
+ mo = NULL; /* avoid compiler warning */
+ break;
+ }
+ if (P_TestMobjLocation(mo) == false)
+ { // Didn't fit
+ P_RemoveMobj(mo);
+ mo = P_SpawnMobj(x, y, z, oldBeast);
+ mo->angle = angle;
+ mo->health = player->health;
+ mo->special1 = weapon;
+ mo->player = player;
+ mo->flags = oldFlags;
+ mo->flags2 = oldFlags2;
+ player->mo = mo;
+ player->morphTics = 2*35;
+ return false;
+ }
+ if (player->playerclass == PCLASS_FIGHTER)
+ {
+ // The first type should be blue, and the third should be the
+ // Fighter's original gold color
+ if (playerNum == 0)
+ {
+ mo->flags |= 2<<MF_TRANSSHIFT;
+ }
+ else if (playerNum != 2)
+ {
+ mo->flags |= playerNum<<MF_TRANSSHIFT;
+ }
+ }
+ else if (playerNum)
+ { // Set color translation bits for player sprites
+ mo->flags |= playerNum<<MF_TRANSSHIFT;
+ }
+ mo->angle = angle;
+ mo->player = player;
+ mo->reactiontime = 18;
+ if (oldFlags2 & MF2_FLY)
+ {
+ mo->flags2 |= MF2_FLY;
+ mo->flags |= MF_NOGRAVITY;
+ }
+ player->morphTics = 0;
+ player->health = mo->health = MAXHEALTH;
+ player->mo = mo;
+ player->playerclass = PlayerClasses[playerNum];
+ angle >>= ANGLETOFINESHIFT;
+ fog = P_SpawnMobj(x + 20*finecosine[angle],
+ y + 20*finesine[angle],
+ z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, SFX_TELEPORT);
+ P_PostMorphWeapon(player, weapon);
+ return true;
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerThink
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerThink(player_t *player)
+{
+ ticcmd_t *cmd;
+ weapontype_t newweapon;
+ int floorType;
+ mobj_t *pmo;
+
+ // No-clip cheat
+ if (player->cheats & CF_NOCLIP)
+ {
+ player->mo->flags |= MF_NOCLIP;
+ }
+ else
+ {
+ player->mo->flags &= ~MF_NOCLIP;
+ }
+ cmd = &player->cmd;
+ if (player->mo->flags & MF_JUSTATTACKED)
+ { // Gauntlets attack auto forward motion
+ cmd->angleturn = 0;
+ cmd->forwardmove = 0xc800 / 512;
+ cmd->sidemove = 0;
+ player->mo->flags &= ~MF_JUSTATTACKED;
+ }
+// messageTics is above the rest of the counters so that messages will
+// go away, even in death.
+ player->messageTics--; // Can go negative
+ if (!player->messageTics || player->messageTics == -1)
+ { // Refresh the screen when a message goes away
+ player->ultimateMessage = false; // clear out any chat messages.
+ player->yellowMessage = false;
+ if (player == &players[consoleplayer])
+ {
+ BorderTopRefresh = true;
+ }
+ }
+ player->worldTimer++;
+ if (player->playerstate == PST_DEAD)
+ {
+ P_DeathThink(player);
+ return;
+ }
+ if (player->jumpTics)
+ {
+ player->jumpTics--;
+ }
+ if (player->morphTics)
+ {
+ P_MorphPlayerThink(player);
+ }
+ // Handle movement
+ if (player->mo->reactiontime)
+ { // Player is frozen
+ player->mo->reactiontime--;
+ }
+ else
+ {
+ P_MovePlayer(player);
+ pmo = player->mo;
+ if (player->powers[pw_speed] && !(leveltime & 1)
+ && P_AproxDistance(pmo->momx, pmo->momy) > 12*FRACUNIT)
+ {
+ mobj_t *speedMo;
+ int playerNum;
+
+ speedMo = P_SpawnMobj(pmo->x, pmo->y, pmo->z, MT_PLAYER_SPEED);
+ if (speedMo)
+ {
+ speedMo->angle = pmo->angle;
+ playerNum = P_GetPlayerNum(player);
+ if (player->playerclass == PCLASS_FIGHTER)
+ {
+ // The first type should be blue, and the
+ // third should be the Fighter's original gold color
+ if (playerNum == 0)
+ {
+ speedMo->flags |= 2<<MF_TRANSSHIFT;
+ }
+ else if (playerNum != 2)
+ {
+ speedMo->flags |= playerNum<<MF_TRANSSHIFT;
+ }
+ }
+ else if (playerNum)
+ { // Set color translation bits for player sprites
+ speedMo->flags |= playerNum<<MF_TRANSSHIFT;
+ }
+ speedMo->target = pmo;
+ speedMo->special1 = player->playerclass;
+ if (speedMo->special1 > 2)
+ {
+ // O.S. -- FIXME: HARDCODED NUMBER: 2 == PCLASS_MAGE
+ speedMo->special1 = 0;
+ }
+ speedMo->sprite = pmo->sprite;
+ speedMo->floorclip = pmo->floorclip;
+ if (player == &players[consoleplayer])
+ {
+ speedMo->flags2 |= MF2_DONTDRAW;
+ }
+ }
+ }
+ }
+ P_CalcHeight(player);
+ if (player->mo->subsector->sector->special)
+ {
+ P_PlayerInSpecialSector(player);
+ }
+ if ((floorType = P_GetThingFloorType(player->mo)) != FLOOR_SOLID)
+ {
+ P_PlayerOnSpecialFlat(player, floorType);
+ }
+ switch (player->playerclass)
+ {
+ case PCLASS_FIGHTER:
+ if (player->mo->momz <= -35*FRACUNIT && player->mo->momz >= -40*FRACUNIT
+ && !player->morphTics
+ && !S_GetSoundPlayingInfo(player->mo, SFX_PLAYER_FIGHTER_FALLING_SCREAM))
+ {
+ S_StartSound(player->mo, SFX_PLAYER_FIGHTER_FALLING_SCREAM);
+ }
+ break;
+ case PCLASS_CLERIC:
+ if (player->mo->momz <= -35*FRACUNIT && player->mo->momz >= -40*FRACUNIT
+ && !player->morphTics
+ && !S_GetSoundPlayingInfo(player->mo, SFX_PLAYER_CLERIC_FALLING_SCREAM))
+ {
+ S_StartSound(player->mo, SFX_PLAYER_CLERIC_FALLING_SCREAM);
+ }
+ break;
+ case PCLASS_MAGE:
+ if (player->mo->momz <= -35*FRACUNIT && player->mo->momz >= -40*FRACUNIT
+ && !player->morphTics
+ && !S_GetSoundPlayingInfo(player->mo, SFX_PLAYER_MAGE_FALLING_SCREAM))
+ {
+ S_StartSound(player->mo, SFX_PLAYER_MAGE_FALLING_SCREAM);
+ }
+#ifdef ASSASSIN
+ case PCLASS_ASS:
+ if (player->mo->momz <= -35*FRACUNIT && player->mo->momz >= -40*FRACUNIT
+ && !player->morphTics
+ && !S_GetSoundPlayingInfo(player->mo, SFX_PLAYER_MAGE_FALLING_SCREAM))
+ {
+ S_StartSound(player->mo, SFX_PLAYER_MAGE_FALLING_SCREAM);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ if (cmd->arti)
+ { // Use an artifact
+ if ((cmd->arti & AFLAG_JUMP) && onground && !player->jumpTics)
+ {
+ if (player->morphTics)
+ {
+ player->mo->momz = 6*FRACUNIT;
+ }
+ else
+ {
+ player->mo->momz = 9*FRACUNIT;
+ }
+ player->mo->flags2 &= ~MF2_ONMOBJ;
+ player->jumpTics = 18;
+ }
+ else if (cmd->arti & AFLAG_SUICIDE)
+ {
+ P_DamageMobj(player->mo, NULL, NULL, 10000);
+ }
+ if (cmd->arti == NUMARTIFACTS)
+ { // use one of each artifact (except puzzle artifacts)
+ int i;
+ for (i = 1; i < arti_firstpuzzitem; i++)
+ {
+ P_PlayerUseArtifact(player, i);
+ }
+ }
+ else
+ {
+ P_PlayerUseArtifact(player, cmd->arti & AFLAG_MASK);
+ }
+ }
+ // Check for weapon change
+ if (cmd->buttons & BT_SPECIAL)
+ { // A special event has no other buttons
+ cmd->buttons = 0;
+ }
+ if (cmd->buttons & BT_CHANGE && !player->morphTics)
+ {
+ // The actual changing of the weapon is done when the weapon
+ // psprite can do it (A_WeaponReady), so it doesn't happen in
+ // the middle of an attack.
+ newweapon = (cmd->buttons & BT_WEAPONMASK)>>BT_WEAPONSHIFT;
+ if (player->weaponowned[newweapon]
+ && newweapon != player->readyweapon)
+ {
+ player->pendingweapon = newweapon;
+ }
+ }
+ // Check for use
+ if (cmd->buttons & BT_USE)
+ {
+ if (!player->usedown)
+ {
+ P_UseLines(player);
+ player->usedown = true;
+ }
+ }
+ else
+ {
+ player->usedown = false;
+ }
+ // Morph counter
+ if (player->morphTics)
+ {
+ if (!--player->morphTics)
+ { // Attempt to undo the pig
+ P_UndoPlayerMorph(player);
+ }
+ }
+ // Cycle psprites
+ P_MovePsprites(player);
+ // Other Counters
+ if (player->powers[pw_invulnerability])
+ {
+ if (player->playerclass == PCLASS_CLERIC)
+ {
+ if (!(leveltime & 7) && player->mo->flags & MF_SHADOW
+ && !(player->mo->flags2 & MF2_DONTDRAW))
+ {
+ player->mo->flags &= ~MF_SHADOW;
+ if (!(player->mo->flags & MF_ALTSHADOW))
+ {
+ player->mo->flags2 |= MF2_DONTDRAW|MF2_NONSHOOTABLE;
+ }
+ }
+ if (!(leveltime & 31))
+ {
+ if (player->mo->flags2 & MF2_DONTDRAW)
+ {
+ if (!(player->mo->flags & MF_SHADOW))
+ {
+ player->mo->flags |= MF_SHADOW|MF_ALTSHADOW;
+ }
+ else
+ {
+ player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
+ }
+ }
+ else
+ {
+ player->mo->flags |= MF_SHADOW;
+ player->mo->flags &= ~MF_ALTSHADOW;
+ }
+ }
+ }
+ if (!(--player->powers[pw_invulnerability]))
+ {
+ player->mo->flags2 &= ~(MF2_INVULNERABLE|MF2_REFLECTIVE);
+ if (player->playerclass == PCLASS_CLERIC)
+ {
+ player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
+ player->mo->flags &= ~(MF_SHADOW|MF_ALTSHADOW);
+ }
+ }
+ }
+ if (player->powers[pw_minotaur])
+ {
+ player->powers[pw_minotaur]--;
+ }
+ if (player->powers[pw_infrared])
+ {
+ player->powers[pw_infrared]--;
+ }
+ if (player->powers[pw_flight] && netgame)
+ {
+ if (!--player->powers[pw_flight])
+ {
+ // if (player->mo->z != player->mo->floorz) { }
+ player->mo->flags2 &= ~MF2_FLY;
+ player->mo->flags &= ~MF_NOGRAVITY;
+ BorderTopRefresh = true; //make sure the sprite's cleared out
+ }
+ }
+ if (player->powers[pw_speed])
+ {
+ player->powers[pw_speed]--;
+ }
+ if (player->damagecount)
+ {
+ player->damagecount--;
+ }
+ if (player->bonuscount)
+ {
+ player->bonuscount--;
+ }
+ if (player->poisoncount && !(leveltime & 15))
+ {
+ player->poisoncount -= 5;
+ if (player->poisoncount < 0)
+ {
+ player->poisoncount = 0;
+ }
+ P_PoisonDamage(player, player->poisoner, 1, true);
+ }
+ // Colormaps
+// if (player->powers[pw_invulnerability])
+// {
+// if (player->powers[pw_invulnerability] > BLINKTHRESHOLD
+// || (player->powers[pw_invulnerability] & 8))
+// {
+// player->fixedcolormap = INVERSECOLORMAP;
+// }
+// else
+// {
+// player->fixedcolormap = 0;
+// }
+// }
+// else
+ if (player->powers[pw_infrared])
+ {
+ if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
+ {
+ if (player->powers[pw_infrared] & 8)
+ {
+ player->fixedcolormap = 0;
+ }
+ else
+ {
+ player->fixedcolormap = 1;
+ }
+ }
+ else if (!(leveltime & 16) && player == &players[consoleplayer])
+ {
+ if (newtorch)
+ {
+ if (player->fixedcolormap + newtorchdelta > 7
+ || player->fixedcolormap + newtorchdelta < 1
+ || newtorch == player->fixedcolormap)
+ {
+ newtorch = 0;
+ }
+ else
+ {
+ player->fixedcolormap += newtorchdelta;
+ }
+ }
+ else
+ {
+ newtorch = (M_Random() & 7) + 1;
+ newtorchdelta = (newtorch == player->fixedcolormap) ?
+ 0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
+ }
+ }
+ }
+ else
+ {
+ player->fixedcolormap = 0;
+ }
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ArtiTele
+//
+//----------------------------------------------------------------------------
+
+static void P_ArtiTele(player_t *player)
+{
+ int i;
+ int selections;
+ fixed_t destX;
+ fixed_t destY;
+ angle_t destAngle;
+
+ if (deathmatch)
+ {
+ selections = deathmatch_p - deathmatchstarts;
+ i = P_Random() % selections;
+ destX = deathmatchstarts[i].x<<FRACBITS;
+ destY = deathmatchstarts[i].y<<FRACBITS;
+ destAngle = ANG45*(deathmatchstarts[i].angle/45);
+ }
+ else
+ {
+ destX = playerstarts[0][0].x<<FRACBITS;
+ destY = playerstarts[0][0].y<<FRACBITS;
+ destAngle = ANG45*(playerstarts[0][0].angle/45);
+ }
+ P_Teleport(player->mo, destX, destY, destAngle, true);
+ if (player->morphTics)
+ { // Teleporting away will undo any morph effects (pig)
+ P_UndoPlayerMorph(player);
+ }
+ //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ArtiTeleportOther
+//
+//----------------------------------------------------------------------------
+
+static void P_ArtiTeleportOther(player_t *player)
+{
+ mobj_t *mo;
+
+ mo = P_SpawnPlayerMissile(player->mo, MT_TELOTHER_FX1);
+ if (mo)
+ {
+ mo->target = player->mo;
+ }
+}
+
+static void P_TeleportToPlayerStarts(mobj_t *victim)
+{
+ int i, selections = 0;
+ fixed_t destX, destY;
+ angle_t destAngle;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ continue;
+ selections++;
+ }
+ i = P_Random() % selections;
+ destX = playerstarts[0][i].x<<FRACBITS;
+ destY = playerstarts[0][i].y<<FRACBITS;
+ destAngle = ANG45*(playerstarts[0][i].angle/45);
+ P_Teleport(victim, destX, destY, destAngle, true);
+ //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
+}
+
+static void P_TeleportToDeathmatchStarts(mobj_t *victim)
+{
+ int i, selections;
+ fixed_t destX, destY;
+ angle_t destAngle;
+
+ selections = deathmatch_p-deathmatchstarts;
+ if (selections)
+ {
+ i = P_Random() % selections;
+ destX = deathmatchstarts[i].x<<FRACBITS;
+ destY = deathmatchstarts[i].y<<FRACBITS;
+ destAngle = ANG45*(deathmatchstarts[i].angle/45);
+ P_Teleport(victim, destX, destY, destAngle, true);
+ //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
+ }
+ else
+ {
+ P_TeleportToPlayerStarts(victim);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_TeleportOther
+//
+//----------------------------------------------------------------------------
+
+void P_TeleportOther(mobj_t *victim)
+{
+ if (victim->player)
+ {
+ if (deathmatch)
+ P_TeleportToDeathmatchStarts(victim);
+ else
+ P_TeleportToPlayerStarts(victim);
+ }
+ else
+ {
+ // If death action, run it upon teleport
+ if (victim->flags & MF_COUNTKILL && victim->special)
+ {
+ P_RemoveMobjFromTIDList(victim);
+ P_ExecuteLineSpecial(victim->special, victim->args,
+ NULL, 0, victim);
+ victim->special = 0;
+ }
+
+ // Send all monsters to deathmatch spots
+ P_TeleportToDeathmatchStarts(victim);
+ }
+}
+
+
+#define BLAST_RADIUS_DIST 255*FRACUNIT
+#define BLAST_SPEED 20*FRACUNIT
+#define BLAST_FULLSTRENGTH 255
+
+void ResetBlasted(mobj_t *mo)
+{
+ mo->flags2 &= ~MF2_BLASTED;
+ if (!(mo->flags & MF_ICECORPSE))
+ {
+ mo->flags2 &= ~MF2_SLIDE;
+ }
+}
+
+static void P_BlastMobj(mobj_t *source, mobj_t *victim, fixed_t strength)
+{
+ angle_t angle, ang;
+ mobj_t *mo;
+ fixed_t x, y, z;
+
+ angle = R_PointToAngle2(source->x, source->y, victim->x, victim->y);
+ angle >>= ANGLETOFINESHIFT;
+ if (strength < BLAST_FULLSTRENGTH)
+ {
+ victim->momx = FixedMul(strength, finecosine[angle]);
+ victim->momy = FixedMul(strength, finesine[angle]);
+ if (victim->player)
+ {
+ // Players handled automatically
+ }
+ else
+ {
+ victim->flags2 |= MF2_SLIDE;
+ victim->flags2 |= MF2_BLASTED;
+ }
+ }
+ else // full strength blast from artifact
+ {
+ if (victim->flags & MF_MISSILE)
+ {
+ switch (victim->type)
+ {
+ case MT_SORCBALL1: // don't blast sorcerer balls
+ case MT_SORCBALL2:
+ case MT_SORCBALL3:
+ return;
+ case MT_MSTAFF_FX2: // Reflect to originator
+ victim->special1 = (intptr_t)victim->target;
+ victim->target = source;
+ break;
+ default:
+ break;
+ }
+ }
+ if (victim->type == MT_HOLY_FX)
+ {
+ if ((mobj_t *)(victim->special1) == source)
+ {
+ victim->special1 = (intptr_t)victim->target;
+ victim->target = source;
+ }
+ }
+ victim->momx = FixedMul(BLAST_SPEED, finecosine[angle]);
+ victim->momy = FixedMul(BLAST_SPEED, finesine[angle]);
+
+ // Spawn blast puff
+ ang = R_PointToAngle2(victim->x, victim->y, source->x, source->y);
+ ang >>= ANGLETOFINESHIFT;
+ x = victim->x + FixedMul(victim->radius + FRACUNIT, finecosine[ang]);
+ y = victim->y + FixedMul(victim->radius + FRACUNIT, finesine[ang]);
+ z = victim->z - victim->floorclip + (victim->height>>1);
+ mo = P_SpawnMobj(x, y, z, MT_BLASTEFFECT);
+ if (mo)
+ {
+ mo->momx = victim->momx;
+ mo->momy = victim->momy;
+ }
+
+ if (victim->flags & MF_MISSILE)
+ {
+ victim->momz = 8*FRACUNIT;
+ mo->momz = victim->momz;
+ }
+ else
+ {
+ victim->momz = (1000/victim->info->mass)<<FRACBITS;
+ }
+ if (victim->player)
+ {
+ // Players handled automatically
+ }
+ else
+ {
+ victim->flags2 |= MF2_SLIDE;
+ victim->flags2 |= MF2_BLASTED;
+ }
+ }
+}
+
+// Blast all mobj things away
+static void P_BlastRadius(player_t *player)
+{
+ mobj_t *mo;
+ mobj_t *pmo = player->mo;
+ thinker_t *think;
+ fixed_t dist;
+
+ S_StartSound(pmo, SFX_ARTIFACT_BLAST);
+ P_NoiseAlert(player->mo, player->mo);
+
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mo = (mobj_t *)think;
+ if ((mo == pmo) || (mo->flags2 & MF2_BOSS))
+ { // Not a valid monster
+ continue;
+ }
+ if ((mo->type == MT_POISONCLOUD) || // poison cloud
+ (mo->type == MT_HOLY_FX) || // holy fx
+ (mo->flags&MF_ICECORPSE)) // frozen corpse
+ {
+ // Let these special cases go
+ }
+ else if ((mo->flags & MF_COUNTKILL) &&
+ (mo->health <= 0))
+ {
+ continue;
+ }
+ else if (!(mo->flags & MF_COUNTKILL) &&
+ !(mo->player) &&
+ !(mo->flags & MF_MISSILE))
+ { // Must be monster, player, or missile
+ continue;
+ }
+ if (mo->flags2 & MF2_DORMANT)
+ {
+ continue; // no dormant creatures
+ }
+ if ((mo->type == MT_WRAITHB) && (mo->flags2 & MF2_DONTDRAW))
+ {
+ continue; // no underground wraiths
+ }
+ if ((mo->type == MT_SPLASHBASE) ||
+ (mo->type == MT_SPLASH))
+ {
+ continue;
+ }
+ if (mo->type == MT_SERPENT || mo->type == MT_SERPENTLEADER)
+ {
+ continue;
+ }
+ dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
+ if (dist > BLAST_RADIUS_DIST)
+ { // Out of range
+ continue;
+ }
+ P_BlastMobj(pmo, mo, BLAST_FULLSTRENGTH);
+ }
+}
+
+
+#define HEAL_RADIUS_DIST 255*FRACUNIT
+
+// Do class specific effect for everyone in radius
+static boolean P_HealRadius(player_t *player)
+{
+ mobj_t *mo;
+ mobj_t *pmo = player->mo;
+ thinker_t *think;
+ fixed_t dist;
+ int effective = false;
+ int amount;
+
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mo = (mobj_t *)think;
+
+ if (!mo->player)
+ continue;
+ if (mo->health <= 0)
+ continue;
+ dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
+ if (dist > HEAL_RADIUS_DIST)
+ { // Out of range
+ continue;
+ }
+
+ switch (player->playerclass)
+ {
+ case PCLASS_FIGHTER: // Radius armor boost
+ if ((P_GiveArmor(mo->player, ARMOR_ARMOR, 1)) ||
+ (P_GiveArmor(mo->player, ARMOR_SHIELD, 1)) ||
+ (P_GiveArmor(mo->player, ARMOR_HELMET, 1)) ||
+ (P_GiveArmor(mo->player, ARMOR_AMULET, 1)))
+ {
+ effective = true;
+ S_StartSound(mo, SFX_MYSTICINCANT);
+ }
+ break;
+ case PCLASS_CLERIC: // Radius heal
+ amount = 50 + (P_Random() % 50);
+ if (P_GiveBody(mo->player, amount))
+ {
+ effective = true;
+ S_StartSound(mo, SFX_MYSTICINCANT);
+ }
+ break;
+ case PCLASS_MAGE: // Radius mana boost
+ amount = 50 + (P_Random() % 50);
+ if ((P_GiveMana(mo->player, MANA_1, amount)) ||
+ (P_GiveMana(mo->player, MANA_2, amount)))
+ {
+ effective = true;
+ S_StartSound(mo, SFX_MYSTICINCANT);
+ }
+ break;
+#ifdef ASSASSIN
+ case PCLASS_ASS: // Also Radius heal
+ amount = 50 + (P_Random() % 50);
+ if (P_GiveBody(mo->player, amount))
+ {
+ effective = true;
+ S_StartSound(mo, SFX_MYSTICINCANT);
+ }
+ break;
+#endif
+ case PCLASS_PIG:
+ default:
+ break;
+ }
+ }
+ return effective;
+}
+
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerNextArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerNextArtifact(player_t *player)
+{
+ if (player == &players[consoleplayer])
+ {
+ inv_ptr--;
+ if (inv_ptr < 6)
+ {
+ curpos--;
+ if (curpos < 0)
+ {
+ curpos = 0;
+ }
+ }
+ if (inv_ptr < 0)
+ {
+ inv_ptr = player->inventorySlotNum - 1;
+ if (inv_ptr < 6)
+ {
+ curpos = inv_ptr;
+ }
+ else
+ {
+ curpos = 6;
+ }
+ }
+ player->readyArtifact =
+ player->inventory[inv_ptr].type;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerRemoveArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerRemoveArtifact(player_t *player, int slot)
+{
+ int i;
+
+ player->artifactCount--;
+ if (!(--player->inventory[slot].count))
+ { // Used last of a type - compact the artifact list
+ player->readyArtifact = arti_none;
+ player->inventory[slot].type = arti_none;
+ for (i = slot + 1; i < player->inventorySlotNum; i++)
+ {
+ player->inventory[i-1] = player->inventory[i];
+ }
+ player->inventorySlotNum--;
+ if (player == &players[consoleplayer])
+ { // Set position markers and get next readyArtifact
+ inv_ptr--;
+ if (inv_ptr < 6)
+ {
+ curpos--;
+ if (curpos < 0)
+ {
+ curpos = 0;
+ }
+ }
+ if (inv_ptr >= player->inventorySlotNum)
+ {
+ inv_ptr = player->inventorySlotNum - 1;
+ }
+ if (inv_ptr < 0)
+ {
+ inv_ptr = 0;
+ }
+ player->readyArtifact =
+ player->inventory[inv_ptr].type;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerUseArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerUseArtifact(player_t *player, artitype_t arti)
+{
+ int i;
+
+ for (i = 0; i < player->inventorySlotNum; i++)
+ {
+ if (player->inventory[i].type == arti)
+ { // Found match - try to use
+ if (P_UseArtifact(player, arti))
+ { // Artifact was used - remove it from inventory
+ P_PlayerRemoveArtifact(player, i);
+ if (player == &players[consoleplayer])
+ {
+ if (arti < arti_firstpuzzitem)
+ {
+ S_StartSound(NULL, SFX_ARTIFACT_USE);
+ }
+ else
+ {
+ S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
+ }
+ ArtifactFlash = 4;
+ }
+ }
+ else if (arti < arti_firstpuzzitem)
+ { // Unable to use artifact, advance pointer
+ P_PlayerNextArtifact(player);
+ }
+ break;
+ }
+ }
+}
+
+//==========================================================================
+//
+// P_UseArtifact
+//
+// Returns true if the artifact was used.
+//
+//==========================================================================
+
+boolean P_UseArtifact(player_t *player, artitype_t arti)
+{
+ mobj_t *mo;
+ angle_t angle;
+ int i;
+ int count;
+
+ switch (arti)
+ {
+ case arti_invulnerability:
+ if (!P_GivePower(player, pw_invulnerability))
+ {
+ return false;
+ }
+ break;
+ case arti_health:
+ if (!P_GiveBody(player, 25))
+ {
+ return false;
+ }
+ break;
+ case arti_superhealth:
+ if (!P_GiveBody(player, 100))
+ {
+ return false;
+ }
+ break;
+ case arti_healingradius:
+ if (!P_HealRadius(player))
+ {
+ return false;
+ }
+ break;
+ case arti_torch:
+ if (!P_GivePower(player, pw_infrared))
+ {
+ return false;
+ }
+ break;
+ case arti_egg:
+ mo = player->mo;
+ P_SpawnPlayerMissile(mo, MT_EGGFX);
+ P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45/6));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45/6));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45/3));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45/3));
+ break;
+ case arti_fly:
+ if (!P_GivePower(player, pw_flight))
+ {
+ return false;
+ }
+ if (player->mo->momz <= -35*FRACUNIT)
+ { // stop falling scream
+ S_StopSound(player->mo);
+ }
+ break;
+ case arti_summon:
+ mo = P_SpawnPlayerMissile(player->mo, MT_SUMMON_FX);
+ if (mo)
+ {
+ mo->target = player->mo;
+ mo->special1 = (intptr_t)(player->mo);
+ mo->momz = 5*FRACUNIT;
+ }
+ break;
+ case arti_teleport:
+ P_ArtiTele(player);
+ break;
+ case arti_teleportother:
+ P_ArtiTeleportOther(player);
+ break;
+ case arti_poisonbag:
+ angle = player->mo->angle>>ANGLETOFINESHIFT;
+ if (player->playerclass == PCLASS_CLERIC)
+ {
+ mo = P_SpawnMobj(player->mo->x + 16*finecosine[angle],
+ player->mo->y + 24*finesine[angle],
+ player->mo->z - player->mo->floorclip + 8*FRACUNIT,
+ MT_POISONBAG);
+ if (mo)
+ {
+ mo->target = player->mo;
+ }
+ }
+ else if (player->playerclass == PCLASS_MAGE)
+ {
+ mo = P_SpawnMobj(player->mo->x + 16*finecosine[angle],
+ player->mo->y + 24*finesine[angle],
+ player->mo->z - player->mo->floorclip + 8*FRACUNIT,
+ MT_FIREBOMB);
+ if (mo)
+ {
+ mo->target = player->mo;
+ }
+ }
+ else // PCLASS_FIGHTER, obviously (also pig, not so obviously)
+ {
+ mo = P_SpawnMobj(player->mo->x, player->mo->y,
+ player->mo->z - player->mo->floorclip + 35*FRACUNIT,
+ MT_THROWINGBOMB);
+ if (mo)
+ {
+ mo->angle = player->mo->angle + (((P_Random() & 7) - 4) << 24);
+ mo->momz = 4*FRACUNIT + ((player->lookdir) << (FRACBITS - 4));
+ mo->z += player->lookdir << (FRACBITS - 4);
+ P_ThrustMobj(mo, mo->angle, mo->info->speed);
+ mo->momx += player->mo->momx>>1;
+ mo->momy += player->mo->momy>>1;
+ mo->target = player->mo;
+ mo->tics -= P_Random() & 3;
+ P_CheckMissileSpawn(mo);
+ }
+ }
+ break;
+ case arti_speed:
+ if (!P_GivePower(player, pw_speed))
+ {
+ return false;
+ }
+ break;
+ case arti_boostmana:
+ if (!P_GiveMana(player, MANA_1, MAX_MANA))
+ {
+ if (!P_GiveMana(player, MANA_2, MAX_MANA))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ P_GiveMana(player, MANA_2, MAX_MANA);
+ }
+ break;
+ case arti_boostarmor:
+ count = 0;
+ for (i = 0; i < NUMARMOR; i++)
+ {
+ count += P_GiveArmor(player, i, 1); // 1 point per armor type
+ }
+ if (!count)
+ {
+ return false;
+ }
+ break;
+ case arti_blastradius:
+ P_BlastRadius(player);
+ break;
+
+ case arti_puzzskull:
+ case arti_puzzgembig:
+ case arti_puzzgemred:
+ case arti_puzzgemgreen1:
+ case arti_puzzgemgreen2:
+ case arti_puzzgemblue1:
+ case arti_puzzgemblue2:
+ case arti_puzzbook1:
+ case arti_puzzbook2:
+ case arti_puzzskull2:
+ case arti_puzzfweapon:
+ case arti_puzzcweapon:
+ case arti_puzzmweapon:
+ case arti_puzzgear1:
+ case arti_puzzgear2:
+ case arti_puzzgear3:
+ case arti_puzzgear4:
+ if (P_UsePuzzleItem(player, arti - arti_firstpuzzitem))
+ {
+ return true;
+ }
+ else
+ {
+ P_SetYellowMessage(player, TXT_USEPUZZLEFAILED, false);
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+//============================================================================
+//
+// A_SpeedFade
+//
+//============================================================================
+
+void A_SpeedFade(mobj_t *actor)
+{
+ actor->flags |= MF_SHADOW;
+ actor->flags &= ~MF_ALTSHADOW;
+ actor->sprite = actor->target->sprite;
+}
+
--- /dev/null
+++ b/po_man.c
@@ -1,0 +1,1453 @@
+
+//**************************************************************************
+//**
+//** PO_MAN.C : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "r_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define PO_MAXPOLYSEGS 64
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+boolean PO_MovePolyobj(int num, int x, int y);
+boolean PO_RotatePolyobj(int num, angle_t angle);
+void PO_Init(int lump);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static polyobj_t *GetPolyobj(int polyNum);
+static int GetPolyobjMirror(int poly);
+static void ThrustMobj(mobj_t *mobj, seg_t *seg, polyobj_t *po);
+static void UpdateSegBBox(seg_t *seg);
+static void RotatePt(int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_t startSpotY);
+static void UnLinkPolyobj(polyobj_t *po);
+static void LinkPolyobj(polyobj_t *po);
+static boolean CheckMobjBlocking(seg_t *seg, polyobj_t *po);
+static void InitBlockMap(void);
+static void IterFindPolySegs(int x, int y, seg_t **segList);
+static void SpawnPolyobj(int idx, int tag, boolean crush);
+static void TranslateToStartSpot(int tag, int originX, int originY);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern seg_t *segs;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+polyblock_t **PolyBlockMap;
+polyobj_t *polyobjs; // list of all poly-objects on the level
+int po_NumPolyobjs;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int PolySegCount;
+static fixed_t PolyStartX;
+static fixed_t PolyStartY;
+
+// CODE --------------------------------------------------------------------
+
+// ===== Polyobj Event Code =====
+
+//==========================================================================
+//
+// T_RotatePoly
+//
+//==========================================================================
+
+void T_RotatePoly(polyevent_t *pe)
+{
+ int absSpeed;
+ polyobj_t *poly;
+
+ if (PO_RotatePolyobj(pe->polyobj, pe->speed))
+ {
+ absSpeed = abs(pe->speed);
+
+ if (pe->dist == -1)
+ { // perpetual polyobj
+ return;
+ }
+ pe->dist -= absSpeed;
+ if (pe->dist <= 0)
+ {
+ poly = GetPolyobj(pe->polyobj);
+ if (poly->specialdata == pe)
+ {
+ poly->specialdata = NULL;
+ }
+ SN_StopSequence((mobj_t *)&poly->startSpot);
+ P_PolyobjFinished(poly->tag);
+ P_RemoveThinker(&pe->thinker);
+ }
+ if (pe->dist < absSpeed)
+ {
+ pe->speed = pe->dist*(pe->speed < 0 ? -1 : 1);
+ }
+ }
+}
+
+//==========================================================================
+//
+// EV_RotatePoly
+//
+//==========================================================================
+
+boolean EV_RotatePoly(line_t *line, byte *args, int direction, boolean overRide)
+{
+ int mirror;
+ int polyNum;
+ polyevent_t *pe;
+ polyobj_t *poly;
+
+ polyNum = args[0];
+ if ((poly = GetPolyobj(polyNum)))
+ {
+ if (poly->specialdata && !overRide)
+ { // poly is already moving
+ return false;
+ }
+ }
+ else
+ {
+ I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum);
+ }
+ pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL);
+ P_AddThinker(&pe->thinker);
+ pe->thinker.function = T_RotatePoly;
+ pe->polyobj = polyNum;
+ if (args[2])
+ {
+ if (args[2] == 255)
+ {
+ pe->dist = -1;
+ }
+ else
+ {
+ pe->dist = args[2]*(ANGLE_90/64); // Angle
+ }
+ }
+ else
+ {
+ pe->dist = ANGLE_MAX-1;
+ }
+ pe->speed = (args[1]*direction*(ANGLE_90/64))>>3;
+ poly->specialdata = pe;
+ SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+
+ while ((mirror = GetPolyobjMirror(polyNum)))
+ {
+ poly = GetPolyobj(mirror);
+ if (poly && poly->specialdata && !overRide)
+ { // mirroring poly is already in motion
+ break;
+ }
+ pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL);
+ P_AddThinker(&pe->thinker);
+ pe->thinker.function = T_RotatePoly;
+ poly->specialdata = pe;
+ pe->polyobj = mirror;
+ if (args[2])
+ {
+ if (args[2] == 255)
+ {
+ pe->dist = -1;
+ }
+ else
+ {
+ pe->dist = args[2]*(ANGLE_90/64); // Angle
+ }
+ }
+ else
+ {
+ pe->dist = ANGLE_MAX-1;
+ }
+ if ((poly = GetPolyobj(polyNum)))
+ {
+ poly->specialdata = pe;
+ }
+ else
+ {
+ I_Error("EV_RotatePoly: Invalid polyobj num: %d\n", polyNum);
+ }
+ direction = -direction;
+ pe->speed = (args[1]*direction*(ANGLE_90/64))>>3;
+ polyNum = mirror;
+ SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// T_MovePoly
+//
+//==========================================================================
+
+void T_MovePoly(polyevent_t *pe)
+{
+ int absSpeed;
+ polyobj_t *poly;
+
+ if (PO_MovePolyobj(pe->polyobj, pe->xSpeed, pe->ySpeed))
+ {
+ absSpeed = abs(pe->speed);
+ pe->dist -= absSpeed;
+ if (pe->dist <= 0)
+ {
+ poly = GetPolyobj(pe->polyobj);
+ if (poly->specialdata == pe)
+ {
+ poly->specialdata = NULL;
+ }
+ SN_StopSequence((mobj_t *)&poly->startSpot);
+ P_PolyobjFinished(poly->tag);
+ P_RemoveThinker(&pe->thinker);
+ }
+ if (pe->dist < absSpeed)
+ {
+ pe->speed = pe->dist*(pe->speed < 0 ? -1 : 1);
+ pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
+ pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
+ }
+ }
+}
+
+//==========================================================================
+//
+// EV_MovePoly
+//
+//==========================================================================
+
+boolean EV_MovePoly(line_t *line, byte *args, boolean timesEight, boolean overRide)
+{
+ int mirror;
+ int polyNum;
+ polyevent_t *pe;
+ polyobj_t *poly;
+ angle_t an;
+
+ polyNum = args[0];
+ if ((poly = GetPolyobj(polyNum)))
+ {
+ if (poly->specialdata && !overRide)
+ { // poly is already moving
+ return false;
+ }
+ }
+ else
+ {
+ I_Error("EV_MovePoly: Invalid polyobj num: %d\n", polyNum);
+ }
+ pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL);
+ P_AddThinker(&pe->thinker);
+ pe->thinker.function = T_MovePoly;
+ pe->polyobj = polyNum;
+ if (timesEight)
+ {
+ pe->dist = args[3]*8*FRACUNIT;
+ }
+ else
+ {
+ pe->dist = args[3]*FRACUNIT; // Distance
+ }
+ pe->speed = args[1]*(FRACUNIT/8);
+ poly->specialdata = pe;
+
+ an = args[2]*(ANGLE_90/64);
+
+ pe->angle = an>>ANGLETOFINESHIFT;
+ pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
+ pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
+ SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+
+ while ((mirror = GetPolyobjMirror(polyNum)))
+ {
+ poly = GetPolyobj(mirror);
+ if (poly && poly->specialdata && !overRide)
+ { // mirroring poly is already in motion
+ break;
+ }
+ pe = (polyevent_t *) Z_Malloc(sizeof(polyevent_t), PU_LEVSPEC, NULL);
+ P_AddThinker(&pe->thinker);
+ pe->thinker.function = T_MovePoly;
+ pe->polyobj = mirror;
+ poly->specialdata = pe;
+ if (timesEight)
+ {
+ pe->dist = args[3]*8*FRACUNIT;
+ }
+ else
+ {
+ pe->dist = args[3]*FRACUNIT; // Distance
+ }
+ pe->speed = args[1]*(FRACUNIT/8);
+ an = an + ANGLE_180; // reverse the angle
+ pe->angle = an>>ANGLETOFINESHIFT;
+ pe->xSpeed = FixedMul(pe->speed, finecosine[pe->angle]);
+ pe->ySpeed = FixedMul(pe->speed, finesine[pe->angle]);
+ polyNum = mirror;
+ SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// T_PolyDoor
+//
+//==========================================================================
+
+void T_PolyDoor(polydoor_t *pd)
+{
+ int absSpeed;
+ polyobj_t *poly;
+
+ if (pd->tics)
+ {
+ if (!--pd->tics)
+ {
+ poly = GetPolyobj(pd->polyobj);
+ SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+ }
+ return;
+ }
+ switch (pd->type)
+ {
+ case PODOOR_SLIDE:
+ if (PO_MovePolyobj(pd->polyobj, pd->xSpeed, pd->ySpeed))
+ {
+ absSpeed = abs(pd->speed);
+ pd->dist -= absSpeed;
+ if (pd->dist <= 0)
+ {
+ poly = GetPolyobj(pd->polyobj);
+ SN_StopSequence((mobj_t *)&poly->startSpot);
+ if (!pd->close)
+ {
+ pd->dist = pd->totalDist;
+ pd->close = true;
+ pd->tics = pd->waitTics;
+ pd->direction = (ANGLE_MAX>>ANGLETOFINESHIFT) - pd->direction;
+ pd->xSpeed = -pd->xSpeed;
+ pd->ySpeed = -pd->ySpeed;
+ }
+ else
+ {
+ if (poly->specialdata == pd)
+ {
+ poly->specialdata = NULL;
+ }
+ P_PolyobjFinished(poly->tag);
+ P_RemoveThinker(&pd->thinker);
+ }
+ }
+ }
+ else
+ {
+ poly = GetPolyobj(pd->polyobj);
+ if (poly->crush || !pd->close)
+ { // continue moving if the poly is a crusher, or is opening
+ return;
+ }
+ else
+ { // open back up
+ pd->dist = pd->totalDist-pd->dist;
+ pd->direction = (ANGLE_MAX>>ANGLETOFINESHIFT) - pd->direction;
+ pd->xSpeed = -pd->xSpeed;
+ pd->ySpeed = -pd->ySpeed;
+ pd->close = false;
+ SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+ }
+ }
+ break;
+
+ case PODOOR_SWING:
+ if (PO_RotatePolyobj(pd->polyobj, pd->speed))
+ {
+ absSpeed = abs(pd->speed);
+ if (pd->dist == -1)
+ { // perpetual polyobj
+ return;
+ }
+ pd->dist -= absSpeed;
+ if (pd->dist <= 0)
+ {
+ poly = GetPolyobj(pd->polyobj);
+ SN_StopSequence((mobj_t *)&poly->startSpot);
+ if (!pd->close)
+ {
+ pd->dist = pd->totalDist;
+ pd->close = true;
+ pd->tics = pd->waitTics;
+ pd->speed = -pd->speed;
+ }
+ else
+ {
+ if (poly->specialdata == pd)
+ {
+ poly->specialdata = NULL;
+ }
+ P_PolyobjFinished(poly->tag);
+ P_RemoveThinker(&pd->thinker);
+ }
+ }
+ }
+ else
+ {
+ poly = GetPolyobj(pd->polyobj);
+ if (poly->crush || !pd->close)
+ { // continue moving if the poly is a crusher, or is opening
+ return;
+ }
+ else
+ { // open back up and rewait
+ pd->dist = pd->totalDist-pd->dist;
+ pd->speed = -pd->speed;
+ pd->close = false;
+ SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+//==========================================================================
+//
+// EV_OpenPolyDoor
+//
+//==========================================================================
+
+boolean EV_OpenPolyDoor(line_t *line, byte *args, podoortype_t type)
+{
+ int mirror;
+ int polyNum;
+ polydoor_t *pd;
+ polyobj_t *poly;
+ angle_t an = 0;
+
+ polyNum = args[0];
+ if ((poly = GetPolyobj(polyNum)))
+ {
+ if (poly->specialdata)
+ { // poly is already moving
+ return false;
+ }
+ }
+ else
+ {
+ I_Error("EV_OpenPolyDoor: Invalid polyobj num: %d\n", polyNum);
+ }
+ pd = (polydoor_t *) Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, NULL);
+ memset(pd, 0, sizeof(polydoor_t));
+ P_AddThinker(&pd->thinker);
+ pd->thinker.function = T_PolyDoor;
+ pd->type = type;
+ pd->polyobj = polyNum;
+ if (type == PODOOR_SLIDE)
+ {
+ pd->waitTics = args[4];
+ pd->speed = args[1]*(FRACUNIT/8);
+ pd->totalDist = args[3]*FRACUNIT; // Distance
+ pd->dist = pd->totalDist;
+ an = args[2]*(ANGLE_90/64);
+ pd->direction = an>>ANGLETOFINESHIFT;
+ pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]);
+ pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]);
+ SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+ }
+ else if (type == PODOOR_SWING)
+ {
+ pd->waitTics = args[3];
+ pd->direction = 1; // ADD: PODOOR_SWINGL, PODOOR_SWINGR
+ pd->speed = (args[1]*pd->direction*(ANGLE_90/64))>>3;
+ pd->totalDist = args[2]*(ANGLE_90/64);
+ pd->dist = pd->totalDist;
+ SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+ }
+
+ poly->specialdata = pd;
+
+ while ((mirror = GetPolyobjMirror(polyNum)))
+ {
+ poly = GetPolyobj(mirror);
+ if (poly && poly->specialdata)
+ { // mirroring poly is already in motion
+ break;
+ }
+ pd = (polydoor_t *) Z_Malloc(sizeof(polydoor_t), PU_LEVSPEC, NULL);
+ memset(pd, 0, sizeof(polydoor_t));
+ P_AddThinker(&pd->thinker);
+ pd->thinker.function = T_PolyDoor;
+ pd->polyobj = mirror;
+ pd->type = type;
+ poly->specialdata = pd;
+ if (type == PODOOR_SLIDE)
+ {
+ pd->waitTics = args[4];
+ pd->speed = args[1]*(FRACUNIT/8);
+ pd->totalDist = args[3]*FRACUNIT; // Distance
+ pd->dist = pd->totalDist;
+ an = an+ANGLE_180; // reverse the angle
+ pd->direction = an>>ANGLETOFINESHIFT;
+ pd->xSpeed = FixedMul(pd->speed, finecosine[pd->direction]);
+ pd->ySpeed = FixedMul(pd->speed, finesine[pd->direction]);
+ SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+ }
+ else if (type == PODOOR_SWING)
+ {
+ pd->waitTics = args[3];
+ pd->direction = -1; // ADD: same as above
+ pd->speed = (args[1]*pd->direction*(ANGLE_90/64))>>3;
+ pd->totalDist = args[2]*(ANGLE_90/64);
+ pd->dist = pd->totalDist;
+ SN_StartSequence((mobj_t *)&poly->startSpot, SEQ_DOOR_STONE + poly->seqType);
+ }
+ polyNum = mirror;
+ }
+ return true;
+}
+
+// ===== Higher Level Poly Interface code =====
+
+//==========================================================================
+//
+// GetPolyobj
+//
+//==========================================================================
+
+static polyobj_t *GetPolyobj(int polyNum)
+{
+ int i;
+
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (polyobjs[i].tag == polyNum)
+ {
+ return &polyobjs[i];
+ }
+ }
+ return NULL;
+}
+
+//==========================================================================
+//
+// GetPolyobjMirror
+//
+//==========================================================================
+
+static int GetPolyobjMirror(int poly)
+{
+ int i;
+
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (polyobjs[i].tag == poly)
+ {
+ return ((*polyobjs[i].segs)->linedef->arg2);
+ }
+ }
+ return 0;
+}
+
+//==========================================================================
+//
+// ThrustMobj
+//
+//==========================================================================
+
+static void ThrustMobj(mobj_t *mobj, seg_t *seg, polyobj_t *po)
+{
+ int thrustAngle;
+ int thrustX;
+ int thrustY;
+ polyevent_t *pe;
+ int force;
+
+ if (!(mobj->flags&MF_SHOOTABLE) && !mobj->player)
+ {
+ return;
+ }
+ thrustAngle = (seg->angle - ANGLE_90)>>ANGLETOFINESHIFT;
+
+ pe = (polyevent_t *) po->specialdata;
+ if (pe)
+ {
+ if (pe->thinker.function == T_RotatePoly)
+ {
+ force = pe->speed>>8;
+ }
+ else
+ {
+ force = pe->speed>>3;
+ }
+ if (force < FRACUNIT)
+ {
+ force = FRACUNIT;
+ }
+ else if (force > 4*FRACUNIT)
+ {
+ force = 4*FRACUNIT;
+ }
+ }
+ else
+ {
+ force = FRACUNIT;
+ }
+
+ thrustX = FixedMul(force, finecosine[thrustAngle]);
+ thrustY = FixedMul(force, finesine[thrustAngle]);
+ mobj->momx += thrustX;
+ mobj->momy += thrustY;
+ if (po->crush)
+ {
+ if (!P_CheckPosition(mobj, mobj->x + thrustX, mobj->y + thrustY))
+ {
+ P_DamageMobj(mobj, NULL, NULL, 3);
+ }
+ }
+}
+
+//==========================================================================
+//
+// UpdateSegBBox
+//
+//==========================================================================
+
+static void UpdateSegBBox(seg_t *seg)
+{
+ line_t *line;
+
+ line = seg->linedef;
+
+ if (seg->v1->x < seg->v2->x)
+ {
+ line->bbox[BOXLEFT] = seg->v1->x;
+ line->bbox[BOXRIGHT] = seg->v2->x;
+ }
+ else
+ {
+ line->bbox[BOXLEFT] = seg->v2->x;
+ line->bbox[BOXRIGHT] = seg->v1->x;
+ }
+ if (seg->v1->y < seg->v2->y)
+ {
+ line->bbox[BOXBOTTOM] = seg->v1->y;
+ line->bbox[BOXTOP] = seg->v2->y;
+ }
+ else
+ {
+ line->bbox[BOXBOTTOM] = seg->v2->y;
+ line->bbox[BOXTOP] = seg->v1->y;
+ }
+
+ // Update the line's slopetype
+ line->dx = line->v2->x - line->v1->x;
+ line->dy = line->v2->y - line->v1->y;
+ if (!line->dx)
+ {
+ line->slopetype = ST_VERTICAL;
+ }
+ else if (!line->dy)
+ {
+ line->slopetype = ST_HORIZONTAL;
+ }
+ else
+ {
+ if (FixedDiv(line->dy, line->dx) > 0)
+ {
+ line->slopetype = ST_POSITIVE;
+ }
+ else
+ {
+ line->slopetype = ST_NEGATIVE;
+ }
+ }
+}
+
+//==========================================================================
+//
+// PO_MovePolyobj
+//
+//==========================================================================
+
+boolean PO_MovePolyobj(int num, int x, int y)
+{
+ int count;
+ seg_t **segList;
+ seg_t **veryTempSeg;
+ polyobj_t *po;
+ vertex_t *prevPts;
+ boolean blocked;
+
+ if (!(po = GetPolyobj(num)))
+ {
+ I_Error("PO_MovePolyobj: Invalid polyobj number: %d\n", num);
+ }
+
+ UnLinkPolyobj(po);
+
+ segList = po->segs;
+ prevPts = po->prevPts;
+ blocked = false;
+
+ validcount++;
+ for (count = po->numsegs; count; count--, segList++, prevPts++)
+ {
+ if ((*segList)->linedef->validcount != validcount)
+ {
+ (*segList)->linedef->bbox[BOXTOP] += y;
+ (*segList)->linedef->bbox[BOXBOTTOM] += y;
+ (*segList)->linedef->bbox[BOXLEFT] += x;
+ (*segList)->linedef->bbox[BOXRIGHT] += x;
+ (*segList)->linedef->validcount = validcount;
+ }
+ for (veryTempSeg = po->segs; veryTempSeg != segList; veryTempSeg++)
+ {
+ if ((*veryTempSeg)->v1 == (*segList)->v1)
+ {
+ break;
+ }
+ }
+ if (veryTempSeg == segList)
+ {
+ (*segList)->v1->x += x;
+ (*segList)->v1->y += y;
+ }
+ (*prevPts).x += x; // previous points are unique for each seg
+ (*prevPts).y += y;
+ }
+ segList = po->segs;
+ for (count = po->numsegs; count; count--, segList++)
+ {
+ if (CheckMobjBlocking(*segList, po))
+ {
+ blocked = true;
+ }
+ }
+ if (blocked)
+ {
+ count = po->numsegs;
+ segList = po->segs;
+ prevPts = po->prevPts;
+ validcount++;
+ while (count--)
+ {
+ if ((*segList)->linedef->validcount != validcount)
+ {
+ (*segList)->linedef->bbox[BOXTOP] -= y;
+ (*segList)->linedef->bbox[BOXBOTTOM] -= y;
+ (*segList)->linedef->bbox[BOXLEFT] -= x;
+ (*segList)->linedef->bbox[BOXRIGHT] -= x;
+ (*segList)->linedef->validcount = validcount;
+ }
+ for (veryTempSeg = po->segs; veryTempSeg != segList; veryTempSeg++)
+ {
+ if ((*veryTempSeg)->v1 == (*segList)->v1)
+ {
+ break;
+ }
+ }
+ if (veryTempSeg == segList)
+ {
+ (*segList)->v1->x -= x;
+ (*segList)->v1->y -= y;
+ }
+ (*prevPts).x -= x;
+ (*prevPts).y -= y;
+ segList++;
+ prevPts++;
+ }
+ LinkPolyobj(po);
+ return false;
+ }
+ po->startSpot.x += x;
+ po->startSpot.y += y;
+ LinkPolyobj(po);
+ return true;
+}
+
+//==========================================================================
+//
+// RotatePt
+//
+//==========================================================================
+
+static void RotatePt(int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_t startSpotY)
+{
+ fixed_t xtr, ytr;
+ fixed_t gxt, gyt;
+
+ xtr = *x;
+ ytr = *y;
+
+ gxt = FixedMul(xtr, finecosine[an]);
+ gyt = FixedMul(ytr, finesine[an]);
+ *x = (gxt - gyt) + startSpotX;
+
+ gxt = FixedMul(xtr, finesine[an]);
+ gyt = FixedMul(ytr, finecosine[an]);
+ *y = (gyt + gxt) + startSpotY;
+}
+
+//==========================================================================
+//
+// PO_RotatePolyobj
+//
+//==========================================================================
+
+boolean PO_RotatePolyobj(int num, angle_t angle)
+{
+ int count;
+ seg_t **segList;
+ vertex_t *originalPts;
+ vertex_t *prevPts;
+ int an;
+ polyobj_t *po;
+ boolean blocked;
+
+ if (!(po = GetPolyobj(num)))
+ {
+ I_Error("PO_RotatePolyobj: Invalid polyobj number: %d\n", num);
+ }
+ an = (po->angle + angle)>>ANGLETOFINESHIFT;
+
+ UnLinkPolyobj(po);
+
+ segList = po->segs;
+ originalPts = po->originalPts;
+ prevPts = po->prevPts;
+
+ for (count = po->numsegs; count; count--, segList++, originalPts++, prevPts++)
+ {
+ prevPts->x = (*segList)->v1->x;
+ prevPts->y = (*segList)->v1->y;
+ (*segList)->v1->x = originalPts->x;
+ (*segList)->v1->y = originalPts->y;
+ RotatePt(an, &(*segList)->v1->x, &(*segList)->v1->y, po->startSpot.x, po->startSpot.y);
+ }
+ segList = po->segs;
+ blocked = false;
+ validcount++;
+ for (count = po->numsegs; count; count--, segList++)
+ {
+ if (CheckMobjBlocking(*segList, po))
+ {
+ blocked = true;
+ }
+ if ((*segList)->linedef->validcount != validcount)
+ {
+ UpdateSegBBox(*segList);
+ (*segList)->linedef->validcount = validcount;
+ }
+ (*segList)->angle += angle;
+ }
+ if (blocked)
+ {
+ segList = po->segs;
+ prevPts = po->prevPts;
+ for (count = po->numsegs; count; count--, segList++, prevPts++)
+ {
+ (*segList)->v1->x = prevPts->x;
+ (*segList)->v1->y = prevPts->y;
+ }
+ segList = po->segs;
+ validcount++;
+ for (count = po->numsegs; count; count--, segList++, prevPts++)
+ {
+ if ((*segList)->linedef->validcount != validcount)
+ {
+ UpdateSegBBox(*segList);
+ (*segList)->linedef->validcount = validcount;
+ }
+ (*segList)->angle -= angle;
+ }
+ LinkPolyobj(po);
+ return false;
+ }
+ po->angle += angle;
+ LinkPolyobj(po);
+ return true;
+}
+
+//==========================================================================
+//
+// UnLinkPolyobj
+//
+//==========================================================================
+
+static void UnLinkPolyobj(polyobj_t *po)
+{
+ polyblock_t *link;
+ int i, j;
+ int idx;
+
+ // remove the polyobj from each blockmap section
+ for (j = po->bbox[BOXBOTTOM]; j <= po->bbox[BOXTOP]; j++)
+ {
+ idx = j * bmapwidth;
+ for (i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
+ {
+ if (i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight)
+ {
+ link = PolyBlockMap[idx + i];
+ while (link != NULL && link->polyobj != po)
+ {
+ link = link->next;
+ }
+ if (link == NULL)
+ { // polyobj not located in the link cell
+ continue;
+ }
+ link->polyobj = NULL;
+ }
+ }
+ }
+}
+
+//==========================================================================
+//
+// LinkPolyobj
+//
+//==========================================================================
+
+static void LinkPolyobj(polyobj_t *po)
+{
+ int leftX, rightX;
+ int topY, bottomY;
+ seg_t **tempSeg;
+ polyblock_t **link;
+ polyblock_t *tempLink;
+ int i, j;
+
+ // calculate the polyobj bbox
+ tempSeg = po->segs;
+ rightX = leftX = (*tempSeg)->v1->x;
+ topY = bottomY = (*tempSeg)->v1->y;
+
+ for (i = 0; i < po->numsegs; i++, tempSeg++)
+ {
+ if ((*tempSeg)->v1->x > rightX)
+ {
+ rightX = (*tempSeg)->v1->x;
+ }
+ if ((*tempSeg)->v1->x < leftX)
+ {
+ leftX = (*tempSeg)->v1->x;
+ }
+ if ((*tempSeg)->v1->y > topY)
+ {
+ topY = (*tempSeg)->v1->y;
+ }
+ if ((*tempSeg)->v1->y < bottomY)
+ {
+ bottomY = (*tempSeg)->v1->y;
+ }
+ }
+ po->bbox[BOXRIGHT] = (rightX - bmaporgx)>>MAPBLOCKSHIFT;
+ po->bbox[BOXLEFT] = (leftX - bmaporgx)>>MAPBLOCKSHIFT;
+ po->bbox[BOXTOP] = (topY - bmaporgy)>>MAPBLOCKSHIFT;
+ po->bbox[BOXBOTTOM] = (bottomY - bmaporgy)>>MAPBLOCKSHIFT;
+ // add the polyobj to each blockmap section
+ for (j = po->bbox[BOXBOTTOM]*bmapwidth; j <= po->bbox[BOXTOP]*bmapwidth;
+ j += bmapwidth)
+ {
+ for (i = po->bbox[BOXLEFT]; i <= po->bbox[BOXRIGHT]; i++)
+ {
+ if (i >= 0 && i < bmapwidth && j >= 0 && j < bmapheight*bmapwidth)
+ {
+ link = &PolyBlockMap[j + i];
+ if (!(*link))
+ { // Create a new link at the current block cell
+ *link = (polyblock_t *) Z_Malloc(sizeof(polyblock_t), PU_LEVEL, NULL);
+ (*link)->next = NULL;
+ (*link)->prev = NULL;
+ (*link)->polyobj = po;
+ continue;
+ }
+ else
+ {
+ tempLink = *link;
+ while (tempLink->next != NULL && tempLink->polyobj != NULL)
+ {
+ tempLink = tempLink->next;
+ }
+ }
+ if (tempLink->polyobj == NULL)
+ {
+ tempLink->polyobj = po;
+ continue;
+ }
+ else
+ {
+ tempLink->next = (polyblock_t *) Z_Malloc(sizeof(polyblock_t), PU_LEVEL, NULL);
+ tempLink->next->next = NULL;
+ tempLink->next->prev = tempLink;
+ tempLink->next->polyobj = po;
+ }
+ }
+ // else, don't link the polyobj, since it's off the map
+ }
+ }
+}
+
+//==========================================================================
+//
+// CheckMobjBlocking
+//
+//==========================================================================
+
+static boolean CheckMobjBlocking(seg_t *seg, polyobj_t *po)
+{
+ mobj_t *mobj;
+ int i, j;
+ int left, right, top, bottom;
+ int tmbbox[4];
+ line_t *ld;
+ boolean blocked;
+
+ ld = seg->linedef;
+
+ top = (ld->bbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
+ bottom = (ld->bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
+ left = (ld->bbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
+ right = (ld->bbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
+
+ blocked = false;
+
+ bottom = bottom < 0 ? 0 : bottom;
+ bottom = bottom >= bmapheight ? bmapheight - 1 : bottom;
+ top = top < 0 ? 0 : top;
+ top = top >= bmapheight ? bmapheight - 1 : top;
+ left = left < 0 ? 0 : left;
+ left = left >= bmapwidth ? bmapwidth - 1 : left;
+ right = right < 0 ? 0 : right;
+ right = right >= bmapwidth ? bmapwidth - 1 : right;
+
+ for (j = bottom*bmapwidth; j <= top*bmapwidth; j += bmapwidth)
+ {
+ for (i = left; i <= right; i++)
+ {
+ for (mobj = blocklinks[j+i]; mobj; mobj = mobj->bnext)
+ {
+ if (mobj->flags&MF_SOLID || mobj->player)
+ {
+ tmbbox[BOXTOP] = mobj->y + mobj->radius;
+ tmbbox[BOXBOTTOM] = mobj->y - mobj->radius;
+ tmbbox[BOXLEFT] = mobj->x - mobj->radius;
+ tmbbox[BOXRIGHT] = mobj->x + mobj->radius;
+
+ if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
+ || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+ || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
+ || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
+ {
+ continue;
+ }
+ if (P_BoxOnLineSide(tmbbox, ld) != -1)
+ {
+ continue;
+ }
+ ThrustMobj(mobj, seg, po);
+ blocked = true;
+ }
+ }
+ }
+ }
+ return blocked;
+}
+
+//==========================================================================
+//
+// InitBlockMap
+//
+//==========================================================================
+
+static void InitBlockMap(void)
+{
+ int i;
+ int j;
+ seg_t **segList;
+// int area;
+ int leftX, rightX;
+ int topY, bottomY;
+
+ PolyBlockMap = (polyblock_t **) Z_Malloc(bmapwidth*bmapheight*sizeof(polyblock_t *), PU_LEVEL, NULL);
+ memset(PolyBlockMap, 0, bmapwidth*bmapheight*sizeof(polyblock_t *));
+
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ LinkPolyobj(&polyobjs[i]);
+
+ // calculate a rough area
+ // right now, working like shit...gotta fix this...
+ segList = polyobjs[i].segs;
+ leftX = rightX = (*segList)->v1->x;
+ topY = bottomY = (*segList)->v1->y;
+ for (j = 0; j < polyobjs[i].numsegs; j++, segList++)
+ {
+ if ((*segList)->v1->x < leftX)
+ {
+ leftX = (*segList)->v1->x;
+ }
+ if ((*segList)->v1->x > rightX)
+ {
+ rightX = (*segList)->v1->x;
+ }
+ if ((*segList)->v1->y < bottomY)
+ {
+ bottomY = (*segList)->v1->y;
+ }
+ if ((*segList)->v1->y > topY)
+ {
+ topY = (*segList)->v1->y;
+ }
+ }
+// area = ((rightX>>FRACBITS) - (leftX>>FRACBITS)) * ((topY>>FRACBITS) - (bottomY>>FRACBITS));
+// fprintf(stdaux, "Area of Polyobj[%d]: %d\n", polyobjs[i].tag, area);
+// fprintf(stdaux, "\t[%d]\n[%d]\t\t[%d]\n\t[%d]\n",
+// topY>>FRACBITS, leftX>>FRACBITS,
+// rightX>>FRACBITS, bottomY>>FRACBITS);
+ }
+}
+
+//==========================================================================
+//
+// IterFindPolySegs
+//
+// Passing NULL for segList will cause IterFindPolySegs to
+// count the number of segs in the polyobj
+//==========================================================================
+
+static void IterFindPolySegs(int x, int y, seg_t **segList)
+{
+ int i;
+
+ if (x == PolyStartX && y == PolyStartY)
+ {
+ return;
+ }
+ for (i = 0; i < numsegs; i++)
+ {
+ if (segs[i].v1->x == x && segs[i].v1->y == y)
+ {
+ if (!segList)
+ {
+ PolySegCount++;
+ }
+ else
+ {
+ *segList++ = &segs[i];
+ }
+ IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, segList);
+ return;
+ }
+ }
+ I_Error("IterFindPolySegs: Non-closed Polyobj located.\n");
+}
+
+
+//==========================================================================
+//
+// SpawnPolyobj
+//
+//==========================================================================
+
+static void SpawnPolyobj(int idx, int tag, boolean crush)
+{
+ int i;
+ int j;
+ int psIndex;
+ int psIndexOld;
+ seg_t *polySegList[PO_MAXPOLYSEGS];
+
+ for (i = 0; i < numsegs; i++)
+ {
+ if (segs[i].linedef->special == PO_LINE_START &&
+ segs[i].linedef->arg1 == tag)
+ {
+ if (polyobjs[idx].segs)
+ {
+ I_Error("SpawnPolyobj: Polyobj %d already spawned.\n", tag);
+ }
+ segs[i].linedef->special = 0;
+ segs[i].linedef->arg1 = 0;
+ PolySegCount = 1;
+ PolyStartX = segs[i].v1->x;
+ PolyStartY = segs[i].v1->y;
+ IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, NULL);
+
+ polyobjs[idx].numsegs = PolySegCount;
+ polyobjs[idx].segs = (seg_t **) Z_Malloc(PolySegCount*sizeof(seg_t *), PU_LEVEL, NULL);
+ *(polyobjs[idx].segs) = &segs[i]; // insert the first seg
+ IterFindPolySegs(segs[i].v2->x, segs[i].v2->y, polyobjs[idx].segs + 1);
+ polyobjs[idx].crush = crush;
+ polyobjs[idx].tag = tag;
+ polyobjs[idx].seqType = segs[i].linedef->arg3;
+ if (polyobjs[idx].seqType < 0
+ || polyobjs[idx].seqType >= SEQTYPE_NUMSEQ)
+ {
+ polyobjs[idx].seqType = 0;
+ }
+ break;
+ }
+ }
+ if (!polyobjs[idx].segs)
+ { // didn't find a polyobj through PO_LINE_START
+ psIndex = 0;
+ polyobjs[idx].numsegs = 0;
+ for (j = 1; j < PO_MAXPOLYSEGS; j++)
+ {
+ psIndexOld = psIndex;
+ for (i = 0; i < numsegs; i++)
+ {
+ if (segs[i].linedef->special == PO_LINE_EXPLICIT &&
+ segs[i].linedef->arg1 == tag)
+ {
+ if (!segs[i].linedef->arg2)
+ {
+ I_Error("SpawnPolyobj: Explicit line missing order number (probably %d) in poly %d.\n",
+ j + 1, tag);
+ }
+ if (segs[i].linedef->arg2 == j)
+ {
+ polySegList[psIndex] = &segs[i];
+ polyobjs[idx].numsegs++;
+ psIndex++;
+ if (psIndex > PO_MAXPOLYSEGS)
+ {
+ I_Error("SpawnPolyobj: psIndex > PO_MAXPOLYSEGS\n");
+ }
+ }
+ }
+ }
+ // Clear out any specials for these segs...we cannot clear them out
+ // in the above loop, since we aren't guaranteed one seg per
+ // linedef.
+ for (i = 0; i < numsegs; i++)
+ {
+ if (segs[i].linedef->special == PO_LINE_EXPLICIT &&
+ segs[i].linedef->arg1 == tag && segs[i].linedef->arg2 == j)
+ {
+ segs[i].linedef->special = 0;
+ segs[i].linedef->arg1 = 0;
+ }
+ }
+ if (psIndex == psIndexOld)
+ { // Check if an explicit line order has been skipped
+ // A line has been skipped if there are any more explicit
+ // lines with the current tag value
+ for (i = 0; i < numsegs; i++)
+ {
+ if (segs[i].linedef->special == PO_LINE_EXPLICIT &&
+ segs[i].linedef->arg1 == tag)
+ {
+ I_Error("SpawnPolyobj: Missing explicit line %d for poly %d\n",
+ j, tag);
+ }
+ }
+ }
+ }
+ if (polyobjs[idx].numsegs)
+ {
+ PolySegCount = polyobjs[idx].numsegs; // PolySegCount used globally
+ polyobjs[idx].crush = crush;
+ polyobjs[idx].tag = tag;
+ polyobjs[idx].segs = (seg_t **) Z_Malloc(polyobjs[idx].numsegs*sizeof(seg_t *), PU_LEVEL, NULL);
+ for (i = 0; i < polyobjs[idx].numsegs; i++)
+ {
+ polyobjs[idx].segs[i] = polySegList[i];
+ }
+ polyobjs[idx].seqType = (*polyobjs[idx].segs)->linedef->arg4;
+ }
+ // Next, change the polyobjs first line to point to a mirror
+ // if it exists
+ (*polyobjs[idx].segs)->linedef->arg2 = (*polyobjs[idx].segs)->linedef->arg3;
+ }
+}
+
+//==========================================================================
+//
+// TranslateToStartSpot
+//
+//==========================================================================
+
+static void TranslateToStartSpot(int tag, int originX, int originY)
+{
+ seg_t **tempSeg;
+ seg_t **veryTempSeg;
+ vertex_t *tempPt;
+ subsector_t *sub;
+ polyobj_t *po;
+ int deltaX;
+ int deltaY;
+ vertex_t avg; // used to find a polyobj's center, and hence subsector
+ int i;
+
+ po = NULL;
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (polyobjs[i].tag == tag)
+ {
+ po = &polyobjs[i];
+ break;
+ }
+ }
+ if (!po)
+ { // didn't match the tag with a polyobj tag
+ I_Error("TranslateToStartSpot: Unable to match polyobj tag: %d\n", tag);
+ }
+ if (po->segs == NULL)
+ {
+ I_Error("TranslateToStartSpot: Anchor point located without a StartSpot point: %d\n", tag);
+ }
+ po->originalPts = (vertex_t *) Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, NULL);
+ po->prevPts = (vertex_t *) Z_Malloc(po->numsegs*sizeof(vertex_t), PU_LEVEL, NULL);
+ deltaX = originX-po->startSpot.x;
+ deltaY = originY-po->startSpot.y;
+
+ tempSeg = po->segs;
+ tempPt = po->originalPts;
+ avg.x = 0;
+ avg.y = 0;
+
+ validcount++;
+ for (i = 0; i < po->numsegs; i++, tempSeg++, tempPt++)
+ {
+ if ((*tempSeg)->linedef->validcount != validcount)
+ {
+ (*tempSeg)->linedef->bbox[BOXTOP] -= deltaY;
+ (*tempSeg)->linedef->bbox[BOXBOTTOM] -= deltaY;
+ (*tempSeg)->linedef->bbox[BOXLEFT] -= deltaX;
+ (*tempSeg)->linedef->bbox[BOXRIGHT] -= deltaX;
+ (*tempSeg)->linedef->validcount = validcount;
+ }
+ for (veryTempSeg = po->segs; veryTempSeg != tempSeg; veryTempSeg++)
+ {
+ if ((*veryTempSeg)->v1 == (*tempSeg)->v1)
+ {
+ break;
+ }
+ }
+ if (veryTempSeg == tempSeg)
+ { // the point hasn't been translated, yet
+ (*tempSeg)->v1->x -= deltaX;
+ (*tempSeg)->v1->y -= deltaY;
+ }
+ avg.x += (*tempSeg)->v1->x>>FRACBITS;
+ avg.y += (*tempSeg)->v1->y>>FRACBITS;
+ // the original Pts are based off the startSpot Pt, and are
+ // unique to each seg, not each linedef
+ tempPt->x = (*tempSeg)->v1->x - po->startSpot.x;
+ tempPt->y = (*tempSeg)->v1->y - po->startSpot.y;
+ }
+ avg.x /= po->numsegs;
+ avg.y /= po->numsegs;
+ sub = R_PointInSubsector(avg.x<<FRACBITS, avg.y<<FRACBITS);
+ if (sub->poly != NULL)
+ {
+ I_Error("PO_TranslateToStartSpot: Multiple polyobjs in a single subsector.\n");
+ }
+ sub->poly = po;
+}
+
+//==========================================================================
+//
+// PO_Init
+//
+//==========================================================================
+
+void PO_Init(int lump)
+{
+ void *data;
+ int i;
+ mapthing_t *mt;
+ int numthings;
+ int polyIndex;
+
+ polyobjs = (polyobj_t *) Z_Malloc(po_NumPolyobjs*sizeof(polyobj_t), PU_LEVEL, NULL);
+ memset(polyobjs, 0, po_NumPolyobjs*sizeof(polyobj_t));
+
+ data = W_CacheLumpNum(lump, PU_STATIC);
+ numthings = W_LumpLength(lump)/sizeof(mapthing_t);
+ mt = (mapthing_t *)data;
+ polyIndex = 0; // index polyobj number
+ // Find the startSpot points, and spawn each polyobj
+ for (i = 0; i < numthings; i++, mt++)
+ {
+ mt->x = SHORT(mt->x);
+ mt->y = SHORT(mt->y);
+ mt->angle = SHORT(mt->angle);
+ mt->type = SHORT(mt->type);
+
+ // 3001 = no crush, 3002 = crushing
+ if (mt->type == PO_SPAWN_TYPE || mt->type == PO_SPAWNCRUSH_TYPE)
+ { // Polyobj StartSpot Pt.
+ polyobjs[polyIndex].startSpot.x = mt->x<<FRACBITS;
+ polyobjs[polyIndex].startSpot.y = mt->y<<FRACBITS;
+ SpawnPolyobj(polyIndex, mt->angle, (mt->type == PO_SPAWNCRUSH_TYPE));
+ polyIndex++;
+ }
+ }
+ mt = (mapthing_t *)data;
+ for (i = 0; i < numthings; i++, mt++)
+ {
+ /* NOTE: we byte swapped the fields in
+ the above loop, don't swap here again */
+ if (mt->type == PO_ANCHOR_TYPE)
+ { // Polyobj Anchor Pt.
+ TranslateToStartSpot(mt->angle, mt->x<<FRACBITS, mt->y<<FRACBITS);
+ }
+ }
+ Z_Free (data);
+ // check for a startspot without an anchor point
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (!polyobjs[i].originalPts)
+ {
+ I_Error("PO_Init: StartSpot located without an Anchor point: %d\n",
+ polyobjs[i].tag);
+ }
+ }
+ InitBlockMap();
+}
+
+//==========================================================================
+//
+// PO_Busy
+//
+//==========================================================================
+
+boolean PO_Busy(int polyobj)
+{
+ polyobj_t *poly;
+
+ poly = GetPolyobj(polyobj);
+ if (!poly->specialdata)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
--- /dev/null
+++ b/r_bsp.c
@@ -1,0 +1,491 @@
+
+//**************************************************************************
+//**
+//** r_bsp.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+
+#ifndef RENDER3D
+
+#include "h2def.h"
+#include "r_local.h"
+
+seg_t *curline;
+side_t *sidedef;
+line_t *linedef;
+sector_t *frontsector, *backsector;
+
+drawseg_t drawsegs[MAXDRAWSEGS], *ds_p;
+
+void R_StoreWallRange (int start, int stop); /* r_segs.c */
+
+/*
+====================
+=
+= R_ClearDrawSegs
+=
+====================
+*/
+
+void R_ClearDrawSegs (void)
+{
+ ds_p = drawsegs;
+}
+
+//=============================================================================
+
+
+/*
+===============================================================================
+=
+= ClipWallSegment
+=
+= Clips the given range of columns and includes it in the new clip list
+===============================================================================
+*/
+
+typedef struct
+{
+ int first, last;
+} cliprange_t;
+
+#define MAXSEGS 32
+
+static cliprange_t solidsegs[MAXSEGS], *newend; // newend is one past the last valid seg
+
+
+static void R_ClipSolidWallSegment (int first, int last)
+{
+ cliprange_t *next, *start;
+
+// find the first range that touches the range (adjacent pixels are touching)
+ start = solidsegs;
+ while (start->last < first - 1)
+ start++;
+
+ if (first < start->first)
+ {
+ if (last < start->first - 1)
+ { // post is entirely visible (above start), so insert a new clippost
+ R_StoreWallRange (first, last);
+ next = newend;
+ newend++;
+ while (next != start)
+ {
+ *next = *(next - 1);
+ next--;
+ }
+ next->first = first;
+ next->last = last;
+ return;
+ }
+
+ // there is a fragment above *start
+ R_StoreWallRange (first, start->first - 1);
+ start->first = first; // adjust the clip size
+ }
+
+ if (last <= start->last)
+ return; // bottom contained in start
+
+ next = start;
+ while (last >= (next + 1)->first - 1)
+ {
+ // there is a fragment between two posts
+ R_StoreWallRange (next->last + 1, (next + 1)->first - 1);
+ next++;
+ if (last <= next->last)
+ { // bottom is contained in next
+ start->last = next->last; // adjust the clip size
+ goto crunch;
+ }
+ }
+
+ // there is a fragment after *next
+ R_StoreWallRange (next->last + 1, last);
+ start->last = last; // adjust the clip size
+
+// remove start+1 to next from the clip list,
+// because start now covers their area
+crunch:
+ if (next == start)
+ return; // post just extended past the bottom of one post
+
+ while (next++ != newend) // remove a post
+ *++start = *next;
+ newend = start + 1;
+}
+
+/*
+===============================================================================
+=
+= R_ClipPassWallSegment
+=
+= Clips the given range of columns, but does not includes it in the clip list
+===============================================================================
+*/
+
+static void R_ClipPassWallSegment (int first, int last)
+{
+ cliprange_t *start;
+
+// find the first range that touches the range (adjacent pixels are touching)
+ start = solidsegs;
+ while (start->last < first - 1)
+ start++;
+
+ if (first < start->first)
+ {
+ if (last < start->first - 1)
+ { // post is entirely visible (above start)
+ R_StoreWallRange (first, last);
+ return;
+ }
+
+ // there is a fragment above *start
+ R_StoreWallRange (first, start->first - 1);
+ }
+
+ if (last <= start->last)
+ return; // bottom contained in start
+
+ while (last >= (start + 1)->first - 1)
+ {
+ // there is a fragment between two posts
+ R_StoreWallRange (start->last + 1, (start + 1)->first - 1);
+ start++;
+ if (last <= start->last)
+ return;
+ }
+
+ // there is a fragment after *next
+ R_StoreWallRange (start->last + 1, last);
+}
+
+
+/*
+====================
+=
+= R_ClearClipSegs
+=
+====================
+*/
+
+void R_ClearClipSegs (void)
+{
+ solidsegs[0].first = -0x7fffffff;
+ solidsegs[0].last = -1;
+ solidsegs[1].first = viewwidth;
+ solidsegs[1].last = 0x7fffffff;
+ newend = solidsegs + 2;
+}
+
+
+//=============================================================================
+
+/*
+======================
+=
+= R_AddLine
+=
+= Clips the given segment and adds any visible pieces to the line list
+=
+======================
+*/
+
+static void R_AddLine (seg_t *line)
+{
+ int x1, x2;
+ angle_t angle1, angle2, span, tspan;
+
+ curline = line;
+
+// OPTIMIZE: quickly reject orthogonal back sides
+
+ angle1 = R_PointToAngle (line->v1->x, line->v1->y);
+ angle2 = R_PointToAngle (line->v2->x, line->v2->y);
+
+//
+// clip to view edges
+// OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW)
+ span = angle1 - angle2;
+ if (span >= ANG180)
+ return; // back side
+
+ rw_angle1 = angle1; // global angle needed by segcalc
+ angle1 -= viewangle;
+ angle2 -= viewangle;
+
+ tspan = angle1 + clipangle;
+ if (tspan > 2*clipangle)
+ {
+ tspan -= 2*clipangle;
+ if (tspan >= span)
+ return; // totally off the left edge
+ angle1 = clipangle;
+ }
+ tspan = clipangle - angle2;
+ if (tspan > 2*clipangle)
+ {
+ tspan -= 2*clipangle;
+ if (tspan >= span)
+ return; // totally off the left edge
+ angle2 = -clipangle;
+ }
+
+//
+// the seg is in the view range, but not necessarily visible
+//
+ angle1 = (angle1 + ANG90)>>ANGLETOFINESHIFT;
+ angle2 = (angle2 + ANG90)>>ANGLETOFINESHIFT;
+ x1 = viewangletox[angle1];
+ x2 = viewangletox[angle2];
+ if (x1 == x2)
+ return; // does not cross a pixel
+
+ backsector = line->backsector;
+
+ if (!backsector)
+ goto clipsolid; // single sided line
+
+ if (backsector->ceilingheight <= frontsector->floorheight ||
+ backsector->floorheight >= frontsector->ceilingheight)
+ goto clipsolid; // closed door
+
+ if (backsector->ceilingheight != frontsector->ceilingheight ||
+ backsector->floorheight != frontsector->floorheight)
+ goto clippass; // window
+
+// reject empty lines used for triggers and special events
+ if (backsector->ceilingpic == frontsector->ceilingpic &&
+ backsector->floorpic == frontsector->floorpic &&
+ backsector->lightlevel == frontsector->lightlevel &&
+ backsector->special == frontsector->special &&
+ curline->sidedef->midtexture == 0)
+ return;
+
+clippass:
+ R_ClipPassWallSegment (x1, x2 - 1);
+ return;
+
+clipsolid:
+ R_ClipSolidWallSegment (x1, x2 - 1);
+}
+
+//============================================================================
+
+
+/*
+===============================================================================
+=
+= R_CheckBBox
+=
+= Returns true if some part of the bbox might be visible
+=
+===============================================================================
+*/
+
+static int checkcoord[12][4] =
+{
+ {3,0, 2,1},
+ {3,0, 2,0},
+ {3,1, 2,0},
+ {0},
+ {2,0, 2,1},
+ {0,0,0,0},
+ {3,1, 3,0},
+ {0},
+ {2,0, 3,1},
+ {2,1, 3,1},
+ {2,1, 3,0}
+};
+
+static boolean R_CheckBBox (fixed_t *bspcoord)
+{
+ int boxx, boxy, boxpos;
+ fixed_t x1, y1, x2, y2;
+ angle_t angle1, angle2, span, tspan;
+ cliprange_t *start;
+ int sx1, sx2;
+
+// find the corners of the box that define the edges from current viewpoint
+ if (viewx <= bspcoord[BOXLEFT])
+ boxx = 0;
+ else if (viewx < bspcoord[BOXRIGHT])
+ boxx = 1;
+ else
+ boxx = 2;
+
+ if (viewy >= bspcoord[BOXTOP])
+ boxy = 0;
+ else if (viewy > bspcoord[BOXBOTTOM])
+ boxy = 1;
+ else
+ boxy = 2;
+
+ boxpos = (boxy<<2) + boxx;
+ if (boxpos == 5)
+ return true;
+
+ x1 = bspcoord[checkcoord[boxpos][0]];
+ y1 = bspcoord[checkcoord[boxpos][1]];
+ x2 = bspcoord[checkcoord[boxpos][2]];
+ y2 = bspcoord[checkcoord[boxpos][3]];
+
+//
+// check clip list for an open space
+//
+ angle1 = R_PointToAngle (x1, y1) - viewangle;
+ angle2 = R_PointToAngle (x2, y2) - viewangle;
+
+ span = angle1 - angle2;
+ if (span >= ANG180)
+ return true; // sitting on a line
+ tspan = angle1 + clipangle;
+ if (tspan > 2*clipangle)
+ {
+ tspan -= 2*clipangle;
+ if (tspan >= span)
+ return false; // totally off the left edge
+ angle1 = clipangle;
+ }
+ tspan = clipangle - angle2;
+ if (tspan > 2*clipangle)
+ {
+ tspan -= 2*clipangle;
+ if (tspan >= span)
+ return false; // totally off the left edge
+ angle2 = -clipangle;
+ }
+
+// find the first clippost that touches the source post (adjacent pixels are touching)
+ angle1 = (angle1 + ANG90)>>ANGLETOFINESHIFT;
+ angle2 = (angle2 + ANG90)>>ANGLETOFINESHIFT;
+ sx1 = viewangletox[angle1];
+ sx2 = viewangletox[angle2];
+ if (sx1 == sx2)
+ return false; // does not cross a pixel
+ sx2--;
+
+ start = solidsegs;
+ while (start->last < sx2)
+ start++;
+ if (sx1 >= start->first && sx2 <= start->last)
+ return false; // the clippost contains the new span
+
+ return true;
+}
+
+
+/*
+================
+=
+= R_Subsector
+=
+= Draw one or more segments
+================
+*/
+
+static void R_Subsector (int num)
+{
+ int count;
+ seg_t *line;
+ subsector_t *sub;
+ int polyCount;
+ seg_t **polySeg;
+
+#ifdef RANGECHECK
+ if (num >= numsubsectors)
+ I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors);
+#endif
+
+ sscount++;
+ sub = &subsectors[num];
+ frontsector = sub->sector;
+ count = sub->numlines;
+ line = &segs[sub->firstline];
+
+ if (frontsector->floorheight < viewz)
+ {
+ floorplane = R_FindPlane(frontsector->floorheight,
+ frontsector->floorpic,
+ frontsector->lightlevel,
+ frontsector->special);
+ }
+ else
+ {
+ floorplane = NULL;
+ }
+
+ if (frontsector->ceilingheight > viewz ||
+ frontsector->ceilingpic == skyflatnum)
+ {
+ ceilingplane = R_FindPlane(frontsector->ceilingheight,
+ frontsector->ceilingpic,
+ frontsector->lightlevel, 0);
+ }
+ else
+ {
+ ceilingplane = NULL;
+ }
+
+ R_AddSprites(frontsector);
+ if (sub->poly)
+ { // Render the polyobj in the subsector first
+ polyCount = sub->poly->numsegs;
+ polySeg = sub->poly->segs;
+ while (polyCount--)
+ {
+ R_AddLine(*polySeg++);
+ }
+ }
+ while (count--)
+ {
+ R_AddLine (line);
+ line++;
+ }
+}
+
+
+/*
+===============================================================================
+=
+= RenderBSPNode
+=
+===============================================================================
+*/
+
+void R_RenderBSPNode (int bspnum)
+{
+ node_t *bsp;
+ int side;
+
+ if (bspnum & NF_SUBSECTOR)
+ {
+ if (bspnum == -1)
+ R_Subsector (0);
+ else
+ R_Subsector (bspnum & (~NF_SUBSECTOR));
+ return;
+ }
+
+ bsp = &nodes[bspnum];
+
+//
+// decide which side the view point is on
+//
+ side = R_PointOnSide (viewx, viewy, bsp);
+
+ R_RenderBSPNode (bsp->children[side]); // recursively divide front space
+
+ if (R_CheckBBox (bsp->bbox[side^1])) // possibly divide back space
+ R_RenderBSPNode (bsp->children[side^1]);
+}
+
+#endif /* RENDER3D */
+
--- /dev/null
+++ b/r_data.c
@@ -1,0 +1,672 @@
+
+//**************************************************************************
+//**
+//** r_data.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "r_local.h"
+#include "p_local.h"
+
+
+int firstflat, lastflat, numflats;
+int firstpatch, lastpatch, numpatches;
+int firstspritelump, lastspritelump, numspritelumps;
+
+int numtextures;
+texture_t **textures;
+
+lighttable_t *colormaps;
+
+int *flattranslation; // for global animation
+int *texturetranslation; // for global animation
+
+fixed_t *spritewidth; // needed for pre rendering
+fixed_t *spriteoffset;
+fixed_t *spritetopoffset;
+
+fixed_t *textureheight; // needed for texture pegging
+
+static int *texturewidthmask;
+static int *texturecompositesize;
+static short **texturecolumnlump;
+static unsigned short **texturecolumnofs;
+static byte **texturecomposite;
+
+
+/*
+==============================================================================
+
+ MAPTEXTURE_T CACHING
+
+when a texture is first needed, it counts the number of composite columns
+required in the texture and allocates space for a column directory and any
+new columns. The directory will simply point inside other patches if there
+is only one patch in a given column, but any columns with multiple patches
+will have new column_ts generated.
+
+==============================================================================
+*/
+
+/*
+===================
+=
+= R_DrawColumnInCache
+=
+= Clip and draw a column from a patch into a cached post
+=
+===================
+*/
+
+static void R_DrawColumnInCache (column_t *patch, byte *cache, int originy, int cacheheight)
+{
+ int count, position;
+ byte *source;
+// byte *dest = (byte *)cache + 3;
+
+ while (patch->topdelta != 0xff)
+ {
+ source = (byte *)patch + 3;
+ count = patch->length;
+ position = originy + patch->topdelta;
+ if (position < 0)
+ {
+ count += position;
+ position = 0;
+ }
+ if (position + count > cacheheight)
+ count = cacheheight - position;
+ if (count > 0)
+ memcpy (cache + position, source, count);
+
+ patch = (column_t *)( (byte *)patch + patch->length + 4);
+ }
+}
+
+
+/*
+===================
+=
+= R_GenerateComposite
+=
+===================
+*/
+
+static void R_GenerateComposite (int texnum)
+{
+ byte *block;
+ texture_t *texture;
+ texpatch_t *patch;
+ patch_t *realpatch;
+ int x, x1, x2;
+ int i;
+ column_t *patchcol;
+ short *collump;
+ unsigned short *colofs;
+
+ texture = textures[texnum];
+ block = (byte *) Z_Malloc (texturecompositesize[texnum], PU_STATIC, &texturecomposite[texnum]);
+ collump = texturecolumnlump[texnum];
+ colofs = texturecolumnofs[texnum];
+
+//
+// composite the columns together
+//
+ patch = texture->patches;
+
+ for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
+ {
+ realpatch = (patch_t *) W_CacheLumpNum (patch->patch, PU_CACHE);
+ x1 = patch->originx;
+ x2 = x1 + SHORT(realpatch->width);
+
+ if (x1 < 0)
+ x = 0;
+ else
+ x = x1;
+ if (x2 > texture->width)
+ x2 = texture->width;
+
+ for ( ; x < x2 ; x++)
+ {
+ if (collump[x] >= 0)
+ continue; // column does not have multiple patches
+ patchcol = (column_t *)((byte *)realpatch + LONG(realpatch->columnofs[x - x1]));
+ R_DrawColumnInCache (patchcol, block + colofs[x], patch->originy, texture->height);
+ }
+ }
+
+// now that the texture has been built, it is purgable
+ Z_ChangeTag (block, PU_CACHE);
+}
+
+
+/*
+===================
+=
+= R_GenerateLookup
+=
+===================
+*/
+
+static void R_GenerateLookup (int texnum)
+{
+ texture_t *texture;
+ byte *patchcount; // [texture->width]
+ texpatch_t *patch;
+ patch_t *realpatch;
+ int x, x1, x2;
+ int i;
+ short *collump;
+ unsigned short *colofs;
+
+ texture = textures[texnum];
+
+ texturecomposite[texnum] = 0; // composited not created yet
+ texturecompositesize[texnum] = 0;
+ collump = texturecolumnlump[texnum];
+ colofs = texturecolumnofs[texnum];
+
+//
+// count the number of columns that are covered by more than one patch
+// fill in the lump / offset, so columns with only a single patch are
+// all done
+//
+ patchcount = (byte *)malloc (texture->width);
+ memset (patchcount, 0, texture->width);
+ patch = texture->patches;
+
+ for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
+ {
+ realpatch = (patch_t *) W_CacheLumpNum (patch->patch, PU_CACHE);
+ x1 = patch->originx;
+ x2 = x1 + SHORT(realpatch->width);
+ if (x1 < 0)
+ x = 0;
+ else
+ x = x1;
+ if (x2 > texture->width)
+ x2 = texture->width;
+ for ( ; x < x2 ; x++)
+ {
+ patchcount[x]++;
+ collump[x] = patch->patch;
+ colofs[x] = LONG(realpatch->columnofs[x - x1]) + 3;
+ }
+ }
+
+ for (x = 0; x < texture->width; x++)
+ {
+ if (!patchcount[x])
+ {
+ char name[9];
+ name[8] = 0;
+ memcpy (name, texture->name, 8);
+ // I_Error ("R_GenerateLookup: column without a patch");
+ ST_Message ("R_GenerateLookup: column without a patch (%s)\n", name);
+ free (patchcount);
+ return;
+ }
+ if (patchcount[x] > 1)
+ {
+ collump[x] = -1; // use the cached block
+ colofs[x] = texturecompositesize[texnum];
+ if (texturecompositesize[texnum] > 0x10000 - texture->height)
+ I_Error ("R_GenerateLookup: texture %i is >64k", texnum);
+ texturecompositesize[texnum] += texture->height;
+ }
+ }
+ free (patchcount);
+}
+
+
+/*
+================
+=
+= R_GetColumn
+=
+================
+*/
+
+byte *R_GetColumn (int tex, int col)
+{
+ int lump, ofs;
+
+ col &= texturewidthmask[tex];
+ lump = texturecolumnlump[tex][col];
+ ofs = texturecolumnofs[tex][col];
+ if (lump > 0)
+ return (byte *)W_CacheLumpNum(lump, PU_CACHE) + ofs;
+ if (!texturecomposite[tex])
+ R_GenerateComposite (tex);
+ return texturecomposite[tex] + ofs;
+}
+
+
+/*
+==================
+=
+= R_InitTextures
+=
+= Initializes the texture list with the textures from the world map
+=
+==================
+*/
+
+static void R_InitTextures (void)
+{
+ maptexture_t *mtexture;
+ texture_t *texture;
+ mappatch_t *mpatch;
+ texpatch_t *patch;
+ int i, j;
+ int *maptex, *maptex2, *maptex1;
+ byte *names;
+ char name[9], *name_p;
+ int *patchlookup;
+ int totalwidth;
+ int nummappatches;
+ int offset, maxoff, maxoff2;
+ int numtextures1, numtextures2;
+ int *directory;
+
+//
+// load the patch names from pnames.lmp
+//
+ name[8] = 0;
+ names = (byte *) W_CacheLumpName ("PNAMES", PU_STATIC);
+ nummappatches = READ_INT32(names);
+ name_p = (char *)names + 4;
+ patchlookup = (int *)malloc(nummappatches*sizeof(*patchlookup));
+ for (i = 0; i < nummappatches; i++)
+ {
+ strncpy (name, name_p + i*8, 8);
+ patchlookup[i] = W_CheckNumForName (name);
+ }
+ Z_Free (names);
+
+//
+// load the map texture definitions from textures.lmp
+//
+ maptex = maptex1 = (int *) W_CacheLumpName ("TEXTURE1", PU_STATIC);
+ numtextures1 = LONG(*maptex);
+ maxoff = W_LumpLength (W_GetNumForName ("TEXTURE1"));
+ directory = maptex + 1;
+
+ if (W_CheckNumForName ("TEXTURE2") != -1)
+ {
+ maptex2 = (int *) W_CacheLumpName ("TEXTURE2", PU_STATIC);
+ numtextures2 = LONG(*maptex2);
+ maxoff2 = W_LumpLength (W_GetNumForName ("TEXTURE2"));
+ }
+ else
+ {
+ maptex2 = NULL;
+ numtextures2 = 0;
+ maxoff2 = 0;
+ }
+ numtextures = numtextures1 + numtextures2;
+
+ textures = (texture_t **) Z_Malloc (numtextures*sizeof(texture_t *), PU_STATIC, NULL);
+ texturecolumnlump = (short **) Z_Malloc (numtextures*sizeof(short *), PU_STATIC, NULL);
+ texturecolumnofs = (unsigned short **) Z_Malloc (numtextures*sizeof(short *), PU_STATIC, NULL);
+ texturecomposite = (byte **) Z_Malloc (numtextures*sizeof(byte *), PU_STATIC, NULL);
+ texturecompositesize = (int *) Z_Malloc (numtextures*sizeof(int), PU_STATIC, NULL);
+ texturewidthmask = (int *) Z_Malloc (numtextures*sizeof(int), PU_STATIC, NULL);
+ textureheight = (fixed_t *) Z_Malloc (numtextures*sizeof(fixed_t), PU_STATIC, NULL);
+
+ totalwidth = 0;
+
+ for (i = 0; i < numtextures; i++, directory++)
+ {
+ if (i == numtextures1)
+ { // start looking in second texture file
+ maptex = maptex2;
+ maxoff = maxoff2;
+ directory = maptex + 1;
+ }
+
+ offset = LONG(*directory);
+ if (offset > maxoff)
+ I_Error ("R_InitTextures: bad texture directory");
+ mtexture = (maptexture_t *) ( (byte *)maptex + offset);
+ j = SHORT(mtexture->patchcount);
+ texture = textures[i] = (texture_t *)
+ Z_Malloc (sizeof(texture_t) + sizeof(texpatch_t)*(j - 1), PU_STATIC, NULL);
+ texture->width = SHORT(mtexture->width);
+ texture->height = SHORT(mtexture->height);
+ texture->patchcount = SHORT(mtexture->patchcount);
+ name_p = (char *)maptex + offset;
+ memcpy (texture->name, name_p, sizeof(texture->name));
+ mpatch = &mtexture->patches[0];
+ patch = &texture->patches[0];
+ for (j = 0; j < texture->patchcount; j++, mpatch++, patch++)
+ {
+ patch->originx = SHORT(mpatch->originx);
+ patch->originy = SHORT(mpatch->originy);
+ patch->patch = patchlookup[SHORT(mpatch->patch)];
+ if (patch->patch == -1)
+ {
+ memcpy (name, texture->name, 8);
+ I_Error ("R_InitTextures: Missing patch in texture %s", name);
+ }
+ }
+ texturecolumnlump[i] = (short *) Z_Malloc (texture->width*2, PU_STATIC, NULL);
+ texturecolumnofs[i] = (unsigned short *) Z_Malloc (texture->width*2, PU_STATIC, NULL);
+ j = 1;
+ while (j*2 <= texture->width)
+ j<<=1;
+ texturewidthmask[i] = j - 1;
+ textureheight[i] = texture->height<<FRACBITS;
+
+ totalwidth += texture->width;
+ }
+
+ Z_Free (maptex1);
+ if (maptex2)
+ Z_Free (maptex2);
+
+//
+// precalculate whatever possible
+//
+ for (i = 0; i < numtextures; i++)
+ {
+ R_GenerateLookup (i);
+ if (!(i & 31))
+ ST_Progress();
+ }
+
+//
+// translation table for global animation
+//
+ texturetranslation = (int *) Z_Malloc ((numtextures + 1)*sizeof(int), PU_STATIC, NULL);
+ for (i = 0; i < numtextures; i++)
+ texturetranslation[i] = i;
+
+ free (patchlookup);
+}
+
+
+/*
+================
+=
+= R_InitFlats
+=
+=================
+*/
+
+static void R_InitFlats (void)
+{
+ int i;
+
+ firstflat = W_GetNumForName ("F_START") + 1;
+ lastflat = W_GetNumForName ("F_END") - 1;
+ numflats = lastflat - firstflat + 1;
+
+// translation table for global animation
+ flattranslation = (int *) Z_Malloc ((numflats + 1) * sizeof(int), PU_STATIC, NULL);
+ for (i = 0; i < numflats; i++)
+ flattranslation[i] = i;
+}
+
+
+/*
+================
+=
+= R_InitSpriteLumps
+=
+= Finds the width and hoffset of all sprites in the wad, so the sprite doesn't
+= need to be cached just for the header during rendering
+=================
+*/
+
+static void R_InitSpriteLumps (void)
+{
+ int i;
+ patch_t *patch;
+
+ firstspritelump = W_GetNumForName ("S_START") + 1;
+ lastspritelump = W_GetNumForName ("S_END") - 1;
+ numspritelumps = lastspritelump - firstspritelump + 1;
+ spritewidth = (fixed_t *) Z_Malloc (numspritelumps*sizeof(fixed_t), PU_STATIC, NULL);
+ spriteoffset = (fixed_t *) Z_Malloc (numspritelumps*sizeof(fixed_t), PU_STATIC, NULL);
+ spritetopoffset = (fixed_t *) Z_Malloc (numspritelumps*sizeof(fixed_t), PU_STATIC, NULL);
+
+ for (i = 0; i < numspritelumps; i++)
+ {
+ if (!(i & 127))
+ ST_Progress();
+ patch = (patch_t *) W_CacheLumpNum (firstspritelump + i, PU_CACHE);
+ spritewidth[i] = SHORT(patch->width)<<FRACBITS;
+ spriteoffset[i] = SHORT(patch->leftoffset)<<FRACBITS;
+ spritetopoffset[i] = SHORT(patch->topoffset)<<FRACBITS;
+ }
+}
+
+
+/*
+================
+=
+= R_InitColormaps
+=
+=================
+*/
+
+static void R_InitColormaps (void)
+{
+ int lump, length;
+//
+// load in the light tables
+// 256 byte align tables
+//
+ lump = W_GetNumForName("COLORMAP");
+ length = W_LumpLength (lump) + 255;
+ colormaps = (lighttable_t *) Z_Malloc (length, PU_STATIC, NULL);
+ colormaps = (byte *)( ((intptr_t)colormaps + 255) & ~0xff);
+ W_ReadLump (lump, colormaps);
+}
+
+
+/*
+================
+=
+= R_InitData
+=
+= Locates all the lumps that will be used by all views
+= Must be called after W_Init
+=================
+*/
+
+void R_InitData (void)
+{
+ R_InitTextures();
+ R_InitFlats();
+ R_InitSpriteLumps();
+ R_InitColormaps();
+}
+
+//=============================================================================
+
+/*
+================
+=
+= R_FlatNumForName
+=
+================
+*/
+
+int R_FlatNumForName (const char *name)
+{
+ int i;
+ char namet[9];
+
+ i = W_CheckNumForName (name);
+ if (i == -1)
+ {
+ namet[8] = 0;
+ memcpy (namet, name,8);
+ I_Error ("R_FlatNumForName: %s not found", namet);
+ }
+ return i - firstflat;
+}
+
+
+/*
+================
+=
+= R_CheckTextureNumForName
+=
+================
+*/
+
+int R_CheckTextureNumForName (const char *name)
+{
+ int i;
+
+ if (name[0] == '-') // no texture marker
+ return 0;
+
+ for (i = 0; i < numtextures; i++)
+ {
+ if (!strncasecmp(textures[i]->name, name, 8))
+ return i;
+ }
+
+ return -1;
+}
+
+
+/*
+================
+=
+= R_TextureNumForName
+=
+================
+*/
+
+int R_TextureNumForName (const char *name)
+{
+ int i;
+
+ i = R_CheckTextureNumForName (name);
+ if (i == -1)
+ I_Error ("R_TextureNumForName: %s not found", name);
+
+ return i;
+}
+
+
+/*
+=================
+=
+= R_PrecacheLevel
+=
+= Preloads all relevent graphics for the level
+=================
+*/
+
+static int flatmemory, texturememory, spritememory;
+
+void R_PrecacheLevel (void)
+{
+ char *flatpresent;
+ char *texturepresent;
+ char *spritepresent;
+ int i, j, k, lump;
+ texture_t *texture;
+ thinker_t *th;
+ spriteframe_t *sf;
+
+ if (demoplayback)
+ return;
+
+//
+// precache flats
+//
+ flatpresent = (char*)malloc(numflats);
+ memset (flatpresent, 0, numflats);
+ for (i = 0; i < numsectors; i++)
+ {
+ flatpresent[sectors[i].floorpic] = 1;
+ flatpresent[sectors[i].ceilingpic] = 1;
+ }
+
+ flatmemory = 0;
+ for (i = 0; i < numflats; i++)
+ {
+ if (flatpresent[i])
+ {
+ lump = firstflat + i;
+ flatmemory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump, PU_CACHE);
+ }
+ }
+
+//
+// precache textures
+//
+ texturepresent = (char*) malloc(numtextures);
+ memset (texturepresent, 0, numtextures);
+
+ for (i = 0; i < numsides; i++)
+ {
+ texturepresent[sides[i].toptexture] = 1;
+ texturepresent[sides[i].midtexture] = 1;
+ texturepresent[sides[i].bottomtexture] = 1;
+ }
+
+ texturepresent[Sky1Texture] = 1;
+ texturepresent[Sky2Texture] = 1;
+
+ texturememory = 0;
+ for (i = 0; i < numtextures; i++)
+ {
+ if (!texturepresent[i])
+ continue;
+ texture = textures[i];
+ for (j = 0; j < texture->patchcount; j++)
+ {
+ lump = texture->patches[j].patch;
+ texturememory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump, PU_CACHE);
+ }
+ }
+
+//
+// precache sprites
+//
+ spritepresent = (char*)malloc(numsprites);
+ memset (spritepresent, 0, numsprites);
+
+ for (th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if (th->function == P_MobjThinker)
+ spritepresent[((mobj_t *)th)->sprite] = 1;
+ }
+
+ spritememory = 0;
+ for (i = 0; i < numsprites; i++)
+ {
+ if (!spritepresent[i])
+ continue;
+ for (j = 0; j < sprites[i].numframes; j++)
+ {
+ sf = &sprites[i].spriteframes[j];
+ for (k = 0; k < 8; k++)
+ {
+ lump = firstspritelump + sf->lump[k];
+ spritememory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump, PU_CACHE);
+ }
+ }
+ }
+ free (flatpresent);
+ free (texturepresent);
+ free (spritepresent);
+}
+
--- /dev/null
+++ b/r_draw.c
@@ -1,0 +1,583 @@
+
+//**************************************************************************
+//**
+//** r_draw.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+
+#ifndef RENDER3D
+
+#include "h2def.h"
+#include "r_local.h"
+
+/*
+
+All drawing to the view buffer is accomplished in this file. The other refresh
+files only know about ccordinates, not the architecture of the frame buffer.
+
+*/
+
+int viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy;
+
+byte *ylookup[MAXHEIGHT];
+int columnofs[MAXWIDTH];
+byte *tinttable; // used for translucent sprites
+
+
+/*
+==================
+=
+= R_DrawColumn
+=
+= Source is the top of the column to scale
+=
+==================
+*/
+
+lighttable_t *dc_colormap;
+int dc_x;
+int dc_yl;
+int dc_yh;
+fixed_t dc_iscale;
+fixed_t dc_texturemid;
+byte *dc_source; // first pixel in a column (possibly virtual)
+
+//int dccount; // just for profiling
+
+
+//#ifndef __i386
+//#ifndef __m68k
+void R_DrawColumn (void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+ do
+ {
+ *dest = dc_colormap[dc_source[(frac>>FRACBITS) & 127]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while (count--);
+}
+//#endif // __m68k
+//#endif // __i386
+
+void R_DrawColumnLow (void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+// dccount++;
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+ do
+ {
+ *dest = dc_colormap[dc_source[(frac>>FRACBITS) & 127]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while (count--);
+}
+
+/*
+#define FUZZTABLE 50
+#define FUZZOFF (SCREENWIDTH)
+static int fuzzoffset[FUZZTABLE] =
+{
+ FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
+ FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
+ FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,
+ FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
+ FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,
+ FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,
+ FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF
+};
+static int fuzzpos = 0;
+*/
+
+void R_DrawFuzzColumn (void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ if (!dc_yl)
+ dc_yl = 1;
+ if (dc_yh == viewheight - 1)
+ dc_yh = viewheight - 2;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error ("R_DrawFuzzColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+// OLD FUZZY INVISO SPRITE STUFF
+/*
+ do
+ {
+ *dest = colormaps[6*256 + dest[fuzzoffset[fuzzpos]]];
+ if (++fuzzpos == FUZZTABLE)
+ fuzzpos = 0;
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while (count--);
+*/
+ do
+ {
+ *dest = tinttable[*dest + (dc_colormap[dc_source[(frac>>FRACBITS) & 127]]<<8)];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while (count--);
+}
+
+
+//============================================================================
+//
+// R_DrawAltFuzzColumn
+//
+//============================================================================
+
+void R_DrawAltFuzzColumn (void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ if (!dc_yl)
+ dc_yl = 1;
+ if (dc_yh == viewheight - 1)
+ dc_yh = viewheight - 2;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error ("R_DrawFuzzColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+ do
+ {
+ *dest = tinttable[((*dest)<<8) + dc_colormap[dc_source[(frac>>FRACBITS) & 127]]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while (count--);
+}
+
+/*
+========================
+=
+= R_DrawTranslatedColumn
+=
+========================
+*/
+
+byte *dc_translation;
+byte *translationtables;
+
+void R_DrawTranslatedColumn (void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+ do
+ {
+ *dest = dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while (count--);
+}
+
+//============================================================================
+//
+// R_DrawTranslatedFuzzColumn
+//
+//============================================================================
+
+void R_DrawTranslatedFuzzColumn (void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+ do
+ {
+ *dest = tinttable[((*dest)<<8) + dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while (count--);
+}
+
+//============================================================================
+//
+// R_DrawTranslatedAltFuzzColumn
+//
+//============================================================================
+
+/*
+void R_DrawTranslatedAltFuzzColumn (void)
+{
+ int count;
+ byte *dest;
+ fixed_t frac, fracstep;
+
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ return;
+
+#ifdef RANGECHECK
+ if ((unsigned)dc_x >= SCREENWIDTH || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ I_Error ("R_DrawColumn: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl - centery)*fracstep;
+
+ do
+ {
+ *dest = tinttable[*dest + (dc_colormap[dc_translation[dc_source[frac>>FRACBITS]]]<<8)];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while (count--);
+}
+*/
+
+//--------------------------------------------------------------------------
+//
+// PROC R_InitTranslationTables
+//
+//--------------------------------------------------------------------------
+
+/* version 1.0 wad has 9 lumps: trantbl0 ... trantbl8 */
+#if 0
+static byte transtable10[256 * 3 * (MAXPLAYERS_10 - 1)] =
+{
+# include "transtb10.h"
+};
+#endif
+/* version 1.1 wad has 21 lumps: trantbl0 .. trantbl9
+ and trantbla .. trantblk */
+#if (MAXPLAYERS == MAXPLAYERS_11)
+static byte transtable11[256 * 3 * (MAXPLAYERS_11 - 1)] =
+{
+# include "transtb11.h"
+};
+#define TRANTBL11_OFS (256 * 3 * (MAXPLAYERS_10 - 1))
+#define TRANTBL11_CNT (256 * 3 * (MAXPLAYERS_11 - MAXPLAYERS_10))
+#endif
+
+void R_InitTranslationTables (void)
+{
+ int i;
+ byte *transLump;
+
+ // Load tint table
+ tinttable = (byte *) W_CacheLumpName("TINTTAB", PU_STATIC);
+
+ // Allocate translation tables
+ translationtables = (byte *) Z_Malloc(256 * 3 * (MAXPLAYERS - 1) + 255, PU_STATIC, NULL);
+ translationtables = (byte *)(((intptr_t)translationtables + 255) & ~255);
+
+ for (i = 0; i < 3 * (MAXPLAYERS - 1); i++)
+ {
+#if (MAXPLAYERS == MAXPLAYERS_11)
+ if (oldwad_10 && i == 3 * (MAXPLAYERS_10 - 1))
+ {
+ /* HACK !! --- old 1.0 wad doesn't have TRANTBL9
+ * to TRANTBLK. Let's just copy from
+ * the extracted v1.1 data. */
+ memcpy (translationtables + TRANTBL11_OFS,
+ transtable11 + TRANTBL11_OFS, TRANTBL11_CNT);
+ break;
+ }
+#endif /* 8-players */
+ transLump = (byte *) W_CacheLumpNum(W_GetNumForName("trantbl0") + i, PU_STATIC);
+ memcpy(translationtables + i*256, transLump, 256);
+ Z_Free(transLump);
+ }
+}
+
+/*
+================
+=
+= R_DrawSpan
+=
+================
+*/
+
+int ds_y;
+int ds_x1;
+int ds_x2;
+lighttable_t *ds_colormap;
+fixed_t ds_xfrac;
+fixed_t ds_yfrac;
+fixed_t ds_xstep;
+fixed_t ds_ystep;
+byte *ds_source; // start of a 64*64 tile image
+
+//int dscount; // just for profiling
+
+
+//#ifndef __i386
+//#ifndef __m68k
+void R_DrawSpan (void)
+{
+ fixed_t xfrac, yfrac;
+ byte *dest;
+ int count, spot;
+
+#ifdef RANGECHECK
+ if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH || (unsigned)ds_y > SCREENHEIGHT)
+ I_Error ("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y);
+// dscount++;
+#endif
+
+ xfrac = ds_xfrac;
+ yfrac = ds_yfrac;
+
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+ count = ds_x2 - ds_x1;
+ do
+ {
+ spot = ((yfrac>>(16-6)) & (63*64)) + ((xfrac>>16) & 63);
+ *dest++ = ds_colormap[ds_source[spot]];
+ xfrac += ds_xstep;
+ yfrac += ds_ystep;
+ } while (count--);
+}
+//#endif
+//#endif
+
+void R_DrawSpanLow (void)
+{
+ fixed_t xfrac, yfrac;
+ byte *dest;
+ int count, spot;
+
+#ifdef RANGECHECK
+ if (ds_x2 < ds_x1 || ds_x1 < 0 || ds_x2 >= SCREENWIDTH || (unsigned)ds_y > SCREENHEIGHT)
+ I_Error ("R_DrawSpan: %i to %i at %i", ds_x1, ds_x2, ds_y);
+// dscount++;
+#endif
+
+ xfrac = ds_xfrac;
+ yfrac = ds_yfrac;
+
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+ count = ds_x2 - ds_x1;
+ do
+ {
+ spot = ((yfrac>>(16-6)) & (63*64)) + ((xfrac>>16) & 63);
+ *dest++ = ds_colormap[ds_source[spot]];
+ xfrac += ds_xstep;
+ yfrac += ds_ystep;
+ } while (count--);
+}
+
+
+/*
+================
+=
+= R_InitBuffer
+=
+=================
+*/
+
+void R_InitBuffer (int width, int height)
+{
+ int i;
+
+ viewwindowx = (SCREENWIDTH - width) >> 1;
+ for (i = 0; i < width; i++)
+ columnofs[i] = viewwindowx + i;
+ if (width == SCREENWIDTH)
+ viewwindowy = 0;
+ else
+ viewwindowy = (SCREENHEIGHT - SBARHEIGHT - height) >> 1;
+ for (i = 0; i < height; i++)
+ ylookup[i] = screen + (i + viewwindowy)*SCREENWIDTH;
+}
+
+
+/*
+==================
+=
+= R_DrawViewBorder
+=
+= Draws the border around the view for different size windows
+==================
+*/
+
+boolean BorderNeedRefresh;
+
+void R_DrawViewBorder (void)
+{
+ byte *src, *dest;
+ int x, y;
+
+ if (scaledviewwidth == SCREENWIDTH)
+ return;
+
+ src = (byte *) W_CacheLumpName("F_022", PU_CACHE);
+ dest = screen;
+
+ for (y = 0 ; y < SCREENHEIGHT - SBARHEIGHT; y++)
+ {
+ for (x = 0; x < SCREENWIDTH/64; x++)
+ {
+ memcpy (dest, src + ((y & 63)<<6), 64);
+ dest += 64;
+ }
+ if (SCREENWIDTH & 63)
+ {
+ memcpy (dest, src + ((y & 63)<<6), SCREENWIDTH & 63);
+ dest += (SCREENWIDTH & 63);
+ }
+ }
+ for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16)
+ {
+ V_DrawPatch(x, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordt", PU_CACHE));
+ V_DrawPatch(x, viewwindowy + viewheight, (patch_t *)W_CacheLumpName("bordb", PU_CACHE));
+ }
+ for (y = viewwindowy; y < viewwindowy + viewheight; y += 16)
+ {
+ V_DrawPatch(viewwindowx - 4, y, (patch_t *)W_CacheLumpName("bordl", PU_CACHE));
+ V_DrawPatch(viewwindowx+viewwidth, y, (patch_t *)W_CacheLumpName("bordr", PU_CACHE));
+ }
+ V_DrawPatch(viewwindowx - 4, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordtl", PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordtr", PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy + viewheight, (patch_t *)W_CacheLumpName("bordbr", PU_CACHE));
+ V_DrawPatch(viewwindowx - 4, viewwindowy + viewheight, (patch_t *)W_CacheLumpName("bordbl", PU_CACHE));
+}
+
+/*
+==================
+=
+= R_DrawTopBorder
+=
+= Draws the top border around the view for different size windows
+==================
+*/
+
+boolean BorderTopRefresh;
+
+void R_DrawTopBorder (void)
+{
+ byte *src, *dest;
+ int x, y;
+
+ if (scaledviewwidth == SCREENWIDTH)
+ return;
+
+ src = (byte *) W_CacheLumpName("F_022", PU_CACHE);
+ dest = screen;
+
+ for (y = 0; y < 34; y++)
+ {
+ for (x = 0; x < SCREENWIDTH/64; x++)
+ {
+ memcpy (dest, src + ((y & 63)<<6), 64);
+ dest += 64;
+ }
+ if (SCREENWIDTH & 63)
+ {
+ memcpy (dest, src + ((y & 63)<<6), SCREENWIDTH & 63);
+ dest += (SCREENWIDTH & 63);
+ }
+ }
+ if (viewwindowy < 35)
+ {
+ for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16)
+ {
+ V_DrawPatch(x, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordt", PU_CACHE));
+ }
+ V_DrawPatch(viewwindowx-4, viewwindowy, (patch_t *)W_CacheLumpName("bordl", PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy, (patch_t *)W_CacheLumpName("bordr", PU_CACHE));
+ V_DrawPatch(viewwindowx - 4, viewwindowy + 16, (patch_t *)W_CacheLumpName("bordl", PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy + 16, (patch_t *)W_CacheLumpName("bordr", PU_CACHE));
+
+ V_DrawPatch(viewwindowx - 4, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordtl", PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4, (patch_t *)W_CacheLumpName("bordtr", PU_CACHE));
+ }
+}
+
+#endif /* RENDER3D */
+
--- /dev/null
+++ b/r_local.h
@@ -1,0 +1,563 @@
+
+//**************************************************************************
+//**
+//** r_local.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __R_LOCAL__
+#define __R_LOCAL__
+
+#define ANGLETOSKYSHIFT 22 /* sky map is 256*128*4 maps */
+
+#define BASEYCENTER 100
+
+#define MAXWIDTH 1120
+#define MAXHEIGHT 832
+
+#define PI 3.141592657
+
+#define CENTERY (SCREENHEIGHT / 2)
+
+#define MINZ (FRACUNIT * 4)
+
+#define FIELDOFVIEW 2048 /* fineangles in the SCREENWIDTH wide window */
+
+/* lighting constants */
+#define LIGHTLEVELS 16
+#define LIGHTSEGSHIFT 4
+#define MAXLIGHTSCALE 48
+#define LIGHTSCALESHIFT 12
+#define MAXLIGHTZ 128
+#define LIGHTZSHIFT 20
+#define NUMCOLORMAPS 32 /* number of diminishing */
+#define INVERSECOLORMAP 32
+
+
+/* ------ INTERNAL MAP TYPES ------ */
+
+/* ---- used by play and refresh ---- */
+
+typedef struct
+{
+ fixed_t x,y;
+} vertex_t;
+
+struct line_s;
+
+typedef struct
+{
+ fixed_t floorheight, ceilingheight;
+ short floorpic, ceilingpic;
+ short lightlevel;
+ short special, tag;
+
+ int soundtraversed; /* 0 = untraversed, 1,2 = sndlines -1 */
+ mobj_t *soundtarget; /* thing that made a sound (or null) */
+ seqtype_t seqType; /* stone, metal, heavy, etc.. */
+
+ int blockbox[4]; /* mapblock bounding box for height changes */
+ degenmobj_t soundorg; /* for any sounds played by the sector */
+ int validcount; /* if == validcount, already checked */
+ mobj_t *thinglist; /* list of mobjs in sector */
+ void *specialdata; /* thinker_t for reversable actions */
+ int linecount;
+ struct line_s **lines; /* [linecount] size */
+
+#ifdef RENDER3D
+ int flatoffx, flatoffy; /* Scrolling flats. */
+ int skyfix; /* Offset to ceiling height rendering w/sky. */
+#endif
+
+} sector_t;
+
+typedef struct
+{
+ fixed_t textureoffset; /* add this to the calculated texture col */
+ fixed_t rowoffset; /* add this to the calculated texture top */
+ short toptexture, bottomtexture, midtexture;
+ sector_t *sector;
+} side_t;
+
+typedef enum
+{
+ ST_HORIZONTAL,
+ ST_VERTICAL,
+ ST_POSITIVE,
+ ST_NEGATIVE
+} slopetype_t;
+
+/*
+typedef struct line_s
+{
+ vertex_t *v1, *v2;
+ fixed_t dx,dy; // v2 - v1 for side checking
+ short flags;
+ short special, tag;
+ short sidenum[2]; // sidenum[1] will be -1 if one sided
+ fixed_t bbox[4];
+ slopetype_t slopetype; // to aid move clipping
+ sector_t *frontsector, *backsector;
+ int validcount; // if == validcount, already checked
+ void *specialdata; // thinker_t for reversable actions
+} line_t;
+*/
+
+typedef struct line_s
+{
+ vertex_t *v1;
+ vertex_t *v2;
+ fixed_t dx;
+ fixed_t dy;
+ short flags;
+ byte special;
+ byte arg1;
+ byte arg2;
+ byte arg3;
+ byte arg4;
+ byte arg5;
+ short sidenum[2];
+ fixed_t bbox[4];
+ slopetype_t slopetype;
+ sector_t *frontsector;
+ sector_t *backsector;
+ int validcount;
+ void *specialdata;
+} line_t;
+
+typedef struct
+{
+ vertex_t *v1, *v2;
+ fixed_t offset;
+ angle_t angle;
+ side_t *sidedef;
+ line_t *linedef;
+ sector_t *frontsector;
+ sector_t *backsector; /* NULL for one sided lines */
+#ifdef RENDER3D
+ float len; /* Length of the segment (v1 -> v2) for texture mapping. */
+#endif
+} seg_t;
+
+
+/* ---- Polyobj data ---- */
+
+typedef struct
+{
+ int numsegs;
+ seg_t **segs;
+ degenmobj_t startSpot;
+ vertex_t *originalPts; /* used as the base for the rotations */
+ vertex_t *prevPts; /* use to restore the old point values */
+ angle_t angle;
+ int tag; /* reference tag assigned in HereticEd */
+ int bbox[4];
+ int validcount;
+ boolean crush; /* should the polyobj attempt to crush mobjs? */
+ int seqType;
+ fixed_t size; /* polyobj size (area of POLY_AREAUNIT == size of FRACUNIT) */
+ void *specialdata; /* pointer a thinker, if the poly is moving */
+} polyobj_t;
+
+typedef struct polyblock_s
+{
+ polyobj_t *polyobj;
+ struct polyblock_s *prev;
+ struct polyblock_s *next;
+} polyblock_t;
+
+
+#ifdef RENDER3D
+typedef struct
+{
+ float x, y;
+} fvertex_t;
+#endif
+
+typedef struct subsector_s
+{
+ sector_t *sector;
+ short numlines;
+ short firstline;
+ polyobj_t *poly;
+#ifdef RENDER3D
+ /* Sorted edge vertices for rendering floors and ceilings. */
+ char numedgeverts;
+ fvertex_t *edgeverts; /* A list of edge vertices. */
+ fvertex_t *origedgeverts; /* Unmodified, accurate edge vertices. */
+ fvertex_t bbox[2]; /* Min and max points. */
+ fvertex_t midpoint; /* Center of bounding box. */
+#endif
+} subsector_t;
+
+typedef struct
+{
+ fixed_t x, y, dx, dy; /* partition line */
+ fixed_t bbox[2][4]; /* bounding box for each child */
+ unsigned short children[2]; /* if NF_SUBSECTOR its a subsector */
+} node_t;
+
+
+/* ------ OTHER TYPES ------ */
+
+typedef byte lighttable_t; /* this could be wider for >8 bit display */
+
+#define MAXVISPLANES 160
+#define MAXOPENINGS (SCREENWIDTH * 64)
+
+typedef struct
+{
+ fixed_t height;
+ int picnum;
+ int lightlevel;
+ int special;
+ int minx, maxx;
+ byte pad1; /* leave pads for [minx-1]/[maxx+1] */
+ byte top[SCREENWIDTH];
+ byte pad2;
+ byte pad3;
+ byte bottom[SCREENWIDTH];
+ byte pad4;
+} visplane_t;
+
+typedef struct drawseg_s
+{
+ seg_t *curline;
+ int x1, x2;
+ fixed_t scale1, scale2, scalestep;
+ int silhouette; /* 0 = none, 1 = bottom, 2 = top, 3 = both */
+ fixed_t bsilheight; /* don't clip sprites above this */
+ fixed_t tsilheight; /* don't clip sprites below this */
+ /* pointers to lists for sprite clipping */
+ short *sprtopclip; /* adjusted so [x1] is first value */
+ short *sprbottomclip; /* adjusted so [x1] is first value */
+ short *maskedtexturecol; /* adjusted so [x1] is first value */
+} drawseg_t;
+
+#define SIL_NONE 0
+#define SIL_BOTTOM 1
+#define SIL_TOP 2
+#define SIL_BOTH 3
+
+#define MAXDRAWSEGS 256
+
+/* A vissprite_t is a thing that will be drawn during a refresh */
+typedef struct vissprite_s
+{
+ struct vissprite_s *prev, *next;
+ int x1, x2;
+ fixed_t gx, gy; /* for line side calculation */
+ fixed_t gz, gzt; /* global bottom / top for silhouette clipping */
+ fixed_t startfrac; /* horizontal position of x1 */
+ fixed_t scale;
+ fixed_t xiscale; /* negative if flipped */
+ fixed_t texturemid;
+ int patch;
+#ifdef RENDER3D
+ int lightlevel;
+ float v1[2], v2[2]; /* The vertices (v1 is the left one). */
+ float secfloor, secceil;
+#else
+ lighttable_t *colormap;
+#endif
+ int mobjflags; /* for color translation and shadow draw */
+ boolean psprite; /* true if psprite */
+ int playerclass; /* player class (used in translation) */
+ fixed_t floorclip;
+} vissprite_t;
+
+
+extern visplane_t *floorplane, *ceilingplane;
+
+/* Sprites are patches with a special naming convention so they can be
+ * recognized by R_InitSprites. The sprite and frame specified by a
+ * thing_t is range checked at run time.
+ * a sprite is a patch_t that is assumed to represent a three dimensional
+ * object and may have multiple rotations pre drawn. Horizontal flipping
+ * is used to save space. Some sprites will only have one picture used
+ * for all views.
+ */
+typedef struct
+{
+ boolean rotate; /* if false use 0 for any position */
+ short lump[8]; /* lump to use for view angles 0-7 */
+ byte flip[8]; /* flip (1 = flip) to use for view angles 0-7 */
+} spriteframe_t;
+
+typedef struct
+{
+ int numframes;
+ spriteframe_t *spriteframes;
+} spritedef_t;
+
+extern spritedef_t *sprites;
+extern int numsprites;
+
+/*============================================================================*/
+
+extern int numvertexes;
+extern vertex_t *vertexes;
+
+extern int numsegs;
+extern seg_t *segs;
+
+extern int numsectors;
+extern sector_t *sectors;
+
+extern int numsubsectors;
+extern subsector_t *subsectors;
+
+extern int numnodes;
+extern node_t *nodes;
+
+extern int numlines;
+extern line_t *lines;
+
+extern int numsides;
+extern side_t *sides;
+
+
+extern fixed_t viewx, viewy, viewz;
+extern angle_t viewangle;
+extern player_t *viewplayer;
+
+#ifdef RENDER3D
+extern float viewpitch;
+extern int sbarscale;
+#endif
+
+extern angle_t clipangle;
+
+extern int viewangletox[FINEANGLES / 2];
+extern angle_t xtoviewangle[SCREENWIDTH + 1];
+extern fixed_t finetangent[FINEANGLES / 2];
+
+extern fixed_t rw_distance;
+extern angle_t rw_normalangle;
+
+
+/* ---- R_main.c ---- */
+
+extern int viewwidth, viewheight, viewwindowx, viewwindowy;
+extern int centerx, centery;
+extern fixed_t centerxfrac;
+extern fixed_t centeryfrac;
+extern fixed_t projection;
+
+extern int validcount;
+
+extern int sscount, linecount, loopcount;
+extern lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+extern lighttable_t *scalelightfixed[MAXLIGHTSCALE];
+extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+extern int extralight;
+extern lighttable_t *fixedcolormap;
+
+extern fixed_t viewcos, viewsin;
+
+extern int detailshift; /* 0 = high, 1 = low */
+
+extern void (*colfunc) (void);
+extern void (*basecolfunc) (void);
+extern void (*fuzzcolfunc) (void);
+extern void (*spanfunc) (void);
+
+int R_PointOnSide (fixed_t x, fixed_t y, node_t *node);
+int R_PointOnSegSide (fixed_t x, fixed_t y, seg_t *line);
+angle_t R_PointToAngle (fixed_t x, fixed_t y);
+angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
+fixed_t R_PointToDist (fixed_t x, fixed_t y);
+fixed_t R_ScaleFromGlobalAngle (angle_t visangle);
+subsector_t *R_PointInSubsector (fixed_t x, fixed_t y);
+/*
+void R_AddPointToBox (int x, int y, fixed_t *box);
+*/
+
+
+/* ---- R_bsp.c ---- */
+
+extern seg_t *curline;
+extern side_t *sidedef;
+extern line_t *linedef;
+extern sector_t *frontsector, *backsector;
+
+extern int rw_x;
+extern int rw_stopx;
+
+extern boolean segtextured;
+extern boolean markfloor; /* false if the back side is the same plane */
+extern boolean markceiling;
+extern boolean skymap;
+
+extern drawseg_t drawsegs[MAXDRAWSEGS], *ds_p;
+
+extern lighttable_t **hscalelight, **vscalelight, **dscalelight;
+
+typedef void (*drawfunc_t) (int start, int stop);
+void R_ClearClipSegs (void);
+
+void R_ClearDrawSegs (void);
+void R_InitSkyMap (void);
+void R_RenderBSPNode (int bspnum);
+
+
+/* ---- R_segs.c ---- */
+
+extern int rw_angle1; /* angle to line origin */
+extern int TransTextureStart;
+extern int TransTextureEnd;
+
+void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2);
+
+
+/* ---- R_plane.c ---- */
+
+typedef void (*planefunction_t) (int top, int bottom);
+extern planefunction_t floorfunc, ceilingfunc;
+
+extern int skyflatnum;
+
+extern short openings[MAXOPENINGS], *lastopening;
+
+extern short floorclip[SCREENWIDTH];
+extern short ceilingclip[SCREENWIDTH];
+
+extern fixed_t yslope[SCREENHEIGHT];
+extern fixed_t distscale[SCREENWIDTH];
+
+void R_InitPlanes (void);
+void R_ClearPlanes (void);
+void R_MapPlane (int y, int x1, int x2);
+void R_MakeSpans (int x, int t1, int b1, int t2, int b2);
+void R_DrawPlanes (void);
+
+visplane_t *R_FindPlane (fixed_t height, int picnum, int lightlevel, int special);
+visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop);
+
+
+/* ---- R_data.c ---- */
+
+typedef struct
+{
+ int originx; /* block origin (allways UL), which has allready */
+ int originy; /* accounted for the patch's internal origin */
+ int patch;
+} texpatch_t;
+
+/* a maptexturedef_t describes a rectangular texture, which is composed of one
+ * or more mappatch_t structures that arrange graphic patches
+ */
+typedef struct
+{
+ char name[8]; /* for switch changing, etc */
+ short width;
+ short height;
+ short patchcount;
+ texpatch_t patches[1]; /* [patchcount] drawn back to front */
+ /* into the cached texture */
+#ifdef RENDER3D
+ boolean masked; /* from maptexture_t */
+#endif
+} texture_t;
+
+extern fixed_t *textureheight; /* needed for texture pegging */
+extern fixed_t *spritewidth; /* needed for pre rendering (fracs) */
+extern fixed_t *spriteoffset;
+extern fixed_t *spritetopoffset;
+extern lighttable_t *colormaps;
+extern int viewwidth, scaledviewwidth, viewheight;
+extern int firstflat;
+extern int numflats;
+
+extern int *flattranslation; /* for global animation */
+extern int *texturetranslation; /* for global animation */
+
+extern int firstspritelump, lastspritelump, numspritelumps;
+extern boolean LevelUseFullBright;
+
+byte *R_GetColumn (int tex, int col);
+void R_InitData (void);
+void R_PrecacheLevel (void);
+
+
+/* ---- R_things.c ---- */
+
+#define MAXVISSPRITES 192
+
+extern vissprite_t vissprites[MAXVISSPRITES], *vissprite_p;
+extern vissprite_t vsprsortedhead;
+
+/* constant arrays used for psprite clipping and initializing clipping */
+extern short negonearray[SCREENWIDTH];
+extern short screenheightarray[SCREENWIDTH];
+
+/* vars for R_DrawMaskedColumn */
+extern short *mfloorclip;
+extern short *mceilingclip;
+extern fixed_t spryscale;
+extern fixed_t sprtopscreen;
+extern fixed_t sprbotscreen;
+
+extern fixed_t pspritescale, pspriteiscale;
+
+
+void R_DrawMaskedColumn (column_t *column, signed int baseclip);
+
+void R_SortVisSprites (void);
+
+void R_AddSprites (sector_t *sec);
+void R_AddPSprites (void);
+void R_DrawSprites (void);
+void R_InitSprites (const char **namelist);
+void R_ClearSprites (void);
+void R_DrawMasked (void);
+void R_ClipVisSprite (vissprite_t *vis, int xl, int xh);
+
+
+/* ---- R_draw.c ---- */
+
+extern lighttable_t *dc_colormap;
+extern int dc_x;
+extern int dc_yl;
+extern int dc_yh;
+extern fixed_t dc_iscale;
+extern fixed_t dc_texturemid;
+extern byte *dc_source; /* first pixel in a column */
+
+void R_DrawColumn (void);
+void R_DrawColumnLow (void);
+void R_DrawFuzzColumn (void);
+void R_DrawFuzzColumnLow (void);
+void R_DrawTranslatedColumn (void);
+void R_DrawTranslatedFuzzColumn (void);
+void R_DrawTranslatedColumnLow (void);
+void R_DrawAltFuzzColumn(void);
+/*
+void R_DrawTranslatedAltFuzzColumn(void);
+*/
+
+extern int ds_y;
+extern int ds_x1;
+extern int ds_x2;
+extern lighttable_t *ds_colormap;
+extern fixed_t ds_xfrac;
+extern fixed_t ds_yfrac;
+extern fixed_t ds_xstep;
+extern fixed_t ds_ystep;
+extern byte *ds_source; /* start of a 64*64 tile image */
+
+extern byte *translationtables;
+extern byte *dc_translation;
+
+void R_DrawSpan (void);
+void R_DrawSpanLow (void);
+
+void R_InitBuffer (int width, int height);
+void R_InitTranslationTables (void);
+
+#endif /* __R_LOCAL__ */
+
--- /dev/null
+++ b/r_main.c
@@ -1,0 +1,831 @@
+
+//**************************************************************************
+//**
+//** r_main.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+
+#ifndef RENDER3D
+
+#include "h2def.h"
+#include "r_local.h"
+
+int viewangleoffset;
+
+int validcount = 1; // increment every time a check is made
+
+lighttable_t *fixedcolormap;
+extern lighttable_t **walllights;
+
+int centerx, centery;
+fixed_t centerxfrac, centeryfrac;
+fixed_t projection;
+
+int framecount; // just for profiling purposes
+
+int sscount, linecount, loopcount;
+
+fixed_t viewx, viewy, viewz;
+angle_t viewangle;
+fixed_t viewcos, viewsin;
+player_t *viewplayer;
+
+int detailshift; // 0 = high, 1 = low
+
+//
+// precalculated math tables
+//
+angle_t clipangle;
+
+// The viewangletox[viewangle + FINEANGLES/4] lookup maps the visible view
+// angles to screen X coordinates, flattening the arc to a flat projection
+// plane. There will be many angles mapped to the same X.
+int viewangletox[FINEANGLES/2];
+
+// The xtoviewangleangle[] table maps a screen pixel to the lowest viewangle
+// that maps back to x ranges from clipangle to -clipangle
+angle_t xtoviewangle[SCREENWIDTH+1];
+
+// the finetangentgent[angle+FINEANGLES/4] table holds the fixed_t tangent
+// values for view angles, ranging from H2MININT to 0 to H2MAXINT.
+// fixed_t finetangent[FINEANGLES/2];
+
+// fixed_t finesine[5*FINEANGLES/4];
+fixed_t *finecosine = &finesine[FINEANGLES/4];
+
+lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+lighttable_t *scalelightfixed[MAXLIGHTSCALE];
+lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+int extralight; // bumped light from gun blasts
+
+void (*colfunc) (void);
+void (*basecolfunc) (void);
+void (*fuzzcolfunc) (void);
+void (*transcolfunc) (void);
+void (*spanfunc) (void);
+
+/*
+===================
+=
+= R_AddPointToBox
+=
+===================
+*/
+
+/*
+void R_AddPointToBox (int x, int y, fixed_t *box)
+{
+ if (x < box[BOXLEFT])
+ box[BOXLEFT] = x;
+ if (x > box[BOXRIGHT])
+ box[BOXRIGHT] = x;
+ if (y < box[BOXBOTTOM])
+ box[BOXBOTTOM] = y;
+ if (y > box[BOXTOP])
+ box[BOXTOP] = y;
+}
+*/
+
+
+/*
+===============================================================================
+=
+= R_PointOnSide
+=
+= Returns side 0 (front) or 1 (back)
+===============================================================================
+*/
+
+int R_PointOnSide (fixed_t x, fixed_t y, node_t *node)
+{
+ fixed_t dx, dy;
+ fixed_t left, right;
+
+ if (!node->dx)
+ {
+ if (x <= node->x)
+ return node->dy > 0;
+ return node->dy < 0;
+ }
+ if (!node->dy)
+ {
+ if (y <= node->y)
+ return node->dx < 0;
+ return node->dx > 0;
+ }
+
+ dx = (x - node->x);
+ dy = (y - node->y);
+
+// try to quickly decide by looking at sign bits
+ if ((node->dy ^ node->dx ^ dx ^ dy) & 0x80000000)
+ {
+ if ((node->dy ^ dx) & 0x80000000)
+ return 1; // (left is negative)
+ return 0;
+ }
+
+ left = FixedMul (node->dy>>FRACBITS , dx);
+ right = FixedMul (dy , node->dx>>FRACBITS);
+
+ if (right < left)
+ return 0; // front side
+ return 1; // back side
+}
+
+
+int R_PointOnSegSide (fixed_t x, fixed_t y, seg_t *line)
+{
+ fixed_t lx, ly;
+ fixed_t ldx, ldy;
+ fixed_t dx, dy;
+ fixed_t left, right;
+
+ lx = line->v1->x;
+ ly = line->v1->y;
+
+ ldx = line->v2->x - lx;
+ ldy = line->v2->y - ly;
+
+ if (!ldx)
+ {
+ if (x <= lx)
+ return ldy > 0;
+ return ldy < 0;
+ }
+ if (!ldy)
+ {
+ if (y <= ly)
+ return ldx < 0;
+ return ldx > 0;
+ }
+
+ dx = (x - lx);
+ dy = (y - ly);
+
+// try to quickly decide by looking at sign bits
+ if ((ldy ^ ldx ^ dx ^ dy) & 0x80000000)
+ {
+ if ((ldy ^ dx) & 0x80000000)
+ return 1; // (left is negative)
+ return 0;
+ }
+
+ left = FixedMul (ldy>>FRACBITS, dx);
+ right = FixedMul (dy, ldx>>FRACBITS);
+
+ if (right < left)
+ return 0; // front side
+ return 1; // back side
+}
+
+
+/*
+===============================================================================
+=
+= R_PointToAngle
+=
+===============================================================================
+*/
+
+// to get a global angle from cartesian coordinates, the coordinates are
+// flipped until they are in the first octant of the coordinate system, then
+// the y (<=x) is scaled and divided by x to get a tangent (slope) value
+// which is looked up in the tantoangle[] table. The +1 size is to handle
+// the case when x==y without additional checking.
+#define SLOPERANGE 2048
+#define SLOPEBITS 11
+#define DBITS (FRACBITS-SLOPEBITS)
+
+extern int tantoangle[SLOPERANGE+1]; // get from tables.c
+
+//int tantoangle[SLOPERANGE+1];
+
+static int SlopeDiv (unsigned num, unsigned den)
+{
+ unsigned ans;
+ if (den < 512)
+ return SLOPERANGE;
+ ans = (num<<3) / (den>>8);
+ return ans <= SLOPERANGE ? ans : SLOPERANGE;
+}
+
+angle_t R_PointToAngle (fixed_t x, fixed_t y)
+{
+ x -= viewx;
+ y -= viewy;
+ if ( (!x) && (!y) )
+ return 0;
+ if (x >= 0)
+ { // x >= 0
+ if (y >= 0)
+ { // y >= 0
+ if (x > y)
+ return tantoangle[SlopeDiv(y,x)]; // octant 0
+ else
+ return ANG90 - 1 - tantoangle[SlopeDiv(x,y)]; // octant 1
+ }
+ else
+ { // y < 0
+ y = -y;
+ if (x > y)
+ return -tantoangle[SlopeDiv(y,x)]; // octant 8
+ else
+ return ANG270 + tantoangle[SlopeDiv(x,y)]; // octant 7
+ }
+ }
+ else
+ { // x < 0
+ x = -x;
+ if (y >= 0)
+ { // y >= 0
+ if (x > y)
+ return ANG180 - 1 - tantoangle[SlopeDiv(y,x)]; // octant 3
+ else
+ return ANG90 + tantoangle[SlopeDiv(x,y)]; // octant 2
+ }
+ else
+ { // y < 0
+ y = -y;
+ if (x > y)
+ return ANG180 + tantoangle[SlopeDiv(y,x)]; // octant 4
+ else
+ return ANG270 - 1 - tantoangle[SlopeDiv(x,y)]; // octant 5
+ }
+ }
+
+ return 0;
+}
+
+
+angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
+{
+ viewx = x1;
+ viewy = y1;
+ return R_PointToAngle (x2, y2);
+}
+
+
+fixed_t R_PointToDist (fixed_t x, fixed_t y)
+{
+ int angle;
+ fixed_t dx, dy, temp;
+ fixed_t dist;
+
+ dx = abs(x - viewx);
+ dy = abs(y - viewy);
+
+ if (dy > dx)
+ {
+ temp = dx;
+ dx = dy;
+ dy = temp;
+ }
+
+ angle = (tantoangle[ FixedDiv(dy,dx)>>DBITS ]+ANG90) >> ANGLETOFINESHIFT;
+
+ dist = FixedDiv (dx, finesine[angle]); // use as cosine
+
+ return dist;
+}
+
+
+/*
+=================
+=
+= R_InitPointToAngle
+=
+=================
+*/
+
+void R_InitPointToAngle (void)
+{
+// now getting from tables.c
+#if 0
+ int i;
+ int t; /* int32_t */
+ float f;
+//
+// slope (tangent) to angle lookup
+//
+ for (i = 0; i <= SLOPERANGE; i++)
+ {
+ f = atan((float)i / SLOPERANGE) / (3.141592657*2);
+ t = 0xffffffff * f;
+ tantoangle[i] = t;
+ }
+#endif
+}
+
+//=============================================================================
+
+/*
+================
+=
+= R_ScaleFromGlobalAngle
+=
+= Returns the texture mapping scale for the current line at the given angle
+= rw_distance must be calculated first
+================
+*/
+
+fixed_t R_ScaleFromGlobalAngle (angle_t visangle)
+{
+ fixed_t scale;
+ int anglea, angleb;
+ int sinea, sineb;
+ fixed_t num, den;
+
+#if 0
+{
+ fixed_t dist, z;
+ fixed_t sinv, cosv;
+
+ sinv = finesine[(visangle - rw_normalangle)>>ANGLETOFINESHIFT];
+ dist = FixedDiv (rw_distance, sinv);
+ cosv = finecosine[(viewangle - visangle)>>ANGLETOFINESHIFT];
+ z = abs(FixedMul (dist, cosv));
+ scale = FixedDiv(projection, z);
+ return scale;
+}
+#endif
+
+ anglea = ANG90 + (visangle - viewangle);
+ angleb = ANG90 + (visangle - rw_normalangle);
+// bothe sines are allways positive
+ sinea = finesine[anglea>>ANGLETOFINESHIFT];
+ sineb = finesine[angleb>>ANGLETOFINESHIFT];
+ num = FixedMul(projection, sineb)<<detailshift;
+ den = FixedMul(rw_distance, sinea);
+ if (den > num>>16)
+ {
+ scale = FixedDiv (num, den);
+ if (scale > 64*FRACUNIT)
+ scale = 64*FRACUNIT;
+ else if (scale < 256)
+ scale = 256;
+ }
+ else
+ scale = 64*FRACUNIT;
+
+ return scale;
+}
+
+
+/*
+=================
+=
+= R_InitTables
+=
+=================
+*/
+
+void R_InitTables (void)
+{
+// now getting from tables.c
+#if 0
+ int i;
+ float a, fv;
+ int t;
+
+//
+// viewangle tangent table
+//
+ for (i = 0; i < FINEANGLES/2; i++)
+ {
+ a = (i - FINEANGLES/4 + 0.5) * PI * 2 / FINEANGLES;
+ fv = FRACUNIT * tan(a);
+ t = fv;
+ finetangent[i] = t;
+ }
+
+//
+// finesine table
+//
+ for (i = 0; i < 5*FINEANGLES/4; i++)
+ {
+// OPTIMIZE: mirror...
+ a = (i + 0.5) * PI * 2 / FINEANGLES;
+ t = FRACUNIT * sin(a);
+ finesine[i] = t;
+ }
+#endif
+}
+
+
+/*
+=================
+=
+= R_InitTextureMapping
+=
+=================
+*/
+
+void R_InitTextureMapping (void)
+{
+ int i;
+ int x;
+ int t;
+ fixed_t focallength;
+
+//
+// use tangent table to generate viewangletox
+// viewangletox will give the next greatest x after the view angle
+//
+ // calc focallength so FIELDOFVIEW angles covers SCREENWIDTH
+ focallength = FixedDiv (centerxfrac, finetangent[FINEANGLES/4 + FIELDOFVIEW/2]);
+
+ for (i = 0; i < FINEANGLES/2; i++)
+ {
+ if (finetangent[i] > FRACUNIT*2)
+ t = -1;
+ else if (finetangent[i] < -FRACUNIT*2)
+ t = viewwidth + 1;
+ else
+ {
+ t = FixedMul (finetangent[i], focallength);
+ t = (centerxfrac - t + FRACUNIT - 1)>>FRACBITS;
+ if (t < -1)
+ t = -1;
+ else if (t > viewwidth + 1)
+ t = viewwidth + 1;
+ }
+ viewangletox[i] = t;
+ }
+
+//
+// scan viewangletox[] to generate xtoviewangleangle[]
+//
+// xtoviewangle will give the smallest view angle that maps to x
+ for (x = 0; x <= viewwidth; x++)
+ {
+ i = 0;
+ while (viewangletox[i] > x)
+ i++;
+ xtoviewangle[x] = (i<<ANGLETOFINESHIFT) - ANG90;
+ }
+
+//
+// take out the fencepost cases from viewangletox
+//
+ for (i = 0; i < FINEANGLES/2; i++)
+ {
+ t = FixedMul (finetangent[i], focallength);
+ t = centerx - t;
+ if (viewangletox[i] == -1)
+ viewangletox[i] = 0;
+ else if (viewangletox[i] == viewwidth + 1)
+ viewangletox[i] = viewwidth;
+ }
+
+ clipangle = xtoviewangle[0];
+}
+
+//=============================================================================
+
+/*
+====================
+=
+= R_InitLightTables
+=
+= Only inits the zlight table, because the scalelight table changes
+= with view size
+=
+====================
+*/
+
+#define DISTMAP 2
+
+void R_InitLightTables (void)
+{
+ int i, j, level, start_map;
+ int scale;
+
+//
+// Calculate the light levels to use for each level / distance combination
+//
+ for (i = 0; i < LIGHTLEVELS; i++)
+ {
+ start_map = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
+ for (j = 0; j < MAXLIGHTZ; j++)
+ {
+ scale = FixedDiv ((SCREENWIDTH/2*FRACUNIT), (j + 1)<<LIGHTZSHIFT);
+ scale >>= LIGHTSCALESHIFT;
+ level = start_map - scale/DISTMAP;
+ if (level < 0)
+ level = 0;
+ if (level >= NUMCOLORMAPS)
+ level = NUMCOLORMAPS-1;
+ zlight[i][j] = colormaps + level*256;
+ }
+ }
+}
+
+
+/*
+==============
+=
+= R_SetViewSize
+=
+= Don't really change anything here, because i might be in the middle of
+= a refresh. The change will take effect next refresh.
+=
+==============
+*/
+
+static int setblocks, setdetail;
+boolean setsizeneeded;
+
+void R_SetViewSize (int blocks, int detail)
+{
+ setsizeneeded = true;
+ setblocks = blocks;
+ setdetail = detail;
+}
+
+/*
+==============
+=
+= R_ExecuteSetViewSize
+=
+==============
+*/
+
+void R_ExecuteSetViewSize (void)
+{
+ fixed_t cosadj, dy;
+ int i, j, level, start_map;
+
+ setsizeneeded = false;
+
+ if (setblocks == 11)
+ {
+ scaledviewwidth = SCREENWIDTH;
+ viewheight = SCREENHEIGHT;
+ }
+ else
+ {
+ scaledviewwidth = setblocks*32;
+ viewheight = (setblocks*161/10);
+ }
+
+ detailshift = setdetail;
+ viewwidth = scaledviewwidth>>detailshift;
+
+ centery = viewheight/2;
+ centerx = viewwidth/2;
+ centerxfrac = centerx<<FRACBITS;
+ centeryfrac = centery<<FRACBITS;
+ projection = centerxfrac;
+
+ if (!detailshift)
+ {
+ colfunc = basecolfunc = R_DrawColumn;
+ fuzzcolfunc = R_DrawFuzzColumn;
+ transcolfunc = R_DrawTranslatedColumn;
+ spanfunc = R_DrawSpan;
+ }
+ else
+ {
+ colfunc = basecolfunc = R_DrawColumnLow;
+ fuzzcolfunc = R_DrawFuzzColumn;
+ transcolfunc = R_DrawTranslatedColumn;
+ spanfunc = R_DrawSpanLow;
+ }
+
+ R_InitBuffer (scaledviewwidth, viewheight);
+
+ R_InitTextureMapping ();
+
+//
+// psprite scales
+//
+ pspritescale = FRACUNIT*viewwidth/SCREENWIDTH;
+ pspriteiscale = FRACUNIT*SCREENWIDTH/viewwidth;
+
+//
+// thing clipping
+//
+ for (i = 0; i < viewwidth; i++)
+ screenheightarray[i] = viewheight;
+
+//
+// planes
+//
+ for (i = 0; i < viewheight; i++)
+ {
+ dy = ((i - viewheight/2)<<FRACBITS) + FRACUNIT/2;
+ dy = abs(dy);
+ yslope[i] = FixedDiv ((viewwidth<<detailshift)/2*FRACUNIT, dy);
+ }
+
+ for (i = 0; i < viewwidth; i++)
+ {
+ cosadj = abs(finecosine[xtoviewangle[i]>>ANGLETOFINESHIFT]);
+ distscale[i] = FixedDiv (FRACUNIT, cosadj);
+ }
+
+//
+// Calculate the light levels to use for each level / scale combination
+//
+ for (i = 0; i < LIGHTLEVELS; i++)
+ {
+ start_map = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
+ for (j = 0; j < MAXLIGHTSCALE; j++)
+ {
+ level = start_map - j*SCREENWIDTH/(viewwidth<<detailshift)/DISTMAP;
+ if (level < 0)
+ level = 0;
+ if (level >= NUMCOLORMAPS)
+ level = NUMCOLORMAPS-1;
+ scalelight[i][j] = colormaps + level*256;
+ }
+ }
+
+//
+// draw the border
+//
+ R_DrawViewBorder (); // erase old menu stuff
+}
+
+
+/*
+==============
+=
+= R_Init
+=
+==============
+*/
+
+int detailLevel;
+int screenblocks;
+
+void R_Init(void)
+{
+ R_InitData();
+ R_InitPointToAngle();
+ R_InitTables();
+ // viewwidth / viewheight / detailLevel are set by the defaults
+ R_SetViewSize(screenblocks, detailLevel);
+ R_InitPlanes();
+ R_InitLightTables();
+ R_InitSkyMap();
+ R_InitTranslationTables();
+ framecount = 0;
+}
+
+/*
+==============
+=
+= R_PointInSubsector
+=
+==============
+*/
+
+subsector_t *R_PointInSubsector (fixed_t x, fixed_t y)
+{
+ node_t *node;
+ int side, nodenum;
+
+ if (!numnodes) // single subsector is a special case
+ return subsectors;
+
+ nodenum = numnodes - 1;
+
+ while (! (nodenum & NF_SUBSECTOR) )
+ {
+ node = &nodes[nodenum];
+ side = R_PointOnSide (x, y, node);
+ nodenum = node->children[side];
+ }
+
+ return &subsectors[nodenum & ~NF_SUBSECTOR];
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC R_SetupFrame
+//
+//----------------------------------------------------------------------------
+
+void R_SetupFrame(player_t *player)
+{
+ int i;
+ int tableAngle;
+ int tempCentery;
+ int intensity;
+
+ viewplayer = player;
+ viewangle = player->mo->angle + viewangleoffset;
+ tableAngle = viewangle>>ANGLETOFINESHIFT;
+ viewx = player->mo->x;
+ viewy = player->mo->y;
+
+ if (localQuakeHappening[displayplayer] && !paused)
+ {
+ intensity = localQuakeHappening[displayplayer];
+ viewx += ((M_Random() % (intensity<<2)) - (intensity<<1)) << FRACBITS;
+ viewy += ((M_Random() % (intensity<<2)) - (intensity<<1)) << FRACBITS;
+ }
+
+ extralight = player->extralight;
+ viewz = player->viewz;
+
+ tempCentery = viewheight/2 + (player->lookdir)*screenblocks/10;
+ if (centery != tempCentery)
+ {
+ centery = tempCentery;
+ centeryfrac = centery<<FRACBITS;
+ for (i = 0; i < viewheight; i++)
+ {
+ yslope[i] = FixedDiv ( (viewwidth<<detailshift)/2*FRACUNIT,
+ abs(((i - centery)<<FRACBITS) + FRACUNIT/2) );
+ }
+ }
+ viewsin = finesine[tableAngle];
+ viewcos = finecosine[tableAngle];
+ sscount = 0;
+ if (player->fixedcolormap)
+ {
+ fixedcolormap = colormaps + player->fixedcolormap*256*sizeof(lighttable_t);
+ walllights = scalelightfixed;
+ for (i = 0; i < MAXLIGHTSCALE; i++)
+ {
+ scalelightfixed[i] = fixedcolormap;
+ }
+ }
+ else
+ {
+ fixedcolormap = 0;
+ }
+ framecount++;
+ validcount++;
+ if (BorderNeedRefresh)
+ {
+ if (setblocks < 10)
+ {
+ R_DrawViewBorder();
+ }
+ BorderNeedRefresh = false;
+ BorderTopRefresh = false;
+ UpdateState |= I_FULLSCRN;
+ }
+ if (BorderTopRefresh)
+ {
+ if (setblocks < 10)
+ {
+ R_DrawTopBorder();
+ }
+ BorderTopRefresh = false;
+ UpdateState |= I_MESSAGES;
+ }
+}
+
+/*
+==============
+=
+= R_RenderView
+=
+==============
+*/
+
+void R_RenderPlayerView (player_t *player)
+{
+ R_SetupFrame (player);
+
+ R_ClearClipSegs ();
+ R_ClearDrawSegs ();
+ R_ClearPlanes ();
+
+ R_ClearSprites ();
+ NetUpdate (); // check for new console commands
+
+ // Make displayed player invisible locally
+ if (localQuakeHappening[displayplayer] && gamestate == GS_LEVEL)
+ {
+ players[displayplayer].mo->flags2 |= MF2_DONTDRAW;
+ R_RenderBSPNode (numnodes - 1); // head node is the last node output
+ players[displayplayer].mo->flags2 &= ~MF2_DONTDRAW;
+ }
+ else
+ {
+ R_RenderBSPNode (numnodes - 1); // head node is the last node output
+ }
+
+ NetUpdate (); // check for new console commands
+
+ R_DrawPlanes ();
+ NetUpdate (); // check for new console commands
+
+ R_DrawMasked ();
+ NetUpdate (); // check for new console commands
+}
+
+#endif /* RENDER3D */
+
--- /dev/null
+++ b/r_plane.c
@@ -1,0 +1,550 @@
+
+//**************************************************************************
+//**
+//** r_plane.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+
+#ifndef RENDER3D
+
+#include "h2def.h"
+#include "r_local.h"
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern fixed_t Sky1ScrollDelta;
+extern fixed_t Sky2ScrollDelta;
+
+extern byte *ylookup[MAXHEIGHT];
+extern int columnofs[MAXWIDTH];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int Sky1Texture;
+int Sky2Texture;
+fixed_t Sky1ColumnOffset;
+fixed_t Sky2ColumnOffset;
+int skyflatnum;
+int skytexturemid;
+fixed_t skyiscale;
+boolean DoubleSky;
+planefunction_t floorfunc, ceilingfunc;
+
+// Opening
+visplane_t visplanes[MAXVISPLANES], *lastvisplane;
+visplane_t *floorplane, *ceilingplane;
+short openings[MAXOPENINGS], *lastopening;
+
+// Clip values are the solid pixel bounding the range.
+// floorclip start out SCREENHEIGHT
+// ceilingclip starts out -1
+short floorclip[SCREENWIDTH];
+short ceilingclip[SCREENWIDTH];
+
+// spanstart holds the start of a plane span, initialized to 0
+int spanstart[SCREENHEIGHT];
+int spanstop[SCREENHEIGHT];
+
+// Texture mapping
+lighttable_t **planezlight;
+fixed_t planeheight;
+fixed_t yslope[SCREENHEIGHT];
+fixed_t distscale[SCREENWIDTH];
+fixed_t basexscale, baseyscale;
+fixed_t cachedheight[SCREENHEIGHT];
+fixed_t cacheddistance[SCREENHEIGHT];
+fixed_t cachedxstep[SCREENHEIGHT];
+fixed_t cachedystep[SCREENHEIGHT];
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// R_InitSky
+//
+// Called at level load.
+//
+//==========================================================================
+
+void R_InitSky(int map)
+{
+ Sky1Texture = P_GetMapSky1Texture(map);
+ Sky2Texture = P_GetMapSky2Texture(map);
+ Sky1ScrollDelta = P_GetMapSky1ScrollDelta(map);
+ Sky2ScrollDelta = P_GetMapSky2ScrollDelta(map);
+ Sky1ColumnOffset = 0;
+ Sky2ColumnOffset = 0;
+ DoubleSky = P_GetMapDoubleSky(map);
+}
+
+//==========================================================================
+//
+// R_InitSkyMap
+//
+// Called whenever the view size changes.
+//
+//==========================================================================
+
+void R_InitSkyMap(void)
+{
+ skyflatnum = R_FlatNumForName("F_SKY");
+ skytexturemid = 200*FRACUNIT;
+ skyiscale = FRACUNIT;
+}
+
+//==========================================================================
+//
+// R_InitPlanes
+//
+// Called at game startup.
+//
+//==========================================================================
+
+void R_InitPlanes(void)
+{
+}
+
+//==========================================================================
+//
+// R_MapPlane
+//
+// Globals used: planeheight, ds_source, basexscale, baseyscale,
+// viewx, viewy.
+//
+//==========================================================================
+
+void R_MapPlane(int y, int x1, int x2)
+{
+ angle_t angle;
+ fixed_t distance, length;
+ unsigned idx;
+
+#ifdef RANGECHECK
+ if (x2 < x1 || x1 < 0 || x2 >= viewwidth || (unsigned)y > viewheight)
+ {
+ I_Error("R_MapPlane: %i, %i at %i", x1, x2, y);
+ }
+#endif
+
+ if (planeheight != cachedheight[y])
+ {
+ cachedheight[y] = planeheight;
+ distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]);
+ ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale);
+ ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale);
+ }
+ else
+ {
+ distance = cacheddistance[y];
+ ds_xstep = cachedxstep[y];
+ ds_ystep = cachedystep[y];
+ }
+
+ length = FixedMul(distance, distscale[x1]);
+ angle = (viewangle+xtoviewangle[x1])>>ANGLETOFINESHIFT;
+ ds_xfrac = viewx+FixedMul(finecosine[angle], length);
+ ds_yfrac = -viewy-FixedMul(finesine[angle], length);
+
+ if (fixedcolormap)
+ {
+ ds_colormap = fixedcolormap;
+ }
+ else
+ {
+ idx = distance >> LIGHTZSHIFT;
+ if (idx >= MAXLIGHTZ)
+ {
+ idx = MAXLIGHTZ-1;
+ }
+ ds_colormap = planezlight[idx];
+ }
+
+ ds_y = y;
+ ds_x1 = x1;
+ ds_x2 = x2;
+
+ spanfunc(); // High or low detail
+}
+
+//==========================================================================
+//
+// R_ClearPlanes
+//
+// Called at the beginning of each frame.
+//
+//==========================================================================
+
+void R_ClearPlanes(void)
+{
+ int i;
+ angle_t angle;
+
+ // Opening / clipping determination
+ for (i = 0; i < viewwidth; i++)
+ {
+ floorclip[i] = viewheight;
+ ceilingclip[i] = -1;
+ }
+
+ lastvisplane = visplanes;
+ lastopening = openings;
+
+ // Texture calculation
+ memset(cachedheight, 0, sizeof(cachedheight));
+ angle = (viewangle - ANG90)>>ANGLETOFINESHIFT; // left to right mapping
+ // Scale will be unit scale at SCREENWIDTH/2 distance
+ basexscale = FixedDiv(finecosine[angle], centerxfrac);
+ baseyscale = -FixedDiv(finesine[angle], centerxfrac);
+}
+
+//==========================================================================
+//
+// R_FindPlane
+//
+//==========================================================================
+
+visplane_t *R_FindPlane(fixed_t height, int picnum,
+ int lightlevel, int special)
+{
+ visplane_t *check;
+
+ if (special < 150)
+ { // Don't let low specials affect search
+ special = 0;
+ }
+
+ if (picnum == skyflatnum)
+ { // All skies map together
+ height = 0;
+ lightlevel = 0;
+ }
+
+ for (check = visplanes; check < lastvisplane; check++)
+ {
+ if (height == check->height &&
+ picnum == check->picnum &&
+ lightlevel == check->lightlevel &&
+ special == check->special)
+ break;
+ }
+
+ if (check < lastvisplane)
+ {
+ return check;
+ }
+
+ if (lastvisplane - visplanes == MAXVISPLANES)
+ {
+ I_Error("R_FindPlane: no more visplanes");
+ }
+
+ lastvisplane++;
+ check->height = height;
+ check->picnum = picnum;
+ check->lightlevel = lightlevel;
+ check->special = special;
+ check->minx = SCREENWIDTH;
+ check->maxx = -1;
+ memset(check->top, 0xff, sizeof(check->top));
+ return check;
+}
+
+//==========================================================================
+//
+// R_CheckPlane
+//
+//==========================================================================
+
+visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop)
+{
+ int intrl, intrh;
+ int unionl, unionh;
+ int x;
+
+ if (start < pl->minx)
+ {
+ intrl = pl->minx;
+ unionl = start;
+ }
+ else
+ {
+ unionl = pl->minx;
+ intrl = start;
+ }
+ if (stop > pl->maxx)
+ {
+ intrh = pl->maxx;
+ unionh = stop;
+ }
+ else
+ {
+ unionh = pl->maxx;
+ intrh = stop;
+ }
+
+ for (x = intrl; x <= intrh; x++)
+ {
+ if (pl->top[x] != 0xff)
+ {
+ break;
+ }
+ }
+
+ if (x > intrh)
+ {
+ pl->minx = unionl;
+ pl->maxx = unionh;
+ return pl; // use the same visplane
+ }
+
+ // Make a new visplane
+ lastvisplane->height = pl->height;
+ lastvisplane->picnum = pl->picnum;
+ lastvisplane->lightlevel = pl->lightlevel;
+ lastvisplane->special = pl->special;
+ pl = lastvisplane++;
+ pl->minx = start;
+ pl->maxx = stop;
+ memset(pl->top, 0xff, sizeof(pl->top));
+
+ return pl;
+}
+
+//==========================================================================
+//
+// R_MakeSpans
+//
+//==========================================================================
+
+void R_MakeSpans(int x, int t1, int b1, int t2, int b2)
+{
+ while (t1 < t2 && t1 <= b1)
+ {
+ R_MapPlane(t1, spanstart[t1], x - 1);
+ t1++;
+ }
+ while (b1 > b2 && b1 >= t1)
+ {
+ R_MapPlane(b1, spanstart[b1], x - 1);
+ b1--;
+ }
+ while (t2 < t1 && t2 <= b2)
+ {
+ spanstart[t2] = x;
+ t2++;
+ }
+ while (b2 > b1 && b2 >= t2)
+ {
+ spanstart[b2] = x;
+ b2--;
+ }
+}
+
+//==========================================================================
+//
+// R_DrawPlanes
+//
+//==========================================================================
+
+#define SKYTEXTUREMIDSHIFTED 200
+
+void R_DrawPlanes(void)
+{
+ visplane_t *pl;
+ int light;
+ int x, stop;
+ int angle;
+ byte *tempSource;
+ byte *source;
+ byte *source2;
+ byte *dest;
+ int count;
+ int offset;
+ int skyTexture;
+ int offset2;
+ int skyTexture2;
+ int scrollOffset;
+
+#ifdef RANGECHECK
+ if (ds_p - drawsegs > MAXDRAWSEGS)
+ {
+ I_Error("R_DrawPlanes: drawsegs overflow (%i)", ds_p - drawsegs);
+ }
+ if (lastvisplane - visplanes > MAXVISPLANES)
+ {
+ I_Error("R_DrawPlanes: visplane overflow (%i)", lastvisplane - visplanes);
+ }
+ if (lastopening - openings > MAXOPENINGS)
+ {
+ I_Error("R_DrawPlanes: opening overflow (%i)", lastopening - openings);
+ }
+#endif
+
+ for (pl = visplanes; pl < lastvisplane; pl++)
+ {
+ if (pl->minx > pl->maxx)
+ {
+ continue;
+ }
+ if (pl->picnum == skyflatnum)
+ { // Sky flat
+ if (DoubleSky)
+ { // Render 2 layers, sky 1 in front
+ offset = Sky1ColumnOffset>>16;
+ skyTexture = texturetranslation[Sky1Texture];
+ offset2 = Sky2ColumnOffset>>16;
+ skyTexture2 = texturetranslation[Sky2Texture];
+ for (x = pl->minx; x <= pl->maxx; x++)
+ {
+ dc_yl = pl->top[x];
+ dc_yh = pl->bottom[x];
+ if (dc_yl <= dc_yh)
+ {
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ {
+ return;
+ }
+ angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT;
+ source = R_GetColumn(skyTexture, angle + offset)
+ + SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
+ source2 = R_GetColumn(skyTexture2, angle + offset2)
+ + SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
+ dest = ylookup[dc_yl] + columnofs[x];
+ do
+ {
+ if (*source)
+ {
+ *dest = *source++;
+ source2++;
+ }
+ else
+ {
+ *dest = *source2++;
+ source++;
+ }
+ dest += SCREENWIDTH;
+ } while (count--);
+ }
+ }
+ continue; // Next visplane
+ }
+ else
+ { // Render single layer
+ if (pl->special == 200)
+ { // Use sky 2
+ offset = Sky2ColumnOffset>>16;
+ skyTexture = texturetranslation[Sky2Texture];
+ }
+ else
+ { // Use sky 1
+ offset = Sky1ColumnOffset>>16;
+ skyTexture = texturetranslation[Sky1Texture];
+ }
+ for (x = pl->minx; x <= pl->maxx; x++)
+ {
+ dc_yl = pl->top[x];
+ dc_yh = pl->bottom[x];
+ if (dc_yl <= dc_yh)
+ {
+ count = dc_yh - dc_yl;
+ if (count < 0)
+ {
+ return;
+ }
+ angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT;
+ source = R_GetColumn(skyTexture, angle + offset)
+ + SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
+ dest = ylookup[dc_yl] + columnofs[x];
+ do
+ {
+ *dest = *source++;
+ dest += SCREENWIDTH;
+ } while (count--);
+ }
+ }
+ continue; // Next visplane
+ }
+ }
+ // Regular flat
+ tempSource = (byte *) W_CacheLumpNum(firstflat + flattranslation[pl->picnum], PU_STATIC);
+ scrollOffset = leveltime>>1 & 63;
+ switch (pl->special)
+ { // Handle scrolling flats
+ case 201: case 202: case 203: // Scroll_North_xxx
+ ds_source = tempSource + ((scrollOffset<<(pl->special - 201) & 63)<<6);
+ break;
+ case 204: case 205: case 206: // Scroll_East_xxx
+ ds_source = tempSource + ((63 - scrollOffset)<<(pl->special - 204) & 63);
+ break;
+ case 207: case 208: case 209: // Scroll_South_xxx
+ ds_source = tempSource + (((63 - scrollOffset)<<(pl->special - 207) & 63)<<6);
+ break;
+ case 210: case 211: case 212: // Scroll_West_xxx
+ ds_source = tempSource + (scrollOffset<<(pl->special - 210) & 63);
+ break;
+ case 213: case 214: case 215: // Scroll_NorthWest_xxx
+ ds_source = tempSource + (scrollOffset<<(pl->special - 213) & 63)
+ + ((scrollOffset<<(pl->special - 213) & 63)<<6);
+ break;
+ case 216: case 217: case 218: // Scroll_NorthEast_xxx
+ ds_source = tempSource + ((63 - scrollOffset)<<(pl->special - 216) & 63)
+ + ((scrollOffset<<(pl->special - 216) & 63)<<6);
+ break;
+ case 219: case 220: case 221: // Scroll_SouthEast_xxx
+ ds_source = tempSource + ((63 - scrollOffset)<<(pl->special - 219) & 63)
+ + (((63 - scrollOffset)<<(pl->special - 219) & 63)<<6);
+ break;
+ case 222: case 223: case 224: // Scroll_SouthWest_xxx
+ ds_source = tempSource + (scrollOffset<<(pl->special - 222) & 63)
+ + (((63 - scrollOffset)<<(pl->special - 222) & 63)<<6);
+ break;
+ default:
+ ds_source = tempSource;
+ break;
+ }
+ planeheight = abs(pl->height - viewz);
+ light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ if (light >= LIGHTLEVELS)
+ {
+ light = LIGHTLEVELS-1;
+ }
+ if (light < 0)
+ {
+ light = 0;
+ }
+ planezlight = zlight[light];
+
+ pl->top[pl->maxx + 1] = 0xff;
+ pl->top[pl->minx - 1] = 0xff;
+
+ stop = pl->maxx + 1;
+ for (x = pl->minx; x <= stop; x++)
+ {
+ R_MakeSpans(x, pl->top[x - 1], pl->bottom[x - 1],
+ pl->top[x], pl->bottom[x]);
+ }
+ Z_ChangeTag(tempSource, PU_CACHE);
+ }
+}
+#endif /* !RENDER3D */
+
--- /dev/null
+++ b/r_segs.c
@@ -1,0 +1,642 @@
+
+//**************************************************************************
+//**
+//** r_segs.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//** This version has the tall-sector-crossing-precision-bug fixed.
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+
+#ifndef RENDER3D
+
+#include "h2def.h"
+#include "r_local.h"
+
+// OPTIMIZE: closed two sided lines as single sided
+
+boolean segtextured; // true if any of the segs textures might be vis
+boolean markfloor; // false if the back side is the same plane
+boolean markceiling;
+boolean maskedtexture;
+int toptexture, bottomtexture, midtexture;
+
+angle_t rw_normalangle;
+int rw_angle1; // angle to line origin
+
+//
+// wall
+//
+int rw_x;
+int rw_stopx;
+angle_t rw_centerangle;
+fixed_t rw_offset;
+fixed_t rw_distance;
+fixed_t rw_scale;
+fixed_t rw_scalestep;
+fixed_t rw_midtexturemid;
+fixed_t rw_toptexturemid;
+fixed_t rw_bottomtexturemid;
+
+int worldtop, worldbottom, worldhigh, worldlow;
+
+fixed_t pixhigh, pixlow;
+fixed_t pixhighstep, pixlowstep;
+fixed_t topfrac, topstep;
+fixed_t bottomfrac, bottomstep;
+
+lighttable_t **walllights;
+
+short *maskedtexturecol;
+
+
+/*
+================
+=
+= R_RenderMaskedSegRange
+=
+================
+*/
+
+void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
+{
+ unsigned idx;
+ column_t *col;
+ int lightnum;
+ int texnum;
+
+//
+// calculate light table
+// use different light tables for horizontal / vertical / diagonal
+// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
+ curline = ds->curline;
+ frontsector = curline->frontsector;
+ backsector = curline->backsector;
+ texnum = texturetranslation[curline->sidedef->midtexture];
+
+ lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ //if (curline->v1->y == curline->v2->y)
+ // lightnum--;
+ //else if (curline->v1->x == curline->v2->x)
+ // lightnum++;
+ //if (lightnum < 0)
+ // walllights = scalelight[0];
+ if (lightnum >= LIGHTLEVELS)
+ walllights = scalelight[LIGHTLEVELS-1];
+ else
+ walllights = scalelight[lightnum];
+
+ maskedtexturecol = ds->maskedtexturecol;
+
+ rw_scalestep = ds->scalestep;
+ spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
+ mfloorclip = ds->sprbottomclip;
+ mceilingclip = ds->sprtopclip;
+
+//
+// find positioning
+//
+ if (curline->linedef->flags & ML_DONTPEGBOTTOM)
+ {
+ dc_texturemid = frontsector->floorheight > backsector->floorheight ?
+ frontsector->floorheight : backsector->floorheight;
+ dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
+ }
+ else
+ {
+ dc_texturemid = frontsector->ceilingheight < backsector->ceilingheight ?
+ frontsector->ceilingheight : backsector->ceilingheight;
+ dc_texturemid = dc_texturemid - viewz;
+ }
+ dc_texturemid += curline->sidedef->rowoffset;
+
+ if (fixedcolormap)
+ dc_colormap = fixedcolormap;
+//
+// draw the columns
+//
+ for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
+ {
+ // calculate lighting
+ if (maskedtexturecol[dc_x] != H2MAXSHORT)
+ {
+ if (!fixedcolormap)
+ {
+ idx = spryscale>>LIGHTSCALESHIFT;
+ if (idx >= MAXLIGHTSCALE)
+ idx = MAXLIGHTSCALE-1;
+ dc_colormap = walllights[idx];
+ }
+
+ sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
+ dc_iscale = 0xffffffffu / (unsigned)spryscale;
+
+ //
+ // draw the texture
+ //
+ col = (column_t *)(
+ (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
+
+ R_DrawMaskedColumn (col, -1);
+ maskedtexturecol[dc_x] = H2MAXSHORT;
+ }
+ spryscale += rw_scalestep;
+ }
+}
+
+/*
+================
+=
+= R_RenderSegLoop
+=
+= Draws zero, one, or two textures (and possibly a masked texture) for walls
+= Can draw or mark the starting pixel of floor and ceiling textures
+=
+= CALLED: CORE LOOPING ROUTINE
+================
+*/
+
+#define HEIGHTBITS 12
+#define HEIGHTUNIT (1<<HEIGHTBITS)
+
+void R_RenderSegLoop (void)
+{
+ angle_t angle;
+ unsigned idx;
+ int yl, yh, mid;
+ fixed_t texturecolumn;
+ int top, bottom;
+
+ texturecolumn = 0; // shut up compiler warning
+
+ for ( ; rw_x < rw_stopx ; rw_x++)
+ {
+//
+// mark floor / ceiling areas
+//
+ yl = (topfrac + HEIGHTUNIT - 1)>>HEIGHTBITS;
+ if (yl < ceilingclip[rw_x] + 1)
+ yl = ceilingclip[rw_x] + 1; // no space above wall
+ if (markceiling)
+ {
+ top = ceilingclip[rw_x] + 1;
+ bottom = yl - 1;
+ if (bottom >= floorclip[rw_x])
+ bottom = floorclip[rw_x] - 1;
+ if (top <= bottom)
+ {
+ ceilingplane->top[rw_x] = top;
+ ceilingplane->bottom[rw_x] = bottom;
+ }
+ }
+
+ yh = bottomfrac>>HEIGHTBITS;
+ if (yh >= floorclip[rw_x])
+ yh = floorclip[rw_x] - 1;
+ if (markfloor)
+ {
+ top = yh + 1;
+ bottom = floorclip[rw_x] - 1;
+ if (top <= ceilingclip[rw_x])
+ top = ceilingclip[rw_x] + 1;
+ if (top <= bottom)
+ {
+ floorplane->top[rw_x] = top;
+ floorplane->bottom[rw_x] = bottom;
+ }
+ }
+
+//
+// texturecolumn and lighting are independent of wall tiers
+//
+ if (segtextured)
+ {
+ // calculate texture offset
+ angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
+ texturecolumn = rw_offset - FixedMul(finetangent[angle], rw_distance);
+ texturecolumn >>= FRACBITS;
+ // calculate lighting
+ idx = rw_scale>>LIGHTSCALESHIFT;
+ if (idx >= MAXLIGHTSCALE)
+ idx = MAXLIGHTSCALE - 1;
+ dc_colormap = walllights[idx];
+ dc_x = rw_x;
+ dc_iscale = 0xffffffffu / (unsigned)rw_scale;
+ }
+
+//
+// draw the wall tiers
+//
+ if (midtexture)
+ { // single sided line
+ dc_yl = yl;
+ dc_yh = yh;
+ dc_texturemid = rw_midtexturemid;
+ dc_source = R_GetColumn(midtexture, texturecolumn);
+ colfunc ();
+ ceilingclip[rw_x] = viewheight;
+ floorclip[rw_x] = -1;
+ }
+ else
+ { // two sided line
+ if (toptexture)
+ { // top wall
+ mid = pixhigh>>HEIGHTBITS;
+ pixhigh += pixhighstep;
+ if (mid >= floorclip[rw_x])
+ mid = floorclip[rw_x] - 1;
+ if (mid >= yl)
+ {
+ dc_yl = yl;
+ dc_yh = mid;
+ dc_texturemid = rw_toptexturemid;
+ dc_source = R_GetColumn(toptexture, texturecolumn);
+ colfunc ();
+ ceilingclip[rw_x] = mid;
+ }
+ else
+ ceilingclip[rw_x] = yl - 1;
+ }
+ else
+ { // no top wall
+ if (markceiling)
+ ceilingclip[rw_x] = yl - 1;
+ }
+
+ if (bottomtexture)
+ { // bottom wall
+ mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS;
+ pixlow += pixlowstep;
+ if (mid <= ceilingclip[rw_x])
+ mid = ceilingclip[rw_x] + 1; // no space above wall
+ if (mid <= yh)
+ {
+ dc_yl = mid;
+ dc_yh = yh;
+ dc_texturemid = rw_bottomtexturemid;
+ dc_source = R_GetColumn(bottomtexture, texturecolumn);
+ colfunc ();
+ floorclip[rw_x] = mid;
+ }
+ else
+ floorclip[rw_x] = yh + 1;
+ }
+ else
+ { // no bottom wall
+ if (markfloor)
+ floorclip[rw_x] = yh + 1;
+ }
+
+ if (maskedtexture)
+ { // save texturecol for backdrawing of masked mid texture
+ maskedtexturecol[rw_x] = texturecolumn;
+ }
+ }
+
+ rw_scale += rw_scalestep;
+ topfrac += topstep;
+ bottomfrac += bottomstep;
+ }
+}
+
+
+/*
+=====================
+=
+= R_StoreWallRange
+=
+= A wall segment will be drawn between start and stop pixels (inclusive)
+=
+======================
+*/
+
+void R_StoreWallRange (int start, int stop)
+{
+ fixed_t hyp;
+ fixed_t sineval;
+ angle_t distangle, offsetangle;
+ fixed_t vtop;
+ int lightnum;
+
+ if (ds_p == &drawsegs[MAXDRAWSEGS])
+ return; // don't overflow and crash
+
+#ifdef RANGECHECK
+ if (start >=viewwidth || start > stop)
+ I_Error ("Bad R_RenderWallRange: %i to %i", start , stop);
+#endif
+
+ sidedef = curline->sidedef;
+ linedef = curline->linedef;
+
+// mark the segment as visible for auto map
+ linedef->flags |= ML_MAPPED;
+
+//
+// calculate rw_distance for scale calculation
+//
+ rw_normalangle = curline->angle + ANG90;
+ offsetangle = abs(rw_normalangle - rw_angle1);
+ if (offsetangle > ANG90)
+ offsetangle = ANG90;
+ distangle = ANG90 - offsetangle;
+ hyp = R_PointToDist (curline->v1->x, curline->v1->y);
+ sineval = finesine[distangle>>ANGLETOFINESHIFT];
+ rw_distance = FixedMul (hyp, sineval);
+
+ ds_p->x1 = rw_x = start;
+ ds_p->x2 = stop;
+ ds_p->curline = curline;
+ rw_stopx = stop + 1;
+
+//
+// calculate scale at both ends and step
+//
+ ds_p->scale1 = rw_scale =
+ R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]);
+ if (stop > start)
+ {
+ ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]);
+ ds_p->scalestep = rw_scalestep =
+ (ds_p->scale2 - rw_scale) / (stop-start);
+ }
+ else
+ {
+ //
+ // try to fix the stretched line bug
+ //
+#if 0
+ if (rw_distance < FRACUNIT/2)
+ {
+ fixed_t xtr, ytr;
+ fixed_t gxt, gyt;
+
+ xtr = curline->v1->x - viewx;
+ ytr = curline->v1->y - viewy;
+
+ gxt = FixedMul(xtr, viewcos);
+ gyt = -FixedMul(ytr, viewsin);
+ ds_p->scale1 = FixedDiv(projection, gxt - gyt);
+ }
+#endif
+ ds_p->scale2 = ds_p->scale1;
+ }
+
+//
+// calculate texture boundaries and decide if floor / ceiling marks
+// are needed
+//
+ worldtop = frontsector->ceilingheight - viewz;
+ worldbottom = frontsector->floorheight - viewz;
+
+ midtexture = toptexture = bottomtexture = maskedtexture = 0;
+ ds_p->maskedtexturecol = NULL;
+
+ if (!backsector)
+ {
+//
+// single sided line
+//
+ midtexture = texturetranslation[sidedef->midtexture];
+ // a single sided line is terminal, so it must mark ends
+ markfloor = markceiling = true;
+ if (linedef->flags & ML_DONTPEGBOTTOM)
+ {
+ vtop = frontsector->floorheight + textureheight[sidedef->midtexture];
+ rw_midtexturemid = vtop - viewz; // bottom of texture at bottom
+ }
+ else
+ rw_midtexturemid = worldtop; // top of texture at top
+ rw_midtexturemid += sidedef->rowoffset;
+ ds_p->silhouette = SIL_BOTH;
+ ds_p->sprtopclip = screenheightarray;
+ ds_p->sprbottomclip = negonearray;
+ ds_p->bsilheight = H2MAXINT;
+ ds_p->tsilheight = H2MININT;
+ }
+ else
+ {
+//
+// two sided line
+//
+ ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
+ ds_p->silhouette = 0;
+ if (frontsector->floorheight > backsector->floorheight)
+ {
+ ds_p->silhouette = SIL_BOTTOM;
+ ds_p->bsilheight = frontsector->floorheight;
+ }
+ else if (backsector->floorheight > viewz)
+ {
+ ds_p->silhouette = SIL_BOTTOM;
+ ds_p->bsilheight = H2MAXINT;
+// ds_p->sprbottomclip = negonearray;
+ }
+ if (frontsector->ceilingheight < backsector->ceilingheight)
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = frontsector->ceilingheight;
+ }
+ else if (backsector->ceilingheight < viewz)
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = H2MININT;
+// ds_p->sprtopclip = screenheightarray;
+ }
+
+ if (backsector->ceilingheight <= frontsector->floorheight)
+ {
+ ds_p->sprbottomclip = negonearray;
+ ds_p->bsilheight = H2MAXINT;
+ ds_p->silhouette |= SIL_BOTTOM;
+ }
+ if (backsector->floorheight >= frontsector->ceilingheight)
+ {
+ ds_p->sprtopclip = screenheightarray;
+ ds_p->tsilheight = H2MININT;
+ ds_p->silhouette |= SIL_TOP;
+ }
+ worldhigh = backsector->ceilingheight - viewz;
+ worldlow = backsector->floorheight - viewz;
+
+ // hack to allow height changes in outdoor areas
+ if (frontsector->ceilingpic == skyflatnum &&
+ backsector->ceilingpic == skyflatnum)
+ worldtop = worldhigh;
+
+ if (worldlow != worldbottom ||
+ backsector->floorpic != frontsector->floorpic ||
+ backsector->lightlevel != frontsector->lightlevel ||
+ backsector->special != frontsector->special)
+ markfloor = true;
+ else
+ markfloor = false; // same plane on both sides
+
+ if (worldhigh != worldtop ||
+ backsector->ceilingpic != frontsector->ceilingpic ||
+ backsector->lightlevel != frontsector->lightlevel)
+ markceiling = true;
+ else
+ markceiling = false; // same plane on both sides
+
+ if (backsector->ceilingheight <= frontsector->floorheight ||
+ backsector->floorheight >= frontsector->ceilingheight)
+ markceiling = markfloor = true; // closed door
+
+ if (worldhigh < worldtop)
+ { // top texture
+ toptexture = texturetranslation[sidedef->toptexture];
+ if (linedef->flags & ML_DONTPEGTOP)
+ rw_toptexturemid = worldtop; // top of texture at top
+ else
+ {
+ vtop = backsector->ceilingheight +
+ textureheight[sidedef->toptexture];
+ rw_toptexturemid = vtop - viewz; // bottom of texture
+ }
+ }
+ if (worldlow > worldbottom)
+ { // bottom texture
+ bottomtexture = texturetranslation[sidedef->bottomtexture];
+ if (linedef->flags & ML_DONTPEGBOTTOM)
+ { // bottom of texture at bottom
+ rw_bottomtexturemid = worldtop; // top of texture at top
+ }
+ else // top of texture at top
+ rw_bottomtexturemid = worldlow;
+ }
+ rw_toptexturemid += sidedef->rowoffset;
+ rw_bottomtexturemid += sidedef->rowoffset;
+
+ //
+ // allocate space for masked texture tables
+ //
+ if (sidedef->midtexture)
+ { // masked midtexture
+ maskedtexture = true;
+ ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
+ lastopening += rw_stopx - rw_x;
+ }
+ }
+
+//
+// calculate rw_offset (only needed for textured lines)
+//
+ segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
+
+ if (segtextured)
+ {
+ offsetangle = rw_normalangle - rw_angle1;
+ if (offsetangle > ANG180)
+ offsetangle = -offsetangle;
+ if (offsetangle > ANG90)
+ offsetangle = ANG90;
+ sineval = finesine[offsetangle >>ANGLETOFINESHIFT];
+ rw_offset = FixedMul (hyp, sineval);
+ if (rw_normalangle - rw_angle1 < ANG180)
+ rw_offset = -rw_offset;
+ rw_offset += sidedef->textureoffset + curline->offset;
+ rw_centerangle = ANG90 + viewangle - rw_normalangle;
+
+ //
+ // calculate light table
+ // use different light tables for horizontal / vertical / diagonal
+ // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
+ if (!fixedcolormap)
+ {
+ lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ //if (curline->v1->y == curline->v2->y)
+ // lightnum--;
+ //else if (curline->v1->x == curline->v2->x)
+ // lightnum++;
+ //if (lightnum < 0)
+ // walllights = scalelight[0];
+ if (lightnum >= LIGHTLEVELS)
+ walllights = scalelight[LIGHTLEVELS-1];
+ else
+ walllights = scalelight[lightnum];
+ }
+ }
+
+//
+// if a floor / ceiling plane is on the wrong side of the view plane
+// it is definately invisible and doesn't need to be marked
+//
+ if (frontsector->floorheight >= viewz)
+ markfloor = false; // above view plane
+ if (frontsector->ceilingheight <= viewz &&
+ frontsector->ceilingpic != skyflatnum)
+ markceiling = false; // below view plane
+
+//
+// calculate incremental stepping values for texture edges
+//
+ worldtop >>= 4;
+ worldbottom >>= 4;
+
+ topstep = -FixedMul (rw_scalestep, worldtop);
+ topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale);
+
+ bottomstep = -FixedMul (rw_scalestep, worldbottom);
+ bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale);
+
+ if (backsector)
+ {
+ worldhigh >>= 4;
+ worldlow >>= 4;
+
+ if (worldhigh < worldtop)
+ {
+ pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
+ pixhighstep = -FixedMul (rw_scalestep,worldhigh);
+ }
+ if (worldlow > worldbottom)
+ {
+ pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
+ pixlowstep = -FixedMul (rw_scalestep, worldlow);
+ }
+ }
+
+//
+// render it
+//
+ if (markceiling)
+ ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx - 1);
+ if (markfloor)
+ floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx - 1);
+
+ R_RenderSegLoop ();
+
+//
+// save sprite clipping info
+//
+ if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip)
+ {
+ memcpy (lastopening, ceilingclip + start, 2*(rw_stopx - start));
+ ds_p->sprtopclip = lastopening - start;
+ lastopening += rw_stopx - start;
+ }
+ if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip)
+ {
+ memcpy (lastopening, floorclip + start, 2*(rw_stopx - start));
+ ds_p->sprbottomclip = lastopening - start;
+ lastopening += rw_stopx - start;
+ }
+ if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
+ {
+ ds_p->silhouette |= SIL_TOP;
+ ds_p->tsilheight = H2MININT;
+ }
+ if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
+ {
+ ds_p->silhouette |= SIL_BOTTOM;
+ ds_p->bsilheight = H2MAXINT;
+ }
+ ds_p++;
+}
+#endif /* !RENDER3D */
+
--- /dev/null
+++ b/r_things.c
@@ -1,0 +1,1196 @@
+
+//**************************************************************************
+//**
+//** r_things.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "r_local.h"
+#ifdef RENDER3D
+#include "ogl_def.h"
+#endif
+
+void R_DrawColumn (void);
+void R_DrawFuzzColumn (void);
+void R_DrawAltFuzzColumn(void);
+//void R_DrawTranslatedAltFuzzColumn(void);
+
+typedef struct
+{
+ int x1, x2;
+
+ int column;
+ int topclip;
+ int bottomclip;
+} maskdraw_t;
+
+/*
+
+Sprite rotation 0 is facing the viewer, rotation 1 is one angle turn CLOCKWISE around the axis.
+This is not the same as the angle, which increases counter clockwise
+(protractor). There was a lot of stuff grabbed wrong, so I changed it...
+
+*/
+
+fixed_t pspritescale, pspriteiscale;
+
+// constant arrays used for psprite clipping and initializing clipping
+#ifndef RENDER3D
+short negonearray[SCREENWIDTH];
+short screenheightarray[SCREENWIDTH];
+#endif
+
+boolean LevelUseFullBright;
+
+// variables used to look up and range check thing_t sprites patches
+spritedef_t *sprites;
+int numsprites;
+
+#ifndef RENDER3D
+static lighttable_t **spritelights;
+#endif
+
+static spriteframe_t sprtemp[30];
+static int maxframe;
+static const char *spritename;
+
+
+/*
+===============================================================================
+
+ INITIALIZATION FUNCTIONS
+
+===============================================================================
+*/
+
+/*
+=================
+=
+= R_InstallSpriteLump
+=
+= Local function for R_InitSprites
+=================
+*/
+
+void R_InstallSpriteLump (int lump, unsigned frame, unsigned rotation, boolean flipped)
+{
+ int r;
+
+ if (frame >= 30 || rotation > 8)
+ I_Error ("R_InstallSpriteLump: Bad frame characters in lump %i", lump);
+
+ if ((int)frame > maxframe)
+ maxframe = frame;
+
+ if (rotation == 0)
+ {
+ // the lump should be used for all rotations
+ if (sprtemp[frame].rotate == false)
+ {
+ I_Error ("R_InitSprites: Sprite %s frame %c has multip rot=0 lump",
+ spritename, 'A'+frame);
+ }
+ if (sprtemp[frame].rotate == true)
+ {
+ I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump",
+ spritename, 'A'+frame);
+ }
+
+ sprtemp[frame].rotate = false;
+ for (r = 0; r < 8; r++)
+ {
+ sprtemp[frame].lump[r] = lump - firstspritelump;
+ sprtemp[frame].flip[r] = (byte)flipped;
+ }
+ return;
+ }
+
+ // the lump is only used for one rotation
+ if (sprtemp[frame].rotate == false)
+ {
+ I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump",
+ spritename, 'A'+frame);
+ }
+
+ sprtemp[frame].rotate = true;
+
+ rotation--; // make 0 based
+ if (sprtemp[frame].lump[rotation] != -1)
+ {
+ I_Error ("R_InitSprites: Sprite %s : %c : %c has two lumps mapped to it",
+ spritename, 'A'+frame, '1' + rotation);
+ }
+
+ sprtemp[frame].lump[rotation] = lump - firstspritelump;
+ sprtemp[frame].flip[rotation] = (byte)flipped;
+}
+
+/*
+=================
+=
+= R_InitSpriteDefs
+=
+= Pass a null terminated list of sprite names (4 chars exactly) to be used
+= Builds the sprite rotation matrixes to account for horizontally flipped
+= sprites. Will report an error if the lumps are inconsistant
+=
+Only called at startup
+=
+= Sprite lump names are 4 characters for the actor, a letter for the frame,
+= and a number for the rotation, A sprite that is flippable will have an
+= additional letter/number appended. The rotation character can be 0 to
+= signify no rotations
+=================
+*/
+
+void R_InitSpriteDefs (const char **namelist)
+{
+ const char **check;
+ int i, l, frame, rotation;
+ int start, end;
+
+// count the number of sprite names
+ check = namelist;
+ while (*check != NULL)
+ check++;
+ numsprites = check - namelist;
+
+ if (!numsprites)
+ return;
+
+ sprites = (spritedef_t *) Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL);
+
+ start = firstspritelump - 1;
+ end = lastspritelump + 1;
+
+// scan all the lump names for each of the names, noting the highest
+// frame letter
+// Just compare 4 characters as ints
+ for (i = 0; i < numsprites; i++)
+ {
+ spritename = namelist[i];
+ memset (sprtemp, -1, sizeof(sprtemp));
+
+ maxframe = -1;
+
+ //
+ // scan the lumps, filling in the frames for whatever is found
+ //
+ for (l = start + 1; l < end; l++)
+ {
+ if (memcmp(lumpinfo[l].name, namelist[i], 4) == 0)
+ {
+ frame = lumpinfo[l].name[4] - 'A';
+ rotation = lumpinfo[l].name[5] - '0';
+ R_InstallSpriteLump (l, frame, rotation, false);
+ if (lumpinfo[l].name[6])
+ {
+ frame = lumpinfo[l].name[6] - 'A';
+ rotation = lumpinfo[l].name[7] - '0';
+ R_InstallSpriteLump (l, frame, rotation, true);
+ }
+ }
+ }
+
+ //
+ // check the frames that were found for completeness
+ //
+ if (maxframe == -1)
+ {
+ //continue;
+ sprites[i].numframes = 0;
+ if (shareware)
+ continue;
+ I_Error ("R_InitSprites: No lumps found for sprite %s", namelist[i]);
+ }
+
+ maxframe++;
+ for (frame = 0; frame < maxframe; frame++)
+ {
+ switch ((int)sprtemp[frame].rotate)
+ {
+ case -1: // no rotations were found for that frame at all
+ I_Error ("R_InitSprites: No patches found for %s frame %c",
+ namelist[i], frame+'A');
+ case 0: // only the first rotation is needed
+ break;
+
+ case 1: // must have all 8 frames
+ for (rotation = 0; rotation < 8; rotation++)
+ {
+ if (sprtemp[frame].lump[rotation] == -1)
+ {
+ I_Error ("R_InitSprites: Sprite %s frame %c is missing rotations",
+ namelist[i], frame+'A');
+ }
+ }
+ }
+ }
+
+ //
+ // allocate space for the frames present and copy sprtemp to it
+ //
+ sprites[i].numframes = maxframe;
+ sprites[i].spriteframes =
+ (spriteframe_t *) Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
+ memcpy (sprites[i].spriteframes, sprtemp, maxframe*sizeof(spriteframe_t));
+ }
+}
+
+
+/*
+===============================================================================
+
+ GAME FUNCTIONS
+
+===============================================================================
+*/
+
+vissprite_t vissprites[MAXVISSPRITES], *vissprite_p;
+
+/*
+===================
+=
+= R_InitSprites
+=
+= Called at program start
+===================
+*/
+
+void R_InitSprites (const char **namelist)
+{
+#ifndef RENDER3D
+ int i;
+
+ for (i = 0; i < SCREENWIDTH; i++)
+ {
+ negonearray[i] = -1;
+ }
+#endif
+ R_InitSpriteDefs (namelist);
+}
+
+
+/*
+===================
+=
+= R_ClearSprites
+=
+= Called at frame start
+===================
+*/
+
+void R_ClearSprites (void)
+{
+ vissprite_p = vissprites;
+}
+
+
+/*
+===================
+=
+= R_NewVisSprite
+=
+===================
+*/
+
+static vissprite_t overflowsprite;
+
+static vissprite_t *R_NewVisSprite (void)
+{
+ if (vissprite_p == &vissprites[MAXVISSPRITES])
+ return &overflowsprite;
+ vissprite_p++;
+ return vissprite_p - 1;
+}
+
+
+#ifndef RENDER3D
+/*
+================
+=
+= R_DrawMaskedColumn
+=
+= Used for sprites and masked mid textures
+================
+*/
+
+short *mfloorclip;
+short *mceilingclip;
+fixed_t spryscale;
+fixed_t sprtopscreen;
+fixed_t sprbotscreen;
+
+void R_DrawMaskedColumn (column_t *column, signed int baseclip)
+{
+ int topscreen, bottomscreen;
+ fixed_t basetexturemid;
+
+ basetexturemid = dc_texturemid;
+
+ for ( ; column->topdelta != 0xff ; )
+ {
+ // calculate unclipped screen coordinates for post
+ topscreen = sprtopscreen + spryscale*column->topdelta;
+ bottomscreen = topscreen + spryscale*column->length;
+ dc_yl = (topscreen + FRACUNIT - 1)>>FRACBITS;
+ dc_yh = (bottomscreen - 1)>>FRACBITS;
+
+ if (dc_yh >= mfloorclip[dc_x])
+ dc_yh = mfloorclip[dc_x] - 1;
+ if (dc_yl <= mceilingclip[dc_x])
+ dc_yl = mceilingclip[dc_x] + 1;
+
+ if (dc_yh >= baseclip && baseclip != -1)
+ dc_yh = baseclip;
+
+ if (dc_yl <= dc_yh)
+ {
+ dc_source = (byte *)column + 3;
+ dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS);
+ // dc_source = (byte *)column + 3 - column->topdelta;
+ colfunc (); // either R_DrawColumn or R_DrawFuzzColumn
+ }
+ column = (column_t *)( (byte *)column + column->length + 4);
+ }
+
+ dc_texturemid = basetexturemid;
+}
+
+
+/*
+================
+=
+= R_DrawVisSprite
+=
+= mfloorclip and mceilingclip should also be set
+================
+*/
+
+void R_DrawVisSprite (vissprite_t *vis, int x1, int x2)
+{
+ column_t *column;
+ int texturecolumn;
+ fixed_t frac;
+ patch_t *patch;
+ fixed_t baseclip;
+
+ patch = (patch_t *) W_CacheLumpNum(vis->patch + firstspritelump, PU_CACHE);
+
+ dc_colormap = vis->colormap;
+
+// if (!dc_colormap)
+// colfunc = fuzzcolfunc; // NULL colormap = shadow draw
+
+ if (vis->mobjflags & (MF_SHADOW|MF_ALTSHADOW))
+ {
+ if (vis->mobjflags & MF_TRANSLATION)
+ {
+ colfunc = R_DrawTranslatedFuzzColumn;
+ dc_translation = translationtables - 256 + vis->playerclass * ((MAXPLAYERS - 1) * 256) +
+ ((vis->mobjflags & MF_TRANSLATION)>>(MF_TRANSSHIFT - 8));
+ }
+ else if (vis->mobjflags & MF_SHADOW)
+ { // Draw using shadow column function
+ colfunc = fuzzcolfunc;
+ }
+ else
+ {
+ colfunc = R_DrawAltFuzzColumn;
+ }
+ }
+ else if (vis->mobjflags & MF_TRANSLATION)
+ {
+ // Draw using translated column function
+ colfunc = R_DrawTranslatedColumn;
+ dc_translation = translationtables - 256 + vis->playerclass * ((MAXPLAYERS - 1) * 256) +
+ ((vis->mobjflags & MF_TRANSLATION)>>(MF_TRANSSHIFT - 8));
+ }
+
+ dc_iscale = abs(vis->xiscale) >> detailshift;
+ dc_texturemid = vis->texturemid;
+ frac = vis->startfrac;
+ spryscale = vis->scale;
+
+ sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
+
+ // check to see if vissprite is a weapon
+ if (vis->psprite)
+ {
+ dc_texturemid += FixedMul(((centery-viewheight/2)<<FRACBITS), vis->xiscale);
+ sprtopscreen += (viewheight/2 - centery)<<FRACBITS;
+ }
+
+ if (vis->floorclip && !vis->psprite)
+ {
+ sprbotscreen = sprtopscreen + FixedMul(SHORT(patch->height)<<FRACBITS, spryscale);
+ baseclip = (sprbotscreen - FixedMul(vis->floorclip, spryscale))>>FRACBITS;
+ }
+ else
+ {
+ baseclip = -1;
+ }
+
+ for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale)
+ {
+ texturecolumn = frac>>FRACBITS;
+#ifdef RANGECHECK
+ if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
+ I_Error ("R_DrawSpriteRange: bad texturecolumn");
+#endif
+ column = (column_t *) ((byte *)patch + LONG(patch->columnofs[texturecolumn]));
+ R_DrawMaskedColumn (column, baseclip);
+ }
+
+ colfunc = basecolfunc;
+}
+#endif /* RENDER3D */
+
+
+/*
+===================
+=
+= R_ProjectSprite
+=
+= Generates a vissprite for a thing if it might be visible
+=
+===================
+*/
+
+void R_ProjectSprite (mobj_t *thing)
+{
+ fixed_t xtr, ytr;
+ fixed_t gxt, gyt;
+ fixed_t tz;
+ fixed_t xscale;
+ int x1 = 0, x2 = 0;
+ spritedef_t *sprdef;
+ spriteframe_t *sprframe;
+ int lump;
+ unsigned int rot;
+ boolean flip;
+#ifndef RENDER3D
+ fixed_t tx;
+ int idx;
+#endif
+ vissprite_t *vis;
+ angle_t ang;
+ fixed_t iscale;
+#ifdef RENDER3D
+ float v1[2], v2[2];
+ float sinrv, cosrv, thangle; // rv = real value
+#endif
+
+ if (thing->flags2 & MF2_DONTDRAW)
+ { // Never make a vissprite when MF2_DONTDRAW is flagged.
+ return;
+ }
+
+//
+// transform the origin point
+//
+ xtr = thing->x - viewx;
+ ytr = thing->y - viewy;
+
+ gxt = FixedMul(xtr,viewcos);
+ gyt = -FixedMul(ytr,viewsin);
+ tz = gxt - gyt;
+
+#ifdef RENDER3D
+ if (tz < 0)
+ tz = -tz; // Make it positive. The clipper will handle backside.
+ if (tz < FRACUNIT)
+ tz = FRACUNIT;
+#else
+ if (tz < MINZ)
+ return; // thing is behind view plane
+#endif
+ xscale = FixedDiv(projection, tz);
+
+#ifndef RENDER3D
+ gxt = -FixedMul(xtr,viewsin);
+ gyt = FixedMul(ytr,viewcos);
+ tx = -(gyt + gxt);
+
+ if (abs(tx) > (tz<<2))
+ return; // too far off the side
+#endif
+
+//
+// decide which patch to use for sprite reletive to player
+//
+#ifdef RANGECHECK
+ if ((unsigned int)thing->sprite >= numsprites)
+ I_Error ("R_ProjectSprite: invalid sprite number %i ", thing->sprite);
+#endif
+ sprdef = &sprites[thing->sprite];
+#ifdef RANGECHECK
+ if ((thing->frame&FF_FRAMEMASK) >= sprdef->numframes)
+ I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ", thing->sprite, thing->frame);
+#endif
+ sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
+
+ if (sprframe->rotate)
+ { // choose a different rotation based on player view
+ ang = R_PointToAngle (thing->x, thing->y);
+ rot = (ang - thing->angle + (unsigned int)(ANG45/2)*9) >> 29;
+ lump = sprframe->lump[rot];
+ flip = !!(sprframe->flip[rot]);
+ }
+ else
+ { // use single rotation for all views
+ lump = sprframe->lump[0];
+ flip = !!(sprframe->flip[0]);
+ }
+
+//
+// calculate edges of the shape
+//
+#ifdef RENDER3D
+ v1[VX] = FIX2FLT(thing->x);
+ v1[VY] = FIX2FLT(thing->y);
+// thangle = BANG2RAD(bamsAtan2((v1[VY]-FIX2FLT(viewy))*10, (v1[VX]-FIX2FLT(viewx))*10)) - PI/2;
+ thangle = BANG2RAD(bamsAtan2(FIX2FLT(ytr)*10, FIX2FLT(xtr)*10)) - PI/2;
+ sinrv = sin(thangle);
+ cosrv = cos(thangle);
+ v1[VX] -= cosrv*(spriteoffset[lump]>>FRACBITS);
+ v1[VY] -= sinrv*(spriteoffset[lump]>>FRACBITS);
+ v2[VX] = v1[VX] + cosrv*(spritewidth[lump]>>FRACBITS);
+ v2[VY] = v1[VY] + sinrv*(spritewidth[lump]>>FRACBITS);
+ // Check for visibility.
+ if (!C_CheckViewRelSeg(v1[VX], v1[VY], v2[VX], v2[VY]))
+ //if (!C_IsAngleVisible(RAD2BANG(thangle+PI/2)))
+ return; // Isn't visible.
+#else
+ tx -= spriteoffset[lump];
+ x1 = (centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS;
+ if (x1 > viewwidth)
+ return; // off the right side
+ tx += spritewidth[lump];
+ x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1;
+ if (x2 < 0)
+ return; // off the left side
+#endif
+
+//
+// store information in a vissprite
+//
+ vis = R_NewVisSprite ();
+ vis->mobjflags = thing->flags;
+ vis->psprite = false;
+ vis->scale = xscale<<detailshift;
+ vis->gx = thing->x;
+ vis->gy = thing->y;
+ vis->gz = thing->z;
+ vis->gzt = thing->z + spritetopoffset[lump];
+
+#ifdef RENDER3D
+ vis->secfloor = FIX2FLT(thing->subsector->sector->floorheight);
+ vis->secceil = FIX2FLT(thing->subsector->sector->ceilingheight);
+#endif
+
+ if (thing->flags & MF_TRANSLATION)
+ {
+ if (thing->player)
+ {
+ vis->playerclass = thing->player->playerclass;
+ }
+ else
+ {
+ vis->playerclass = thing->special1;
+ }
+ if (vis->playerclass > 2)
+ {
+ // O.S. -- FIXME: HARDCODED NUMBER: 2 == PCLASS_MAGE
+ vis->playerclass = 0;
+ }
+ }
+ // foot clipping
+ vis->floorclip = thing->floorclip;
+ vis->texturemid = vis->gzt - viewz - vis->floorclip;
+
+#ifdef RENDER3D
+ // The start and end vertices.
+ vis->v1[VX] = v1[VX];
+ vis->v1[VY] = v1[VY];
+ vis->v2[VX] = v2[VX];
+ vis->v2[VY] = v2[VY];
+#endif
+
+ vis->x1 = x1 < 0 ? 0 : x1;
+ vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+ iscale = FixedDiv (FRACUNIT, xscale);
+ if (flip)
+ {
+ vis->startfrac = spritewidth[lump]-1;
+ vis->xiscale = -iscale;
+ }
+ else
+ {
+ vis->startfrac = 0;
+ vis->xiscale = iscale;
+ }
+ if (vis->x1 > x1)
+ vis->startfrac += vis->xiscale*(vis->x1 - x1);
+ vis->patch = lump;
+//
+// get light level
+//
+
+// if (thing->flags & MF_SHADOW)
+// vis->colormap = NULL; // shadow draw
+// else ...
+
+#ifdef RENDER3D
+ if (thing->frame & FF_FULLBRIGHT)
+ { // full bright
+ vis->lightlevel = -1;
+ }
+ else
+ { // diminished light
+ vis->lightlevel = thing->subsector->sector->lightlevel;
+ }
+#else
+ if (fixedcolormap)
+ vis->colormap = fixedcolormap; // fixed map
+ else if (LevelUseFullBright && thing->frame & FF_FULLBRIGHT)
+ vis->colormap = colormaps; // full bright
+ else
+ { // diminished light
+ idx = xscale>>(LIGHTSCALESHIFT - detailshift);
+ if (idx >= MAXLIGHTSCALE)
+ idx = MAXLIGHTSCALE-1;
+ vis->colormap = spritelights[idx];
+ }
+#endif
+}
+
+
+/*
+========================
+=
+= R_AddSprites
+=
+========================
+*/
+
+void R_AddSprites (sector_t *sec)
+{
+ if (sec->validcount == validcount)
+ {
+ return; // already added
+ }
+ else
+ {
+ mobj_t *thing;
+#ifndef RENDER3D
+ int lightnum;
+
+ lightnum = (sec->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ if (lightnum < 0)
+ spritelights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ spritelights = scalelight[LIGHTLEVELS-1];
+ else
+ spritelights = scalelight[lightnum];
+#endif
+
+ sec->validcount = validcount;
+
+ for (thing = sec->thinglist ; thing ; thing = thing->snext)
+ R_ProjectSprite (thing);
+ }
+}
+
+
+/*
+========================
+=
+= R_DrawPSprite
+=
+========================
+*/
+
+/* Y-adjustment values for full screen (4 weapons) */
+static int PSpriteSY[NUMCLASSES][NUMWEAPONS] =
+{
+ { 0, -12 * FRACUNIT, -10 * FRACUNIT, 10 * FRACUNIT }, /* Fighter */
+ { -8 * FRACUNIT, 10 * FRACUNIT, 10 * FRACUNIT, 0 }, /* Cleric */
+ { 9 * FRACUNIT, 20 * FRACUNIT, 20 * FRACUNIT, 20 * FRACUNIT }, /* Mage */
+ { 10 * FRACUNIT, 10 * FRACUNIT, 10 * FRACUNIT, 10 * FRACUNIT } /* Pig */
+};
+
+void R_DrawPSprite (pspdef_t *psp)
+{
+ fixed_t tx;
+ int x1;
+#ifndef RENDER3D
+ int x2;
+#endif
+ spritedef_t *sprdef;
+ spriteframe_t *sprframe;
+ int lump;
+ boolean flip;
+#ifdef RENDER3D
+ float light, alpha;
+ int y;
+#else
+ vissprite_t *vis, avis;
+#endif
+ int tempangle;
+
+//
+// decide which patch to use
+//
+#ifdef RANGECHECK
+ if ( (unsigned int)psp->state->sprite >= numsprites)
+ I_Error ("R_ProjectSprite: invalid sprite number %i ", psp->state->sprite);
+#endif
+ sprdef = &sprites[psp->state->sprite];
+#ifdef RANGECHECK
+ if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes)
+ I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ", psp->state->sprite, psp->state->frame);
+#endif
+ sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK];
+
+ lump = sprframe->lump[0];
+ flip = !!(sprframe->flip[0]);
+
+//
+// calculate edges of the shape
+//
+ tx = psp->sx - 160*FRACUNIT;
+
+ tx -= spriteoffset[lump];
+ if (viewangleoffset)
+ {
+ tempangle = ((centerxfrac/1024)*(viewangleoffset>>ANGLETOFINESHIFT));
+ }
+ else
+ {
+ tempangle = 0;
+ }
+ x1 = (centerxfrac + FixedMul (tx,pspritescale)+tempangle ) >>FRACBITS;
+
+#ifdef RENDER3D
+ // Set the OpenGL color & alpha.
+ light = 1;
+ alpha = 1;
+ if (viewplayer->powers[pw_invulnerability] &&
+ viewplayer->playerclass == PCLASS_CLERIC)
+ {
+ if (viewplayer->powers[pw_invulnerability] > 4*32)
+ {
+ if (viewplayer->mo->flags2 & MF2_DONTDRAW)
+ { // don't draw the psprite
+ alpha = .333f;
+ }
+ else if (viewplayer->mo->flags & MF_SHADOW)
+ {
+ alpha = .666f;
+ }
+ }
+ else if (viewplayer->powers[pw_invulnerability] & 8)
+ {
+ alpha = .333f;
+ }
+ }
+ else if (fixedcolormap)
+ {
+ // Fixed color
+ light = 1;
+ }
+ else if (psp->state->frame & FF_FULLBRIGHT)
+ {
+ // Full bright
+ light = 1;
+ }
+ else
+ {
+ // local light
+ light = viewplayer->mo->subsector->sector->lightlevel / 255.0;
+ }
+
+//
+// do some OpenGL rendering, oh yeah
+//
+ y = -(spritetopoffset[lump]>>FRACBITS) + (psp->sy>>FRACBITS);
+ if (viewheight == SCREENHEIGHT)
+ {
+ y += PSpriteSY[viewplayer->playerclass][players[consoleplayer].readyweapon] >> FRACBITS;
+ }
+ else
+ y -= 39/2;
+
+ light += .1f; // Add some extra light.
+ OGL_SetColorAndAlpha(light, light, light, alpha);
+ OGL_DrawPSprite(x1, y, 1, flip, lump);
+
+#else
+
+ if (x1 > viewwidth)
+ return; // off the right side
+ tx += spritewidth[lump];
+ x2 = ((centerxfrac + FixedMul(tx, pspritescale) + tempangle) >>FRACBITS) - 1;
+ if (x2 < 0)
+ return; // off the left side
+
+//
+// store information in a vissprite
+//
+ vis = &avis;
+ vis->mobjflags = 0;
+ vis->playerclass = 0;
+ vis->psprite = true;
+ vis->texturemid = (BASEYCENTER<<FRACBITS)+FRACUNIT/2 - (psp->sy-spritetopoffset[lump]);
+ if (viewheight == SCREENHEIGHT)
+ {
+ vis->texturemid -= PSpriteSY[viewplayer->playerclass][players[consoleplayer].readyweapon];
+ }
+ vis->x1 = x1 < 0 ? 0 : x1;
+ vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+ vis->scale = pspritescale<<detailshift;
+ if (flip)
+ {
+ vis->xiscale = -pspriteiscale;
+ vis->startfrac = spritewidth[lump]-1;
+ }
+ else
+ {
+ vis->xiscale = pspriteiscale;
+ vis->startfrac = 0;
+ }
+ if (vis->x1 > x1)
+ vis->startfrac += vis->xiscale*(vis->x1 - x1);
+ vis->patch = lump;
+
+ if (viewplayer->powers[pw_invulnerability] &&
+ viewplayer->playerclass == PCLASS_CLERIC)
+ {
+ vis->colormap = spritelights[MAXLIGHTSCALE-1];
+ if (viewplayer->powers[pw_invulnerability] > 4*32)
+ {
+ if (viewplayer->mo->flags2 & MF2_DONTDRAW)
+ { // don't draw the psprite
+ vis->mobjflags |= MF_SHADOW;
+ }
+ else if (viewplayer->mo->flags & MF_SHADOW)
+ {
+ vis->mobjflags |= MF_ALTSHADOW;
+ }
+ }
+ else if (viewplayer->powers[pw_invulnerability] & 8)
+ {
+ vis->mobjflags |= MF_SHADOW;
+ }
+ }
+ else if (fixedcolormap)
+ {
+ // Fixed color
+ vis->colormap = fixedcolormap;
+ }
+ else if (psp->state->frame & FF_FULLBRIGHT)
+ {
+ // Full bright
+ vis->colormap = colormaps;
+ }
+ else
+ {
+ // local light
+ vis->colormap = spritelights[MAXLIGHTSCALE-1];
+ }
+ R_DrawVisSprite(vis, vis->x1, vis->x2);
+#endif
+}
+
+/*
+========================
+=
+= R_DrawPlayerSprites
+=
+========================
+*/
+
+void R_DrawPlayerSprites (void)
+{
+ int i;
+ pspdef_t *psp;
+#ifndef RENDER3D
+ int lightnum;
+
+//
+// get light level
+//
+ lightnum = (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) + extralight;
+ if (lightnum < 0)
+ spritelights = scalelight[0];
+ else if (lightnum >= LIGHTLEVELS)
+ spritelights = scalelight[LIGHTLEVELS-1];
+ else
+ spritelights = scalelight[lightnum];
+//
+// clip to screen bounds
+//
+ mfloorclip = screenheightarray;
+ mceilingclip = negonearray;
+#endif
+
+//
+// add all active psprites
+//
+ for (i = 0, psp = viewplayer->psprites; i < NUMPSPRITES; i++, psp++)
+ {
+ if (psp->state)
+ R_DrawPSprite (psp);
+ }
+}
+
+
+/*
+========================
+=
+= R_SortVisSprites
+=
+========================
+*/
+
+vissprite_t vsprsortedhead;
+
+void R_SortVisSprites (void)
+{
+ int i, count;
+ vissprite_t *ds, *best;
+ vissprite_t unsorted;
+ fixed_t bestscale;
+
+ count = vissprite_p - vissprites;
+
+ unsorted.next = unsorted.prev = &unsorted;
+ if (!count)
+ return;
+
+ for (ds = vissprites; ds < vissprite_p; ds++)
+ {
+ ds->next = ds + 1;
+ ds->prev = ds - 1;
+ }
+ vissprites[0].prev = &unsorted;
+ unsorted.next = &vissprites[0];
+ (vissprite_p - 1)->next = &unsorted;
+ unsorted.prev = vissprite_p - 1;
+
+//
+// pull the vissprites out by scale
+//
+ best = 0; // shut up the compiler warning
+ vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
+ for (i = 0; i < count; i++)
+ {
+ bestscale = H2MAXINT;
+ for (ds = unsorted.next; ds != &unsorted; ds = ds->next)
+ {
+ if (ds->scale < bestscale)
+ {
+ bestscale = ds->scale;
+ best = ds;
+ }
+ }
+ best->next->prev = best->prev;
+ best->prev->next = best->next;
+ best->next = &vsprsortedhead;
+ best->prev = vsprsortedhead.prev;
+ vsprsortedhead.prev->next = best;
+ vsprsortedhead.prev = best;
+ }
+}
+
+
+#ifndef RENDER3D
+/*
+========================
+=
+= R_DrawSprite
+=
+========================
+*/
+
+void R_DrawSprite (vissprite_t *spr)
+{
+ drawseg_t *ds;
+ short clipbot[SCREENWIDTH], cliptop[SCREENWIDTH];
+ int x, r1, r2;
+ fixed_t scale, lowscale;
+ int silhouette;
+
+ for (x = spr->x1; x <= spr->x2; x++)
+ clipbot[x] = cliptop[x] = -2;
+
+//
+// scan drawsegs from end to start for obscuring segs
+// the first drawseg that has a greater scale is the clip seg
+//
+ for (ds = ds_p - 1; ds >= drawsegs; ds--)
+ {
+ //
+ // determine if the drawseg obscures the sprite
+ //
+ if (ds->x1 > spr->x2 || ds->x2 < spr->x1 ||
+ (!ds->silhouette && !ds->maskedtexturecol))
+ continue; // doesn't cover sprite
+
+ r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
+ r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
+ if (ds->scale1 > ds->scale2)
+ {
+ lowscale = ds->scale2;
+ scale = ds->scale1;
+ }
+ else
+ {
+ lowscale = ds->scale1;
+ scale = ds->scale2;
+ }
+
+ if (scale < spr->scale || ( lowscale < spr->scale
+ && !R_PointOnSegSide(spr->gx, spr->gy, ds->curline) ) )
+ {
+ if (ds->maskedtexturecol) // masked mid texture
+ R_RenderMaskedSegRange (ds, r1, r2);
+ continue; // seg is behind sprite
+ }
+
+//
+// clip this piece of the sprite
+//
+ silhouette = ds->silhouette;
+ if (spr->gz >= ds->bsilheight)
+ silhouette &= ~SIL_BOTTOM;
+ if (spr->gzt <= ds->tsilheight)
+ silhouette &= ~SIL_TOP;
+
+ if (silhouette == 1)
+ { // bottom sil
+ for (x = r1; x <= r2; x++)
+ {
+ if (clipbot[x] == -2)
+ clipbot[x] = ds->sprbottomclip[x];
+ }
+ }
+ else if (silhouette == 2)
+ { // top sil
+ for (x = r1; x <= r2; x++)
+ {
+ if (cliptop[x] == -2)
+ cliptop[x] = ds->sprtopclip[x];
+ }
+ }
+ else if (silhouette == 3)
+ { // both
+ for (x = r1; x <= r2; x++)
+ {
+ if (clipbot[x] == -2)
+ clipbot[x] = ds->sprbottomclip[x];
+ if (cliptop[x] == -2)
+ cliptop[x] = ds->sprtopclip[x];
+ }
+ }
+ }
+
+//
+// all clipping has been performed, so draw the sprite
+//
+
+// check for unclipped columns
+ for (x = spr->x1; x <= spr->x2; x++)
+ {
+ if (clipbot[x] == -2)
+ clipbot[x] = viewheight;
+ if (cliptop[x] == -2)
+ cliptop[x] = -1;
+ }
+
+ mfloorclip = clipbot;
+ mceilingclip = cliptop;
+ R_DrawVisSprite (spr, spr->x1, spr->x2);
+}
+#endif /* !RENDER3D */
+
+
+/*
+========================
+=
+= R_DrawMasked
+=
+========================
+*/
+
+void R_DrawMasked (void)
+{
+ vissprite_t *spr;
+
+#ifdef RENDER3D
+ extern boolean willRenderSprites;
+
+ if (!willRenderSprites)
+ return;
+
+ R_SortVisSprites();
+
+ if (vissprite_p > vissprites)
+ {
+ // draw all vissprites back to front
+ glDepthMask(GL_FALSE);
+
+ for (spr = vsprsortedhead.next; spr != &vsprsortedhead;
+ spr = spr->next)
+ {
+ R_RenderSprite(spr);
+ }
+
+ glDepthMask(GL_TRUE);
+ }
+#else
+ drawseg_t *ds;
+
+ R_SortVisSprites ();
+
+ if (vissprite_p > vissprites)
+ {
+ // draw all vissprites back to front
+ for (spr = vsprsortedhead.next; spr != &vsprsortedhead;
+ spr = spr->next)
+ {
+ R_DrawSprite (spr);
+ }
+ }
+
+//
+// render any remaining masked mid textures
+//
+ for (ds = ds_p - 1; ds >= drawsegs; ds--)
+ {
+ if (ds->maskedtexturecol)
+ R_RenderMaskedSegRange (ds, ds->x1, ds->x2);
+ }
+
+//
+// draw the psprites on top of everything
+//
+// Added for the sideviewing with an external device
+ if (viewangleoffset <= 1024<<ANGLETOFINESHIFT ||
+ viewangleoffset >= -1024<<ANGLETOFINESHIFT)
+ {
+ // don't draw on side views
+ R_DrawPlayerSprites ();
+ }
+
+// if (!viewangleoffset) // don't draw on side views
+// R_DrawPlayerSprites ();
+#endif
+}
+
--- /dev/null
+++ b/s_sound.c
@@ -1,0 +1,1260 @@
+//**************************************************************************
+//**
+//** S_SOUND.C: MUSIC & SFX API
+//**
+//** $Revision: 590 $
+//** $Date: 2012-10-23 23:55:31 +0300 (Tue, 23 Oct 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h" /* P_AproxDistance() */
+#include "sounds.h"
+#include "i_sound.h"
+#include "i_cdmus.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define DEFAULT_ARCHIVEPATH "o:\\sound\\archive\\"
+#define PRIORITY_MAX_ADJUST 10
+#define DIST_ADJUST (MAX_SND_DIST/PRIORITY_MAX_ADJUST)
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static boolean S_StopSoundID(int sound_id, int priority);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern int snd_MaxVolume;
+extern int snd_MusicVolume;
+extern int snd_Channels;
+
+#ifdef __WATCOMC__
+extern int snd_SfxDevice;
+extern int snd_MusicDevice;
+extern int snd_DesiredSfxDevice;
+extern int snd_DesiredMusicDevice;
+extern int tsm_ID;
+#endif
+
+extern void **lumpcache;
+
+extern int startepisode;
+extern int startmap;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+/* Sound info */
+sfxinfo_t S_sfx[] =
+{
+ /* tagname, lumpname, priority, usefulness, snd_ptr, lumpnum, numchannels, */
+ /* pitchshift */
+ { "", "", 0, -1, NULL, 0, 0, 0 },
+ { "PlayerFighterNormalDeath", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerFighterCrazyDeath", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerFighterExtreme1Death", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerFighterExtreme2Death", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerFighterExtreme3Death", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerFighterBurnDeath", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerClericNormalDeath", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerClericCrazyDeath", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerClericExtreme1Death", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerClericExtreme2Death", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerClericExtreme3Death", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerClericBurnDeath", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerMageNormalDeath", "", 256, -1, NULL, 0, 2, 0 },
+ { "PlayerMageCrazyDeath", "", 256, -1, NULL, 0, 2, 0 },
+ { "PlayerMageExtreme1Death", "", 256, -1, NULL, 0, 2, 0 },
+ { "PlayerMageExtreme2Death", "", 256, -1, NULL, 0, 2, 0 },
+ { "PlayerMageExtreme3Death", "", 256, -1, NULL, 0, 2, 0 },
+ { "PlayerMageBurnDeath", "", 256, -1, NULL, 0, 2, 0 },
+ { "PlayerFighterPain", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerClericPain", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerMagePain", "", 256, -1, NULL, 0, 2, 0 },
+ { "PlayerFighterGrunt", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerClericGrunt", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerMageGrunt", "", 256, -1, NULL, 0, 2, 0 },
+ { "PlayerLand", "", 32, -1, NULL, 0, 2, 1 },
+ { "PlayerPoisonCough", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerFighterFallingScream", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerClericFallingScream", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerMageFallingScream", "", 256, -1, NULL, 0, 2, 0 },
+ { "PlayerFallingSplat", "", 256, -1, NULL, 0, 2, 1 },
+ { "PlayerFighterFailedUse", "", 256, -1, NULL, 0, 1, 1 },
+ { "PlayerClericFailedUse", "", 256, -1, NULL, 0, 1, 1 },
+ { "PlayerMageFailedUse", "", 256, -1, NULL, 0, 1, 0 },
+ { "PlatformStart", "", 36, -1, NULL, 0, 2, 1 },
+ { "PlatformStartMetal", "", 36, -1, NULL, 0, 2, 1 },
+ { "PlatformStop", "", 40, -1, NULL, 0, 2, 1 },
+ { "StoneMove", "", 32, -1, NULL, 0, 2, 1 },
+ { "MetalMove", "", 32, -1, NULL, 0, 2, 1 },
+ { "DoorOpen", "", 36, -1, NULL, 0, 2, 1 },
+ { "DoorLocked", "", 36, -1, NULL, 0, 2, 1 },
+ { "DoorOpenMetal", "", 36, -1, NULL, 0, 2, 1 },
+ { "DoorCloseMetal", "", 36, -1, NULL, 0, 2, 1 },
+ { "DoorCloseLight", "", 36, -1, NULL, 0, 2, 1 },
+ { "DoorCloseHeavy", "", 36, -1, NULL, 0, 2, 1 },
+ { "DoorCreak", "", 36, -1, NULL, 0, 2, 1 },
+ { "PickupWeapon", "", 36, -1, NULL, 0, 2, 0 },
+ { "PickupArtifact", "", 36, -1, NULL, 0, 2, 1 },
+ { "PickupKey", "", 36, -1, NULL, 0, 2, 1 },
+ { "PickupItem", "", 36, -1, NULL, 0, 2, 1 },
+ { "PickupPiece", "", 36, -1, NULL, 0, 2, 0 },
+ { "WeaponBuild", "", 36, -1, NULL, 0, 2, 0 },
+ { "UseArtifact", "", 36, -1, NULL, 0, 2, 1 },
+ { "BlastRadius", "", 36, -1, NULL, 0, 2, 1 },
+ { "Teleport", "", 256, -1, NULL, 0, 2, 1 },
+ { "ThunderCrash", "", 30, -1, NULL, 0, 2, 1 },
+ { "FighterPunchMiss", "", 80, -1, NULL, 0, 2, 1 },
+ { "FighterPunchHitThing", "", 80, -1, NULL, 0, 2, 1 },
+ { "FighterPunchHitWall", "", 80, -1, NULL, 0, 2, 1 },
+ { "FighterGrunt", "", 80, -1, NULL, 0, 2, 1 },
+ { "FighterAxeHitThing", "", 80, -1, NULL, 0, 2, 1 },
+ { "FighterHammerMiss", "", 80, -1, NULL, 0, 2, 1 },
+ { "FighterHammerHitThing", "", 80, -1, NULL, 0, 2, 1 },
+ { "FighterHammerHitWall", "", 80, -1, NULL, 0, 2, 1 },
+ { "FighterHammerContinuous", "", 32, -1, NULL, 0, 2, 1 },
+ { "FighterHammerExplode", "", 80, -1, NULL, 0, 2, 1 },
+ { "FighterSwordFire", "", 80, -1, NULL, 0, 2, 1 },
+ { "FighterSwordExplode", "", 80, -1, NULL, 0, 2, 1 },
+ { "ClericCStaffFire", "", 80, -1, NULL, 0, 2, 1 },
+ { "ClericCStaffExplode", "", 40, -1, NULL, 0, 2, 1 },
+ { "ClericCStaffHitThing", "", 80, -1, NULL, 0, 2, 1 },
+ { "ClericFlameFire", "", 80, -1, NULL, 0, 2, 1 },
+ { "ClericFlameExplode", "", 80, -1, NULL, 0, 2, 1 },
+ { "ClericFlameCircle", "", 80, -1, NULL, 0, 2, 1 },
+ { "MageWandFire", "", 80, -1, NULL, 0, 2, 1 },
+ { "MageLightningFire", "", 80, -1, NULL, 0, 2, 1 },
+ { "MageLightningZap", "", 32, -1, NULL, 0, 2, 1 },
+ { "MageLightningContinuous", "", 32, -1, NULL, 0, 2, 1 },
+ { "MageLightningReady", "", 30, -1, NULL, 0, 2, 1 },
+ { "MageShardsFire","", 80, -1, NULL, 0, 2, 1 },
+ { "MageShardsExplode","", 36, -1, NULL, 0, 2, 1 },
+ { "MageStaffFire","", 80, -1, NULL, 0, 2, 1 },
+ { "MageStaffExplode","", 40, -1, NULL, 0, 2, 1 },
+ { "Switch1", "", 32, -1, NULL, 0, 2, 1 },
+ { "Switch2", "", 32, -1, NULL, 0, 2, 1 },
+ { "SerpentSight", "", 32, -1, NULL, 0, 2, 1 },
+ { "SerpentActive", "", 32, -1, NULL, 0, 2, 1 },
+ { "SerpentPain", "", 32, -1, NULL, 0, 2, 1 },
+ { "SerpentAttack", "", 32, -1, NULL, 0, 2, 1 },
+ { "SerpentMeleeHit", "", 32, -1, NULL, 0, 2, 1 },
+ { "SerpentDeath", "", 40, -1, NULL, 0, 2, 1 },
+ { "SerpentBirth", "", 32, -1, NULL, 0, 2, 1 },
+ { "SerpentFXContinuous", "", 32, -1, NULL, 0, 2, 1 },
+ { "SerpentFXHit", "", 32, -1, NULL, 0, 2, 1 },
+ { "PotteryExplode", "", 32, -1, NULL, 0, 2, 1 },
+ { "Drip", "", 32, -1, NULL, 0, 2, 1 },
+ { "CentaurSight", "", 32, -1, NULL, 0, 2, 1 },
+ { "CentaurActive", "", 32, -1, NULL, 0, 2, 1 },
+ { "CentaurPain", "", 32, -1, NULL, 0, 2, 1 },
+ { "CentaurAttack", "", 32, -1, NULL, 0, 2, 1 },
+ { "CentaurDeath", "", 40, -1, NULL, 0, 2, 1 },
+ { "CentaurLeaderAttack", "", 32, -1, NULL, 0, 2, 1 },
+ { "CentaurMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
+ { "Wind", "", 1, -1, NULL, 0, 2, 1 },
+ { "BishopSight", "", 32, -1, NULL, 0, 2, 1 },
+ { "BishopActive", "", 32, -1, NULL, 0, 2, 1 },
+ { "BishopPain", "", 32, -1, NULL, 0, 2, 1 },
+ { "BishopAttack", "", 32, -1, NULL, 0, 2, 1 },
+ { "BishopDeath", "", 40, -1, NULL, 0, 2, 1 },
+ { "BishopMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
+ { "BishopBlur", "", 32, -1, NULL, 0, 2, 1 },
+ { "DemonSight", "", 32, -1, NULL, 0, 2, 1 },
+ { "DemonActive", "", 32, -1, NULL, 0, 2, 1 },
+ { "DemonPain", "", 32, -1, NULL, 0, 2, 1 },
+ { "DemonAttack", "", 32, -1, NULL, 0, 2, 1 },
+ { "DemonMissileFire", "", 32, -1, NULL, 0, 2, 1 },
+ { "DemonMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
+ { "DemonDeath", "", 40, -1, NULL, 0, 2, 1 },
+ { "WraithSight", "", 32, -1, NULL, 0, 2, 1 },
+ { "WraithActive", "", 32, -1, NULL, 0, 2, 1 },
+ { "WraithPain", "", 32, -1, NULL, 0, 2, 1 },
+ { "WraithAttack", "", 32, -1, NULL, 0, 2, 1 },
+ { "WraithMissileFire", "", 32, -1, NULL, 0, 2, 1 },
+ { "WraithMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
+ { "WraithDeath", "", 40, -1, NULL, 0, 2, 1 },
+ { "PigActive1", "", 32, -1, NULL, 0, 2, 1 },
+ { "PigActive2", "", 32, -1, NULL, 0, 2, 1 },
+ { "PigPain", "", 32, -1, NULL, 0, 2, 1 },
+ { "PigAttack", "", 32, -1, NULL, 0, 2, 1 },
+ { "PigDeath", "", 40, -1, NULL, 0, 2, 1 },
+ { "MaulatorSight", "", 32, -1, NULL, 0, 2, 1 },
+ { "MaulatorActive", "", 32, -1, NULL, 0, 2, 1 },
+ { "MaulatorPain", "", 32, -1, NULL, 0, 2, 1 },
+ { "MaulatorHamSwing", "", 32, -1, NULL, 0, 2, 1 },
+ { "MaulatorHamHit", "", 32, -1, NULL, 0, 2, 1 },
+ { "MaulatorMissileHit", "", 32, -1, NULL, 0, 2, 1 },
+ { "MaulatorDeath", "", 40, -1, NULL, 0, 2, 1 },
+ { "FreezeDeath", "", 40, -1, NULL, 0, 2, 1 },
+ { "FreezeShatter", "", 40, -1, NULL, 0, 2, 1 },
+ { "EttinSight", "", 32, -1, NULL, 0, 2, 1 },
+ { "EttinActive", "", 32, -1, NULL, 0, 2, 1 },
+ { "EttinPain", "", 32, -1, NULL, 0, 2, 1 },
+ { "EttinAttack", "", 32, -1, NULL, 0, 2, 1 },
+ { "EttinDeath", "", 40, -1, NULL, 0, 2, 1 },
+ { "FireDemonSpawn", "", 32, -1, NULL, 0, 2, 1 },
+ { "FireDemonActive", "", 32, -1, NULL, 0, 2, 1 },
+ { "FireDemonPain", "", 32, -1, NULL, 0, 2, 1 },
+ { "FireDemonAttack", "", 32, -1, NULL, 0, 2, 1 },
+ { "FireDemonMissileHit", "", 32, -1, NULL, 0, 2, 1 },
+ { "FireDemonDeath", "", 40, -1, NULL, 0, 2, 1 },
+ { "IceGuySight", "", 32, -1, NULL, 0, 2, 1 },
+ { "IceGuyActive", "", 32, -1, NULL, 0, 2, 1 },
+ { "IceGuyAttack", "", 32, -1, NULL, 0, 2, 1 },
+ { "IceGuyMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
+ { "SorcererSight", "", 256, -1, NULL, 0, 2, 1 },
+ { "SorcererActive", "", 256, -1, NULL, 0, 2, 1 },
+ { "SorcererPain", "", 256, -1, NULL, 0, 2, 1 },
+ { "SorcererSpellCast", "", 256, -1, NULL, 0, 2, 1 },
+ { "SorcererBallWoosh", "", 256, -1, NULL, 0, 4, 1 },
+ { "SorcererDeathScream", "", 256, -1, NULL, 0, 2, 1 },
+ { "SorcererBishopSpawn", "", 80, -1, NULL, 0, 2, 1 },
+ { "SorcererBallPop", "", 80, -1, NULL, 0, 2, 1 },
+ { "SorcererBallBounce", "", 80, -1, NULL, 0, 3, 1 },
+ { "SorcererBallExplode", "", 80, -1, NULL, 0, 3, 1 },
+ { "SorcererBigBallExplode", "", 80, -1, NULL, 0, 3, 1 },
+ { "SorcererHeadScream", "", 256, -1, NULL, 0, 2, 1 },
+ { "DragonSight", "", 64, -1, NULL, 0, 2, 1 },
+ { "DragonActive", "", 64, -1, NULL, 0, 2, 1 },
+ { "DragonWingflap", "", 64, -1, NULL, 0, 2, 1 },
+ { "DragonAttack", "", 64, -1, NULL, 0, 2, 1 },
+ { "DragonPain", "", 64, -1, NULL, 0, 2, 1 },
+ { "DragonDeath", "", 64, -1, NULL, 0, 2, 1 },
+ { "DragonFireballExplode", "", 32, -1, NULL, 0, 2, 1 },
+ { "KoraxSight", "", 256, -1, NULL, 0, 2, 1 },
+ { "KoraxActive", "", 256, -1, NULL, 0, 2, 1 },
+ { "KoraxPain", "", 256, -1, NULL, 0, 2, 1 },
+ { "KoraxAttack", "", 256, -1, NULL, 0, 2, 1 },
+ { "KoraxCommand", "", 256, -1, NULL, 0, 2, 1 },
+ { "KoraxDeath", "", 256, -1, NULL, 0, 2, 1 },
+ { "KoraxStep", "", 128, -1, NULL, 0, 2, 1 },
+ { "ThrustSpikeRaise", "", 32, -1, NULL, 0, 2, 1 },
+ { "ThrustSpikeLower", "", 32, -1, NULL, 0, 2, 1 },
+ { "GlassShatter", "", 32, -1, NULL, 0, 2, 1 },
+ { "FlechetteBounce", "", 32, -1, NULL, 0, 2, 1 },
+ { "FlechetteExplode", "", 32, -1, NULL, 0, 2, 1 },
+ { "LavaMove", "", 36, -1, NULL, 0, 2, 1 },
+ { "WaterMove", "", 36, -1, NULL, 0, 2, 1 },
+ { "IceStartMove", "", 36, -1, NULL, 0, 2, 1 },
+ { "EarthStartMove", "", 36, -1, NULL, 0, 2, 1 },
+ { "WaterSplash", "", 32, -1, NULL, 0, 2, 1 },
+ { "LavaSizzle", "", 32, -1, NULL, 0, 2, 1 },
+ { "SludgeGloop", "", 32, -1, NULL, 0, 2, 1 },
+ { "HolySymbolFire", "", 64, -1, NULL, 0, 2, 1 },
+ { "SpiritActive", "", 32, -1, NULL, 0, 2, 1 },
+ { "SpiritAttack", "", 32, -1, NULL, 0, 2, 1 },
+ { "SpiritDie", "", 32, -1, NULL, 0, 2, 1 },
+ { "ValveTurn", "", 36, -1, NULL, 0, 2, 1 },
+ { "RopePull", "", 36, -1, NULL, 0, 2, 1 },
+ { "FlyBuzz", "", 20, -1, NULL, 0, 2, 1 },
+ { "Ignite", "", 32, -1, NULL, 0, 2, 1 },
+ { "PuzzleSuccess", "", 256, -1, NULL, 0, 2, 1 },
+ { "PuzzleFailFighter", "", 256, -1, NULL, 0, 2, 1 },
+ { "PuzzleFailCleric", "", 256, -1, NULL, 0, 2, 1 },
+ { "PuzzleFailMage", "", 256, -1, NULL, 0, 2, 1 },
+ { "Earthquake", "", 32, -1, NULL, 0, 2, 1 },
+ { "BellRing", "", 32, -1, NULL, 0, 2, 0 },
+ { "TreeBreak", "", 32, -1, NULL, 0, 2, 1 },
+ { "TreeExplode", "", 32, -1, NULL, 0, 2, 1 },
+ { "SuitofArmorBreak", "", 32, -1, NULL, 0, 2, 1 },
+ { "PoisonShroomPain", "", 20, -1, NULL, 0, 2, 1 },
+ { "PoisonShroomDeath", "", 32, -1, NULL, 0, 2, 1 },
+ { "Ambient1", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient2", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient3", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient4", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient5", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient6", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient7", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient8", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient9", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient10", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient11", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient12", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient13", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient14", "", 1, -1, NULL, 0, 1, 1 },
+ { "Ambient15", "", 1, -1, NULL, 0, 1, 1 },
+ { "StartupTick", "", 32, -1, NULL, 0, 2, 1 },
+ { "SwitchOtherLevel", "", 32, -1, NULL, 0, 2, 1 },
+ { "Respawn", "", 32, -1, NULL, 0, 2, 1 },
+ { "KoraxVoiceGreetings", "", 512, -1, NULL, 0, 2, 1 },
+ { "KoraxVoiceReady", "", 512, -1, NULL, 0, 2, 1 },
+ { "KoraxVoiceBlood", "", 512, -1, NULL, 0, 2, 1 },
+ { "KoraxVoiceGame", "", 512, -1, NULL, 0, 2, 1 },
+ { "KoraxVoiceBoard", "", 512, -1, NULL, 0, 2, 1 },
+ { "KoraxVoiceWorship", "", 512, -1, NULL, 0, 2, 1 },
+ { "KoraxVoiceMaybe", "", 512, -1, NULL, 0, 2, 1 },
+ { "KoraxVoiceStrong", "", 512, -1, NULL, 0, 2, 1 },
+ { "KoraxVoiceFace", "", 512, -1, NULL, 0, 2, 1 },
+ { "BatScream", "", 32, -1, NULL, 0, 2, 1 },
+ { "Chat", "", 512, -1, NULL, 0, 2, 1 },
+ { "MenuMove", "", 32, -1, NULL, 0, 2, 1 },
+ { "ClockTick", "", 32, -1, NULL, 0, 2, 1 },
+ { "Fireball", "", 32, -1, NULL, 0, 2, 1 },
+ { "PuppyBeat", "", 30, -1, NULL, 0, 2, 1 },
+ { "MysticIncant", "", 32, -1, NULL, 0, 4, 1 }
+};
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static channel_t Channel[MAX_CHANNELS];
+static int RegisteredSong; /* the current registered song. */
+static int isExternalSong;
+static int NextCleanup;
+static boolean MusicPaused;
+static int Mus_Song = -1;
+static int Mus_LumpNum;
+static void *Mus_SndPtr;
+static byte *SoundCurve;
+
+static boolean UseSndScript;
+static char ArchivePath[MAX_OSPATH];
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// S_Init
+//
+//==========================================================================
+
+void S_Init(void)
+{
+ SoundCurve = (byte *) W_CacheLumpName("SNDCURVE", PU_STATIC);
+// SoundCurve = (byte *) Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
+ I_StartupSound();
+ if (snd_Channels > 8)
+ {
+ snd_Channels = 8;
+ }
+ I_SetChannels(snd_Channels);
+ I_SetMusicVolume(snd_MusicVolume);
+
+ // Attempt to setup CD music
+ ST_Message("Initializing CD Audio: ");
+ i_CDMusic = (I_CDMusInit() != -1);
+ if (i_CDMusic)
+ {
+ ST_Message("success.\n");
+ }
+ else
+ {
+ ST_Message("failed.\n");
+ }
+}
+
+//==========================================================================
+//
+// S_InitScript
+//
+//==========================================================================
+
+void S_InitScript(void)
+{
+ int p;
+ int i;
+
+ strcpy(ArchivePath, DEFAULT_ARCHIVEPATH);
+ p = M_CheckParm("-devsnd");
+ if (p && p < myargc - 1)
+ {
+ UseSndScript = true;
+ SC_OpenFile(myargv[p+1]);
+ }
+ else
+ {
+ UseSndScript = false;
+ SC_OpenLump("sndinfo");
+ }
+ while (SC_GetString())
+ {
+ if (*sc_String == '$')
+ {
+ if (!strcasecmp(sc_String, "$ARCHIVEPATH"))
+ {
+ SC_MustGetString();
+ strcpy(ArchivePath, sc_String);
+ }
+ else if (!strcasecmp(sc_String, "$MAP"))
+ {
+ SC_MustGetNumber();
+ SC_MustGetString();
+ if (sc_Number)
+ {
+ P_PutMapSongLump(sc_Number, sc_String);
+ }
+ }
+ continue;
+ }
+ else
+ {
+ for (i = 0; i < NUMSFX; i++)
+ {
+ if (!strcmp(S_sfx[i].tagName, sc_String))
+ {
+ SC_MustGetString();
+ if (*sc_String != '?')
+ {
+ strcpy(S_sfx[i].lumpname, sc_String);
+ }
+ else
+ {
+ strcpy(S_sfx[i].lumpname, "default");
+ }
+ break;
+ }
+ }
+ if (i == NUMSFX)
+ {
+ SC_MustGetString();
+ }
+ }
+ }
+ SC_Close();
+
+ for (i = 0; i < NUMSFX; i++)
+ {
+ if (!strcmp(S_sfx[i].lumpname, ""))
+ {
+ strcpy(S_sfx[i].lumpname, "default");
+ }
+ }
+}
+
+//==========================================================================
+//
+// S_ShutDown
+//
+//==========================================================================
+
+void S_ShutDown(void)
+{
+ if (i_CDMusic)
+ {
+ I_CDMusStop();
+ }
+ I_CDMusShutdown();
+#ifdef __WATCOMC__
+ if (tsm_ID == -1)
+ return;
+#endif
+ if (RegisteredSong)
+ {
+ I_StopSong(RegisteredSong);
+ I_UnRegisterSong(RegisteredSong);
+ }
+ I_ShutdownSound();
+}
+
+//==========================================================================
+//
+// S_Start
+//
+//==========================================================================
+
+void S_Start(void)
+{
+ S_StopAllSound();
+ S_StartSong(gamemap, true);
+}
+
+//==========================================================================
+//
+// S_StartSong
+//
+//==========================================================================
+
+void S_StartSong(int song, boolean loop)
+{
+ const char *songLump;
+ int track;
+
+ if (i_CDMusic && cdaudio)
+ { // Play a CD track, instead
+ if (i_CDTrack)
+ { // Default to the player-chosen track
+ track = i_CDTrack;
+ }
+ else
+ {
+ track = P_GetMapCDTrack(gamemap);
+ }
+ if (track == i_CDCurrentTrack && i_CDMusicLength > 0)
+ {
+ return;
+ }
+ if (!I_CDMusPlay(track))
+ {
+ /*
+ if (loop)
+ {
+ // i_CDMusicLength = 35*I_CDMusTrackLength(track);
+ oldTic = gametic;
+ }
+ else
+ {
+ i_CDMusicLength = -1;
+ }
+ */
+ i_CDCurrentTrack = track;
+ }
+ }
+ else
+ {
+ if (song == Mus_Song)
+ { // don't replay an old song
+ return;
+ }
+ if (RegisteredSong)
+ {
+ I_StopSong(RegisteredSong);
+ I_UnRegisterSong(RegisteredSong);
+ if (!isExternalSong)
+ {
+ if (UseSndScript)
+ {
+ Z_Free(Mus_SndPtr);
+ }
+ else
+ {
+ Z_ChangeTag(lumpcache[Mus_LumpNum], PU_CACHE);
+ }
+#ifdef __WATCOMC__
+ _dpmi_unlockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
+#endif
+ }
+ RegisteredSong = 0;
+ }
+ songLump = P_GetMapSongLump(song);
+ if (!songLump)
+ {
+ return;
+ }
+ isExternalSong = I_RegisterExternalSong(songLump);
+ if (isExternalSong)
+ {
+ RegisteredSong = isExternalSong;
+ I_PlaySong(RegisteredSong, loop);
+ Mus_Song = song;
+ return;
+ }
+ if (UseSndScript)
+ {
+ char name[MAX_OSPATH];
+ snprintf(name, sizeof(name), "%s%s.lmp", ArchivePath, songLump);
+ M_ReadFile(name, &Mus_SndPtr);
+ }
+ else
+ {
+ Mus_LumpNum = W_GetNumForName(songLump);
+ Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
+ }
+#ifdef __WATCOMC__
+ _dpmi_lockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
+#endif
+ RegisteredSong = I_RegisterSong(Mus_SndPtr);
+ I_PlaySong(RegisteredSong, loop); // 'true' denotes endless looping.
+ Mus_Song = song;
+ }
+}
+
+//==========================================================================
+//
+// S_StartSongName
+//
+//==========================================================================
+
+void S_StartSongName(const char *songLump, boolean loop)
+{
+ int cdTrack;
+
+ if (!songLump)
+ {
+ return;
+ }
+ if (i_CDMusic && cdaudio)
+ {
+ cdTrack = 0;
+
+ if (!strcmp(songLump, "hexen"))
+ {
+ cdTrack = P_GetCDTitleTrack();
+ }
+ else if (!strcmp(songLump, "hub"))
+ {
+ cdTrack = P_GetCDIntermissionTrack();
+ }
+ else if (!strcmp(songLump, "hall"))
+ {
+ cdTrack = P_GetCDEnd1Track();
+ }
+ else if (!strcmp(songLump, "orb"))
+ {
+ cdTrack = P_GetCDEnd2Track();
+ }
+ else if (!strcmp(songLump, "chess") && !i_CDTrack)
+ {
+ cdTrack = P_GetCDEnd3Track();
+ }
+/* Uncomment this, if Kevin writes a specific song for startup
+ else if (!strcmp(songLump, "start"))
+ {
+ cdTrack = P_GetCDStartTrack();
+ }
+*/
+ if (!cdTrack || (cdTrack == i_CDCurrentTrack && i_CDMusicLength > 0))
+ {
+ return;
+ }
+ if (!I_CDMusPlay(cdTrack))
+ {
+ /*
+ if (loop)
+ {
+ i_CDMusicLength = 35*I_CDMusTrackLength(cdTrack);
+ oldTic = gametic;
+ }
+ else
+ {
+ i_CDMusicLength = -1;
+ }
+ */
+ i_CDCurrentTrack = cdTrack;
+ i_CDTrack = false;
+ }
+ }
+ else
+ {
+ if (RegisteredSong)
+ {
+ I_StopSong(RegisteredSong);
+ I_UnRegisterSong(RegisteredSong);
+ if (!isExternalSong)
+ {
+ if (UseSndScript)
+ {
+ Z_Free(Mus_SndPtr);
+ }
+ else
+ {
+ Z_ChangeTag(lumpcache[Mus_LumpNum], PU_CACHE);
+ }
+ }
+#ifdef __WATCOMC__
+ _dpmi_unlockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
+#endif
+ RegisteredSong = 0;
+ }
+ isExternalSong = I_RegisterExternalSong(songLump);
+ if (isExternalSong)
+ {
+ RegisteredSong = isExternalSong;
+ I_PlaySong(RegisteredSong, loop);
+ Mus_Song = -1;
+ return;
+ }
+ if (UseSndScript)
+ {
+ char name[MAX_OSPATH];
+ snprintf(name, sizeof(name), "%s%s.lmp", ArchivePath, songLump);
+ M_ReadFile(name, &Mus_SndPtr);
+ }
+ else
+ {
+ Mus_LumpNum = W_GetNumForName(songLump);
+ Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
+ }
+#ifdef __WATCOMC__
+ _dpmi_lockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
+#endif
+ RegisteredSong = I_RegisterSong(Mus_SndPtr);
+ I_PlaySong(RegisteredSong, loop); // 'true' denotes endless looping.
+ Mus_Song = -1;
+ }
+}
+
+//==========================================================================
+//
+// S_GetSoundID
+//
+//==========================================================================
+
+int S_GetSoundID(const char *name)
+{
+ int i;
+
+ for (i = 0; i < NUMSFX; i++)
+ {
+ if (!strcmp(S_sfx[i].tagName, name))
+ {
+ return i;
+ }
+ }
+ return 0;
+}
+
+//==========================================================================
+//
+// S_StartSound
+//
+//==========================================================================
+
+void S_StartSound(mobj_t *origin, int sound_id)
+{
+ S_StartSoundAtVolume(origin, sound_id, 127);
+}
+
+//==========================================================================
+//
+// S_StartSoundAtVolume
+//
+//==========================================================================
+
+void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume)
+{
+ static int sndcount = 0;
+
+ int i;
+ int dist, vol, chan;
+ int priority;
+ int angle, sep;
+ int absx, absy;
+
+ if (sound_id == 0 || snd_MaxVolume == 0)
+ return;
+#if 0
+ if (origin == NULL)
+ {
+ origin = players[displayplayer].mo;
+ // this can be uninitialized when we are newly
+ // started before the demos start playing !...
+ }
+#endif
+ if (volume == 0)
+ {
+ return;
+ }
+
+ // calculate the distance before other stuff so that we can throw out
+ // sounds that are beyond the hearing range.
+ if (origin)
+ {
+ absx = abs(origin->x - players[displayplayer].mo->x);
+ absy = abs(origin->y - players[displayplayer].mo->y);
+ }
+ else
+ {
+ absx = absy = 0;
+ }
+ dist = absx + absy - (absx > absy ? absy>>1 : absx>>1);
+ dist >>= FRACBITS;
+ if (dist >= MAX_SND_DIST)
+ {
+ return; // sound is beyond the hearing range...
+ }
+ if (dist < 0)
+ {
+ dist = 0;
+ }
+ priority = S_sfx[sound_id].priority;
+ priority *= (PRIORITY_MAX_ADJUST - (dist / DIST_ADJUST));
+ if (!S_StopSoundID(sound_id, priority))
+ {
+ return; // other sounds have greater priority
+ }
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (!origin || origin->player)
+ {
+ i = snd_Channels;
+ break; // let the player have more than one sound.
+ }
+ if (origin == Channel[i].mo)
+ { // only allow other mobjs one sound
+ S_StopSound(Channel[i].mo);
+ break;
+ }
+ }
+ if (i >= snd_Channels)
+ {
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].mo == NULL)
+ {
+ break;
+ }
+ }
+ if (i >= snd_Channels)
+ {
+ // look for a lower priority sound to replace.
+ sndcount++;
+ if (sndcount >= snd_Channels)
+ {
+ sndcount = 0;
+ }
+ for (chan = 0; chan < snd_Channels; chan++)
+ {
+ i = (sndcount + chan) % snd_Channels;
+ if (priority >= Channel[i].priority)
+ {
+ chan = -1; // denote that sound should be replaced.
+ break;
+ }
+ }
+ if (chan != -1)
+ {
+ return; // no free channels.
+ }
+ else // replace the lower priority sound.
+ {
+ if (Channel[i].handle)
+ {
+ if (I_SoundIsPlaying(Channel[i].handle))
+ {
+ I_StopSound(Channel[i].handle);
+ }
+ if (S_sfx[Channel[i].sound_id].usefulness > 0)
+ {
+ S_sfx[Channel[i].sound_id].usefulness--;
+ }
+ }
+ }
+ }
+ }
+ if (S_sfx[sound_id].lumpnum == 0)
+ {
+ S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
+ }
+ if (S_sfx[sound_id].snd_ptr == NULL)
+ {
+ if (UseSndScript)
+ {
+ char name[MAX_OSPATH];
+ int len;
+ snprintf(name, sizeof(name), "%s%s.lmp",
+ ArchivePath, S_sfx[sound_id].lumpname);
+ len = M_ReadFile(name, &S_sfx[sound_id].snd_ptr);
+ if (len <= 8)
+ {
+ I_Error("broken sound lump #%d (%s)\n",
+ S_sfx[sound_id].lumpnum, name);
+ }
+ }
+ else
+ {
+ if (W_LumpLength(S_sfx[sound_id].lumpnum) <= 8)
+ {
+ // I_Error("broken sound lump #%d (%s)\n",
+ fprintf(stderr, "broken sound lump #%d (%s)\n",
+ S_sfx[sound_id].lumpnum,
+ S_sfx[sound_id].lumpname);
+ return;
+ }
+ S_sfx[sound_id].snd_ptr =
+ W_CacheLumpNum(S_sfx[sound_id].lumpnum, PU_SOUND);
+ }
+#ifdef __WATCOMC__
+ _dpmi_lockregion(S_sfx[sound_id].snd_ptr,
+ lumpinfo[S_sfx[sound_id].lumpnum].size);
+#endif
+ }
+
+ vol = (SoundCurve[dist] * (snd_MaxVolume * 8) * volume)>>14;
+ if (!origin || origin == players[displayplayer].mo)
+ {
+ sep = 128;
+ // vol = (volume*(snd_MaxVolume+1)*8)>>7;
+ }
+ else
+ {
+ angle = R_PointToAngle2(players[displayplayer].mo->x,
+ players[displayplayer].mo->y,
+ origin->x, origin->y);
+ angle = (angle - viewangle)>>24;
+ sep = angle*2 - 128;
+ if (sep < 64)
+ sep = -sep;
+ if (sep > 192)
+ sep = 512-sep;
+ // vol = SoundCurve[dist];
+ }
+
+ if (S_sfx[sound_id].changePitch)
+ {
+ Channel[i].pitch = (byte)(127 + (M_Random() & 7) - (M_Random() & 7));
+ }
+ else
+ {
+ Channel[i].pitch = 127;
+ }
+ Channel[i].handle = I_StartSound(sound_id, S_sfx[sound_id].snd_ptr, vol,
+ sep, Channel[i].pitch, 0);
+ Channel[i].mo = origin;
+ Channel[i].sound_id = sound_id;
+ Channel[i].priority = priority;
+ Channel[i].volume = volume;
+ if (S_sfx[sound_id].usefulness < 0)
+ {
+ S_sfx[sound_id].usefulness = 1;
+ }
+ else
+ {
+ S_sfx[sound_id].usefulness++;
+ }
+}
+
+//==========================================================================
+//
+// S_StopSoundID
+//
+//==========================================================================
+
+static boolean S_StopSoundID(int sound_id, int priority)
+{
+ int i;
+ int lp; //least priority
+ int found;
+
+ if (S_sfx[sound_id].numchannels == -1)
+ {
+ return true;
+ }
+ lp = -1; //denote the argument sound_id
+ found = 0;
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].sound_id == sound_id && Channel[i].mo)
+ {
+ found++; //found one. Now, should we replace it??
+ if (priority >= Channel[i].priority)
+ { // if we're gonna kill one, then this'll be it
+ lp = i;
+ priority = Channel[i].priority;
+ }
+ }
+ }
+ if (found < S_sfx[sound_id].numchannels)
+ {
+ return true;
+ }
+ else if (lp == -1)
+ {
+ return false; // don't replace any sounds
+ }
+ if (Channel[lp].handle)
+ {
+ if (I_SoundIsPlaying(Channel[lp].handle))
+ {
+ I_StopSound(Channel[lp].handle);
+ }
+ if (S_sfx[Channel[lp].sound_id].usefulness > 0)
+ {
+ S_sfx[Channel[lp].sound_id].usefulness--;
+ }
+ Channel[lp].mo = NULL;
+ }
+ return true;
+}
+
+//==========================================================================
+//
+// S_StopSound
+//
+//==========================================================================
+
+void S_StopSound(mobj_t *origin)
+{
+ int i;
+
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].mo == origin)
+ {
+ I_StopSound(Channel[i].handle);
+ if (S_sfx[Channel[i].sound_id].usefulness > 0)
+ {
+ S_sfx[Channel[i].sound_id].usefulness--;
+ }
+ Channel[i].handle = 0;
+ Channel[i].mo = NULL;
+ }
+ }
+}
+
+//==========================================================================
+//
+// S_StopAllSound
+//
+//==========================================================================
+
+void S_StopAllSound(void)
+{
+ int i;
+
+ //stop all sounds
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].handle)
+ {
+ S_StopSound(Channel[i].mo);
+ }
+ }
+ memset(Channel, 0, 8*sizeof(channel_t));
+}
+
+//==========================================================================
+//
+// S_SoundLink
+//
+//==========================================================================
+
+void S_SoundLink(mobj_t *oldactor, mobj_t *newactor)
+{
+ int i;
+
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].mo == oldactor)
+ Channel[i].mo = newactor;
+ }
+}
+
+//==========================================================================
+//
+// S_PauseSound
+//
+//==========================================================================
+
+void S_PauseSound(void)
+{
+ I_CDMusStop();
+ I_PauseSong(RegisteredSong);
+}
+
+//==========================================================================
+//
+// S_ResumeSound
+//
+//==========================================================================
+
+void S_ResumeSound(void)
+{
+ if (i_CDMusic && cdaudio)
+ {
+ I_CDMusResume();
+ }
+ else
+ {
+ I_ResumeSong(RegisteredSong);
+ }
+}
+
+//==========================================================================
+//
+// S_UpdateSounds
+//
+//==========================================================================
+
+void S_UpdateSounds(mobj_t *listener)
+{
+ int i, dist, vol;
+ int angle, sep;
+ int priority;
+ int absx, absy;
+
+ if (i_CDMusic)
+ {
+ I_CDMusUpdate();
+ }
+ if (snd_MaxVolume == 0)
+ {
+ return;
+ }
+
+ // Update any Sequences
+ SN_UpdateActiveSequences();
+
+ if (NextCleanup < gametic)
+ {
+ if (UseSndScript)
+ {
+ for (i = 0; i < NUMSFX; i++)
+ {
+ if (S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
+ {
+ S_sfx[i].usefulness = -1;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < NUMSFX; i++)
+ {
+ if (S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
+ {
+ if (lumpcache[S_sfx[i].lumpnum])
+ {
+ if (((memblock_t *) ((byte*)(lumpcache[S_sfx[i].lumpnum]) -
+ sizeof(memblock_t)))->id == ZONEID)
+ { // taken directly from the Z_ChangeTag macro
+ Z_ChangeTag2(lumpcache[S_sfx[i].lumpnum], PU_CACHE);
+#ifdef __WATCOMC__
+ _dpmi_unlockregion(S_sfx[i].snd_ptr,
+ lumpinfo[S_sfx[i].lumpnum].size);
+#endif
+ }
+ }
+ S_sfx[i].usefulness = -1;
+ S_sfx[i].snd_ptr = NULL;
+ }
+ }
+ }
+ NextCleanup = gametic + 35*30; // every 30 seconds
+ }
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (!Channel[i].handle || S_sfx[Channel[i].sound_id].usefulness == -1)
+ {
+ continue;
+ }
+ if (!I_SoundIsPlaying(Channel[i].handle))
+ {
+ if (S_sfx[Channel[i].sound_id].usefulness > 0)
+ {
+ S_sfx[Channel[i].sound_id].usefulness--;
+ }
+ Channel[i].handle = 0;
+ Channel[i].mo = NULL;
+ Channel[i].sound_id = 0;
+ }
+ if (Channel[i].mo == NULL || Channel[i].sound_id == 0
+ || Channel[i].mo == listener)
+ {
+ continue;
+ }
+ else
+ {
+ absx = abs(Channel[i].mo->x - listener->x);
+ absy = abs(Channel[i].mo->y - listener->y);
+ dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
+ dist >>= FRACBITS;
+
+ if (dist >= MAX_SND_DIST)
+ {
+ S_StopSound(Channel[i].mo);
+ continue;
+ }
+ if (dist < 0)
+ {
+ dist = 0;
+ }
+ //vol = SoundCurve[dist];
+ vol = (SoundCurve[dist] * (snd_MaxVolume * 8) * Channel[i].volume)>>14;
+ if (Channel[i].mo == listener)
+ {
+ sep = 128;
+ }
+ else
+ {
+ angle = R_PointToAngle2(listener->x, listener->y,
+ Channel[i].mo->x, Channel[i].mo->y);
+ angle = (angle-viewangle)>>24;
+ sep = angle*2-128;
+ if (sep < 64)
+ sep = -sep;
+ if (sep > 192)
+ sep = 512-sep;
+ }
+ I_UpdateSoundParams(Channel[i].handle, vol, sep, Channel[i].pitch);
+ priority = S_sfx[Channel[i].sound_id].priority;
+ priority *= PRIORITY_MAX_ADJUST - (dist / DIST_ADJUST);
+ Channel[i].priority = priority;
+ }
+ }
+}
+
+//==========================================================================
+//
+// S_GetChannelInfo
+//
+//==========================================================================
+
+void S_GetChannelInfo(SoundInfo_t *s)
+{
+ int i;
+ ChanInfo_t *c;
+
+ s->channelCount = snd_Channels;
+ s->musicVolume = snd_MusicVolume;
+ s->soundVolume = snd_MaxVolume;
+ for (i = 0; i < snd_Channels; i++)
+ {
+ c = &s->chan[i];
+ c->id = Channel[i].sound_id;
+ c->priority = Channel[i].priority;
+ c->name = S_sfx[c->id].lumpname;
+ c->mo = Channel[i].mo;
+ c->distance = P_AproxDistance(c->mo->x-viewx, c->mo->y-viewy)>>FRACBITS;
+ }
+}
+
+//==========================================================================
+//
+// S_GetSoundPlayingInfo
+//
+//==========================================================================
+
+boolean S_GetSoundPlayingInfo(mobj_t *mobj, int sound_id)
+{
+ int i;
+
+ for (i = 0; i < snd_Channels; i++)
+ {
+ if (Channel[i].sound_id == sound_id && Channel[i].mo == mobj)
+ {
+ if (I_SoundIsPlaying(Channel[i].handle))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//==========================================================================
+//
+// S_SetMusicVolume
+//
+//==========================================================================
+
+void S_SetMusicVolume(void)
+{
+ if (i_CDMusic)
+ I_CDMusSetVolume(snd_MusicVolume*16); // 0-255
+ I_SetMusicVolume(snd_MusicVolume);
+ if (snd_MusicVolume == 0)
+ {
+ I_PauseSong(RegisteredSong);
+ MusicPaused = true;
+ }
+ else if (MusicPaused)
+ {
+ if (!i_CDMusic || !cdaudio)
+ {
+ I_ResumeSong(RegisteredSong);
+ }
+ MusicPaused = false;
+ }
+}
+
--- /dev/null
+++ b/sb_bar.c
@@ -1,0 +1,2242 @@
+
+//**************************************************************************
+//**
+//** sb_bar.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 575 $
+//** $Date: 2011-04-13 22:06:28 +0300 (Wed, 13 Apr 2011) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.h"
+#include "i_cdmus.h" /* for CD track cheat */
+
+#define PLAYPAL_NUM PlayPalette
+#include "v_compat.h"
+
+// MACROS ------------------------------------------------------------------
+
+#if defined(RENDER3D)
+#define V_DrawPatch(x,y,p) OGL_DrawPatch((x),(y),(p))
+#define V_DrawFuzzPatch(x,y,p) OGL_DrawFuzzPatch((x),(y),(p))
+#define V_DrawAltFuzzPatch(x,y,p) OGL_DrawAltFuzzPatch((x),(y),(p))
+#endif /* RENDER3D */
+
+#define CHEAT_ENCRYPT(a) \
+ ((((a) & 1 ) << 2) + \
+ (((a) & 2 ) >> 1) + \
+ (((a) & 4 ) << 5) + \
+ (((a) & 8 ) << 2) + \
+ (((a) & 16 ) >> 3) + \
+ (((a) & 32 ) << 1) + \
+ (((a) & 64 ) >> 3) + \
+ (((a) & 128) >> 3))
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct Cheat_s
+{
+ void (*func)(player_t *player, struct Cheat_s *cheat);
+ byte *sequence;
+ byte *pos;
+ int args[2];
+ int currentArg;
+} Cheat_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+extern boolean P_UndoPlayerMorph(player_t *player);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+void SB_PaletteFlash(boolean forceChange);
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void DrawSoundInfo(void);
+static void DrINumber(signed int val, int x, int y);
+static void DrRedINumber(signed int val, int x, int y);
+static void DrBNumber(signed int val, int x, int y);
+static void DrawCommonBar(void);
+static void DrawMainBar(void);
+static void DrawInventoryBar(void);
+static void DrawKeyBar(void);
+static void DrawWeaponPieces(void);
+static void DrawFullScreenStuff(void);
+static void DrawAnimatedIcons(void);
+static boolean HandleCheats(byte key);
+static boolean CheatAddKey(Cheat_t *cheat, byte key, boolean *eat);
+static void CheatGodFunc(player_t *player, Cheat_t *cheat);
+static void CheatNoClipFunc(player_t *player, Cheat_t *cheat);
+static void CheatWeaponsFunc(player_t *player, Cheat_t *cheat);
+static void CheatHealthFunc(player_t *player, Cheat_t *cheat);
+static void CheatKeysFunc(player_t *player, Cheat_t *cheat);
+static void CheatSoundFunc(player_t *player, Cheat_t *cheat);
+static void CheatTickerFunc(player_t *player, Cheat_t *cheat);
+static void CheatArtifactAllFunc(player_t *player, Cheat_t *cheat);
+static void CheatPuzzleFunc(player_t *player, Cheat_t *cheat);
+static void CheatWarpFunc(player_t *player, Cheat_t *cheat);
+static void CheatPigFunc(player_t *player, Cheat_t *cheat);
+static void CheatMassacreFunc(player_t *player, Cheat_t *cheat);
+static void CheatIDKFAFunc(player_t *player, Cheat_t *cheat);
+static void CheatQuickenFunc1(player_t *player, Cheat_t *cheat);
+static void CheatQuickenFunc2(player_t *player, Cheat_t *cheat);
+static void CheatQuickenFunc3(player_t *player, Cheat_t *cheat);
+static void CheatClassFunc1(player_t *player, Cheat_t *cheat);
+static void CheatClassFunc2(player_t *player, Cheat_t *cheat);
+static void CheatInitFunc(player_t *player, Cheat_t *cheat);
+static void CheatInitFunc(player_t *player, Cheat_t *cheat);
+static void CheatVersionFunc(player_t *player, Cheat_t *cheat);
+static void CheatDebugFunc(player_t *player, Cheat_t *cheat);
+static void CheatScriptFunc1(player_t *player, Cheat_t *cheat);
+static void CheatScriptFunc2(player_t *player, Cheat_t *cheat);
+static void CheatScriptFunc3(player_t *player, Cheat_t *cheat);
+static void CheatRevealFunc(player_t *player, Cheat_t *cheat);
+static void CheatTrackFunc1(player_t *player, Cheat_t *cheat);
+static void CheatTrackFunc2(player_t *player, Cheat_t *cheat);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern byte *screen;
+extern int ArmorIncrement[NUMCLASSES][NUMARMOR];
+extern int AutoArmorSave[NUMCLASSES];
+
+// PUBLIC DATA DECLARATIONS ------------------------------------------------
+
+boolean DebugSound; /* Debug flag for displaying sound info */
+boolean inventory;
+int curpos;
+int inv_ptr;
+int ArtifactFlash;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static byte CheatLookup[256];
+static int HealthMarker;
+static player_t *CPlayer;
+static int SpinFlylump;
+static int SpinMinotaurLump;
+static int SpinSpeedLump;
+static int SpinDefenseLump;
+
+static int FontBNumBase;
+static int PlayPalette;
+
+static PATCH_REF PatchH2BAR;
+static PATCH_REF PatchH2TOP;
+static PATCH_REF PatchLFEDGE;
+static PATCH_REF PatchRTEDGE;
+static PATCH_REF PatchARMCLEAR;
+static PATCH_REF PatchARTICLEAR;
+static PATCH_REF PatchMANACLEAR;
+static PATCH_REF PatchKILLS;
+static PATCH_REF PatchMANAVIAL1;
+static PATCH_REF PatchMANAVIAL2;
+static PATCH_REF PatchMANAVIALDIM1;
+static PATCH_REF PatchMANAVIALDIM2;
+static PATCH_REF PatchMANADIM1;
+static PATCH_REF PatchMANADIM2;
+static PATCH_REF PatchMANABRIGHT1;
+static PATCH_REF PatchMANABRIGHT2;
+static PATCH_REF PatchCHAIN;
+static PATCH_REF PatchSTATBAR;
+static PATCH_REF PatchKEYBAR;
+static PATCH_REF PatchLIFEGEM;
+static PATCH_REF PatchSELECTBOX;
+static PATCH_REF PatchINumbers[10];
+static PATCH_REF PatchNEGATIVE;
+static PATCH_REF PatchSmNumbers[10];
+static PATCH_REF PatchINVBAR;
+static PATCH_REF PatchWEAPONSLOT;
+static PATCH_REF PatchWEAPONFULL;
+static PATCH_REF PatchPIECE1;
+static PATCH_REF PatchPIECE2;
+static PATCH_REF PatchPIECE3;
+static PATCH_REF PatchINVLFGEM1;
+static PATCH_REF PatchINVLFGEM2;
+static PATCH_REF PatchINVRTGEM1;
+static PATCH_REF PatchINVRTGEM2;
+
+/* Toggle god mode */
+static byte CheatGodSeq[] =
+{
+ CHEAT_ENCRYPT('s'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('n'),
+ 0xff
+};
+
+/* Toggle no clipping mode */
+static byte CheatNoClipSeq[] =
+{
+ CHEAT_ENCRYPT('c'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('s'),
+ CHEAT_ENCRYPT('p'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('r'),
+ 0xff
+};
+
+/* Get all weapons and mana */
+static byte CheatWeaponsSeq[] =
+{
+ CHEAT_ENCRYPT('n'),
+ CHEAT_ENCRYPT('r'),
+ CHEAT_ENCRYPT('a'),
+ 0xff
+};
+
+/* Get full health */
+static byte CheatHealthSeq[] =
+{
+ CHEAT_ENCRYPT('c'),
+ CHEAT_ENCRYPT('l'),
+ CHEAT_ENCRYPT('u'),
+ CHEAT_ENCRYPT('b'),
+ CHEAT_ENCRYPT('m'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('d'),
+ 0xff
+};
+
+/* Get all keys */
+static byte CheatKeysSeq[] =
+{
+ CHEAT_ENCRYPT('l'),
+ CHEAT_ENCRYPT('o'),
+ CHEAT_ENCRYPT('c'),
+ CHEAT_ENCRYPT('k'),
+ CHEAT_ENCRYPT('s'),
+ CHEAT_ENCRYPT('m'),
+ CHEAT_ENCRYPT('i'),
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('h'),
+ 0xff, 0
+};
+
+/* Toggle sound debug info */
+static byte CheatSoundSeq[] =
+{
+ CHEAT_ENCRYPT('n'),
+ CHEAT_ENCRYPT('o'),
+ CHEAT_ENCRYPT('i'),
+ CHEAT_ENCRYPT('s'),
+ CHEAT_ENCRYPT('e'),
+ 0xff
+};
+
+/* Toggle ticker */
+static byte CheatTickerSeq[] =
+{
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('i'),
+ CHEAT_ENCRYPT('c'),
+ CHEAT_ENCRYPT('k'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('r'),
+ 0xff, 0
+};
+
+/* Get all artifacts */
+static byte CheatArtifactAllSeq[] =
+{
+ CHEAT_ENCRYPT('i'),
+ CHEAT_ENCRYPT('n'),
+ CHEAT_ENCRYPT('d'),
+ CHEAT_ENCRYPT('i'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('n'),
+ CHEAT_ENCRYPT('a'),
+ 0xff, 0
+};
+
+/* Get all puzzle pieces */
+static byte CheatPuzzleSeq[] =
+{
+ CHEAT_ENCRYPT('s'),
+ CHEAT_ENCRYPT('h'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('r'),
+ CHEAT_ENCRYPT('l'),
+ CHEAT_ENCRYPT('o'),
+ CHEAT_ENCRYPT('c'),
+ CHEAT_ENCRYPT('k'),
+ 0xff, 0
+};
+
+/* Warp to new level */
+static byte CheatWarpSeq[] =
+{
+ CHEAT_ENCRYPT('v'),
+ CHEAT_ENCRYPT('i'),
+ CHEAT_ENCRYPT('s'),
+ CHEAT_ENCRYPT('i'),
+ CHEAT_ENCRYPT('t'),
+ 0, 0, 0xff, 0
+};
+
+/* Become a pig */
+static byte CheatPigSeq[] =
+{
+ CHEAT_ENCRYPT('d'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('l'),
+ CHEAT_ENCRYPT('i'),
+ CHEAT_ENCRYPT('v'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('r'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('n'),
+ CHEAT_ENCRYPT('c'),
+ CHEAT_ENCRYPT('e'),
+ 0xff, 0
+};
+
+/* Kill all monsters */
+static byte CheatMassacreSeq[] =
+{
+ CHEAT_ENCRYPT('b'),
+ CHEAT_ENCRYPT('u'),
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('c'),
+ CHEAT_ENCRYPT('h'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('r'),
+ 0xff, 0
+};
+
+static byte CheatIDKFASeq[] =
+{
+ CHEAT_ENCRYPT('c'),
+ CHEAT_ENCRYPT('o'),
+ CHEAT_ENCRYPT('n'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('n'),
+ 0xff, 0
+};
+
+static byte CheatQuickenSeq1[] =
+{
+ CHEAT_ENCRYPT('m'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('r'),
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('k'),
+ 0xff, 0
+};
+
+static byte CheatQuickenSeq2[] =
+{
+ CHEAT_ENCRYPT('m'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('r'),
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('k'),
+ CHEAT_ENCRYPT('m'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('r'),
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('k'),
+ 0xff, 0
+};
+
+static byte CheatQuickenSeq3[] =
+{
+ CHEAT_ENCRYPT('m'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('r'),
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('k'),
+ CHEAT_ENCRYPT('m'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('r'),
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('k'),
+ CHEAT_ENCRYPT('m'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('r'),
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('k'),
+ 0xff, 0
+};
+
+/* New class */
+static byte CheatClass1Seq[] =
+{
+ CHEAT_ENCRYPT('s'),
+ CHEAT_ENCRYPT('h'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('d'),
+ CHEAT_ENCRYPT('o'),
+ CHEAT_ENCRYPT('w'),
+ CHEAT_ENCRYPT('c'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('s'),
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('r'),
+ 0xff, 0
+};
+
+static byte CheatClass2Seq[] =
+{
+ CHEAT_ENCRYPT('s'),
+ CHEAT_ENCRYPT('h'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('d'),
+ CHEAT_ENCRYPT('o'),
+ CHEAT_ENCRYPT('w'),
+ CHEAT_ENCRYPT('c'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('s'),
+ CHEAT_ENCRYPT('t'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('r'),
+ 0, 0xff, 0
+};
+
+static byte CheatInitSeq[] =
+{
+ CHEAT_ENCRYPT('i'),
+ CHEAT_ENCRYPT('n'),
+ CHEAT_ENCRYPT('i'),
+ CHEAT_ENCRYPT('t'),
+ 0xff, 0
+};
+
+static byte CheatVersionSeq[] =
+{
+ CHEAT_ENCRYPT('m'),
+ CHEAT_ENCRYPT('r'),
+ CHEAT_ENCRYPT('j'),
+ CHEAT_ENCRYPT('o'),
+ CHEAT_ENCRYPT('n'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('s'),
+ 0xff, 0
+};
+
+static byte CheatDebugSeq[] =
+{
+ CHEAT_ENCRYPT('w'),
+ CHEAT_ENCRYPT('h'),
+ CHEAT_ENCRYPT('e'),
+ CHEAT_ENCRYPT('r'),
+ CHEAT_ENCRYPT('e'),
+ 0xff, 0
+};
+
+static byte CheatScriptSeq1[] =
+{
+ CHEAT_ENCRYPT('p'),
+ CHEAT_ENCRYPT('u'),
+ CHEAT_ENCRYPT('k'),
+ CHEAT_ENCRYPT('e'),
+ 0xff, 0
+};
+
+static byte CheatScriptSeq2[] =
+{
+ CHEAT_ENCRYPT('p'),
+ CHEAT_ENCRYPT('u'),
+ CHEAT_ENCRYPT('k'),
+ CHEAT_ENCRYPT('e'),
+ 0, 0xff, 0
+};
+
+static byte CheatScriptSeq3[] =
+{
+ CHEAT_ENCRYPT('p'),
+ CHEAT_ENCRYPT('u'),
+ CHEAT_ENCRYPT('k'),
+ CHEAT_ENCRYPT('e'),
+ 0, 0, 0xff,
+};
+
+static byte CheatRevealSeq[] =
+{
+ CHEAT_ENCRYPT('m'),
+ CHEAT_ENCRYPT('a'),
+ CHEAT_ENCRYPT('p'),
+ CHEAT_ENCRYPT('s'),
+ CHEAT_ENCRYPT('c'),
+ CHEAT_ENCRYPT('o'),
+ 0xff, 0
+};
+
+static byte CheatTrackSeq1[] =
+{
+ CHEAT_ENCRYPT('`'),
+ 0xff, 0
+};
+
+static byte CheatTrackSeq2[] =
+{
+ CHEAT_ENCRYPT('`'),
+ 0, 0, 0xff, 0
+};
+
+static Cheat_t Cheats[] =
+{
+ { CheatTrackFunc1, CheatTrackSeq1, NULL, {0, 0}, 0 },
+ { CheatTrackFunc2, CheatTrackSeq2, NULL, {0, 0}, 0 },
+ { CheatGodFunc, CheatGodSeq, NULL, {0, 0}, 0 },
+ { CheatNoClipFunc, CheatNoClipSeq, NULL, {0, 0}, 0 },
+ { CheatWeaponsFunc, CheatWeaponsSeq, NULL, {0, 0}, 0 },
+ { CheatHealthFunc, CheatHealthSeq, NULL, {0, 0}, 0 },
+ { CheatKeysFunc, CheatKeysSeq, NULL, {0, 0}, 0 },
+ { CheatSoundFunc, CheatSoundSeq, NULL, {0, 0}, 0 },
+ { CheatTickerFunc, CheatTickerSeq, NULL, {0, 0}, 0 },
+ { CheatArtifactAllFunc, CheatArtifactAllSeq, NULL, {0, 0}, 0 },
+ { CheatPuzzleFunc, CheatPuzzleSeq, NULL, {0, 0}, 0 },
+ { CheatWarpFunc, CheatWarpSeq, NULL, {0, 0}, 0 },
+ { CheatPigFunc, CheatPigSeq, NULL, {0, 0}, 0 },
+ { CheatMassacreFunc, CheatMassacreSeq, NULL, {0, 0}, 0 },
+ { CheatIDKFAFunc, CheatIDKFASeq, NULL, {0, 0}, 0 },
+ { CheatQuickenFunc1, CheatQuickenSeq1, NULL, {0, 0}, 0 },
+ { CheatQuickenFunc2, CheatQuickenSeq2, NULL, {0, 0}, 0 },
+ { CheatQuickenFunc3, CheatQuickenSeq3, NULL, {0, 0}, 0 },
+ { CheatClassFunc1, CheatClass1Seq, NULL, {0, 0}, 0 },
+ { CheatClassFunc2, CheatClass2Seq, NULL, {0, 0}, 0 },
+ { CheatInitFunc, CheatInitSeq, NULL, {0, 0}, 0 },
+ { CheatVersionFunc, CheatVersionSeq, NULL, {0, 0}, 0 },
+ { CheatDebugFunc, CheatDebugSeq, NULL, {0, 0}, 0 },
+ { CheatScriptFunc1, CheatScriptSeq1, NULL, {0, 0}, 0 },
+ { CheatScriptFunc2, CheatScriptSeq2, NULL, {0, 0}, 0 },
+ { CheatScriptFunc3, CheatScriptSeq3, NULL, {0, 0}, 0 },
+ { CheatRevealFunc, CheatRevealSeq, NULL, {0, 0}, 0 },
+ { NULL, NULL, NULL, {0, 0}, 0 } /* Terminator */
+};
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// SB_Init
+//
+//==========================================================================
+
+void SB_Init(void)
+{
+ int i;
+ int startLump;
+
+ PatchH2BAR = (PATCH_REF) WR_CacheLumpName("H2BAR", PU_STATIC);
+ PatchH2TOP = (PATCH_REF) WR_CacheLumpName("H2TOP", PU_STATIC);
+ PatchINVBAR = (PATCH_REF) WR_CacheLumpName("INVBAR", PU_STATIC);
+ PatchLFEDGE = (PATCH_REF) WR_CacheLumpName("LFEDGE", PU_STATIC);
+ PatchRTEDGE = (PATCH_REF) WR_CacheLumpName("RTEDGE", PU_STATIC);
+ PatchSTATBAR = (PATCH_REF) WR_CacheLumpName("STATBAR", PU_STATIC);
+ PatchKEYBAR = (PATCH_REF) WR_CacheLumpName("KEYBAR", PU_STATIC);
+ PatchSELECTBOX = (PATCH_REF) WR_CacheLumpName("SELECTBOX", PU_STATIC);
+ PatchARTICLEAR = (PATCH_REF) WR_CacheLumpName("ARTICLS", PU_STATIC);
+ PatchARMCLEAR = (PATCH_REF) WR_CacheLumpName("ARMCLS", PU_STATIC);
+ PatchMANACLEAR = (PATCH_REF) WR_CacheLumpName("MANACLS", PU_STATIC);
+ PatchMANAVIAL1 = (PATCH_REF) WR_CacheLumpName("MANAVL1", PU_STATIC);
+ PatchMANAVIAL2 = (PATCH_REF) WR_CacheLumpName("MANAVL2", PU_STATIC);
+ PatchMANAVIALDIM1 = (PATCH_REF) WR_CacheLumpName("MANAVL1D", PU_STATIC);
+ PatchMANAVIALDIM2 = (PATCH_REF) WR_CacheLumpName("MANAVL2D", PU_STATIC);
+ PatchMANADIM1 = (PATCH_REF) WR_CacheLumpName("MANADIM1", PU_STATIC);
+ PatchMANADIM2 = (PATCH_REF) WR_CacheLumpName("MANADIM2", PU_STATIC);
+ PatchMANABRIGHT1 = (PATCH_REF) WR_CacheLumpName("MANABRT1", PU_STATIC);
+ PatchMANABRIGHT2 = (PATCH_REF) WR_CacheLumpName("MANABRT2", PU_STATIC);
+ PatchINVLFGEM1 = (PATCH_REF) WR_CacheLumpName("invgeml1", PU_STATIC);
+ PatchINVLFGEM2 = (PATCH_REF) WR_CacheLumpName("invgeml2", PU_STATIC);
+ PatchINVRTGEM1 = (PATCH_REF) WR_CacheLumpName("invgemr1", PU_STATIC);
+ PatchINVRTGEM2 = (PATCH_REF) WR_CacheLumpName("invgemr2", PU_STATIC);
+
+ startLump = W_GetNumForName("IN0");
+ for (i = 0; i < 10; i++)
+ {
+ PatchINumbers[i] = (PATCH_REF) WR_CacheLumpNum(startLump + i, PU_STATIC);
+ }
+ PatchNEGATIVE = (PATCH_REF) WR_CacheLumpName("NEGNUM", PU_STATIC);
+ FontBNumBase = W_GetNumForName("FONTB16");
+ startLump = W_GetNumForName("SMALLIN0");
+ for (i = 0; i < 10; i++)
+ {
+ PatchSmNumbers[i] = (PATCH_REF) WR_CacheLumpNum(startLump + i, PU_STATIC);
+ }
+ PlayPalette = W_GetNumForName("PLAYPAL");
+ SpinFlylump = W_GetNumForName("SPFLY0");
+ SpinMinotaurLump = W_GetNumForName("SPMINO0");
+ SpinSpeedLump = W_GetNumForName("SPBOOT0");
+ SpinDefenseLump = W_GetNumForName("SPSHLD0");
+
+ for (i = 0; i < 256; i++)
+ {
+ CheatLookup[i] = CHEAT_ENCRYPT(i);
+ }
+
+ if (deathmatch)
+ {
+ PatchKILLS = (PATCH_REF) WR_CacheLumpName("KILLS", PU_STATIC);
+ }
+ SB_SetClassData();
+}
+
+//==========================================================================
+//
+// SB_SetClassData
+//
+//==========================================================================
+
+void SB_SetClassData(void)
+{
+ int pClass;
+ int max_players;
+
+ pClass = PlayerClasses[consoleplayer]; // original player class (not pig)
+#ifdef ASSASSIN
+ if (pClass == PCLASS_ASS)
+ pClass = PCLASS_FIGHTER; // Use FIghter chain and gem for now
+#endif
+
+ max_players = ((MAXPLAYERS > MAXPLAYERS_10) && oldwad_10) ? MAXPLAYERS_10 : MAXPLAYERS;
+
+ PatchWEAPONSLOT = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("wpslot0") + pClass, PU_STATIC);
+ PatchWEAPONFULL = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("wpfull0") + pClass, PU_STATIC);
+ PatchPIECE1 = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("wpiecef1")+ pClass, PU_STATIC);
+ PatchPIECE2 = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("wpiecef2")+ pClass, PU_STATIC);
+ PatchPIECE3 = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("wpiecef3")+ pClass, PU_STATIC);
+ PatchCHAIN = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("chain") + pClass, PU_STATIC);
+
+ if (!netgame)
+ { // single player game uses red life gem (the second gem)
+ PatchLIFEGEM = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("lifegem") + max_players*pClass + 1, PU_STATIC);
+ }
+ else
+ {
+ PatchLIFEGEM = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("lifegem") + max_players*pClass + consoleplayer, PU_STATIC);
+ }
+ SB_state = -1;
+ UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// SB_Ticker
+//
+//==========================================================================
+
+void SB_Ticker(void)
+{
+ int delta;
+ int curHealth;
+
+ curHealth = players[consoleplayer].mo->health;
+ if (curHealth < 0)
+ {
+ curHealth = 0;
+ }
+ if (curHealth < HealthMarker)
+ {
+ delta = (HealthMarker - curHealth)>>2;
+ if (delta < 1)
+ {
+ delta = 1;
+ }
+ else if (delta > 6)
+ {
+ delta = 6;
+ }
+ HealthMarker -= delta;
+ }
+ else if (curHealth > HealthMarker)
+ {
+ delta = (curHealth - HealthMarker)>>2;
+ if (delta < 1)
+ {
+ delta = 1;
+ }
+ else if (delta > 6)
+ {
+ delta = 6;
+ }
+ HealthMarker += delta;
+ }
+}
+
+//==========================================================================
+//
+// DrINumber
+//
+// Draws a three digit number.
+//
+//==========================================================================
+
+static void DrINumber(signed int val, int x, int y)
+{
+ PATCH_REF patch;
+ int oldval;
+
+ oldval = val;
+ if (val < 0)
+ {
+ val = -val;
+ if (val > 99)
+ {
+ val = 99;
+ }
+ if (val > 9)
+ {
+ patch = PatchINumbers[val/10];
+ V_DrawPatch(x + 8, y, patch);
+ V_DrawPatch(x, y, PatchNEGATIVE);
+ }
+ else
+ {
+ V_DrawPatch(x + 8, y, PatchNEGATIVE);
+ }
+ val = val % 10;
+ patch = PatchINumbers[val];
+ V_DrawPatch(x + 16, y, patch);
+ return;
+ }
+ if (val > 99)
+ {
+ patch = PatchINumbers[val/100];
+ V_DrawPatch(x, y, patch);
+ }
+ val = val % 100;
+ if (val > 9 || oldval > 99)
+ {
+ patch = PatchINumbers[val/10];
+ V_DrawPatch(x + 8, y, patch);
+ }
+ val = val % 10;
+ patch = PatchINumbers[val];
+ V_DrawPatch(x + 16, y, patch);
+}
+
+//==========================================================================
+//
+// DrRedINumber
+//
+// Draws a three digit number using the red font
+//
+//==========================================================================
+
+static void DrRedINumber(signed int val, int x, int y)
+{
+ PATCH_REF patch;
+ int oldval;
+
+ oldval = val;
+ if (val < 0)
+ {
+ val = 0;
+ }
+ if (val > 99)
+ {
+ patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("inred0") + val/100, PU_CACHE);
+ V_DrawPatch(x, y, patch);
+ }
+ val = val % 100;
+ if (val > 9 || oldval > 99)
+ {
+ patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("inred0") + val/10, PU_CACHE);
+ V_DrawPatch(x + 8, y, patch);
+ }
+ val = val % 10;
+ patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("inred0") + val, PU_CACHE);
+ V_DrawPatch(x + 16, y, patch);
+}
+
+//==========================================================================
+//
+// DrBNumber
+//
+// Draws a three digit number using FontB
+//
+//==========================================================================
+
+static void DrBNumber(signed int val, int x, int y)
+{
+ patch_t* patch;
+ int xpos;
+ int oldval;
+ int width;
+
+ oldval = val;
+ xpos = x;
+ if (val < 0)
+ {
+ val = 0;
+ }
+ if (val > 99)
+ {
+ patch = (patch_t *) W_CacheLumpNum(FontBNumBase + val/100, PU_CACHE);
+ width = SHORT(patch->width) / 2;
+#ifdef RENDER3D
+ OGL_DrawShadowedPatch(xpos + 6 - width, y, FontBNumBase + val/100);
+#else
+ V_DrawShadowedPatch(xpos + 6 - width, y, patch);
+#endif
+ }
+ val = val % 100;
+ xpos += 12;
+ if (val > 9 || oldval > 99)
+ {
+ patch = (patch_t *) W_CacheLumpNum(FontBNumBase + val/10, PU_CACHE);
+ width = SHORT(patch->width) / 2;
+#ifdef RENDER3D
+ OGL_DrawShadowedPatch(xpos + 6 - width, y, FontBNumBase + val/10);
+#else
+ V_DrawShadowedPatch(xpos + 6 - width, y, patch);
+#endif
+ }
+ val = val % 10;
+ xpos += 12;
+ patch = (patch_t *) W_CacheLumpNum(FontBNumBase + val, PU_CACHE);
+ width = SHORT(patch->width) / 2;
+#ifdef RENDER3D
+ OGL_DrawShadowedPatch(xpos + 6 - width, y, FontBNumBase + val/1);
+#else
+ V_DrawShadowedPatch(xpos + 6 - width, y, patch);
+#endif
+}
+
+//==========================================================================
+//
+// DrSmallNumber
+//
+// Draws a small two digit number.
+//
+//==========================================================================
+
+static void DrSmallNumber(int val, int x, int y)
+{
+ PATCH_REF patch;
+
+ if (val <= 0)
+ {
+ return;
+ }
+ if (val > 999)
+ {
+ val %= 1000;
+ }
+ if (val > 99)
+ {
+ patch = PatchSmNumbers[val/100];
+ V_DrawPatch(x, y, patch);
+ patch = PatchSmNumbers[(val % 100) / 10];
+ V_DrawPatch(x + 4, y, patch);
+ }
+ else if (val > 9)
+ {
+ patch = PatchSmNumbers[val/10];
+ V_DrawPatch(x + 4, y, patch);
+ }
+ val %= 10;
+ patch = PatchSmNumbers[val];
+ V_DrawPatch(x + 8, y, patch);
+}
+
+//==========================================================================
+//
+// DrawSoundInfo
+//
+// Displays sound debugging information.
+//
+//==========================================================================
+
+static void DrawSoundInfo(void)
+{
+ int i;
+ SoundInfo_t s;
+ ChanInfo_t *c;
+ char text[32];
+ int x;
+ int y;
+ int xPos[7] = {1, 75, 112, 156, 200, 230, 260};
+
+ if (leveltime & 16)
+ {
+ MN_DrTextA("*** SOUND DEBUG INFO ***", xPos[0], 20);
+ }
+ S_GetChannelInfo(&s);
+ if (s.channelCount == 0)
+ {
+ return;
+ }
+ x = 0;
+ MN_DrTextA("NAME", xPos[x++], 30);
+ MN_DrTextA("MO.T", xPos[x++], 30);
+ MN_DrTextA("MO.X", xPos[x++], 30);
+ MN_DrTextA("MO.Y", xPos[x++], 30);
+ MN_DrTextA("ID", xPos[x++], 30);
+ MN_DrTextA("PRI", xPos[x++], 30);
+ MN_DrTextA("DIST", xPos[x++], 30);
+ for (i = 0; i < s.channelCount; i++)
+ {
+ c = &s.chan[i];
+ x = 0;
+ y = 40 + i*10;
+ if (c->mo == NULL)
+ { // Channel is unused
+ MN_DrTextA("------", xPos[0], y);
+ continue;
+ }
+ snprintf(text, sizeof(text), "%s", c->name);
+ M_ForceUppercase(text);
+ MN_DrTextA(text, xPos[x++], y);
+ snprintf(text, sizeof(text), "%d", c->mo->type);
+ MN_DrTextA(text, xPos[x++], y);
+ snprintf(text, sizeof(text), "%d", c->mo->x>>FRACBITS);
+ MN_DrTextA(text, xPos[x++], y);
+ snprintf(text, sizeof(text), "%d", c->mo->y>>FRACBITS);
+ MN_DrTextA(text, xPos[x++], y);
+ snprintf(text, sizeof(text), "%d", c->id);
+ MN_DrTextA(text, xPos[x++], y);
+ snprintf(text, sizeof(text), "%d", c->priority);
+ MN_DrTextA(text, xPos[x++], y);
+ snprintf(text, sizeof(text), "%d", c->distance);
+ MN_DrTextA(text, xPos[x++], y);
+ }
+ UpdateState |= I_FULLSCRN;
+ BorderNeedRefresh = true;
+}
+
+//==========================================================================
+//
+// SB_Drawer
+//
+//==========================================================================
+
+static const char patcharti[][10] =
+{
+ { "ARTIBOX" }, /* none */
+ { "ARTIINVU" }, /* invulnerability */
+ { "ARTIPTN2" }, /* health */
+ { "ARTISPHL" }, /* superhealth */
+ { "ARTIHRAD" }, /* healing radius */
+ { "ARTISUMN" }, /* summon maulator */
+ { "ARTITRCH" }, /* torch */
+ { "ARTIPORK" }, /* egg */
+ { "ARTISOAR" }, /* fly */
+ { "ARTIBLST" }, /* blast radius */
+ { "ARTIPSBG" }, /* poison bag */
+ { "ARTITELO" }, /* teleport other */
+ { "ARTISPED" }, /* speed */
+ { "ARTIBMAN" }, /* boost mana */
+ { "ARTIBRAC" }, /* boost armor */
+ { "ARTIATLP" }, /* teleport */
+ { "ARTISKLL" }, /* arti_puzzskull */
+ { "ARTIBGEM" }, /* arti_puzzgembig */
+ { "ARTIGEMR" }, /* arti_puzzgemred */
+ { "ARTIGEMG" }, /* arti_puzzgemgreen1 */
+ { "ARTIGMG2" }, /* arti_puzzgemgreen2 */
+ { "ARTIGEMB" }, /* arti_puzzgemblue1 */
+ { "ARTIGMB2" }, /* arti_puzzgemblue2 */
+ { "ARTIBOK1" }, /* arti_puzzbook1 */
+ { "ARTIBOK2" }, /* arti_puzzbook2 */
+ { "ARTISKL2" }, /* arti_puzzskull2 */
+ { "ARTIFWEP" }, /* arti_puzzfweapon */
+ { "ARTICWEP" }, /* arti_puzzcweapon */
+ { "ARTIMWEP" }, /* arti_puzzmweapon */
+ { "ARTIGEAR" }, /* arti_puzzgear1 */
+ { "ARTIGER2" }, /* arti_puzzgear2 */
+ { "ARTIGER3" }, /* arti_puzzgear3 */
+ { "ARTIGER4" }, /* arti_puzzgear4 */
+};
+
+int SB_state = -1;
+#ifndef RENDER3D
+static int oldfrags = -9999;
+static int oldmana1 = -1;
+static int oldmana2 = -1;
+static int oldhealth = -1;
+static int oldlife = -1;
+static int oldpieces = -1;
+static int oldweapon = -1;
+#endif
+static int oldarti = 0;
+static int oldartiCount = 0;
+static int oldkeys = -1;
+static int oldarmor = -1;
+
+void SB_Drawer(void)
+{
+ // Sound info debug stuff
+ if (DebugSound == true)
+ {
+ DrawSoundInfo();
+ }
+ CPlayer = &players[consoleplayer];
+ if (viewheight == SCREENHEIGHT && !automapactive)
+ {
+ DrawFullScreenStuff();
+ SB_state = -1;
+ }
+ else
+ {
+#ifndef RENDER3D
+ if (SB_state == -1)
+ {
+#endif
+ V_DrawPatch(0, 134, PatchH2BAR);
+#ifndef RENDER3D
+ oldhealth = -1;
+ }
+#endif
+ DrawCommonBar();
+
+ if (!inventory)
+ {
+#ifndef RENDER3D
+ if (SB_state != 0)
+ {
+#endif
+ // Main interface
+ if (!automapactive)
+ {
+ V_DrawPatch(38, 162, PatchSTATBAR);
+ }
+ else
+ {
+ V_DrawPatch(38, 162, PatchKEYBAR);
+ }
+#ifndef RENDER3D
+ oldarti = 0;
+ oldmana1 = -1;
+ oldmana2 = -1;
+ oldarmor = -1;
+ oldpieces = -1;
+ oldfrags = -9999; //can't use -1, 'cuz of negative frags
+ oldlife = -1;
+ oldweapon = -1;
+ oldkeys = -1;
+ }
+#endif
+ if (!automapactive)
+ {
+ DrawMainBar();
+ }
+ else
+ {
+ DrawKeyBar();
+ }
+ SB_state = 0;
+ }
+ else
+ {
+ DrawInventoryBar();
+ SB_state = 1;
+ }
+ }
+ SB_PaletteFlash(false);
+ DrawAnimatedIcons();
+}
+
+//==========================================================================
+//
+// DrawAnimatedIcons
+//
+//==========================================================================
+
+static void DrawAnimatedIcons(void)
+{
+ int frame;
+ static boolean hitCenterFrame;
+
+ // Wings of wrath
+ if (CPlayer->powers[pw_flight])
+ {
+ if (CPlayer->powers[pw_flight] > BLINKTHRESHOLD
+ || !(CPlayer->powers[pw_flight] & 16))
+ {
+ frame = (leveltime / 3) & 15;
+ if (CPlayer->mo->flags2 & MF2_FLY)
+ {
+ if (hitCenterFrame && (frame != 15 && frame != 0))
+ {
+ V_DrawPatch(20, 19, (PATCH_REF)WR_CacheLumpNum(SpinFlylump + 15, PU_CACHE));
+ }
+ else
+ {
+ V_DrawPatch(20, 19, (PATCH_REF)WR_CacheLumpNum(SpinFlylump + frame, PU_CACHE));
+ hitCenterFrame = false;
+ }
+ }
+ else
+ {
+ if (!hitCenterFrame && (frame != 15 && frame != 0))
+ {
+ V_DrawPatch(20, 19, (PATCH_REF)WR_CacheLumpNum(SpinFlylump + frame, PU_CACHE));
+ hitCenterFrame = false;
+ }
+ else
+ {
+ V_DrawPatch(20, 19, (PATCH_REF)WR_CacheLumpNum(SpinFlylump + 15, PU_CACHE));
+ hitCenterFrame = true;
+ }
+ }
+ }
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+
+ // Speed Boots
+ if (CPlayer->powers[pw_speed])
+ {
+ if (CPlayer->powers[pw_speed] > BLINKTHRESHOLD
+ || !(CPlayer->powers[pw_speed] & 16))
+ {
+ frame = (leveltime / 3) & 15;
+ V_DrawPatch(60, 19, (PATCH_REF)WR_CacheLumpNum(SpinSpeedLump + frame, PU_CACHE));
+ }
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+
+ // Defensive power
+ if (CPlayer->powers[pw_invulnerability])
+ {
+ if (CPlayer->powers[pw_invulnerability] > BLINKTHRESHOLD
+ || !(CPlayer->powers[pw_invulnerability] & 16))
+ {
+ frame = (leveltime / 3) & 15;
+ V_DrawPatch(260, 19, (PATCH_REF)WR_CacheLumpNum(SpinDefenseLump + frame, PU_CACHE));
+ }
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+
+ // Minotaur Active
+ if (CPlayer->powers[pw_minotaur])
+ {
+ if (CPlayer->powers[pw_minotaur] > BLINKTHRESHOLD
+ || !(CPlayer->powers[pw_minotaur] & 16))
+ {
+ frame = (leveltime / 3) & 15;
+ V_DrawPatch(300, 19, (PATCH_REF)WR_CacheLumpNum(SpinMinotaurLump + frame, PU_CACHE));
+ }
+ BorderTopRefresh = true;
+ UpdateState |= I_MESSAGES;
+ }
+}
+
+//==========================================================================
+//
+// SB_PaletteFlash
+//
+// Sets the new palette based upon the current values of
+// consoleplayer->damagecount and consoleplayer->bonuscount.
+//
+//==========================================================================
+
+void SB_PaletteFlash(boolean forceChange)
+{
+ static int sb_palette = 0;
+ int palette;
+
+ if (forceChange)
+ {
+ sb_palette = -1;
+ }
+ if (gamestate == GS_LEVEL)
+ {
+ CPlayer = &players[consoleplayer];
+ if (CPlayer->poisoncount)
+ {
+ palette = 0;
+ palette = (CPlayer->poisoncount + 7)>>3;
+ if (palette >= NUMPOISONPALS)
+ {
+ palette = NUMPOISONPALS - 1;
+ }
+ palette += STARTPOISONPALS;
+ }
+ else if (CPlayer->damagecount)
+ {
+ palette = (CPlayer->damagecount + 7)>>3;
+ if (palette >= NUMREDPALS)
+ {
+ palette = NUMREDPALS - 1;
+ }
+ palette += STARTREDPALS;
+ }
+ else if (CPlayer->bonuscount)
+ {
+ palette = (CPlayer->bonuscount + 7)>>3;
+ if (palette >= NUMBONUSPALS)
+ {
+ palette = NUMBONUSPALS - 1;
+ }
+ palette += STARTBONUSPALS;
+ }
+ else if (CPlayer->mo->flags2 & MF2_ICEDAMAGE)
+ { // Frozen player
+ palette = STARTICEPAL;
+ }
+ else
+ {
+ palette = 0;
+ }
+ }
+ else
+ {
+ palette = 0;
+ }
+ if (palette != sb_palette)
+ {
+ sb_palette = palette;
+ V_SetPaletteShift(palette);
+ }
+}
+
+//==========================================================================
+//
+// DrawCommonBar
+//
+//==========================================================================
+
+void DrawCommonBar(void)
+{
+ int healthPos;
+
+#ifndef RENDER3D
+ V_DrawPatch(0, 134, PatchH2TOP);
+
+ if (oldhealth != HealthMarker)
+ {
+ oldhealth = HealthMarker;
+#endif
+ healthPos = HealthMarker;
+ if (healthPos < 0)
+ {
+ healthPos = 0;
+ }
+ if (healthPos > 100)
+ {
+ healthPos = 100;
+ }
+ V_DrawPatch(28 + (((healthPos * 196) / 100) % 9), 193, PatchCHAIN);
+ V_DrawPatch( 7 + ((healthPos * 11) / 5), 193, PatchLIFEGEM);
+ V_DrawPatch(0, 193, PatchLFEDGE);
+ V_DrawPatch(277, 193, PatchRTEDGE);
+#ifndef RENDER3D
+ UpdateState |= I_STATBAR;
+ }
+#endif
+}
+
+//==========================================================================
+//
+// DrawMainBar
+//
+//==========================================================================
+
+void DrawMainBar(void)
+{
+ PATCH_REF manaPatch1 = INVALID_PATCH;
+ PATCH_REF manaPatch2 = INVALID_PATCH;
+ PATCH_REF manaVialPatch1 = INVALID_PATCH;
+ PATCH_REF manaVialPatch2 = INVALID_PATCH;
+ int i, temp;
+
+ // Ready artifact
+ if (ArtifactFlash)
+ {
+#ifndef RENDER3D
+ V_DrawPatch(144, 160, PatchARTICLEAR);
+#endif
+ V_DrawPatch(148, 164, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("useartia") + ArtifactFlash - 1, PU_CACHE));
+ ArtifactFlash--;
+ oldarti = -1; /* so that the correct artifact fills in after the flash */
+ UpdateState |= I_STATBAR;
+ }
+ else if (oldarti != CPlayer->readyArtifact ||
+ oldartiCount != CPlayer->inventory[inv_ptr].count)
+ {
+#ifndef RENDER3D
+ V_DrawPatch(144, 160, PatchARTICLEAR);
+#endif
+ if (CPlayer->readyArtifact > 0)
+ {
+ V_DrawPatch(143, 163, (PATCH_REF)WR_CacheLumpName(patcharti[CPlayer->readyArtifact], PU_CACHE));
+ if (CPlayer->inventory[inv_ptr].count > 1)
+ {
+ DrSmallNumber(CPlayer->inventory[inv_ptr].count, 162, 184);
+ }
+ }
+#ifndef RENDER3D
+ oldarti = CPlayer->readyArtifact;
+ oldartiCount = CPlayer->inventory[inv_ptr].count;
+ UpdateState |= I_STATBAR;
+#endif
+ }
+
+ // Frags
+ if (deathmatch)
+ {
+ temp = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ temp += CPlayer->frags[i];
+ }
+#ifndef RENDER3D
+ if (temp != oldfrags)
+ {
+#endif
+ V_DrawPatch(38, 162, PatchKILLS);
+ DrINumber(temp, 40, 176);
+#ifndef RENDER3D
+ oldfrags = temp;
+ UpdateState |= I_STATBAR;
+ }
+#endif
+ }
+ else
+ {
+ temp = HealthMarker;
+ if (temp < 0)
+ {
+ temp = 0;
+ }
+ else if (temp > 100)
+ {
+ temp = 100;
+ }
+#ifndef RENDER3D
+ if (oldlife != temp)
+ {
+ oldlife = temp;
+#endif
+ V_DrawPatch(41, 178, PatchARMCLEAR);
+ if (temp >= 25)
+ {
+ DrINumber(temp, 40, 176);
+ }
+ else
+ {
+ DrRedINumber(temp, 40, 176);
+ }
+#ifndef RENDER3D
+ UpdateState |= I_STATBAR;
+ }
+#endif
+ }
+ // Mana
+ temp = CPlayer->mana[0];
+#ifndef RENDER3D
+ if (oldmana1 != temp)
+ {
+#endif
+ V_DrawPatch(77, 178, PatchMANACLEAR);
+ DrSmallNumber(temp, 79, 181);
+#ifndef RENDER3D
+ manaVialPatch1 = (patch_t *)1; // force a vial update
+#endif
+ if (temp == 0)
+ { // Draw Dim Mana icon
+ manaPatch1 = PatchMANADIM1;
+ }
+#ifndef RENDER3D
+ else if (oldmana1 == 0)
+ {
+ manaPatch1 = PatchMANABRIGHT1;
+ }
+ oldmana1 = temp;
+ UpdateState |= I_STATBAR;
+ }
+#endif
+ temp = CPlayer->mana[1];
+#ifndef RENDER3D
+ if (oldmana2 != temp)
+ {
+#endif
+ V_DrawPatch(109, 178, PatchMANACLEAR);
+ DrSmallNumber(temp, 111, 181);
+#ifndef RENDER3D
+ manaVialPatch1 = (patch_t *)1; // force a vial update
+#endif
+ if (temp == 0)
+ { // Draw Dim Mana icon
+ manaPatch2 = PatchMANADIM2;
+ }
+#ifndef RENDER3D
+ else if (oldmana2 == 0)
+ {
+ manaPatch2 = PatchMANABRIGHT2;
+ }
+ oldmana2 = temp;
+ UpdateState |= I_STATBAR;
+ }
+#endif
+#ifndef RENDER3D
+ if (oldweapon != CPlayer->readyweapon || manaPatch1 || manaPatch2
+ || manaVialPatch1)
+ { // Update mana graphics based upon mana count/weapon type
+#endif
+ if (CPlayer->readyweapon == WP_FIRST)
+ {
+ manaPatch1 = PatchMANADIM1;
+ manaPatch2 = PatchMANADIM2;
+ manaVialPatch1 = PatchMANAVIALDIM1;
+ manaVialPatch2 = PatchMANAVIALDIM2;
+ }
+ else if (CPlayer->readyweapon == WP_SECOND)
+ {
+ if (!manaPatch1)
+ {
+ manaPatch1 = PatchMANABRIGHT1;
+ }
+ manaVialPatch1 = PatchMANAVIAL1;
+ manaPatch2 = PatchMANADIM2;
+ manaVialPatch2 = PatchMANAVIALDIM2;
+ }
+ else if (CPlayer->readyweapon == WP_THIRD)
+ {
+ manaPatch1 = PatchMANADIM1;
+ manaVialPatch1 = PatchMANAVIALDIM1;
+ if (!manaPatch2)
+ {
+ manaPatch2 = PatchMANABRIGHT2;
+ }
+ manaVialPatch2 = PatchMANAVIAL2;
+ }
+ else
+ {
+ manaVialPatch1 = PatchMANAVIAL1;
+ manaVialPatch2 = PatchMANAVIAL2;
+ if (!manaPatch1)
+ {
+ manaPatch1 = PatchMANABRIGHT1;
+ }
+ if (!manaPatch2)
+ {
+ manaPatch2 = PatchMANABRIGHT2;
+ }
+ }
+ V_DrawPatch(77, 164, manaPatch1);
+ V_DrawPatch(110, 164, manaPatch2);
+ V_DrawPatch(94, 164, manaVialPatch1);
+#ifndef RENDER3D
+ for (i = 165; i < 187 - (22*CPlayer->mana[0]) / MAX_MANA; i++)
+ {
+ screen[i*SCREENWIDTH+95] = 0;
+ screen[i*SCREENWIDTH+96] = 0;
+ screen[i*SCREENWIDTH+97] = 0;
+ }
+#endif
+ V_DrawPatch(102, 164, manaVialPatch2);
+#ifndef RENDER3D
+ for (i = 165; i < 187-(22*CPlayer->mana[1])/MAX_MANA; i++)
+ {
+ screen[i*SCREENWIDTH+103] = 0;
+ screen[i*SCREENWIDTH+104] = 0;
+ screen[i*SCREENWIDTH+105] = 0;
+ }
+ oldweapon = CPlayer->readyweapon;
+ UpdateState |= I_STATBAR;
+ }
+#endif
+
+ // Armor
+ temp = AutoArmorSave[CPlayer->playerclass]
+ + CPlayer->armorpoints[ARMOR_ARMOR] + CPlayer->armorpoints[ARMOR_SHIELD]
+ + CPlayer->armorpoints[ARMOR_HELMET]+ CPlayer->armorpoints[ARMOR_AMULET];
+#ifndef RENDER3D
+ if (oldarmor != temp)
+ {
+ oldarmor = temp;
+#endif
+ V_DrawPatch(255, 178, PatchARMCLEAR);
+ DrINumber(FixedDiv(temp, 5*FRACUNIT)>>FRACBITS, 250, 176);
+#ifndef RENDER3D
+ UpdateState |= I_STATBAR;
+ }
+#endif
+
+ // Weapon Pieces
+#ifndef RENDER3D
+ if (oldpieces != CPlayer->pieces)
+ {
+#endif
+ DrawWeaponPieces();
+#ifndef RENDER3D
+ oldpieces = CPlayer->pieces;
+ UpdateState |= I_STATBAR;
+ }
+#endif
+}
+
+//==========================================================================
+//
+// DrawInventoryBar
+//
+//==========================================================================
+
+void DrawInventoryBar(void)
+{
+ int i;
+ int x;
+
+ x = inv_ptr - curpos;
+ UpdateState |= I_STATBAR;
+ V_DrawPatch(38, 162, PatchINVBAR);
+ for (i = 0; i < 7; i++)
+ {
+ // V_DrawPatch(50 + i*31, 160, (PATCH_REF)WR_CacheLumpName("ARTIBOX", PU_CACHE));
+ if (CPlayer->inventorySlotNum > x + i
+ && CPlayer->inventory[x + i].type != arti_none)
+ {
+ V_DrawPatch(50 + i*31, 163, (PATCH_REF)WR_CacheLumpName(patcharti[CPlayer->inventory[x + i].type], PU_CACHE));
+ if (CPlayer->inventory[x + i].count > 1)
+ {
+ DrSmallNumber(CPlayer->inventory[x + i].count, 68 + i*31, 185);
+ }
+ }
+ }
+ V_DrawPatch(50 + curpos*31, 163, PatchSELECTBOX);
+ if (x != 0)
+ {
+ V_DrawPatch(42, 163, !(leveltime & 4) ? PatchINVLFGEM1 : PatchINVLFGEM2);
+ }
+ if (CPlayer->inventorySlotNum - x > 7)
+ {
+ V_DrawPatch(269, 163, !(leveltime & 4) ? PatchINVRTGEM1 : PatchINVRTGEM2);
+ }
+}
+
+//==========================================================================
+//
+// DrawKeyBar
+//
+//==========================================================================
+
+void DrawKeyBar(void)
+{
+ int i;
+ int xPosition;
+#ifdef RENDER3D
+ int temp;
+
+ if (oldkeys != CPlayer->keys)
+ {
+#endif
+ xPosition = 46;
+ for (i = 0; i < NUMKEYS && xPosition <= 126; i++)
+ {
+ if (CPlayer->keys & (1 << i))
+ {
+ V_DrawPatch(xPosition, 164, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("keyslot1") + i, PU_CACHE));
+ xPosition += 20;
+ }
+ }
+#ifdef RENDER3D
+ oldkeys = CPlayer->keys;
+ UpdateState |= I_STATBAR;
+ }
+ temp = AutoArmorSave[CPlayer->playerclass]
+ + CPlayer->armorpoints[ARMOR_ARMOR] + CPlayer->armorpoints[ARMOR_SHIELD]
+ + CPlayer->armorpoints[ARMOR_HELMET]+ CPlayer->armorpoints[ARMOR_AMULET];
+ if (oldarmor != temp)
+ {
+#endif
+ for (i = 0; i < NUMARMOR; i++)
+ {
+ if (!CPlayer->armorpoints[i])
+ {
+ continue;
+ }
+ if (CPlayer->armorpoints[i] <= (ArmorIncrement[CPlayer->playerclass][i]>>2))
+ {
+ V_DrawFuzzPatch(150 + 31*i, 164, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("armslot1") + i, PU_CACHE));
+ }
+ else if (CPlayer->armorpoints[i] <= (ArmorIncrement[CPlayer->playerclass][i]>>1))
+ {
+ V_DrawAltFuzzPatch(150 + 31*i, 164, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("armslot1") + i, PU_CACHE));
+ }
+ else
+ {
+ V_DrawPatch(150 + 31*i, 164, (PATCH_REF)WR_CacheLumpNum(W_GetNumForName("armslot1") + i, PU_CACHE));
+ }
+ }
+#ifdef RENDER3D
+ oldarmor = temp;
+ UpdateState |= I_STATBAR;
+ }
+#endif
+}
+
+//==========================================================================
+//
+// DrawWeaponPieces
+//
+//==========================================================================
+
+static int PieceX[NUMCLASSES][3] =
+{
+ { 190, 225, 234 },
+ { 190, 212, 225 },
+ { 190, 205, 224 },
+#ifdef ASSASSIN
+ { 190, 205, 224 }, /* Use mage xpositions for now */
+#endif
+ { 0, 0, 0 } /* Pig is never used */
+};
+
+static void DrawWeaponPieces(void)
+{
+ if (CPlayer->pieces == 7)
+ {
+ V_DrawPatch(190, 162, PatchWEAPONFULL);
+ return;
+ }
+ V_DrawPatch(190, 162, PatchWEAPONSLOT);
+ if (CPlayer->pieces & WPIECE1)
+ {
+ V_DrawPatch(PieceX[PlayerClasses[consoleplayer]][0], 162, PatchPIECE1);
+ }
+ if (CPlayer->pieces & WPIECE2)
+ {
+ V_DrawPatch(PieceX[PlayerClasses[consoleplayer]][1], 162, PatchPIECE2);
+ }
+ if (CPlayer->pieces & WPIECE3)
+ {
+ V_DrawPatch(PieceX[PlayerClasses[consoleplayer]][2], 162, PatchPIECE3);
+ }
+}
+
+//==========================================================================
+//
+// DrawFullScreenStuff
+//
+//==========================================================================
+
+void DrawFullScreenStuff(void)
+{
+ int i;
+ int x;
+ int temp;
+
+ UpdateState |= I_FULLSCRN;
+ if (CPlayer->mo->health > 0)
+ {
+ DrBNumber(CPlayer->mo->health, 5, 180);
+ }
+ else
+ {
+ DrBNumber(0, 5, 180);
+ }
+ if (deathmatch)
+ {
+ temp = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ temp += CPlayer->frags[i];
+ }
+ }
+ DrINumber(temp, 45, 185);
+ }
+ if (!inventory)
+ {
+ if (CPlayer->readyArtifact > 0)
+ {
+ V_DrawFuzzPatch(286, 170, (PATCH_REF)WR_CacheLumpName("ARTIBOX", PU_CACHE));
+ V_DrawPatch(284, 169, (PATCH_REF)WR_CacheLumpName(patcharti[CPlayer->readyArtifact], PU_CACHE));
+ if (CPlayer->inventory[inv_ptr].count > 1)
+ {
+ DrSmallNumber(CPlayer->inventory[inv_ptr].count, 302, 192);
+ }
+ }
+ }
+ else
+ {
+ x = inv_ptr - curpos;
+ for (i = 0; i < 7; i++)
+ {
+ V_DrawFuzzPatch(50 + i*31, 168, (PATCH_REF)WR_CacheLumpName("ARTIBOX", PU_CACHE));
+ if (CPlayer->inventorySlotNum > x + i
+ && CPlayer->inventory[x + i].type != arti_none)
+ {
+ V_DrawPatch(49 + i*31, 167, (PATCH_REF)WR_CacheLumpName(patcharti[CPlayer->inventory[x + i].type], PU_CACHE));
+ if (CPlayer->inventory[x + i].count > 1)
+ {
+ DrSmallNumber(CPlayer->inventory[x + i].count, 66 + i*31, 188);
+ }
+ }
+ }
+ V_DrawPatch(50 + curpos*31, 167, PatchSELECTBOX);
+ if (x != 0)
+ {
+ V_DrawPatch(40, 167, !(leveltime & 4) ? PatchINVLFGEM1 : PatchINVLFGEM2);
+ }
+ if (CPlayer->inventorySlotNum - x > 7)
+ {
+ V_DrawPatch(268, 167, !(leveltime & 4) ? PatchINVRTGEM1 : PatchINVRTGEM2);
+ }
+ }
+}
+
+
+//==========================================================================
+//
+// Draw_TeleportIcon
+//
+//==========================================================================
+void Draw_TeleportIcon(void)
+{
+ PATCH_REF patch;
+ patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("teleicon"), PU_CACHE);
+ V_DrawPatch(100, 68, patch);
+ UpdateState |= I_FULLSCRN;
+ I_Update();
+ UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// Draw_SaveIcon
+//
+//==========================================================================
+
+void Draw_SaveIcon(void)
+{
+ PATCH_REF patch;
+ patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("saveicon"), PU_CACHE);
+ V_DrawPatch(100, 68, patch);
+ UpdateState |= I_FULLSCRN;
+ I_Update();
+ UpdateState |= I_FULLSCRN;
+}
+
+//==========================================================================
+//
+// Draw_LoadIcon
+//
+//==========================================================================
+
+void Draw_LoadIcon(void)
+{
+ PATCH_REF patch;
+ patch = (PATCH_REF) WR_CacheLumpNum(W_GetNumForName("loadicon"), PU_CACHE);
+ V_DrawPatch(100, 68, patch);
+ UpdateState |= I_FULLSCRN;
+ I_Update();
+ UpdateState |= I_FULLSCRN;
+}
+
+
+//==========================================================================
+//
+// SB_Responder
+//
+//==========================================================================
+
+boolean SB_Responder(event_t *event)
+{
+ if (event->type == ev_keydown)
+ {
+ if (HandleCheats(event->data1))
+ { // Need to eat the key
+ return true;
+ }
+ }
+ return false;
+}
+
+//==========================================================================
+//
+// HandleCheats
+//
+// Returns true if the caller should eat the key.
+//
+//==========================================================================
+
+static boolean HandleCheats(byte key)
+{
+ int i;
+ boolean eat;
+
+ if (gameskill == sk_nightmare)
+ { // Can't cheat in nightmare mode
+ return false;
+ }
+ else if (netgame)
+ { // change CD track is the only cheat available in deathmatch
+ eat = false;
+ if (i_CDMusic && cdaudio)
+ {
+ if (CheatAddKey(&Cheats[0], key, &eat))
+ {
+ Cheats[0].func(&players[consoleplayer], &Cheats[0]);
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ }
+ if (CheatAddKey(&Cheats[1], key, &eat))
+ {
+ Cheats[1].func(&players[consoleplayer], &Cheats[1]);
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ }
+ }
+ return eat;
+ }
+ if (players[consoleplayer].health <= 0)
+ { // Dead players can't cheat
+ return false;
+ }
+ eat = false;
+ for (i = 0; Cheats[i].func != NULL; i++)
+ {
+ if (CheatAddKey(&Cheats[i], key, &eat))
+ {
+ Cheats[i].func(&players[consoleplayer], &Cheats[i]);
+ S_StartSound(NULL, SFX_PLATFORM_STOP);
+ }
+ }
+ return eat;
+}
+
+//==========================================================================
+//
+// CheatAddkey
+//
+// Returns true if the added key completed the cheat, false otherwise.
+//
+//==========================================================================
+
+static boolean CheatAddKey(Cheat_t *cheat, byte key, boolean *eat)
+{
+ if (!cheat->pos)
+ {
+ cheat->pos = cheat->sequence;
+ cheat->currentArg = 0;
+ }
+ if (*cheat->pos == 0)
+ {
+ *eat = true;
+ cheat->args[cheat->currentArg++] = key;
+ cheat->pos++;
+ }
+ else if (CheatLookup[key] == *cheat->pos)
+ {
+ cheat->pos++;
+ }
+ else
+ {
+ cheat->pos = cheat->sequence;
+ cheat->currentArg = 0;
+ }
+ if (*cheat->pos == 0xff)
+ {
+ cheat->pos = cheat->sequence;
+ cheat->currentArg = 0;
+ return true;
+ }
+ return false;
+}
+
+//==========================================================================
+//
+// CHEAT FUNCTIONS
+//
+//==========================================================================
+
+static void CheatGodFunc(player_t *player, Cheat_t *cheat)
+{
+ player->cheats ^= CF_GODMODE;
+ if (player->cheats & CF_GODMODE)
+ {
+ P_SetMessage(player, TXT_CHEATGODON, true);
+ }
+ else
+ {
+ P_SetMessage(player, TXT_CHEATGODOFF, true);
+ }
+ SB_state = -1;
+}
+
+static void CheatNoClipFunc(player_t *player, Cheat_t *cheat)
+{
+ player->cheats ^= CF_NOCLIP;
+ if (player->cheats & CF_NOCLIP)
+ {
+ P_SetMessage(player, TXT_CHEATNOCLIPON, true);
+ }
+ else
+ {
+ P_SetMessage(player, TXT_CHEATNOCLIPOFF, true);
+ }
+}
+
+static void CheatWeaponsFunc(player_t *player, Cheat_t *cheat)
+{
+ int i;
+ //extern boolean *WeaponInShareware;
+
+ for (i = 0; i < NUMARMOR; i++)
+ {
+ player->armorpoints[i] = ArmorIncrement[player->playerclass][i];
+ }
+ for (i = 0; i < NUMWEAPONS; i++)
+ {
+ player->weaponowned[i] = true;
+ }
+ for (i = 0; i < NUMMANA; i++)
+ {
+ player->mana[i] = MAX_MANA;
+ }
+ P_SetMessage(player, TXT_CHEATWEAPONS, true);
+}
+
+static void CheatHealthFunc(player_t *player, Cheat_t *cheat)
+{
+ if (player->morphTics)
+ {
+ player->health = player->mo->health = MAXMORPHHEALTH;
+ }
+ else
+ {
+ player->health = player->mo->health = MAXHEALTH;
+ }
+ P_SetMessage(player, TXT_CHEATHEALTH, true);
+}
+
+static void CheatKeysFunc(player_t *player, Cheat_t *cheat)
+{
+ player->keys = 2047;
+ P_SetMessage(player, TXT_CHEATKEYS, true);
+}
+
+static void CheatSoundFunc(player_t *player, Cheat_t *cheat)
+{
+ DebugSound = !DebugSound;
+ if (DebugSound)
+ {
+ P_SetMessage(player, TXT_CHEATSOUNDON, true);
+ }
+ else
+ {
+ P_SetMessage(player, TXT_CHEATSOUNDOFF, true);
+ }
+}
+
+static void CheatTickerFunc(player_t *player, Cheat_t *cheat)
+{
+ extern int DisplayTicker;
+
+ DisplayTicker = !DisplayTicker;
+ if (DisplayTicker)
+ {
+ P_SetMessage(player, TXT_CHEATTICKERON, true);
+ }
+ else
+ {
+ P_SetMessage(player, TXT_CHEATTICKEROFF, true);
+ }
+}
+
+static void CheatArtifactAllFunc(player_t *player, Cheat_t *cheat)
+{
+ int i;
+ int j;
+
+ for (i = arti_none + 1; i < arti_firstpuzzitem; i++)
+ {
+ for (j = 0; j < 25; j++)
+ {
+ P_GiveArtifact(player, i, NULL);
+ }
+ }
+ P_SetMessage(player, TXT_CHEATARTIFACTS3, true);
+}
+
+static void CheatPuzzleFunc(player_t *player, Cheat_t *cheat)
+{
+ int i;
+
+ for (i = arti_firstpuzzitem; i < NUMARTIFACTS; i++)
+ {
+ P_GiveArtifact(player, i, NULL);
+ }
+ P_SetMessage(player, TXT_CHEATARTIFACTS3, true);
+}
+
+static void CheatInitFunc(player_t *player, Cheat_t *cheat)
+{
+ G_DeferedInitNew(gameskill, gameepisode, gamemap);
+ P_SetMessage(player, TXT_CHEATWARP, true);
+}
+
+static void CheatWarpFunc(player_t *player, Cheat_t *cheat)
+{
+ int tens;
+ int ones;
+ int map;
+ char mapName[9];
+ char auxName[MAX_OSPATH];
+ FILE *fp;
+
+ tens = cheat->args[0] - '0';
+ ones = cheat->args[1] - '0';
+ if (tens < 0 || tens > 9 || ones < 0 || ones > 9)
+ { // Bad map
+ P_SetMessage(player, TXT_CHEATBADINPUT, true);
+ return;
+ }
+ map = P_TranslateMap((cheat->args[0] - '0')*10 + cheat->args[1] - '0');
+ if (map == -1)
+ { // Not found
+ P_SetMessage(player, TXT_CHEATNOMAP, true);
+ return;
+ }
+ if (map == gamemap)
+ { // Don't try to teleport to current map
+ P_SetMessage(player, TXT_CHEATBADINPUT, true);
+ return;
+ }
+ if (DevMaps)
+ { // Search map development directory
+ snprintf(auxName, sizeof(auxName), "%smap%02d.wad", DevMapsDir, map);
+ fp = fopen(auxName, "rb");
+ if (fp)
+ {
+ fclose(fp);
+ }
+ else
+ { // Can't find
+ P_SetMessage(player, TXT_CHEATNOMAP, true);
+ return;
+ }
+ }
+ else
+ { // Search primary lumps
+ snprintf(mapName, sizeof(mapName), "MAP%02d", map);
+ if (W_CheckNumForName(mapName) == -1)
+ { // Can't find
+ P_SetMessage(player, TXT_CHEATNOMAP, true);
+ return;
+ }
+ }
+ P_SetMessage(player, TXT_CHEATWARP, true);
+ G_TeleportNewMap(map, 0);
+}
+
+static void CheatPigFunc(player_t *player, Cheat_t *cheat)
+{
+ if (player->morphTics)
+ {
+ P_UndoPlayerMorph(player);
+ }
+ else
+ {
+ P_MorphPlayer(player);
+ }
+ P_SetMessage(player, "SQUEAL!!", true);
+}
+
+static void CheatMassacreFunc(player_t *player, Cheat_t *cheat)
+{
+ int count;
+ char buffer[80];
+
+ count = P_Massacre();
+ snprintf(buffer, sizeof(buffer), "%d MONSTERS KILLED\n", count);
+ P_SetMessage(player, buffer, true);
+}
+
+static void CheatIDKFAFunc(player_t *player, Cheat_t *cheat)
+{
+ int i;
+ if (player->morphTics)
+ {
+ return;
+ }
+ for (i = 1; i < NUMWEAPONS; i++)
+ {
+ player->weaponowned[i] = false;
+ }
+ player->pendingweapon = WP_FIRST;
+ P_SetMessage(player, TXT_CHEATIDKFA, true);
+}
+
+static void CheatQuickenFunc1(player_t *player, Cheat_t *cheat)
+{
+ P_SetMessage(player, "TRYING TO CHEAT? THAT'S ONE....", true);
+}
+
+static void CheatQuickenFunc2(player_t *player, Cheat_t *cheat)
+{
+ P_SetMessage(player, "THAT'S TWO....", true);
+}
+
+static void CheatQuickenFunc3(player_t *player, Cheat_t *cheat)
+{
+ P_DamageMobj(player->mo, NULL, player->mo, 10000);
+ P_SetMessage(player, "THAT'S THREE! TIME TO DIE.", true);
+}
+
+static void CheatClassFunc1(player_t *player, Cheat_t *cheat)
+{
+/* P_SetMessage isn't variably arg'ed: set the messages by hand: */
+#ifdef ASSASSIN
+ P_SetMessage(player, "ENTER NEW PLAYER CLASS (0 - 3)", true);
+#else
+ P_SetMessage(player, "ENTER NEW PLAYER CLASS (0 - 2)", true);
+#endif
+}
+
+static void CheatClassFunc2(player_t *player, Cheat_t *cheat)
+{
+ int i;
+ int pClass;
+
+ if (player->morphTics)
+ { // don't change class if the player is morphed
+ return;
+ }
+ pClass = cheat->args[0] - '0';
+ if (pClass > NUMCLASSES_HUMAN - 1 || pClass < 0)
+ {
+ P_SetMessage(player, "INVALID PLAYER CLASS", true);
+ return;
+ }
+ player->playerclass = pClass;
+ for (i = 0; i < NUMARMOR; i++)
+ {
+ player->armorpoints[i] = 0;
+ }
+ PlayerClasses[consoleplayer] = pClass;
+ P_PostMorphWeapon(player, WP_FIRST);
+ SB_SetClassData();
+ SB_state = -1;
+ UpdateState |= I_FULLSCRN;
+}
+
+static void CheatVersionFunc(player_t *player, Cheat_t *cheat)
+{
+ P_SetMessage(player, VERSIONTEXT, true);
+}
+
+static void CheatDebugFunc(player_t *player, Cheat_t *cheat)
+{
+ char textBuffer[50];
+ snprintf(textBuffer, sizeof(textBuffer), "MAP %d (%d) X:%5d Y:%5d Z:%5d",
+ P_GetMapWarpTrans(gamemap),
+ gamemap,
+ player->mo->x >> FRACBITS,
+ player->mo->y >> FRACBITS,
+ player->mo->z >> FRACBITS);
+ P_SetMessage(player, textBuffer, true);
+}
+
+static void CheatScriptFunc1(player_t *player, Cheat_t *cheat)
+{
+ P_SetMessage(player, "RUN WHICH SCRIPT(01-99)?", true);
+}
+
+static void CheatScriptFunc2(player_t *player, Cheat_t *cheat)
+{
+ P_SetMessage(player, "RUN WHICH SCRIPT(01-99)?", true);
+}
+
+static void CheatScriptFunc3(player_t *player, Cheat_t *cheat)
+{
+ int script;
+ byte args[3];
+ int tens, ones;
+ char textBuffer[40];
+
+ tens = cheat->args[0] - '0';
+ ones = cheat->args[1] - '0';
+ script = tens*10 + ones;
+ if (script < 1)
+ return;
+ if (script > 99)
+ return;
+ args[0] = args[1] = args[2] = 0;
+
+ if (P_StartACS(script, 0, args, player->mo, NULL, 0))
+ {
+ snprintf(textBuffer, sizeof(textBuffer), "RUNNING SCRIPT %.2d", script);
+ P_SetMessage(player, textBuffer, true);
+ }
+}
+
+extern int cheating;
+
+static void CheatRevealFunc(player_t *player, Cheat_t *cheat)
+{
+ cheating = (cheating + 1) % 3;
+}
+
+//===========================================================================
+//
+// CheatTrackFunc1
+//
+//===========================================================================
+
+static void CheatTrackFunc1(player_t *player, Cheat_t *cheat)
+{
+ char buffer[80];
+
+ if (!i_CDMusic || !cdaudio)
+ {
+ return;
+ }
+ snprintf(buffer, sizeof(buffer), "ENTER DESIRED CD TRACK (%.2d - %.2d):\n",
+ I_CDMusFirstTrack(), I_CDMusLastTrack());
+ P_SetMessage(player, buffer, true);
+}
+
+//===========================================================================
+//
+// CheatTrackFunc2
+//
+//===========================================================================
+
+static void CheatTrackFunc2(player_t *player, Cheat_t *cheat)
+{
+ char buffer[80];
+ int track;
+
+ if (!i_CDMusic || !cdaudio)
+ {
+ return;
+ }
+ track = (cheat->args[0] - '0') * 10 + (cheat->args[1] - '0');
+ if (track < I_CDMusFirstTrack() || track > I_CDMusLastTrack())
+ {
+ P_SetMessage(player, "INVALID TRACK NUMBER\n", true);
+ return;
+ }
+ if (track == i_CDCurrentTrack)
+ {
+ return;
+ }
+ if (I_CDMusPlay(track))
+ {
+ snprintf(buffer, sizeof(buffer), "ERROR WHILE TRYING TO PLAY CD TRACK: %.2d\n", track);
+ P_SetMessage(player, buffer, true);
+ }
+ else
+ { // No error encountered while attempting to play the track
+ snprintf(buffer, sizeof(buffer), "PLAYING TRACK: %.2d\n", track);
+ P_SetMessage(player, buffer, true);
+ // i_CDMusicLength = 35*I_CDMusTrackLength(track);
+ // oldTic = gametic;
+ i_CDTrack = track;
+ i_CDCurrentTrack = track;
+ }
+}
+
--- /dev/null
+++ b/sc_man.c
@@ -1,0 +1,482 @@
+
+//**************************************************************************
+//**
+//** sc_man.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_STRING_SIZE 64
+#define ASCII_COMMENT (';')
+#define ASCII_QUOTE (34)
+#define LUMP_SCRIPT 1
+#define FILE_ZONE_SCRIPT 2
+#define FILE_CLIB_SCRIPT 3
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void CheckOpen(void);
+static void OpenScript(const char *name, int type);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+char *sc_String;
+int sc_Number;
+int sc_Line;
+boolean sc_End;
+boolean sc_Crossed;
+boolean sc_FileScripts = false;
+const char *sc_ScriptsDir = ""; // "scripts/";
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static char ScriptName[16];
+static void *ScriptBuffer;
+static char *ScriptPtr;
+static char *ScriptEndPtr;
+static char StringBuffer[MAX_STRING_SIZE];
+static boolean ScriptOpen = false;
+static boolean ScriptFreeCLib; // true = de-allocate using free()
+static int ScriptSize;
+static boolean AlreadyGot = false;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// SC_Open
+//
+//==========================================================================
+
+void SC_Open(const char *name)
+{
+ char fileName[MAX_OSPATH];
+
+ if (sc_FileScripts == true)
+ {
+ sprintf(fileName, "%s%s.txt", sc_ScriptsDir, name);
+ SC_OpenFile(fileName);
+ }
+ else
+ {
+ SC_OpenLump(name);
+ }
+}
+
+//==========================================================================
+//
+// SC_OpenLump
+//
+// Loads a script (from the WAD files) and prepares it for parsing.
+//
+//==========================================================================
+
+void SC_OpenLump(const char *name)
+{
+ OpenScript(name, LUMP_SCRIPT);
+}
+
+//==========================================================================
+//
+// SC_OpenFile
+//
+// Loads a script (from a file) and prepares it for parsing. Uses the
+// zone memory allocator for memory allocation and de-allocation.
+//
+//==========================================================================
+
+void SC_OpenFile(const char *name)
+{
+ OpenScript(name, FILE_ZONE_SCRIPT);
+}
+
+//==========================================================================
+//
+// SC_OpenFileCLib
+//
+// Loads a script (from a file) and prepares it for parsing. Uses C
+// library function calls for memory allocation and de-allocation.
+//
+//==========================================================================
+
+void SC_OpenFileCLib(const char *name)
+{
+ OpenScript(name, FILE_CLIB_SCRIPT);
+}
+
+//==========================================================================
+//
+// OpenScript
+//
+//==========================================================================
+
+static void OpenScript(const char *name, int type)
+{
+ SC_Close();
+ if (type == LUMP_SCRIPT)
+ { // Lump script
+ ScriptBuffer = W_CacheLumpName(name, PU_STATIC);
+ ScriptSize = W_LumpLength(W_GetNumForName(name));
+ strcpy(ScriptName, name);
+ ScriptFreeCLib = false; // De-allocate using Z_Free()
+ }
+ else if (type == FILE_ZONE_SCRIPT)
+ { // File script - zone
+ ScriptSize = M_ReadFile(name, &ScriptBuffer);
+ M_ExtractFileBase(name, ScriptName);
+ ScriptFreeCLib = false; // De-allocate using Z_Free()
+ }
+ else
+ { // File script - clib
+ ScriptSize = M_ReadFileCLib(name, &ScriptBuffer);
+ M_ExtractFileBase(name, ScriptName);
+ ScriptFreeCLib = true; // De-allocate using free()
+ }
+ ScriptPtr = (char *) ScriptBuffer;
+ ScriptEndPtr = ScriptPtr+ScriptSize;
+ sc_Line = 1;
+ sc_End = false;
+ ScriptOpen = true;
+ sc_String = StringBuffer;
+ AlreadyGot = false;
+}
+
+//==========================================================================
+//
+// SC_Close
+//
+//==========================================================================
+
+void SC_Close(void)
+{
+ if (ScriptOpen)
+ {
+ if (ScriptFreeCLib == true)
+ {
+ free(ScriptBuffer);
+ }
+ else
+ {
+ Z_Free(ScriptBuffer);
+ }
+ ScriptOpen = false;
+ }
+}
+
+//==========================================================================
+//
+// SC_GetString
+//
+//==========================================================================
+
+boolean SC_GetString(void)
+{
+ char *text;
+ boolean foundToken;
+
+ CheckOpen();
+ if (AlreadyGot)
+ {
+ AlreadyGot = false;
+ return true;
+ }
+ foundToken = false;
+ sc_Crossed = false;
+ if (ScriptPtr >= ScriptEndPtr)
+ {
+ sc_End = true;
+ return false;
+ }
+ while (foundToken == false)
+ {
+ while (*ScriptPtr <= 32)
+ {
+ if (ScriptPtr >= ScriptEndPtr)
+ {
+ sc_End = true;
+ return false;
+ }
+ if (*ScriptPtr++ == '\n')
+ {
+ sc_Line++;
+ sc_Crossed = true;
+ }
+ }
+ if (ScriptPtr >= ScriptEndPtr)
+ {
+ sc_End = true;
+ return false;
+ }
+ if (*ScriptPtr != ASCII_COMMENT)
+ { // Found a token
+ foundToken = true;
+ }
+ else
+ { // Skip comment
+ while (*ScriptPtr++ != '\n')
+ {
+ if (ScriptPtr >= ScriptEndPtr)
+ {
+ sc_End = true;
+ return false;
+ }
+ }
+ sc_Line++;
+ sc_Crossed = true;
+ }
+ }
+ text = sc_String;
+ if (*ScriptPtr == ASCII_QUOTE)
+ { // Quoted string
+ ScriptPtr++;
+ while (*ScriptPtr != ASCII_QUOTE)
+ {
+ *text++ = *ScriptPtr++;
+ if (ScriptPtr == ScriptEndPtr
+ || text == &sc_String[MAX_STRING_SIZE-1])
+ {
+ break;
+ }
+ }
+ ScriptPtr++;
+ }
+ else
+ { // Normal string
+ while ((*ScriptPtr > 32) && (*ScriptPtr != ASCII_COMMENT))
+ {
+ *text++ = *ScriptPtr++;
+ if (ScriptPtr == ScriptEndPtr
+ || text == &sc_String[MAX_STRING_SIZE-1])
+ {
+ break;
+ }
+ }
+ }
+ *text = 0;
+ return true;
+}
+
+//==========================================================================
+//
+// SC_MustGetString
+//
+//==========================================================================
+
+void SC_MustGetString(void)
+{
+ if (SC_GetString() == false)
+ {
+ SC_ScriptError("Missing string.");
+ }
+}
+
+//==========================================================================
+//
+// SC_MustGetStringName
+//
+//==========================================================================
+
+void SC_MustGetStringName(const char *name)
+{
+ SC_MustGetString();
+ if (SC_Compare(name) == false)
+ {
+ SC_ScriptError(NULL);
+ }
+}
+
+//==========================================================================
+//
+// SC_GetNumber
+//
+//==========================================================================
+
+boolean SC_GetNumber(void)
+{
+ char *stopper;
+
+ CheckOpen();
+ if (SC_GetString())
+ {
+ sc_Number = strtol(sc_String, &stopper, 0);
+ if (*stopper != 0)
+ {
+ I_Error("SC_GetNumber: Bad numeric constant \"%s\".\n"
+ "Script %s, Line %d", sc_String, ScriptName, sc_Line);
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//==========================================================================
+//
+// SC_MustGetNumber
+//
+//==========================================================================
+
+void SC_MustGetNumber(void)
+{
+ if (SC_GetNumber() == false)
+ {
+ SC_ScriptError("Missing integer.");
+ }
+}
+
+//==========================================================================
+//
+// SC_UnGet
+//
+// Assumes there is a valid string in sc_String.
+//
+//==========================================================================
+
+void SC_UnGet(void)
+{
+ AlreadyGot = true;
+}
+
+//==========================================================================
+//
+// SC_Check
+//
+// Returns true if another token is on the current line.
+//
+//==========================================================================
+
+/*
+boolean SC_Check(void)
+{
+ char *text;
+
+ CheckOpen();
+ text = ScriptPtr;
+ if (text >= ScriptEndPtr)
+ {
+ return false;
+ }
+ while (*text <= 32)
+ {
+ if (*text == '\n')
+ {
+ return false;
+ }
+ text++;
+ if (text == ScriptEndPtr)
+ {
+ return false;
+ }
+ }
+ if (*text == ASCII_COMMENT)
+ {
+ return false;
+ }
+ return true;
+}
+*/
+
+//==========================================================================
+//
+// SC_MatchString
+//
+// Returns the index of the first match to sc_String from the passed
+// array of strings, or -1 if not found.
+//
+//==========================================================================
+
+int SC_MatchString(const char **strings)
+{
+ int i;
+
+ for (i = 0; *strings != NULL; i++)
+ {
+ if (SC_Compare(*strings++))
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+//==========================================================================
+//
+// SC_MustMatchString
+//
+//==========================================================================
+
+int SC_MustMatchString(const char **strings)
+{
+ int i;
+
+ i = SC_MatchString(strings);
+ if (i == -1)
+ {
+ SC_ScriptError(NULL);
+ }
+ return i;
+}
+
+//==========================================================================
+//
+// SC_Compare
+//
+//==========================================================================
+
+boolean SC_Compare(const char *text)
+{
+ if (strcasecmp(text, sc_String) == 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+//==========================================================================
+//
+// SC_ScriptError
+//
+//==========================================================================
+
+void SC_ScriptError(const char *message)
+{
+ if (message == NULL)
+ {
+ message = "Bad syntax.";
+ }
+ I_Error("Script error, \"%s\" line %d: %s", ScriptName, sc_Line, message);
+}
+
+//==========================================================================
+//
+// CheckOpen
+//
+//==========================================================================
+
+static void CheckOpen(void)
+{
+ if (ScriptOpen == false)
+ {
+ I_Error("SC_ call before SC_Open().");
+ }
+}
+
--- /dev/null
+++ b/sn_sonix.c
@@ -1,0 +1,502 @@
+
+//**************************************************************************
+//**
+//** sn_sonix.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "soundst.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define SS_MAX_SCRIPTS 64
+#define SS_TEMPBUFFER_SIZE 1024
+#define SS_SEQUENCE_NAME_LENGTH 32
+
+#define SS_SCRIPT_NAME "SNDSEQ"
+#define SS_STRING_PLAY "play"
+#define SS_STRING_PLAYUNTILDONE "playuntildone"
+#define SS_STRING_PLAYTIME "playtime"
+#define SS_STRING_PLAYREPEAT "playrepeat"
+#define SS_STRING_DELAY "delay"
+#define SS_STRING_DELAYRAND "delayrand"
+#define SS_STRING_VOLUME "volume"
+#define SS_STRING_END "end"
+#define SS_STRING_STOPSOUND "stopsound"
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+ SS_CMD_NONE,
+ SS_CMD_PLAY,
+ SS_CMD_WAITUNTILDONE, /* used by PLAYUNTILDONE */
+ SS_CMD_PLAYTIME,
+ SS_CMD_PLAYREPEAT,
+ SS_CMD_DELAY,
+ SS_CMD_DELAYRAND,
+ SS_CMD_VOLUME,
+ SS_CMD_STOPSOUND,
+ SS_CMD_END
+} sscmds_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void VerifySequencePtr(int *base, int *ptr);
+static int GetSoundOffset(const char *name);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern sfxinfo_t S_sfx[];
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static struct
+{
+ const char name[SS_SEQUENCE_NAME_LENGTH];
+ int scriptNum;
+ int stopSound;
+} SequenceTranslate[SEQ_NUMSEQ] =
+{
+ { "Platform", 0, 0 },
+ { "Platform", 0, 0 }, /* a 'heavy' platform is just a platform */
+ { "PlatformMetal", 0, 0 },
+ { "Platform", 0, 0 }, /* same with a 'creak' platform */
+ { "Silence", 0, 0 },
+ { "Lava", 0, 0 },
+ { "Water", 0, 0 },
+ { "Ice", 0, 0 },
+ { "Earth", 0, 0 },
+ { "PlatformMetal2", 0, 0 },
+ { "DoorNormal", 0, 0 },
+ { "DoorHeavy", 0, 0 },
+ { "DoorMetal", 0, 0 },
+ { "DoorCreak", 0, 0 },
+ { "Silence", 0, 0 },
+ { "Lava", 0, 0 },
+ { "Water", 0, 0},
+ { "Ice", 0, 0 },
+ { "Earth", 0, 0},
+ { "DoorMetal2", 0, 0 },
+ { "Wind", 0, 0 }
+};
+
+static int *SequenceData[SS_MAX_SCRIPTS];
+
+int ActiveSequences;
+seqnode_t *SequenceListHead;
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+// VerifySequencePtr
+//
+// Verifies the integrity of the temporary ptr, and ensures that the ptr
+// isn't exceeding the size of the temporary buffer
+//==========================================================================
+
+static void VerifySequencePtr(int *base, int *ptr)
+{
+ if (ptr-base > SS_TEMPBUFFER_SIZE)
+ {
+ I_Error("VerifySequencePtr: tempPtr >= %d\n", SS_TEMPBUFFER_SIZE);
+ }
+}
+
+//==========================================================================
+//
+// GetSoundOffset
+//
+//==========================================================================
+
+static int GetSoundOffset(const char *name)
+{
+ int i;
+
+ for (i = 0; i < NUMSFX; i++)
+ {
+ if (!strcasecmp(name, S_sfx[i].tagName))
+ {
+ return i;
+ }
+ }
+ SC_ScriptError("GetSoundOffset: Unknown sound name\n");
+ return 0;
+}
+
+//==========================================================================
+//
+// SN_InitSequenceScript
+//
+//==========================================================================
+
+void SN_InitSequenceScript(void)
+{
+ int i, j;
+ int inSequence;
+ int *tempDataStart = NULL; /* jim added initialiser */
+ int *tempDataPtr = NULL; /* jim added initialiser */
+
+ inSequence = -1;
+ ActiveSequences = 0;
+ for (i = 0; i < SS_MAX_SCRIPTS; i++)
+ {
+ SequenceData[i] = NULL;
+ }
+ SC_Open(SS_SCRIPT_NAME);
+ while (SC_GetString())
+ {
+ if (*sc_String == ':')
+ {
+ if (inSequence != -1)
+ {
+ SC_ScriptError("SN_InitSequenceScript: Nested Script Error");
+ }
+ tempDataStart = (int *)Z_Malloc(SS_TEMPBUFFER_SIZE, PU_STATIC, NULL);
+ memset(tempDataStart, 0, SS_TEMPBUFFER_SIZE);
+ tempDataPtr = tempDataStart;
+ for (i = 0; i < SS_MAX_SCRIPTS; i++)
+ {
+ if (SequenceData[i] == NULL)
+ {
+ break;
+ }
+ }
+ if (i == SS_MAX_SCRIPTS)
+ {
+ I_Error("Number of SS Scripts >= SS_MAX_SCRIPTS");
+ }
+ for (j = 0; j < SEQ_NUMSEQ; j++)
+ {
+ if (!strcasecmp(SequenceTranslate[j].name, sc_String+1))
+ {
+ SequenceTranslate[j].scriptNum = i;
+ inSequence = j;
+ break;
+ }
+ }
+ continue; // parse the next command
+ }
+ if (inSequence == -1)
+ {
+ continue;
+ }
+ if (SC_Compare(SS_STRING_PLAYUNTILDONE))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ SC_MustGetString();
+ *tempDataPtr++ = SS_CMD_PLAY;
+ *tempDataPtr++ = GetSoundOffset(sc_String);
+ *tempDataPtr++ = SS_CMD_WAITUNTILDONE;
+ }
+ else if (SC_Compare(SS_STRING_PLAY))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ SC_MustGetString();
+ *tempDataPtr++ = SS_CMD_PLAY;
+ *tempDataPtr++ = GetSoundOffset(sc_String);
+ }
+ else if (SC_Compare(SS_STRING_PLAYTIME))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ SC_MustGetString();
+ *tempDataPtr++ = SS_CMD_PLAY;
+ *tempDataPtr++ = GetSoundOffset(sc_String);
+ SC_MustGetNumber();
+ *tempDataPtr++ = SS_CMD_DELAY;
+ *tempDataPtr++ = sc_Number;
+ }
+ else if (SC_Compare(SS_STRING_PLAYREPEAT))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ SC_MustGetString();
+ *tempDataPtr++ = SS_CMD_PLAYREPEAT;
+ *tempDataPtr++ = GetSoundOffset(sc_String);
+ }
+ else if (SC_Compare(SS_STRING_DELAY))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ *tempDataPtr++ = SS_CMD_DELAY;
+ SC_MustGetNumber();
+ *tempDataPtr++ = sc_Number;
+ }
+ else if (SC_Compare(SS_STRING_DELAYRAND))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ *tempDataPtr++ = SS_CMD_DELAYRAND;
+ SC_MustGetNumber();
+ *tempDataPtr++ = sc_Number;
+ SC_MustGetNumber();
+ *tempDataPtr++ = sc_Number;
+ }
+ else if (SC_Compare(SS_STRING_VOLUME))
+ {
+ VerifySequencePtr(tempDataStart, tempDataPtr);
+ *tempDataPtr++ = SS_CMD_VOLUME;
+ SC_MustGetNumber();
+ *tempDataPtr++ = sc_Number;
+ }
+ else if (SC_Compare(SS_STRING_END))
+ {
+ int dataSize;
+
+ *tempDataPtr++ = SS_CMD_END;
+ dataSize = (tempDataPtr - tempDataStart) * sizeof(int);
+ SequenceData[i] = (int *)Z_Malloc(dataSize, PU_STATIC, NULL);
+ memcpy(SequenceData[i], tempDataStart, dataSize);
+ Z_Free(tempDataStart);
+ inSequence = -1;
+ }
+ else if (SC_Compare(SS_STRING_STOPSOUND))
+ {
+ SC_MustGetString();
+ SequenceTranslate[inSequence].stopSound = GetSoundOffset(sc_String);
+ *tempDataPtr++ = SS_CMD_STOPSOUND;
+ }
+ else
+ {
+ SC_ScriptError("SN_InitSequenceScript: Unknown commmand.\n");
+ }
+ }
+}
+
+//==========================================================================
+//
+// SN_StartSequence
+//
+//==========================================================================
+
+void SN_StartSequence(mobj_t *mobj, int sequence)
+{
+ seqnode_t *node;
+
+ SN_StopSequence(mobj); // Stop any previous sequence
+ node = (seqnode_t *)Z_Malloc(sizeof(seqnode_t), PU_STATIC, NULL);
+ node->sequencePtr = SequenceData[SequenceTranslate[sequence].scriptNum];
+ node->sequence = sequence;
+ node->mobj = mobj;
+ node->delayTics = 0;
+ node->stopSound = SequenceTranslate[sequence].stopSound;
+ node->volume = 127; // Start at max volume
+
+ if (!SequenceListHead)
+ {
+ SequenceListHead = node;
+ node->next = node->prev = NULL;
+ }
+ else
+ {
+ SequenceListHead->prev = node;
+ node->next = SequenceListHead;
+ node->prev = NULL;
+ SequenceListHead = node;
+ }
+ ActiveSequences++;
+ return;
+}
+
+//==========================================================================
+//
+// SN_StartSequenceName
+//
+//==========================================================================
+
+void SN_StartSequenceName(mobj_t *mobj, const char *name)
+{
+ int i;
+
+ for (i = 0; i < SEQ_NUMSEQ; i++)
+ {
+ if (!strcmp(name, SequenceTranslate[i].name))
+ {
+ SN_StartSequence(mobj, i);
+ return;
+ }
+ }
+}
+
+//==========================================================================
+//
+// SN_StopSequence
+//
+//==========================================================================
+
+void SN_StopSequence(mobj_t *mobj)
+{
+ seqnode_t *node;
+
+ for (node = SequenceListHead; node; node = node->next)
+ {
+ if (node->mobj == mobj)
+ {
+ S_StopSound(mobj);
+ if (node->stopSound)
+ {
+ S_StartSoundAtVolume(mobj, node->stopSound, node->volume);
+ }
+ if (SequenceListHead == node)
+ {
+ SequenceListHead = node->next;
+ }
+ if (node->prev)
+ {
+ node->prev->next = node->next;
+ }
+ if (node->next)
+ {
+ node->next->prev = node->prev;
+ }
+ Z_Free(node);
+ ActiveSequences--;
+ }
+ }
+}
+
+//==========================================================================
+//
+// SN_UpdateActiveSequences
+//
+//==========================================================================
+
+void SN_UpdateActiveSequences(void)
+{
+ seqnode_t *node;
+ boolean sndPlaying;
+
+ if (!ActiveSequences || paused)
+ { // No sequences currently playing/game is paused
+ return;
+ }
+ for (node = SequenceListHead; node; node = node->next)
+ {
+ if (node->delayTics)
+ {
+ node->delayTics--;
+ continue;
+ }
+ sndPlaying = S_GetSoundPlayingInfo(node->mobj, node->currentSoundID);
+ switch (*node->sequencePtr)
+ {
+ case SS_CMD_PLAY:
+ if (!sndPlaying)
+ {
+ node->currentSoundID = *(node->sequencePtr + 1);
+ S_StartSoundAtVolume(node->mobj, node->currentSoundID,
+ node->volume);
+ }
+ node->sequencePtr += 2;
+ break;
+ case SS_CMD_WAITUNTILDONE:
+ if (!sndPlaying)
+ {
+ node->sequencePtr++;
+ node->currentSoundID = 0;
+ }
+ break;
+ case SS_CMD_PLAYREPEAT:
+ if (!sndPlaying)
+ {
+ node->currentSoundID = *(node->sequencePtr + 1);
+ S_StartSoundAtVolume(node->mobj, node->currentSoundID,
+ node->volume);
+ }
+ break;
+ case SS_CMD_DELAY:
+ node->delayTics = *(node->sequencePtr + 1);
+ node->sequencePtr += 2;
+ node->currentSoundID = 0;
+ break;
+ case SS_CMD_DELAYRAND:
+ node->delayTics = *(node->sequencePtr + 1) +
+ M_Random() % (*(node->sequencePtr + 2) - *(node->sequencePtr + 1));
+ node->sequencePtr += 2;
+ node->currentSoundID = 0;
+ break;
+ case SS_CMD_VOLUME:
+ node->volume = (127 * (*(node->sequencePtr + 1))) / 100;
+ node->sequencePtr += 2;
+ break;
+ case SS_CMD_STOPSOUND:
+ // Wait until something else stops the sequence
+ break;
+ case SS_CMD_END:
+ SN_StopSequence(node->mobj);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+//==========================================================================
+//
+// SN_StopAllSequences
+//
+//==========================================================================
+
+void SN_StopAllSequences(void)
+{
+ seqnode_t *node;
+
+ for (node = SequenceListHead; node; node = node->next)
+ {
+ node->stopSound = 0; // don't play any stop sounds
+ SN_StopSequence(node->mobj);
+ }
+}
+
+//==========================================================================
+//
+// SN_GetSequenceOffset
+//
+//==========================================================================
+
+int SN_GetSequenceOffset(int sequence, int *sequencePtr)
+{
+ return (sequencePtr - SequenceData[SequenceTranslate[sequence].scriptNum]);
+}
+
+//==========================================================================
+//
+// SN_ChangeNodeData
+//
+// nodeNum zero is the first node
+//==========================================================================
+
+void SN_ChangeNodeData (int nodeNum, int seqOffset, int delayTics, int volume,
+ int currentSoundID)
+{
+ int i;
+ seqnode_t *node;
+
+ i = 0;
+ node = SequenceListHead;
+ while (node && i < nodeNum)
+ {
+ node = node->next;
+ i++;
+ }
+ if (!node)
+ { // reach the end of the list before finding the nodeNum-th node
+ return;
+ }
+ node->delayTics = delayTics;
+ node->volume = volume;
+ node->sequencePtr += seqOffset;
+ node->currentSoundID = currentSoundID;
+}
+
--- /dev/null
+++ b/sounds.h
@@ -1,0 +1,310 @@
+
+//**************************************************************************
+//**
+//** sounds.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __SOUNDSH__
+#define __SOUNDSH__
+
+#include "soundst.h"
+
+#define MAX_SND_DIST 2025
+#define MAX_CHANNELS 16
+
+/* ---- Music identifiers ---- */
+
+typedef enum
+{
+ mus_e1m1,
+ mus_e1m2,
+ mus_e1m3,
+ mus_e1m4,
+ mus_e1m5,
+ mus_e1m6,
+ mus_e1m7,
+ mus_e1m8,
+ mus_e1m9,
+ mus_e2m1,
+ mus_e2m2,
+ mus_e2m3,
+ mus_e2m4,
+ mus_e2m5,
+ mus_e2m6,
+ mus_e2m7,
+ mus_e2m8,
+ mus_e2m9,
+ mus_e3m1,
+ mus_e3m2,
+ mus_e3m3,
+ mus_e3m4,
+ mus_e3m5,
+ mus_e3m6,
+ mus_e3m7,
+ mus_e3m8,
+ mus_e3m9,
+ mus_e4m1,
+ mus_titl,
+ mus_intr,
+ mus_cptd,
+ NUMMUSIC
+} musicenum_t;
+
+/* ---- Sound identifiers ---- */
+
+typedef enum
+{
+ SFX_NONE,
+ SFX_PLAYER_FIGHTER_NORMAL_DEATH, /* class specific death screams */
+ SFX_PLAYER_FIGHTER_CRAZY_DEATH,
+ SFX_PLAYER_FIGHTER_EXTREME1_DEATH,
+ SFX_PLAYER_FIGHTER_EXTREME2_DEATH,
+ SFX_PLAYER_FIGHTER_EXTREME3_DEATH,
+ SFX_PLAYER_FIGHTER_BURN_DEATH,
+ SFX_PLAYER_CLERIC_NORMAL_DEATH,
+ SFX_PLAYER_CLERIC_CRAZY_DEATH,
+ SFX_PLAYER_CLERIC_EXTREME1_DEATH,
+ SFX_PLAYER_CLERIC_EXTREME2_DEATH,
+ SFX_PLAYER_CLERIC_EXTREME3_DEATH,
+ SFX_PLAYER_CLERIC_BURN_DEATH,
+ SFX_PLAYER_MAGE_NORMAL_DEATH,
+ SFX_PLAYER_MAGE_CRAZY_DEATH,
+ SFX_PLAYER_MAGE_EXTREME1_DEATH,
+ SFX_PLAYER_MAGE_EXTREME2_DEATH,
+ SFX_PLAYER_MAGE_EXTREME3_DEATH,
+ SFX_PLAYER_MAGE_BURN_DEATH,
+ SFX_PLAYER_FIGHTER_PAIN,
+ SFX_PLAYER_CLERIC_PAIN,
+ SFX_PLAYER_MAGE_PAIN,
+ SFX_PLAYER_FIGHTER_GRUNT,
+ SFX_PLAYER_CLERIC_GRUNT,
+ SFX_PLAYER_MAGE_GRUNT,
+ SFX_PLAYER_LAND,
+ SFX_PLAYER_POISONCOUGH,
+ SFX_PLAYER_FIGHTER_FALLING_SCREAM, /* class specific falling screams */
+ SFX_PLAYER_CLERIC_FALLING_SCREAM,
+ SFX_PLAYER_MAGE_FALLING_SCREAM,
+ SFX_PLAYER_FALLING_SPLAT,
+ SFX_PLAYER_FIGHTER_FAILED_USE,
+ SFX_PLAYER_CLERIC_FAILED_USE,
+ SFX_PLAYER_MAGE_FAILED_USE,
+ SFX_PLATFORM_START,
+ SFX_PLATFORM_STARTMETAL,
+ SFX_PLATFORM_STOP,
+ SFX_STONE_MOVE,
+ SFX_METAL_MOVE,
+ SFX_DOOR_OPEN,
+ SFX_DOOR_LOCKED,
+ SFX_DOOR_METAL_OPEN,
+ SFX_DOOR_METAL_CLOSE,
+ SFX_DOOR_LIGHT_CLOSE,
+ SFX_DOOR_HEAVY_CLOSE,
+ SFX_DOOR_CREAK,
+ SFX_PICKUP_WEAPON,
+ SFX_PICKUP_ARTIFACT,
+ SFX_PICKUP_KEY,
+ SFX_PICKUP_ITEM,
+ SFX_PICKUP_PIECE,
+ SFX_WEAPON_BUILD,
+ SFX_ARTIFACT_USE,
+ SFX_ARTIFACT_BLAST,
+ SFX_TELEPORT,
+ SFX_THUNDER_CRASH,
+ SFX_FIGHTER_PUNCH_MISS,
+ SFX_FIGHTER_PUNCH_HITTHING,
+ SFX_FIGHTER_PUNCH_HITWALL,
+ SFX_FIGHTER_GRUNT,
+ SFX_FIGHTER_AXE_HITTHING,
+ SFX_FIGHTER_HAMMER_MISS,
+ SFX_FIGHTER_HAMMER_HITTHING,
+ SFX_FIGHTER_HAMMER_HITWALL,
+ SFX_FIGHTER_HAMMER_CONTINUOUS,
+ SFX_FIGHTER_HAMMER_EXPLODE,
+ SFX_FIGHTER_SWORD_FIRE,
+ SFX_FIGHTER_SWORD_EXPLODE,
+ SFX_CLERIC_CSTAFF_FIRE,
+ SFX_CLERIC_CSTAFF_EXPLODE,
+ SFX_CLERIC_CSTAFF_HITTHING,
+ SFX_CLERIC_FLAME_FIRE,
+ SFX_CLERIC_FLAME_EXPLODE,
+ SFX_CLERIC_FLAME_CIRCLE,
+ SFX_MAGE_WAND_FIRE,
+ SFX_MAGE_LIGHTNING_FIRE,
+ SFX_MAGE_LIGHTNING_ZAP,
+ SFX_MAGE_LIGHTNING_CONTINUOUS,
+ SFX_MAGE_LIGHTNING_READY,
+ SFX_MAGE_SHARDS_FIRE,
+ SFX_MAGE_SHARDS_EXPLODE,
+ SFX_MAGE_STAFF_FIRE,
+ SFX_MAGE_STAFF_EXPLODE,
+ SFX_SWITCH1,
+ SFX_SWITCH2,
+ SFX_SERPENT_SIGHT,
+ SFX_SERPENT_ACTIVE,
+ SFX_SERPENT_PAIN,
+ SFX_SERPENT_ATTACK,
+ SFX_SERPENT_MELEEHIT,
+ SFX_SERPENT_DEATH,
+ SFX_SERPENT_BIRTH,
+ SFX_SERPENTFX_CONTINUOUS,
+ SFX_SERPENTFX_HIT,
+ SFX_POTTERY_EXPLODE,
+ SFX_DRIP,
+ SFX_CENTAUR_SIGHT,
+ SFX_CENTAUR_ACTIVE,
+ SFX_CENTAUR_PAIN,
+ SFX_CENTAUR_ATTACK,
+ SFX_CENTAUR_DEATH,
+ SFX_CENTAURLEADER_ATTACK,
+ SFX_CENTAUR_MISSILE_EXPLODE,
+ SFX_WIND,
+ SFX_BISHOP_SIGHT,
+ SFX_BISHOP_ACTIVE,
+ SFX_BISHOP_PAIN,
+ SFX_BISHOP_ATTACK,
+ SFX_BISHOP_DEATH,
+ SFX_BISHOP_MISSILE_EXPLODE,
+ SFX_BISHOP_BLUR,
+ SFX_DEMON_SIGHT,
+ SFX_DEMON_ACTIVE,
+ SFX_DEMON_PAIN,
+ SFX_DEMON_ATTACK,
+ SFX_DEMON_MISSILE_FIRE,
+ SFX_DEMON_MISSILE_EXPLODE,
+ SFX_DEMON_DEATH,
+ SFX_WRAITH_SIGHT,
+ SFX_WRAITH_ACTIVE,
+ SFX_WRAITH_PAIN,
+ SFX_WRAITH_ATTACK,
+ SFX_WRAITH_MISSILE_FIRE,
+ SFX_WRAITH_MISSILE_EXPLODE,
+ SFX_WRAITH_DEATH,
+ SFX_PIG_ACTIVE1,
+ SFX_PIG_ACTIVE2,
+ SFX_PIG_PAIN,
+ SFX_PIG_ATTACK,
+ SFX_PIG_DEATH,
+ SFX_MAULATOR_SIGHT,
+ SFX_MAULATOR_ACTIVE,
+ SFX_MAULATOR_PAIN,
+ SFX_MAULATOR_HAMMER_SWING,
+ SFX_MAULATOR_HAMMER_HIT,
+ SFX_MAULATOR_MISSILE_HIT,
+ SFX_MAULATOR_DEATH,
+ SFX_FREEZE_DEATH,
+ SFX_FREEZE_SHATTER,
+ SFX_ETTIN_SIGHT,
+ SFX_ETTIN_ACTIVE,
+ SFX_ETTIN_PAIN,
+ SFX_ETTIN_ATTACK,
+ SFX_ETTIN_DEATH,
+ SFX_FIRED_SPAWN,
+ SFX_FIRED_ACTIVE,
+ SFX_FIRED_PAIN,
+ SFX_FIRED_ATTACK,
+ SFX_FIRED_MISSILE_HIT,
+ SFX_FIRED_DEATH,
+ SFX_ICEGUY_SIGHT,
+ SFX_ICEGUY_ACTIVE,
+ SFX_ICEGUY_ATTACK,
+ SFX_ICEGUY_FX_EXPLODE,
+ SFX_SORCERER_SIGHT,
+ SFX_SORCERER_ACTIVE,
+ SFX_SORCERER_PAIN,
+ SFX_SORCERER_SPELLCAST,
+ SFX_SORCERER_BALLWOOSH,
+ SFX_SORCERER_DEATHSCREAM,
+ SFX_SORCERER_BISHOPSPAWN,
+ SFX_SORCERER_BALLPOP,
+ SFX_SORCERER_BALLBOUNCE,
+ SFX_SORCERER_BALLEXPLODE,
+ SFX_SORCERER_BIGBALLEXPLODE,
+ SFX_SORCERER_HEADSCREAM,
+ SFX_DRAGON_SIGHT,
+ SFX_DRAGON_ACTIVE,
+ SFX_DRAGON_WINGFLAP,
+ SFX_DRAGON_ATTACK,
+ SFX_DRAGON_PAIN,
+ SFX_DRAGON_DEATH,
+ SFX_DRAGON_FIREBALL_EXPLODE,
+ SFX_KORAX_SIGHT,
+ SFX_KORAX_ACTIVE,
+ SFX_KORAX_PAIN,
+ SFX_KORAX_ATTACK,
+ SFX_KORAX_COMMAND,
+ SFX_KORAX_DEATH,
+ SFX_KORAX_STEP,
+ SFX_THRUSTSPIKE_RAISE,
+ SFX_THRUSTSPIKE_LOWER,
+ SFX_STAINEDGLASS_SHATTER,
+ SFX_FLECHETTE_BOUNCE,
+ SFX_FLECHETTE_EXPLODE,
+ SFX_LAVA_MOVE,
+ SFX_WATER_MOVE,
+ SFX_ICE_STARTMOVE,
+ SFX_EARTH_STARTMOVE,
+ SFX_WATER_SPLASH,
+ SFX_LAVA_SIZZLE,
+ SFX_SLUDGE_GLOOP,
+ SFX_CHOLY_FIRE,
+ SFX_SPIRIT_ACTIVE,
+ SFX_SPIRIT_ATTACK,
+ SFX_SPIRIT_DIE,
+ SFX_VALVE_TURN,
+ SFX_ROPE_PULL,
+ SFX_FLY_BUZZ,
+ SFX_IGNITE,
+ SFX_PUZZLE_SUCCESS,
+ SFX_PUZZLE_FAIL_FIGHTER,
+ SFX_PUZZLE_FAIL_CLERIC,
+ SFX_PUZZLE_FAIL_MAGE,
+ SFX_EARTHQUAKE,
+ SFX_BELLRING,
+ SFX_TREE_BREAK,
+ SFX_TREE_EXPLODE,
+ SFX_SUITOFARMOR_BREAK,
+ SFX_POISONSHROOM_PAIN,
+ SFX_POISONSHROOM_DEATH,
+ SFX_AMBIENT1,
+ SFX_AMBIENT2,
+ SFX_AMBIENT3,
+ SFX_AMBIENT4,
+ SFX_AMBIENT5,
+ SFX_AMBIENT6,
+ SFX_AMBIENT7,
+ SFX_AMBIENT8,
+ SFX_AMBIENT9,
+ SFX_AMBIENT10,
+ SFX_AMBIENT11,
+ SFX_AMBIENT12,
+ SFX_AMBIENT13,
+ SFX_AMBIENT14,
+ SFX_AMBIENT15,
+ SFX_STARTUP_TICK,
+ SFX_SWITCH_OTHERLEVEL,
+ SFX_RESPAWN,
+ SFX_KORAX_VOICE_1,
+ SFX_KORAX_VOICE_2,
+ SFX_KORAX_VOICE_3,
+ SFX_KORAX_VOICE_4,
+ SFX_KORAX_VOICE_5,
+ SFX_KORAX_VOICE_6,
+ SFX_KORAX_VOICE_7,
+ SFX_KORAX_VOICE_8,
+ SFX_KORAX_VOICE_9,
+ SFX_BAT_SCREAM,
+ SFX_CHAT,
+ SFX_MENU_MOVE,
+ SFX_CLOCK_TICK,
+ SFX_FIREBALL,
+ SFX_PUPPYBEAT,
+ SFX_MYSTICINCANT,
+ NUMSFX
+} sfxenum_t;
+
+#endif /* __SOUNDSH__ */
+
--- /dev/null
+++ b/soundst.h
@@ -1,0 +1,80 @@
+//**************************************************************************
+//**
+//** soundst.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 505 $
+//** $Date: 2009-06-03 22:41:58 +0300 (Wed, 03 Jun 2009) $
+//**
+//**************************************************************************
+
+#ifndef __SOUNDSTH__
+#define __SOUNDSTH__
+
+typedef struct
+{
+ const char name[8];
+ int p1;
+} musicinfo_t;
+
+typedef struct sfxinfo_s
+{
+ const char tagName[32];
+ char lumpname[12]; /* Only need 9 bytes, but padded out to be dword aligned */
+// struct sfxinfo_s *link; /* Make alias for another sound */
+ int priority; /* Higher priority takes precendence */
+ int usefulness; /* Determines when a sound should be cached out */
+ void *snd_ptr;
+ int lumpnum;
+ int numchannels; /* total number of channels a sound type may occupy */
+ boolean changePitch;
+} sfxinfo_t;
+
+typedef struct
+{
+ mobj_t *mo;
+ int sound_id;
+ int handle;
+ int volume;
+ int pitch;
+ int priority;
+} channel_t;
+
+typedef struct
+{
+ int id;
+ unsigned short priority;
+ const char *name;
+ mobj_t *mo;
+ int distance;
+} ChanInfo_t;
+
+typedef struct
+{
+ int channelCount;
+ int musicVolume;
+ int soundVolume;
+ ChanInfo_t chan[8];
+} SoundInfo_t;
+
+extern int snd_MaxVolume;
+extern int snd_MusicVolume;
+
+void S_Init(void);
+void S_ShutDown(void);
+void S_Start(void);
+void S_StartSound(mobj_t *origin, int sound_id);
+int S_GetSoundID(const char *name);
+void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume);
+void S_StopSound(mobj_t *origin);
+void S_StopAllSound(void);
+void S_PauseSound(void);
+void S_ResumeSound(void);
+void S_UpdateSounds(mobj_t *listener);
+void S_StartSong(int song, boolean loop);
+void S_StartSongName(const char *songLump, boolean loop);
+void S_GetChannelInfo(SoundInfo_t *s);
+void S_SetMusicVolume(void);
+boolean S_GetSoundPlayingInfo(mobj_t *mobj, int sound_id);
+
+#endif /* __SOUNDSTH__ */
+
--- /dev/null
+++ b/st_start.c
@@ -1,0 +1,329 @@
+
+//**************************************************************************
+//**
+//** st_start.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+
+// HEADER FILES ------------------------------------------------------------
+
+#if 0
+/* I doubt I'll readd DOS support, but who knows */
+#include <libc.h>
+#include <ctype.h>
+#endif
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "st_start.h"
+
+
+// MACROS ------------------------------------------------------------------
+
+#define ST_MAX_NOTCHES 32
+#define ST_NOTCH_WIDTH 16
+#define ST_NOTCH_HEIGHT 23
+#define ST_PROGRESS_X 64 /* Start of notches x screen pos. */
+#define ST_PROGRESS_Y 441 /* Start of notches y screen pos. */
+
+#define ST_NETPROGRESS_X 288
+#define ST_NETPROGRESS_Y 32
+#define ST_NETNOTCH_WIDTH 8
+#define ST_NETNOTCH_HEIGHT 16
+#define ST_MAX_NETNOTCHES 8
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+extern void SetVideoModeHR(void);
+extern void ClearScreenHR(void);
+extern void SlamHR(char *buffer);
+extern void SlamBlockHR(int x, int y, int w, int h, char *src);
+extern void InitPaletteHR(void);
+extern void SetPaletteHR(byte *palette);
+extern void GetPaletteHR(byte *palette);
+extern void FadeToPaletteHR(byte *palette);
+extern void FadeToBlackHR(void);
+extern void BlackPaletteHR(void);
+extern void I_StartupReadKeys(void);
+#endif /* DOS : I_IBM.C */
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+char *ST_LoadScreen(void);
+void ST_UpdateNotches(int notchPosition);
+void ST_UpdateNetNotches(int notchPosition);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+static char *bitmap = NULL;
+
+static char notchTable[] =
+{
+ /* plane 0 */
+ 0x00, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40,
+ 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x03, 0xC0,
+ 0x0F, 0x90, 0x1B, 0x68, 0x3D, 0xBC, 0x3F, 0xFC, 0x20, 0x08, 0x20, 0x08,
+ 0x2F, 0xD8, 0x37, 0xD8, 0x37, 0xF8, 0x1F, 0xF8, 0x1C, 0x50,
+
+ /* plane 1 */
+ 0x00, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xA0,
+ 0x30, 0x6C, 0x24, 0x94, 0x42, 0x4A, 0x60, 0x0E, 0x60, 0x06, 0x7F, 0xF6,
+ 0x7F, 0xF6, 0x7F, 0xF6, 0x5E, 0xF6, 0x38, 0x16, 0x23, 0xAC,
+
+ /* plane 2 */
+ 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40,
+ 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x03, 0xE0,
+ 0x30, 0x6C, 0x24, 0x94, 0x52, 0x6A, 0x7F, 0xFE, 0x60, 0x0E, 0x60, 0x0E,
+ 0x6F, 0xD6, 0x77, 0xD6, 0x56, 0xF6, 0x38, 0x36, 0x23, 0xAC,
+
+ /* plane 3 */
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
+ 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0x80, 0x02, 0x40,
+ 0x0F, 0x90, 0x1B, 0x68, 0x3D, 0xB4, 0x1F, 0xF0, 0x1F, 0xF8, 0x1F, 0xF8,
+ 0x10, 0x28, 0x08, 0x28, 0x29, 0x08, 0x07, 0xE8, 0x1C, 0x50
+};
+
+/* Red Network Progress notches */
+static char netnotchTable[] =
+{
+ /* plane 0 */
+ 0x80, 0x50, 0xD0, 0xf0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xD0, 0xF0, 0xC0,
+ 0x70, 0x50, 0x80, 0x60,
+
+ /* plane 1 */
+ 0x60, 0xE0, 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, 0xA0, 0xA0, 0xA0, 0xE0, 0xA0,
+ 0xA0, 0xE0, 0x60, 0x00,
+
+ /* plane 2 */
+ 0x80, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00,
+ 0x10, 0x10, 0x80, 0x60,
+
+ /* plane 3 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+#endif /* DOS : I_IBM.C */
+
+// CODE --------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------------
+//
+// Startup Screen Functions
+//
+//--------------------------------------------------------------------------
+
+//==========================================================================
+//
+// ST_Init - Do the startup screen
+//
+//==========================================================================
+
+void ST_Init(void)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+ char *pal;
+ char *buffer;
+
+ if (!debugmode)
+ {
+ /* Set 640x480x16 mode */
+ SetVideoModeHR();
+ ClearScreenHR();
+ InitPaletteHR();
+ BlackPaletteHR();
+
+ /* Load graphic */
+ buffer = ST_LoadScreen();
+ pal = buffer;
+ bitmap = buffer + 16*3;
+
+ SlamHR(bitmap);
+ FadeToPaletteHR(pal);
+ Z_Free(buffer);
+ }
+#endif /* DOS : I_IBM.C */
+}
+
+
+void ST_Done(void)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+ ClearScreenHR();
+#endif /* DOS : I_IBM.C */
+}
+
+
+//==========================================================================
+//
+// ST_UpdateNotches
+//
+//==========================================================================
+
+void ST_UpdateNotches(int notchPosition)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+ int x = ST_PROGRESS_X + notchPosition*ST_NOTCH_WIDTH;
+ int y = ST_PROGRESS_Y;
+ SlamBlockHR(x,y, ST_NOTCH_WIDTH,ST_NOTCH_HEIGHT, notchTable);
+#endif /* DOS : I_IBM.C */
+}
+
+
+//==========================================================================
+//
+// ST_UpdateNetNotches - indicates network progress
+//
+//==========================================================================
+
+void ST_UpdateNetNotches(int notchPosition)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+ int x = ST_NETPROGRESS_X + notchPosition*ST_NETNOTCH_WIDTH;
+ int y = ST_NETPROGRESS_Y;
+ SlamBlockHR(x,y, ST_NETNOTCH_WIDTH, ST_NETNOTCH_HEIGHT, netnotchTable);
+#endif /* DOS : I_IBM.C */
+}
+
+
+//==========================================================================
+//
+// ST_Progress - increments progress indicator
+//
+//==========================================================================
+
+void ST_Progress(void)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+ static int notchPosition = 0;
+
+ /* Check for ESC press -- during startup all events eaten here */
+ I_StartupReadKeys();
+
+ if (debugmode)
+ {
+ printf(".");
+ }
+ else
+ {
+ if (notchPosition < ST_MAX_NOTCHES)
+ {
+ ST_UpdateNotches(notchPosition);
+ S_StartSound(NULL, SFX_STARTUP_TICK);
+ notchPosition++;
+ }
+ }
+#else /* DOS : I_IBM.C */
+ putchar ('.');
+#endif
+}
+
+
+//==========================================================================
+//
+// ST_NetProgress - indicates network progress
+//
+//==========================================================================
+
+void ST_NetProgress(void)
+{
+#if defined(__WATCOMC__) || defined(__DJGPP__) || defined(__DOS__)
+ static int netnotchPosition = 0;
+ if (debugmode)
+ {
+ printf("*");
+ }
+ else
+ {
+ if (netnotchPosition < ST_MAX_NETNOTCHES)
+ {
+ ST_UpdateNetNotches(netnotchPosition);
+ S_StartSound(NULL, SFX_DRIP);
+ netnotchPosition++;
+ }
+ }
+#endif /* DOS : I_IBM.C */
+}
+
+
+//==========================================================================
+//
+// ST_NetDone - net progress complete
+//
+//==========================================================================
+
+void ST_NetDone(void)
+{
+ S_StartSound(NULL, SFX_PICKUP_WEAPON);
+}
+
+
+//==========================================================================
+//
+// ST_Message - gives debug message
+//
+//==========================================================================
+
+void ST_Message(const char *message, ...)
+{
+ va_list argptr;
+ char buffer[MAX_ST_MSG];
+
+ va_start(argptr, message);
+ vsnprintf(buffer, sizeof(buffer), message, argptr);
+ va_end(argptr);
+
+// if (debugmode)
+ printf("%s", buffer);
+}
+
+//==========================================================================
+//
+// ST_RealMessage - gives user message
+//
+//==========================================================================
+
+void ST_RealMessage(const char *message, ...)
+{
+ va_list argptr;
+ char buffer[MAX_ST_MSG];
+
+ va_start(argptr, message);
+ vsnprintf(buffer, sizeof(buffer), message, argptr);
+ va_end(argptr);
+
+ printf("%s", buffer); // Always print these messages
+}
+
+
+//==========================================================================
+//
+// ST_LoadScreen - loads startup graphic
+//
+//==========================================================================
+
+char *ST_LoadScreen(void)
+{
+ int length, lump;
+ char *buffer;
+
+ lump = W_GetNumForName("STARTUP");
+ length = W_LumpLength(lump);
+ buffer = (char *)Z_Malloc(length, PU_STATIC, NULL);
+ W_ReadLump(lump, buffer);
+ return (buffer);
+}
+
--- /dev/null
+++ b/st_start.h
@@ -1,0 +1,29 @@
+
+//**************************************************************************
+//**
+//** st_start.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 543 $
+//** $Date: 2010-01-11 20:44:55 +0200 (Mon, 11 Jan 2010) $
+//**
+//**************************************************************************
+
+#ifndef __ST_START__
+#define __ST_START__
+
+extern void ST_Init(void);
+extern void ST_Done(void);
+
+extern void ST_Progress(void);
+extern void ST_NetProgress(void);
+extern void ST_NetDone(void);
+
+/* Maximum size of a debug message */
+#define MAX_ST_MSG 256
+
+/* These two doesn't add a '\n' to the message, the caller must add it by himself */
+extern void ST_Message(const char *message, ...);
+extern void ST_RealMessage(const char *message, ...);
+
+#endif /* __ST_START__ */
+
--- /dev/null
+++ b/sv_save.c
@@ -1,0 +1,2478 @@
+
+//**************************************************************************
+//**
+//** sv_save.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 522 $
+//** $Date: 2009-06-08 11:45:17 +0300 (Mon, 08 Jun 2009) $
+//**
+//** Games are always saved Little Endian, with 32 bit offsets.
+//** The saved games then can be properly read on 64 bit and/or
+//** Big Endian machines all the same.
+//** See the file SAVEGAME for notes and/or issues.
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+#include "p_local.h"
+#include "sv_save.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_TARGET_PLAYERS 512
+#define MOBJ_NULL -1
+#define MOBJ_XX_PLAYER -2
+
+#define MAX_MAPS 99
+#define BASE_SLOT 6
+#define REBORN_SLOT 7
+#define REBORN_DESCRIPTION "TEMP GAME"
+#define MAX_THINKER_SIZE 256
+
+// TYPES -------------------------------------------------------------------
+
+typedef enum
+{
+ ASEG_GAME_HEADER = 101,
+ ASEG_MAP_HEADER,
+ ASEG_WORLD,
+ ASEG_POLYOBJS,
+ ASEG_MOBJS,
+ ASEG_THINKERS,
+ ASEG_SCRIPTS,
+ ASEG_PLAYERS,
+ ASEG_SOUNDS,
+ ASEG_MISC,
+ ASEG_END
+} gameArchiveSegment_t;
+
+typedef enum
+{
+ TC_NULL,
+ TC_MOVE_CEILING,
+ TC_VERTICAL_DOOR,
+ TC_MOVE_FLOOR,
+ TC_PLAT_RAISE,
+ TC_INTERPRET_ACS,
+ TC_FLOOR_WAGGLE,
+ TC_LIGHT,
+ TC_PHASE,
+ TC_BUILD_PILLAR,
+ TC_ROTATE_POLY,
+ TC_MOVE_POLY,
+ TC_POLY_DOOR
+} thinkClass_t;
+
+typedef struct
+{
+ thinkClass_t tClass;
+ think_t thinkerFunc;
+ void (*mangleFunc)(void *, void *);
+ void (*restoreFunc)(void *, void *);
+ size_t realsize, savesize;
+} thinkInfo_t;
+
+typedef struct
+{
+ thinker_t thinker;
+ sector_t *sector;
+} ssthinker_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+void P_SpawnPlayer(mapthing_t *mthing);
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void ArchiveWorld(void);
+static void UnarchiveWorld(void);
+static void ArchivePolyobjs(void);
+static void UnarchivePolyobjs(void);
+static void ArchiveMobjs(void);
+static void UnarchiveMobjs(void);
+static void ArchiveThinkers(void);
+static void UnarchiveThinkers(void);
+static void ArchiveScripts(void);
+static void UnarchiveScripts(void);
+static void ArchivePlayers(void);
+static void UnarchivePlayers(void);
+static void ArchiveSounds(void);
+static void UnarchiveSounds(void);
+static void ArchiveMisc(void);
+static void UnarchiveMisc(void);
+static void SetMobjArchiveNums(void);
+static void RemoveAllThinkers(void);
+static void MangleMobj(mobj_t *mobj, save_mobj_t *temp);
+static void RestoreMobj(mobj_t *mobj, save_mobj_t *temp);
+static int32_t GetMobjNum(mobj_t *mobj);
+static mobj_t *GetMobjPtr(int32_t archiveNum, intptr_t *target);
+static void MangleFloorMove(void *arg1, void *arg2);
+static void RestoreFloorMove(void *arg1, void *arg2);
+static void MangleLight(void *arg1, void *arg2);
+static void RestoreLight(void *arg1, void *arg2);
+static void MangleVerticalDoor(void *arg1, void *arg2);
+static void RestoreVerticalDoor(void *arg1, void *arg2);
+static void ManglePhase(void *arg1, void *arg2);
+static void RestorePhase(void *arg1, void *arg2);
+static void ManglePillar(void *arg1, void *arg2);
+static void RestorePillar(void *arg1, void *arg2);
+static void MangleFloorWaggle(void *arg1, void *arg2);
+static void RestoreFloorWaggle(void *arg1, void *arg2);
+static void ManglePolyEvent(void *arg1, void *arg2);
+static void RestorePolyEvent(void *arg1, void *arg2);
+static void ManglePolyDoor(void *arg1, void *arg2);
+static void RestorePolyDoor(void *arg1, void *arg2);
+static void MangleScript(void *arg1, void *arg2);
+static void RestoreScript(void *arg1, void *arg2);
+static void ManglePlatRaise(void *arg1, void *arg2);
+static void RestorePlatRaise(void *arg1, void *arg2);
+static void MangleMoveCeiling(void *arg1, void *arg2);
+static void RestoreMoveCeiling(void *arg1, void *arg2);
+static void AssertSegment(gameArchiveSegment_t segType);
+static void ClearSaveSlot(int slot);
+static void CopySaveSlot(int sourceSlot, int destSlot);
+static void CopyFile(const char *sourceName, const char *destName);
+static boolean ExistingFile(const char *name);
+static void OpenStreamOut(const char *fileName);
+static void CloseStreamOut(void);
+static void StreamOutBuffer(const void *buffer, size_t size);
+static void StreamOutByte(byte val);
+static void StreamOutWord(uint16_t val);
+static void StreamOutLong(uint32_t val);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern int ACScriptCount;
+extern byte *ActionCodeBase;
+extern acsInfo_t *ACSInfo;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int MobjCount;
+static mobj_t **MobjList;
+static intptr_t **TargetPlayerAddrs;
+static int TargetPlayerCount;
+static void *SaveBuffer;
+static boolean SavingPlayers;
+static byte *SavePtr;
+static FILE *SavingFP;
+
+// This list has been prioritized using frequency estimates
+static thinkInfo_t ThinkerInfo[] =
+{
+ {
+ TC_MOVE_FLOOR,
+ T_MoveFloor,
+ MangleFloorMove,
+ RestoreFloorMove,
+ sizeof(floormove_t),
+ sizeof(save_floormove_t)
+ },
+ {
+ TC_PLAT_RAISE,
+ T_PlatRaise,
+ ManglePlatRaise,
+ RestorePlatRaise,
+ sizeof(plat_t),
+ sizeof(save_plat_t)
+ },
+ {
+ TC_MOVE_CEILING,
+ T_MoveCeiling,
+ MangleMoveCeiling,
+ RestoreMoveCeiling,
+ sizeof(ceiling_t),
+ sizeof(save_ceiling_t)
+ },
+ {
+ TC_LIGHT,
+ T_Light,
+ MangleLight,
+ RestoreLight,
+ sizeof(light_t),
+ sizeof(save_light_t)
+ },
+ {
+ TC_VERTICAL_DOOR,
+ T_VerticalDoor,
+ MangleVerticalDoor,
+ RestoreVerticalDoor,
+ sizeof(vldoor_t),
+ sizeof(save_vldoor_t)
+ },
+ {
+ TC_PHASE,
+ T_Phase,
+ ManglePhase,
+ RestorePhase,
+ sizeof(phase_t),
+ sizeof(save_phase_t)
+ },
+ {
+ TC_INTERPRET_ACS,
+ T_InterpretACS,
+ MangleScript,
+ RestoreScript,
+ sizeof(acs_t),
+ sizeof(save_acs_t)
+ },
+ {
+ TC_ROTATE_POLY,
+ T_RotatePoly,
+ ManglePolyEvent,
+ RestorePolyEvent,
+ sizeof(polyevent_t),
+ sizeof(save_polyevent_t)
+ },
+ {
+ TC_BUILD_PILLAR,
+ T_BuildPillar,
+ ManglePillar,
+ RestorePillar,
+ sizeof(pillar_t),
+ sizeof(save_pillar_t)
+ },
+ {
+ TC_MOVE_POLY,
+ T_MovePoly,
+ ManglePolyEvent,
+ RestorePolyEvent,
+ sizeof(polyevent_t),
+ sizeof(save_polyevent_t)
+ },
+ {
+ TC_POLY_DOOR,
+ T_PolyDoor,
+ ManglePolyDoor,
+ RestorePolyDoor,
+ sizeof(polydoor_t),
+ sizeof(save_polydoor_t)
+ },
+ {
+ TC_FLOOR_WAGGLE,
+ T_FloorWaggle,
+ MangleFloorWaggle,
+ RestoreFloorWaggle,
+ sizeof(floorWaggle_t),
+ sizeof(save_floorWaggle_t)
+ },
+ { // Terminator
+ TC_NULL, NULL, NULL, NULL, 0
+ }
+};
+
+// CODE --------------------------------------------------------------------
+
+static inline byte GET_BYTE (void)
+{
+ return *SavePtr++;
+}
+
+static inline int16_t GET_WORD (void)
+{
+ uint16_t val = READ_INT16(SavePtr);
+ INCR_INT16(SavePtr);
+ return (int16_t) val;
+}
+
+static inline int32_t GET_LONG (void)
+{
+ uint32_t val = READ_INT32(SavePtr);
+ INCR_INT32(SavePtr);
+ return (int32_t) val;
+}
+
+//==========================================================================
+//
+// SV_SaveGame
+//
+//==========================================================================
+
+void SV_SaveGame(int slot, const char *description)
+{
+ int i;
+ char fileName[MAX_OSPATH];
+ char versionText[HXS_VERSION_TEXT_LENGTH];
+
+ // Open the output file
+ snprintf(fileName, sizeof(fileName), "%shex6.hxs", basePath);
+ OpenStreamOut(fileName);
+
+ // Write game save description
+ StreamOutBuffer(description, HXS_DESCRIPTION_LENGTH);
+
+ // Write version info
+ memset(versionText, 0, HXS_VERSION_TEXT_LENGTH);
+ strcpy(versionText, HXS_VERSION_TEXT);
+ StreamOutBuffer(versionText, HXS_VERSION_TEXT_LENGTH);
+
+ // Place a header marker
+ StreamOutLong(ASEG_GAME_HEADER);
+
+ // Write current map and difficulty
+ StreamOutByte(gamemap);
+ StreamOutByte(gameskill);
+
+ // Write global script info
+ for (i = 0; i < MAX_ACS_WORLD_VARS; i++)
+ {
+ StreamOutLong(WorldVars[i]);
+ }
+ for (i = 0; i <= MAX_ACS_STORE; i++)
+ {
+ StreamOutLong(ACSStore[i].map);
+ StreamOutLong(ACSStore[i].script);
+ StreamOutBuffer(ACSStore[i].args, 4);
+ }
+
+ ArchivePlayers();
+
+ // Place a termination marker
+ StreamOutLong(ASEG_END);
+
+ // Close the output file
+ CloseStreamOut();
+
+ // Save out the current map
+ SV_SaveMap(true); // true = save player info
+
+ // Clear all save files at destination slot
+ ClearSaveSlot(slot);
+
+ // Copy base slot to destination slot
+ CopySaveSlot(BASE_SLOT, slot);
+}
+
+//==========================================================================
+//
+// SV_SaveMap
+//
+//==========================================================================
+
+void SV_SaveMap(boolean savePlayers)
+{
+ char fileName[MAX_OSPATH];
+
+ SavingPlayers = savePlayers;
+
+ // Open the output file
+ snprintf(fileName, sizeof(fileName), "%shex6%02d.hxs", basePath, gamemap);
+ OpenStreamOut(fileName);
+
+ // Place a header marker
+ StreamOutLong(ASEG_MAP_HEADER);
+
+ // Write the level timer
+ StreamOutLong(leveltime);
+
+ // Set the mobj archive numbers
+ SetMobjArchiveNums();
+
+ ArchiveWorld();
+ ArchivePolyobjs();
+ ArchiveMobjs();
+ ArchiveThinkers();
+ ArchiveScripts();
+ ArchiveSounds();
+ ArchiveMisc();
+
+ // Place a termination marker
+ StreamOutLong(ASEG_END);
+
+ // Close the output file
+ CloseStreamOut();
+}
+
+//==========================================================================
+//
+// SV_LoadGame
+//
+//==========================================================================
+
+void SV_LoadGame(int slot)
+{
+ int i;
+ char fileName[MAX_OSPATH];
+ player_t playerBackup[MAXPLAYERS];
+ mobj_t *mobj;
+
+ // Copy all needed save files to the base slot
+ if (slot != BASE_SLOT)
+ {
+ ClearSaveSlot(BASE_SLOT);
+ CopySaveSlot(slot, BASE_SLOT);
+ }
+
+ // Create the name
+ snprintf(fileName, sizeof(fileName), "%shex6.hxs", basePath);
+
+ // Load the file
+ M_ReadFile(fileName, &SaveBuffer);
+
+ // Set the save pointer and skip the description field
+ SavePtr = (byte *)SaveBuffer + HXS_DESCRIPTION_LENGTH;
+
+ // Check the version text
+ if (strcmp((char *)SavePtr, HXS_VERSION_TEXT))
+ { // Bad version
+ return;
+ }
+ SavePtr += HXS_VERSION_TEXT_LENGTH;
+
+ AssertSegment(ASEG_GAME_HEADER);
+
+ gameepisode = 1;
+ gamemap = GET_BYTE();
+ gameskill = GET_BYTE();
+
+ // Read global script info
+ memcpy(WorldVars, SavePtr, sizeof(WorldVars));
+ SavePtr += sizeof(WorldVars);
+ memcpy(ACSStore, SavePtr, sizeof(ACSStore));
+ SavePtr += sizeof(ACSStore);
+ for (i = 0; i < MAX_ACS_WORLD_VARS; i++)
+ {
+ WorldVars[i] = (int) LONG(WorldVars[i]);
+ }
+ for (i = 0; i <= MAX_ACS_STORE; i++)
+ {
+ ACSStore[i].map = (int) LONG(ACSStore[i].map);
+ ACSStore[i].script = (int) LONG(ACSStore[i].script);
+ }
+
+ // Read the player structures
+ UnarchivePlayers();
+
+ AssertSegment(ASEG_END);
+
+ Z_Free(SaveBuffer);
+
+ // Save player structs
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ playerBackup[i] = players[i];
+ }
+
+ // Load the current map
+ SV_LoadMap();
+
+ // Don't need the player mobj relocation info for load game
+ Z_Free(TargetPlayerAddrs);
+ TargetPlayerAddrs = NULL;
+
+ // Restore player structs
+ inv_ptr = 0;
+ curpos = 0;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ mobj = players[i].mo;
+ players[i] = playerBackup[i];
+ players[i].mo = mobj;
+ if (i == consoleplayer)
+ {
+ players[i].readyArtifact = players[i].inventory[inv_ptr].type;
+ }
+ }
+}
+
+//==========================================================================
+//
+// SV_UpdateRebornSlot
+//
+// Copies the base slot to the reborn slot.
+//
+//==========================================================================
+
+void SV_UpdateRebornSlot(void)
+{
+ ClearSaveSlot(REBORN_SLOT);
+ CopySaveSlot(BASE_SLOT, REBORN_SLOT);
+}
+
+//==========================================================================
+//
+// SV_ClearRebornSlot
+//
+//==========================================================================
+
+void SV_ClearRebornSlot(void)
+{
+ ClearSaveSlot(REBORN_SLOT);
+}
+
+//==========================================================================
+//
+// SV_MapTeleport
+//
+//==========================================================================
+
+void SV_MapTeleport(int map, int position)
+{
+ int i;
+ int j;
+ char fileName[MAX_OSPATH];
+ player_t playerBackup[MAXPLAYERS];
+ mobj_t *mobj;
+ mobj_t *targetPlayerMobj;
+ int inventoryPtr;
+ int currentInvPos;
+ boolean rClass;
+ boolean playerWasReborn;
+ boolean oldWeaponowned[NUMWEAPONS];
+ int oldKeys = 0; /* jim added initialiser */
+ int oldPieces = 0; /* jim added initialiser */
+ int bestWeapon;
+
+ if (!deathmatch)
+ {
+ if (P_GetMapCluster(gamemap) == P_GetMapCluster(map))
+ { // Same cluster - save map without saving player mobjs
+ SV_SaveMap(false);
+ }
+ else
+ { // Entering new cluster - clear base slot
+ ClearSaveSlot(BASE_SLOT);
+ }
+ }
+
+ // Store player structs for later
+ rClass = randomclass;
+ randomclass = false;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ playerBackup[i] = players[i];
+ }
+
+ // Save some globals that get trashed during the load
+ inventoryPtr = inv_ptr;
+ currentInvPos = curpos;
+
+ gamemap = map;
+ snprintf(fileName, sizeof(fileName), "%shex6%02d.hxs", basePath, gamemap);
+ if (!deathmatch && ExistingFile(fileName))
+ { // Unarchive map
+ SV_LoadMap();
+ }
+ else
+ { // New map
+ G_InitNew(gameskill, gameepisode, gamemap);
+
+ // Destroy all freshly spawned players
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ P_RemoveMobj(players[i].mo);
+ }
+ }
+ }
+
+ // Restore player structs
+ targetPlayerMobj = NULL;
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ players[i] = playerBackup[i];
+ P_ClearMessage(&players[i]);
+ players[i].attacker = NULL;
+ players[i].poisoner = NULL;
+
+ if (netgame)
+ {
+ if (players[i].playerstate == PST_DEAD)
+ { // In a network game, force all players to be alive
+ players[i].playerstate = PST_REBORN;
+ }
+ if (!deathmatch)
+ { // Cooperative net-play, retain keys and weapons
+ oldKeys = players[i].keys;
+ oldPieces = players[i].pieces;
+ for (j = 0; j < NUMWEAPONS; j++)
+ {
+ oldWeaponowned[j] = players[i].weaponowned[j];
+ }
+ }
+ }
+ playerWasReborn = (players[i].playerstate == PST_REBORN);
+ if (deathmatch)
+ {
+ memset(players[i].frags, 0, sizeof(players[i].frags));
+ mobj = P_SpawnMobj(playerstarts[0][i].x<<16,
+ playerstarts[0][i].y<<16, 0, MT_PLAYER_FIGHTER);
+ players[i].mo = mobj;
+ G_DeathMatchSpawnPlayer(i);
+ P_RemoveMobj(mobj);
+ }
+ else
+ {
+ P_SpawnPlayer(&playerstarts[position][i]);
+ }
+
+ if (playerWasReborn && netgame && !deathmatch)
+ { // Restore keys and weapons when reborn in co-op
+ players[i].keys = oldKeys;
+ players[i].pieces = oldPieces;
+ for (bestWeapon = 0, j = 0; j < NUMWEAPONS; j++)
+ {
+ if (oldWeaponowned[j])
+ {
+ bestWeapon = j;
+ players[i].weaponowned[j] = true;
+ }
+ }
+ players[i].mana[MANA_1] = 25;
+ players[i].mana[MANA_2] = 25;
+ if (bestWeapon)
+ { // Bring up the best weapon
+ players[i].pendingweapon = bestWeapon;
+ }
+ }
+
+ if (targetPlayerMobj == NULL)
+ { // The poor sap
+ targetPlayerMobj = players[i].mo;
+ }
+ }
+ randomclass = rClass;
+
+ // Redirect anything targeting a player mobj
+ if (TargetPlayerAddrs)
+ {
+ for (i = 0; i < TargetPlayerCount; i++)
+ {
+ *TargetPlayerAddrs[i] = (intptr_t)targetPlayerMobj;
+ }
+ Z_Free(TargetPlayerAddrs);
+ TargetPlayerAddrs = NULL;
+ }
+
+ // Destroy all things touching players
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (playeringame[i])
+ {
+ P_TeleportMove(players[i].mo, players[i].mo->x, players[i].mo->y);
+ }
+ }
+
+ // Restore trashed globals
+ inv_ptr = inventoryPtr;
+ curpos = currentInvPos;
+
+ // Launch waiting scripts
+ if (!deathmatch)
+ {
+ P_CheckACSStore();
+ }
+
+ // For single play, save immediately into the reborn slot
+ if (!netgame)
+ {
+ SV_SaveGame(REBORN_SLOT, REBORN_DESCRIPTION);
+ }
+}
+
+//==========================================================================
+//
+// SV_GetRebornSlot
+//
+//==========================================================================
+
+int SV_GetRebornSlot(void)
+{
+ return (REBORN_SLOT);
+}
+
+//==========================================================================
+//
+// SV_RebornSlotAvailable
+//
+// Returns true if the reborn slot is available.
+//
+//==========================================================================
+
+boolean SV_RebornSlotAvailable(void)
+{
+ char fileName[MAX_OSPATH];
+
+ snprintf(fileName, sizeof(fileName), "%shex%d.hxs", basePath, REBORN_SLOT);
+ return ExistingFile(fileName);
+}
+
+//==========================================================================
+//
+// SV_LoadMap
+//
+//==========================================================================
+
+void SV_LoadMap(void)
+{
+ char fileName[MAX_OSPATH];
+
+ // Load a base level
+ G_InitNew(gameskill, gameepisode, gamemap);
+
+ // Remove all thinkers
+ RemoveAllThinkers();
+
+ // Create the name
+ snprintf(fileName, sizeof(fileName), "%shex6%02d.hxs", basePath, gamemap);
+
+ // Load the file
+ M_ReadFile(fileName, &SaveBuffer);
+ SavePtr = (byte *) SaveBuffer;
+
+ AssertSegment(ASEG_MAP_HEADER);
+
+ // Read the level timer
+ leveltime = GET_LONG();
+
+ UnarchiveWorld();
+ UnarchivePolyobjs();
+ UnarchiveMobjs();
+ UnarchiveThinkers();
+ UnarchiveScripts();
+ UnarchiveSounds();
+ UnarchiveMisc();
+
+ AssertSegment(ASEG_END);
+
+ // Free mobj list and save buffer
+ Z_Free(MobjList);
+ Z_Free(SaveBuffer);
+}
+
+//==========================================================================
+//
+// SV_InitBaseSlot
+//
+//==========================================================================
+
+void SV_InitBaseSlot(void)
+{
+ ClearSaveSlot(BASE_SLOT);
+}
+
+//==========================================================================
+//
+// ArchivePlayers
+//
+//==========================================================================
+
+static void ArchivePlayers(void)
+{
+ int i, j;
+ save_player_t savp;
+ player_t *p;
+
+ StreamOutLong(ASEG_PLAYERS);
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ StreamOutByte(playeringame[i]);
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ StreamOutByte(PlayerClasses[i]);
+
+ p = &players[i];
+ savp.mo_idx = 0;
+ savp.poisoner_idx = 0;
+ savp.attacker_idx = 0;
+ savp.playerstate = (int) LONG(p->playerstate);
+ savp.cmd.forwardmove = p->cmd.forwardmove;
+ savp.cmd.sidemove = p->cmd.sidemove;
+ savp.cmd.angleturn = (short) SHORT(p->cmd.angleturn);
+ savp.cmd.consistancy = (short) SHORT(p->cmd.consistancy);
+ savp.cmd.chatchar = p->cmd.chatchar;
+ savp.cmd.buttons = p->cmd.buttons;
+ savp.cmd.lookfly = p->cmd.lookfly;
+ savp.cmd.arti = p->cmd.arti;
+ savp.playerclass = (int) LONG(p->playerclass);
+ savp.viewz = (fixed_t) LONG(p->viewz);
+ savp.viewheight = (fixed_t) LONG(p->viewheight);
+ savp.deltaviewheight = (fixed_t) LONG(p->deltaviewheight);
+ savp.bob = (fixed_t) LONG(p->bob);
+ savp.flyheight = (int) LONG(p->flyheight);
+ savp.lookdir = (int) LONG(p->lookdir);
+ savp.centering = (int) LONG(p->centering);
+ savp.health = (int) LONG(p->health);
+ for (j = 0; j < NUMARMOR; j++)
+ {
+ savp.armorpoints[j] = (int) LONG(p->armorpoints[j]);
+ }
+ for (j = 0; j < NUMINVENTORYSLOTS; j++)
+ {
+ savp.inventory[j].type = (int) LONG(p->inventory[j].type);
+ savp.inventory[j].count = (int) LONG(p->inventory[j].count);
+ }
+ savp.readyArtifact = (int) LONG(p->readyArtifact);
+ savp.inventorySlotNum = (int) LONG(p->inventorySlotNum);
+ savp.artifactCount = (int) LONG(p->artifactCount);
+ for (j = 0; j < NUMPOWERS; j++)
+ {
+ savp.powers[j] = (int) LONG(p->powers[j]);
+ }
+ savp.keys = (int) LONG(p->keys);
+ savp.pieces = (int) LONG(p->pieces);
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ savp.frags[j] = (signed int) LONG(p->frags[j]);
+ }
+ savp.readyweapon = (int) LONG(p->readyweapon);
+ savp.pendingweapon = (int) LONG(p->pendingweapon);
+ for (j = 0; j < NUMWEAPONS; j++)
+ {
+ savp.weaponowned[j] = (int) LONG(p->weaponowned[j]);
+ }
+ for (j = 0; j < NUMMANA; j++)
+ {
+ savp.mana[j] = (int) LONG(p->mana[j]);
+ }
+ savp.attackdown = (int) LONG(p->attackdown);
+ savp.usedown = (int) LONG(p->usedown);
+ savp.cheats = (int) LONG(p->cheats);
+ savp.refire = (int) LONG(p->refire);
+ savp.killcount = (int) LONG(p->killcount);
+ savp.itemcount = (int) LONG(p->itemcount);
+ savp.secretcount = (int) LONG(p->secretcount);
+ memcpy (savp.message, p->message, 80);
+ savp.messageTics = (int) LONG(p->messageTics);
+ savp.ultimateMessage = (short) SHORT(p->ultimateMessage);
+ savp.yellowMessage = (short) SHORT(p->yellowMessage);
+ savp.damagecount = (int) LONG(p->damagecount);
+ savp.bonuscount = (int) LONG(p->bonuscount);
+ savp.poisoncount = (int) LONG(p->poisoncount);
+ savp.extralight = (int) LONG(p->extralight);
+ savp.fixedcolormap = (int) LONG(p->fixedcolormap);
+ savp.colormap = (int) LONG(p->colormap);
+ savp.morphTics = (int) LONG(p->morphTics);
+ savp.jumpTics = (unsigned int) LONG(p->jumpTics);
+ savp.worldTimer = (unsigned int) LONG(p->worldTimer);
+ for (j = 0; j < NUMPSPRITES; j++)
+ {
+ savp.psprites[j].tics = (int) LONG(p->psprites[j].tics);
+ savp.psprites[j].sx = (fixed_t) LONG(p->psprites[j].sx);
+ savp.psprites[j].sy = (fixed_t) LONG(p->psprites[j].sy);
+ if (p->psprites[j].state)
+ {
+ savp.psprites[j].state_idx =
+ LONG((int32_t) (p->psprites[j].state - states));
+ }
+ else
+ {
+ savp.psprites[j].state_idx = 0;
+ }
+ }
+ StreamOutBuffer(&savp, sizeof(save_player_t));
+ }
+}
+
+//==========================================================================
+//
+// UnarchivePlayers
+//
+//==========================================================================
+
+static void UnarchivePlayers(void)
+{
+ int i, j;
+ save_player_t savp;
+ player_t *p;
+
+ AssertSegment(ASEG_PLAYERS);
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ playeringame[i] = GET_BYTE();
+ }
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (!playeringame[i])
+ {
+ continue;
+ }
+ PlayerClasses[i] = GET_BYTE();
+ memcpy(&savp, SavePtr, sizeof(save_player_t));
+ SavePtr += sizeof(save_player_t);
+
+ p = &players[i];
+ p->mo = NULL; // Will be set when unarc thinker
+ p->attacker = NULL;
+ p->poisoner = NULL;
+ p->playerstate = (playerstate_t) LONG(savp.playerstate);
+ p->cmd.forwardmove = savp.cmd.forwardmove;
+ p->cmd.sidemove = savp.cmd.sidemove;
+ p->cmd.angleturn = (short) SHORT(savp.cmd.angleturn);
+ p->cmd.consistancy = (short) SHORT(savp.cmd.consistancy);
+ p->cmd.chatchar = savp.cmd.chatchar;
+ p->cmd.buttons = savp.cmd.buttons;
+ p->cmd.lookfly = savp.cmd.lookfly;
+ p->cmd.arti = savp.cmd.arti;
+ p->playerclass = (pclass_t) LONG(savp.playerclass);
+ p->viewz = (fixed_t) LONG(savp.viewz);
+ p->viewheight = (fixed_t) LONG(savp.viewheight);
+ p->deltaviewheight = (fixed_t) LONG(savp.deltaviewheight);
+ p->bob = (fixed_t) LONG(savp.bob);
+ p->flyheight = (int) LONG(savp.flyheight);
+ p->lookdir = (int) LONG(savp.lookdir);
+ p->centering = !!(LONG(savp.centering));
+ p->health = (int) LONG(savp.health);
+ for (j = 0; j < NUMARMOR; j++)
+ {
+ p->armorpoints[j] = (int) LONG(savp.armorpoints[j]);
+ }
+ for (j = 0; j < NUMINVENTORYSLOTS; j++)
+ {
+ p->inventory[j].type = (int) LONG(savp.inventory[j].type);
+ p->inventory[j].count = (int) LONG(savp.inventory[j].count);
+ }
+ p->readyArtifact = (artitype_t) LONG(savp.readyArtifact);
+ p->artifactCount = (int) LONG(savp.artifactCount);
+ p->inventorySlotNum = (int) LONG(savp.inventorySlotNum);
+ for (j = 0; j < NUMPOWERS; j++)
+ {
+ p->powers[j] = (int) LONG(savp.powers[j]);
+ }
+ p->keys = (int) LONG(savp.keys);
+ p->pieces = (int) LONG(savp.pieces);
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ p->frags[j] = (signed int) LONG(savp.frags[j]);
+ }
+ p->readyweapon = (weapontype_t) LONG(savp.readyweapon);
+ p->pendingweapon = (weapontype_t) LONG(savp.pendingweapon);
+ for (j = 0; j < NUMWEAPONS; j++)
+ {
+ p->weaponowned[j] = !!(LONG(savp.weaponowned[j]));
+ }
+ for (j = 0; j < NUMMANA; j++)
+ {
+ p->mana[j] = (int) LONG(savp.mana[j]);
+ }
+ p->attackdown = (int) LONG(savp.attackdown);
+ p->usedown = (int) LONG(savp.usedown);
+ p->cheats = (int) LONG(savp.cheats);
+ p->refire = (int) LONG(savp.refire);
+ p->killcount = (int) LONG(savp.killcount);
+ p->itemcount = (int) LONG(savp.itemcount);
+ p->secretcount = (int) LONG(savp.secretcount);
+ memcpy (p->message, savp.message, 80);
+ p->messageTics = (int) LONG(savp.messageTics);
+ p->ultimateMessage = (short) SHORT(savp.ultimateMessage);
+ p->yellowMessage = (short) SHORT(savp.yellowMessage);
+ p->damagecount = (int) LONG(savp.damagecount);
+ p->bonuscount = (int) LONG(savp.bonuscount);
+ p->poisoncount = (int) LONG(savp.poisoncount);
+ p->extralight = (int) LONG(savp.extralight);
+ p->fixedcolormap = (int) LONG(savp.fixedcolormap);
+ p->colormap = (int) LONG(savp.colormap);
+ p->morphTics = (int) LONG(savp.morphTics);
+ p->jumpTics = (unsigned int) LONG(savp.jumpTics);
+ p->worldTimer = (unsigned int) LONG(savp.worldTimer);
+ P_ClearMessage(p);
+ for (j = 0; j < NUMPSPRITES; j++)
+ {
+ p->psprites[j].tics = (int) LONG(savp.psprites[j].tics);
+ p->psprites[j].sx = (fixed_t) LONG(savp.psprites[j].sx);
+ p->psprites[j].sy = (fixed_t) LONG(savp.psprites[j].sy);
+ if (savp.psprites[j].state_idx)
+ {
+ savp.psprites[j].state_idx =
+ LONG(savp.psprites[j].state_idx);
+ p->psprites[j].state =
+ &states[savp.psprites[j].state_idx];
+ }
+ else
+ {
+ p->psprites[j].state = NULL;
+ }
+ }
+ }
+}
+
+//==========================================================================
+//
+// ArchiveWorld
+//
+//==========================================================================
+
+static void ArchiveWorld(void)
+{
+ int i;
+ int j;
+ sector_t *sec;
+ line_t *li;
+ side_t *si;
+
+ StreamOutLong(ASEG_WORLD);
+ for (i = 0, sec = sectors; i < numsectors; i++, sec++)
+ {
+ StreamOutWord(sec->floorheight>>FRACBITS);
+ StreamOutWord(sec->ceilingheight>>FRACBITS);
+ StreamOutWord(sec->floorpic);
+ StreamOutWord(sec->ceilingpic);
+ StreamOutWord(sec->lightlevel);
+ StreamOutWord(sec->special);
+ StreamOutWord(sec->tag);
+ StreamOutWord(sec->seqType);
+ }
+ for (i = 0, li = lines; i < numlines; i++, li++)
+ {
+ StreamOutWord(li->flags);
+ StreamOutByte(li->special);
+ StreamOutByte(li->arg1);
+ StreamOutByte(li->arg2);
+ StreamOutByte(li->arg3);
+ StreamOutByte(li->arg4);
+ StreamOutByte(li->arg5);
+ for (j = 0; j < 2; j++)
+ {
+ if (li->sidenum[j] == -1)
+ {
+ continue;
+ }
+ si = &sides[li->sidenum[j]];
+ StreamOutWord(si->textureoffset>>FRACBITS);
+ StreamOutWord(si->rowoffset>>FRACBITS);
+ StreamOutWord(si->toptexture);
+ StreamOutWord(si->bottomtexture);
+ StreamOutWord(si->midtexture);
+ }
+ }
+}
+
+//==========================================================================
+//
+// UnarchiveWorld
+//
+//==========================================================================
+
+static void UnarchiveWorld(void)
+{
+ int i;
+ int j;
+ sector_t *sec;
+ line_t *li;
+ side_t *si;
+
+ AssertSegment(ASEG_WORLD);
+ for (i = 0, sec = sectors; i < numsectors; i++, sec++)
+ {
+ sec->floorheight = ((fixed_t) GET_WORD())<<FRACBITS;
+ sec->ceilingheight = ((fixed_t) GET_WORD())<<FRACBITS;
+ sec->floorpic = GET_WORD();
+ sec->ceilingpic = GET_WORD();
+ sec->lightlevel = GET_WORD();
+ sec->special = GET_WORD();
+ sec->tag = GET_WORD();
+ sec->seqType = GET_WORD();
+ sec->specialdata = NULL;
+ sec->soundtarget = NULL;
+ }
+ for (i = 0, li = lines; i < numlines; i++, li++)
+ {
+ li->flags = GET_WORD();
+ li->special = GET_BYTE();
+ li->arg1 = GET_BYTE();
+ li->arg2 = GET_BYTE();
+ li->arg3 = GET_BYTE();
+ li->arg4 = GET_BYTE();
+ li->arg5 = GET_BYTE();
+ for (j = 0; j < 2; j++)
+ {
+ if (li->sidenum[j] == -1)
+ {
+ continue;
+ }
+ si = &sides[li->sidenum[j]];
+ si->textureoffset = ((fixed_t) GET_WORD())<<FRACBITS;
+ si->rowoffset = ((fixed_t) GET_WORD())<<FRACBITS;
+ si->toptexture = GET_WORD();
+ si->bottomtexture = GET_WORD();
+ si->midtexture = GET_WORD();
+ }
+ }
+}
+
+//==========================================================================
+//
+// SetMobjArchiveNums
+//
+// Sets the archive numbers in all mobj structs. Also sets the MobjCount
+// global. Ignores player mobjs if SavingPlayers is false.
+//
+//==========================================================================
+
+static void SetMobjArchiveNums(void)
+{
+ mobj_t *mobj;
+ thinker_t *thinker;
+
+ MobjCount = 0;
+ for (thinker = thinkercap.next; thinker != &thinkercap;
+ thinker = thinker->next)
+ {
+ if (thinker->function == P_MobjThinker)
+ {
+ mobj = (mobj_t *)thinker;
+ if (mobj->player && !SavingPlayers)
+ { // Skipping player mobjs
+ continue;
+ }
+ mobj->archiveNum = MobjCount++;
+ }
+ }
+}
+
+//==========================================================================
+//
+// ArchiveMobjs
+//
+//==========================================================================
+
+static void ArchiveMobjs(void)
+{
+ int count;
+ thinker_t *thinker;
+ save_mobj_t tempMobj;
+ mobj_t *mobj;
+
+ StreamOutLong(ASEG_MOBJS);
+ StreamOutLong(MobjCount);
+ count = 0;
+ for (thinker = thinkercap.next; thinker != &thinkercap;
+ thinker = thinker->next)
+ {
+ if (thinker->function != P_MobjThinker)
+ { // Not a mobj thinker
+ continue;
+ }
+ mobj = (mobj_t *)thinker;
+ if (mobj->player && !SavingPlayers)
+ { // Skipping player mobjs
+ continue;
+ }
+ count++;
+ memset(&tempMobj, 0, sizeof(save_mobj_t));
+ MangleMobj(mobj, &tempMobj);
+ StreamOutBuffer(&tempMobj, sizeof(save_mobj_t));
+ }
+ if (count != MobjCount)
+ {
+ I_Error("ArchiveMobjs: bad mobj count");
+ }
+}
+
+//==========================================================================
+//
+// UnarchiveMobjs
+//
+//==========================================================================
+
+static void UnarchiveMobjs(void)
+{
+ int i;
+ save_mobj_t tempMobj;
+ mobj_t *mobj;
+
+ AssertSegment(ASEG_MOBJS);
+ TargetPlayerAddrs = (intptr_t **) Z_Malloc(MAX_TARGET_PLAYERS*sizeof(intptr_t *), PU_STATIC, NULL);
+ TargetPlayerCount = 0;
+ MobjCount = GET_LONG();
+ MobjList = (mobj_t **) Z_Malloc(MobjCount*sizeof(mobj_t *), PU_STATIC, NULL);
+ for (i = 0; i < MobjCount; i++)
+ {
+ MobjList[i] = (mobj_t *) Z_Malloc(sizeof(mobj_t), PU_LEVEL, NULL);
+ }
+ for (i = 0; i < MobjCount; i++)
+ {
+ mobj = MobjList[i];
+ memset(&tempMobj, 0, sizeof(save_mobj_t));
+ memset(mobj, 0, sizeof(mobj_t));
+ memcpy(&tempMobj, SavePtr, sizeof(save_mobj_t));
+ SavePtr += sizeof(save_mobj_t);
+ RestoreMobj(mobj, &tempMobj);
+ P_AddThinker(&mobj->thinker);
+ }
+ P_CreateTIDList();
+ P_InitCreatureCorpseQueue(true); // true = scan for corpses
+}
+
+//==========================================================================
+//
+// MangleMobj
+//
+//==========================================================================
+
+static void MangleMobj(mobj_t *mobj, save_mobj_t *temp)
+{
+ boolean corpse;
+
+ temp->x = (fixed_t) LONG(mobj->x);
+ temp->y = (fixed_t) LONG(mobj->y);
+ temp->z = (fixed_t) LONG(mobj->z);
+ temp->angle = (angle_t) LONG(mobj->angle);
+ temp->sprite = (int) LONG(mobj->sprite);
+ temp->frame = (int) LONG(mobj->frame);
+ temp->floorpic = (fixed_t) LONG(mobj->floorpic);
+ temp->radius = (fixed_t) LONG(mobj->radius);
+ temp->height = (fixed_t) LONG(mobj->height);
+ temp->momx = (fixed_t) LONG(mobj->momx);
+ temp->momy = (fixed_t) LONG(mobj->momy);
+ temp->momz = (fixed_t) LONG(mobj->momz);
+ temp->validcount = (int) LONG(mobj->validcount);
+ temp->type = (int) LONG(mobj->type);
+ temp->tics = (int) LONG(mobj->tics);
+ temp->damage = (int) LONG(mobj->damage);
+ temp->flags = (int) LONG(mobj->flags);
+ temp->flags2 = (int) LONG(mobj->flags2);
+ temp->health = (int) LONG(mobj->health);
+ temp->movedir = (int) LONG(mobj->movedir);
+ temp->movecount = (int) LONG(mobj->movecount);
+ temp->reactiontime = (int) LONG(mobj->reactiontime);
+ temp->threshold = (int) LONG(mobj->threshold);
+ temp->lastlook = (int) LONG(mobj->lastlook);
+ temp->floorclip = (fixed_t) LONG(mobj->floorclip);
+ temp->archiveNum = (int) LONG(mobj->archiveNum);
+ temp->tid = (short) SHORT(mobj->tid);
+ temp->special = mobj->special;
+ temp->args[0] = mobj->args[0];
+ temp->args[1] = mobj->args[1];
+ temp->args[2] = mobj->args[2];
+ temp->args[3] = mobj->args[3];
+ temp->args[4] = mobj->args[4];
+
+ corpse = mobj->flags & MF_CORPSE;
+ temp->state_idx = LONG((int32_t)(mobj->state - states));
+ if (mobj->player)
+ {
+ temp->player_idx = LONG((int32_t)((mobj->player - players) + 1));
+ }
+ if (corpse)
+ {
+ temp->target_idx = (int32_t) LONG(MOBJ_NULL);
+ }
+ else
+ {
+ temp->target_idx = (int32_t) LONG(GetMobjNum(mobj->target));
+ }
+ switch (mobj->type)
+ {
+ // Just special1
+ case MT_BISH_FX:
+ case MT_HOLY_FX:
+ case MT_DRAGON:
+ case MT_THRUSTFLOOR_UP:
+ case MT_THRUSTFLOOR_DOWN:
+ case MT_MINOTAUR:
+ case MT_SORCFX1:
+ case MT_MSTAFF_FX2:
+ if (corpse)
+ {
+ temp->special1 = (int32_t) LONG(MOBJ_NULL);
+ }
+ else
+ {
+ temp->special1 = (int32_t) LONG(GetMobjNum((mobj_t *)mobj->special1));
+ }
+ break;
+
+ // Just special2
+ case MT_LIGHTNING_FLOOR:
+ case MT_LIGHTNING_ZAP:
+ if (corpse)
+ {
+ temp->special2 = (int32_t) LONG(MOBJ_NULL);
+ }
+ else
+ {
+ temp->special2 = (int32_t) LONG(GetMobjNum((mobj_t *)mobj->special2));
+ }
+ break;
+
+ // Both special1 and special2
+ case MT_HOLY_TAIL:
+ case MT_LIGHTNING_CEILING:
+ if (corpse)
+ {
+ temp->special1 = (int32_t) LONG(MOBJ_NULL);
+ temp->special2 = (int32_t) LONG(MOBJ_NULL);
+ }
+ else
+ {
+ temp->special1 = (int32_t) LONG(GetMobjNum((mobj_t *)mobj->special1));
+ temp->special2 = (int32_t) LONG(GetMobjNum((mobj_t *)mobj->special2));
+ }
+ break;
+
+ // Miscellaneous
+ case MT_KORAX:
+ temp->special1 = 0; // Searching index
+ break;
+
+ default:
+ break;
+ }
+}
+
+//==========================================================================
+//
+// GetMobjNum
+//
+//==========================================================================
+
+static int32_t GetMobjNum(mobj_t *mobj)
+{
+ if (mobj == NULL)
+ {
+ return MOBJ_NULL;
+ }
+ if (mobj->player && !SavingPlayers)
+ {
+ return MOBJ_XX_PLAYER;
+ }
+ return mobj->archiveNum;
+}
+
+//==========================================================================
+//
+// RestoreMobj
+//
+//==========================================================================
+
+static void RestoreMobj(mobj_t *mobj, save_mobj_t *temp)
+{
+ mobj->x = (fixed_t) LONG(temp->x);
+ mobj->y = (fixed_t) LONG(temp->y);
+ mobj->z = (fixed_t) LONG(temp->z);
+ mobj->angle = (angle_t) LONG(temp->angle);
+ mobj->sprite = (spritenum_t) LONG(temp->sprite);
+ mobj->frame = (int) LONG(temp->frame);
+ mobj->floorpic = (fixed_t) LONG(temp->floorpic);
+ mobj->radius = (fixed_t) LONG(temp->radius);
+ mobj->height = (fixed_t) LONG(temp->height);
+ mobj->momx = (fixed_t) LONG(temp->momx);
+ mobj->momy = (fixed_t) LONG(temp->momy);
+ mobj->momz = (fixed_t) LONG(temp->momz);
+ mobj->validcount = (int) LONG(temp->validcount);
+ mobj->type = (mobjtype_t) LONG(temp->type);
+ mobj->tics = (int) LONG(temp->tics);
+ mobj->damage = (int) LONG(temp->damage);
+ mobj->flags = (int) LONG(temp->flags);
+ mobj->flags2 = (int) LONG(temp->flags2);
+ mobj->health = (int) LONG(temp->health);
+ mobj->movedir = (int) LONG(temp->movedir);
+ mobj->movecount = (int) LONG(temp->movecount);
+ mobj->reactiontime = (int) LONG(temp->reactiontime);
+ mobj->threshold = (int) LONG(temp->threshold);
+ mobj->lastlook = (int) LONG(temp->lastlook);
+ mobj->floorclip = (fixed_t) LONG(temp->floorclip);
+ mobj->archiveNum = (int) LONG(temp->archiveNum);
+ mobj->tid = (short) SHORT(temp->tid);
+ mobj->special = temp->special;
+ mobj->args[0] = temp->args[0];
+ mobj->args[1] = temp->args[1];
+ mobj->args[2] = temp->args[2];
+ mobj->args[3] = temp->args[3];
+ mobj->args[4] = temp->args[4];
+
+ temp->state_idx = (int32_t) LONG(temp->state_idx);
+ temp->player_idx = (int32_t) LONG(temp->player_idx);
+ temp->target_idx = (int32_t) LONG(temp->target_idx);
+ temp->special1 = (int32_t) LONG(temp->special1);
+ temp->special2 = (int32_t) LONG(temp->special2);
+
+ mobj->thinker.function = P_MobjThinker;
+ mobj->state = &states[temp->state_idx];
+ if (temp->player_idx)
+ {
+ mobj->player = &players[temp->player_idx - 1];
+ mobj->player->mo = mobj;
+ }
+ P_SetThingPosition(mobj);
+ mobj->info = &mobjinfo[mobj->type];
+ mobj->floorz = mobj->subsector->sector->floorheight;
+ mobj->ceilingz = mobj->subsector->sector->ceilingheight;
+ mobj->target = GetMobjPtr(temp->target_idx, (intptr_t *)(void *)&mobj->target);
+ switch (mobj->type)
+ {
+ // Just special1
+ case MT_BISH_FX:
+ case MT_HOLY_FX:
+ case MT_DRAGON:
+ case MT_THRUSTFLOOR_UP:
+ case MT_THRUSTFLOOR_DOWN:
+ case MT_MINOTAUR:
+ case MT_SORCFX1:
+ mobj->special1 = (intptr_t) GetMobjPtr(temp->special1, &mobj->special1);
+ break;
+
+ // Just special2
+ case MT_LIGHTNING_FLOOR:
+ case MT_LIGHTNING_ZAP:
+ mobj->special2 = (intptr_t) GetMobjPtr(temp->special2, &mobj->special2);
+ break;
+
+ // Both special1 and special2
+ case MT_HOLY_TAIL:
+ case MT_LIGHTNING_CEILING:
+ mobj->special1 = (intptr_t) GetMobjPtr(temp->special1, &mobj->special1);
+ mobj->special2 = (intptr_t) GetMobjPtr(temp->special2, &mobj->special2);
+ break;
+
+ default:
+ break;
+ }
+}
+
+//==========================================================================
+//
+// GetMobjPtr
+//
+//==========================================================================
+
+static mobj_t *GetMobjPtr(int32_t archiveNum, intptr_t *target)
+{
+ if (archiveNum == MOBJ_NULL)
+ {
+ return NULL;
+ }
+ if (archiveNum == MOBJ_XX_PLAYER)
+ {
+ if (TargetPlayerCount == MAX_TARGET_PLAYERS)
+ {
+ I_Error("RestoreMobj: exceeded MAX_TARGET_PLAYERS");
+ }
+ TargetPlayerAddrs[TargetPlayerCount++] = target;
+ return NULL;
+ }
+ return MobjList[archiveNum];
+}
+
+//==========================================================================
+//
+// ArchiveThinkers
+//
+//==========================================================================
+
+static void ArchiveThinkers(void)
+{
+ thinker_t *thinker;
+ thinkInfo_t *info;
+ byte buffer[MAX_THINKER_SIZE];
+
+ StreamOutLong(ASEG_THINKERS);
+ for (thinker = thinkercap.next; thinker != &thinkercap;
+ thinker = thinker->next)
+ {
+ for (info = ThinkerInfo; info->tClass != TC_NULL; info++)
+ {
+ if (thinker->function == info->thinkerFunc)
+ {
+ StreamOutByte(info->tClass);
+ memset(buffer, 0, sizeof(buffer));
+ info->mangleFunc(thinker, buffer);
+ StreamOutBuffer(buffer, info->savesize);
+ break;
+ }
+ }
+ }
+ // Add a termination marker
+ StreamOutByte(TC_NULL);
+}
+
+//==========================================================================
+//
+// UnarchiveThinkers
+//
+//==========================================================================
+
+static void UnarchiveThinkers(void)
+{
+ int tClass;
+ thinker_t *thinker;
+ thinkInfo_t *info;
+ byte buffer[MAX_THINKER_SIZE];
+
+ AssertSegment(ASEG_THINKERS);
+ while ((tClass = GET_BYTE()) != TC_NULL)
+ {
+ for (info = ThinkerInfo; info->tClass != TC_NULL; info++)
+ {
+ if (tClass == info->tClass)
+ {
+ thinker = (thinker_t *) Z_Malloc(info->realsize, PU_LEVEL, NULL);
+ memset(thinker, 0, info->realsize);
+ memset(buffer, 0, sizeof(buffer));
+ memcpy(buffer, SavePtr, info->savesize);
+ SavePtr += info->savesize;
+ thinker->function = info->thinkerFunc;
+ info->restoreFunc(thinker, buffer);
+ P_AddThinker(thinker);
+ break;
+ }
+ }
+ if (info->tClass == TC_NULL)
+ {
+ I_Error("UnarchiveThinkers: Unknown tClass %d in savegame", tClass);
+ }
+ }
+}
+
+//==========================================================================
+//
+// MangleFloorMove
+//
+//==========================================================================
+
+static void MangleFloorMove(void *arg1, void *arg2)
+{
+ floormove_t *fm = (floormove_t *) arg1;
+ save_floormove_t *temp = (save_floormove_t *) arg2;
+
+ temp->sector_idx = LONG((int32_t)(fm->sector - sectors));
+ temp->type = (int) LONG(fm->type);
+ temp->crush = (int) LONG(fm->crush);
+ temp->direction = (int) LONG(fm->direction);
+ temp->newspecial = (int) LONG(fm->newspecial);
+ temp->texture = (short) SHORT(fm->texture);
+ temp->floordestheight = (fixed_t) LONG(fm->floordestheight);
+ temp->speed = (fixed_t) LONG(fm->speed);
+ temp->delayCount = (int) LONG(fm->delayCount);
+ temp->delayTotal = (int) LONG(fm->delayTotal);
+ temp->stairsDelayHeight = (fixed_t) LONG(fm->stairsDelayHeight);
+ temp->stairsDelayHeightDelta = (fixed_t) LONG(fm->stairsDelayHeightDelta);
+ temp->resetHeight = (fixed_t) LONG(fm->resetHeight);
+ temp->resetDelay = (short) SHORT(fm->resetDelay);
+ temp->resetDelayCount = (short) SHORT(fm->resetDelayCount);
+ temp->textureChange = fm->textureChange;
+}
+
+//==========================================================================
+//
+// RestoreFloorMove
+//
+//==========================================================================
+
+static void RestoreFloorMove(void *arg1, void *arg2)
+{
+ floormove_t *fm = (floormove_t *) arg1;
+ save_floormove_t *temp = (save_floormove_t *) arg2;
+
+ temp->sector_idx = LONG(temp->sector_idx);
+ fm->sector = §ors[temp->sector_idx];
+ fm->sector->specialdata = T_MoveFloor; //fm->thinker.function
+ fm->type = (floor_e) LONG(temp->type);
+ fm->crush = (int) LONG(temp->crush);
+ fm->direction = (int) LONG(temp->direction);
+ fm->newspecial = (int) LONG(temp->newspecial);
+ fm->texture = (short) SHORT(temp->texture);
+ fm->floordestheight = (fixed_t) LONG(temp->floordestheight);
+ fm->speed = (fixed_t) LONG(temp->speed);
+ fm->delayCount = (int) LONG(temp->delayCount);
+ fm->delayTotal = (int) LONG(temp->delayTotal);
+ fm->stairsDelayHeight = (fixed_t) LONG(temp->stairsDelayHeight);
+ fm->stairsDelayHeightDelta = (fixed_t) LONG(temp->stairsDelayHeightDelta);
+ fm->resetHeight = (fixed_t) LONG(temp->resetHeight);
+ fm->resetDelay = (short) SHORT(temp->resetDelay);
+ fm->resetDelayCount = (short) SHORT(temp->resetDelayCount);
+ fm->textureChange = temp->textureChange;
+}
+
+//==========================================================================
+//
+// MangleLight
+//
+//==========================================================================
+
+static void MangleLight(void *arg1, void *arg2)
+{
+ light_t *light = (light_t *) arg1;
+ save_light_t *temp = (save_light_t *) arg2;
+
+ temp->sector_idx = LONG((int32_t)(light->sector - sectors));
+ temp->type = (int) LONG(light->type);
+ temp->value1 = (int) LONG(light->value1);
+ temp->value2 = (int) LONG(light->value2);
+ temp->tics1 = (int) LONG(light->tics1);
+ temp->tics2 = (int) LONG(light->tics2);
+ temp->count = (int) LONG(light->count);
+}
+
+//==========================================================================
+//
+// RestoreLight
+//
+//==========================================================================
+
+static void RestoreLight(void *arg1, void *arg2)
+{
+ light_t *light = (light_t *) arg1;
+ save_light_t *temp = (save_light_t *) arg2;
+
+ temp->sector_idx = LONG(temp->sector_idx);
+ light->sector = §ors[temp->sector_idx];
+ light->type = (lighttype_t) LONG(temp->type);
+ light->value1 = (int) LONG(temp->value1);
+ light->value2 = (int) LONG(temp->value2);
+ light->tics1 = (int) LONG(temp->tics1);
+ light->tics2 = (int) LONG(temp->tics2);
+ light->count = (int) LONG(temp->count);
+}
+
+//==========================================================================
+//
+// MangleVerticalDoor
+//
+//==========================================================================
+
+static void MangleVerticalDoor(void *arg1, void *arg2)
+{
+ vldoor_t *vldoor = (vldoor_t *) arg1;
+ save_vldoor_t *temp = (save_vldoor_t *) arg2;
+
+ temp->sector_idx = LONG((int32_t)(vldoor->sector - sectors));
+ temp->type = (int) LONG(vldoor->type);
+ temp->topheight = (fixed_t) LONG(vldoor->topheight);
+ temp->speed = (fixed_t) LONG(vldoor->speed);
+ temp->direction = (int) LONG(vldoor->direction);
+ temp->topwait = (int) LONG(vldoor->topwait);
+ temp->topcountdown = (int) LONG(vldoor->topcountdown);
+}
+
+//==========================================================================
+//
+// RestoreVerticalDoor
+//
+//==========================================================================
+
+static void RestoreVerticalDoor(void *arg1, void *arg2)
+{
+ vldoor_t *vldoor = (vldoor_t *) arg1;
+ save_vldoor_t *temp = (save_vldoor_t *) arg2;
+
+ temp->sector_idx = LONG(temp->sector_idx);
+ vldoor->sector = §ors[temp->sector_idx];
+ vldoor->sector->specialdata = T_VerticalDoor; //vldoor->thinker.function
+ vldoor->type = (vldoor_e) LONG(temp->type);
+ vldoor->topheight = (fixed_t) LONG(temp->topheight);
+ vldoor->speed = (fixed_t) LONG(temp->speed);
+ vldoor->direction = (int) LONG(temp->direction);
+ vldoor->topwait = (int) LONG(temp->topwait);
+ vldoor->topcountdown = (int) LONG(temp->topcountdown);
+}
+
+//==========================================================================
+//
+// ManglePhase
+//
+//==========================================================================
+
+static void ManglePhase(void *arg1, void *arg2)
+{
+ phase_t *phase = (phase_t *) arg1;
+ save_phase_t *temp = (save_phase_t *) arg2;
+
+ temp->sector_idx = LONG((int32_t)(phase->sector - sectors));
+ temp->index = (int) LONG(phase->index);
+ temp->base = (int) LONG(phase->base);
+}
+
+//==========================================================================
+//
+// RestorePhase
+//
+//==========================================================================
+
+static void RestorePhase(void *arg1, void *arg2)
+{
+ phase_t *phase = (phase_t *) arg1;
+ save_phase_t *temp = (save_phase_t *) arg2;
+
+ temp->sector_idx = LONG(temp->sector_idx);
+ phase->sector = §ors[temp->sector_idx];
+ phase->index = (int) LONG(temp->index);
+ phase->base = (int) LONG(temp->base);
+}
+
+//==========================================================================
+//
+// ManglePillar
+//
+//==========================================================================
+
+static void ManglePillar(void *arg1, void *arg2)
+{
+ pillar_t *pillar = (pillar_t *) arg1;
+ save_pillar_t *temp = (save_pillar_t *) arg2;
+
+ temp->sector_idx = LONG((int32_t)(pillar->sector - sectors));
+ temp->ceilingSpeed = (int) LONG(pillar->ceilingSpeed);
+ temp->floorSpeed = (int) LONG(pillar->floorSpeed);
+ temp->floordest = (int) LONG(pillar->floordest);
+ temp->ceilingdest = (int) LONG(pillar->ceilingdest);
+ temp->direction = (int) LONG(pillar->direction);
+ temp->crush = (int) LONG(pillar->crush);
+}
+
+//==========================================================================
+//
+// RestorePillar
+//
+//==========================================================================
+
+static void RestorePillar(void *arg1, void *arg2)
+{
+ pillar_t *pillar = (pillar_t *) arg1;
+ save_pillar_t *temp = (save_pillar_t *) arg2;
+
+ temp->sector_idx = LONG(temp->sector_idx);
+ pillar->sector = §ors[temp->sector_idx];
+ pillar->sector->specialdata = T_BuildPillar; //pillar->thinker.function
+ pillar->ceilingSpeed = (int) LONG(temp->ceilingSpeed);
+ pillar->floorSpeed = (int) LONG(temp->floorSpeed);
+ pillar->floordest = (int) LONG(temp->floordest);
+ pillar->ceilingdest = (int) LONG(temp->ceilingdest);
+ pillar->direction = (int) LONG(temp->direction);
+ pillar->crush = (int) LONG(temp->crush);
+}
+
+//==========================================================================
+//
+// MangleFloorWaggle
+//
+//==========================================================================
+
+static void MangleFloorWaggle(void *arg1, void *arg2)
+{
+ floorWaggle_t *fw = (floorWaggle_t *) arg1;
+ save_floorWaggle_t *temp = (save_floorWaggle_t *) arg2;
+
+ temp->sector_idx = LONG((int32_t)(fw->sector - sectors));
+ temp->originalHeight = (fixed_t) LONG(fw->originalHeight);
+ temp->accumulator = (fixed_t) LONG(fw->accumulator);
+ temp->accDelta = (fixed_t) LONG(fw->accDelta);
+ temp->targetScale = (fixed_t) LONG(fw->targetScale);
+ temp->scale = (fixed_t) LONG(fw->scale);
+ temp->scaleDelta = (fixed_t) LONG(fw->scaleDelta);
+ temp->ticker = (int) LONG(fw->ticker);
+ temp->state = (int) LONG(fw->state);
+}
+
+//==========================================================================
+//
+// RestoreFloorWaggle
+//
+//==========================================================================
+
+static void RestoreFloorWaggle(void *arg1, void *arg2)
+{
+ floorWaggle_t *fw = (floorWaggle_t *) arg1;
+ save_floorWaggle_t *temp = (save_floorWaggle_t *) arg2;
+
+ temp->sector_idx = LONG(temp->sector_idx);
+ fw->sector = §ors[temp->sector_idx];
+ fw->sector->specialdata = T_FloorWaggle; //fw->thinker.function
+ fw->originalHeight = (fixed_t) LONG(temp->originalHeight);
+ fw->accumulator = (fixed_t) LONG(temp->accumulator);
+ fw->accDelta = (fixed_t) LONG(temp->accDelta);
+ fw->targetScale = (fixed_t) LONG(temp->targetScale);
+ fw->scale = (fixed_t) LONG(temp->scale);
+ fw->scaleDelta = (fixed_t) LONG(temp->scaleDelta);
+ fw->ticker = (int) LONG(temp->ticker);
+ fw->state = (int) LONG(temp->state);
+}
+
+//==========================================================================
+//
+// ManglePolyEvent
+//
+//==========================================================================
+
+static void ManglePolyEvent(void *arg1, void *arg2)
+{
+ polyevent_t *pe = (polyevent_t *) arg1;
+ save_polyevent_t *temp = (save_polyevent_t *) arg2;
+
+ temp->polyobj = LONG(pe->polyobj);
+ temp->speed = LONG(pe->speed);
+ temp->dist = LONG(pe->dist);
+ temp->angle = LONG(pe->angle);
+ temp->xSpeed = LONG(pe->xSpeed);
+ temp->ySpeed = LONG(pe->ySpeed);
+}
+
+//==========================================================================
+//
+// RestorePolyEvent
+//
+//==========================================================================
+
+static void RestorePolyEvent(void *arg1, void *arg2)
+{
+ polyevent_t *pe = (polyevent_t *) arg1;
+ save_polyevent_t *temp = (save_polyevent_t *) arg2;
+
+ pe->polyobj = (int) LONG(temp->polyobj);
+ pe->speed = (int) LONG(temp->speed);
+ pe->dist = (unsigned int) LONG(temp->dist);
+ pe->angle = (int) LONG(temp->angle);
+ pe->xSpeed = (fixed_t) LONG(temp->xSpeed);
+ pe->ySpeed = (fixed_t) LONG(temp->ySpeed);
+}
+
+//==========================================================================
+//
+// ManglePolyDoor
+//
+//==========================================================================
+
+static void ManglePolyDoor(void *arg1, void *arg2)
+{
+ polydoor_t *pd = (polydoor_t *) arg1;
+ save_polydoor_t *temp = (save_polydoor_t *) arg2;
+
+ temp->polyobj = (int) LONG(pd->polyobj);
+ temp->speed = (int) LONG(pd->speed);
+ temp->dist = (int) LONG(pd->dist);
+ temp->totalDist = (int) LONG(pd->totalDist);
+ temp->direction = (int) LONG(pd->direction);
+ temp->xSpeed = (fixed_t) LONG(pd->xSpeed);
+ temp->ySpeed = (fixed_t) LONG(pd->ySpeed);
+ temp->tics = (int) LONG(pd->tics);
+ temp->waitTics = (int) LONG(pd->waitTics);
+ temp->type = (int) LONG(pd->type);
+ temp->close = (int) LONG(pd->close);
+}
+
+//==========================================================================
+//
+// RestorePolyEvent
+//
+//==========================================================================
+
+static void RestorePolyDoor(void *arg1, void *arg2)
+{
+ polydoor_t *pd = (polydoor_t *) arg1;
+ save_polydoor_t *temp = (save_polydoor_t *) arg2;
+
+ pd->polyobj = (int) LONG(temp->polyobj);
+ pd->speed = (int) LONG(temp->speed);
+ pd->dist = (int) LONG(temp->dist);
+ pd->totalDist = (int) LONG(temp->totalDist);
+ pd->direction = (int) LONG(temp->direction);
+ pd->xSpeed = (fixed_t) LONG(temp->xSpeed);
+ pd->ySpeed = (fixed_t) LONG(temp->ySpeed);
+ pd->tics = (int) LONG(temp->tics);
+ pd->waitTics = (int) LONG(temp->waitTics);
+ pd->type = (podoortype_t) LONG(temp->type);
+ pd->close = !!(LONG(temp->close));
+}
+
+//==========================================================================
+//
+// MangleScript
+//
+//==========================================================================
+
+static void MangleScript(void *arg1, void *arg2)
+{
+ int i;
+ acs_t *script = (acs_t *) arg1;
+ save_acs_t *temp = (save_acs_t *) arg2;
+
+ temp->ip_idx = LONG((int32_t)((intptr_t)(script->ip) - (intptr_t)ActionCodeBase));
+ temp->line_idx = script->line ? LONG((int32_t)(script->line - lines)) : (int32_t)LONG(-1);
+ temp->activator_idx = (int32_t) LONG(GetMobjNum(script->activator));
+ temp->side = (int) LONG(script->side);
+ temp->number = (int) LONG(script->number);
+ temp->infoIndex = (int) LONG(script->infoIndex);
+ temp->delayCount = (int) LONG(script->delayCount);
+ temp->stackPtr = (int) LONG(script->stackPtr);
+ for (i = 0; i < ACS_STACK_DEPTH; i++)
+ {
+ temp->stack[i] = (int) LONG(script->stack[i]);
+ }
+ for (i = 0; i < MAX_ACS_SCRIPT_VARS; i++)
+ {
+ temp->vars[i] = (int) LONG(script->vars[i]);
+ }
+}
+
+//==========================================================================
+//
+// RestoreScript
+//
+//==========================================================================
+
+static void RestoreScript(void *arg1, void *arg2)
+{
+ int i;
+ acs_t *script = (acs_t *) arg1;
+ save_acs_t *temp = (save_acs_t *) arg2;
+
+ temp->ip_idx = (int32_t) LONG(temp->ip_idx);
+ temp->line_idx = (int32_t) LONG(temp->line_idx);
+ temp->activator_idx = (int32_t) LONG(temp->activator_idx);
+ script->ip = ActionCodeBase + temp->ip_idx;
+ if (temp->line_idx == -1)
+ {
+ script->line = NULL;
+ }
+ else
+ {
+ script->line = &lines[temp->line_idx];
+ }
+ script->activator = GetMobjPtr(temp->activator_idx, (intptr_t *)(void *)&script->activator);
+ script->side = (int) LONG(temp->side);
+ script->number = (int) LONG(temp->number);
+ script->infoIndex = (int) LONG(temp->infoIndex);
+ script->delayCount = (int) LONG(temp->delayCount);
+ script->stackPtr = (int) LONG(temp->stackPtr);
+ for (i = 0; i < ACS_STACK_DEPTH; i++)
+ {
+ script->stack[i] = (int) LONG(temp->stack[i]);
+ }
+ for (i = 0; i < MAX_ACS_SCRIPT_VARS; i++)
+ {
+ script->vars[i] = (int) LONG(temp->vars[i]);
+ }
+}
+
+//==========================================================================
+//
+// ManglePlatRaise
+//
+//==========================================================================
+
+static void ManglePlatRaise(void *arg1, void *arg2)
+{
+ plat_t *plat = (plat_t *) arg1;
+ save_plat_t *temp = (save_plat_t *) arg2;
+
+ temp->sector_idx = LONG((int32_t)(plat->sector - sectors));
+ temp->speed = (fixed_t) LONG(plat->speed);
+ temp->low = (fixed_t) LONG(plat->low);
+ temp->high = (fixed_t) LONG(plat->high);
+ temp->wait = (int) LONG(plat->wait);
+ temp->count = (int) LONG(plat->count);
+ temp->status = (int) LONG(plat->status);
+ temp->oldstatus = (int) LONG(plat->oldstatus);
+ temp->crush = (int) LONG(plat->crush);
+ temp->tag = (int) LONG(plat->tag);
+ temp->type = (int) LONG(plat->type);
+}
+
+//==========================================================================
+//
+// RestorePlatRaise
+//
+//==========================================================================
+
+static void RestorePlatRaise(void *arg1, void *arg2)
+{
+ plat_t *plat = (plat_t *) arg1;
+ save_plat_t *temp = (save_plat_t *) arg2;
+
+ temp->sector_idx = LONG(temp->sector_idx);
+ plat->sector = §ors[temp->sector_idx];
+ plat->sector->specialdata = T_PlatRaise;
+ plat->speed = (fixed_t) LONG(temp->speed);
+ plat->low = (fixed_t) LONG(temp->low);
+ plat->high = (fixed_t) LONG(temp->high);
+ plat->wait = (int) LONG(temp->wait);
+ plat->count = (int) LONG(temp->count);
+ plat->status = (plat_e) LONG(temp->status);
+ plat->oldstatus = (plat_e) LONG(temp->oldstatus);
+ plat->crush = (int) LONG(temp->crush);
+ plat->tag = (int) LONG(temp->tag);
+ plat->type = (plattype_e) LONG(temp->type);
+ P_AddActivePlat(plat);
+}
+
+//==========================================================================
+//
+// MangleMoveCeiling
+//
+//==========================================================================
+
+static void MangleMoveCeiling(void *arg1, void *arg2)
+{
+ ceiling_t *ceiling = (ceiling_t *) arg1;
+ save_ceiling_t *temp = (save_ceiling_t *) arg2;
+
+ temp->sector_idx = LONG((int32_t)(ceiling->sector - sectors));
+ temp->type = (int) LONG(ceiling->type);
+ temp->bottomheight = (fixed_t) LONG(ceiling->bottomheight);
+ temp->topheight = (fixed_t) LONG(ceiling->topheight);
+ temp->speed = (fixed_t) LONG(ceiling->speed);
+ temp->crush = (int) LONG(ceiling->crush);
+ temp->direction = (int) LONG(ceiling->direction);
+ temp->tag = (int) LONG(ceiling->tag);
+ temp->olddirection = (int) LONG(ceiling->olddirection);
+}
+
+//==========================================================================
+//
+// RestoreMoveCeiling
+//
+//==========================================================================
+
+static void RestoreMoveCeiling(void *arg1, void *arg2)
+{
+ ceiling_t *ceiling = (ceiling_t *) arg1;
+ save_ceiling_t *temp = (save_ceiling_t *) arg2;
+
+ temp->sector_idx = LONG(temp->sector_idx);
+ ceiling->sector = §ors[temp->sector_idx];
+ ceiling->sector->specialdata = T_MoveCeiling;
+ ceiling->type = (ceiling_e) LONG(temp->type);
+ ceiling->bottomheight = (fixed_t) LONG(temp->bottomheight);
+ ceiling->topheight = (fixed_t) LONG(temp->topheight);
+ ceiling->speed = (fixed_t) LONG(temp->speed);
+ ceiling->crush = (int) LONG(temp->crush);
+ ceiling->direction = (int) LONG(temp->direction);
+ ceiling->tag = (int) LONG(temp->tag);
+ ceiling->olddirection = (int) LONG(temp->olddirection);
+ P_AddActiveCeiling(ceiling);
+}
+
+//==========================================================================
+//
+// ArchiveScripts
+//
+//==========================================================================
+
+static void ArchiveScripts(void)
+{
+ int i;
+
+ StreamOutLong(ASEG_SCRIPTS);
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ StreamOutWord(ACSInfo[i].state);
+ StreamOutWord(ACSInfo[i].waitValue);
+ }
+ for (i = 0; i < MAX_ACS_MAP_VARS; i++)
+ {
+ StreamOutLong(MapVars[i]);
+ }
+}
+
+//==========================================================================
+//
+// UnarchiveScripts
+//
+//==========================================================================
+
+static void UnarchiveScripts(void)
+{
+ int i;
+
+ AssertSegment(ASEG_SCRIPTS);
+ for (i = 0; i < ACScriptCount; i++)
+ {
+ ACSInfo[i].state = GET_WORD();
+ ACSInfo[i].waitValue = GET_WORD();
+ }
+ for (i = 0; i < MAX_ACS_MAP_VARS; i++)
+ {
+ MapVars[i] = GET_LONG();
+ }
+}
+
+//==========================================================================
+//
+// ArchiveMisc
+//
+//==========================================================================
+
+static void ArchiveMisc(void)
+{
+ int ix;
+
+ StreamOutLong(ASEG_MISC);
+ for (ix = 0; ix < MAXPLAYERS; ix++)
+ {
+ StreamOutLong(localQuakeHappening[ix]);
+ }
+}
+
+//==========================================================================
+//
+// UnarchiveMisc
+//
+//==========================================================================
+
+static void UnarchiveMisc(void)
+{
+ int ix;
+
+ AssertSegment(ASEG_MISC);
+ for (ix = 0; ix < MAXPLAYERS; ix++)
+ {
+ localQuakeHappening[ix] = GET_LONG();
+ }
+}
+
+//==========================================================================
+//
+// RemoveAllThinkers
+//
+//==========================================================================
+
+static void RemoveAllThinkers(void)
+{
+ thinker_t *thinker;
+ thinker_t *nextThinker;
+
+ thinker = thinkercap.next;
+ while (thinker != &thinkercap)
+ {
+ nextThinker = thinker->next;
+ if (thinker->function == P_MobjThinker)
+ {
+ P_RemoveMobj((mobj_t *)thinker);
+ }
+ else
+ {
+ Z_Free(thinker);
+ }
+ thinker = nextThinker;
+ }
+ P_InitThinkers();
+}
+
+//==========================================================================
+//
+// ArchiveSounds
+//
+//==========================================================================
+
+static void ArchiveSounds(void)
+{
+ seqnode_t *node;
+ sector_t *sec;
+ int difference;
+ int i;
+
+ StreamOutLong(ASEG_SOUNDS);
+
+ // Save the sound sequences
+ StreamOutLong(ActiveSequences);
+ for (node = SequenceListHead; node; node = node->next)
+ {
+ StreamOutLong(node->sequence);
+ StreamOutLong(node->delayTics);
+ StreamOutLong(node->volume);
+ StreamOutLong(SN_GetSequenceOffset(node->sequence, node->sequencePtr));
+ StreamOutLong(node->currentSoundID);
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (node->mobj == (mobj_t *)&polyobjs[i].startSpot)
+ {
+ break;
+ }
+ }
+ if (i == po_NumPolyobjs)
+ { // Sound is attached to a sector, not a polyobj
+ sec = R_PointInSubsector(node->mobj->x, node->mobj->y)->sector;
+ difference = (int)(((byte *)sec - (byte *)§ors[0]) / sizeof(sector_t));
+ StreamOutLong(0); // 0 -- sector sound origin
+ }
+ else
+ {
+ StreamOutLong(1); // 1 -- polyobj sound origin
+ difference = i;
+ }
+ StreamOutLong(difference);
+ }
+}
+
+//==========================================================================
+//
+// UnarchiveSounds
+//
+//==========================================================================
+
+static void UnarchiveSounds(void)
+{
+ int i;
+ int numSequences;
+ int sequence;
+ int delayTics;
+ int volume;
+ int seqOffset;
+ int soundID;
+ int polySnd;
+ int secNum;
+ mobj_t *sndMobj;
+
+ AssertSegment(ASEG_SOUNDS);
+
+ // Reload and restart all sound sequences
+ numSequences = GET_LONG();
+ i = 0;
+ while (i < numSequences)
+ {
+ sequence = GET_LONG();
+ delayTics = GET_LONG();
+ volume = GET_LONG();
+ seqOffset = GET_LONG();
+
+ soundID = GET_LONG();
+ polySnd = GET_LONG();
+ secNum = GET_LONG();
+ if (!polySnd)
+ {
+ sndMobj = (mobj_t *)(void *)§ors[secNum].soundorg;
+ }
+ else
+ {
+ sndMobj = (mobj_t *)&polyobjs[secNum].startSpot;
+ }
+ SN_StartSequence(sndMobj, sequence);
+ SN_ChangeNodeData(i, seqOffset, delayTics, volume, soundID);
+ i++;
+ }
+}
+
+//==========================================================================
+//
+// ArchivePolyobjs
+//
+//==========================================================================
+
+static void ArchivePolyobjs(void)
+{
+ int i;
+
+ StreamOutLong(ASEG_POLYOBJS);
+ StreamOutLong(po_NumPolyobjs);
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ StreamOutLong(polyobjs[i].tag);
+ StreamOutLong(polyobjs[i].angle);
+ StreamOutLong(polyobjs[i].startSpot.x);
+ StreamOutLong(polyobjs[i].startSpot.y);
+ }
+}
+
+//==========================================================================
+//
+// UnarchivePolyobjs
+//
+//==========================================================================
+
+static void UnarchivePolyobjs(void)
+{
+ int i;
+ fixed_t deltaX;
+ fixed_t deltaY;
+
+ AssertSegment(ASEG_POLYOBJS);
+ if (GET_LONG() != po_NumPolyobjs)
+ {
+ I_Error("UnarchivePolyobjs: Bad polyobj count");
+ }
+ for (i = 0; i < po_NumPolyobjs; i++)
+ {
+ if (GET_LONG() != polyobjs[i].tag)
+ {
+ I_Error("UnarchivePolyobjs: Invalid polyobj tag");
+ }
+ PO_RotatePolyobj(polyobjs[i].tag, (angle_t)GET_LONG());
+ deltaX = GET_LONG() - polyobjs[i].startSpot.x;
+ deltaY = GET_LONG() - polyobjs[i].startSpot.y;
+ PO_MovePolyobj(polyobjs[i].tag, deltaX, deltaY);
+ }
+}
+
+//==========================================================================
+//
+// AssertSegment
+//
+//==========================================================================
+
+static void AssertSegment(gameArchiveSegment_t segType)
+{
+ if (GET_LONG() != segType)
+ {
+ I_Error("Corrupt save game: Segment [%d] failed alignment check", segType);
+ }
+}
+
+//==========================================================================
+//
+// ClearSaveSlot
+//
+// Deletes all save game files associated with a slot number.
+//
+//==========================================================================
+
+static void ClearSaveSlot(int slot)
+{
+ int i;
+ char fileName[MAX_OSPATH];
+
+ for (i = 0; i < MAX_MAPS; i++)
+ {
+ snprintf(fileName, sizeof(fileName), "%shex%d%02d.hxs", basePath, slot, i);
+ remove(fileName);
+ }
+ snprintf(fileName, sizeof(fileName), "%shex%d.hxs", basePath, slot);
+ remove(fileName);
+}
+
+//==========================================================================
+//
+// CopySaveSlot
+//
+// Copies all the save game files from one slot to another.
+//
+//==========================================================================
+
+static void CopySaveSlot(int sourceSlot, int destSlot)
+{
+ int i;
+ char sourceName[MAX_OSPATH];
+ char destName[MAX_OSPATH];
+
+ for (i = 0; i < MAX_MAPS; i++)
+ {
+ snprintf(sourceName, sizeof(sourceName), "%shex%d%02d.hxs", basePath,sourceSlot, i);
+ if (ExistingFile(sourceName))
+ {
+ snprintf(destName, sizeof(destName), "%shex%d%02d.hxs", basePath,destSlot, i);
+ CopyFile(sourceName, destName);
+ }
+ }
+ snprintf(sourceName, sizeof(sourceName), "%shex%d.hxs", basePath, sourceSlot);
+ if (ExistingFile(sourceName))
+ {
+ snprintf(destName, sizeof(destName), "%shex%d.hxs", basePath, destSlot);
+ CopyFile(sourceName, destName);
+ }
+}
+
+//==========================================================================
+//
+// CopyFile
+//
+//==========================================================================
+
+static void CopyFile(const char *sourceName, const char *destName)
+{
+ int length;
+ void *buffer;
+
+ length = M_ReadFile(sourceName, &buffer);
+ M_WriteFile(destName, buffer, length);
+ Z_Free(buffer);
+}
+
+//==========================================================================
+//
+// ExistingFile
+//
+//==========================================================================
+
+static boolean ExistingFile(const char *name)
+{
+ FILE *fp;
+
+ if ((fp = fopen(name, "rb")) != NULL)
+ {
+ fclose(fp);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//==========================================================================
+//
+// OpenStreamOut
+//
+//==========================================================================
+
+static void OpenStreamOut(const char *fileName)
+{
+ SavingFP = fopen(fileName, "wb");
+}
+
+//==========================================================================
+//
+// CloseStreamOut
+//
+//==========================================================================
+
+static void CloseStreamOut(void)
+{
+ if (SavingFP)
+ {
+ fclose(SavingFP);
+ }
+}
+
+//==========================================================================
+//
+// StreamOutBuffer
+//
+//==========================================================================
+
+static void StreamOutBuffer(const void *buffer, size_t size)
+{
+ fwrite(buffer, size, 1, SavingFP);
+}
+
+//==========================================================================
+//
+// StreamOutByte
+//
+//==========================================================================
+
+static void StreamOutByte(byte val)
+{
+ fwrite(&val, sizeof(byte), 1, SavingFP);
+}
+
+//==========================================================================
+//
+// StreamOutWord
+//
+//==========================================================================
+
+static void StreamOutWord(uint16_t val)
+{
+ uint16_t tmp = (uint16_t) SHORT(val);
+ fwrite(&tmp, sizeof(uint16_t), 1, SavingFP);
+}
+
+//==========================================================================
+//
+// StreamOutLong
+//
+//==========================================================================
+
+static void StreamOutLong(uint32_t val)
+{
+ uint32_t tmp = (uint32_t) LONG(val);
+ fwrite(&tmp, sizeof(uint32_t), 1, SavingFP);
+}
+
--- /dev/null
+++ b/sv_save.h
@@ -1,0 +1,293 @@
+/*
+ sv_save.h: Heretic 2 (Hexen)
+ Structures used for saved games.
+
+ $Revision: 543 $
+ $Date: 2010-01-11 20:44:55 +0200 (Mon, 11 Jan 2010) $
+
+ See the file SAVEGAME for notes and/or issues.
+*/
+
+#ifndef __SAVE_DEFS
+#define __SAVE_DEFS
+
+#ifndef _DOSSAVE_COMPAT
+#define __compat_doshexen
+#else
+#define __compat_doshexen __attribute__((__packed__))
+#endif
+
+typedef struct
+{
+ int32_t state_idx; /* state_t *state */
+ int tics;
+ fixed_t sx, sy;
+} save_pspdef_t;
+
+typedef struct
+{
+ int32_t prev_idx, next_idx; /* struct thinker_s *prev, *next; */
+ int32_t function_idx; /* think_t function; */
+} save_thinker_t;
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+
+ fixed_t x, y, z;
+ int32_t snext_idx, sprev_idx; /* struct mobj_s *snext, *sprev; */
+ angle_t angle;
+ int sprite; /* spritenum_t sprite */
+ int frame;
+
+ int32_t bnext_idx, bprev_idx; /* struct mobj_s *bnext, *bprev; */
+ int32_t subsector_idx; /* struct subsector_s *subsector; */
+ fixed_t floorz, ceilingz;
+ fixed_t floorpic;
+ fixed_t radius, height;
+ fixed_t momx, momy, momz;
+ int validcount;
+ int type; /* mobjtype_t type */
+ int32_t info_idx; /* mobjinfo_t *info; */
+ int tics;
+ int32_t state_idx; /* state_t *state; */
+ int damage;
+ int flags;
+ int flags2;
+ int32_t special1; /* intptr_t special1; */
+ int32_t special2; /* intptr_t special2; */
+ int health;
+ int movedir;
+ int movecount;
+ int32_t target_idx; /* struct mobj_s *target; */
+ int reactiontime;
+ int threshold;
+ int32_t player_idx; /* struct player_s *player; */
+ int lastlook;
+ fixed_t floorclip;
+ int archiveNum;
+ short tid;
+ byte special;
+ byte args[5];
+} __compat_doshexen save_mobj_t;
+#if !(defined(VERSION10_WAD) || defined(_DOSSAVE_COMPAT))
+/* make sure the struct is of 176 bytes size, so that all our
+ saved games are uniform. */
+#endif
+
+typedef struct
+{
+ int32_t mo_idx; /* mobj_t *mo; */
+ int playerstate; /* playerstate_t playerstate */
+ ticcmd_t cmd; /* note: sizeof(ticcmd_t) is
+ 10, not 4 byte aligned. */
+
+ int playerclass; /* pclass_t playerclass */
+
+ fixed_t viewz;
+ fixed_t viewheight;
+ fixed_t deltaviewheight;
+ fixed_t bob;
+
+ int flyheight;
+ int lookdir;
+ int centering; /* boolean centering */
+ int health;
+ int armorpoints[NUMARMOR];
+
+ inventory_t inventory[NUMINVENTORYSLOTS];
+ int readyArtifact; /* artitype_t readyArtifact */
+ int artifactCount;
+ int inventorySlotNum;
+ int powers[NUMPOWERS];
+ int keys;
+ int pieces;
+ signed int frags[MAXPLAYERS];
+ int readyweapon; /* weapontype_t readyweapon */
+ int pendingweapon; /* weapontype_t pendingweapon */
+ int weaponowned[NUMWEAPONS]; /* boolean weaponowned[NUMWEAPONS] */
+ int mana[NUMMANA];
+ int attackdown, usedown;
+ int cheats;
+
+ int refire;
+
+ int killcount, itemcount, secretcount;
+ char message[80];
+ int messageTics;
+ short ultimateMessage;
+ short yellowMessage;
+ int damagecount, bonuscount;
+ int poisoncount;
+ int32_t poisoner_idx; /* mobj_t *poisoner; */
+ int32_t attacker_idx; /* mobj_t *attacker; */
+ int extralight;
+ int fixedcolormap;
+ int colormap;
+ save_pspdef_t psprites[NUMPSPRITES]; /* pspdef_t psprites[NUMPSPRITES]; */
+ int morphTics;
+ unsigned int jumpTics;
+ unsigned int worldTimer;
+} __compat_doshexen save_player_t;
+#if !(defined(VERSION10_WAD) || defined(_DOSSAVE_COMPAT))
+/* make sure the struct is of 648 bytes size, so that all our saved
+ games are uniform: Raven's DOS versions seem to have this struct
+ packed, with sizeof(player_t) == 646 and offsetof playerclass at
+ 18 instead of 20. */
+#endif
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+ int32_t sector_idx; /* sector_t *sector; */
+ int type; /* floor_e type; */
+ int crush;
+ int direction;
+ int newspecial;
+ short texture; /* */
+ fixed_t floordestheight;
+ fixed_t speed;
+ int delayCount;
+ int delayTotal;
+ fixed_t stairsDelayHeight;
+ fixed_t stairsDelayHeightDelta;
+ fixed_t resetHeight;
+ short resetDelay;
+ short resetDelayCount;
+ byte textureChange; /* */
+} __compat_doshexen save_floormove_t;
+#if !(defined(VERSION10_WAD) || defined(_DOSSAVE_COMPAT))
+/* make sure the struct is of 72 bytes size, so that all our saved
+ games are uniform. */
+#endif
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+ int32_t sector_idx; /* sector_t *sector; */
+ int ceilingSpeed;
+ int floorSpeed;
+ int floordest;
+ int ceilingdest;
+ int direction;
+ int crush;
+} save_pillar_t;
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+ int32_t sector_idx; /* sector_t *sector; */
+ fixed_t originalHeight;
+ fixed_t accumulator;
+ fixed_t accDelta;
+ fixed_t targetScale;
+ fixed_t scale;
+ fixed_t scaleDelta;
+ int ticker;
+ int state;
+} save_floorWaggle_t;
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+ int32_t sector_idx; /* sector_t *sector; */
+ fixed_t speed;
+ fixed_t low;
+ fixed_t high;
+ int wait;
+ int count;
+ int status; /* plat_e status; */
+ int oldstatus; /* plat_e oldstatus; */
+ int crush;
+ int tag;
+ int type; /* plattype_e type; */
+} save_plat_t;
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+ int32_t sector_idx; /* sector_t *sector; */
+ int type; /* ceiling_e type; */
+ fixed_t bottomheight, topheight;
+ fixed_t speed;
+ int crush;
+ int direction;
+ int tag;
+ int olddirection;
+} save_ceiling_t;
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+ int32_t sector_idx; /* sector_t *sector; */
+ int type; /* lighttype_t type; */
+ int value1;
+ int value2;
+ int tics1;
+ int tics2;
+ int count;
+} save_light_t;
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+ int32_t sector_idx; /* sector_t *sector; */
+ int index;
+ int base;
+} save_phase_t;
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+ int32_t sector_idx; /* sector_t *sector; */
+ int type; /* vldoor_e type; */
+ fixed_t topheight;
+ fixed_t speed;
+ int direction;
+ int topwait;
+ int topcountdown;
+} save_vldoor_t;
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+ int polyobj;
+ int speed;
+ unsigned int dist;
+ int angle;
+ fixed_t xSpeed;
+ fixed_t ySpeed;
+} save_polyevent_t;
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+ int polyobj;
+ int speed;
+ int dist;
+ int totalDist;
+ int direction;
+ fixed_t xSpeed, ySpeed;
+ int tics;
+ int waitTics;
+ int type; /* podoortype_t type; */
+ int close; /* boolean close; */
+} save_polydoor_t;
+
+typedef struct
+{
+ save_thinker_t thinker; /* thinker_t thinker; */
+ int32_t activator_idx; /* mobj_t *activator; */
+ int32_t line_idx; /* line_t *line; */
+ int side;
+ int number;
+ int infoIndex;
+ int delayCount;
+ int stack[ACS_STACK_DEPTH];
+ int stackPtr;
+ int vars[MAX_ACS_SCRIPT_VARS];
+ int32_t ip_idx; /* byte *ip; */
+} save_acs_t;
+
+#endif /* __SAVE_DEFS */
+
--- /dev/null
+++ b/tables.c
@@ -1,0 +1,2074 @@
+
+//**************************************************************************
+//**
+//** tables.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+int finetangent[4096] =
+{
+-170910304,-56965752,-34178904,-24413316,-18988036,-15535599,-13145455,-11392683,
+-10052327,-8994149,-8137527,-7429880,-6835455,-6329090,-5892567,-5512368,
+-5178251,-4882318,-4618375,-4381502,-4167737,-3973855,-3797206,-3635590,
+-3487165,-3350381,-3223918,-3106651,-2997613,-2895966,-2800983,-2712030,
+-2628549,-2550052,-2476104,-2406322,-2340362,-2277919,-2218719,-2162516,
+-2109087,-2058233,-2009771,-1963536,-1919378,-1877161,-1836758,-1798063,
+-1760956,-1725348,-1691149,-1658278,-1626658,-1596220,-1566898,-1538632,
+-1511367,-1485049,-1459630,-1435065,-1411312,-1388330,-1366084,-1344537,
+-1323658,-1303416,-1283783,-1264730,-1246234,-1228269,-1210813,-1193846,
+-1177345,-1161294,-1145673,-1130465,-1115654,-1101225,-1087164,-1073455,
+-1060087,-1047046,-1034322,-1021901,-1009774,-997931,-986361,-975054,
+-964003,-953199,-942633,-932298,-922186,-912289,-902602,-893117,
+-883829,-874730,-865817,-857081,-848520,-840127,-831898,-823827,
+-815910,-808143,-800521,-793041,-785699,-778490,-771411,-764460,
+-757631,-750922,-744331,-737853,-731486,-725227,-719074,-713023,
+-707072,-701219,-695462,-689797,-684223,-678737,-673338,-668024,
+-662792,-657640,-652568,-647572,-642651,-637803,-633028,-628323,
+-623686,-619117,-614613,-610174,-605798,-601483,-597229,-593033,
+-588896,-584815,-580789,-576818,-572901,-569035,-565221,-561456,
+-557741,-554074,-550455,-546881,-543354,-539870,-536431,-533034,
+-529680,-526366,-523094,-519861,-516667,-513512,-510394,-507313,
+-504269,-501261,-498287,-495348,-492443,-489571,-486732,-483925,
+-481150,-478406,-475692,-473009,-470355,-467730,-465133,-462565,
+-460024,-457511,-455024,-452564,-450129,-447720,-445337,-442978,
+-440643,-438332,-436045,-433781,-431540,-429321,-427125,-424951,
+-422798,-420666,-418555,-416465,-414395,-412344,-410314,-408303,
+-406311,-404338,-402384,-400448,-398530,-396630,-394747,-392882,
+-391034,-389202,-387387,-385589,-383807,-382040,-380290,-378555,
+-376835,-375130,-373440,-371765,-370105,-368459,-366826,-365208,
+-363604,-362013,-360436,-358872,-357321,-355783,-354257,-352744,
+-351244,-349756,-348280,-346816,-345364,-343924,-342495,-341078,
+-339671,-338276,-336892,-335519,-334157,-332805,-331464,-330133,
+-328812,-327502,-326201,-324910,-323629,-322358,-321097,-319844,
+-318601,-317368,-316143,-314928,-313721,-312524,-311335,-310154,
+-308983,-307819,-306664,-305517,-304379,-303248,-302126,-301011,
+-299904,-298805,-297714,-296630,-295554,-294485,-293423,-292369,
+-291322,-290282,-289249,-288223,-287204,-286192,-285186,-284188,
+-283195,-282210,-281231,-280258,-279292,-278332,-277378,-276430,
+-275489,-274553,-273624,-272700,-271782,-270871,-269965,-269064,
+-268169,-267280,-266397,-265519,-264646,-263779,-262917,-262060,
+-261209,-260363,-259522,-258686,-257855,-257029,-256208,-255392,
+-254581,-253774,-252973,-252176,-251384,-250596,-249813,-249035,
+-248261,-247492,-246727,-245966,-245210,-244458,-243711,-242967,
+-242228,-241493,-240763,-240036,-239314,-238595,-237881,-237170,
+-236463,-235761,-235062,-234367,-233676,-232988,-232304,-231624,
+-230948,-230275,-229606,-228941,-228279,-227621,-226966,-226314,
+-225666,-225022,-224381,-223743,-223108,-222477,-221849,-221225,
+-220603,-219985,-219370,-218758,-218149,-217544,-216941,-216341,
+-215745,-215151,-214561,-213973,-213389,-212807,-212228,-211652,
+-211079,-210509,-209941,-209376,-208815,-208255,-207699,-207145,
+-206594,-206045,-205500,-204956,-204416,-203878,-203342,-202809,
+-202279,-201751,-201226,-200703,-200182,-199664,-199149,-198636,
+-198125,-197616,-197110,-196606,-196105,-195606,-195109,-194614,
+-194122,-193631,-193143,-192658,-192174,-191693,-191213,-190736,
+-190261,-189789,-189318,-188849,-188382,-187918,-187455,-186995,
+-186536,-186080,-185625,-185173,-184722,-184274,-183827,-183382,
+-182939,-182498,-182059,-181622,-181186,-180753,-180321,-179891,
+-179463,-179037,-178612,-178190,-177769,-177349,-176932,-176516,
+-176102,-175690,-175279,-174870,-174463,-174057,-173653,-173251,
+-172850,-172451,-172053,-171657,-171263,-170870,-170479,-170089,
+-169701,-169315,-168930,-168546,-168164,-167784,-167405,-167027,
+-166651,-166277,-165904,-165532,-165162,-164793,-164426,-164060,
+-163695,-163332,-162970,-162610,-162251,-161893,-161537,-161182,
+-160828,-160476,-160125,-159775,-159427,-159079,-158734,-158389,
+-158046,-157704,-157363,-157024,-156686,-156349,-156013,-155678,
+-155345,-155013,-154682,-154352,-154024,-153697,-153370,-153045,
+-152722,-152399,-152077,-151757,-151438,-151120,-150803,-150487,
+-150172,-149859,-149546,-149235,-148924,-148615,-148307,-148000,
+-147693,-147388,-147084,-146782,-146480,-146179,-145879,-145580,
+-145282,-144986,-144690,-144395,-144101,-143808,-143517,-143226,
+-142936,-142647,-142359,-142072,-141786,-141501,-141217,-140934,
+-140651,-140370,-140090,-139810,-139532,-139254,-138977,-138701,
+-138426,-138152,-137879,-137607,-137335,-137065,-136795,-136526,
+-136258,-135991,-135725,-135459,-135195,-134931,-134668,-134406,
+-134145,-133884,-133625,-133366,-133108,-132851,-132594,-132339,
+-132084,-131830,-131576,-131324,-131072,-130821,-130571,-130322,
+-130073,-129825,-129578,-129332,-129086,-128841,-128597,-128353,
+-128111,-127869,-127627,-127387,-127147,-126908,-126669,-126432,
+-126195,-125959,-125723,-125488,-125254,-125020,-124787,-124555,
+-124324,-124093,-123863,-123633,-123404,-123176,-122949,-122722,
+-122496,-122270,-122045,-121821,-121597,-121374,-121152,-120930,
+-120709,-120489,-120269,-120050,-119831,-119613,-119396,-119179,
+-118963,-118747,-118532,-118318,-118104,-117891,-117678,-117466,
+-117254,-117044,-116833,-116623,-116414,-116206,-115998,-115790,
+-115583,-115377,-115171,-114966,-114761,-114557,-114354,-114151,
+-113948,-113746,-113545,-113344,-113143,-112944,-112744,-112546,
+-112347,-112150,-111952,-111756,-111560,-111364,-111169,-110974,
+-110780,-110586,-110393,-110200,-110008,-109817,-109626,-109435,
+-109245,-109055,-108866,-108677,-108489,-108301,-108114,-107927,
+-107741,-107555,-107369,-107184,-107000,-106816,-106632,-106449,
+-106266,-106084,-105902,-105721,-105540,-105360,-105180,-105000,
+-104821,-104643,-104465,-104287,-104109,-103933,-103756,-103580,
+-103404,-103229,-103054,-102880,-102706,-102533,-102360,-102187,
+-102015,-101843,-101671,-101500,-101330,-101159,-100990,-100820,
+-100651,-100482,-100314,-100146,-99979,-99812,-99645,-99479,
+-99313,-99148,-98982,-98818,-98653,-98489,-98326,-98163,
+-98000,-97837,-97675,-97513,-97352,-97191,-97030,-96870,
+-96710,-96551,-96391,-96233,-96074,-95916,-95758,-95601,
+-95444,-95287,-95131,-94975,-94819,-94664,-94509,-94354,
+-94200,-94046,-93892,-93739,-93586,-93434,-93281,-93129,
+-92978,-92826,-92675,-92525,-92375,-92225,-92075,-91926,
+-91777,-91628,-91480,-91332,-91184,-91036,-90889,-90742,
+-90596,-90450,-90304,-90158,-90013,-89868,-89724,-89579,
+-89435,-89292,-89148,-89005,-88862,-88720,-88577,-88435,
+-88294,-88152,-88011,-87871,-87730,-87590,-87450,-87310,
+-87171,-87032,-86893,-86755,-86616,-86479,-86341,-86204,
+-86066,-85930,-85793,-85657,-85521,-85385,-85250,-85114,
+-84980,-84845,-84710,-84576,-84443,-84309,-84176,-84043,
+-83910,-83777,-83645,-83513,-83381,-83250,-83118,-82987,
+-82857,-82726,-82596,-82466,-82336,-82207,-82078,-81949,
+-81820,-81691,-81563,-81435,-81307,-81180,-81053,-80925,
+-80799,-80672,-80546,-80420,-80294,-80168,-80043,-79918,
+-79793,-79668,-79544,-79420,-79296,-79172,-79048,-78925,
+-78802,-78679,-78557,-78434,-78312,-78190,-78068,-77947,
+-77826,-77705,-77584,-77463,-77343,-77223,-77103,-76983,
+-76864,-76744,-76625,-76506,-76388,-76269,-76151,-76033,
+-75915,-75797,-75680,-75563,-75446,-75329,-75213,-75096,
+-74980,-74864,-74748,-74633,-74517,-74402,-74287,-74172,
+-74058,-73944,-73829,-73715,-73602,-73488,-73375,-73262,
+-73149,-73036,-72923,-72811,-72699,-72587,-72475,-72363,
+-72252,-72140,-72029,-71918,-71808,-71697,-71587,-71477,
+-71367,-71257,-71147,-71038,-70929,-70820,-70711,-70602,
+-70494,-70385,-70277,-70169,-70061,-69954,-69846,-69739,
+-69632,-69525,-69418,-69312,-69205,-69099,-68993,-68887,
+-68781,-68676,-68570,-68465,-68360,-68255,-68151,-68046,
+-67942,-67837,-67733,-67629,-67526,-67422,-67319,-67216,
+-67113,-67010,-66907,-66804,-66702,-66600,-66498,-66396,
+-66294,-66192,-66091,-65989,-65888,-65787,-65686,-65586,
+-65485,-65385,-65285,-65185,-65085,-64985,-64885,-64786,
+-64687,-64587,-64488,-64389,-64291,-64192,-64094,-63996,
+-63897,-63799,-63702,-63604,-63506,-63409,-63312,-63215,
+-63118,-63021,-62924,-62828,-62731,-62635,-62539,-62443,
+-62347,-62251,-62156,-62060,-61965,-61870,-61775,-61680,
+-61585,-61491,-61396,-61302,-61208,-61114,-61020,-60926,
+-60833,-60739,-60646,-60552,-60459,-60366,-60273,-60181,
+-60088,-59996,-59903,-59811,-59719,-59627,-59535,-59444,
+-59352,-59261,-59169,-59078,-58987,-58896,-58805,-58715,
+-58624,-58534,-58443,-58353,-58263,-58173,-58083,-57994,
+-57904,-57815,-57725,-57636,-57547,-57458,-57369,-57281,
+-57192,-57104,-57015,-56927,-56839,-56751,-56663,-56575,
+-56487,-56400,-56312,-56225,-56138,-56051,-55964,-55877,
+-55790,-55704,-55617,-55531,-55444,-55358,-55272,-55186,
+-55100,-55015,-54929,-54843,-54758,-54673,-54587,-54502,
+-54417,-54333,-54248,-54163,-54079,-53994,-53910,-53826,
+-53741,-53657,-53574,-53490,-53406,-53322,-53239,-53156,
+-53072,-52989,-52906,-52823,-52740,-52657,-52575,-52492,
+-52410,-52327,-52245,-52163,-52081,-51999,-51917,-51835,
+-51754,-51672,-51591,-51509,-51428,-51347,-51266,-51185,
+-51104,-51023,-50942,-50862,-50781,-50701,-50621,-50540,
+-50460,-50380,-50300,-50221,-50141,-50061,-49982,-49902,
+-49823,-49744,-49664,-49585,-49506,-49427,-49349,-49270,
+-49191,-49113,-49034,-48956,-48878,-48799,-48721,-48643,
+-48565,-48488,-48410,-48332,-48255,-48177,-48100,-48022,
+-47945,-47868,-47791,-47714,-47637,-47560,-47484,-47407,
+-47331,-47254,-47178,-47102,-47025,-46949,-46873,-46797,
+-46721,-46646,-46570,-46494,-46419,-46343,-46268,-46193,
+-46118,-46042,-45967,-45892,-45818,-45743,-45668,-45593,
+-45519,-45444,-45370,-45296,-45221,-45147,-45073,-44999,
+-44925,-44851,-44778,-44704,-44630,-44557,-44483,-44410,
+-44337,-44263,-44190,-44117,-44044,-43971,-43898,-43826,
+-43753,-43680,-43608,-43535,-43463,-43390,-43318,-43246,
+-43174,-43102,-43030,-42958,-42886,-42814,-42743,-42671,
+-42600,-42528,-42457,-42385,-42314,-42243,-42172,-42101,
+-42030,-41959,-41888,-41817,-41747,-41676,-41605,-41535,
+-41465,-41394,-41324,-41254,-41184,-41113,-41043,-40973,
+-40904,-40834,-40764,-40694,-40625,-40555,-40486,-40416,
+-40347,-40278,-40208,-40139,-40070,-40001,-39932,-39863,
+-39794,-39726,-39657,-39588,-39520,-39451,-39383,-39314,
+-39246,-39178,-39110,-39042,-38973,-38905,-38837,-38770,
+-38702,-38634,-38566,-38499,-38431,-38364,-38296,-38229,
+-38161,-38094,-38027,-37960,-37893,-37826,-37759,-37692,
+-37625,-37558,-37491,-37425,-37358,-37291,-37225,-37158,
+-37092,-37026,-36959,-36893,-36827,-36761,-36695,-36629,
+-36563,-36497,-36431,-36365,-36300,-36234,-36168,-36103,
+-36037,-35972,-35907,-35841,-35776,-35711,-35646,-35580,
+-35515,-35450,-35385,-35321,-35256,-35191,-35126,-35062,
+-34997,-34932,-34868,-34803,-34739,-34675,-34610,-34546,
+-34482,-34418,-34354,-34289,-34225,-34162,-34098,-34034,
+-33970,-33906,-33843,-33779,-33715,-33652,-33588,-33525,
+-33461,-33398,-33335,-33272,-33208,-33145,-33082,-33019,
+-32956,-32893,-32830,-32767,-32705,-32642,-32579,-32516,
+-32454,-32391,-32329,-32266,-32204,-32141,-32079,-32017,
+-31955,-31892,-31830,-31768,-31706,-31644,-31582,-31520,
+-31458,-31396,-31335,-31273,-31211,-31150,-31088,-31026,
+-30965,-30904,-30842,-30781,-30719,-30658,-30597,-30536,
+-30474,-30413,-30352,-30291,-30230,-30169,-30108,-30048,
+-29987,-29926,-29865,-29805,-29744,-29683,-29623,-29562,
+-29502,-29441,-29381,-29321,-29260,-29200,-29140,-29080,
+-29020,-28959,-28899,-28839,-28779,-28719,-28660,-28600,
+-28540,-28480,-28420,-28361,-28301,-28241,-28182,-28122,
+-28063,-28003,-27944,-27884,-27825,-27766,-27707,-27647,
+-27588,-27529,-27470,-27411,-27352,-27293,-27234,-27175,
+-27116,-27057,-26998,-26940,-26881,-26822,-26763,-26705,
+-26646,-26588,-26529,-26471,-26412,-26354,-26295,-26237,
+-26179,-26120,-26062,-26004,-25946,-25888,-25830,-25772,
+-25714,-25656,-25598,-25540,-25482,-25424,-25366,-25308,
+-25251,-25193,-25135,-25078,-25020,-24962,-24905,-24847,
+-24790,-24732,-24675,-24618,-24560,-24503,-24446,-24389,
+-24331,-24274,-24217,-24160,-24103,-24046,-23989,-23932,
+-23875,-23818,-23761,-23704,-23647,-23591,-23534,-23477,
+-23420,-23364,-23307,-23250,-23194,-23137,-23081,-23024,
+-22968,-22911,-22855,-22799,-22742,-22686,-22630,-22573,
+-22517,-22461,-22405,-22349,-22293,-22237,-22181,-22125,
+-22069,-22013,-21957,-21901,-21845,-21789,-21733,-21678,
+-21622,-21566,-21510,-21455,-21399,-21343,-21288,-21232,
+-21177,-21121,-21066,-21010,-20955,-20900,-20844,-20789,
+-20734,-20678,-20623,-20568,-20513,-20457,-20402,-20347,
+-20292,-20237,-20182,-20127,-20072,-20017,-19962,-19907,
+-19852,-19797,-19742,-19688,-19633,-19578,-19523,-19469,
+-19414,-19359,-19305,-19250,-19195,-19141,-19086,-19032,
+-18977,-18923,-18868,-18814,-18760,-18705,-18651,-18597,
+-18542,-18488,-18434,-18380,-18325,-18271,-18217,-18163,
+-18109,-18055,-18001,-17946,-17892,-17838,-17784,-17731,
+-17677,-17623,-17569,-17515,-17461,-17407,-17353,-17300,
+-17246,-17192,-17138,-17085,-17031,-16977,-16924,-16870,
+-16817,-16763,-16710,-16656,-16603,-16549,-16496,-16442,
+-16389,-16335,-16282,-16229,-16175,-16122,-16069,-16015,
+-15962,-15909,-15856,-15802,-15749,-15696,-15643,-15590,
+-15537,-15484,-15431,-15378,-15325,-15272,-15219,-15166,
+-15113,-15060,-15007,-14954,-14901,-14848,-14795,-14743,
+-14690,-14637,-14584,-14531,-14479,-14426,-14373,-14321,
+-14268,-14215,-14163,-14110,-14057,-14005,-13952,-13900,
+-13847,-13795,-13742,-13690,-13637,-13585,-13533,-13480,
+-13428,-13375,-13323,-13271,-13218,-13166,-13114,-13062,
+-13009,-12957,-12905,-12853,-12800,-12748,-12696,-12644,
+-12592,-12540,-12488,-12436,-12383,-12331,-12279,-12227,
+-12175,-12123,-12071,-12019,-11967,-11916,-11864,-11812,
+-11760,-11708,-11656,-11604,-11552,-11501,-11449,-11397,
+-11345,-11293,-11242,-11190,-11138,-11086,-11035,-10983,
+-10931,-10880,-10828,-10777,-10725,-10673,-10622,-10570,
+-10519,-10467,-10415,-10364,-10312,-10261,-10209,-10158,
+-10106,-10055,-10004,-9952,-9901,-9849,-9798,-9747,
+-9695,-9644,-9592,-9541,-9490,-9438,-9387,-9336,
+-9285,-9233,-9182,-9131,-9080,-9028,-8977,-8926,
+-8875,-8824,-8772,-8721,-8670,-8619,-8568,-8517,
+-8466,-8414,-8363,-8312,-8261,-8210,-8159,-8108,
+-8057,-8006,-7955,-7904,-7853,-7802,-7751,-7700,
+-7649,-7598,-7547,-7496,-7445,-7395,-7344,-7293,
+-7242,-7191,-7140,-7089,-7038,-6988,-6937,-6886,
+-6835,-6784,-6733,-6683,-6632,-6581,-6530,-6480,
+-6429,-6378,-6327,-6277,-6226,-6175,-6124,-6074,
+-6023,-5972,-5922,-5871,-5820,-5770,-5719,-5668,
+-5618,-5567,-5517,-5466,-5415,-5365,-5314,-5264,
+-5213,-5162,-5112,-5061,-5011,-4960,-4910,-4859,
+-4808,-4758,-4707,-4657,-4606,-4556,-4505,-4455,
+-4404,-4354,-4303,-4253,-4202,-4152,-4101,-4051,
+-4001,-3950,-3900,-3849,-3799,-3748,-3698,-3648,
+-3597,-3547,-3496,-3446,-3395,-3345,-3295,-3244,
+-3194,-3144,-3093,-3043,-2992,-2942,-2892,-2841,
+-2791,-2741,-2690,-2640,-2590,-2539,-2489,-2439,
+-2388,-2338,-2288,-2237,-2187,-2137,-2086,-2036,
+-1986,-1935,-1885,-1835,-1784,-1734,-1684,-1633,
+-1583,-1533,-1483,-1432,-1382,-1332,-1281,-1231,
+-1181,-1131,-1080,-1030,-980,-929,-879,-829,
+-779,-728,-678,-628,-578,-527,-477,-427,
+-376,-326,-276,-226,-175,-125,-75,-25,
+25,75,125,175,226,276,326,376,
+427,477,527,578,628,678,728,779,
+829,879,929,980,1030,1080,1131,1181,
+1231,1281,1332,1382,1432,1483,1533,1583,
+1633,1684,1734,1784,1835,1885,1935,1986,
+2036,2086,2137,2187,2237,2288,2338,2388,
+2439,2489,2539,2590,2640,2690,2741,2791,
+2841,2892,2942,2992,3043,3093,3144,3194,
+3244,3295,3345,3395,3446,3496,3547,3597,
+3648,3698,3748,3799,3849,3900,3950,4001,
+4051,4101,4152,4202,4253,4303,4354,4404,
+4455,4505,4556,4606,4657,4707,4758,4808,
+4859,4910,4960,5011,5061,5112,5162,5213,
+5264,5314,5365,5415,5466,5517,5567,5618,
+5668,5719,5770,5820,5871,5922,5972,6023,
+6074,6124,6175,6226,6277,6327,6378,6429,
+6480,6530,6581,6632,6683,6733,6784,6835,
+6886,6937,6988,7038,7089,7140,7191,7242,
+7293,7344,7395,7445,7496,7547,7598,7649,
+7700,7751,7802,7853,7904,7955,8006,8057,
+8108,8159,8210,8261,8312,8363,8414,8466,
+8517,8568,8619,8670,8721,8772,8824,8875,
+8926,8977,9028,9080,9131,9182,9233,9285,
+9336,9387,9438,9490,9541,9592,9644,9695,
+9747,9798,9849,9901,9952,10004,10055,10106,
+10158,10209,10261,10312,10364,10415,10467,10519,
+10570,10622,10673,10725,10777,10828,10880,10931,
+10983,11035,11086,11138,11190,11242,11293,11345,
+11397,11449,11501,11552,11604,11656,11708,11760,
+11812,11864,11916,11967,12019,12071,12123,12175,
+12227,12279,12331,12383,12436,12488,12540,12592,
+12644,12696,12748,12800,12853,12905,12957,13009,
+13062,13114,13166,13218,13271,13323,13375,13428,
+13480,13533,13585,13637,13690,13742,13795,13847,
+13900,13952,14005,14057,14110,14163,14215,14268,
+14321,14373,14426,14479,14531,14584,14637,14690,
+14743,14795,14848,14901,14954,15007,15060,15113,
+15166,15219,15272,15325,15378,15431,15484,15537,
+15590,15643,15696,15749,15802,15856,15909,15962,
+16015,16069,16122,16175,16229,16282,16335,16389,
+16442,16496,16549,16603,16656,16710,16763,16817,
+16870,16924,16977,17031,17085,17138,17192,17246,
+17300,17353,17407,17461,17515,17569,17623,17677,
+17731,17784,17838,17892,17946,18001,18055,18109,
+18163,18217,18271,18325,18380,18434,18488,18542,
+18597,18651,18705,18760,18814,18868,18923,18977,
+19032,19086,19141,19195,19250,19305,19359,19414,
+19469,19523,19578,19633,19688,19742,19797,19852,
+19907,19962,20017,20072,20127,20182,20237,20292,
+20347,20402,20457,20513,20568,20623,20678,20734,
+20789,20844,20900,20955,21010,21066,21121,21177,
+21232,21288,21343,21399,21455,21510,21566,21622,
+21678,21733,21789,21845,21901,21957,22013,22069,
+22125,22181,22237,22293,22349,22405,22461,22517,
+22573,22630,22686,22742,22799,22855,22911,22968,
+23024,23081,23137,23194,23250,23307,23364,23420,
+23477,23534,23591,23647,23704,23761,23818,23875,
+23932,23989,24046,24103,24160,24217,24274,24331,
+24389,24446,24503,24560,24618,24675,24732,24790,
+24847,24905,24962,25020,25078,25135,25193,25251,
+25308,25366,25424,25482,25540,25598,25656,25714,
+25772,25830,25888,25946,26004,26062,26120,26179,
+26237,26295,26354,26412,26471,26529,26588,26646,
+26705,26763,26822,26881,26940,26998,27057,27116,
+27175,27234,27293,27352,27411,27470,27529,27588,
+27647,27707,27766,27825,27884,27944,28003,28063,
+28122,28182,28241,28301,28361,28420,28480,28540,
+28600,28660,28719,28779,28839,28899,28959,29020,
+29080,29140,29200,29260,29321,29381,29441,29502,
+29562,29623,29683,29744,29805,29865,29926,29987,
+30048,30108,30169,30230,30291,30352,30413,30474,
+30536,30597,30658,30719,30781,30842,30904,30965,
+31026,31088,31150,31211,31273,31335,31396,31458,
+31520,31582,31644,31706,31768,31830,31892,31955,
+32017,32079,32141,32204,32266,32329,32391,32454,
+32516,32579,32642,32705,32767,32830,32893,32956,
+33019,33082,33145,33208,33272,33335,33398,33461,
+33525,33588,33652,33715,33779,33843,33906,33970,
+34034,34098,34162,34225,34289,34354,34418,34482,
+34546,34610,34675,34739,34803,34868,34932,34997,
+35062,35126,35191,35256,35321,35385,35450,35515,
+35580,35646,35711,35776,35841,35907,35972,36037,
+36103,36168,36234,36300,36365,36431,36497,36563,
+36629,36695,36761,36827,36893,36959,37026,37092,
+37158,37225,37291,37358,37425,37491,37558,37625,
+37692,37759,37826,37893,37960,38027,38094,38161,
+38229,38296,38364,38431,38499,38566,38634,38702,
+38770,38837,38905,38973,39042,39110,39178,39246,
+39314,39383,39451,39520,39588,39657,39726,39794,
+39863,39932,40001,40070,40139,40208,40278,40347,
+40416,40486,40555,40625,40694,40764,40834,40904,
+40973,41043,41113,41184,41254,41324,41394,41465,
+41535,41605,41676,41747,41817,41888,41959,42030,
+42101,42172,42243,42314,42385,42457,42528,42600,
+42671,42743,42814,42886,42958,43030,43102,43174,
+43246,43318,43390,43463,43535,43608,43680,43753,
+43826,43898,43971,44044,44117,44190,44263,44337,
+44410,44483,44557,44630,44704,44778,44851,44925,
+44999,45073,45147,45221,45296,45370,45444,45519,
+45593,45668,45743,45818,45892,45967,46042,46118,
+46193,46268,46343,46419,46494,46570,46646,46721,
+46797,46873,46949,47025,47102,47178,47254,47331,
+47407,47484,47560,47637,47714,47791,47868,47945,
+48022,48100,48177,48255,48332,48410,48488,48565,
+48643,48721,48799,48878,48956,49034,49113,49191,
+49270,49349,49427,49506,49585,49664,49744,49823,
+49902,49982,50061,50141,50221,50300,50380,50460,
+50540,50621,50701,50781,50862,50942,51023,51104,
+51185,51266,51347,51428,51509,51591,51672,51754,
+51835,51917,51999,52081,52163,52245,52327,52410,
+52492,52575,52657,52740,52823,52906,52989,53072,
+53156,53239,53322,53406,53490,53574,53657,53741,
+53826,53910,53994,54079,54163,54248,54333,54417,
+54502,54587,54673,54758,54843,54929,55015,55100,
+55186,55272,55358,55444,55531,55617,55704,55790,
+55877,55964,56051,56138,56225,56312,56400,56487,
+56575,56663,56751,56839,56927,57015,57104,57192,
+57281,57369,57458,57547,57636,57725,57815,57904,
+57994,58083,58173,58263,58353,58443,58534,58624,
+58715,58805,58896,58987,59078,59169,59261,59352,
+59444,59535,59627,59719,59811,59903,59996,60088,
+60181,60273,60366,60459,60552,60646,60739,60833,
+60926,61020,61114,61208,61302,61396,61491,61585,
+61680,61775,61870,61965,62060,62156,62251,62347,
+62443,62539,62635,62731,62828,62924,63021,63118,
+63215,63312,63409,63506,63604,63702,63799,63897,
+63996,64094,64192,64291,64389,64488,64587,64687,
+64786,64885,64985,65085,65185,65285,65385,65485,
+65586,65686,65787,65888,65989,66091,66192,66294,
+66396,66498,66600,66702,66804,66907,67010,67113,
+67216,67319,67422,67526,67629,67733,67837,67942,
+68046,68151,68255,68360,68465,68570,68676,68781,
+68887,68993,69099,69205,69312,69418,69525,69632,
+69739,69846,69954,70061,70169,70277,70385,70494,
+70602,70711,70820,70929,71038,71147,71257,71367,
+71477,71587,71697,71808,71918,72029,72140,72252,
+72363,72475,72587,72699,72811,72923,73036,73149,
+73262,73375,73488,73602,73715,73829,73944,74058,
+74172,74287,74402,74517,74633,74748,74864,74980,
+75096,75213,75329,75446,75563,75680,75797,75915,
+76033,76151,76269,76388,76506,76625,76744,76864,
+76983,77103,77223,77343,77463,77584,77705,77826,
+77947,78068,78190,78312,78434,78557,78679,78802,
+78925,79048,79172,79296,79420,79544,79668,79793,
+79918,80043,80168,80294,80420,80546,80672,80799,
+80925,81053,81180,81307,81435,81563,81691,81820,
+81949,82078,82207,82336,82466,82596,82726,82857,
+82987,83118,83250,83381,83513,83645,83777,83910,
+84043,84176,84309,84443,84576,84710,84845,84980,
+85114,85250,85385,85521,85657,85793,85930,86066,
+86204,86341,86479,86616,86755,86893,87032,87171,
+87310,87450,87590,87730,87871,88011,88152,88294,
+88435,88577,88720,88862,89005,89148,89292,89435,
+89579,89724,89868,90013,90158,90304,90450,90596,
+90742,90889,91036,91184,91332,91480,91628,91777,
+91926,92075,92225,92375,92525,92675,92826,92978,
+93129,93281,93434,93586,93739,93892,94046,94200,
+94354,94509,94664,94819,94975,95131,95287,95444,
+95601,95758,95916,96074,96233,96391,96551,96710,
+96870,97030,97191,97352,97513,97675,97837,98000,
+98163,98326,98489,98653,98818,98982,99148,99313,
+99479,99645,99812,99979,100146,100314,100482,100651,
+100820,100990,101159,101330,101500,101671,101843,102015,
+102187,102360,102533,102706,102880,103054,103229,103404,
+103580,103756,103933,104109,104287,104465,104643,104821,
+105000,105180,105360,105540,105721,105902,106084,106266,
+106449,106632,106816,107000,107184,107369,107555,107741,
+107927,108114,108301,108489,108677,108866,109055,109245,
+109435,109626,109817,110008,110200,110393,110586,110780,
+110974,111169,111364,111560,111756,111952,112150,112347,
+112546,112744,112944,113143,113344,113545,113746,113948,
+114151,114354,114557,114761,114966,115171,115377,115583,
+115790,115998,116206,116414,116623,116833,117044,117254,
+117466,117678,117891,118104,118318,118532,118747,118963,
+119179,119396,119613,119831,120050,120269,120489,120709,
+120930,121152,121374,121597,121821,122045,122270,122496,
+122722,122949,123176,123404,123633,123863,124093,124324,
+124555,124787,125020,125254,125488,125723,125959,126195,
+126432,126669,126908,127147,127387,127627,127869,128111,
+128353,128597,128841,129086,129332,129578,129825,130073,
+130322,130571,130821,131072,131324,131576,131830,132084,
+132339,132594,132851,133108,133366,133625,133884,134145,
+134406,134668,134931,135195,135459,135725,135991,136258,
+136526,136795,137065,137335,137607,137879,138152,138426,
+138701,138977,139254,139532,139810,140090,140370,140651,
+140934,141217,141501,141786,142072,142359,142647,142936,
+143226,143517,143808,144101,144395,144690,144986,145282,
+145580,145879,146179,146480,146782,147084,147388,147693,
+148000,148307,148615,148924,149235,149546,149859,150172,
+150487,150803,151120,151438,151757,152077,152399,152722,
+153045,153370,153697,154024,154352,154682,155013,155345,
+155678,156013,156349,156686,157024,157363,157704,158046,
+158389,158734,159079,159427,159775,160125,160476,160828,
+161182,161537,161893,162251,162610,162970,163332,163695,
+164060,164426,164793,165162,165532,165904,166277,166651,
+167027,167405,167784,168164,168546,168930,169315,169701,
+170089,170479,170870,171263,171657,172053,172451,172850,
+173251,173653,174057,174463,174870,175279,175690,176102,
+176516,176932,177349,177769,178190,178612,179037,179463,
+179891,180321,180753,181186,181622,182059,182498,182939,
+183382,183827,184274,184722,185173,185625,186080,186536,
+186995,187455,187918,188382,188849,189318,189789,190261,
+190736,191213,191693,192174,192658,193143,193631,194122,
+194614,195109,195606,196105,196606,197110,197616,198125,
+198636,199149,199664,200182,200703,201226,201751,202279,
+202809,203342,203878,204416,204956,205500,206045,206594,
+207145,207699,208255,208815,209376,209941,210509,211079,
+211652,212228,212807,213389,213973,214561,215151,215745,
+216341,216941,217544,218149,218758,219370,219985,220603,
+221225,221849,222477,223108,223743,224381,225022,225666,
+226314,226966,227621,228279,228941,229606,230275,230948,
+231624,232304,232988,233676,234367,235062,235761,236463,
+237170,237881,238595,239314,240036,240763,241493,242228,
+242967,243711,244458,245210,245966,246727,247492,248261,
+249035,249813,250596,251384,252176,252973,253774,254581,
+255392,256208,257029,257855,258686,259522,260363,261209,
+262060,262917,263779,264646,265519,266397,267280,268169,
+269064,269965,270871,271782,272700,273624,274553,275489,
+276430,277378,278332,279292,280258,281231,282210,283195,
+284188,285186,286192,287204,288223,289249,290282,291322,
+292369,293423,294485,295554,296630,297714,298805,299904,
+301011,302126,303248,304379,305517,306664,307819,308983,
+310154,311335,312524,313721,314928,316143,317368,318601,
+319844,321097,322358,323629,324910,326201,327502,328812,
+330133,331464,332805,334157,335519,336892,338276,339671,
+341078,342495,343924,345364,346816,348280,349756,351244,
+352744,354257,355783,357321,358872,360436,362013,363604,
+365208,366826,368459,370105,371765,373440,375130,376835,
+378555,380290,382040,383807,385589,387387,389202,391034,
+392882,394747,396630,398530,400448,402384,404338,406311,
+408303,410314,412344,414395,416465,418555,420666,422798,
+424951,427125,429321,431540,433781,436045,438332,440643,
+442978,445337,447720,450129,452564,455024,457511,460024,
+462565,465133,467730,470355,473009,475692,478406,481150,
+483925,486732,489571,492443,495348,498287,501261,504269,
+507313,510394,513512,516667,519861,523094,526366,529680,
+533034,536431,539870,543354,546881,550455,554074,557741,
+561456,565221,569035,572901,576818,580789,584815,588896,
+593033,597229,601483,605798,610174,614613,619117,623686,
+628323,633028,637803,642651,647572,652568,657640,662792,
+668024,673338,678737,684223,689797,695462,701219,707072,
+713023,719074,725227,731486,737853,744331,750922,757631,
+764460,771411,778490,785699,793041,800521,808143,815910,
+823827,831898,840127,848520,857081,865817,874730,883829,
+893117,902602,912289,922186,932298,942633,953199,964003,
+975054,986361,997931,1009774,1021901,1034322,1047046,1060087,
+1073455,1087164,1101225,1115654,1130465,1145673,1161294,1177345,
+1193846,1210813,1228269,1246234,1264730,1283783,1303416,1323658,
+1344537,1366084,1388330,1411312,1435065,1459630,1485049,1511367,
+1538632,1566898,1596220,1626658,1658278,1691149,1725348,1760956,
+1798063,1836758,1877161,1919378,1963536,2009771,2058233,2109087,
+2162516,2218719,2277919,2340362,2406322,2476104,2550052,2628549,
+2712030,2800983,2895966,2997613,3106651,3223918,3350381,3487165,
+3635590,3797206,3973855,4167737,4381502,4618375,4882318,5178251,
+5512368,5892567,6329090,6835455,7429880,8137527,8994149,10052327,
+11392683,13145455,15535599,18988036,24413316,34178904,56965752,170910304
+};
+
+int finesine[10240] =
+{
+25,75,125,175,226,276,326,376,
+427,477,527,578,628,678,728,779,
+829,879,929,980,1030,1080,1130,1181,
+1231,1281,1331,1382,1432,1482,1532,1583,
+1633,1683,1733,1784,1834,1884,1934,1985,
+2035,2085,2135,2186,2236,2286,2336,2387,
+2437,2487,2537,2587,2638,2688,2738,2788,
+2839,2889,2939,2989,3039,3090,3140,3190,
+3240,3291,3341,3391,3441,3491,3541,3592,
+3642,3692,3742,3792,3843,3893,3943,3993,
+4043,4093,4144,4194,4244,4294,4344,4394,
+4445,4495,4545,4595,4645,4695,4745,4796,
+4846,4896,4946,4996,5046,5096,5146,5197,
+5247,5297,5347,5397,5447,5497,5547,5597,
+5647,5697,5748,5798,5848,5898,5948,5998,
+6048,6098,6148,6198,6248,6298,6348,6398,
+6448,6498,6548,6598,6648,6698,6748,6798,
+6848,6898,6948,6998,7048,7098,7148,7198,
+7248,7298,7348,7398,7448,7498,7548,7598,
+7648,7697,7747,7797,7847,7897,7947,7997,
+8047,8097,8147,8196,8246,8296,8346,8396,
+8446,8496,8545,8595,8645,8695,8745,8794,
+8844,8894,8944,8994,9043,9093,9143,9193,
+9243,9292,9342,9392,9442,9491,9541,9591,
+9640,9690,9740,9790,9839,9889,9939,9988,
+10038,10088,10137,10187,10237,10286,10336,10386,
+10435,10485,10534,10584,10634,10683,10733,10782,
+10832,10882,10931,10981,11030,11080,11129,11179,
+11228,11278,11327,11377,11426,11476,11525,11575,
+11624,11674,11723,11773,11822,11872,11921,11970,
+12020,12069,12119,12168,12218,12267,12316,12366,
+12415,12464,12514,12563,12612,12662,12711,12760,
+12810,12859,12908,12957,13007,13056,13105,13154,
+13204,13253,13302,13351,13401,13450,13499,13548,
+13597,13647,13696,13745,13794,13843,13892,13941,
+13990,14040,14089,14138,14187,14236,14285,14334,
+14383,14432,14481,14530,14579,14628,14677,14726,
+14775,14824,14873,14922,14971,15020,15069,15118,
+15167,15215,15264,15313,15362,15411,15460,15509,
+15557,15606,15655,15704,15753,15802,15850,15899,
+15948,15997,16045,16094,16143,16191,16240,16289,
+16338,16386,16435,16484,16532,16581,16629,16678,
+16727,16775,16824,16872,16921,16970,17018,17067,
+17115,17164,17212,17261,17309,17358,17406,17455,
+17503,17551,17600,17648,17697,17745,17793,17842,
+17890,17939,17987,18035,18084,18132,18180,18228,
+18277,18325,18373,18421,18470,18518,18566,18614,
+18663,18711,18759,18807,18855,18903,18951,19000,
+19048,19096,19144,19192,19240,19288,19336,19384,
+19432,19480,19528,19576,19624,19672,19720,19768,
+19816,19864,19912,19959,20007,20055,20103,20151,
+20199,20246,20294,20342,20390,20438,20485,20533,
+20581,20629,20676,20724,20772,20819,20867,20915,
+20962,21010,21057,21105,21153,21200,21248,21295,
+21343,21390,21438,21485,21533,21580,21628,21675,
+21723,21770,21817,21865,21912,21960,22007,22054,
+22102,22149,22196,22243,22291,22338,22385,22433,
+22480,22527,22574,22621,22668,22716,22763,22810,
+22857,22904,22951,22998,23045,23092,23139,23186,
+23233,23280,23327,23374,23421,23468,23515,23562,
+23609,23656,23703,23750,23796,23843,23890,23937,
+23984,24030,24077,24124,24171,24217,24264,24311,
+24357,24404,24451,24497,24544,24591,24637,24684,
+24730,24777,24823,24870,24916,24963,25009,25056,
+25102,25149,25195,25241,25288,25334,25381,25427,
+25473,25520,25566,25612,25658,25705,25751,25797,
+25843,25889,25936,25982,26028,26074,26120,26166,
+26212,26258,26304,26350,26396,26442,26488,26534,
+26580,26626,26672,26718,26764,26810,26856,26902,
+26947,26993,27039,27085,27131,27176,27222,27268,
+27313,27359,27405,27450,27496,27542,27587,27633,
+27678,27724,27770,27815,27861,27906,27952,27997,
+28042,28088,28133,28179,28224,28269,28315,28360,
+28405,28451,28496,28541,28586,28632,28677,28722,
+28767,28812,28858,28903,28948,28993,29038,29083,
+29128,29173,29218,29263,29308,29353,29398,29443,
+29488,29533,29577,29622,29667,29712,29757,29801,
+29846,29891,29936,29980,30025,30070,30114,30159,
+30204,30248,30293,30337,30382,30426,30471,30515,
+30560,30604,30649,30693,30738,30782,30826,30871,
+30915,30959,31004,31048,31092,31136,31181,31225,
+31269,31313,31357,31402,31446,31490,31534,31578,
+31622,31666,31710,31754,31798,31842,31886,31930,
+31974,32017,32061,32105,32149,32193,32236,32280,
+32324,32368,32411,32455,32499,32542,32586,32630,
+32673,32717,32760,32804,32847,32891,32934,32978,
+33021,33065,33108,33151,33195,33238,33281,33325,
+33368,33411,33454,33498,33541,33584,33627,33670,
+33713,33756,33799,33843,33886,33929,33972,34015,
+34057,34100,34143,34186,34229,34272,34315,34358,
+34400,34443,34486,34529,34571,34614,34657,34699,
+34742,34785,34827,34870,34912,34955,34997,35040,
+35082,35125,35167,35210,35252,35294,35337,35379,
+35421,35464,35506,35548,35590,35633,35675,35717,
+35759,35801,35843,35885,35927,35969,36011,36053,
+36095,36137,36179,36221,36263,36305,36347,36388,
+36430,36472,36514,36555,36597,36639,36681,36722,
+36764,36805,36847,36889,36930,36972,37013,37055,
+37096,37137,37179,37220,37262,37303,37344,37386,
+37427,37468,37509,37551,37592,37633,37674,37715,
+37756,37797,37838,37879,37920,37961,38002,38043,
+38084,38125,38166,38207,38248,38288,38329,38370,
+38411,38451,38492,38533,38573,38614,38655,38695,
+38736,38776,38817,38857,38898,38938,38979,39019,
+39059,39100,39140,39180,39221,39261,39301,39341,
+39382,39422,39462,39502,39542,39582,39622,39662,
+39702,39742,39782,39822,39862,39902,39942,39982,
+40021,40061,40101,40141,40180,40220,40260,40300,
+40339,40379,40418,40458,40497,40537,40576,40616,
+40655,40695,40734,40773,40813,40852,40891,40931,
+40970,41009,41048,41087,41127,41166,41205,41244,
+41283,41322,41361,41400,41439,41478,41517,41556,
+41595,41633,41672,41711,41750,41788,41827,41866,
+41904,41943,41982,42020,42059,42097,42136,42174,
+42213,42251,42290,42328,42366,42405,42443,42481,
+42520,42558,42596,42634,42672,42711,42749,42787,
+42825,42863,42901,42939,42977,43015,43053,43091,
+43128,43166,43204,43242,43280,43317,43355,43393,
+43430,43468,43506,43543,43581,43618,43656,43693,
+43731,43768,43806,43843,43880,43918,43955,43992,
+44029,44067,44104,44141,44178,44215,44252,44289,
+44326,44363,44400,44437,44474,44511,44548,44585,
+44622,44659,44695,44732,44769,44806,44842,44879,
+44915,44952,44989,45025,45062,45098,45135,45171,
+45207,45244,45280,45316,45353,45389,45425,45462,
+45498,45534,45570,45606,45642,45678,45714,45750,
+45786,45822,45858,45894,45930,45966,46002,46037,
+46073,46109,46145,46180,46216,46252,46287,46323,
+46358,46394,46429,46465,46500,46536,46571,46606,
+46642,46677,46712,46747,46783,46818,46853,46888,
+46923,46958,46993,47028,47063,47098,47133,47168,
+47203,47238,47273,47308,47342,47377,47412,47446,
+47481,47516,47550,47585,47619,47654,47688,47723,
+47757,47792,47826,47860,47895,47929,47963,47998,
+48032,48066,48100,48134,48168,48202,48237,48271,
+48305,48338,48372,48406,48440,48474,48508,48542,
+48575,48609,48643,48676,48710,48744,48777,48811,
+48844,48878,48911,48945,48978,49012,49045,49078,
+49112,49145,49178,49211,49244,49278,49311,49344,
+49377,49410,49443,49476,49509,49542,49575,49608,
+49640,49673,49706,49739,49771,49804,49837,49869,
+49902,49935,49967,50000,50032,50065,50097,50129,
+50162,50194,50226,50259,50291,50323,50355,50387,
+50420,50452,50484,50516,50548,50580,50612,50644,
+50675,50707,50739,50771,50803,50834,50866,50898,
+50929,50961,50993,51024,51056,51087,51119,51150,
+51182,51213,51244,51276,51307,51338,51369,51401,
+51432,51463,51494,51525,51556,51587,51618,51649,
+51680,51711,51742,51773,51803,51834,51865,51896,
+51926,51957,51988,52018,52049,52079,52110,52140,
+52171,52201,52231,52262,52292,52322,52353,52383,
+52413,52443,52473,52503,52534,52564,52594,52624,
+52653,52683,52713,52743,52773,52803,52832,52862,
+52892,52922,52951,52981,53010,53040,53069,53099,
+53128,53158,53187,53216,53246,53275,53304,53334,
+53363,53392,53421,53450,53479,53508,53537,53566,
+53595,53624,53653,53682,53711,53739,53768,53797,
+53826,53854,53883,53911,53940,53969,53997,54026,
+54054,54082,54111,54139,54167,54196,54224,54252,
+54280,54308,54337,54365,54393,54421,54449,54477,
+54505,54533,54560,54588,54616,54644,54672,54699,
+54727,54755,54782,54810,54837,54865,54892,54920,
+54947,54974,55002,55029,55056,55084,55111,55138,
+55165,55192,55219,55246,55274,55300,55327,55354,
+55381,55408,55435,55462,55489,55515,55542,55569,
+55595,55622,55648,55675,55701,55728,55754,55781,
+55807,55833,55860,55886,55912,55938,55965,55991,
+56017,56043,56069,56095,56121,56147,56173,56199,
+56225,56250,56276,56302,56328,56353,56379,56404,
+56430,56456,56481,56507,56532,56557,56583,56608,
+56633,56659,56684,56709,56734,56760,56785,56810,
+56835,56860,56885,56910,56935,56959,56984,57009,
+57034,57059,57083,57108,57133,57157,57182,57206,
+57231,57255,57280,57304,57329,57353,57377,57402,
+57426,57450,57474,57498,57522,57546,57570,57594,
+57618,57642,57666,57690,57714,57738,57762,57785,
+57809,57833,57856,57880,57903,57927,57950,57974,
+57997,58021,58044,58067,58091,58114,58137,58160,
+58183,58207,58230,58253,58276,58299,58322,58345,
+58367,58390,58413,58436,58459,58481,58504,58527,
+58549,58572,58594,58617,58639,58662,58684,58706,
+58729,58751,58773,58795,58818,58840,58862,58884,
+58906,58928,58950,58972,58994,59016,59038,59059,
+59081,59103,59125,59146,59168,59190,59211,59233,
+59254,59276,59297,59318,59340,59361,59382,59404,
+59425,59446,59467,59488,59509,59530,59551,59572,
+59593,59614,59635,59656,59677,59697,59718,59739,
+59759,59780,59801,59821,59842,59862,59883,59903,
+59923,59944,59964,59984,60004,60025,60045,60065,
+60085,60105,60125,60145,60165,60185,60205,60225,
+60244,60264,60284,60304,60323,60343,60363,60382,
+60402,60421,60441,60460,60479,60499,60518,60537,
+60556,60576,60595,60614,60633,60652,60671,60690,
+60709,60728,60747,60766,60785,60803,60822,60841,
+60859,60878,60897,60915,60934,60952,60971,60989,
+61007,61026,61044,61062,61081,61099,61117,61135,
+61153,61171,61189,61207,61225,61243,61261,61279,
+61297,61314,61332,61350,61367,61385,61403,61420,
+61438,61455,61473,61490,61507,61525,61542,61559,
+61577,61594,61611,61628,61645,61662,61679,61696,
+61713,61730,61747,61764,61780,61797,61814,61831,
+61847,61864,61880,61897,61913,61930,61946,61963,
+61979,61995,62012,62028,62044,62060,62076,62092,
+62108,62125,62141,62156,62172,62188,62204,62220,
+62236,62251,62267,62283,62298,62314,62329,62345,
+62360,62376,62391,62407,62422,62437,62453,62468,
+62483,62498,62513,62528,62543,62558,62573,62588,
+62603,62618,62633,62648,62662,62677,62692,62706,
+62721,62735,62750,62764,62779,62793,62808,62822,
+62836,62850,62865,62879,62893,62907,62921,62935,
+62949,62963,62977,62991,63005,63019,63032,63046,
+63060,63074,63087,63101,63114,63128,63141,63155,
+63168,63182,63195,63208,63221,63235,63248,63261,
+63274,63287,63300,63313,63326,63339,63352,63365,
+63378,63390,63403,63416,63429,63441,63454,63466,
+63479,63491,63504,63516,63528,63541,63553,63565,
+63578,63590,63602,63614,63626,63638,63650,63662,
+63674,63686,63698,63709,63721,63733,63745,63756,
+63768,63779,63791,63803,63814,63825,63837,63848,
+63859,63871,63882,63893,63904,63915,63927,63938,
+63949,63960,63971,63981,63992,64003,64014,64025,
+64035,64046,64057,64067,64078,64088,64099,64109,
+64120,64130,64140,64151,64161,64171,64181,64192,
+64202,64212,64222,64232,64242,64252,64261,64271,
+64281,64291,64301,64310,64320,64330,64339,64349,
+64358,64368,64377,64387,64396,64405,64414,64424,
+64433,64442,64451,64460,64469,64478,64487,64496,
+64505,64514,64523,64532,64540,64549,64558,64566,
+64575,64584,64592,64601,64609,64617,64626,64634,
+64642,64651,64659,64667,64675,64683,64691,64699,
+64707,64715,64723,64731,64739,64747,64754,64762,
+64770,64777,64785,64793,64800,64808,64815,64822,
+64830,64837,64844,64852,64859,64866,64873,64880,
+64887,64895,64902,64908,64915,64922,64929,64936,
+64943,64949,64956,64963,64969,64976,64982,64989,
+64995,65002,65008,65015,65021,65027,65033,65040,
+65046,65052,65058,65064,65070,65076,65082,65088,
+65094,65099,65105,65111,65117,65122,65128,65133,
+65139,65144,65150,65155,65161,65166,65171,65177,
+65182,65187,65192,65197,65202,65207,65212,65217,
+65222,65227,65232,65237,65242,65246,65251,65256,
+65260,65265,65270,65274,65279,65283,65287,65292,
+65296,65300,65305,65309,65313,65317,65321,65325,
+65329,65333,65337,65341,65345,65349,65352,65356,
+65360,65363,65367,65371,65374,65378,65381,65385,
+65388,65391,65395,65398,65401,65404,65408,65411,
+65414,65417,65420,65423,65426,65429,65431,65434,
+65437,65440,65442,65445,65448,65450,65453,65455,
+65458,65460,65463,65465,65467,65470,65472,65474,
+65476,65478,65480,65482,65484,65486,65488,65490,
+65492,65494,65496,65497,65499,65501,65502,65504,
+65505,65507,65508,65510,65511,65513,65514,65515,
+65516,65518,65519,65520,65521,65522,65523,65524,
+65525,65526,65527,65527,65528,65529,65530,65530,
+65531,65531,65532,65532,65533,65533,65534,65534,
+65534,65535,65535,65535,65535,65535,65535,65535,
+65535,65535,65535,65535,65535,65535,65535,65534,
+65534,65534,65533,65533,65532,65532,65531,65531,
+65530,65530,65529,65528,65527,65527,65526,65525,
+65524,65523,65522,65521,65520,65519,65518,65516,
+65515,65514,65513,65511,65510,65508,65507,65505,
+65504,65502,65501,65499,65497,65496,65494,65492,
+65490,65488,65486,65484,65482,65480,65478,65476,
+65474,65472,65470,65467,65465,65463,65460,65458,
+65455,65453,65450,65448,65445,65442,65440,65437,
+65434,65431,65429,65426,65423,65420,65417,65414,
+65411,65408,65404,65401,65398,65395,65391,65388,
+65385,65381,65378,65374,65371,65367,65363,65360,
+65356,65352,65349,65345,65341,65337,65333,65329,
+65325,65321,65317,65313,65309,65305,65300,65296,
+65292,65287,65283,65279,65274,65270,65265,65260,
+65256,65251,65246,65242,65237,65232,65227,65222,
+65217,65212,65207,65202,65197,65192,65187,65182,
+65177,65171,65166,65161,65155,65150,65144,65139,
+65133,65128,65122,65117,65111,65105,65099,65094,
+65088,65082,65076,65070,65064,65058,65052,65046,
+65040,65033,65027,65021,65015,65008,65002,64995,
+64989,64982,64976,64969,64963,64956,64949,64943,
+64936,64929,64922,64915,64908,64902,64895,64887,
+64880,64873,64866,64859,64852,64844,64837,64830,
+64822,64815,64808,64800,64793,64785,64777,64770,
+64762,64754,64747,64739,64731,64723,64715,64707,
+64699,64691,64683,64675,64667,64659,64651,64642,
+64634,64626,64617,64609,64600,64592,64584,64575,
+64566,64558,64549,64540,64532,64523,64514,64505,
+64496,64487,64478,64469,64460,64451,64442,64433,
+64424,64414,64405,64396,64387,64377,64368,64358,
+64349,64339,64330,64320,64310,64301,64291,64281,
+64271,64261,64252,64242,64232,64222,64212,64202,
+64192,64181,64171,64161,64151,64140,64130,64120,
+64109,64099,64088,64078,64067,64057,64046,64035,
+64025,64014,64003,63992,63981,63971,63960,63949,
+63938,63927,63915,63904,63893,63882,63871,63859,
+63848,63837,63825,63814,63803,63791,63779,63768,
+63756,63745,63733,63721,63709,63698,63686,63674,
+63662,63650,63638,63626,63614,63602,63590,63578,
+63565,63553,63541,63528,63516,63504,63491,63479,
+63466,63454,63441,63429,63416,63403,63390,63378,
+63365,63352,63339,63326,63313,63300,63287,63274,
+63261,63248,63235,63221,63208,63195,63182,63168,
+63155,63141,63128,63114,63101,63087,63074,63060,
+63046,63032,63019,63005,62991,62977,62963,62949,
+62935,62921,62907,62893,62879,62865,62850,62836,
+62822,62808,62793,62779,62764,62750,62735,62721,
+62706,62692,62677,62662,62648,62633,62618,62603,
+62588,62573,62558,62543,62528,62513,62498,62483,
+62468,62453,62437,62422,62407,62391,62376,62360,
+62345,62329,62314,62298,62283,62267,62251,62236,
+62220,62204,62188,62172,62156,62141,62125,62108,
+62092,62076,62060,62044,62028,62012,61995,61979,
+61963,61946,61930,61913,61897,61880,61864,61847,
+61831,61814,61797,61780,61764,61747,61730,61713,
+61696,61679,61662,61645,61628,61611,61594,61577,
+61559,61542,61525,61507,61490,61473,61455,61438,
+61420,61403,61385,61367,61350,61332,61314,61297,
+61279,61261,61243,61225,61207,61189,61171,61153,
+61135,61117,61099,61081,61062,61044,61026,61007,
+60989,60971,60952,60934,60915,60897,60878,60859,
+60841,60822,60803,60785,60766,60747,60728,60709,
+60690,60671,60652,60633,60614,60595,60576,60556,
+60537,60518,60499,60479,60460,60441,60421,60402,
+60382,60363,60343,60323,60304,60284,60264,60244,
+60225,60205,60185,60165,60145,60125,60105,60085,
+60065,60045,60025,60004,59984,59964,59944,59923,
+59903,59883,59862,59842,59821,59801,59780,59759,
+59739,59718,59697,59677,59656,59635,59614,59593,
+59572,59551,59530,59509,59488,59467,59446,59425,
+59404,59382,59361,59340,59318,59297,59276,59254,
+59233,59211,59190,59168,59146,59125,59103,59081,
+59059,59038,59016,58994,58972,58950,58928,58906,
+58884,58862,58840,58818,58795,58773,58751,58729,
+58706,58684,58662,58639,58617,58594,58572,58549,
+58527,58504,58481,58459,58436,58413,58390,58367,
+58345,58322,58299,58276,58253,58230,58207,58183,
+58160,58137,58114,58091,58067,58044,58021,57997,
+57974,57950,57927,57903,57880,57856,57833,57809,
+57785,57762,57738,57714,57690,57666,57642,57618,
+57594,57570,57546,57522,57498,57474,57450,57426,
+57402,57377,57353,57329,57304,57280,57255,57231,
+57206,57182,57157,57133,57108,57083,57059,57034,
+57009,56984,56959,56935,56910,56885,56860,56835,
+56810,56785,56760,56734,56709,56684,56659,56633,
+56608,56583,56557,56532,56507,56481,56456,56430,
+56404,56379,56353,56328,56302,56276,56250,56225,
+56199,56173,56147,56121,56095,56069,56043,56017,
+55991,55965,55938,55912,55886,55860,55833,55807,
+55781,55754,55728,55701,55675,55648,55622,55595,
+55569,55542,55515,55489,55462,55435,55408,55381,
+55354,55327,55300,55274,55246,55219,55192,55165,
+55138,55111,55084,55056,55029,55002,54974,54947,
+54920,54892,54865,54837,54810,54782,54755,54727,
+54699,54672,54644,54616,54588,54560,54533,54505,
+54477,54449,54421,54393,54365,54337,54308,54280,
+54252,54224,54196,54167,54139,54111,54082,54054,
+54026,53997,53969,53940,53911,53883,53854,53826,
+53797,53768,53739,53711,53682,53653,53624,53595,
+53566,53537,53508,53479,53450,53421,53392,53363,
+53334,53304,53275,53246,53216,53187,53158,53128,
+53099,53069,53040,53010,52981,52951,52922,52892,
+52862,52832,52803,52773,52743,52713,52683,52653,
+52624,52594,52564,52534,52503,52473,52443,52413,
+52383,52353,52322,52292,52262,52231,52201,52171,
+52140,52110,52079,52049,52018,51988,51957,51926,
+51896,51865,51834,51803,51773,51742,51711,51680,
+51649,51618,51587,51556,51525,51494,51463,51432,
+51401,51369,51338,51307,51276,51244,51213,51182,
+51150,51119,51087,51056,51024,50993,50961,50929,
+50898,50866,50834,50803,50771,50739,50707,50675,
+50644,50612,50580,50548,50516,50484,50452,50420,
+50387,50355,50323,50291,50259,50226,50194,50162,
+50129,50097,50065,50032,50000,49967,49935,49902,
+49869,49837,49804,49771,49739,49706,49673,49640,
+49608,49575,49542,49509,49476,49443,49410,49377,
+49344,49311,49278,49244,49211,49178,49145,49112,
+49078,49045,49012,48978,48945,48911,48878,48844,
+48811,48777,48744,48710,48676,48643,48609,48575,
+48542,48508,48474,48440,48406,48372,48338,48304,
+48271,48237,48202,48168,48134,48100,48066,48032,
+47998,47963,47929,47895,47860,47826,47792,47757,
+47723,47688,47654,47619,47585,47550,47516,47481,
+47446,47412,47377,47342,47308,47273,47238,47203,
+47168,47133,47098,47063,47028,46993,46958,46923,
+46888,46853,46818,46783,46747,46712,46677,46642,
+46606,46571,46536,46500,46465,46429,46394,46358,
+46323,46287,46252,46216,46180,46145,46109,46073,
+46037,46002,45966,45930,45894,45858,45822,45786,
+45750,45714,45678,45642,45606,45570,45534,45498,
+45462,45425,45389,45353,45316,45280,45244,45207,
+45171,45135,45098,45062,45025,44989,44952,44915,
+44879,44842,44806,44769,44732,44695,44659,44622,
+44585,44548,44511,44474,44437,44400,44363,44326,
+44289,44252,44215,44178,44141,44104,44067,44029,
+43992,43955,43918,43880,43843,43806,43768,43731,
+43693,43656,43618,43581,43543,43506,43468,43430,
+43393,43355,43317,43280,43242,43204,43166,43128,
+43091,43053,43015,42977,42939,42901,42863,42825,
+42787,42749,42711,42672,42634,42596,42558,42520,
+42481,42443,42405,42366,42328,42290,42251,42213,
+42174,42136,42097,42059,42020,41982,41943,41904,
+41866,41827,41788,41750,41711,41672,41633,41595,
+41556,41517,41478,41439,41400,41361,41322,41283,
+41244,41205,41166,41127,41088,41048,41009,40970,
+40931,40891,40852,40813,40773,40734,40695,40655,
+40616,40576,40537,40497,40458,40418,40379,40339,
+40300,40260,40220,40180,40141,40101,40061,40021,
+39982,39942,39902,39862,39822,39782,39742,39702,
+39662,39622,39582,39542,39502,39462,39422,39382,
+39341,39301,39261,39221,39180,39140,39100,39059,
+39019,38979,38938,38898,38857,38817,38776,38736,
+38695,38655,38614,38573,38533,38492,38451,38411,
+38370,38329,38288,38248,38207,38166,38125,38084,
+38043,38002,37961,37920,37879,37838,37797,37756,
+37715,37674,37633,37592,37551,37509,37468,37427,
+37386,37344,37303,37262,37220,37179,37137,37096,
+37055,37013,36972,36930,36889,36847,36805,36764,
+36722,36681,36639,36597,36556,36514,36472,36430,
+36388,36347,36305,36263,36221,36179,36137,36095,
+36053,36011,35969,35927,35885,35843,35801,35759,
+35717,35675,35633,35590,35548,35506,35464,35421,
+35379,35337,35294,35252,35210,35167,35125,35082,
+35040,34997,34955,34912,34870,34827,34785,34742,
+34699,34657,34614,34571,34529,34486,34443,34400,
+34358,34315,34272,34229,34186,34143,34100,34057,
+34015,33972,33929,33886,33843,33799,33756,33713,
+33670,33627,33584,33541,33498,33454,33411,33368,
+33325,33281,33238,33195,33151,33108,33065,33021,
+32978,32934,32891,32847,32804,32760,32717,32673,
+32630,32586,32542,32499,32455,32411,32368,32324,
+32280,32236,32193,32149,32105,32061,32017,31974,
+31930,31886,31842,31798,31754,31710,31666,31622,
+31578,31534,31490,31446,31402,31357,31313,31269,
+31225,31181,31136,31092,31048,31004,30959,30915,
+30871,30826,30782,30738,30693,30649,30604,30560,
+30515,30471,30426,30382,30337,30293,30248,30204,
+30159,30114,30070,30025,29980,29936,29891,29846,
+29801,29757,29712,29667,29622,29577,29533,29488,
+29443,29398,29353,29308,29263,29218,29173,29128,
+29083,29038,28993,28948,28903,28858,28812,28767,
+28722,28677,28632,28586,28541,28496,28451,28405,
+28360,28315,28269,28224,28179,28133,28088,28042,
+27997,27952,27906,27861,27815,27770,27724,27678,
+27633,27587,27542,27496,27450,27405,27359,27313,
+27268,27222,27176,27131,27085,27039,26993,26947,
+26902,26856,26810,26764,26718,26672,26626,26580,
+26534,26488,26442,26396,26350,26304,26258,26212,
+26166,26120,26074,26028,25982,25936,25889,25843,
+25797,25751,25705,25658,25612,25566,25520,25473,
+25427,25381,25334,25288,25241,25195,25149,25102,
+25056,25009,24963,24916,24870,24823,24777,24730,
+24684,24637,24591,24544,24497,24451,24404,24357,
+24311,24264,24217,24171,24124,24077,24030,23984,
+23937,23890,23843,23796,23750,23703,23656,23609,
+23562,23515,23468,23421,23374,23327,23280,23233,
+23186,23139,23092,23045,22998,22951,22904,22857,
+22810,22763,22716,22668,22621,22574,22527,22480,
+22433,22385,22338,22291,22243,22196,22149,22102,
+22054,22007,21960,21912,21865,21817,21770,21723,
+21675,21628,21580,21533,21485,21438,21390,21343,
+21295,21248,21200,21153,21105,21057,21010,20962,
+20915,20867,20819,20772,20724,20676,20629,20581,
+20533,20485,20438,20390,20342,20294,20246,20199,
+20151,20103,20055,20007,19959,19912,19864,19816,
+19768,19720,19672,19624,19576,19528,19480,19432,
+19384,19336,19288,19240,19192,19144,19096,19048,
+19000,18951,18903,18855,18807,18759,18711,18663,
+18614,18566,18518,18470,18421,18373,18325,18277,
+18228,18180,18132,18084,18035,17987,17939,17890,
+17842,17793,17745,17697,17648,17600,17551,17503,
+17455,17406,17358,17309,17261,17212,17164,17115,
+17067,17018,16970,16921,16872,16824,16775,16727,
+16678,16629,16581,16532,16484,16435,16386,16338,
+16289,16240,16191,16143,16094,16045,15997,15948,
+15899,15850,15802,15753,15704,15655,15606,15557,
+15509,15460,15411,15362,15313,15264,15215,15167,
+15118,15069,15020,14971,14922,14873,14824,14775,
+14726,14677,14628,14579,14530,14481,14432,14383,
+14334,14285,14236,14187,14138,14089,14040,13990,
+13941,13892,13843,13794,13745,13696,13646,13597,
+13548,13499,13450,13401,13351,13302,13253,13204,
+13154,13105,13056,13007,12957,12908,12859,12810,
+12760,12711,12662,12612,12563,12514,12464,12415,
+12366,12316,12267,12218,12168,12119,12069,12020,
+11970,11921,11872,11822,11773,11723,11674,11624,
+11575,11525,11476,11426,11377,11327,11278,11228,
+11179,11129,11080,11030,10981,10931,10882,10832,
+10782,10733,10683,10634,10584,10534,10485,10435,
+10386,10336,10286,10237,10187,10137,10088,10038,
+9988,9939,9889,9839,9790,9740,9690,9640,
+9591,9541,9491,9442,9392,9342,9292,9243,
+9193,9143,9093,9043,8994,8944,8894,8844,
+8794,8745,8695,8645,8595,8545,8496,8446,
+8396,8346,8296,8246,8196,8147,8097,8047,
+7997,7947,7897,7847,7797,7747,7697,7648,
+7598,7548,7498,7448,7398,7348,7298,7248,
+7198,7148,7098,7048,6998,6948,6898,6848,
+6798,6748,6698,6648,6598,6548,6498,6448,
+6398,6348,6298,6248,6198,6148,6098,6048,
+5998,5948,5898,5848,5798,5748,5697,5647,
+5597,5547,5497,5447,5397,5347,5297,5247,
+5197,5146,5096,5046,4996,4946,4896,4846,
+4796,4745,4695,4645,4595,4545,4495,4445,
+4394,4344,4294,4244,4194,4144,4093,4043,
+3993,3943,3893,3843,3792,3742,3692,3642,
+3592,3541,3491,3441,3391,3341,3291,3240,
+3190,3140,3090,3039,2989,2939,2889,2839,
+2788,2738,2688,2638,2587,2537,2487,2437,
+2387,2336,2286,2236,2186,2135,2085,2035,
+1985,1934,1884,1834,1784,1733,1683,1633,
+1583,1532,1482,1432,1382,1331,1281,1231,
+1181,1130,1080,1030,980,929,879,829,
+779,728,678,628,578,527,477,427,
+376,326,276,226,175,125,75,25,
+-25,-75,-125,-175,-226,-276,-326,-376,
+-427,-477,-527,-578,-628,-678,-728,-779,
+-829,-879,-929,-980,-1030,-1080,-1130,-1181,
+-1231,-1281,-1331,-1382,-1432,-1482,-1532,-1583,
+-1633,-1683,-1733,-1784,-1834,-1884,-1934,-1985,
+-2035,-2085,-2135,-2186,-2236,-2286,-2336,-2387,
+-2437,-2487,-2537,-2588,-2638,-2688,-2738,-2788,
+-2839,-2889,-2939,-2989,-3039,-3090,-3140,-3190,
+-3240,-3291,-3341,-3391,-3441,-3491,-3541,-3592,
+-3642,-3692,-3742,-3792,-3843,-3893,-3943,-3993,
+-4043,-4093,-4144,-4194,-4244,-4294,-4344,-4394,
+-4445,-4495,-4545,-4595,-4645,-4695,-4745,-4796,
+-4846,-4896,-4946,-4996,-5046,-5096,-5146,-5197,
+-5247,-5297,-5347,-5397,-5447,-5497,-5547,-5597,
+-5647,-5697,-5748,-5798,-5848,-5898,-5948,-5998,
+-6048,-6098,-6148,-6198,-6248,-6298,-6348,-6398,
+-6448,-6498,-6548,-6598,-6648,-6698,-6748,-6798,
+-6848,-6898,-6948,-6998,-7048,-7098,-7148,-7198,
+-7248,-7298,-7348,-7398,-7448,-7498,-7548,-7598,
+-7648,-7697,-7747,-7797,-7847,-7897,-7947,-7997,
+-8047,-8097,-8147,-8196,-8246,-8296,-8346,-8396,
+-8446,-8496,-8545,-8595,-8645,-8695,-8745,-8794,
+-8844,-8894,-8944,-8994,-9043,-9093,-9143,-9193,
+-9243,-9292,-9342,-9392,-9442,-9491,-9541,-9591,
+-9640,-9690,-9740,-9790,-9839,-9889,-9939,-9988,
+-10038,-10088,-10137,-10187,-10237,-10286,-10336,-10386,
+-10435,-10485,-10534,-10584,-10634,-10683,-10733,-10782,
+-10832,-10882,-10931,-10981,-11030,-11080,-11129,-11179,
+-11228,-11278,-11327,-11377,-11426,-11476,-11525,-11575,
+-11624,-11674,-11723,-11773,-11822,-11872,-11921,-11970,
+-12020,-12069,-12119,-12168,-12218,-12267,-12316,-12366,
+-12415,-12464,-12514,-12563,-12612,-12662,-12711,-12760,
+-12810,-12859,-12908,-12957,-13007,-13056,-13105,-13154,
+-13204,-13253,-13302,-13351,-13401,-13450,-13499,-13548,
+-13597,-13647,-13696,-13745,-13794,-13843,-13892,-13941,
+-13990,-14040,-14089,-14138,-14187,-14236,-14285,-14334,
+-14383,-14432,-14481,-14530,-14579,-14628,-14677,-14726,
+-14775,-14824,-14873,-14922,-14971,-15020,-15069,-15118,
+-15167,-15215,-15264,-15313,-15362,-15411,-15460,-15509,
+-15557,-15606,-15655,-15704,-15753,-15802,-15850,-15899,
+-15948,-15997,-16045,-16094,-16143,-16191,-16240,-16289,
+-16338,-16386,-16435,-16484,-16532,-16581,-16629,-16678,
+-16727,-16775,-16824,-16872,-16921,-16970,-17018,-17067,
+-17115,-17164,-17212,-17261,-17309,-17358,-17406,-17455,
+-17503,-17551,-17600,-17648,-17697,-17745,-17793,-17842,
+-17890,-17939,-17987,-18035,-18084,-18132,-18180,-18228,
+-18277,-18325,-18373,-18421,-18470,-18518,-18566,-18614,
+-18663,-18711,-18759,-18807,-18855,-18903,-18951,-19000,
+-19048,-19096,-19144,-19192,-19240,-19288,-19336,-19384,
+-19432,-19480,-19528,-19576,-19624,-19672,-19720,-19768,
+-19816,-19864,-19912,-19959,-20007,-20055,-20103,-20151,
+-20199,-20246,-20294,-20342,-20390,-20438,-20485,-20533,
+-20581,-20629,-20676,-20724,-20772,-20819,-20867,-20915,
+-20962,-21010,-21057,-21105,-21153,-21200,-21248,-21295,
+-21343,-21390,-21438,-21485,-21533,-21580,-21628,-21675,
+-21723,-21770,-21817,-21865,-21912,-21960,-22007,-22054,
+-22102,-22149,-22196,-22243,-22291,-22338,-22385,-22433,
+-22480,-22527,-22574,-22621,-22668,-22716,-22763,-22810,
+-22857,-22904,-22951,-22998,-23045,-23092,-23139,-23186,
+-23233,-23280,-23327,-23374,-23421,-23468,-23515,-23562,
+-23609,-23656,-23703,-23750,-23796,-23843,-23890,-23937,
+-23984,-24030,-24077,-24124,-24171,-24217,-24264,-24311,
+-24357,-24404,-24451,-24497,-24544,-24591,-24637,-24684,
+-24730,-24777,-24823,-24870,-24916,-24963,-25009,-25056,
+-25102,-25149,-25195,-25241,-25288,-25334,-25381,-25427,
+-25473,-25520,-25566,-25612,-25658,-25705,-25751,-25797,
+-25843,-25889,-25936,-25982,-26028,-26074,-26120,-26166,
+-26212,-26258,-26304,-26350,-26396,-26442,-26488,-26534,
+-26580,-26626,-26672,-26718,-26764,-26810,-26856,-26902,
+-26947,-26993,-27039,-27085,-27131,-27176,-27222,-27268,
+-27313,-27359,-27405,-27450,-27496,-27542,-27587,-27633,
+-27678,-27724,-27770,-27815,-27861,-27906,-27952,-27997,
+-28042,-28088,-28133,-28179,-28224,-28269,-28315,-28360,
+-28405,-28451,-28496,-28541,-28586,-28632,-28677,-28722,
+-28767,-28812,-28858,-28903,-28948,-28993,-29038,-29083,
+-29128,-29173,-29218,-29263,-29308,-29353,-29398,-29443,
+-29488,-29533,-29577,-29622,-29667,-29712,-29757,-29801,
+-29846,-29891,-29936,-29980,-30025,-30070,-30114,-30159,
+-30204,-30248,-30293,-30337,-30382,-30426,-30471,-30515,
+-30560,-30604,-30649,-30693,-30738,-30782,-30826,-30871,
+-30915,-30959,-31004,-31048,-31092,-31136,-31181,-31225,
+-31269,-31313,-31357,-31402,-31446,-31490,-31534,-31578,
+-31622,-31666,-31710,-31754,-31798,-31842,-31886,-31930,
+-31974,-32017,-32061,-32105,-32149,-32193,-32236,-32280,
+-32324,-32368,-32411,-32455,-32499,-32542,-32586,-32630,
+-32673,-32717,-32760,-32804,-32847,-32891,-32934,-32978,
+-33021,-33065,-33108,-33151,-33195,-33238,-33281,-33325,
+-33368,-33411,-33454,-33498,-33541,-33584,-33627,-33670,
+-33713,-33756,-33799,-33843,-33886,-33929,-33972,-34015,
+-34057,-34100,-34143,-34186,-34229,-34272,-34315,-34358,
+-34400,-34443,-34486,-34529,-34571,-34614,-34657,-34699,
+-34742,-34785,-34827,-34870,-34912,-34955,-34997,-35040,
+-35082,-35125,-35167,-35210,-35252,-35294,-35337,-35379,
+-35421,-35464,-35506,-35548,-35590,-35633,-35675,-35717,
+-35759,-35801,-35843,-35885,-35927,-35969,-36011,-36053,
+-36095,-36137,-36179,-36221,-36263,-36305,-36347,-36388,
+-36430,-36472,-36514,-36555,-36597,-36639,-36681,-36722,
+-36764,-36805,-36847,-36889,-36930,-36972,-37013,-37055,
+-37096,-37137,-37179,-37220,-37262,-37303,-37344,-37386,
+-37427,-37468,-37509,-37551,-37592,-37633,-37674,-37715,
+-37756,-37797,-37838,-37879,-37920,-37961,-38002,-38043,
+-38084,-38125,-38166,-38207,-38248,-38288,-38329,-38370,
+-38411,-38451,-38492,-38533,-38573,-38614,-38655,-38695,
+-38736,-38776,-38817,-38857,-38898,-38938,-38979,-39019,
+-39059,-39100,-39140,-39180,-39221,-39261,-39301,-39341,
+-39382,-39422,-39462,-39502,-39542,-39582,-39622,-39662,
+-39702,-39742,-39782,-39822,-39862,-39902,-39942,-39982,
+-40021,-40061,-40101,-40141,-40180,-40220,-40260,-40299,
+-40339,-40379,-40418,-40458,-40497,-40537,-40576,-40616,
+-40655,-40695,-40734,-40773,-40813,-40852,-40891,-40931,
+-40970,-41009,-41048,-41087,-41127,-41166,-41205,-41244,
+-41283,-41322,-41361,-41400,-41439,-41478,-41517,-41556,
+-41595,-41633,-41672,-41711,-41750,-41788,-41827,-41866,
+-41904,-41943,-41982,-42020,-42059,-42097,-42136,-42174,
+-42213,-42251,-42290,-42328,-42366,-42405,-42443,-42481,
+-42520,-42558,-42596,-42634,-42672,-42711,-42749,-42787,
+-42825,-42863,-42901,-42939,-42977,-43015,-43053,-43091,
+-43128,-43166,-43204,-43242,-43280,-43317,-43355,-43393,
+-43430,-43468,-43506,-43543,-43581,-43618,-43656,-43693,
+-43731,-43768,-43806,-43843,-43880,-43918,-43955,-43992,
+-44029,-44067,-44104,-44141,-44178,-44215,-44252,-44289,
+-44326,-44363,-44400,-44437,-44474,-44511,-44548,-44585,
+-44622,-44659,-44695,-44732,-44769,-44806,-44842,-44879,
+-44915,-44952,-44989,-45025,-45062,-45098,-45135,-45171,
+-45207,-45244,-45280,-45316,-45353,-45389,-45425,-45462,
+-45498,-45534,-45570,-45606,-45642,-45678,-45714,-45750,
+-45786,-45822,-45858,-45894,-45930,-45966,-46002,-46037,
+-46073,-46109,-46145,-46180,-46216,-46252,-46287,-46323,
+-46358,-46394,-46429,-46465,-46500,-46536,-46571,-46606,
+-46642,-46677,-46712,-46747,-46783,-46818,-46853,-46888,
+-46923,-46958,-46993,-47028,-47063,-47098,-47133,-47168,
+-47203,-47238,-47273,-47308,-47342,-47377,-47412,-47446,
+-47481,-47516,-47550,-47585,-47619,-47654,-47688,-47723,
+-47757,-47792,-47826,-47860,-47895,-47929,-47963,-47998,
+-48032,-48066,-48100,-48134,-48168,-48202,-48236,-48271,
+-48304,-48338,-48372,-48406,-48440,-48474,-48508,-48542,
+-48575,-48609,-48643,-48676,-48710,-48744,-48777,-48811,
+-48844,-48878,-48911,-48945,-48978,-49012,-49045,-49078,
+-49112,-49145,-49178,-49211,-49244,-49278,-49311,-49344,
+-49377,-49410,-49443,-49476,-49509,-49542,-49575,-49608,
+-49640,-49673,-49706,-49739,-49771,-49804,-49837,-49869,
+-49902,-49935,-49967,-50000,-50032,-50065,-50097,-50129,
+-50162,-50194,-50226,-50259,-50291,-50323,-50355,-50387,
+-50420,-50452,-50484,-50516,-50548,-50580,-50612,-50644,
+-50675,-50707,-50739,-50771,-50803,-50834,-50866,-50898,
+-50929,-50961,-50993,-51024,-51056,-51087,-51119,-51150,
+-51182,-51213,-51244,-51276,-51307,-51338,-51369,-51401,
+-51432,-51463,-51494,-51525,-51556,-51587,-51618,-51649,
+-51680,-51711,-51742,-51773,-51803,-51834,-51865,-51896,
+-51926,-51957,-51988,-52018,-52049,-52079,-52110,-52140,
+-52171,-52201,-52231,-52262,-52292,-52322,-52353,-52383,
+-52413,-52443,-52473,-52503,-52534,-52564,-52594,-52624,
+-52653,-52683,-52713,-52743,-52773,-52803,-52832,-52862,
+-52892,-52922,-52951,-52981,-53010,-53040,-53069,-53099,
+-53128,-53158,-53187,-53216,-53246,-53275,-53304,-53334,
+-53363,-53392,-53421,-53450,-53479,-53508,-53537,-53566,
+-53595,-53624,-53653,-53682,-53711,-53739,-53768,-53797,
+-53826,-53854,-53883,-53911,-53940,-53969,-53997,-54026,
+-54054,-54082,-54111,-54139,-54167,-54196,-54224,-54252,
+-54280,-54308,-54337,-54365,-54393,-54421,-54449,-54477,
+-54505,-54533,-54560,-54588,-54616,-54644,-54672,-54699,
+-54727,-54755,-54782,-54810,-54837,-54865,-54892,-54920,
+-54947,-54974,-55002,-55029,-55056,-55084,-55111,-55138,
+-55165,-55192,-55219,-55246,-55274,-55300,-55327,-55354,
+-55381,-55408,-55435,-55462,-55489,-55515,-55542,-55569,
+-55595,-55622,-55648,-55675,-55701,-55728,-55754,-55781,
+-55807,-55833,-55860,-55886,-55912,-55938,-55965,-55991,
+-56017,-56043,-56069,-56095,-56121,-56147,-56173,-56199,
+-56225,-56250,-56276,-56302,-56328,-56353,-56379,-56404,
+-56430,-56456,-56481,-56507,-56532,-56557,-56583,-56608,
+-56633,-56659,-56684,-56709,-56734,-56760,-56785,-56810,
+-56835,-56860,-56885,-56910,-56935,-56959,-56984,-57009,
+-57034,-57059,-57083,-57108,-57133,-57157,-57182,-57206,
+-57231,-57255,-57280,-57304,-57329,-57353,-57377,-57402,
+-57426,-57450,-57474,-57498,-57522,-57546,-57570,-57594,
+-57618,-57642,-57666,-57690,-57714,-57738,-57762,-57785,
+-57809,-57833,-57856,-57880,-57903,-57927,-57950,-57974,
+-57997,-58021,-58044,-58067,-58091,-58114,-58137,-58160,
+-58183,-58207,-58230,-58253,-58276,-58299,-58322,-58345,
+-58367,-58390,-58413,-58436,-58459,-58481,-58504,-58527,
+-58549,-58572,-58594,-58617,-58639,-58662,-58684,-58706,
+-58729,-58751,-58773,-58795,-58818,-58840,-58862,-58884,
+-58906,-58928,-58950,-58972,-58994,-59016,-59038,-59059,
+-59081,-59103,-59125,-59146,-59168,-59190,-59211,-59233,
+-59254,-59276,-59297,-59318,-59340,-59361,-59382,-59404,
+-59425,-59446,-59467,-59488,-59509,-59530,-59551,-59572,
+-59593,-59614,-59635,-59656,-59677,-59697,-59718,-59739,
+-59759,-59780,-59801,-59821,-59842,-59862,-59883,-59903,
+-59923,-59944,-59964,-59984,-60004,-60025,-60045,-60065,
+-60085,-60105,-60125,-60145,-60165,-60185,-60205,-60225,
+-60244,-60264,-60284,-60304,-60323,-60343,-60363,-60382,
+-60402,-60421,-60441,-60460,-60479,-60499,-60518,-60537,
+-60556,-60576,-60595,-60614,-60633,-60652,-60671,-60690,
+-60709,-60728,-60747,-60766,-60785,-60803,-60822,-60841,
+-60859,-60878,-60897,-60915,-60934,-60952,-60971,-60989,
+-61007,-61026,-61044,-61062,-61081,-61099,-61117,-61135,
+-61153,-61171,-61189,-61207,-61225,-61243,-61261,-61279,
+-61297,-61314,-61332,-61350,-61367,-61385,-61403,-61420,
+-61438,-61455,-61473,-61490,-61507,-61525,-61542,-61559,
+-61577,-61594,-61611,-61628,-61645,-61662,-61679,-61696,
+-61713,-61730,-61747,-61764,-61780,-61797,-61814,-61831,
+-61847,-61864,-61880,-61897,-61913,-61930,-61946,-61963,
+-61979,-61995,-62012,-62028,-62044,-62060,-62076,-62092,
+-62108,-62125,-62141,-62156,-62172,-62188,-62204,-62220,
+-62236,-62251,-62267,-62283,-62298,-62314,-62329,-62345,
+-62360,-62376,-62391,-62407,-62422,-62437,-62453,-62468,
+-62483,-62498,-62513,-62528,-62543,-62558,-62573,-62588,
+-62603,-62618,-62633,-62648,-62662,-62677,-62692,-62706,
+-62721,-62735,-62750,-62764,-62779,-62793,-62808,-62822,
+-62836,-62850,-62865,-62879,-62893,-62907,-62921,-62935,
+-62949,-62963,-62977,-62991,-63005,-63019,-63032,-63046,
+-63060,-63074,-63087,-63101,-63114,-63128,-63141,-63155,
+-63168,-63182,-63195,-63208,-63221,-63235,-63248,-63261,
+-63274,-63287,-63300,-63313,-63326,-63339,-63352,-63365,
+-63378,-63390,-63403,-63416,-63429,-63441,-63454,-63466,
+-63479,-63491,-63504,-63516,-63528,-63541,-63553,-63565,
+-63578,-63590,-63602,-63614,-63626,-63638,-63650,-63662,
+-63674,-63686,-63698,-63709,-63721,-63733,-63745,-63756,
+-63768,-63779,-63791,-63803,-63814,-63825,-63837,-63848,
+-63859,-63871,-63882,-63893,-63904,-63915,-63927,-63938,
+-63949,-63960,-63971,-63981,-63992,-64003,-64014,-64025,
+-64035,-64046,-64057,-64067,-64078,-64088,-64099,-64109,
+-64120,-64130,-64140,-64151,-64161,-64171,-64181,-64192,
+-64202,-64212,-64222,-64232,-64242,-64252,-64261,-64271,
+-64281,-64291,-64301,-64310,-64320,-64330,-64339,-64349,
+-64358,-64368,-64377,-64387,-64396,-64405,-64414,-64424,
+-64433,-64442,-64451,-64460,-64469,-64478,-64487,-64496,
+-64505,-64514,-64523,-64532,-64540,-64549,-64558,-64566,
+-64575,-64584,-64592,-64601,-64609,-64617,-64626,-64634,
+-64642,-64651,-64659,-64667,-64675,-64683,-64691,-64699,
+-64707,-64715,-64723,-64731,-64739,-64747,-64754,-64762,
+-64770,-64777,-64785,-64793,-64800,-64808,-64815,-64822,
+-64830,-64837,-64844,-64852,-64859,-64866,-64873,-64880,
+-64887,-64895,-64902,-64908,-64915,-64922,-64929,-64936,
+-64943,-64949,-64956,-64963,-64969,-64976,-64982,-64989,
+-64995,-65002,-65008,-65015,-65021,-65027,-65033,-65040,
+-65046,-65052,-65058,-65064,-65070,-65076,-65082,-65088,
+-65094,-65099,-65105,-65111,-65117,-65122,-65128,-65133,
+-65139,-65144,-65150,-65155,-65161,-65166,-65171,-65177,
+-65182,-65187,-65192,-65197,-65202,-65207,-65212,-65217,
+-65222,-65227,-65232,-65237,-65242,-65246,-65251,-65256,
+-65260,-65265,-65270,-65274,-65279,-65283,-65287,-65292,
+-65296,-65300,-65305,-65309,-65313,-65317,-65321,-65325,
+-65329,-65333,-65337,-65341,-65345,-65349,-65352,-65356,
+-65360,-65363,-65367,-65371,-65374,-65378,-65381,-65385,
+-65388,-65391,-65395,-65398,-65401,-65404,-65408,-65411,
+-65414,-65417,-65420,-65423,-65426,-65429,-65431,-65434,
+-65437,-65440,-65442,-65445,-65448,-65450,-65453,-65455,
+-65458,-65460,-65463,-65465,-65467,-65470,-65472,-65474,
+-65476,-65478,-65480,-65482,-65484,-65486,-65488,-65490,
+-65492,-65494,-65496,-65497,-65499,-65501,-65502,-65504,
+-65505,-65507,-65508,-65510,-65511,-65513,-65514,-65515,
+-65516,-65518,-65519,-65520,-65521,-65522,-65523,-65524,
+-65525,-65526,-65527,-65527,-65528,-65529,-65530,-65530,
+-65531,-65531,-65532,-65532,-65533,-65533,-65534,-65534,
+-65534,-65535,-65535,-65535,-65535,-65535,-65535,-65535,
+-65535,-65535,-65535,-65535,-65535,-65535,-65535,-65534,
+-65534,-65534,-65533,-65533,-65532,-65532,-65531,-65531,
+-65530,-65530,-65529,-65528,-65527,-65527,-65526,-65525,
+-65524,-65523,-65522,-65521,-65520,-65519,-65518,-65516,
+-65515,-65514,-65513,-65511,-65510,-65508,-65507,-65505,
+-65504,-65502,-65501,-65499,-65497,-65496,-65494,-65492,
+-65490,-65488,-65486,-65484,-65482,-65480,-65478,-65476,
+-65474,-65472,-65470,-65467,-65465,-65463,-65460,-65458,
+-65455,-65453,-65450,-65448,-65445,-65442,-65440,-65437,
+-65434,-65431,-65429,-65426,-65423,-65420,-65417,-65414,
+-65411,-65408,-65404,-65401,-65398,-65395,-65391,-65388,
+-65385,-65381,-65378,-65374,-65371,-65367,-65363,-65360,
+-65356,-65352,-65349,-65345,-65341,-65337,-65333,-65329,
+-65325,-65321,-65317,-65313,-65309,-65305,-65300,-65296,
+-65292,-65287,-65283,-65279,-65274,-65270,-65265,-65260,
+-65256,-65251,-65246,-65242,-65237,-65232,-65227,-65222,
+-65217,-65212,-65207,-65202,-65197,-65192,-65187,-65182,
+-65177,-65171,-65166,-65161,-65155,-65150,-65144,-65139,
+-65133,-65128,-65122,-65117,-65111,-65105,-65099,-65094,
+-65088,-65082,-65076,-65070,-65064,-65058,-65052,-65046,
+-65040,-65033,-65027,-65021,-65015,-65008,-65002,-64995,
+-64989,-64982,-64976,-64969,-64963,-64956,-64949,-64943,
+-64936,-64929,-64922,-64915,-64908,-64902,-64895,-64887,
+-64880,-64873,-64866,-64859,-64852,-64844,-64837,-64830,
+-64822,-64815,-64808,-64800,-64793,-64785,-64777,-64770,
+-64762,-64754,-64747,-64739,-64731,-64723,-64715,-64707,
+-64699,-64691,-64683,-64675,-64667,-64659,-64651,-64642,
+-64634,-64626,-64617,-64609,-64601,-64592,-64584,-64575,
+-64566,-64558,-64549,-64540,-64532,-64523,-64514,-64505,
+-64496,-64487,-64478,-64469,-64460,-64451,-64442,-64433,
+-64424,-64414,-64405,-64396,-64387,-64377,-64368,-64358,
+-64349,-64339,-64330,-64320,-64310,-64301,-64291,-64281,
+-64271,-64261,-64252,-64242,-64232,-64222,-64212,-64202,
+-64192,-64181,-64171,-64161,-64151,-64140,-64130,-64120,
+-64109,-64099,-64088,-64078,-64067,-64057,-64046,-64035,
+-64025,-64014,-64003,-63992,-63981,-63971,-63960,-63949,
+-63938,-63927,-63915,-63904,-63893,-63882,-63871,-63859,
+-63848,-63837,-63825,-63814,-63803,-63791,-63779,-63768,
+-63756,-63745,-63733,-63721,-63709,-63698,-63686,-63674,
+-63662,-63650,-63638,-63626,-63614,-63602,-63590,-63578,
+-63565,-63553,-63541,-63528,-63516,-63504,-63491,-63479,
+-63466,-63454,-63441,-63429,-63416,-63403,-63390,-63378,
+-63365,-63352,-63339,-63326,-63313,-63300,-63287,-63274,
+-63261,-63248,-63235,-63221,-63208,-63195,-63182,-63168,
+-63155,-63141,-63128,-63114,-63101,-63087,-63074,-63060,
+-63046,-63032,-63019,-63005,-62991,-62977,-62963,-62949,
+-62935,-62921,-62907,-62893,-62879,-62865,-62850,-62836,
+-62822,-62808,-62793,-62779,-62764,-62750,-62735,-62721,
+-62706,-62692,-62677,-62662,-62648,-62633,-62618,-62603,
+-62588,-62573,-62558,-62543,-62528,-62513,-62498,-62483,
+-62468,-62453,-62437,-62422,-62407,-62391,-62376,-62360,
+-62345,-62329,-62314,-62298,-62283,-62267,-62251,-62236,
+-62220,-62204,-62188,-62172,-62156,-62141,-62125,-62108,
+-62092,-62076,-62060,-62044,-62028,-62012,-61995,-61979,
+-61963,-61946,-61930,-61913,-61897,-61880,-61864,-61847,
+-61831,-61814,-61797,-61780,-61764,-61747,-61730,-61713,
+-61696,-61679,-61662,-61645,-61628,-61611,-61594,-61577,
+-61559,-61542,-61525,-61507,-61490,-61473,-61455,-61438,
+-61420,-61403,-61385,-61367,-61350,-61332,-61314,-61297,
+-61279,-61261,-61243,-61225,-61207,-61189,-61171,-61153,
+-61135,-61117,-61099,-61081,-61062,-61044,-61026,-61007,
+-60989,-60971,-60952,-60934,-60915,-60897,-60878,-60859,
+-60841,-60822,-60803,-60785,-60766,-60747,-60728,-60709,
+-60690,-60671,-60652,-60633,-60614,-60595,-60576,-60556,
+-60537,-60518,-60499,-60479,-60460,-60441,-60421,-60402,
+-60382,-60363,-60343,-60323,-60304,-60284,-60264,-60244,
+-60225,-60205,-60185,-60165,-60145,-60125,-60105,-60085,
+-60065,-60045,-60025,-60004,-59984,-59964,-59944,-59923,
+-59903,-59883,-59862,-59842,-59821,-59801,-59780,-59759,
+-59739,-59718,-59697,-59677,-59656,-59635,-59614,-59593,
+-59572,-59551,-59530,-59509,-59488,-59467,-59446,-59425,
+-59404,-59382,-59361,-59340,-59318,-59297,-59276,-59254,
+-59233,-59211,-59189,-59168,-59146,-59125,-59103,-59081,
+-59059,-59038,-59016,-58994,-58972,-58950,-58928,-58906,
+-58884,-58862,-58840,-58818,-58795,-58773,-58751,-58729,
+-58706,-58684,-58662,-58639,-58617,-58594,-58572,-58549,
+-58527,-58504,-58481,-58459,-58436,-58413,-58390,-58367,
+-58345,-58322,-58299,-58276,-58253,-58230,-58207,-58183,
+-58160,-58137,-58114,-58091,-58067,-58044,-58021,-57997,
+-57974,-57950,-57927,-57903,-57880,-57856,-57833,-57809,
+-57785,-57762,-57738,-57714,-57690,-57666,-57642,-57618,
+-57594,-57570,-57546,-57522,-57498,-57474,-57450,-57426,
+-57402,-57377,-57353,-57329,-57304,-57280,-57255,-57231,
+-57206,-57182,-57157,-57133,-57108,-57083,-57059,-57034,
+-57009,-56984,-56959,-56935,-56910,-56885,-56860,-56835,
+-56810,-56785,-56760,-56734,-56709,-56684,-56659,-56633,
+-56608,-56583,-56557,-56532,-56507,-56481,-56456,-56430,
+-56404,-56379,-56353,-56328,-56302,-56276,-56250,-56225,
+-56199,-56173,-56147,-56121,-56095,-56069,-56043,-56017,
+-55991,-55965,-55938,-55912,-55886,-55860,-55833,-55807,
+-55781,-55754,-55728,-55701,-55675,-55648,-55622,-55595,
+-55569,-55542,-55515,-55489,-55462,-55435,-55408,-55381,
+-55354,-55327,-55300,-55274,-55246,-55219,-55192,-55165,
+-55138,-55111,-55084,-55056,-55029,-55002,-54974,-54947,
+-54920,-54892,-54865,-54837,-54810,-54782,-54755,-54727,
+-54699,-54672,-54644,-54616,-54588,-54560,-54533,-54505,
+-54477,-54449,-54421,-54393,-54365,-54337,-54308,-54280,
+-54252,-54224,-54196,-54167,-54139,-54111,-54082,-54054,
+-54026,-53997,-53969,-53940,-53911,-53883,-53854,-53826,
+-53797,-53768,-53739,-53711,-53682,-53653,-53624,-53595,
+-53566,-53537,-53508,-53479,-53450,-53421,-53392,-53363,
+-53334,-53304,-53275,-53246,-53216,-53187,-53158,-53128,
+-53099,-53069,-53040,-53010,-52981,-52951,-52922,-52892,
+-52862,-52832,-52803,-52773,-52743,-52713,-52683,-52653,
+-52624,-52594,-52564,-52534,-52503,-52473,-52443,-52413,
+-52383,-52353,-52322,-52292,-52262,-52231,-52201,-52171,
+-52140,-52110,-52079,-52049,-52018,-51988,-51957,-51926,
+-51896,-51865,-51834,-51803,-51773,-51742,-51711,-51680,
+-51649,-51618,-51587,-51556,-51525,-51494,-51463,-51432,
+-51401,-51369,-51338,-51307,-51276,-51244,-51213,-51182,
+-51150,-51119,-51087,-51056,-51024,-50993,-50961,-50929,
+-50898,-50866,-50834,-50803,-50771,-50739,-50707,-50675,
+-50644,-50612,-50580,-50548,-50516,-50484,-50452,-50420,
+-50387,-50355,-50323,-50291,-50259,-50226,-50194,-50162,
+-50129,-50097,-50065,-50032,-50000,-49967,-49935,-49902,
+-49869,-49837,-49804,-49771,-49739,-49706,-49673,-49640,
+-49608,-49575,-49542,-49509,-49476,-49443,-49410,-49377,
+-49344,-49311,-49278,-49244,-49211,-49178,-49145,-49112,
+-49078,-49045,-49012,-48978,-48945,-48911,-48878,-48844,
+-48811,-48777,-48744,-48710,-48676,-48643,-48609,-48575,
+-48542,-48508,-48474,-48440,-48406,-48372,-48338,-48305,
+-48271,-48237,-48202,-48168,-48134,-48100,-48066,-48032,
+-47998,-47963,-47929,-47895,-47860,-47826,-47792,-47757,
+-47723,-47688,-47654,-47619,-47585,-47550,-47516,-47481,
+-47446,-47412,-47377,-47342,-47307,-47273,-47238,-47203,
+-47168,-47133,-47098,-47063,-47028,-46993,-46958,-46923,
+-46888,-46853,-46818,-46783,-46747,-46712,-46677,-46642,
+-46606,-46571,-46536,-46500,-46465,-46429,-46394,-46358,
+-46323,-46287,-46251,-46216,-46180,-46145,-46109,-46073,
+-46037,-46002,-45966,-45930,-45894,-45858,-45822,-45786,
+-45750,-45714,-45678,-45642,-45606,-45570,-45534,-45498,
+-45462,-45425,-45389,-45353,-45316,-45280,-45244,-45207,
+-45171,-45135,-45098,-45062,-45025,-44989,-44952,-44915,
+-44879,-44842,-44806,-44769,-44732,-44695,-44659,-44622,
+-44585,-44548,-44511,-44474,-44437,-44400,-44363,-44326,
+-44289,-44252,-44215,-44178,-44141,-44104,-44067,-44029,
+-43992,-43955,-43918,-43880,-43843,-43806,-43768,-43731,
+-43693,-43656,-43618,-43581,-43543,-43506,-43468,-43430,
+-43393,-43355,-43317,-43280,-43242,-43204,-43166,-43128,
+-43091,-43053,-43015,-42977,-42939,-42901,-42863,-42825,
+-42787,-42749,-42711,-42672,-42634,-42596,-42558,-42520,
+-42481,-42443,-42405,-42366,-42328,-42290,-42251,-42213,
+-42174,-42136,-42097,-42059,-42020,-41982,-41943,-41904,
+-41866,-41827,-41788,-41750,-41711,-41672,-41633,-41595,
+-41556,-41517,-41478,-41439,-41400,-41361,-41322,-41283,
+-41244,-41205,-41166,-41127,-41087,-41048,-41009,-40970,
+-40931,-40891,-40852,-40813,-40773,-40734,-40695,-40655,
+-40616,-40576,-40537,-40497,-40458,-40418,-40379,-40339,
+-40299,-40260,-40220,-40180,-40141,-40101,-40061,-40021,
+-39982,-39942,-39902,-39862,-39822,-39782,-39742,-39702,
+-39662,-39622,-39582,-39542,-39502,-39462,-39422,-39382,
+-39341,-39301,-39261,-39221,-39180,-39140,-39100,-39059,
+-39019,-38979,-38938,-38898,-38857,-38817,-38776,-38736,
+-38695,-38655,-38614,-38573,-38533,-38492,-38451,-38411,
+-38370,-38329,-38288,-38248,-38207,-38166,-38125,-38084,
+-38043,-38002,-37961,-37920,-37879,-37838,-37797,-37756,
+-37715,-37674,-37633,-37592,-37550,-37509,-37468,-37427,
+-37386,-37344,-37303,-37262,-37220,-37179,-37137,-37096,
+-37055,-37013,-36972,-36930,-36889,-36847,-36805,-36764,
+-36722,-36681,-36639,-36597,-36556,-36514,-36472,-36430,
+-36388,-36347,-36305,-36263,-36221,-36179,-36137,-36095,
+-36053,-36011,-35969,-35927,-35885,-35843,-35801,-35759,
+-35717,-35675,-35633,-35590,-35548,-35506,-35464,-35421,
+-35379,-35337,-35294,-35252,-35210,-35167,-35125,-35082,
+-35040,-34997,-34955,-34912,-34870,-34827,-34785,-34742,
+-34699,-34657,-34614,-34571,-34529,-34486,-34443,-34400,
+-34358,-34315,-34272,-34229,-34186,-34143,-34100,-34057,
+-34015,-33972,-33929,-33886,-33843,-33799,-33756,-33713,
+-33670,-33627,-33584,-33541,-33498,-33454,-33411,-33368,
+-33325,-33281,-33238,-33195,-33151,-33108,-33065,-33021,
+-32978,-32934,-32891,-32847,-32804,-32760,-32717,-32673,
+-32630,-32586,-32542,-32499,-32455,-32411,-32368,-32324,
+-32280,-32236,-32193,-32149,-32105,-32061,-32017,-31974,
+-31930,-31886,-31842,-31798,-31754,-31710,-31666,-31622,
+-31578,-31534,-31490,-31446,-31402,-31357,-31313,-31269,
+-31225,-31181,-31136,-31092,-31048,-31004,-30959,-30915,
+-30871,-30826,-30782,-30738,-30693,-30649,-30604,-30560,
+-30515,-30471,-30426,-30382,-30337,-30293,-30248,-30204,
+-30159,-30114,-30070,-30025,-29980,-29936,-29891,-29846,
+-29801,-29757,-29712,-29667,-29622,-29577,-29533,-29488,
+-29443,-29398,-29353,-29308,-29263,-29218,-29173,-29128,
+-29083,-29038,-28993,-28948,-28903,-28858,-28812,-28767,
+-28722,-28677,-28632,-28586,-28541,-28496,-28451,-28405,
+-28360,-28315,-28269,-28224,-28179,-28133,-28088,-28042,
+-27997,-27952,-27906,-27861,-27815,-27770,-27724,-27678,
+-27633,-27587,-27542,-27496,-27450,-27405,-27359,-27313,
+-27268,-27222,-27176,-27131,-27085,-27039,-26993,-26947,
+-26902,-26856,-26810,-26764,-26718,-26672,-26626,-26580,
+-26534,-26488,-26442,-26396,-26350,-26304,-26258,-26212,
+-26166,-26120,-26074,-26028,-25982,-25936,-25889,-25843,
+-25797,-25751,-25705,-25658,-25612,-25566,-25520,-25473,
+-25427,-25381,-25334,-25288,-25241,-25195,-25149,-25102,
+-25056,-25009,-24963,-24916,-24870,-24823,-24777,-24730,
+-24684,-24637,-24591,-24544,-24497,-24451,-24404,-24357,
+-24311,-24264,-24217,-24171,-24124,-24077,-24030,-23984,
+-23937,-23890,-23843,-23796,-23750,-23703,-23656,-23609,
+-23562,-23515,-23468,-23421,-23374,-23327,-23280,-23233,
+-23186,-23139,-23092,-23045,-22998,-22951,-22904,-22857,
+-22810,-22763,-22716,-22668,-22621,-22574,-22527,-22480,
+-22432,-22385,-22338,-22291,-22243,-22196,-22149,-22102,
+-22054,-22007,-21960,-21912,-21865,-21817,-21770,-21723,
+-21675,-21628,-21580,-21533,-21485,-21438,-21390,-21343,
+-21295,-21248,-21200,-21153,-21105,-21057,-21010,-20962,
+-20915,-20867,-20819,-20772,-20724,-20676,-20629,-20581,
+-20533,-20485,-20438,-20390,-20342,-20294,-20246,-20199,
+-20151,-20103,-20055,-20007,-19959,-19912,-19864,-19816,
+-19768,-19720,-19672,-19624,-19576,-19528,-19480,-19432,
+-19384,-19336,-19288,-19240,-19192,-19144,-19096,-19048,
+-19000,-18951,-18903,-18855,-18807,-18759,-18711,-18663,
+-18614,-18566,-18518,-18470,-18421,-18373,-18325,-18277,
+-18228,-18180,-18132,-18084,-18035,-17987,-17939,-17890,
+-17842,-17793,-17745,-17697,-17648,-17600,-17551,-17503,
+-17455,-17406,-17358,-17309,-17261,-17212,-17164,-17115,
+-17067,-17018,-16970,-16921,-16872,-16824,-16775,-16727,
+-16678,-16629,-16581,-16532,-16484,-16435,-16386,-16338,
+-16289,-16240,-16191,-16143,-16094,-16045,-15997,-15948,
+-15899,-15850,-15802,-15753,-15704,-15655,-15606,-15557,
+-15509,-15460,-15411,-15362,-15313,-15264,-15215,-15167,
+-15118,-15069,-15020,-14971,-14922,-14873,-14824,-14775,
+-14726,-14677,-14628,-14579,-14530,-14481,-14432,-14383,
+-14334,-14285,-14236,-14187,-14138,-14089,-14040,-13990,
+-13941,-13892,-13843,-13794,-13745,-13696,-13647,-13597,
+-13548,-13499,-13450,-13401,-13351,-13302,-13253,-13204,
+-13154,-13105,-13056,-13007,-12957,-12908,-12859,-12810,
+-12760,-12711,-12662,-12612,-12563,-12514,-12464,-12415,
+-12366,-12316,-12267,-12217,-12168,-12119,-12069,-12020,
+-11970,-11921,-11872,-11822,-11773,-11723,-11674,-11624,
+-11575,-11525,-11476,-11426,-11377,-11327,-11278,-11228,
+-11179,-11129,-11080,-11030,-10981,-10931,-10882,-10832,
+-10782,-10733,-10683,-10634,-10584,-10534,-10485,-10435,
+-10386,-10336,-10286,-10237,-10187,-10137,-10088,-10038,
+-9988,-9939,-9889,-9839,-9790,-9740,-9690,-9640,
+-9591,-9541,-9491,-9442,-9392,-9342,-9292,-9243,
+-9193,-9143,-9093,-9043,-8994,-8944,-8894,-8844,
+-8794,-8745,-8695,-8645,-8595,-8545,-8496,-8446,
+-8396,-8346,-8296,-8246,-8196,-8147,-8097,-8047,
+-7997,-7947,-7897,-7847,-7797,-7747,-7697,-7648,
+-7598,-7548,-7498,-7448,-7398,-7348,-7298,-7248,
+-7198,-7148,-7098,-7048,-6998,-6948,-6898,-6848,
+-6798,-6748,-6698,-6648,-6598,-6548,-6498,-6448,
+-6398,-6348,-6298,-6248,-6198,-6148,-6098,-6048,
+-5998,-5948,-5898,-5848,-5798,-5747,-5697,-5647,
+-5597,-5547,-5497,-5447,-5397,-5347,-5297,-5247,
+-5197,-5146,-5096,-5046,-4996,-4946,-4896,-4846,
+-4796,-4745,-4695,-4645,-4595,-4545,-4495,-4445,
+-4394,-4344,-4294,-4244,-4194,-4144,-4093,-4043,
+-3993,-3943,-3893,-3843,-3792,-3742,-3692,-3642,
+-3592,-3541,-3491,-3441,-3391,-3341,-3291,-3240,
+-3190,-3140,-3090,-3039,-2989,-2939,-2889,-2839,
+-2788,-2738,-2688,-2638,-2588,-2537,-2487,-2437,
+-2387,-2336,-2286,-2236,-2186,-2135,-2085,-2035,
+-1985,-1934,-1884,-1834,-1784,-1733,-1683,-1633,
+-1583,-1532,-1482,-1432,-1382,-1331,-1281,-1231,
+-1181,-1130,-1080,-1030,-980,-929,-879,-829,
+-779,-728,-678,-628,-578,-527,-477,-427,
+-376,-326,-276,-226,-175,-125,-75,-25,
+25,75,125,175,226,276,326,376,
+427,477,527,578,628,678,728,779,
+829,879,929,980,1030,1080,1130,1181,
+1231,1281,1331,1382,1432,1482,1532,1583,
+1633,1683,1733,1784,1834,1884,1934,1985,
+2035,2085,2135,2186,2236,2286,2336,2387,
+2437,2487,2537,2587,2638,2688,2738,2788,
+2839,2889,2939,2989,3039,3090,3140,3190,
+3240,3291,3341,3391,3441,3491,3542,3592,
+3642,3692,3742,3792,3843,3893,3943,3993,
+4043,4093,4144,4194,4244,4294,4344,4394,
+4445,4495,4545,4595,4645,4695,4745,4796,
+4846,4896,4946,4996,5046,5096,5146,5197,
+5247,5297,5347,5397,5447,5497,5547,5597,
+5647,5697,5747,5798,5848,5898,5948,5998,
+6048,6098,6148,6198,6248,6298,6348,6398,
+6448,6498,6548,6598,6648,6698,6748,6798,
+6848,6898,6948,6998,7048,7098,7148,7198,
+7248,7298,7348,7398,7448,7498,7548,7598,
+7648,7697,7747,7797,7847,7897,7947,7997,
+8047,8097,8147,8196,8246,8296,8346,8396,
+8446,8496,8545,8595,8645,8695,8745,8794,
+8844,8894,8944,8994,9043,9093,9143,9193,
+9243,9292,9342,9392,9442,9491,9541,9591,
+9640,9690,9740,9790,9839,9889,9939,9988,
+10038,10088,10137,10187,10237,10286,10336,10386,
+10435,10485,10534,10584,10634,10683,10733,10782,
+10832,10882,10931,10981,11030,11080,11129,11179,
+11228,11278,11327,11377,11426,11476,11525,11575,
+11624,11674,11723,11773,11822,11872,11921,11970,
+12020,12069,12119,12168,12218,12267,12316,12366,
+12415,12464,12514,12563,12612,12662,12711,12760,
+12810,12859,12908,12957,13007,13056,13105,13154,
+13204,13253,13302,13351,13401,13450,13499,13548,
+13597,13647,13696,13745,13794,13843,13892,13941,
+13990,14040,14089,14138,14187,14236,14285,14334,
+14383,14432,14481,14530,14579,14628,14677,14726,
+14775,14824,14873,14922,14971,15020,15069,15118,
+15167,15215,15264,15313,15362,15411,15460,15509,
+15557,15606,15655,15704,15753,15802,15850,15899,
+15948,15997,16045,16094,16143,16191,16240,16289,
+16338,16386,16435,16484,16532,16581,16629,16678,
+16727,16775,16824,16872,16921,16970,17018,17067,
+17115,17164,17212,17261,17309,17358,17406,17455,
+17503,17551,17600,17648,17697,17745,17793,17842,
+17890,17939,17987,18035,18084,18132,18180,18228,
+18277,18325,18373,18421,18470,18518,18566,18614,
+18663,18711,18759,18807,18855,18903,18951,19000,
+19048,19096,19144,19192,19240,19288,19336,19384,
+19432,19480,19528,19576,19624,19672,19720,19768,
+19816,19864,19912,19959,20007,20055,20103,20151,
+20199,20246,20294,20342,20390,20438,20485,20533,
+20581,20629,20676,20724,20772,20819,20867,20915,
+20962,21010,21057,21105,21153,21200,21248,21295,
+21343,21390,21438,21485,21533,21580,21628,21675,
+21723,21770,21817,21865,21912,21960,22007,22054,
+22102,22149,22196,22243,22291,22338,22385,22432,
+22480,22527,22574,22621,22668,22716,22763,22810,
+22857,22904,22951,22998,23045,23092,23139,23186,
+23233,23280,23327,23374,23421,23468,23515,23562,
+23609,23656,23703,23750,23796,23843,23890,23937,
+23984,24030,24077,24124,24171,24217,24264,24311,
+24357,24404,24451,24497,24544,24591,24637,24684,
+24730,24777,24823,24870,24916,24963,25009,25056,
+25102,25149,25195,25241,25288,25334,25381,25427,
+25473,25520,25566,25612,25658,25705,25751,25797,
+25843,25889,25936,25982,26028,26074,26120,26166,
+26212,26258,26304,26350,26396,26442,26488,26534,
+26580,26626,26672,26718,26764,26810,26856,26902,
+26947,26993,27039,27085,27131,27176,27222,27268,
+27313,27359,27405,27450,27496,27542,27587,27633,
+27678,27724,27770,27815,27861,27906,27952,27997,
+28042,28088,28133,28179,28224,28269,28315,28360,
+28405,28451,28496,28541,28586,28632,28677,28722,
+28767,28812,28858,28903,28948,28993,29038,29083,
+29128,29173,29218,29263,29308,29353,29398,29443,
+29488,29533,29577,29622,29667,29712,29757,29801,
+29846,29891,29936,29980,30025,30070,30114,30159,
+30204,30248,30293,30337,30382,30427,30471,30516,
+30560,30604,30649,30693,30738,30782,30826,30871,
+30915,30959,31004,31048,31092,31136,31181,31225,
+31269,31313,31357,31402,31446,31490,31534,31578,
+31622,31666,31710,31754,31798,31842,31886,31930,
+31974,32017,32061,32105,32149,32193,32236,32280,
+32324,32368,32411,32455,32499,32542,32586,32630,
+32673,32717,32760,32804,32847,32891,32934,32978,
+33021,33065,33108,33151,33195,33238,33281,33325,
+33368,33411,33454,33498,33541,33584,33627,33670,
+33713,33756,33799,33843,33886,33929,33972,34015,
+34057,34100,34143,34186,34229,34272,34315,34358,
+34400,34443,34486,34529,34571,34614,34657,34699,
+34742,34785,34827,34870,34912,34955,34997,35040,
+35082,35125,35167,35210,35252,35294,35337,35379,
+35421,35464,35506,35548,35590,35633,35675,35717,
+35759,35801,35843,35885,35927,35969,36011,36053,
+36095,36137,36179,36221,36263,36305,36347,36388,
+36430,36472,36514,36556,36597,36639,36681,36722,
+36764,36805,36847,36889,36930,36972,37013,37055,
+37096,37137,37179,37220,37262,37303,37344,37386,
+37427,37468,37509,37551,37592,37633,37674,37715,
+37756,37797,37838,37879,37920,37961,38002,38043,
+38084,38125,38166,38207,38248,38288,38329,38370,
+38411,38451,38492,38533,38573,38614,38655,38695,
+38736,38776,38817,38857,38898,38938,38979,39019,
+39059,39100,39140,39180,39221,39261,39301,39341,
+39382,39422,39462,39502,39542,39582,39622,39662,
+39702,39742,39782,39822,39862,39902,39942,39982,
+40021,40061,40101,40141,40180,40220,40260,40299,
+40339,40379,40418,40458,40497,40537,40576,40616,
+40655,40695,40734,40773,40813,40852,40891,40931,
+40970,41009,41048,41087,41127,41166,41205,41244,
+41283,41322,41361,41400,41439,41478,41517,41556,
+41595,41633,41672,41711,41750,41788,41827,41866,
+41904,41943,41982,42020,42059,42097,42136,42174,
+42213,42251,42290,42328,42366,42405,42443,42481,
+42520,42558,42596,42634,42672,42711,42749,42787,
+42825,42863,42901,42939,42977,43015,43053,43091,
+43128,43166,43204,43242,43280,43317,43355,43393,
+43430,43468,43506,43543,43581,43618,43656,43693,
+43731,43768,43806,43843,43880,43918,43955,43992,
+44029,44067,44104,44141,44178,44215,44252,44289,
+44326,44363,44400,44437,44474,44511,44548,44585,
+44622,44659,44695,44732,44769,44806,44842,44879,
+44915,44952,44989,45025,45062,45098,45135,45171,
+45207,45244,45280,45316,45353,45389,45425,45462,
+45498,45534,45570,45606,45642,45678,45714,45750,
+45786,45822,45858,45894,45930,45966,46002,46037,
+46073,46109,46145,46180,46216,46252,46287,46323,
+46358,46394,46429,46465,46500,46536,46571,46606,
+46642,46677,46712,46747,46783,46818,46853,46888,
+46923,46958,46993,47028,47063,47098,47133,47168,
+47203,47238,47273,47308,47342,47377,47412,47446,
+47481,47516,47550,47585,47619,47654,47688,47723,
+47757,47792,47826,47861,47895,47929,47963,47998,
+48032,48066,48100,48134,48168,48202,48237,48271,
+48305,48338,48372,48406,48440,48474,48508,48542,
+48575,48609,48643,48676,48710,48744,48777,48811,
+48844,48878,48911,48945,48978,49012,49045,49078,
+49112,49145,49178,49211,49244,49278,49311,49344,
+49377,49410,49443,49476,49509,49542,49575,49608,
+49640,49673,49706,49739,49771,49804,49837,49869,
+49902,49935,49967,50000,50032,50064,50097,50129,
+50162,50194,50226,50259,50291,50323,50355,50387,
+50420,50452,50484,50516,50548,50580,50612,50644,
+50675,50707,50739,50771,50803,50834,50866,50898,
+50929,50961,50993,51024,51056,51087,51119,51150,
+51182,51213,51244,51276,51307,51338,51369,51401,
+51432,51463,51494,51525,51556,51587,51618,51649,
+51680,51711,51742,51773,51803,51834,51865,51896,
+51926,51957,51988,52018,52049,52079,52110,52140,
+52171,52201,52231,52262,52292,52322,52353,52383,
+52413,52443,52473,52503,52534,52564,52594,52624,
+52653,52683,52713,52743,52773,52803,52832,52862,
+52892,52922,52951,52981,53010,53040,53069,53099,
+53128,53158,53187,53216,53246,53275,53304,53334,
+53363,53392,53421,53450,53479,53508,53537,53566,
+53595,53624,53653,53682,53711,53739,53768,53797,
+53826,53854,53883,53912,53940,53969,53997,54026,
+54054,54082,54111,54139,54167,54196,54224,54252,
+54280,54309,54337,54365,54393,54421,54449,54477,
+54505,54533,54560,54588,54616,54644,54672,54699,
+54727,54755,54782,54810,54837,54865,54892,54920,
+54947,54974,55002,55029,55056,55084,55111,55138,
+55165,55192,55219,55246,55274,55300,55327,55354,
+55381,55408,55435,55462,55489,55515,55542,55569,
+55595,55622,55648,55675,55701,55728,55754,55781,
+55807,55833,55860,55886,55912,55938,55965,55991,
+56017,56043,56069,56095,56121,56147,56173,56199,
+56225,56250,56276,56302,56328,56353,56379,56404,
+56430,56456,56481,56507,56532,56557,56583,56608,
+56633,56659,56684,56709,56734,56760,56785,56810,
+56835,56860,56885,56910,56935,56959,56984,57009,
+57034,57059,57083,57108,57133,57157,57182,57206,
+57231,57255,57280,57304,57329,57353,57377,57402,
+57426,57450,57474,57498,57522,57546,57570,57594,
+57618,57642,57666,57690,57714,57738,57762,57785,
+57809,57833,57856,57880,57903,57927,57950,57974,
+57997,58021,58044,58067,58091,58114,58137,58160,
+58183,58207,58230,58253,58276,58299,58322,58345,
+58367,58390,58413,58436,58459,58481,58504,58527,
+58549,58572,58594,58617,58639,58662,58684,58706,
+58729,58751,58773,58795,58818,58840,58862,58884,
+58906,58928,58950,58972,58994,59016,59038,59059,
+59081,59103,59125,59146,59168,59190,59211,59233,
+59254,59276,59297,59318,59340,59361,59382,59404,
+59425,59446,59467,59488,59509,59530,59551,59572,
+59593,59614,59635,59656,59677,59697,59718,59739,
+59759,59780,59801,59821,59842,59862,59883,59903,
+59923,59944,59964,59984,60004,60025,60045,60065,
+60085,60105,60125,60145,60165,60185,60205,60225,
+60244,60264,60284,60304,60323,60343,60363,60382,
+60402,60421,60441,60460,60479,60499,60518,60537,
+60556,60576,60595,60614,60633,60652,60671,60690,
+60709,60728,60747,60766,60785,60803,60822,60841,
+60859,60878,60897,60915,60934,60952,60971,60989,
+61007,61026,61044,61062,61081,61099,61117,61135,
+61153,61171,61189,61207,61225,61243,61261,61279,
+61297,61314,61332,61350,61367,61385,61403,61420,
+61438,61455,61473,61490,61507,61525,61542,61559,
+61577,61594,61611,61628,61645,61662,61679,61696,
+61713,61730,61747,61764,61780,61797,61814,61831,
+61847,61864,61880,61897,61913,61930,61946,61963,
+61979,61995,62012,62028,62044,62060,62076,62092,
+62108,62125,62141,62156,62172,62188,62204,62220,
+62236,62251,62267,62283,62298,62314,62329,62345,
+62360,62376,62391,62407,62422,62437,62453,62468,
+62483,62498,62513,62528,62543,62558,62573,62588,
+62603,62618,62633,62648,62662,62677,62692,62706,
+62721,62735,62750,62764,62779,62793,62808,62822,
+62836,62850,62865,62879,62893,62907,62921,62935,
+62949,62963,62977,62991,63005,63019,63032,63046,
+63060,63074,63087,63101,63114,63128,63141,63155,
+63168,63182,63195,63208,63221,63235,63248,63261,
+63274,63287,63300,63313,63326,63339,63352,63365,
+63378,63390,63403,63416,63429,63441,63454,63466,
+63479,63491,63504,63516,63528,63541,63553,63565,
+63578,63590,63602,63614,63626,63638,63650,63662,
+63674,63686,63698,63709,63721,63733,63745,63756,
+63768,63779,63791,63803,63814,63825,63837,63848,
+63859,63871,63882,63893,63904,63915,63927,63938,
+63949,63960,63971,63981,63992,64003,64014,64025,
+64035,64046,64057,64067,64078,64088,64099,64109,
+64120,64130,64140,64151,64161,64171,64181,64192,
+64202,64212,64222,64232,64242,64252,64261,64271,
+64281,64291,64301,64310,64320,64330,64339,64349,
+64358,64368,64377,64387,64396,64405,64414,64424,
+64433,64442,64451,64460,64469,64478,64487,64496,
+64505,64514,64523,64532,64540,64549,64558,64566,
+64575,64584,64592,64600,64609,64617,64626,64634,
+64642,64651,64659,64667,64675,64683,64691,64699,
+64707,64715,64723,64731,64739,64747,64754,64762,
+64770,64777,64785,64793,64800,64808,64815,64822,
+64830,64837,64844,64852,64859,64866,64873,64880,
+64887,64895,64902,64908,64915,64922,64929,64936,
+64943,64949,64956,64963,64969,64976,64982,64989,
+64995,65002,65008,65015,65021,65027,65033,65040,
+65046,65052,65058,65064,65070,65076,65082,65088,
+65094,65099,65105,65111,65117,65122,65128,65133,
+65139,65144,65150,65155,65161,65166,65171,65177,
+65182,65187,65192,65197,65202,65207,65212,65217,
+65222,65227,65232,65237,65242,65246,65251,65256,
+65260,65265,65270,65274,65279,65283,65287,65292,
+65296,65300,65305,65309,65313,65317,65321,65325,
+65329,65333,65337,65341,65345,65349,65352,65356,
+65360,65363,65367,65371,65374,65378,65381,65385,
+65388,65391,65395,65398,65401,65404,65408,65411,
+65414,65417,65420,65423,65426,65429,65431,65434,
+65437,65440,65442,65445,65448,65450,65453,65455,
+65458,65460,65463,65465,65467,65470,65472,65474,
+65476,65478,65480,65482,65484,65486,65488,65490,
+65492,65494,65496,65497,65499,65501,65502,65504,
+65505,65507,65508,65510,65511,65513,65514,65515,
+65516,65518,65519,65520,65521,65522,65523,65524,
+65525,65526,65527,65527,65528,65529,65530,65530,
+65531,65531,65532,65532,65533,65533,65534,65534,
+65534,65535,65535,65535,65535,65535,65535,65535
+};
+
+int tantoangle[2049] =
+{
+0,333772,667544,1001315,1335086,1668857,2002626,2336395,
+2670163,3003929,3337694,3671457,4005219,4338979,4672736,5006492,
+5340245,5673995,6007743,6341488,6675230,7008968,7342704,7676435,
+8010164,8343888,8677609,9011325,9345037,9678744,10012447,10346145,
+10679838,11013526,11347209,11680887,12014558,12348225,12681885,13015539,
+13349187,13682829,14016464,14350092,14683714,15017328,15350936,15684536,
+16018129,16351714,16685291,17018860,17352422,17685974,18019518,18353054,
+18686582,19020100,19353610,19687110,20020600,20354080,20687552,21021014,
+21354466,21687906,22021338,22354758,22688168,23021568,23354956,23688332,
+24021698,24355052,24688396,25021726,25355046,25688352,26021648,26354930,
+26688200,27021456,27354702,27687932,28021150,28354356,28687548,29020724,
+29353888,29687038,30020174,30353296,30686404,31019496,31352574,31685636,
+32018684,32351718,32684734,33017736,33350722,33683692,34016648,34349584,
+34682508,35015412,35348300,35681172,36014028,36346868,36679688,37012492,
+37345276,37678044,38010792,38343524,38676240,39008936,39341612,39674272,
+40006912,40339532,40672132,41004716,41337276,41669820,42002344,42334848,
+42667332,42999796,43332236,43664660,43997060,44329444,44661800,44994140,
+45326456,45658752,45991028,46323280,46655512,46987720,47319908,47652072,
+47984212,48316332,48648428,48980500,49312548,49644576,49976580,50308556,
+50640512,50972444,51304352,51636236,51968096,52299928,52631740,52963524,
+53295284,53627020,53958728,54290412,54622068,54953704,55285308,55616888,
+55948444,56279972,56611472,56942948,57274396,57605816,57937212,58268576,
+58599916,58931228,59262512,59593768,59924992,60256192,60587364,60918508,
+61249620,61580704,61911760,62242788,62573788,62904756,63235692,63566604,
+63897480,64228332,64559148,64889940,65220696,65551424,65882120,66212788,
+66543420,66874024,67204600,67535136,67865648,68196120,68526568,68856984,
+69187360,69517712,69848024,70178304,70508560,70838776,71168960,71499112,
+71829224,72159312,72489360,72819376,73149360,73479304,73809216,74139096,
+74468936,74798744,75128520,75458264,75787968,76117632,76447264,76776864,
+77106424,77435952,77765440,78094888,78424304,78753688,79083032,79412336,
+79741608,80070840,80400032,80729192,81058312,81387392,81716432,82045440,
+82374408,82703336,83032224,83361080,83689896,84018664,84347400,84676096,
+85004760,85333376,85661952,85990488,86318984,86647448,86975864,87304240,
+87632576,87960872,88289128,88617344,88945520,89273648,89601736,89929792,
+90257792,90585760,90913688,91241568,91569408,91897200,92224960,92552672,
+92880336,93207968,93535552,93863088,94190584,94518040,94845448,95172816,
+95500136,95827416,96154648,96481832,96808976,97136080,97463136,97790144,
+98117112,98444032,98770904,99097736,99424520,99751256,100077944,100404592,
+100731192,101057744,101384248,101710712,102037128,102363488,102689808,103016080,
+103342312,103668488,103994616,104320696,104646736,104972720,105298656,105624552,
+105950392,106276184,106601928,106927624,107253272,107578872,107904416,108229920,
+108555368,108880768,109206120,109531416,109856664,110181872,110507016,110832120,
+111157168,111482168,111807112,112132008,112456856,112781648,113106392,113431080,
+113755720,114080312,114404848,114729328,115053760,115378136,115702464,116026744,
+116350960,116675128,116999248,117323312,117647320,117971272,118295176,118619024,
+118942816,119266560,119590248,119913880,120237456,120560984,120884456,121207864,
+121531224,121854528,122177784,122500976,122824112,123147200,123470224,123793200,
+124116120,124438976,124761784,125084528,125407224,125729856,126052432,126374960,
+126697424,127019832,127342184,127664472,127986712,128308888,128631008,128953072,
+129275080,129597024,129918912,130240744,130562520,130884232,131205888,131527480,
+131849016,132170496,132491912,132813272,133134576,133455816,133776992,134098120,
+134419184,134740176,135061120,135382000,135702816,136023584,136344272,136664912,
+136985488,137306016,137626464,137946864,138267184,138587456,138907664,139227808,
+139547904,139867920,140187888,140507776,140827616,141147392,141467104,141786752,
+142106336,142425856,142745312,143064720,143384048,143703312,144022512,144341664,
+144660736,144979744,145298704,145617584,145936400,146255168,146573856,146892480,
+147211040,147529536,147847968,148166336,148484640,148802880,149121056,149439152,
+149757200,150075168,150393072,150710912,151028688,151346400,151664048,151981616,
+152299136,152616576,152933952,153251264,153568496,153885680,154202784,154519824,
+154836784,155153696,155470528,155787296,156104000,156420624,156737200,157053696,
+157370112,157686480,158002768,158318976,158635136,158951216,159267232,159583168,
+159899040,160214848,160530592,160846256,161161840,161477376,161792832,162108208,
+162423520,162738768,163053952,163369040,163684080,163999040,164313936,164628752,
+164943504,165258176,165572784,165887312,166201776,166516160,166830480,167144736,
+167458912,167773008,168087040,168400992,168714880,169028688,169342432,169656096,
+169969696,170283216,170596672,170910032,171223344,171536576,171849728,172162800,
+172475808,172788736,173101600,173414384,173727104,174039728,174352288,174664784,
+174977200,175289536,175601792,175913984,176226096,176538144,176850096,177161984,
+177473792,177785536,178097200,178408784,178720288,179031728,179343088,179654368,
+179965568,180276704,180587744,180898720,181209616,181520448,181831184,182141856,
+182452448,182762960,183073408,183383760,183694048,184004240,184314368,184624416,
+184934400,185244288,185554096,185863840,186173504,186483072,186792576,187102000,
+187411344,187720608,188029808,188338912,188647936,188956896,189265760,189574560,
+189883264,190191904,190500448,190808928,191117312,191425632,191733872,192042016,
+192350096,192658096,192966000,193273840,193581584,193889264,194196848,194504352,
+194811792,195119136,195426400,195733584,196040688,196347712,196654656,196961520,
+197268304,197574992,197881616,198188144,198494592,198800960,199107248,199413456,
+199719584,200025616,200331584,200637456,200943248,201248960,201554576,201860128,
+202165584,202470960,202776256,203081456,203386592,203691632,203996592,204301472,
+204606256,204910976,205215600,205520144,205824592,206128960,206433248,206737456,
+207041584,207345616,207649568,207953424,208257216,208560912,208864512,209168048,
+209471488,209774832,210078112,210381296,210684384,210987408,211290336,211593184,
+211895936,212198608,212501184,212803680,213106096,213408432,213710672,214012816,
+214314880,214616864,214918768,215220576,215522288,215823920,216125472,216426928,
+216728304,217029584,217330784,217631904,217932928,218233856,218534704,218835472,
+219136144,219436720,219737216,220037632,220337952,220638192,220938336,221238384,
+221538352,221838240,222138032,222437728,222737344,223036880,223336304,223635664,
+223934912,224234096,224533168,224832160,225131072,225429872,225728608,226027232,
+226325776,226624240,226922608,227220880,227519056,227817152,228115168,228413088,
+228710912,229008640,229306288,229603840,229901312,230198688,230495968,230793152,
+231090256,231387280,231684192,231981024,232277760,232574416,232870960,233167440,
+233463808,233760096,234056288,234352384,234648384,234944304,235240128,235535872,
+235831504,236127056,236422512,236717888,237013152,237308336,237603424,237898416,
+238193328,238488144,238782864,239077488,239372016,239666464,239960816,240255072,
+240549232,240843312,241137280,241431168,241724960,242018656,242312256,242605776,
+242899200,243192512,243485744,243778896,244071936,244364880,244657744,244950496,
+245243168,245535744,245828224,246120608,246412912,246705104,246997216,247289216,
+247581136,247872960,248164688,248456320,248747856,249039296,249330640,249621904,
+249913056,250204128,250495088,250785968,251076736,251367424,251658016,251948512,
+252238912,252529200,252819408,253109520,253399536,253689456,253979280,254269008,
+254558640,254848176,255137632,255426976,255716224,256005376,256294432,256583392,
+256872256,257161024,257449696,257738272,258026752,258315136,258603424,258891600,
+259179696,259467696,259755600,260043392,260331104,260618704,260906224,261193632,
+261480960,261768176,262055296,262342320,262629248,262916080,263202816,263489456,
+263776000,264062432,264348784,264635024,264921168,265207216,265493168,265779024,
+266064784,266350448,266636000,266921472,267206832,267492096,267777264,268062336,
+268347312,268632192,268916960,269201632,269486208,269770688,270055072,270339360,
+270623552,270907616,271191616,271475488,271759296,272042976,272326560,272610048,
+272893440,273176736,273459936,273743040,274026048,274308928,274591744,274874432,
+275157024,275439520,275721920,276004224,276286432,276568512,276850528,277132416,
+277414240,277695936,277977536,278259040,278540448,278821728,279102944,279384032,
+279665056,279945952,280226752,280507456,280788064,281068544,281348960,281629248,
+281909472,282189568,282469568,282749440,283029248,283308960,283588544,283868032,
+284147424,284426720,284705920,284985024,285264000,285542912,285821696,286100384,
+286378976,286657440,286935840,287214112,287492320,287770400,288048384,288326240,
+288604032,288881696,289159264,289436768,289714112,289991392,290268576,290545632,
+290822592,291099456,291376224,291652896,291929440,292205888,292482272,292758528,
+293034656,293310720,293586656,293862496,294138240,294413888,294689440,294964864,
+295240192,295515424,295790560,296065600,296340512,296615360,296890080,297164704,
+297439200,297713632,297987936,298262144,298536256,298810240,299084160,299357952,
+299631648,299905248,300178720,300452128,300725408,300998592,301271680,301544640,
+301817536,302090304,302362976,302635520,302908000,303180352,303452608,303724768,
+303996800,304268768,304540608,304812320,305083968,305355520,305626944,305898272,
+306169472,306440608,306711616,306982528,307253344,307524064,307794656,308065152,
+308335552,308605856,308876032,309146112,309416096,309685984,309955744,310225408,
+310494976,310764448,311033824,311303072,311572224,311841280,312110208,312379040,
+312647776,312916416,313184960,313453376,313721696,313989920,314258016,314526016,
+314793920,315061728,315329408,315597024,315864512,316131872,316399168,316666336,
+316933408,317200384,317467232,317733984,318000640,318267200,318533632,318799968,
+319066208,319332352,319598368,319864288,320130112,320395808,320661408,320926912,
+321192320,321457632,321722816,321987904,322252864,322517760,322782528,323047200,
+323311744,323576192,323840544,324104800,324368928,324632992,324896928,325160736,
+325424448,325688096,325951584,326215008,326478304,326741504,327004608,327267584,
+327530464,327793248,328055904,328318496,328580960,328843296,329105568,329367712,
+329629760,329891680,330153536,330415264,330676864,330938400,331199808,331461120,
+331722304,331983392,332244384,332505280,332766048,333026752,333287296,333547776,
+333808128,334068384,334328544,334588576,334848512,335108352,335368064,335627712,
+335887200,336146624,336405920,336665120,336924224,337183200,337442112,337700864,
+337959552,338218112,338476576,338734944,338993184,339251328,339509376,339767296,
+340025120,340282848,340540480,340797984,341055392,341312704,341569888,341826976,
+342083968,342340832,342597600,342854272,343110848,343367296,343623648,343879904,
+344136032,344392064,344648000,344903808,345159520,345415136,345670656,345926048,
+346181344,346436512,346691616,346946592,347201440,347456224,347710880,347965440,
+348219872,348474208,348728448,348982592,349236608,349490528,349744320,349998048,
+350251648,350505152,350758528,351011808,351264992,351518048,351771040,352023872,
+352276640,352529280,352781824,353034272,353286592,353538816,353790944,354042944,
+354294880,354546656,354798368,355049952,355301440,355552800,355804096,356055264,
+356306304,356557280,356808128,357058848,357309504,357560032,357810464,358060768,
+358311008,358561088,358811104,359060992,359310784,359560480,359810048,360059520,
+360308896,360558144,360807296,361056352,361305312,361554144,361802880,362051488,
+362300032,362548448,362796736,363044960,363293056,363541024,363788928,364036704,
+364284384,364531936,364779392,365026752,365274016,365521152,365768192,366015136,
+366261952,366508672,366755296,367001792,367248192,367494496,367740704,367986784,
+368232768,368478656,368724416,368970080,369215648,369461088,369706432,369951680,
+370196800,370441824,370686752,370931584,371176288,371420896,371665408,371909792,
+372154080,372398272,372642336,372886304,373130176,373373952,373617600,373861152,
+374104608,374347936,374591168,374834304,375077312,375320224,375563040,375805760,
+376048352,376290848,376533248,376775520,377017696,377259776,377501728,377743584,
+377985344,378227008,378468544,378709984,378951328,379192544,379433664,379674688,
+379915584,380156416,380397088,380637696,380878176,381118560,381358848,381599040,
+381839104,382079072,382318912,382558656,382798304,383037856,383277280,383516640,
+383755840,383994976,384233984,384472896,384711712,384950400,385188992,385427488,
+385665888,385904160,386142336,386380384,386618368,386856224,387093984,387331616,
+387569152,387806592,388043936,388281152,388518272,388755296,388992224,389229024,
+389465728,389702336,389938816,390175200,390411488,390647680,390883744,391119712,
+391355584,391591328,391826976,392062528,392297984,392533312,392768544,393003680,
+393238720,393473632,393708448,393943168,394177760,394412256,394646656,394880960,
+395115136,395349216,395583200,395817088,396050848,396284512,396518080,396751520,
+396984864,397218112,397451264,397684288,397917248,398150080,398382784,398615424,
+398847936,399080320,399312640,399544832,399776928,400008928,400240832,400472608,
+400704288,400935872,401167328,401398720,401629984,401861120,402092192,402323136,
+402553984,402784736,403015360,403245888,403476320,403706656,403936896,404167008,
+404397024,404626944,404856736,405086432,405316032,405545536,405774912,406004224,
+406233408,406462464,406691456,406920320,407149088,407377760,407606336,407834784,
+408063136,408291392,408519520,408747584,408975520,409203360,409431072,409658720,
+409886240,410113664,410340992,410568192,410795296,411022304,411249216,411476032,
+411702720,411929312,412155808,412382176,412608480,412834656,413060736,413286720,
+413512576,413738336,413964000,414189568,414415040,414640384,414865632,415090784,
+415315840,415540800,415765632,415990368,416215008,416439552,416663968,416888288,
+417112512,417336640,417560672,417784576,418008384,418232096,418455712,418679200,
+418902624,419125920,419349120,419572192,419795200,420018080,420240864,420463552,
+420686144,420908608,421130976,421353280,421575424,421797504,422019488,422241344,
+422463104,422684768,422906336,423127776,423349120,423570400,423791520,424012576,
+424233536,424454368,424675104,424895744,425116288,425336736,425557056,425777280,
+425997408,426217440,426437376,426657184,426876928,427096544,427316064,427535488,
+427754784,427974016,428193120,428412128,428631040,428849856,429068544,429287168,
+429505664,429724064,429942368,430160576,430378656,430596672,430814560,431032352,
+431250048,431467616,431685120,431902496,432119808,432336992,432554080,432771040,
+432987936,433204736,433421408,433637984,433854464,434070848,434287104,434503296,
+434719360,434935360,435151232,435367008,435582656,435798240,436013696,436229088,
+436444352,436659520,436874592,437089568,437304416,437519200,437733856,437948416,
+438162880,438377248,438591520,438805696,439019744,439233728,439447584,439661344,
+439875008,440088576,440302048,440515392,440728672,440941824,441154880,441367872,
+441580736,441793472,442006144,442218720,442431168,442643552,442855808,443067968,
+443280032,443492000,443703872,443915648,444127296,444338880,444550336,444761696,
+444972992,445184160,445395232,445606176,445817056,446027840,446238496,446449088,
+446659552,446869920,447080192,447290400,447500448,447710432,447920320,448130112,
+448339776,448549376,448758848,448968224,449177536,449386720,449595808,449804800,
+450013664,450222464,450431168,450639776,450848256,451056640,451264960,451473152,
+451681248,451889248,452097152,452304960,452512672,452720288,452927808,453135232,
+453342528,453549760,453756864,453963904,454170816,454377632,454584384,454791008,
+454997536,455203968,455410304,455616544,455822688,456028704,456234656,456440512,
+456646240,456851904,457057472,457262912,457468256,457673536,457878688,458083744,
+458288736,458493600,458698368,458903040,459107616,459312096,459516480,459720768,
+459924960,460129056,460333056,460536960,460740736,460944448,461148064,461351584,
+461554976,461758304,461961536,462164640,462367680,462570592,462773440,462976160,
+463178816,463381344,463583776,463786144,463988384,464190560,464392608,464594560,
+464796448,464998208,465199872,465401472,465602944,465804320,466005600,466206816,
+466407904,466608896,466809824,467010624,467211328,467411936,467612480,467812896,
+468013216,468213440,468413600,468613632,468813568,469013440,469213184,469412832,
+469612416,469811872,470011232,470210528,470409696,470608800,470807776,471006688,
+471205472,471404192,471602784,471801312,471999712,472198048,472396288,472594400,
+472792448,472990400,473188256,473385984,473583648,473781216,473978688,474176064,
+474373344,474570528,474767616,474964608,475161504,475358336,475555040,475751648,
+475948192,476144608,476340928,476537184,476733312,476929376,477125344,477321184,
+477516960,477712640,477908224,478103712,478299104,478494400,478689600,478884704,
+479079744,479274656,479469504,479664224,479858880,480053408,480247872,480442240,
+480636512,480830656,481024736,481218752,481412640,481606432,481800128,481993760,
+482187264,482380704,482574016,482767264,482960416,483153472,483346432,483539296,
+483732064,483924768,484117344,484309856,484502240,484694560,484886784,485078912,
+485270944,485462880,485654720,485846464,486038144,486229696,486421184,486612576,
+486803840,486995040,487186176,487377184,487568096,487758912,487949664,488140320,
+488330880,488521312,488711712,488901984,489092160,489282240,489472256,489662176,
+489851968,490041696,490231328,490420896,490610336,490799712,490988960,491178144,
+491367232,491556224,491745120,491933920,492122656,492311264,492499808,492688256,
+492876608,493064864,493253056,493441120,493629120,493817024,494004832,494192544,
+494380160,494567712,494755136,494942496,495129760,495316928,495504000,495691008,
+495877888,496064704,496251424,496438048,496624608,496811040,496997408,497183680,
+497369856,497555936,497741920,497927840,498113632,498299360,498484992,498670560,
+498856000,499041376,499226656,499411840,499596928,499781920,499966848,500151680,
+500336416,500521056,500705600,500890080,501074464,501258752,501442944,501627040,
+501811072,501995008,502178848,502362592,502546240,502729824,502913312,503096704,
+503280000,503463232,503646368,503829408,504012352,504195200,504377984,504560672,
+504743264,504925760,505108192,505290496,505472736,505654912,505836960,506018944,
+506200832,506382624,506564320,506745952,506927488,507108928,507290272,507471552,
+507652736,507833824,508014816,508195744,508376576,508557312,508737952,508918528,
+509099008,509279392,509459680,509639904,509820032,510000064,510180000,510359872,
+510539648,510719328,510898944,511078432,511257856,511437216,511616448,511795616,
+511974688,512153664,512332576,512511392,512690112,512868768,513047296,513225792,
+513404160,513582432,513760640,513938784,514116800,514294752,514472608,514650368,
+514828064,515005664,515183168,515360608,515537952,515715200,515892352,516069440,
+516246432,516423328,516600160,516776896,516953536,517130112,517306592,517482976,
+517659264,517835488,518011616,518187680,518363648,518539520,518715296,518891008,
+519066624,519242144,519417600,519592960,519768256,519943424,520118528,520293568,
+520468480,520643328,520818112,520992800,521167392,521341888,521516320,521690656,
+521864896,522039072,522213152,522387168,522561056,522734912,522908640,523082304,
+523255872,523429376,523602784,523776096,523949312,524122464,524295552,524468512,
+524641440,524814240,524986976,525159616,525332192,525504640,525677056,525849344,
+526021568,526193728,526365792,526537760,526709632,526881440,527053152,527224800,
+527396352,527567840,527739200,527910528,528081728,528252864,528423936,528594880,
+528765760,528936576,529107296,529277920,529448480,529618944,529789344,529959648,
+530129856,530300000,530470048,530640000,530809888,530979712,531149440,531319072,
+531488608,531658080,531827488,531996800,532166016,532335168,532504224,532673184,
+532842080,533010912,533179616,533348288,533516832,533685312,533853728,534022048,
+534190272,534358432,534526496,534694496,534862400,535030240,535197984,535365632,
+535533216,535700704,535868128,536035456,536202720,536369888,536536992,536704000,
+536870912
+};
+
--- /dev/null
+++ b/template.c
@@ -1,0 +1,33 @@
+
+//**************************************************************************
+//**
+//** TEMPLATE.C
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+// MACROS ------------------------------------------------------------------
+
+// TYPES -------------------------------------------------------------------
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+// CODE --------------------------------------------------------------------
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
--- /dev/null
+++ b/textdefs.h
@@ -1,0 +1,161 @@
+//**************************************************************************
+//**
+//** textdefs.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 477 $
+//** $Date: 2009-05-27 19:55:37 +0300 (Wed, 27 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __TEXTDEFS_H
+#define __TEXTDEFS_H
+
+/* ---- MN_menu.c ---- */
+
+#define TXT_GAMMA_LEVEL_OFF "GAMMA CORRECTION OFF"
+#define TXT_GAMMA_LEVEL_1 "GAMMA CORRECTION LEVEL 1"
+#define TXT_GAMMA_LEVEL_2 "GAMMA CORRECTION LEVEL 2"
+#define TXT_GAMMA_LEVEL_3 "GAMMA CORRECTION LEVEL 3"
+#define TXT_GAMMA_LEVEL_4 "GAMMA CORRECTION LEVEL 4"
+
+
+/* ---- P_inter.c ---- */
+
+/* Mana */
+
+#define TXT_MANA_1 "BLUE MANA"
+#define TXT_MANA_2 "GREEN MANA"
+#define TXT_MANA_BOTH "COMBINED MANA"
+
+/* Keys */
+
+#define TXT_KEY_STEEL "STEEL KEY"
+#define TXT_KEY_CAVE "CAVE KEY"
+#define TXT_KEY_AXE "AXE KEY"
+#define TXT_KEY_FIRE "FIRE KEY"
+#define TXT_KEY_EMERALD "EMERALD KEY"
+#define TXT_KEY_DUNGEON "DUNGEON KEY"
+#define TXT_KEY_SILVER "SILVER KEY"
+#define TXT_KEY_RUSTED "RUSTED KEY"
+#define TXT_KEY_HORN "HORN KEY"
+#define TXT_KEY_SWAMP "SWAMP KEY"
+#define TXT_KEY_CASTLE "CASTLE KEY"
+
+/* Artifacts */
+
+#define TXT_ARTIINVULNERABILITY "ICON OF THE DEFENDER"
+#define TXT_ARTIHEALTH "QUARTZ FLASK"
+#define TXT_ARTISUPERHEALTH "MYSTIC URN"
+#define TXT_ARTISUMMON "DARK SERVANT"
+#define TXT_ARTITORCH "TORCH"
+#define TXT_ARTIEGG "PORKALATOR"
+#define TXT_ARTIFLY "WINGS OF WRATH"
+#define TXT_ARTITELEPORT "CHAOS DEVICE"
+#define TXT_ARTIPOISONBAG "FLECHETTE"
+#define TXT_ARTITELEPORTOTHER "BANISHMENT DEVICE"
+#define TXT_ARTISPEED "BOOTS OF SPEED"
+#define TXT_ARTIBOOSTMANA "KRATER OF MIGHT"
+#define TXT_ARTIBOOSTARMOR "DRAGONSKIN BRACERS"
+#define TXT_ARTIBLASTRADIUS "DISC OF REPULSION"
+#define TXT_ARTIHEALINGRADIUS "MYSTIC AMBIT INCANT"
+
+/* Puzzle artifacts */
+
+#define TXT_ARTIPUZZSKULL "YORICK'S SKULL"
+#define TXT_ARTIPUZZGEMBIG "HEART OF D'SPARIL"
+#define TXT_ARTIPUZZGEMRED "RUBY PLANET"
+#define TXT_ARTIPUZZGEMGREEN1 "EMERALD PLANET"
+#define TXT_ARTIPUZZGEMGREEN2 "EMERALD PLANET"
+#define TXT_ARTIPUZZGEMBLUE1 "SAPPHIRE PLANET"
+#define TXT_ARTIPUZZGEMBLUE2 "SAPPHIRE PLANET"
+#define TXT_ARTIPUZZBOOK1 "DAEMON CODEX"
+#define TXT_ARTIPUZZBOOK2 "LIBER OSCURA"
+#define TXT_ARTIPUZZSKULL2 "FLAME MASK"
+#define TXT_ARTIPUZZFWEAPON "GLAIVE SEAL"
+#define TXT_ARTIPUZZCWEAPON "HOLY RELIC"
+#define TXT_ARTIPUZZMWEAPON "SIGIL OF THE MAGUS"
+#define TXT_ARTIPUZZGEAR "CLOCK GEAR"
+#define TXT_USEPUZZLEFAILED "YOU CANNOT USE THIS HERE"
+
+/* Items */
+
+#define TXT_ITEMHEALTH "CRYSTAL VIAL"
+#define TXT_ITEMBAGOFHOLDING "BAG OF HOLDING"
+#define TXT_ITEMSHIELD1 "SILVER SHIELD"
+#define TXT_ITEMSHIELD2 "ENCHANTED SHIELD"
+#define TXT_ITEMSUPERMAP "MAP SCROLL"
+#define TXT_ARMOR1 "MESH ARMOR"
+#define TXT_ARMOR2 "FALCON SHIELD"
+#define TXT_ARMOR3 "PLATINUM HELMET"
+#define TXT_ARMOR4 "AMULET OF WARDING"
+
+/* Weapons */
+
+#define TXT_WEAPON_F2 "TIMON'S AXE"
+#define TXT_WEAPON_F3 "HAMMER OF RETRIBUTION"
+#define TXT_WEAPON_F4 "QUIETUS ASSEMBLED"
+#define TXT_WEAPON_C2 "SERPENT STAFF"
+#define TXT_WEAPON_C3 "FIRESTORM"
+#define TXT_WEAPON_C4 "WRAITHVERGE ASSEMBLED"
+#define TXT_WEAPON_M2 "FROST SHARDS"
+#define TXT_WEAPON_M3 "ARC OF DEATH"
+#define TXT_WEAPON_M4 "BLOODSCOURGE ASSEMBLED"
+#define TXT_WEAPON_A2 "HAND CROSSBOW"
+#define TXT_WEAPON_A3 "GRENADES"
+#define TXT_WEAPON_A4 "STAFF OF SET ASSEMBLED"
+#define TXT_QUIETUS_PIECE "SEGMENT OF QUIETUS"
+#define TXT_WRAITHVERGE_PIECE "SEGMENT OF WRAITHVERGE"
+#define TXT_BLOODSCOURGE_PIECE "SEGMENT OF BLOODSCOURGE"
+#define TXT_STAFFOFSET_PIECE "SEGMENT OF STAFF OF SET"
+
+
+/* ---- SB_bar.c ---- */
+
+#define TXT_CHEATGODON "GOD MODE ON"
+#define TXT_CHEATGODOFF "GOD MODE OFF"
+#define TXT_CHEATNOCLIPON "NO CLIPPING ON"
+#define TXT_CHEATNOCLIPOFF "NO CLIPPING OFF"
+#define TXT_CHEATWEAPONS "ALL WEAPONS"
+#define TXT_CHEATHEALTH "FULL HEALTH"
+#define TXT_CHEATKEYS "ALL KEYS"
+#define TXT_CHEATSOUNDON "SOUND DEBUG ON"
+#define TXT_CHEATSOUNDOFF "SOUND DEBUG OFF"
+#define TXT_CHEATTICKERON "TICKER ON"
+#define TXT_CHEATTICKEROFF "TICKER OFF"
+#define TXT_CHEATARTIFACTS3 "ALL ARTIFACTS"
+#define TXT_CHEATARTIFACTSFAIL "BAD INPUT"
+#define TXT_CHEATWARP "LEVEL WARP"
+#define TXT_CHEATSCREENSHOT "SCREENSHOT"
+#define TXT_CHEATIDDQD "TRYING TO CHEAT, EH? NOW YOU DIE!"
+#define TXT_CHEATIDKFA "CHEATER - YOU DON'T DESERVE WEAPONS"
+#define TXT_CHEATBADINPUT "BAD INPUT"
+#define TXT_CHEATNOMAP "CAN'T FIND MAP"
+
+
+/* ---- G_game.c ---- */
+
+#define TXT_GAMESAVED "GAME SAVED"
+
+
+/* ---- M_misc.c ---- */
+
+#define HUSTR_CHATMACRO1 "I'm ready to kick butt!"
+#define HUSTR_CHATMACRO2 "I'm OK."
+#define HUSTR_CHATMACRO3 "I'm not looking too good!"
+#define HUSTR_CHATMACRO4 "Help!"
+#define HUSTR_CHATMACRO5 "You suck!"
+#define HUSTR_CHATMACRO6 "Next time, scumbag..."
+#define HUSTR_CHATMACRO7 "Come here!"
+#define HUSTR_CHATMACRO8 "I'll take care of it."
+#define HUSTR_CHATMACRO9 "Yes"
+#define HUSTR_CHATMACRO0 "No"
+
+
+/* ---- AM_map.c ---- */
+
+#define AMSTR_FOLLOWON "FOLLOW MODE ON"
+#define AMSTR_FOLLOWOFF "FOLLOW MODE OFF"
+
+
+#endif /* __TEXTDEFS_H */
+
--- /dev/null
+++ b/transtb10.h
@@ -1,0 +1,167 @@
+/*
+ * translation table from hexen.wad version 1.0
+ * MAXPLAYERS == 4, 3 * (MAXPLAYERS - 1) == 9 entries
+ */
+
+ /* TRANTBL0 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xac,0xae,0x01,
+
+ /* TRANTBL1 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x92,0x93,0x94,0x95,0x96,0x97,0x99,0x9b,0x9d,0x01,
+
+ /* TRANTBL2 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3b,0x3d,0x01,
+
+ /* TRANTBL3 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,
+ 0xb2,0xb3,0xb4,0xb5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBL4 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
+ 0x88,0x89,0x8a,0x8b,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBL5 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,
+ 0x41,0x42,0xc7,0xc8,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBL6 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,
+ 0xb2,0xb3,0xb4,0xb5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBL7 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
+ 0x88,0x89,0x8a,0x8b,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBL8 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,
+ 0x41,0x42,0xc7,0xc8,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
--- /dev/null
+++ b/transtb11.h
@@ -1,0 +1,383 @@
+/*
+ * translation table from hexen.wad version 1.0
+ * MAXPLAYERS == 8, 3 * (MAXPLAYERS - 1) == 21 entries
+ */
+
+ /* TRANTBL0 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xac,0xae,0x01,
+
+ /* TRANTBL1 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x93,0x95,0x97,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x01,
+
+ /* TRANTBL2 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x33,0x35,0x36,0x37,0x38,0x39,0x3b,0x3e,0x40,0x01,
+
+ /* TRANTBL3 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xbd,0xbf,0xc1,0xc3,0xc5,0xc6,0xc7,0xc8,0xc9,0x01,
+
+ /* TRANTBL4 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x06,0x09,0x0b,0x26,0x27,0x29,0x2b,0x2d,0x2f,0x01,
+
+ /* TRANTBL5 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0x61,0x63,0x66,0x69,0x6a,0x6b,0x6c,0x6f,0x71,0x00,
+
+ /* TRANTBL6 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0x00,
+
+ /* TRANTBL7 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,
+ 0xb2,0xb3,0xb4,0xb5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBL8 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x7a,0x7b,0x7d,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,
+ 0x8b,0x8c,0x8d,0x8f,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBL9 */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,
+ 0x41,0x41,0x42,0x42,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBLA */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
+ 0xc8,0xc9,0xca,0xd5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBLB */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,
+ 0x2f,0x30,0x31,0x32,0x01,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBLC */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x61,0x62,0x63,0x64,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x72,0x74,0x76,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBLD */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0xe7,0xe7,0xe8,0xe8,0xe9,0xe9,0xea,0xea,0xeb,0xeb,0xec,0xec,0xed,0xed,
+ 0xee,0xee,0xef,0xef,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBLE */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,
+ 0xb2,0xb3,0xb4,0xb5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBLF */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x7a,0x7b,0x7d,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,
+ 0x8b,0x8c,0x8d,0x8f,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBLG */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,
+ 0x41,0x41,0x42,0x42,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBLH */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
+ 0xc8,0xc9,0xca,0xd5,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBLI */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,
+ 0x2f,0x30,0x31,0x32,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBLJ */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0x61,0x62,0x63,0x64,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x72,0x74,0x76,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
+ /* TRANTBLK */
+ 0x01,0x01,0x02,0x03,0x05,0x21,0x06,0x07,0x08,0x09,0x24,0x0b,0x0c,0x26,0x0e,0x0f,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
+ 0x20,0x21,0x22,0x09,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+ 0x90,0x91,0xe7,0xe7,0xe8,0xe8,0xe9,0xe9,0xea,0xea,0xeb,0xeb,0xec,0xec,0xed,0xed,
+ 0xee,0xee,0xef,0xef,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+ 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+ 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+ 0xe0,0xe1,0xe2,0xe3,0xe4,0xd1,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0x01,
+
--- /dev/null
+++ b/v_compat.h
@@ -1,0 +1,55 @@
+
+//**************************************************************************
+//**
+//** v_compat.h
+//**
+//** $Revision: 458 $
+//** $Date: 2009-05-25 15:35:27 +0300 (Mon, 25 May 2009) $
+//**
+//**************************************************************************
+
+#ifndef __V_COMPAT_H
+#define __V_COMPAT_H
+
+#if defined(RENDER3D)
+#include "ogl_def.h"
+#endif
+
+/* SetPalette */
+
+#ifndef PLAYPAL_NUM
+#define PLAYPAL_NUM W_GetNumForName("PLAYPAL")
+#endif
+
+#if defined(RENDER3D)
+#define V_SetPaletteBase() OGL_SetFilter(0)
+#define V_SetPaletteShift(num) OGL_SetFilter((num))
+#else
+#define V_SetPaletteBase() I_SetPalette((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE))
+#define V_SetPaletteShift(num) I_SetPalette((byte *)W_CacheLumpNum(PLAYPAL_NUM, PU_CACHE) + (num)*768)
+#endif
+
+/* Minimal definitions for DrawPatch / DrawRawScreen stuff. */
+#if defined(RENDER3D)
+#define PATCH_REF int
+#define INVALID_PATCH 0
+#define BYTE_REF int
+#else
+#define BYTE_REF byte*
+#define PATCH_REF patch_t*
+#define INVALID_PATCH NULL
+#endif
+
+/* Minimal definitions for CacheLumpName / CacheLumpNum stuff. */
+#if defined(RENDER3D)
+#define ZR_ChangeTag(a,b)
+#define WR_CacheLumpName(a,b) W_GetNumForName((a))
+#define WR_CacheLumpNum(a,b) (a)
+#else
+#define ZR_ChangeTag Z_ChangeTag
+#define WR_CacheLumpName W_CacheLumpName
+#define WR_CacheLumpNum W_CacheLumpNum
+#endif
+
+#endif /* __V_COMPAT_H */
+
--- /dev/null
+++ b/v_video.c
@@ -1,0 +1,414 @@
+
+//**************************************************************************
+//**
+//** v_video.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 373 $
+//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+#define SC_INDEX 0x3c4
+
+int usegamma;
+
+byte gammatable[5][256] =
+{
+ { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,112,
+ 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
+ 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
+ },
+
+ { 2, 4, 5, 7, 8, 10, 11, 12, 14, 15, 16, 18, 19, 20, 21, 23,
+ 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41,
+ 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,
+ 109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,
+ 125,126,127,128,129,129,130,131,132,133,134,135,136,137,138,139,
+ 140,141,142,143,144,145,146,147,148,148,149,150,151,152,153,154,
+ 155,156,157,158,159,160,161,162,163,163,164,165,166,167,168,169,
+ 170,171,172,173,174,175,175,176,177,178,179,180,181,182,183,184,
+ 185,186,186,187,188,189,190,191,192,193,194,195,196,196,197,198,
+ 199,200,201,202,203,204,205,205,206,207,208,209,210,211,212,213,
+ 214,214,215,216,217,218,219,220,221,222,222,223,224,225,226,227,
+ 228,229,230,230,231,232,233,234,235,236,237,237,238,239,240,241,
+ 242,243,244,245,245,246,247,248,249,250,251,252,252,253,254,255
+ },
+
+ { 4, 7, 9, 11, 13, 15, 17, 19, 21, 22, 24, 26, 27, 29, 30, 32,
+ 33, 35, 36, 38, 39, 40, 42, 43, 45, 46, 47, 48, 50, 51, 52, 54,
+ 55, 56, 57, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 70, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ 91, 92, 93, 94, 95, 96, 97, 98,100,101,102,103,104,105,106,107,
+ 108,109,110,111,112,113,114,114,115,116,117,118,119,120,121,122,
+ 123,124,125,126,127,128,129,130,131,132,133,133,134,135,136,137,
+ 138,139,140,141,142,143,144,144,145,146,147,148,149,150,151,152,
+ 153,153,154,155,156,157,158,159,160,160,161,162,163,164,165,166,
+ 166,167,168,169,170,171,172,172,173,174,175,176,177,178,178,179,
+ 180,181,182,183,183,184,185,186,187,188,188,189,190,191,192,193,
+ 193,194,195,196,197,197,198,199,200,201,201,202,203,204,205,206,
+ 206,207,208,209,210,210,211,212,213,213,214,215,216,217,217,218,
+ 219,220,221,221,222,223,224,224,225,226,227,228,228,229,230,231,
+ 231,232,233,234,235,235,236,237,238,238,239,240,241,241,242,243,
+ 244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,255
+ },
+
+ { 8, 12, 16, 19, 22, 24, 27, 29, 31, 34, 36, 38, 40, 41, 43, 45,
+ 47, 49, 50, 52, 53, 55, 57, 58, 60, 61, 63, 64, 65, 67, 68, 70,
+ 71, 72, 74, 75, 76, 77, 79, 80, 81, 82, 84, 85, 86, 87, 88, 90,
+ 91, 92, 93, 94, 95, 96, 98, 99,100,101,102,103,104,105,106,107,
+ 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,
+ 124,125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,
+ 139,140,141,142,143,143,144,145,146,147,148,149,150,150,151,152,
+ 153,154,155,155,156,157,158,159,160,160,161,162,163,164,165,165,
+ 166,167,168,169,169,170,171,172,173,173,174,175,176,176,177,178,
+ 179,180,180,181,182,183,183,184,185,186,186,187,188,189,189,190,
+ 191,192,192,193,194,195,195,196,197,197,198,199,200,200,201,202,
+ 202,203,204,205,205,206,207,207,208,209,210,210,211,212,212,213,
+ 214,214,215,216,216,217,218,219,219,220,221,221,222,223,223,224,
+ 225,225,226,227,227,228,229,229,230,231,231,232,233,233,234,235,
+ 235,236,237,237,238,238,239,240,240,241,242,242,243,244,244,245,
+ 246,246,247,247,248,249,249,250,251,251,252,253,253,254,254,255
+ },
+
+ { 16, 23, 28, 32, 36, 39, 42, 45, 48, 50, 53, 55, 57, 60, 62, 64,
+ 66, 68, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, 90,
+ 92, 93, 94, 96, 97, 98,100,101,102,103,105,106,107,108,109,110,
+ 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,128,
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+ 143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156,
+ 157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,
+ 169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,
+ 181,182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,
+ 192,193,193,194,195,195,196,196,197,198,198,199,200,200,201,202,
+ 202,203,203,204,205,205,206,207,207,208,208,209,210,210,211,211,
+ 212,213,213,214,214,215,216,216,217,217,218,219,219,220,220,221,
+ 221,222,223,223,224,224,225,225,226,227,227,228,228,229,229,230,
+ 230,231,232,232,233,233,234,234,235,235,236,236,237,237,238,239,
+ 239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,
+ 247,248,248,249,249,250,250,251,251,252,252,253,254,254,255,255
+ }
+};
+
+#if defined(RENDER3D)
+
+void V_Init(void)
+{
+ /* OpenGL: NOTHING TO DO HERE. */
+}
+
+#else /* RENDER3D */
+
+byte *screen;
+int dirtybox[4];
+
+//---------------------------------------------------------------------------
+//
+// PROC V_Init
+//
+//---------------------------------------------------------------------------
+
+void V_Init(void)
+{
+ // I_AllocLow will put screen in low dos memory on PCs.
+ screen = I_AllocLow(SCREENWIDTH*SCREENHEIGHT);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC V_DrawPatch
+//
+// Draws a column based masked pic to the screen.
+//
+//---------------------------------------------------------------------------
+
+void V_DrawPatch(int x, int y, patch_t *patch)
+{
+ int count;
+ int col;
+ column_t *column;
+ byte *desttop;
+ byte *dest;
+ byte *source;
+ int w;
+
+ y -= SHORT(patch->topoffset);
+ x -= SHORT(patch->leftoffset);
+ if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0
+ || y + SHORT(patch->height) > SCREENHEIGHT)
+ {
+ I_Error("Bad V_DrawPatch");
+ }
+
+ col = 0;
+ desttop = screen + y*SCREENWIDTH + x;
+ w = SHORT(patch->width);
+
+ for ( ; col < w; x++, col++, desttop++)
+ {
+ column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+ // Step through the posts in a column
+ while (column->topdelta != 0xff)
+ {
+ source = (byte *)column + 3;
+ dest = desttop + column->topdelta*SCREENWIDTH;
+ count = column->length;
+ while (count--)
+ {
+ *dest = *source++;
+ dest += SCREENWIDTH;
+ }
+ column = (column_t *)((byte *)column + column->length + 4);
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC V_DrawPatchBuffer
+//
+// Draws a column based masked pic to a specified buffer.
+//
+//---------------------------------------------------------------------------
+
+void V_DrawPatchBuffer(int x, int y, patch_t *patch, byte *buffer)
+{
+ int count;
+ int col;
+ column_t *column;
+ byte *desttop;
+ byte *dest;
+ byte *source;
+ int w;
+
+ col = 0;
+ desttop = buffer + y*SCREENWIDTH + x;
+ w = SHORT(patch->width);
+
+ for ( ; col < w; x++, col++, desttop++)
+ {
+ column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+ // Step through the posts in a column
+ while (column->topdelta != 0xff)
+ {
+ source = (byte *)column + 3;
+ dest = desttop + column->topdelta*SCREENWIDTH;
+ count = column->length;
+ while (count--)
+ {
+ *dest = *source++;
+ dest += SCREENWIDTH;
+ }
+ column = (column_t *)((byte *)column + column->length + 4);
+ }
+ }
+}
+
+/*
+==================
+=
+= V_DrawFuzzPatch
+=
+= Masks a column based translucent masked pic to the screen.
+=
+==================
+*/
+extern byte *tinttable;
+
+void V_DrawFuzzPatch (int x, int y, patch_t *patch)
+{
+ int count,col;
+ column_t *column;
+ byte *desttop, *dest, *source;
+ int w;
+
+ y -= SHORT(patch->topoffset);
+ x -= SHORT(patch->leftoffset);
+
+ if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0
+ || y + SHORT(patch->height) > SCREENHEIGHT)
+ {
+ I_Error ("Bad V_DrawPatch");
+ }
+
+ col = 0;
+ desttop = screen + y*SCREENWIDTH + x;
+ w = SHORT(patch->width);
+
+ for ( ; col < w; x++, col++, desttop++)
+ {
+ column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+
+ // step through the posts in a column
+ while (column->topdelta != 0xff )
+ {
+ source = (byte *)column + 3;
+ dest = desttop + column->topdelta*SCREENWIDTH;
+ count = column->length;
+
+ while (count--)
+ {
+ *dest = tinttable[*dest + ((*source++)<<8)];
+ dest += SCREENWIDTH;
+ }
+ column = (column_t *)((byte *)column + column->length + 4);
+ }
+ }
+}
+
+/*
+==================
+=
+= V_DrawAltFuzzPatch
+=
+= Masks a column based translucent masked pic to the screen.
+=
+==================
+*/
+extern byte *tinttable;
+
+void V_DrawAltFuzzPatch (int x, int y, patch_t *patch)
+{
+ int count,col;
+ column_t *column;
+ byte *desttop, *dest, *source;
+ int w;
+
+ y -= SHORT(patch->topoffset);
+ x -= SHORT(patch->leftoffset);
+
+ if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0
+ || y + SHORT(patch->height)> SCREENHEIGHT)
+ {
+ I_Error ("Bad V_DrawPatch");
+ }
+
+ col = 0;
+ desttop = screen + y*SCREENWIDTH + x;
+ w = SHORT(patch->width);
+
+ for ( ; col < w; x++, col++, desttop++)
+ {
+ column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+
+ // step through the posts in a column
+ while (column->topdelta != 0xff )
+ {
+ source = (byte *)column + 3;
+ dest = desttop + column->topdelta*SCREENWIDTH;
+ count = column->length;
+
+ while (count--)
+ {
+ *dest = tinttable[((*dest)<<8) + *source++];
+ dest += SCREENWIDTH;
+ }
+ column = (column_t *)((byte *)column + column->length + 4);
+ }
+ }
+}
+
+/*
+==================
+=
+= V_DrawShadowedPatch
+=
+= Masks a column based masked pic to the screen.
+=
+==================
+*/
+
+void V_DrawShadowedPatch(int x, int y, patch_t *patch)
+{
+ int count,col;
+ column_t *column;
+ byte *desttop, *dest, *source;
+ byte *desttop2, *dest2;
+ int w;
+
+ y -= SHORT(patch->topoffset);
+ x -= SHORT(patch->leftoffset);
+
+ if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH || y < 0
+ || y + SHORT(patch->height) > SCREENHEIGHT)
+ {
+ I_Error ("Bad V_DrawPatch");
+ }
+
+ col = 0;
+ desttop = screen+y*SCREENWIDTH+x;
+ desttop2 = screen+(y+2)*SCREENWIDTH+x+2;
+ w = SHORT(patch->width);
+
+ for ( ; col < w; x++, col++, desttop++, desttop2++)
+ {
+ column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+
+ // step through the posts in a column
+ while (column->topdelta != 0xff )
+ {
+ source = (byte *)column + 3;
+ dest = desttop + column->topdelta*SCREENWIDTH;
+ dest2 = desttop2 + column->topdelta*SCREENWIDTH;
+ count = column->length;
+
+ while (count--)
+ {
+ *dest2 = tinttable[((*dest2)<<8)];
+ dest2 += SCREENWIDTH;
+ *dest = *source++;
+ dest += SCREENWIDTH;
+
+ }
+ column = (column_t *)( (byte *)column + column->length + 4);
+ }
+ }
+}
+
+void V_BlitToScreen (int x, int y, byte *buffer, int width, int height)
+{
+ int i, j;
+ byte *dest;
+
+ dest = screen + x + SCREENWIDTH*y;
+ for (i = 0; i < height; i++)
+ {
+ for (j = 0; j < width; j++)
+ {
+ *dest++ = *buffer++;
+ }
+ dest += (SCREENWIDTH-width);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC V_DrawRawScreen
+//
+//---------------------------------------------------------------------------
+
+void V_DrawRawScreen(byte *raw)
+{
+ memcpy(screen, raw, SCREENWIDTH*SCREENHEIGHT);
+}
+
+#endif /* ! RENDER3D */
+
--- /dev/null
+++ b/w_wad.c
@@ -1,0 +1,811 @@
+
+//**************************************************************************
+//**
+//** w_wad.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 586 $
+//** $Date: 2012-08-31 21:51:13 +0300 (Fri, 31 Aug 2012) $
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+// MACROS ------------------------------------------------------------------
+
+/* Old (beta) PC demo from hexen.zip, "Released October 2nd, 1995" */
+#define OLDDEMO_LUMPS 2762
+#define OLDDEMO_WADSIZE 10615976
+/* PC Shareware from hexndemo.zip, "Re-released October 18th, 1995" */
+#define PCDEMO_LUMPS 2856
+#define PCDEMO_WADSIZE 10644136
+/* Mac Shareware: */
+#define MACDEMO_LUMPS 3500
+#define MACDEMO_WADSIZE 13596228
+/* PC Retail, original: */
+#define RETAIL10_LUMPS 4249
+#define RETAIL10_SIZE 20128392
+/* PC Retail, patched : */
+#define RETAIL11_LUMPS 4270
+#define RETAIL11_SIZE 20083672
+/* Macintosh, retail : */
+#define MACRETAIL_LUMPS 4567
+#define MACRETAIL_SIZE 21078584
+/* DeathKings, original: */
+#define DKINGS10_LUMPS 325
+#define DKINGS10_SIZE 4429700
+/* DeathKings, patched : */
+#define DKINGS11_LUMPS 326
+#define DKINGS11_SIZE 4440584
+
+// TYPES -------------------------------------------------------------------
+
+typedef struct
+{
+ char identification[4];
+ int numlumps;
+ int infotableofs;
+} wadinfo_t;
+
+typedef struct
+{
+ int filepos;
+ int size;
+ char name[8];
+} filelump_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void W_MergeLumps(const char *start, const char *end);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+const char *waddir;
+lumpinfo_t *lumpinfo;
+int numlumps;
+void **lumpcache;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static lumpinfo_t *PrimaryLumpInfo;
+static int PrimaryNumLumps;
+static void **PrimaryLumpCache;
+static lumpinfo_t *AuxiliaryLumpInfo;
+static int AuxiliaryNumLumps;
+static void **AuxiliaryLumpCache;
+static int AuxiliaryHandle = 0;
+boolean AuxiliaryOpened = false;
+
+// CODE --------------------------------------------------------------------
+
+boolean W_IsWadPresent(const char *filename)
+{
+ char path[MAX_OSPATH];
+ int handle = -1;
+
+ /* try the directory from the command line or
+ * from the shared data environment variable.
+ */
+ if (waddir && *waddir)
+ {
+ snprintf (path, sizeof(path), "%s/%s", waddir, filename);
+ handle = open(path, OREAD);
+ }
+#if !defined(_NO_USERDIRS)
+ if (handle == -1) /* Try UserDIR */
+ {
+ snprintf (path, sizeof(path), "%s%s", basePath, filename);
+ handle = open(path, OREAD);
+ }
+#endif /* !_NO_USERDIRS */
+ if (handle == -1) /* Now try CWD */
+ {
+ handle = open(filename, OREAD);
+ }
+ if (handle == -1)
+ return false; /* Didn't find the file. */
+ close(handle);
+ return true;
+}
+
+//==========================================================================
+//
+// W_AddFile
+//
+// Files with a .wad extension are wadlink files with multiple lumps,
+// other files are single lumps with the base filename for the lump name.
+//
+//==========================================================================
+
+void W_AddFile(const char *filename)
+{
+ wadinfo_t header;
+ lumpinfo_t *lump_p;
+ char path[MAX_OSPATH];
+ int handle, length, flength;
+ int startlump;
+ filelump_t *fileinfo, singleinfo;
+ filelump_t *freeFileInfo;
+ int i, j;
+ byte *c;
+
+ handle = -1;
+ /* try the directory from the command line or
+ * from the shared data environment variable.
+ */
+ if (waddir && *waddir)
+ {
+ snprintf (path, sizeof(path), "%s/%s", waddir, filename);
+ handle = open(path, OREAD);
+ }
+#if !defined(_NO_USERDIRS)
+ if (handle == -1) /* Try UserDIR */
+ {
+ snprintf (path, sizeof(path), "%s%s", basePath, filename);
+ handle = open(path, OREAD);
+ }
+#endif /* !_NO_USERDIRS */
+ if (handle == -1) /* Now try CWD */
+ {
+ handle = open(filename, OREAD);
+ }
+ if (handle == -1)
+ return; /* Didn't find the file. */
+
+ flength = filelength(handle);
+ startlump = numlumps;
+ if (strcmp(filename + strlen(filename) - 3, "wad") != 0)
+ { // Single lump file
+ fileinfo = &singleinfo;
+ freeFileInfo = NULL;
+ singleinfo.filepos = 0;
+ singleinfo.size = LONG(flength);
+ M_ExtractFileBase(filename, singleinfo.name);
+ numlumps++;
+ }
+ else
+ { // WAD file
+ read(handle, &header, sizeof(header));
+ if (strncmp(header.identification, "IWAD", 4) != 0)
+ {
+ if (strncmp(header.identification, "PWAD", 4) != 0)
+ { // Bad file id
+ I_Error("Wad file %s doesn't have IWAD or PWAD id\n", filename);
+ }
+ }
+ header.numlumps = LONG(header.numlumps);
+ header.infotableofs = LONG(header.infotableofs);
+ length = header.numlumps * sizeof(filelump_t);
+ if (strncmp(header.identification, "IWAD", 4) == 0 &&
+ header.numlumps == PCDEMO_LUMPS && flength == PCDEMO_WADSIZE)
+ {
+ shareware = true;
+ ST_Message("Shareware WAD detected (4 level 1.0 PC version).\n");
+ }
+ else if (strncmp(header.identification, "IWAD", 4) == 0 &&
+ header.numlumps == MACDEMO_LUMPS && flength == MACDEMO_WADSIZE)
+ {
+ shareware = true;
+ ST_Message("Shareware WAD detected (4 level 1.1 Mac version).\n");
+ }
+ else if (strncmp(header.identification, "IWAD", 4) == 0 &&
+ header.numlumps == OLDDEMO_LUMPS && flength == OLDDEMO_WADSIZE)
+ {
+ shareware = true;
+ /* This old beta version is not supported: it is missing
+ * at least the FONTAY_S, chess and orb lumps. Its demos
+ * do not play correctly, either. Just reject it. */
+ I_Error("Beta Shareware WAD from 2 Oct. 1995 not supported.");
+ }
+ fileinfo = (filelump_t *) malloc(length);
+ if (!fileinfo)
+ {
+ I_Error("W_AddFile: fileinfo malloc failed\n");
+ }
+ freeFileInfo = fileinfo;
+ seek(handle, header.infotableofs, 0);
+ read(handle, fileinfo, length);
+ numlumps += header.numlumps;
+ }
+
+ // Fill in lumpinfo
+ lumpinfo = (lumpinfo_t *) realloc(lumpinfo, numlumps * sizeof(lumpinfo_t));
+ if (!lumpinfo)
+ {
+ I_Error("Couldn't realloc lumpinfo");
+ }
+ lump_p = &lumpinfo[startlump];
+ for (i = startlump; i < numlumps; i++, lump_p++, fileinfo++)
+ {
+ memset(lump_p->name, 0, 8);
+ lump_p->handle = handle;
+ lump_p->position = LONG(fileinfo->filepos);
+ lump_p->size = LONG(fileinfo->size);
+ strncpy(lump_p->name, fileinfo->name, 8);
+ /* In the Mac demo wad, many (1784) of the lump names
+ * have their first character with the high bit (0x80)
+ * set. I don't know the reason for that.. We must
+ * clear the high bits for such Mac wad files to work
+ * in this engine. This shouldn't break other wads. */
+ c = (byte *)lump_p->name;
+ for (j = 0; j < 8; c++, j++)
+ *c &= 0x7f;
+ }
+ if (freeFileInfo)
+ {
+ free(freeFileInfo);
+ }
+}
+
+//==========================================================================
+//
+// W_InitMultipleFiles
+//
+// Pass a null terminated list of files to use. All files are optional,
+// but at least one file must be found. Lump names can appear multiple
+// times. The name searcher looks backwards, so a later file can
+// override an earlier one.
+//
+//==========================================================================
+
+void W_InitMultipleFiles(const char **filenames)
+{
+ int size;
+
+ // Open all the files, load headers, and count lumps
+ numlumps = 0;
+ lumpinfo = (lumpinfo_t *) malloc(1); // Will be realloced as lumps are added
+
+ for ( ; *filenames; filenames++)
+ {
+ W_AddFile(*filenames);
+ }
+ if (!numlumps)
+ {
+ I_Error("W_InitMultipleFiles: no files found");
+ }
+
+ // Merge lumps for flats and sprites
+ W_MergeLumps("S_START","S_END");
+ W_MergeLumps("F_START","F_END");
+
+ // Set up caching
+ size = numlumps * sizeof(*lumpcache);
+ lumpcache = (void **) malloc(size);
+ if (!lumpcache)
+ {
+ I_Error("Couldn't allocate lumpcache");
+ }
+ memset(lumpcache, 0, size);
+
+ PrimaryLumpInfo = lumpinfo;
+ PrimaryLumpCache = lumpcache;
+ PrimaryNumLumps = numlumps;
+}
+
+//==========================================================================
+//
+// IsMarker
+//
+// From BOOM/xdoom. Finds an S_START or SS_START marker
+//
+//==========================================================================
+
+static int IsMarker(const char *marker, const char *name)
+{
+ return !strncmp(name, marker, 8) ||
+ (*name == *marker && !strncmp(name + 1, marker, 7));
+}
+
+//==========================================================================
+//
+// W_MergeLumps
+//
+// From xdoom/BOOM again. Merges all sprite lumps into one big 'ol block
+//
+//==========================================================================
+
+static void W_MergeLumps(const char *start, const char *end)
+{
+ lumpinfo_t *newlumpinfo;
+ int newlumps, oldlumps;
+ int in_block = 0;
+ int i;
+
+ oldlumps = newlumps = 0;
+ newlumpinfo = (lumpinfo_t *) malloc(numlumps * sizeof(lumpinfo_t));
+ if (!newlumpinfo)
+ {
+ I_Error("W_MergeLumps: newlumpinfo malloc failed");
+ }
+
+ for (i = 0; i < numlumps; i++)
+ {
+ //process lumps in global namespace
+ if (!in_block)
+ {
+ //check for start of block
+ if (IsMarker(start, lumpinfo[i].name))
+ {
+ in_block = 1;
+ if (!newlumps)
+ {
+ newlumps++;
+ memset(newlumpinfo[0].name, 0, 8);
+ strcpy(newlumpinfo[0].name, start);
+ newlumpinfo[0].handle = -1;
+ newlumpinfo[0].position = newlumpinfo[0].size = 0;
+ }
+ }
+ // else copy it
+ else
+ {
+ lumpinfo[oldlumps++] = lumpinfo[i];
+ }
+ }
+ // process lumps in sprites or flats namespace
+ else
+ {
+ // check for end of block
+ if (IsMarker(end, lumpinfo[i].name))
+ {
+ in_block = 0;
+ }
+ else if (i && lumpinfo[i].handle != lumpinfo[i-1].handle)
+ {
+ in_block = 0;
+ lumpinfo[oldlumps++] = lumpinfo[i];
+ }
+ else
+ {
+ newlumpinfo[newlumps++] = lumpinfo[i];
+ }
+ }
+ }
+
+ // now copy the merged lumps to the end of the old list
+ if (newlumps)
+ {
+ if (oldlumps + newlumps > numlumps)
+ lumpinfo = (lumpinfo_t *) realloc(lumpinfo, (oldlumps + newlumps) * sizeof(lumpinfo_t));
+ memcpy(lumpinfo + oldlumps, newlumpinfo, sizeof(lumpinfo_t) * newlumps);
+
+ numlumps = oldlumps + newlumps;
+
+ memset(lumpinfo[numlumps].name, 0, 8);
+ strcpy(lumpinfo[numlumps].name, end);
+ lumpinfo[numlumps].handle = -1;
+ lumpinfo[numlumps].position = lumpinfo[numlumps].size = 0;
+ numlumps++;
+ }
+ free (newlumpinfo);
+}
+
+//==========================================================================
+//
+// W_InitFile
+//
+// Initialize the primary from a single file.
+//
+//==========================================================================
+
+void W_InitFile(const char *filename)
+{
+ const char *names[2];
+
+ names[0] = filename;
+ names[1] = NULL;
+ W_InitMultipleFiles(names);
+}
+
+//==========================================================================
+//
+// W_OpenAuxiliary
+//
+//==========================================================================
+
+void W_OpenAuxiliary(const char *filename)
+{
+ int i;
+ int size;
+ wadinfo_t header;
+ int handle;
+ int length;
+ filelump_t *fileinfo;
+ filelump_t *sourceLump;
+ lumpinfo_t *destLump;
+
+ if (AuxiliaryOpened)
+ {
+ W_CloseAuxiliary();
+ }
+ if ((handle = open(filename, OREAD)) == -1)
+ {
+ I_Error("W_OpenAuxiliary: %s not found.", filename);
+ return;
+ }
+ AuxiliaryHandle = handle;
+ read(handle, &header, sizeof(header));
+ if (strncmp(header.identification, "IWAD", 4))
+ {
+ if (strncmp(header.identification, "PWAD", 4))
+ { // Bad file id
+ I_Error("Wad file %s doesn't have IWAD or PWAD id\n",
+ filename);
+ }
+ }
+ header.numlumps = LONG(header.numlumps);
+ header.infotableofs = LONG(header.infotableofs);
+ length = header.numlumps*sizeof(filelump_t);
+ fileinfo = (filelump_t *) Z_Malloc(length, PU_STATIC, NULL);
+ seek(handle, header.infotableofs, 0);
+ read(handle, fileinfo, length);
+ numlumps = header.numlumps;
+
+ // Init the auxiliary lumpinfo array
+ lumpinfo = (lumpinfo_t *) Z_Malloc(numlumps*sizeof(lumpinfo_t), PU_STATIC, NULL);
+ sourceLump = fileinfo;
+ destLump = lumpinfo;
+ for (i = 0; i < numlumps; i++, destLump++, sourceLump++)
+ {
+ destLump->handle = handle;
+ destLump->position = LONG(sourceLump->filepos);
+ destLump->size = LONG(sourceLump->size);
+ strncpy(destLump->name, sourceLump->name, 8);
+ }
+ Z_Free(fileinfo);
+
+ // Allocate the auxiliary lumpcache array
+ size = numlumps*sizeof(*lumpcache);
+ lumpcache = (void **) Z_Malloc(size, PU_STATIC, NULL);
+ memset(lumpcache, 0, size);
+
+ AuxiliaryLumpInfo = lumpinfo;
+ AuxiliaryLumpCache = lumpcache;
+ AuxiliaryNumLumps = numlumps;
+ AuxiliaryOpened = true;
+}
+
+//==========================================================================
+//
+// W_CloseAuxiliary
+//
+//==========================================================================
+
+void W_CloseAuxiliary(void)
+{
+ int i;
+
+ if (AuxiliaryOpened)
+ {
+ W_UseAuxiliary();
+ for (i = 0; i < numlumps; i++)
+ {
+ if (lumpcache[i])
+ {
+ Z_Free(lumpcache[i]);
+ }
+ }
+ Z_Free(AuxiliaryLumpInfo);
+ Z_Free(AuxiliaryLumpCache);
+ W_CloseAuxiliaryFile();
+ AuxiliaryOpened = false;
+ }
+ W_UsePrimary();
+}
+
+//==========================================================================
+//
+// W_CloseAuxiliaryFile
+//
+// WARNING: W_CloseAuxiliary() must be called before any further
+// auxiliary lump processing.
+//
+//==========================================================================
+
+void W_CloseAuxiliaryFile(void)
+{
+ if (AuxiliaryHandle)
+ {
+ close(AuxiliaryHandle);
+ AuxiliaryHandle = 0;
+ }
+}
+
+//==========================================================================
+//
+// W_UsePrimary
+//
+//==========================================================================
+
+void W_UsePrimary(void)
+{
+ lumpinfo = PrimaryLumpInfo;
+ numlumps = PrimaryNumLumps;
+ lumpcache = PrimaryLumpCache;
+}
+
+//==========================================================================
+//
+// W_UseAuxiliary
+//
+//==========================================================================
+
+void W_UseAuxiliary(void)
+{
+ if (AuxiliaryOpened == false)
+ {
+ I_Error("W_UseAuxiliary: WAD not opened.");
+ }
+ lumpinfo = AuxiliaryLumpInfo;
+ numlumps = AuxiliaryNumLumps;
+ lumpcache = AuxiliaryLumpCache;
+}
+
+//==========================================================================
+//
+// W_NumLumps
+//
+//==========================================================================
+
+int W_NumLumps(void)
+{
+ return numlumps;
+}
+
+//==========================================================================
+//
+// W_CheckNumForName
+//
+// Returns -1 if name not found.
+//
+//==========================================================================
+
+int W_CheckNumForName(const char *name)
+{
+ char name8[9];
+ lumpinfo_t *lump_p;
+
+ // Make the name into two integers for easy compares
+ memset(name8, 0, sizeof(name8));
+ strncpy(name8, name, 8);
+ strupr(name8); // case insensitive
+
+ // Scan backwards so patch lump files take precedence
+ lump_p = lumpinfo + numlumps;
+ while (lump_p-- != lumpinfo)
+ {
+ if (memcmp(lump_p->name, name8, 8) == 0)
+ {
+ return (int)(lump_p - lumpinfo);
+ }
+ }
+ return -1;
+}
+
+//==========================================================================
+//
+// W_GetNumForName
+//
+// Calls W_CheckNumForName, but bombs out if not found.
+//
+//==========================================================================
+
+int W_GetNumForName (const char *name)
+{
+ int i;
+
+ i = W_CheckNumForName(name);
+ if (i != -1)
+ {
+ return i;
+ }
+ I_Error("W_GetNumForName: %s not found!", name);
+ return -1;
+}
+
+//==========================================================================
+//
+// W_LumpLength
+//
+// Returns the buffer size needed to load the given lump.
+//
+//==========================================================================
+
+int W_LumpLength(int lump)
+{
+ if (lump >= numlumps)
+ {
+ I_Error("W_LumpLength: %i >= numlumps", lump);
+ }
+ return lumpinfo[lump].size;
+}
+
+//==========================================================================
+//
+// W_ReadLump
+//
+// Loads the lump into the given buffer, which must be >= W_LumpLength().
+//
+//==========================================================================
+
+void W_ReadLump(int lump, void *dest)
+{
+ int c;
+ lumpinfo_t *l;
+
+ if (lump >= numlumps)
+ {
+ I_Error("W_ReadLump: %i >= numlumps", lump);
+ }
+ l = lumpinfo+lump;
+ //I_BeginRead();
+ lseek(l->handle, l->position, SEEK_SET);
+ c = read(l->handle, dest, l->size);
+ if (c < l->size)
+ {
+ I_Error("W_ReadLump: only read %i of %i on lump %i",
+ c, l->size, lump);
+ }
+ //I_EndRead();
+}
+
+//==========================================================================
+//
+// W_CacheLumpNum
+//
+//==========================================================================
+
+void *W_CacheLumpNum(int lump, int tag)
+{
+ if ((unsigned)lump >= numlumps)
+ {
+ I_Error("W_CacheLumpNum: %i >= numlumps", lump);
+ }
+ if (!lumpcache[lump])
+ { // Need to read the lump in
+ Z_Malloc(W_LumpLength(lump), tag, &lumpcache[lump]);
+ W_ReadLump(lump, lumpcache[lump]);
+ }
+ else
+ {
+ Z_ChangeTag(lumpcache[lump], tag);
+ }
+ return lumpcache[lump];
+}
+
+//==========================================================================
+//
+// W_CacheLumpName
+//
+//==========================================================================
+
+void *W_CacheLumpName(const char *name, int tag)
+{
+ return W_CacheLumpNum(W_GetNumForName(name), tag);
+}
+
+void W_CheckWADFiles (void)
+{
+ char lumpmsg[10];
+ int i;
+
+ if (W_CheckNumForName("PRSGCRED") != -1)
+ mac_hexen = true; /* credits page lump for Mac port by Presage is present. */
+
+ strcpy (lumpmsg, "CLUS1MSG");
+ for (i = 1; i <= 4 && oldwad_10 != true; i++)
+ {
+ lumpmsg[4] = '0' + i;
+ if (W_CheckNumForName(lumpmsg) == -1)
+ oldwad_10 = true;
+ }
+
+ strcpy (lumpmsg, "WIN1MSG");
+ for (i = 1; i <= 3 && oldwad_10 != true; i++)
+ {
+ lumpmsg[3] = '0' + i;
+ if (W_CheckNumForName(lumpmsg) == -1)
+ oldwad_10 = true;
+ }
+
+#if 0
+ if (shareware)
+ {
+ ST_Message ("\n========================================================================\n");
+ ST_Message (" Hexen: Beyond Heretic\n\n");
+ ST_Message (" 4 Level Demo Version\n");
+ ST_Message (" Press any key to continue.\n");
+ ST_Message ("========================================================================\n\n");
+ getchar();
+ }
+#endif
+
+#if defined(DEMO_VERSION)
+ if (shareware != true)
+ I_Error ("\nShareware WAD not detected.\nThis exe is configured only for the DEMO version of Hexen!\n");
+#endif /* Shareware-only */
+
+#if defined(VERSION10_WAD)
+ if (oldwad_10 != true)
+ I_Error ("\nThis exe is configured only for Hexen 1.0 (4-player-only) wad files!\n");
+ ST_Message ("Running with 4-player-only Version 1.0 hexen.wad files.\n");
+#else
+ if (oldwad_10 == true)
+ {
+ ST_Message ("\nIt appears that you are using a 4-player-only Version 1.0 hexen.wad.\n");
+ ST_Message ("Running HHexen without a Version 1.1 wadfile can cause many problems.\n");
+ ST_Message ("\nPress <ENTER> to continue.\n");
+ getchar();
+ }
+#endif
+}
+
+//==========================================================================
+//
+// W_Profile
+//
+//==========================================================================
+
+// Ripped out for Heretic
+/*
+static int info[2500][10];
+static int profilecount;
+
+void W_Profile (void)
+{
+ int i;
+ memblock_t *block;
+ void *ptr;
+ char ch;
+ FILE *f;
+ int j;
+ char name[9];
+
+ for (i = 0; i < numlumps; i++)
+ {
+ ptr = lumpcache[i];
+ if (!ptr)
+ {
+ ch = ' ';
+ continue;
+ }
+ else
+ {
+ block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+ if (block->tag < PU_PURGELEVEL)
+ ch = 'S';
+ else
+ ch = 'P';
+ }
+ info[i][profilecount] = ch;
+ }
+ profilecount++;
+
+ f = fopen ("waddump.txt","w");
+ name[8] = 0;
+ for (i = 0; i < numlumps; i++)
+ {
+ memcpy (name, lumpinfo[i].name, 8);
+ for (j = 0; j < 8; j++)
+ if (!name[j])
+ break;
+ for ( ; j < 8; j++)
+ name[j] = ' ';
+ fprintf (f,"%s ",name);
+ for (j = 0; j < profilecount; j++)
+ fprintf (f," %c",info[i][j]);
+ fprintf (f,"\n");
+ }
+ fclose (f);
+}
+*/
+
--- /dev/null
+++ b/xddefs.h
@@ -1,0 +1,216 @@
+
+//**************************************************************************
+//**
+//** xddefs.h : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 543 $
+//** $Date: 2010-01-11 20:44:55 +0200 (Mon, 11 Jan 2010) $
+//**
+//**************************************************************************
+
+#ifndef __XDDEFS__
+#define __XDDEFS__
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+/* ---- Map level types ---- */
+
+/* lump order in a map wad */
+enum
+{
+ ML_LABEL,
+ ML_THINGS,
+ ML_LINEDEFS,
+ ML_SIDEDEFS,
+ ML_VERTEXES,
+ ML_SEGS,
+ ML_SSECTORS,
+ ML_NODES,
+ ML_SECTORS,
+ ML_REJECT,
+ ML_BLOCKMAP,
+ ML_BEHAVIOR
+};
+
+typedef struct
+{
+ short x;
+ short y;
+} mapvertex_t;
+
+#pragma pack on
+
+typedef struct
+{
+ short textureoffset;
+ short rowoffset;
+ char toptexture[8];
+ char bottomtexture[8];
+ char midtexture[8];
+ short sector; /* on viewer's side */
+} mapsidedef_t;
+
+#pragma pack off
+
+typedef struct
+{
+ short v1;
+ short v2;
+ short flags;
+ byte special;
+ byte arg1;
+ byte arg2;
+ byte arg3;
+ byte arg4;
+ byte arg5;
+ short sidenum[2]; /* sidenum[1] will be -1 if one sided */
+} maplinedef_t;
+
+#define ML_BLOCKING 0x0001
+#define ML_BLOCKMONSTERS 0x0002
+#define ML_TWOSIDED 0x0004
+#define ML_DONTPEGTOP 0x0008
+#define ML_DONTPEGBOTTOM 0x0010
+#define ML_SECRET 0x0020 /* don't map as two sided: IT'S A SECRET! */
+#define ML_SOUNDBLOCK 0x0040 /* don't let sound cross two of these */
+#define ML_DONTDRAW 0x0080 /* don't draw on the automap */
+#define ML_MAPPED 0x0100 /* set if already drawn in automap */
+#define ML_REPEAT_SPECIAL 0x0200 /* special is repeatable */
+#define ML_SPAC_SHIFT 10
+#define ML_SPAC_MASK 0x1c00
+#define GET_SPAC(flags) (((flags) & ML_SPAC_MASK) >> ML_SPAC_SHIFT)
+
+/* Special activation types */
+#define SPAC_CROSS 0 /* when player crosses line */
+#define SPAC_USE 1 /* when player uses line */
+#define SPAC_MCROSS 2 /* when monster crosses line */
+#define SPAC_IMPACT 3 /* when projectile hits line */
+#define SPAC_PUSH 4 /* when player/monster pushes line */
+#define SPAC_PCROSS 5 /* when projectile crosses line */
+
+typedef struct
+{
+ short floorheight;
+ short ceilingheight;
+ char floorpic[8];
+ char ceilingpic[8];
+ short lightlevel;
+ short special;
+ short tag;
+} __attribute__((__packed__)) mapsector_t;
+
+typedef struct
+{
+ short numsegs;
+ short firstseg; /* segs are stored sequentially */
+} mapsubsector_t;
+
+typedef struct
+{
+ short v1;
+ short v2;
+ short angle;
+ short linedef;
+ short side;
+ short offset;
+} mapseg_t;
+
+/* bbox coordinates */
+enum
+{
+ BOXTOP,
+ BOXBOTTOM,
+ BOXLEFT,
+ BOXRIGHT
+};
+
+#define NF_SUBSECTOR 0x8000
+typedef struct
+{
+ short x, y, dx, dy; /* partition line */
+ short bbox[2][4]; /* bounding box for each child */
+ unsigned short children[2]; /* if NF_SUBSECTOR its a subsector */
+} mapnode_t;
+
+typedef struct
+{
+ short tid;
+ short x;
+ short y;
+ short height;
+ short angle;
+ short type;
+ short options;
+ byte special;
+ byte arg1;
+ byte arg2;
+ byte arg3;
+ byte arg4;
+ byte arg5;
+} mapthing_t;
+
+#define MTF_EASY 1
+#define MTF_NORMAL 2
+#define MTF_HARD 4
+#define MTF_AMBUSH 8
+#define MTF_DORMANT 16
+#define MTF_FIGHTER 32
+#define MTF_CLERIC 64
+#define MTF_MAGE 128
+#define MTF_GSINGLE 256
+#define MTF_GCOOP 512
+#define MTF_GDEATHMATCH 1024
+
+
+/* ---- Texture definition ---- */
+
+typedef struct
+{
+ short originx;
+ short originy;
+ short patch;
+ short stepdir;
+ short colormap;
+} __attribute__((__packed__)) mappatch_t;
+
+typedef struct
+{
+ char name[8];
+ boolean masked;
+ short width;
+ short height;
+ int32_t columndirectory; /* OBSOLETE */
+ short patchcount;
+ mappatch_t patches[1];
+} __attribute__((__packed__)) maptexture_t;
+
+
+/* ---- Graphics ---- */
+
+/* posts are runs of non masked source pixels */
+typedef struct
+{
+ byte topdelta; /* -1 is the last post in a column */
+ byte length;
+ /* length data bytes follows */
+} __attribute__((__packed__)) post_t;
+
+/* column_t is a list of 0 or more post_t, (byte)-1 terminated */
+typedef post_t column_t;
+
+/* a patch holds one or more columns
+ * patches are used for sprites and all masked pictures
+ */
+typedef struct
+{
+ short width; /* bounding box size */
+ short height;
+ short leftoffset; /* pixels to the left of origin */
+ short topoffset; /* pixels below the origin */
+ int columnofs[8]; /* only [width] used */
+ /* the [0] is &columnofs[width] */
+} patch_t;
+
+#endif /* __XDDEFS__ */
+
--- /dev/null
+++ b/z_zone.c
@@ -1,0 +1,393 @@
+
+//**************************************************************************
+//**
+//** z_zone.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $Revision: 491 $
+//** $Date: 2009-05-30 01:10:42 +0300 (Sat, 30 May 2009) $
+//**
+//**************************************************************************
+
+#include "h2stdinc.h"
+#include "h2def.h"
+
+/*
+==============================================================================
+
+ ZONE MEMORY ALLOCATION
+
+There is never any space between memblocks, and there will never be two
+contiguous free memblocks.
+
+The rover can be left pointing at a non-empty block
+
+It is of no value to free a cachable block, because it will get overwritten
+automatically if needed
+
+==============================================================================
+*/
+
+
+typedef struct
+{
+ int size; // total bytes malloced, including header
+ memblock_t blocklist; // start / end cap for linked list
+ memblock_t *rover;
+} memzone_t;
+
+static memzone_t *mainzone;
+
+/*
+========================
+=
+= Z_ClearZone
+=
+========================
+*/
+
+/*
+void Z_ClearZone (memzone_t *zone)
+{
+ memblock_t *block;
+
+// set the entire zone to one free block
+
+ zone->blocklist.next = zone->blocklist.prev = block =
+ (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
+ zone->blocklist.user = (void **)zone;
+ zone->blocklist.tag = PU_STATIC;
+ zone->rover = block;
+
+ block->prev = block->next = &zone->blocklist;
+ block->user = NULL; // free block
+ block->size = zone->size - sizeof(memzone_t);
+}
+*/
+
+
+/*
+========================
+=
+= Z_Init
+=
+========================
+*/
+
+void Z_Init (void)
+{
+ memblock_t *block;
+ int size;
+
+ mainzone = (memzone_t *)I_ZoneBase (&size);
+ mainzone->size = size;
+
+// set the entire zone to one free block
+
+ mainzone->blocklist.next = mainzone->blocklist.prev = block =
+ (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
+ mainzone->blocklist.user = (void **)mainzone;
+ mainzone->blocklist.tag = PU_STATIC;
+ mainzone->rover = block;
+
+ block->prev = block->next = &mainzone->blocklist;
+ block->user = NULL; // free block
+ block->size = mainzone->size - sizeof(memzone_t);
+}
+
+
+/*
+========================
+=
+= Z_Free
+=
+========================
+*/
+
+void Z_Free (void *ptr)
+{
+ memblock_t *block, *other;
+
+ block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+ if (block->id != ZONEID)
+ I_Error ("Z_Free: freed a pointer without ZONEID");
+
+ if (block->user > (void **)0x100) // smaller values are not pointers
+ *block->user = 0; // clear the user's mark
+ block->user = NULL; // mark as free
+ block->tag = 0;
+ block->id = 0;
+
+ other = block->prev;
+ if (!other->user)
+ { // merge with previous free block
+ other->size += block->size;
+ other->next = block->next;
+ other->next->prev = other;
+ if (block == mainzone->rover)
+ mainzone->rover = other;
+ block = other;
+ }
+
+ other = block->next;
+ if (!other->user)
+ { // merge the next free block onto the end
+ block->size += other->size;
+ block->next = other->next;
+ block->next->prev = block;
+ if (other == mainzone->rover)
+ mainzone->rover = block;
+ }
+}
+
+
+/*
+========================
+=
+= Z_Malloc
+=
+= You can pass a NULL user if the tag is < PU_PURGELEVEL
+========================
+*/
+
+#define MINFRAGMENT 64
+
+void *Z_Malloc (int size, int tag, void *user)
+{
+ int extra;
+ memblock_t *start, *rover, *newblock, *base;
+
+//
+// scan through the block list looking for the first free block
+// of sufficient size, throwing out any purgable blocks along the way
+//
+ size += sizeof(memblock_t); // account for size of block header
+ size = (size + 7) & ~7; // align to 8-byte boundary
+
+//
+// if there is a free block behind the rover, back up over them
+//
+ base = mainzone->rover;
+ if (!base->prev->user)
+ base = base->prev;
+
+ rover = base;
+ start = base->prev;
+
+ do
+ {
+ if (rover == start) // scaned all the way around the list
+ I_Error ("Z_Malloc: failed on allocation of %i bytes", size);
+ if (rover->user)
+ {
+ if (rover->tag < PU_PURGELEVEL)
+ // hit a block that can't be purged, so move base past it
+ base = rover = rover->next;
+ else
+ {
+ // free the rover block (adding the size to base)
+ base = base->prev; // the rover can be the base block
+ Z_Free ((byte *)rover + sizeof(memblock_t));
+ base = base->next;
+ rover = base->next;
+ }
+ }
+ else
+ rover = rover->next;
+ } while (base->user || base->size < size);
+
+//
+// found a block big enough
+//
+ extra = base->size - size;
+ if (extra > MINFRAGMENT)
+ { // there will be a free fragment after the allocated block
+ newblock = (memblock_t *) ((byte *)base + size);
+ newblock->size = extra;
+ newblock->user = NULL; // free block
+ newblock->tag = 0;
+ newblock->prev = base;
+ newblock->next = base->next;
+ newblock->next->prev = newblock;
+ base->next = newblock;
+ base->size = size;
+ }
+
+ if (user)
+ {
+ base->user = (void **)user; // mark as an in use block
+ *(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
+ }
+ else
+ {
+ if (tag >= PU_PURGELEVEL)
+ I_Error ("Z_Malloc: an owner is required for purgable blocks");
+ base->user = (void **) 2; // mark as in use, but unowned
+ }
+ base->tag = tag;
+
+ mainzone->rover = base->next; // next allocation will start looking here
+
+ base->id = ZONEID;
+ return (void *) ((byte *)base + sizeof(memblock_t));
+}
+
+
+/*
+========================
+=
+= Z_FreeTags
+=
+========================
+*/
+
+void Z_FreeTags (int lowtag, int hightag)
+{
+ memblock_t *block, *next;
+
+ for (block = mainzone->blocklist.next ; block != &mainzone->blocklist; block = next)
+ {
+ next = block->next; // get link before freeing
+ if (!block->user)
+ continue; // free block
+ if (block->tag >= lowtag && block->tag <= hightag)
+ Z_Free ( (byte *)block+sizeof(memblock_t));
+ }
+}
+
+/*
+========================
+=
+= Z_DumpHeap
+=
+========================
+*/
+
+/*
+void Z_DumpHeap (int lowtag, int hightag)
+{
+ memblock_t *block;
+
+ printf ("zone size: %i location: %p\n", mainzone->size,mainzone);
+ printf ("tag range: %i to %i\n", lowtag, hightag);
+
+ for (block = mainzone->blocklist.next ; ; block = block->next)
+ {
+ if (block->tag >= lowtag && block->tag <= hightag)
+ printf ("block:%p size:%7i user:%p tag:%3i\n",
+ block, block->size, block->user, block->tag);
+
+ if (block->next == &mainzone->blocklist)
+ break; // all blocks have been hit
+ if ( (byte *)block + block->size != (byte *)block->next)
+ printf ("ERROR: block size does not touch the next block\n");
+ if ( block->next->prev != block)
+ printf ("ERROR: next block doesn't have proper back link\n");
+ if (!block->user && !block->next->user)
+ printf ("ERROR: two consecutive free blocks\n");
+ }
+}
+*/
+
+/*
+========================
+=
+= Z_FileDumpHeap
+=
+========================
+*/
+
+/*
+void Z_FileDumpHeap (FILE *f)
+{
+ memblock_t *block;
+
+ fprintf (f, "zone size: %i location: %p\n", mainzone->size, mainzone);
+
+ for (block = mainzone->blocklist.next ; ; block = block->next)
+ {
+ fprintf (f, "block:%p size:%7i user:%p tag:%3i\n",
+ block, block->size, block->user, block->tag);
+
+ if (block->next == &mainzone->blocklist)
+ break; // all blocks have been hit
+ if ( (byte *)block + block->size != (byte *)block->next)
+ fprintf (f, "ERROR: block size does not touch the next block\n");
+ if ( block->next->prev != block)
+ fprintf (f, "ERROR: next block doesn't have proper back link\n");
+ if (!block->user && !block->next->user)
+ fprintf (f, "ERROR: two consecutive free blocks\n");
+ }
+}
+*/
+
+/*
+========================
+=
+= Z_CheckHeap
+=
+========================
+*/
+
+void Z_CheckHeap (void)
+{
+ memblock_t *block;
+
+ for (block = mainzone->blocklist.next ; ; block = block->next)
+ {
+ if (block->next == &mainzone->blocklist)
+ break; // all blocks have been hit
+ if ( (byte *)block + block->size != (byte *)block->next)
+ I_Error ("Z_CheckHeap: block size does not touch the next block\n");
+ if ( block->next->prev != block)
+ I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
+ if (!block->user && !block->next->user)
+ I_Error ("Z_CheckHeap: two consecutive free blocks\n");
+ }
+}
+
+
+/*
+========================
+=
+= Z_ChangeTag
+=
+========================
+*/
+
+void Z_ChangeTag2 (void *ptr, int tag)
+{
+ memblock_t *block;
+
+ block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
+ if (block->id != ZONEID)
+ I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
+ if (tag >= PU_PURGELEVEL && (uintptr_t)block->user < 0x100)
+ I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
+ block->tag = tag;
+}
+
+
+/*
+========================
+=
+= Z_FreeMemory
+=
+========================
+*/
+
+/*
+int Z_FreeMemory (void)
+{
+ memblock_t *block;
+ int freemem;
+
+ freemem = 0;
+ for (block = mainzone->blocklist.next ; block != &mainzone->blocklist; block = block->next)
+ {
+ if (!block->user || block->tag >= PU_PURGELEVEL)
+ freemem += block->size;
+ }
+ return freemem;
+}
+*/
+