mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-17 18:01:42 +00:00
40739d9176
* Duke used `ototalclock` only to keep track of when the game ticked. SW uses it in the rendering code for differentials between tics so we should preserve that to prevent issues down the track.
1458 lines
44 KiB
C++
1458 lines
44 KiB
C++
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 1997, 2005 - 3D Realms Entertainment
|
|
|
|
This file is part of Shadow Warrior version 1.2
|
|
|
|
Shadow Warrior 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.
|
|
|
|
Original Source: 1997 - Frank Maddin and Jim Norwood
|
|
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
|
|
// JSECTOR.C
|
|
// This is all Jim's programming having to do with sectors.
|
|
#include "ns.h"
|
|
|
|
#include "build.h"
|
|
|
|
#include "names2.h"
|
|
#include "panel.h"
|
|
#include "game.h"
|
|
#include "tags.h"
|
|
#include "sector.h"
|
|
#include "player.h"
|
|
#include "sprite.h"
|
|
#include "jsector.h"
|
|
#include "jtags.h"
|
|
#include "lists.h"
|
|
#include "pal.h"
|
|
#include "parent.h"
|
|
#include "v_video.h"
|
|
#include "glbackend/glbackend.h"
|
|
|
|
BEGIN_SW_NS
|
|
|
|
// V A R I A B L E D E C L A R A T I O N S //////////////////////////////////////////////////////
|
|
|
|
MIRRORTYPE mirror[MAXMIRRORS];
|
|
|
|
short mirrorcnt; //, floormirrorcnt;
|
|
//short floormirrorsector[MAXMIRRORS];
|
|
SWBOOL mirrorinview;
|
|
uint32_t oscilationclock;
|
|
|
|
// Voxel stuff
|
|
//SWBOOL bVoxelsOn = TRUE; // Turn voxels on by default
|
|
SWBOOL bSpinBobVoxels = FALSE; // Do twizzly stuff to voxels, but
|
|
// not by default
|
|
SWBOOL bAutoSize = TRUE; // Autosizing on/off
|
|
|
|
//extern int chainnumpages;
|
|
extern AMB_INFO ambarray[];
|
|
extern short NormalVisibility;
|
|
|
|
extern ParentalStruct aVoxelArray[MAXTILES];
|
|
|
|
// F U N C T I O N S //////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
// SpawnWallSound
|
|
/////////////////////////////////////////////////////
|
|
void SpawnWallSound(short sndnum, short i)
|
|
{
|
|
short SpriteNum;
|
|
vec3_t mid;
|
|
SPRITEp sp;
|
|
|
|
SpriteNum = COVERinsertsprite(0, STAT_DEFAULT);
|
|
if (SpriteNum < 0)
|
|
return;
|
|
|
|
sp = &sprite[SpriteNum];
|
|
sp->cstat = 0;
|
|
sp->extra = 0;
|
|
// Get wall midpoint for offset in mirror view
|
|
mid.x = (wall[i].x + wall[wall[i].point2].x) / 2;
|
|
mid.y = (wall[i].y + wall[wall[i].point2].y) / 2;
|
|
mid.z = (sector[wall[i].nextsector].ceilingz + sector[wall[i].nextsector].floorz) / 2;
|
|
setspritez(SpriteNum, &mid);
|
|
sp = &sprite[SpriteNum];
|
|
|
|
PlaySound(sndnum, sp, v3df_dontpan | v3df_doppler);
|
|
}
|
|
|
|
short
|
|
CheckTileSound(short picnum)
|
|
{
|
|
short sndnum = -1;
|
|
|
|
switch (picnum)
|
|
{
|
|
case 163: // Sizzly Lava
|
|
case 167:
|
|
sndnum = DIGI_VOLCANOSTEAM1;
|
|
break;
|
|
case 175: // Flowing Lava
|
|
sndnum = DIGI_ERUPTION;
|
|
break;
|
|
case 179: // Bubbly lava
|
|
sndnum = DIGI_LAVAFLOW1;
|
|
break;
|
|
case 300: // Water fall tile
|
|
sndnum = DIGI_WATERFALL1;
|
|
break;
|
|
case 334: // Teleporter Pad
|
|
sndnum = DIGI_ENGROOM1;
|
|
break;
|
|
case 2690: // Jet engine fan
|
|
sndnum = DIGI_JET;
|
|
break;
|
|
case 2672: // X-Ray Machine engine
|
|
sndnum = DIGI_ENGROOM5;
|
|
break;
|
|
case 768: // Electricity
|
|
// sndnum = DIGI_;
|
|
break;
|
|
case 2714: // Pachinko Machine
|
|
// sndnum = DIGI_;
|
|
break;
|
|
case 2782: // Telepad
|
|
sndnum = DIGI_ENGROOM4;
|
|
break;
|
|
case 3382: // Gears
|
|
sndnum = DIGI_ENGROOM5;
|
|
break;
|
|
case 2801: // Computers
|
|
case 2804:
|
|
case 2807:
|
|
case 3352:
|
|
case 3385:
|
|
case 3389:
|
|
case 3393:
|
|
case 3397:
|
|
case 3401:
|
|
case 3405:
|
|
// sndnum = DIGI_;
|
|
break;
|
|
case 3478: // Radar screen
|
|
// sndnum = DIGI_;
|
|
break;
|
|
default:
|
|
sndnum = -1;
|
|
break;
|
|
}
|
|
return sndnum;
|
|
}
|
|
|
|
ANIMATOR GenerateDrips;
|
|
|
|
/////////////////////////////////////////////////////
|
|
// Initialize any of my special use sprites
|
|
/////////////////////////////////////////////////////
|
|
void
|
|
JS_SpriteSetup(void)
|
|
{
|
|
SPRITEp sp;
|
|
short SpriteNum = 0, NextSprite;
|
|
USERp u;
|
|
short i;
|
|
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[0], SpriteNum, NextSprite)
|
|
{
|
|
short tag;
|
|
|
|
sp = &sprite[SpriteNum];
|
|
tag = sp->hitag;
|
|
|
|
// Non static camera. Camera sprite will be drawn!
|
|
if (tag == MIRROR_CAM && sprite[SpriteNum].picnum != ST1)
|
|
{
|
|
// Just change it to static, sprite has all the info I need
|
|
// u = SpawnUser(SpriteNum, sp->picnum, NULL);
|
|
// RESET(sp->cstat, CSTAT_SPRITE_BLOCK);
|
|
// SET(sp->cstat, CSTAT_SPRITE_BLOCK_HITSCAN);
|
|
change_sprite_stat(SpriteNum, STAT_SPAWN_SPOT);
|
|
}
|
|
|
|
switch (sprite[SpriteNum].picnum)
|
|
{
|
|
case ST1:
|
|
if (tag == MIRROR_CAM)
|
|
{
|
|
// Just change it to static, sprite has all the info I need
|
|
// ST1 cameras won't move with SOBJ's!
|
|
change_sprite_stat(SpriteNum, STAT_ST1);
|
|
}
|
|
else if (tag == MIRROR_SPAWNSPOT)
|
|
{
|
|
// Just change it to static, sprite has all the info I need
|
|
change_sprite_stat(SpriteNum, STAT_ST1);
|
|
}
|
|
else if (tag == AMBIENT_SOUND)
|
|
{
|
|
change_sprite_stat(SpriteNum, STAT_AMBIENT);
|
|
}
|
|
else if (tag == TAG_ECHO_SOUND)
|
|
{
|
|
change_sprite_stat(SpriteNum, STAT_ECHO);
|
|
}
|
|
else if (tag == TAG_DRIPGEN)
|
|
{
|
|
u = SpawnUser(SpriteNum, 0, NULL);
|
|
|
|
ASSERT(u != NULL);
|
|
u->RotNum = 0;
|
|
u->WaitTics = sp->lotag * 120;
|
|
|
|
u->ActorActionFunc = GenerateDrips;
|
|
|
|
change_sprite_stat(SpriteNum, STAT_NO_STATE);
|
|
SET(sp->cstat, CSTAT_SPRITE_INVISIBLE);
|
|
}
|
|
break;
|
|
// Sprites in editart that should play ambient sounds
|
|
// automatically
|
|
case 380:
|
|
case 396:
|
|
case 430:
|
|
case 443:
|
|
case 512:
|
|
case 521:
|
|
case 541:
|
|
case 2720:
|
|
case 3143:
|
|
case 3157:
|
|
PlaySound(DIGI_FIRE1, sp, v3df_follow|v3df_dontpan|v3df_doppler);
|
|
break;
|
|
case 795:
|
|
case 880:
|
|
PlaySound(DIGI_WATERFLOW1, sp, v3df_follow|v3df_dontpan|v3df_doppler);
|
|
break;
|
|
case 460: // Wind Chimes
|
|
InitAmbient(79, sp);
|
|
break;
|
|
|
|
}
|
|
}
|
|
// Check for certain walls to make sounds
|
|
for (i = 0; i < numwalls; i++)
|
|
{
|
|
short picnum;
|
|
|
|
|
|
picnum = wall[i].picnum;
|
|
|
|
// Set the don't stick bit for liquid tiles
|
|
switch (picnum)
|
|
{
|
|
case 175:
|
|
case 179:
|
|
case 300:
|
|
case 320:
|
|
case 330:
|
|
case 352:
|
|
case 780:
|
|
case 890:
|
|
case 2608:
|
|
case 2616:
|
|
//case 3834:
|
|
SET(wall[i].extra, WALLFX_DONT_STICK);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
// Initialize the mirrors
|
|
/////////////////////////////////////////////////////
|
|
void JS_InitMirrors(void)
|
|
{
|
|
short startwall, endwall;
|
|
int i, j, s;
|
|
short SpriteNum = 0, NextSprite;
|
|
SWBOOL Found_Cam = FALSE;
|
|
|
|
|
|
// Set all the mirror struct values to -1
|
|
memset(mirror, 0xFF, sizeof(mirror));
|
|
|
|
mirrorinview = FALSE; // Initially set global mirror flag
|
|
// to no mirrors seen
|
|
|
|
// Scan wall tags for mirrors
|
|
mirrorcnt = 0;
|
|
tileDelete(MIRROR);
|
|
oscilationclock = ogameclock;
|
|
|
|
for (i = 0; i < MAXMIRRORS; i++)
|
|
{
|
|
tileDelete(i + MIRRORLABEL);
|
|
mirror[i].campic = -1;
|
|
mirror[i].camsprite = -1;
|
|
mirror[i].camera = -1;
|
|
mirror[i].ismagic = FALSE;
|
|
}
|
|
|
|
for (i = 0; i < numwalls; i++)
|
|
{
|
|
s = wall[i].nextsector;
|
|
if ((s >= 0) && (wall[i].overpicnum == MIRROR) && (wall[i].cstat & 32))
|
|
{
|
|
if ((sector[s].floorstat & 1) == 0)
|
|
{
|
|
if (mirrorcnt >= MAXMIRRORS)
|
|
{
|
|
Printf("MAXMIRRORS reached! Skipping mirror wall[%d]\n", i);
|
|
wall[i].overpicnum = sector[s].ceilingpicnum;
|
|
continue;
|
|
}
|
|
|
|
wall[i].overpicnum = MIRRORLABEL + mirrorcnt;
|
|
wall[i].picnum = MIRRORLABEL + mirrorcnt;
|
|
sector[s].ceilingpicnum = MIRRORLABEL + mirrorcnt;
|
|
sector[s].floorpicnum = MIRRORLABEL + mirrorcnt;
|
|
sector[s].floorstat |= 1;
|
|
mirror[mirrorcnt].mirrorwall = i;
|
|
mirror[mirrorcnt].mirrorsector = s;
|
|
mirror[mirrorcnt].numspawnspots = 0;
|
|
mirror[mirrorcnt].ismagic = FALSE;
|
|
do if (wall[i].lotag == TAG_WALL_MAGIC_MIRROR)
|
|
{
|
|
short ii, nextii;
|
|
SPRITEp sp;
|
|
|
|
Found_Cam = FALSE;
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_ST1], ii, nextii)
|
|
{
|
|
sp = &sprite[ii];
|
|
// if correct type and matches
|
|
if (sp->hitag == MIRROR_CAM && sp->lotag == wall[i].hitag)
|
|
{
|
|
mirror[mirrorcnt].camera = ii;
|
|
// Set up camera varialbes
|
|
SP_TAG5(sp) = sp->ang; // Set current angle to
|
|
// sprite angle
|
|
Found_Cam = TRUE;
|
|
}
|
|
}
|
|
|
|
ii = nextii = 0;
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_SPAWN_SPOT], ii, nextii)
|
|
{
|
|
|
|
sp = &sprite[ii];
|
|
|
|
// if correct type and matches
|
|
if (sp->hitag == MIRROR_CAM && sp->lotag == wall[i].hitag)
|
|
{
|
|
mirror[mirrorcnt].camera = ii;
|
|
// Set up camera varialbes
|
|
SP_TAG5(sp) = sp->ang; // Set current angle to
|
|
// sprite angle
|
|
Found_Cam = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!Found_Cam)
|
|
{
|
|
Printf("Cound not find the camera view sprite for match %d\n",TrackerCast(wall[i].hitag));
|
|
Printf("Map Coordinates: x = %d, y = %d\n",TrackerCast(wall[i].x),TrackerCast(wall[i].y));
|
|
break;
|
|
}
|
|
|
|
mirror[mirrorcnt].ismagic = TRUE;
|
|
|
|
Found_Cam = FALSE;
|
|
if (TEST_BOOL1(&sprite[mirror[mirrorcnt].camera]))
|
|
{
|
|
TRAVERSE_SPRITE_STAT(headspritestat[0], SpriteNum, NextSprite)
|
|
{
|
|
sp = &sprite[SpriteNum];
|
|
if (sp->picnum >= CAMSPRITE && sp->picnum < CAMSPRITE + 8 &&
|
|
sp->hitag == wall[i].hitag)
|
|
{
|
|
mirror[mirrorcnt].campic = sp->picnum;
|
|
mirror[mirrorcnt].camsprite = SpriteNum;
|
|
|
|
// JBF: commenting out this line results in the screen in $BULLET being visible
|
|
tileDelete(mirror[mirrorcnt].campic);
|
|
|
|
Found_Cam = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!Found_Cam)
|
|
{
|
|
Printf("Did not find drawtotile for camera number %d\n",mirrorcnt);
|
|
Printf("wall[%d].hitag == %d\n",i,TrackerCast(wall[i].hitag));
|
|
Printf("Map Coordinates: x = %d, y = %d\n", TrackerCast(wall[i].x), TrackerCast(wall[i].y));
|
|
RESET_BOOL1(&sprite[mirror[mirrorcnt].camera]);
|
|
}
|
|
}
|
|
|
|
// For magic mirrors, set allowable viewing time to 30
|
|
// secs
|
|
// Base rate is supposed to be 120, but time is double
|
|
// what I expect
|
|
mirror[mirrorcnt].maxtics = 60 * 30;
|
|
|
|
}
|
|
while (0);
|
|
|
|
mirror[mirrorcnt].mstate = m_normal;
|
|
|
|
// Set tics used to none
|
|
mirror[mirrorcnt].tics = 0;
|
|
|
|
if (mirror[mirrorcnt].ismagic)
|
|
{
|
|
//DSPRINTF(ds, "mirror.mirrorwall %d", mirror[mirrorcnt].mirrorwall);
|
|
MONO_PRINT(ds);
|
|
//DSPRINTF(ds, "mirror.mirrorsector %d", mirror[mirrorcnt].mirrorsector);
|
|
MONO_PRINT(ds);
|
|
//DSPRINTF(ds, "mirror.camera %d", mirror[mirrorcnt].camera);
|
|
MONO_PRINT(ds);
|
|
}
|
|
|
|
mirrorcnt++;
|
|
}
|
|
else
|
|
wall[i].overpicnum = sector[s].ceilingpicnum;
|
|
}
|
|
}
|
|
|
|
// Invalidate textures in sector behind mirror
|
|
for (i = 0; i < mirrorcnt; i++)
|
|
{
|
|
startwall = sector[mirror[i].mirrorsector].wallptr;
|
|
endwall = startwall + sector[mirror[i].mirrorsector].wallnum;
|
|
for (j = startwall; j < endwall; j++)
|
|
{
|
|
wall[j].picnum = MIRROR;
|
|
wall[j].overpicnum = MIRROR;
|
|
}
|
|
}
|
|
|
|
} // InitMirrors
|
|
|
|
/////////////////////////////////////////////////////
|
|
// Draw a 3d screen to a specific tile
|
|
/////////////////////////////////////////////////////
|
|
void drawroomstotile(int daposx, int daposy, int daposz,
|
|
fix16_t daq16ang, fix16_t daq16horiz, short dacursectnum, short tilenume)
|
|
{
|
|
TileFiles.MakeCanvas(tilenume, tilesiz[tilenume].x, tilesiz[tilenume].y);
|
|
|
|
auto canvas = renderSetTarget(tilenume);
|
|
if (!canvas) return;
|
|
|
|
screen->RenderTextureView(canvas, [=](IntRect& rect)
|
|
{
|
|
renderDrawRoomsQ16(daposx, daposy, daposz, daq16ang, daq16horiz, dacursectnum);
|
|
analyzesprites(daposx, daposy, daposz, FALSE);
|
|
renderDrawMasks();
|
|
});
|
|
|
|
renderRestoreTarget();
|
|
}
|
|
|
|
void
|
|
JS_ProcessEchoSpot()
|
|
{
|
|
short i,nexti;
|
|
SPRITEp tp;
|
|
int j,dist;
|
|
PLAYERp pp = Player+screenpeek;
|
|
int16_t reverb;
|
|
SWBOOL reverb_set = FALSE;
|
|
|
|
// Process echo sprites
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_ECHO], i, nexti)
|
|
{
|
|
dist = 0x7fffffff;
|
|
|
|
tp = &sprite[i];
|
|
|
|
j = klabs(tp->x - pp->posx);
|
|
j += klabs(tp->y - pp->posy);
|
|
if (j < dist)
|
|
dist = j;
|
|
|
|
if (dist <= SP_TAG4(tp)) // tag4 = ang
|
|
{
|
|
reverb = SP_TAG2(tp);
|
|
if (reverb > 200) reverb = 200;
|
|
if (reverb < 100) reverb = 100;
|
|
|
|
COVER_SetReverb(reverb);
|
|
reverb_set = TRUE;
|
|
}
|
|
}
|
|
if (!TEST(pp->Flags, PF_DIVING) && !reverb_set && pp->Reverb <= 0)
|
|
COVER_SetReverb(0);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
// Draw one mirror, the one closest to player
|
|
// Cams and see to teleporters do NOT support room above room!
|
|
/////////////////////////////////////////////////////
|
|
#define MAXCAMDIST 8000
|
|
|
|
int camloopcnt = 0; // Timer to cycle through player
|
|
// views
|
|
short camplayerview = 1; // Don't show yourself!
|
|
|
|
// Hack job alert!
|
|
// Mirrors and cameras are maintained in the same data structure, but for hardware rendering they cannot be interleaved.
|
|
// So this function replicates JS_DrawMirrors to only process the camera textures but not change any global state.
|
|
void JS_DrawCameras(PLAYERp pp, int tx, int ty, int tz)
|
|
{
|
|
int j, cnt;
|
|
int dist;
|
|
int tposx, tposy; // Camera
|
|
int* longptr;
|
|
|
|
SWBOOL bIsWallMirror = FALSE;
|
|
|
|
camloopcnt += gameclock - ogameclock;
|
|
if (camloopcnt > (60 * 5)) // 5 seconds per player view
|
|
{
|
|
camloopcnt = 0;
|
|
camplayerview++;
|
|
if (camplayerview >= numplayers)
|
|
camplayerview = 1;
|
|
}
|
|
|
|
// WARNING! Assuming (MIRRORLABEL&31) = 0 and MAXMIRRORS = 64 <-- JBF: wrong
|
|
longptr = (int*)&gotpic[MIRRORLABEL >> 3];
|
|
if (longptr && (longptr[0] || longptr[1]))
|
|
{
|
|
uint32_t oscilation_delta = ogameclock - oscilationclock;
|
|
oscilation_delta -= oscilation_delta % 4;
|
|
oscilationclock += oscilation_delta;
|
|
oscilation_delta *= 2;
|
|
for (cnt = MAXMIRRORS - 1; cnt >= 0; cnt--)
|
|
{
|
|
if (!mirror[cnt].ismagic) continue; // these are definitely not camera textures.
|
|
|
|
//if (TEST_GOTPIC(cnt + MIRRORLABEL) || TEST_GOTPIC(cnt + CAMSPRITE))
|
|
if (TEST_GOTPIC(cnt + MIRRORLABEL) || ((unsigned)mirror[cnt].campic < MAXTILES && TEST_GOTPIC(mirror[cnt].campic)))
|
|
{
|
|
// Do not change any global state here!
|
|
bIsWallMirror = (TEST_GOTPIC(cnt + MIRRORLABEL));
|
|
dist = 0x7fffffff;
|
|
|
|
if (bIsWallMirror)
|
|
{
|
|
j = klabs(wall[mirror[cnt].mirrorwall].x - tx);
|
|
j += klabs(wall[mirror[cnt].mirrorwall].y - ty);
|
|
if (j < dist)
|
|
dist = j;
|
|
}
|
|
else
|
|
{
|
|
SPRITEp tp;
|
|
|
|
tp = &sprite[mirror[cnt].camsprite];
|
|
|
|
j = klabs(tp->x - tx);
|
|
j += klabs(tp->y - ty);
|
|
if (j < dist)
|
|
dist = j;
|
|
}
|
|
|
|
|
|
SPRITEp sp = NULL;
|
|
int camhoriz;
|
|
short w;
|
|
int dx, dy, dz, tdx, tdy, tdz, midx, midy;
|
|
|
|
|
|
ASSERT(mirror[cnt].camera != -1);
|
|
|
|
sp = &sprite[mirror[cnt].camera];
|
|
|
|
ASSERT(sp);
|
|
|
|
// Calculate the angle of the mirror wall
|
|
w = mirror[cnt].mirrorwall;
|
|
|
|
// Get wall midpoint for offset in mirror view
|
|
midx = (wall[w].x + wall[wall[w].point2].x) / 2;
|
|
midy = (wall[w].y + wall[wall[w].point2].y) / 2;
|
|
|
|
// Finish finding offsets
|
|
tdx = klabs(midx - tx);
|
|
tdy = klabs(midy - ty);
|
|
|
|
if (midx >= tx)
|
|
dx = sp->x - tdx;
|
|
else
|
|
dx = sp->x + tdx;
|
|
|
|
if (midy >= ty)
|
|
dy = sp->y - tdy;
|
|
else
|
|
dy = sp->y + tdy;
|
|
|
|
tdz = klabs(tz - sp->z);
|
|
if (tz >= sp->z)
|
|
dz = sp->z + tdz;
|
|
else
|
|
dz = sp->z - tdz;
|
|
|
|
|
|
// Is it a TV cam or a teleporter that shows destination?
|
|
// TRUE = It's a TV cam
|
|
mirror[cnt].mstate = m_normal;
|
|
if (TEST_BOOL1(sp))
|
|
mirror[cnt].mstate = m_viewon;
|
|
|
|
// Show teleport destination
|
|
// NOTE: Adding MAXSECTORS lets you draw a room, even if
|
|
// you are outside of it!
|
|
if (mirror[cnt].mstate == m_viewon)
|
|
{
|
|
SWBOOL DoCam = FALSE;
|
|
|
|
if (mirror[cnt].campic == -1)
|
|
{
|
|
Printf("Missing campic for mirror %d\n",cnt);
|
|
Printf("Map Coordinates: x = %d, y = %d\n",midx,midy);
|
|
return;
|
|
}
|
|
|
|
// BOOL2 = Oscilate camera
|
|
if (TEST_BOOL2(sp) && MoveSkip2 == 0)
|
|
{
|
|
if (TEST_BOOL3(sp)) // If true add increment to
|
|
// angle else subtract
|
|
{
|
|
// Store current angle in TAG5
|
|
SP_TAG5(sp) = NORM_ANGLE((SP_TAG5(sp) + oscilation_delta));
|
|
|
|
// TAG6 = Turn radius
|
|
if (klabs(GetDeltaAngle(SP_TAG5(sp), sp->ang)) >= SP_TAG6(sp))
|
|
{
|
|
SP_TAG5(sp) = NORM_ANGLE((SP_TAG5(sp) - oscilation_delta));
|
|
RESET_BOOL3(sp); // Reverse turn
|
|
// direction.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Store current angle in TAG5
|
|
SP_TAG5(sp) = NORM_ANGLE((SP_TAG5(sp) - oscilation_delta));
|
|
|
|
// TAG6 = Turn radius
|
|
if (klabs(GetDeltaAngle(SP_TAG5(sp), sp->ang)) >= SP_TAG6(sp))
|
|
{
|
|
SP_TAG5(sp) = NORM_ANGLE((SP_TAG5(sp) + oscilation_delta));
|
|
SET_BOOL3(sp); // Reverse turn
|
|
// direction.
|
|
}
|
|
}
|
|
}
|
|
else if (!TEST_BOOL2(sp))
|
|
{
|
|
SP_TAG5(sp) = sp->ang; // Copy sprite angle to
|
|
// tag5
|
|
}
|
|
|
|
// See if there is a horizon value. 0 defaults to
|
|
// 100!
|
|
if (SP_TAG7(sp) != 0)
|
|
{
|
|
camhoriz = SP_TAG7(sp);
|
|
if (camhoriz > PLAYER_HORIZ_MAX)
|
|
camhoriz = PLAYER_HORIZ_MAX;
|
|
else if (camhoriz < PLAYER_HORIZ_MIN)
|
|
camhoriz = PLAYER_HORIZ_MIN;
|
|
}
|
|
else
|
|
camhoriz = 100; // Default
|
|
|
|
// If player is dead still then update at MoveSkip4
|
|
// rate.
|
|
if (pp->posx == pp->oposx && pp->posy == pp->oposy && pp->posz == pp->oposz)
|
|
DoCam = TRUE;
|
|
|
|
|
|
// Set up the tile for drawing
|
|
TileFiles.MakeCanvas(mirror[cnt].campic, 128, 128);
|
|
|
|
{
|
|
if (dist < MAXCAMDIST)
|
|
{
|
|
PLAYERp cp = Player + camplayerview;
|
|
|
|
if (TEST_BOOL11(sp) && numplayers > 1)
|
|
{
|
|
drawroomstotile(cp->posx, cp->posy, cp->posz, cp->q16ang, cp->q16horiz, cp->cursectnum, mirror[cnt].campic);
|
|
}
|
|
else
|
|
{
|
|
drawroomstotile(sp->x, sp->y, sp->z, fix16_from_int(SP_TAG5(sp)), fix16_from_int(camhoriz), sp->sectnum, mirror[cnt].campic);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void JS_DrawMirrors(PLAYERp pp, int tx, int ty, int tz, fix16_t tpq16ang, fix16_t tpq16horiz)
|
|
{
|
|
int j, cnt;
|
|
int dist;
|
|
int tposx, tposy; // Camera
|
|
int *longptr;
|
|
fix16_t tang;
|
|
|
|
// int tx, ty, tz, tpang; // Interpolate so mirror doesn't
|
|
// drift!
|
|
SWBOOL bIsWallMirror = FALSE;
|
|
|
|
// WARNING! Assuming (MIRRORLABEL&31) = 0 and MAXMIRRORS = 64 <-- JBF: wrong
|
|
longptr = (int *)&gotpic[MIRRORLABEL >> 3];
|
|
if (longptr && (longptr[0] || longptr[1]))
|
|
{
|
|
for (cnt = MAXMIRRORS - 1; cnt >= 0; cnt--)
|
|
//if (TEST_GOTPIC(cnt + MIRRORLABEL) || TEST_GOTPIC(cnt + CAMSPRITE))
|
|
if (TEST_GOTPIC(cnt + MIRRORLABEL) || ((unsigned)mirror[cnt].campic < MAXTILES && TEST_GOTPIC(mirror[cnt].campic)))
|
|
{
|
|
bIsWallMirror = FALSE;
|
|
if (TEST_GOTPIC(cnt + MIRRORLABEL))
|
|
{
|
|
bIsWallMirror = TRUE;
|
|
RESET_GOTPIC(cnt + MIRRORLABEL);
|
|
}
|
|
//else if (TEST_GOTPIC(cnt + CAMSPRITE))
|
|
else if ((unsigned)mirror[cnt].campic < MAXTILES && TEST_GOTPIC(mirror[cnt].campic))
|
|
{
|
|
//RESET_GOTPIC(cnt + CAMSPRITE);
|
|
RESET_GOTPIC(mirror[cnt].campic);
|
|
}
|
|
|
|
mirrorinview = TRUE;
|
|
|
|
// tx = pp->oposx + mulscale16(pp->posx - pp->oposx, smoothratio);
|
|
// ty = pp->oposy + mulscale16(pp->posy - pp->oposy, smoothratio);
|
|
// tz = pp->oposz + mulscale16(pp->posz - pp->oposz, smoothratio);
|
|
// tpq16ang = pp->q16ang;
|
|
|
|
|
|
dist = 0x7fffffff;
|
|
|
|
if (bIsWallMirror)
|
|
{
|
|
j = klabs(wall[mirror[cnt].mirrorwall].x - tx);
|
|
j += klabs(wall[mirror[cnt].mirrorwall].y - ty);
|
|
if (j < dist)
|
|
dist = j;
|
|
}
|
|
else
|
|
{
|
|
SPRITEp tp;
|
|
|
|
tp = &sprite[mirror[cnt].camsprite];
|
|
|
|
j = klabs(tp->x - tx);
|
|
j += klabs(tp->y - ty);
|
|
if (j < dist)
|
|
dist = j;
|
|
}
|
|
|
|
if (mirror[cnt].ismagic)
|
|
{
|
|
SPRITEp sp=NULL;
|
|
int camhoriz;
|
|
short w;
|
|
int dx, dy, dz, tdx, tdy, tdz, midx, midy;
|
|
|
|
|
|
ASSERT(mirror[cnt].camera != -1);
|
|
|
|
sp = &sprite[mirror[cnt].camera];
|
|
|
|
ASSERT(sp);
|
|
|
|
// Calculate the angle of the mirror wall
|
|
w = mirror[cnt].mirrorwall;
|
|
|
|
// Get wall midpoint for offset in mirror view
|
|
midx = (wall[w].x + wall[wall[w].point2].x) / 2;
|
|
midy = (wall[w].y + wall[wall[w].point2].y) / 2;
|
|
|
|
// Finish finding offsets
|
|
tdx = klabs(midx - tx);
|
|
tdy = klabs(midy - ty);
|
|
|
|
if (midx >= tx)
|
|
dx = sp->x - tdx;
|
|
else
|
|
dx = sp->x + tdx;
|
|
|
|
if (midy >= ty)
|
|
dy = sp->y - tdy;
|
|
else
|
|
dy = sp->y + tdy;
|
|
|
|
tdz = klabs(tz - sp->z);
|
|
if (tz >= sp->z)
|
|
dz = sp->z + tdz;
|
|
else
|
|
dz = sp->z - tdz;
|
|
|
|
|
|
// Is it a TV cam or a teleporter that shows destination?
|
|
// TRUE = It's a TV cam
|
|
mirror[cnt].mstate = m_normal;
|
|
if (TEST_BOOL1(sp))
|
|
mirror[cnt].mstate = m_viewon;
|
|
|
|
// Show teleport destination
|
|
// NOTE: Adding MAXSECTORS lets you draw a room, even if
|
|
// you are outside of it!
|
|
if (mirror[cnt].mstate != m_viewon)
|
|
{
|
|
tileDelete(MIRROR);
|
|
// Set TV camera sprite size to 0 to show mirror
|
|
// behind in this case!
|
|
|
|
if (mirror[cnt].campic != -1)
|
|
tileDelete(mirror[cnt].campic);
|
|
renderDrawRoomsQ16(dx, dy, dz, tpq16ang, tpq16horiz, sp->sectnum + MAXSECTORS);
|
|
analyzesprites(dx, dy, dz, FALSE);
|
|
renderDrawMasks();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// It's just a mirror
|
|
// Prepare drawrooms for drawing mirror and calculate
|
|
// reflected
|
|
// position into tposx, tposy, and tang (tposz == cposz)
|
|
// Must call preparemirror before drawrooms and
|
|
// completemirror after drawrooms
|
|
|
|
renderPrepareMirror(tx, ty, tz, tpq16ang, tpq16horiz,
|
|
mirror[cnt].mirrorwall, /*mirror[cnt].mirrorsector,*/ &tposx, &tposy, &tang);
|
|
|
|
renderDrawRoomsQ16(tposx, tposy, tz, (tang), tpq16horiz, mirror[cnt].mirrorsector + MAXSECTORS);
|
|
|
|
analyzesprites(tposx, tposy, tz, TRUE);
|
|
renderDrawMasks();
|
|
|
|
renderCompleteMirror(); // Reverse screen x-wise in this
|
|
// function
|
|
}
|
|
|
|
|
|
// g_visibility = tvisibility;
|
|
// g_visibility = NormalVisibility;
|
|
|
|
// renderDrawRoomsQ16(tx, ty, tz, tpq16ang, tpq16horiz, pp->cursectnum);
|
|
// Clean up anything that the camera view might have done
|
|
tileDelete(MIRROR);
|
|
wall[mirror[cnt].mirrorwall].overpicnum = MIRRORLABEL + cnt;
|
|
}
|
|
else
|
|
mirrorinview = FALSE;
|
|
}
|
|
}
|
|
|
|
void
|
|
DoAutoSize(tspriteptr_t tspr)
|
|
{
|
|
if (!bAutoSize)
|
|
return;
|
|
|
|
switch (tspr->picnum)
|
|
{
|
|
case ICON_STAR: // 1793
|
|
break;
|
|
case ICON_UZI: // 1797
|
|
tspr->xrepeat = 43;
|
|
tspr->yrepeat = 40;
|
|
break;
|
|
case ICON_UZIFLOOR: // 1807
|
|
tspr->xrepeat = 43;
|
|
tspr->yrepeat = 40;
|
|
break;
|
|
case ICON_LG_UZI_AMMO: // 1799
|
|
break;
|
|
case ICON_HEART: // 1824
|
|
break;
|
|
case ICON_HEART_LG_AMMO: // 1820
|
|
break;
|
|
case ICON_GUARD_HEAD: // 1814
|
|
break;
|
|
case ICON_FIREBALL_LG_AMMO: // 3035
|
|
break;
|
|
case ICON_ROCKET: // 1843
|
|
break;
|
|
case ICON_SHOTGUN: // 1794
|
|
tspr->xrepeat = 57;
|
|
tspr->yrepeat = 58;
|
|
break;
|
|
case ICON_LG_ROCKET: // 1796
|
|
break;
|
|
case ICON_LG_SHOTSHELL: // 1823
|
|
break;
|
|
case ICON_MICRO_GUN: // 1818
|
|
break;
|
|
case ICON_MICRO_BATTERY: // 1800
|
|
break;
|
|
case ICON_GRENADE_LAUNCHER: // 1817
|
|
tspr->xrepeat = 54;
|
|
tspr->yrepeat = 52;
|
|
break;
|
|
case ICON_LG_GRENADE: // 1831
|
|
break;
|
|
case ICON_LG_MINE: // 1842
|
|
break;
|
|
case ICON_RAIL_GUN: // 1811
|
|
tspr->xrepeat = 50;
|
|
tspr->yrepeat = 54;
|
|
break;
|
|
case ICON_RAIL_AMMO: // 1812
|
|
break;
|
|
case ICON_SM_MEDKIT: // 1802
|
|
break;
|
|
case ICON_MEDKIT: // 1803
|
|
break;
|
|
case ICON_CHEMBOMB:
|
|
tspr->xrepeat = 64;
|
|
tspr->yrepeat = 47;
|
|
break;
|
|
case ICON_FLASHBOMB:
|
|
tspr->xrepeat = 32;
|
|
tspr->yrepeat = 34;
|
|
break;
|
|
case ICON_NUKE:
|
|
break;
|
|
case ICON_CALTROPS:
|
|
tspr->xrepeat = 37;
|
|
tspr->yrepeat = 30;
|
|
break;
|
|
case ICON_BOOSTER: // 1810
|
|
tspr->xrepeat = 30;
|
|
tspr->yrepeat = 38;
|
|
break;
|
|
case ICON_HEAT_CARD: // 1819
|
|
tspr->xrepeat = 46;
|
|
tspr->yrepeat = 47;
|
|
break;
|
|
case ICON_REPAIR_KIT: // 1813
|
|
break;
|
|
case ICON_EXPLOSIVE_BOX: // 1801
|
|
break;
|
|
case ICON_ENVIRON_SUIT: // 1837
|
|
break;
|
|
case ICON_FLY: // 1782
|
|
break;
|
|
case ICON_CLOAK: // 1826
|
|
break;
|
|
case ICON_NIGHT_VISION: // 3031
|
|
tspr->xrepeat = 59;
|
|
tspr->yrepeat = 71;
|
|
break;
|
|
case ICON_NAPALM: // 3046
|
|
break;
|
|
case ICON_RING: // 3050
|
|
break;
|
|
case ICON_RINGAMMO: // 3054
|
|
break;
|
|
case ICON_NAPALMAMMO: // 3058
|
|
break;
|
|
case ICON_GRENADE: // 3059
|
|
break;
|
|
case ICON_ARMOR: // 3030
|
|
tspr->xrepeat = 82;
|
|
tspr->yrepeat = 84;
|
|
break;
|
|
case BLUE_KEY: // 1766
|
|
break;
|
|
case RED_KEY: // 1770
|
|
break;
|
|
case GREEN_KEY: // 1774
|
|
break;
|
|
case YELLOW_KEY: // 1778
|
|
break;
|
|
case BLUE_CARD:
|
|
case RED_CARD:
|
|
case GREEN_CARD:
|
|
case YELLOW_CARD:
|
|
tspr->xrepeat = 36;
|
|
tspr->yrepeat = 33;
|
|
break;
|
|
case GOLD_SKELKEY:
|
|
case SILVER_SKELKEY:
|
|
case BRONZE_SKELKEY:
|
|
case RED_SKELKEY:
|
|
tspr->xrepeat = 39;
|
|
tspr->yrepeat = 45;
|
|
break;
|
|
case SKEL_LOCKED:
|
|
case SKEL_UNLOCKED:
|
|
tspr->xrepeat = 47;
|
|
tspr->yrepeat = 40;
|
|
break;
|
|
case RAMCARD_LOCKED:
|
|
case RAMCARD_UNLOCKED:
|
|
case CARD_LOCKED:
|
|
case CARD_UNLOCKED:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Rotation angles for sprites
|
|
short rotang = 0;
|
|
|
|
void
|
|
JAnalyzeSprites(tspriteptr_t tspr)
|
|
{
|
|
rotang += 4;
|
|
if (rotang > 2047)
|
|
rotang = 0;
|
|
|
|
|
|
// Take care of autosizing
|
|
DoAutoSize(tspr);
|
|
|
|
if (videoGetRenderMode() >= REND_POLYMOST && md_tilehasmodel(tspr->picnum, 0) >= 0 && hw_models) return;
|
|
|
|
// Check for voxels
|
|
//if (bVoxelsOn)
|
|
if (r_voxels)
|
|
{
|
|
if (aVoxelArray[tspr->picnum].Voxel >= 0 && !(spriteext[tspr->owner].flags & SPREXT_NOTMD))
|
|
{
|
|
// Turn on voxels
|
|
tspr->picnum = aVoxelArray[tspr->picnum].Voxel; // Get the voxel number
|
|
tspr->cstat |= 48; // Set stat to voxelize sprite
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (tspr->picnum)
|
|
{
|
|
case 764: // Gun barrel
|
|
|
|
if (!r_voxels || (spriteext[tspr->owner].flags & SPREXT_NOTMD))
|
|
{
|
|
tspr->cstat |= 16;
|
|
break;
|
|
}
|
|
|
|
if (aVoxelArray[tspr->picnum].Voxel >= 0)
|
|
{
|
|
// Turn on voxels
|
|
tspr->picnum = aVoxelArray[tspr->picnum].Voxel; // Get the voxel number
|
|
tspr->cstat |= 48; // Set stat to voxelize sprite
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Parental Lockout Stuff
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
OrgTileList orgwalllist; // The list containing orginal wall
|
|
// pics
|
|
OrgTileList orgwalloverlist; // The list containing orginal wall
|
|
// over pics
|
|
OrgTileList orgsectorceilinglist; // The list containing orginal sector
|
|
// ceiling pics
|
|
OrgTileList orgsectorfloorlist; // The list containing orginal sector
|
|
// floor pics
|
|
|
|
void
|
|
InsertOrgTile(OrgTileP tp, OrgTileListP thelist)
|
|
{
|
|
ASSERT(tp);
|
|
|
|
// if list is empty, insert at front
|
|
if (EMPTY(thelist))
|
|
{
|
|
INSERT(thelist, tp);
|
|
return;
|
|
}
|
|
|
|
// Otherwise insert it at end
|
|
INSERT_TAIL(thelist, tp);
|
|
return;
|
|
}
|
|
|
|
|
|
OrgTileP
|
|
InitOrgTile(OrgTileListP thelist)
|
|
{
|
|
OrgTileP tp;
|
|
|
|
|
|
tp = (OrgTileP)CallocMem(sizeof(OrgTile), 1);
|
|
|
|
ASSERT(tp);
|
|
|
|
InsertOrgTile(tp, thelist);
|
|
|
|
return tp;
|
|
}
|
|
|
|
void
|
|
KillOrgTile(OrgTileP tp)
|
|
{
|
|
ASSERT(tp);
|
|
|
|
REMOVE(tp);
|
|
|
|
FreeMem(tp);
|
|
}
|
|
|
|
OrgTileP
|
|
FindOrgTile(short index, OrgTileListP thelist)
|
|
{
|
|
OrgTileP tp, next_tp;
|
|
|
|
if (EMPTY(thelist))
|
|
return NULL;
|
|
|
|
TRAVERSE(thelist, tp, next_tp)
|
|
{
|
|
if (tp->index == index)
|
|
return tp;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Call this at terminate game time
|
|
void
|
|
JS_UnInitLockouts(void)
|
|
{
|
|
OrgTileP tp=NULL, next_tp=NULL;
|
|
|
|
if (orgwalllist.Next)
|
|
{
|
|
TRAVERSE(&orgwalllist, tp, next_tp)
|
|
{
|
|
KillOrgTile(tp);
|
|
}
|
|
}
|
|
if (orgwalloverlist.Next)
|
|
{
|
|
TRAVERSE(&orgwalloverlist, tp, next_tp)
|
|
{
|
|
KillOrgTile(tp);
|
|
}
|
|
}
|
|
if (orgsectorceilinglist.Next)
|
|
{
|
|
TRAVERSE(&orgsectorceilinglist, tp, next_tp)
|
|
{
|
|
KillOrgTile(tp);
|
|
}
|
|
}
|
|
if (orgsectorfloorlist.Next)
|
|
{
|
|
TRAVERSE(&orgsectorfloorlist, tp, next_tp)
|
|
{
|
|
KillOrgTile(tp);
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
// Initialize the original tiles list
|
|
// Creates a list of all orginal tiles and their
|
|
// replacements. Several tiles can use the same
|
|
// replacement tilenum, so the list is built
|
|
// using the original tilenums as a basis for
|
|
// memory allocation
|
|
// t == 1 - wall
|
|
// t == 2 - overpicnum
|
|
// t == 3 - ceiling
|
|
// t == 4 - floor
|
|
/////////////////////////////////////////////////////
|
|
void
|
|
JS_PlockError(short wall_num, short t)
|
|
{
|
|
Printf("ERROR: JS_InitLockouts(), out of range tile number\n");
|
|
switch (t)
|
|
{
|
|
case 1:
|
|
Printf("wall %d, x %d, y %d, pic %d\n", wall_num, TrackerCast(wall[wall_num].x), TrackerCast(wall[wall_num].y), TrackerCast(wall[wall_num].picnum));
|
|
break;
|
|
case 2:
|
|
Printf("wall %d, x %d, y %d, OVERpic %d\n", wall_num, TrackerCast(wall[wall_num].x), TrackerCast(wall[wall_num].y), TrackerCast(wall[wall_num].overpicnum));
|
|
break;
|
|
case 3:
|
|
Printf("sector %d, ceiling %d\n", wall_num, TrackerCast(sector[wall_num].ceilingpicnum));
|
|
break;
|
|
case 4:
|
|
Printf("sector %d, floor %d\n", wall_num, TrackerCast(sector[wall_num].floorpicnum));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
JS_InitLockouts(void)
|
|
{
|
|
short i;
|
|
OrgTileP tp;
|
|
|
|
INITLIST(&orgwalllist); // The list containing orginal wall
|
|
// pics
|
|
INITLIST(&orgwalloverlist); // The list containing orginal wall
|
|
// over pics
|
|
INITLIST(&orgsectorceilinglist); // The list containing orginal sector
|
|
// ceiling pics
|
|
INITLIST(&orgsectorfloorlist); // The list containing orginal sector
|
|
// floor pics
|
|
|
|
// Check all walls
|
|
for (i = 0; i < numwalls; i++)
|
|
{
|
|
short picnum;
|
|
|
|
picnum = wall[i].picnum;
|
|
if (aVoxelArray[picnum].Parental >= INVISTILE)
|
|
{
|
|
JS_PlockError(i, 1);
|
|
continue;
|
|
}
|
|
|
|
if (aVoxelArray[picnum].Parental >= 0)
|
|
{
|
|
if ((tp = FindOrgTile(i, &orgwalllist)) == NULL)
|
|
tp = InitOrgTile(&orgwalllist);
|
|
tp->index = i;
|
|
tp->orgpicnum = wall[i].picnum;
|
|
}
|
|
|
|
picnum = wall[i].overpicnum;
|
|
if (aVoxelArray[picnum].Parental >= INVISTILE)
|
|
{
|
|
JS_PlockError(i, 2);
|
|
continue;
|
|
}
|
|
|
|
if (aVoxelArray[picnum].Parental >= 0)
|
|
{
|
|
if ((tp = FindOrgTile(i, &orgwalloverlist)) == NULL)
|
|
tp = InitOrgTile(&orgwalloverlist);
|
|
tp->index = i;
|
|
tp->orgpicnum = wall[i].overpicnum;
|
|
}
|
|
}
|
|
// Check all ceilings and floors
|
|
for (i = 0; i < numsectors; i++)
|
|
{
|
|
short picnum;
|
|
|
|
picnum = sector[i].ceilingpicnum;
|
|
if (aVoxelArray[picnum].Parental >= INVISTILE)
|
|
{
|
|
JS_PlockError(i, 3);
|
|
continue;
|
|
}
|
|
|
|
if (aVoxelArray[picnum].Parental >= 0)
|
|
{
|
|
if ((tp = FindOrgTile(i, &orgsectorceilinglist)) == NULL)
|
|
tp = InitOrgTile(&orgsectorceilinglist);
|
|
tp->index = i;
|
|
tp->orgpicnum = sector[i].ceilingpicnum;
|
|
}
|
|
|
|
picnum = sector[i].floorpicnum;
|
|
if (aVoxelArray[picnum].Parental >= INVISTILE)
|
|
{
|
|
JS_PlockError(i, 2);
|
|
continue;
|
|
}
|
|
|
|
if (aVoxelArray[picnum].Parental >= 0)
|
|
{
|
|
if ((tp = FindOrgTile(i, &orgsectorfloorlist)) == NULL)
|
|
tp = InitOrgTile(&orgsectorfloorlist);
|
|
tp->index = i;
|
|
tp->orgpicnum = sector[i].floorpicnum;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
// Switch back and forth between locked out stuff
|
|
/////////////////////////////////////////////////////
|
|
void
|
|
JS_ToggleLockouts(void)
|
|
{
|
|
short i;
|
|
OrgTileP tp;
|
|
|
|
|
|
// Check all walls
|
|
for (i = 0; i < numwalls; i++)
|
|
{
|
|
short picnum;
|
|
|
|
if (adult_lockout)
|
|
{
|
|
picnum = wall[i].picnum;
|
|
ASSERT(aVoxelArray[picnum].Parental < INVISTILE); // Invalid, walls can't
|
|
// be invisible
|
|
if (aVoxelArray[picnum].Parental >= 0)
|
|
{
|
|
wall[i].picnum = aVoxelArray[picnum].Parental;
|
|
}
|
|
}
|
|
else if ((tp = FindOrgTile(i, &orgwalllist)) != NULL)
|
|
wall[i].picnum = tp->orgpicnum; // Restore them
|
|
|
|
|
|
if (adult_lockout)
|
|
{
|
|
picnum = wall[i].overpicnum;
|
|
ASSERT(aVoxelArray[picnum].Parental < INVISTILE); // Invalid, walls can't
|
|
// be invisible
|
|
if (aVoxelArray[picnum].Parental >= 0)
|
|
{
|
|
wall[i].overpicnum = aVoxelArray[picnum].Parental;
|
|
}
|
|
}
|
|
else if ((tp = FindOrgTile(i, &orgwalloverlist)) != NULL)
|
|
wall[i].overpicnum = tp->orgpicnum; // Restore them
|
|
}
|
|
|
|
// Check all sectors
|
|
for (i = 0; i < numsectors; i++)
|
|
{
|
|
short picnum;
|
|
|
|
if (adult_lockout)
|
|
{
|
|
picnum = sector[i].ceilingpicnum;
|
|
ASSERT(aVoxelArray[picnum].Parental < INVISTILE); // Invalid, walls can't
|
|
// be invisible
|
|
if (aVoxelArray[picnum].Parental >= 0)
|
|
{
|
|
sector[i].ceilingpicnum = aVoxelArray[picnum].Parental;
|
|
}
|
|
}
|
|
else if ((tp = FindOrgTile(i, &orgsectorceilinglist)) != NULL)
|
|
sector[i].ceilingpicnum = tp->orgpicnum; // Restore them
|
|
|
|
|
|
if (adult_lockout)
|
|
{
|
|
picnum = sector[i].floorpicnum;
|
|
ASSERT(aVoxelArray[picnum].Parental < INVISTILE); // Invalid, walls can't
|
|
// be invisible
|
|
if (aVoxelArray[picnum].Parental >= 0)
|
|
{
|
|
sector[i].floorpicnum = aVoxelArray[picnum].Parental;
|
|
}
|
|
}
|
|
else if ((tp = FindOrgTile(i, &orgsectorfloorlist)) != NULL)
|
|
sector[i].floorpicnum = tp->orgpicnum; // Restore them
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
UnlockKeyLock(short key_num, short hit_sprite)
|
|
{
|
|
SPRITEp sp;
|
|
int SpriteNum = 0, NextSprite = 0, color = 0;
|
|
|
|
// Get palette by looking at key number
|
|
switch (key_num - 1)
|
|
{
|
|
case 0: // RED_KEY
|
|
color = PALETTE_PLAYER9;
|
|
break;
|
|
case 1: // BLUE_KEY
|
|
color = PALETTE_PLAYER7;
|
|
break;
|
|
case 2: // GREEN_KEY
|
|
color = PALETTE_PLAYER6;
|
|
break;
|
|
case 3: // YELLOW_KEY
|
|
color = PALETTE_PLAYER4;
|
|
break;
|
|
case 4: // SILVER_SKELKEY
|
|
color = PALETTE_PLAYER4;
|
|
break;
|
|
case 5: // GOLD_SKELKEY
|
|
color = PALETTE_PLAYER1;
|
|
break;
|
|
case 6: // BRONZE_SKELKEY
|
|
color = PALETTE_PLAYER8;
|
|
break;
|
|
case 7: // RED_SKELKEY
|
|
color = PALETTE_PLAYER9;
|
|
break;
|
|
}
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[0], SpriteNum, NextSprite)
|
|
{
|
|
sp = &sprite[SpriteNum];
|
|
|
|
switch (sp->picnum)
|
|
{
|
|
case SKEL_LOCKED:
|
|
if (sp->pal == color)
|
|
{
|
|
PlaySound(DIGI_UNLOCK, sp, v3df_doppler | v3df_dontpan);
|
|
if (SpriteNum == hit_sprite)
|
|
sp->picnum = SKEL_UNLOCKED;
|
|
}
|
|
break;
|
|
case RAMCARD_LOCKED:
|
|
if (sp->pal == color)
|
|
{
|
|
PlaySound(DIGI_CARDUNLOCK, sp, v3df_doppler | v3df_dontpan);
|
|
sp->picnum = RAMCARD_UNLOCKED;
|
|
}
|
|
break;
|
|
case CARD_LOCKED:
|
|
if (sp->pal == color)
|
|
{
|
|
PlaySound(DIGI_RAMUNLOCK, sp, v3df_doppler | v3df_dontpan);
|
|
if (SpriteNum == hit_sprite)
|
|
sp->picnum = CARD_UNLOCKED;
|
|
else
|
|
sp->picnum = CARD_UNLOCKED+1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
END_SW_NS
|