mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-17 09:51:39 +00:00
a087d566ee
* removed all cases of getting a sound handle and checking it later. * In particular, refactor the cases where the handle is stored in a static local variable. These are fundamentally unsafe because nothing maintains these local variables. * finished rewriting the PlaySound function. Let's hope this is what was intended, the entire coding here was not particularly good, mixing high and low level sound handling all on the same level. * call the update routine each tic and not merely every 4th or 8th one, this kind of granularity was ok in 1997 but not with a modern sound engine.
3503 lines
86 KiB
C++
3503 lines
86 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
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
#include "ns.h"
|
|
#include "build.h"
|
|
#include "common.h"
|
|
|
|
#include "keys.h"
|
|
#include "names2.h"
|
|
#include "panel.h"
|
|
#include "game.h"
|
|
#include "tags.h"
|
|
#include "sector.h"
|
|
#include "player.h"
|
|
#include "quake.h"
|
|
#include "weapon.h"
|
|
#include "jtags.h"
|
|
|
|
#include "network.h"
|
|
|
|
#include "break.h"
|
|
#include "track.h"
|
|
#include "sprite.h"
|
|
#include "common_game.h"
|
|
#include "light.h"
|
|
#include "text.h"
|
|
#include "gstrings.h"
|
|
#include "secrets.h"
|
|
|
|
BEGIN_SW_NS
|
|
|
|
#define LAVASIZ 128
|
|
#define LAVALOGSIZ 7
|
|
#define LAVAMAXDROPS 32
|
|
#define DEFAULT_DOOR_SPEED 800
|
|
|
|
int InitFireballTrap(short SpriteNum);
|
|
ANIMATOR DoGrating;
|
|
void DoPlayerBeginForceJump(PLAYERp);
|
|
|
|
short FindNextSectorByTag(short sectnum, int tag);
|
|
short LevelSecrets;
|
|
SWBOOL TestVatorMatchActive(short match);
|
|
SWBOOL TestSpikeMatchActive(short match);
|
|
SWBOOL TestRotatorMatchActive(short match);
|
|
SWBOOL TestSlidorMatchActive(short match);
|
|
int PlayerCheckDeath(PLAYERp, short);
|
|
short DoVatorOperate(PLAYERp, short);
|
|
short DoVatorMatch(PLAYERp pp, short match);
|
|
short DoRotatorOperate(PLAYERp, short);
|
|
short DoRotatorMatch(PLAYERp pp, short match, SWBOOL);
|
|
short DoSlidorOperate(PLAYERp, short);
|
|
short DoSlidorMatch(PLAYERp pp, short match, SWBOOL);
|
|
|
|
void KillMatchingCrackSprites(short match);
|
|
int DoTrapReset(short match);
|
|
int DoTrapMatch(short match);
|
|
|
|
PLAYERp GlobPlayerP;
|
|
#if 0
|
|
char lavabakpic[(LAVASIZ + 2) * (LAVASIZ + 2)], lavainc[LAVASIZ];
|
|
int lavanumdrops, lavanumframes;
|
|
int lavadropx[LAVAMAXDROPS], lavadropy[LAVAMAXDROPS];
|
|
int lavadropsiz[LAVAMAXDROPS], lavadropsizlookup[LAVAMAXDROPS];
|
|
int lavaradx[32][128], lavarady[32][128], lavaradcnt[32];
|
|
#endif
|
|
|
|
SECT_USERp SectUser[MAXSECTORS];
|
|
USERp User[MAXSPRITES];
|
|
|
|
ANIM Anim[MAXANIM];
|
|
short AnimCnt = 0;
|
|
|
|
SINE_WAVE_FLOOR SineWaveFloor[MAX_SINE_WAVE][21];
|
|
SINE_WALL SineWall[MAX_SINE_WALL][MAX_SINE_WALL_POINTS];
|
|
SPRING_BOARD SpringBoard[20];
|
|
int x_min_bound, y_min_bound, x_max_bound, y_max_bound;
|
|
|
|
void SetSectorWallBits(short sectnum, int bit_mask, SWBOOL set_sectwall, SWBOOL set_nextwall)
|
|
{
|
|
short wall_num, start_wall;
|
|
|
|
wall_num = start_wall = sector[sectnum].wallptr;
|
|
|
|
do
|
|
{
|
|
if (set_sectwall)
|
|
SET(wall[wall_num].extra, bit_mask);
|
|
|
|
if (set_nextwall)
|
|
{
|
|
uint16_t const nextwall = wall[wall_num].nextwall;
|
|
if (nextwall < MAXWALLS)
|
|
SET(wall[nextwall].extra, bit_mask);
|
|
}
|
|
|
|
wall_num = wall[wall_num].point2;
|
|
}
|
|
while (wall_num != start_wall);
|
|
|
|
}
|
|
|
|
void WallSetupDontMove(void)
|
|
{
|
|
int i,j,nexti,nextj;
|
|
SPRITEp spu, spl;
|
|
WALLp wallp;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_WALL_DONT_MOVE_UPPER],i,nexti)
|
|
{
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_WALL_DONT_MOVE_LOWER],j,nextj)
|
|
{
|
|
spu = &sprite[i];
|
|
spl = &sprite[j];
|
|
|
|
if (spu->lotag == spl->lotag)
|
|
{
|
|
for (wallp = wall; wallp < &wall[numwalls]; wallp++)
|
|
{
|
|
if (wallp->x < spl->x && wallp->x > spu->x && wallp->y < spl->y && wallp->y > spu->y)
|
|
{
|
|
SET(wallp->extra, WALLFX_DONT_MOVE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void WallSetupLoop(WALLp wp, int16_t lotag, int16_t extra)
|
|
{
|
|
// set first wall
|
|
{
|
|
SET(wp->extra, extra);
|
|
uint16_t const nextwall = wp->nextwall;
|
|
if (nextwall < MAXWALLS)
|
|
SET(wall[nextwall].extra, extra);
|
|
}
|
|
|
|
// Travel all the way around loop setting wall bits
|
|
for (uint16_t wall_num = wp->point2;
|
|
wall[wall_num].lotag != lotag;
|
|
wall_num = wall[wall_num].point2)
|
|
{
|
|
SET(wall[wall_num].extra, extra);
|
|
uint16_t const nextwall = wall[wall_num].nextwall;
|
|
if (nextwall < MAXWALLS)
|
|
SET(wall[nextwall].extra, extra);
|
|
}
|
|
}
|
|
|
|
void
|
|
WallSetup(void)
|
|
{
|
|
short i = 0;
|
|
short NextSineWall = 0;
|
|
WALLp wp;
|
|
|
|
WallSetupDontMove();
|
|
|
|
memset(SineWall, -1, sizeof(SineWall));
|
|
|
|
x_min_bound = 999999;
|
|
y_min_bound = 999999;
|
|
x_max_bound = -999999;
|
|
y_max_bound = -999999;
|
|
|
|
|
|
for (wp = wall, i = 0; wp < &wall[numwalls]; i++, wp++)
|
|
{
|
|
if (wp->picnum == FAF_PLACE_MIRROR_PIC)
|
|
wp->picnum = FAF_MIRROR_PIC;
|
|
|
|
if (wall[i].picnum == FAF_PLACE_MIRROR_PIC+1)
|
|
wall[i].picnum = FAF_MIRROR_PIC+1;
|
|
|
|
// get map min and max coordinates
|
|
x_min_bound = min(TrackerCast(wp->x), x_min_bound);
|
|
y_min_bound = min(TrackerCast(wp->y), y_min_bound);
|
|
x_max_bound = max(TrackerCast(wp->x), x_max_bound);
|
|
y_max_bound = max(TrackerCast(wp->y), y_max_bound);
|
|
|
|
// this overwrites the lotag so it needs to be called LAST - its down there
|
|
// SetupWallForBreak(wp);
|
|
|
|
switch (wp->lotag)
|
|
{
|
|
case TAG_WALL_LOOP_DONT_SPIN:
|
|
{
|
|
WallSetupLoop(wp, TAG_WALL_LOOP_DONT_SPIN, WALLFX_LOOP_DONT_SPIN);
|
|
break;
|
|
}
|
|
|
|
case TAG_WALL_LOOP_DONT_SCALE:
|
|
{
|
|
WallSetupLoop(wp, TAG_WALL_LOOP_DONT_SCALE, WALLFX_DONT_SCALE);
|
|
wp->lotag = 0;
|
|
break;
|
|
}
|
|
|
|
case TAG_WALL_LOOP_OUTER_SECONDARY:
|
|
{
|
|
// make sure it's a red wall
|
|
ASSERT((uint16_t)wp->nextwall < MAXWALLS);
|
|
|
|
WallSetupLoop(wp, TAG_WALL_LOOP_OUTER_SECONDARY, WALLFX_LOOP_OUTER|WALLFX_LOOP_OUTER_SECONDARY);
|
|
break;
|
|
}
|
|
|
|
case TAG_WALL_LOOP_OUTER:
|
|
{
|
|
// make sure it's a red wall
|
|
ASSERT((uint16_t)wp->nextwall < MAXWALLS);
|
|
|
|
WallSetupLoop(wp, TAG_WALL_LOOP_OUTER, WALLFX_LOOP_OUTER);
|
|
wp->lotag = 0;
|
|
break;
|
|
}
|
|
|
|
case TAG_WALL_DONT_MOVE:
|
|
{
|
|
// set first wall
|
|
SET(wp->extra, WALLFX_DONT_MOVE);
|
|
break;
|
|
}
|
|
|
|
case TAG_WALL_LOOP_SPIN_2X:
|
|
{
|
|
WallSetupLoop(wp, TAG_WALL_LOOP_SPIN_2X, WALLFX_LOOP_SPIN_2X);
|
|
break;
|
|
}
|
|
|
|
case TAG_WALL_LOOP_SPIN_4X:
|
|
{
|
|
WallSetupLoop(wp, TAG_WALL_LOOP_SPIN_4X, WALLFX_LOOP_SPIN_4X);
|
|
break;
|
|
}
|
|
|
|
case TAG_WALL_LOOP_REVERSE_SPIN:
|
|
{
|
|
WallSetupLoop(wp, TAG_WALL_LOOP_REVERSE_SPIN, WALLFX_LOOP_REVERSE_SPIN);
|
|
break;
|
|
}
|
|
|
|
case TAG_WALL_SINE_Y_BEGIN:
|
|
case TAG_WALL_SINE_X_BEGIN:
|
|
{
|
|
short wall_num, cnt, last_wall, num_points, type, tag_end;
|
|
SINE_WALLp sw;
|
|
short range = 250, speed = 3, peak = 0;
|
|
|
|
tag_end = wp->lotag + 2;
|
|
|
|
type = wp->lotag - TAG_WALL_SINE_Y_BEGIN;
|
|
|
|
|
|
// count up num_points
|
|
for (wall_num = i, num_points = 0;
|
|
num_points < MAX_SINE_WALL_POINTS && wall[wall_num].lotag != tag_end;
|
|
wall_num = wall[wall_num].point2, num_points++)
|
|
{
|
|
if (num_points == 0)
|
|
{
|
|
if (wall[wall_num].hitag)
|
|
range = wall[wall_num].hitag;
|
|
}
|
|
else if (num_points == 1)
|
|
{
|
|
if (wall[wall_num].hitag)
|
|
speed = wall[wall_num].hitag;
|
|
}
|
|
else if (num_points == 2)
|
|
{
|
|
if (wall[wall_num].hitag)
|
|
peak = wall[wall_num].hitag;
|
|
}
|
|
}
|
|
|
|
if (peak)
|
|
num_points = peak;
|
|
|
|
for (wall_num = i, cnt = 0;
|
|
cnt < MAX_SINE_WALL_POINTS && wall[wall_num].lotag != tag_end;
|
|
wall_num = wall[wall_num].point2, cnt++)
|
|
{
|
|
// set the first on up
|
|
sw = &SineWall[NextSineWall][cnt];
|
|
|
|
sw->type = type;
|
|
sw->wall = wall_num;
|
|
sw->speed_shift = speed;
|
|
sw->range = range;
|
|
|
|
// don't allow bullet holes/stars
|
|
SET(wall[wall_num].extra, WALLFX_DONT_STICK);
|
|
|
|
if (!sw->type)
|
|
sw->orig_xy = wall[wall_num].y - (sw->range >> 2);
|
|
else
|
|
sw->orig_xy = wall[wall_num].x - (sw->range >> 2);
|
|
|
|
sw->sintable_ndx = cnt * (2048 / num_points);
|
|
}
|
|
|
|
NextSineWall++;
|
|
|
|
ASSERT(NextSineWall < MAX_SINE_WALL);
|
|
|
|
}
|
|
}
|
|
|
|
// this overwrites the lotag so it needs to be called LAST
|
|
SetupWallForBreak(wp);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
SectorLiquidSet(short i)
|
|
{
|
|
SECT_USERp sectu;
|
|
|
|
// ///////////////////////////////////
|
|
//
|
|
// CHECK for pics that mean something
|
|
//
|
|
// ///////////////////////////////////
|
|
|
|
if (sector[i].floorpicnum >= 300 && sector[i].floorpicnum <= 307)
|
|
{
|
|
sectu = GetSectUser(i);
|
|
|
|
SET(sector[i].extra, SECTFX_LIQUID_WATER);
|
|
}
|
|
else if (sector[i].floorpicnum >= 320 && sector[i].floorpicnum <= 343)
|
|
{
|
|
sectu = GetSectUser(i);
|
|
|
|
SET(sector[i].extra, SECTFX_LIQUID_WATER);
|
|
}
|
|
else if (sector[i].floorpicnum >= 780 && sector[i].floorpicnum <= 794)
|
|
{
|
|
sectu = GetSectUser(i);
|
|
|
|
SET(sector[i].extra, SECTFX_LIQUID_WATER);
|
|
}
|
|
else if (sector[i].floorpicnum >= 890 && sector[i].floorpicnum <= 897)
|
|
{
|
|
sectu = GetSectUser(i);
|
|
|
|
SET(sector[i].extra, SECTFX_LIQUID_WATER);
|
|
}
|
|
else if (sector[i].floorpicnum >= 175 && sector[i].floorpicnum <= 182)
|
|
{
|
|
sectu = GetSectUser(i);
|
|
|
|
SET(sector[i].extra, SECTFX_LIQUID_LAVA);
|
|
if (!sectu->damage)
|
|
sectu->damage = 40;
|
|
}
|
|
}
|
|
|
|
void
|
|
SectorSetup(void)
|
|
{
|
|
short i = 0, k, tag;
|
|
short NextSineWave = 0, rotcnt = 0, swingcnt = 0;
|
|
|
|
short startwall, endwall, j, ndx, door_sector;
|
|
|
|
WallSetup();
|
|
|
|
for (ndx = 0; ndx < MAX_SECTOR_OBJECTS; ndx++)
|
|
{
|
|
memset(&SectorObject[ndx], -1, sizeof(SectorObject[0]));
|
|
// 0 pointers
|
|
//memset(&SectorObject[ndx].sectp, NULL, sizeof(SectorObject[0].sectp));
|
|
SectorObject[ndx].PreMoveAnimator = NULL;
|
|
SectorObject[ndx].PostMoveAnimator = NULL;
|
|
SectorObject[ndx].Animator = NULL;
|
|
SectorObject[ndx].controller = NULL;
|
|
SectorObject[ndx].sp_child = NULL;
|
|
SectorObject[ndx].xmid = INT32_MAX;
|
|
}
|
|
|
|
memset(SineWaveFloor, -1, sizeof(SineWaveFloor));
|
|
memset(SpringBoard, -1, sizeof(SpringBoard));
|
|
|
|
LevelSecrets = 0;
|
|
|
|
//for (i = 0; i < MAX_SW_PLAYERS; i++)
|
|
// memset((Player + i)->HasKey, 0, sizeof((Player + i)->HasKey));
|
|
|
|
for (i = 0; i < numsectors; i++)
|
|
{
|
|
tag = LOW_TAG(i);
|
|
|
|
// DOH! NOT AGAIN! :(
|
|
//ASSERT(wall[4568].lotag != 307);
|
|
|
|
// ///////////////////////////////////
|
|
//
|
|
// CHECK for pics that mean something
|
|
//
|
|
// ///////////////////////////////////
|
|
|
|
// ///////////////////////////////////
|
|
//
|
|
// CHECK for flags
|
|
//
|
|
// ///////////////////////////////////
|
|
|
|
if (TEST(sector[i].extra, SECTFX_SINK))
|
|
{
|
|
SectorLiquidSet(i);
|
|
}
|
|
|
|
if (TEST(sector[i].floorstat, FLOOR_STAT_PLAX))
|
|
{
|
|
// don't do a z adjust for FAF area
|
|
if (sector[i].floorpicnum != FAF_PLACE_MIRROR_PIC)
|
|
{
|
|
SET(sector[i].extra, SECTFX_Z_ADJUST);
|
|
}
|
|
}
|
|
|
|
if (TEST(sector[i].ceilingstat, CEILING_STAT_PLAX))
|
|
{
|
|
// don't do a z adjust for FAF area
|
|
if (sector[i].ceilingpicnum != FAF_PLACE_MIRROR_PIC)
|
|
{
|
|
SET(sector[i].extra, SECTFX_Z_ADJUST);
|
|
}
|
|
}
|
|
|
|
// ///////////////////////////////////
|
|
//
|
|
// CHECK for sector/sprite objects
|
|
//
|
|
// ///////////////////////////////////
|
|
|
|
if (tag >= TAG_OBJECT_CENTER && tag < TAG_OBJECT_CENTER + 100)
|
|
{
|
|
SetupSectorObject(i, tag);
|
|
}
|
|
|
|
// ///////////////////////////////////
|
|
//
|
|
// CHECK lo and hi tags
|
|
//
|
|
// ///////////////////////////////////
|
|
|
|
switch (tag)
|
|
{
|
|
case TAG_SECRET_AREA_TRIGGER:
|
|
LevelSecrets++;
|
|
break;
|
|
|
|
case TAG_DOOR_SLIDING:
|
|
SetSectorWallBits(i, WALLFX_DONT_STICK, TRUE, TRUE);
|
|
break;
|
|
|
|
case TAG_SINE_WAVE_FLOOR:
|
|
case TAG_SINE_WAVE_CEILING:
|
|
case TAG_SINE_WAVE_BOTH:
|
|
{
|
|
SINE_WAVE_FLOOR *swf;
|
|
short near_sect = i, base_sect = i;
|
|
uint16_t swf_ndx = 0;
|
|
short cnt = 0, sector_cnt;
|
|
int range;
|
|
int range_diff = 0;
|
|
int wave_diff = 0;
|
|
short peak_dist = 0;
|
|
short speed_shift = 3;
|
|
short num;
|
|
|
|
#define SINE_FLOOR (1<<0)
|
|
#define SINE_CEILING (1<<1)
|
|
|
|
num = (tag - TAG_SINE_WAVE_FLOOR) / 20;
|
|
|
|
// set the first on up
|
|
swf = &SineWaveFloor[NextSineWave][swf_ndx];
|
|
|
|
swf->flags = 0;
|
|
|
|
switch (num)
|
|
{
|
|
case 0:
|
|
SET(swf->flags, SINE_FLOOR);
|
|
#define SINE_SLOPED BIT(3)
|
|
if (TEST(sector[base_sect].floorstat, FLOOR_STAT_SLOPE))
|
|
{
|
|
SET(swf->flags, SINE_SLOPED);
|
|
}
|
|
break;
|
|
case 1:
|
|
SET(swf->flags, SINE_CEILING);
|
|
break;
|
|
case 2:
|
|
SET(swf->flags, SINE_FLOOR | SINE_CEILING);
|
|
break;
|
|
}
|
|
|
|
|
|
swf->sector = near_sect;
|
|
ASSERT(sector[swf->sector].hitag != 0);
|
|
swf->range = range = Z(sector[swf->sector].hitag);
|
|
swf->floor_origz = sector[swf->sector].floorz - (range >> 2);
|
|
swf->ceiling_origz = sector[swf->sector].ceilingz - (range >> 2);
|
|
|
|
// look for the rest by distance
|
|
for (swf_ndx = 1, sector_cnt = 1; TRUE; swf_ndx++)
|
|
{
|
|
// near_sect = FindNextSectorByTag(base_sect,
|
|
// TAG_SINE_WAVE_FLOOR + swf_ndx);
|
|
near_sect = FindNextSectorByTag(base_sect, tag + swf_ndx);
|
|
|
|
if (near_sect >= 0)
|
|
{
|
|
swf = &SineWaveFloor[NextSineWave][swf_ndx];
|
|
|
|
if (swf_ndx == 1 && sector[near_sect].hitag)
|
|
range_diff = sector[near_sect].hitag;
|
|
else if (swf_ndx == 2 && sector[near_sect].hitag)
|
|
speed_shift = sector[near_sect].hitag;
|
|
else if (swf_ndx == 3 && sector[near_sect].hitag)
|
|
peak_dist = sector[near_sect].hitag;
|
|
|
|
swf->sector = near_sect;
|
|
swf->floor_origz = sector[swf->sector].floorz - (range >> 2);
|
|
swf->ceiling_origz = sector[swf->sector].ceilingz - (range >> 2);
|
|
range -= range_diff;
|
|
swf->range = range;
|
|
|
|
base_sect = swf->sector;
|
|
sector_cnt++;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
|
|
ASSERT(swf_ndx <= SIZ(SineWaveFloor[NextSineWave]));
|
|
|
|
// more than 6 waves and something in high tag - set up wave
|
|
// dissapate
|
|
if (sector_cnt > 8 && sector[base_sect].hitag)
|
|
{
|
|
wave_diff = sector[base_sect].hitag;
|
|
}
|
|
|
|
// setup the sintable_ndx based on the actual number of
|
|
// sectors (swf_ndx)
|
|
for (swf = &SineWaveFloor[NextSineWave][0], cnt = 0; swf->sector >= 0 && swf < (SINE_WAVE_FLOORp)&SineWaveFloor[SIZ(SineWaveFloor)]; swf++, cnt++)
|
|
{
|
|
if (peak_dist)
|
|
swf->sintable_ndx = cnt * (2048 / peak_dist);
|
|
else
|
|
swf->sintable_ndx = cnt * (2048 / swf_ndx);
|
|
|
|
swf->speed_shift = speed_shift;
|
|
}
|
|
|
|
// set up the a real wave that dissapates at the end
|
|
if (wave_diff)
|
|
{
|
|
for (cnt = sector_cnt - 1; cnt >= 0; cnt--)
|
|
{
|
|
// only do the last (actually the first) few for the
|
|
// dissapate
|
|
if (cnt > 8)
|
|
continue;
|
|
|
|
swf = &SineWaveFloor[NextSineWave][cnt];
|
|
|
|
swf->range -= wave_diff;
|
|
|
|
wave_diff += wave_diff;
|
|
|
|
if (swf->range < Z(4))
|
|
swf->range = Z(4);
|
|
|
|
// reset origz's based on new range
|
|
swf->floor_origz = sector[swf->sector].floorz - (swf->range >> 2);
|
|
swf->ceiling_origz = sector[swf->sector].ceilingz - (swf->range >> 2);
|
|
}
|
|
}
|
|
|
|
NextSineWave++;
|
|
|
|
ASSERT(NextSineWave < MAX_SINE_WAVE);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SectorMidPoint(short sectnum, int *xmid, int *ymid, int *zmid)
|
|
{
|
|
short startwall, endwall, j;
|
|
int xsum = 0, ysum = 0;
|
|
WALLp wp;
|
|
|
|
startwall = sector[sectnum].wallptr;
|
|
endwall = startwall + sector[sectnum].wallnum - 1;
|
|
|
|
for (wp = &wall[startwall], j = startwall; j <= endwall; wp++, j++)
|
|
{
|
|
xsum += wp->x;
|
|
ysum += wp->y;
|
|
}
|
|
|
|
*xmid = xsum / (endwall - startwall + 1);
|
|
*ymid = ysum / (endwall - startwall + 1);
|
|
|
|
*zmid = DIV2(sector[sectnum].floorz + sector[sectnum].ceilingz);
|
|
}
|
|
|
|
|
|
void
|
|
DoSpringBoard(PLAYERp pp, short sectnum)
|
|
{
|
|
int sb;
|
|
int i;
|
|
|
|
#if 0
|
|
i = AnimGetGoal(§or[sectnum].floorz);
|
|
|
|
// if in motion return
|
|
if (i >= 0)
|
|
return;
|
|
|
|
AnimSet(§or[sectnum].floorz, sector[sectnum].floorz - Z(32), 512);
|
|
|
|
for (sb = 0; sb < SIZ(SpringBoard); sb++)
|
|
{
|
|
// if empty set up an entry to close the sb later
|
|
if (SpringBoard[sb].Sector == -1)
|
|
{
|
|
pp->jump_speed = -sector[pp->cursectnum].hitag;
|
|
DoPlayerBeginForceJump(pp);
|
|
|
|
SpringBoard[sb].Sector = sectnum;
|
|
SpringBoard[sb].TimeOut = 1 * 120;
|
|
|
|
sector[sectnum].lotag = 0;
|
|
}
|
|
}
|
|
#else
|
|
pp->jump_speed = -sector[pp->cursectnum].hitag;
|
|
DoPlayerBeginForceJump(pp);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
DoSpringBoardDown(void)
|
|
{
|
|
unsigned sb;
|
|
SPRING_BOARD *sbp;
|
|
|
|
for (sb = 0; sb < SIZ(SpringBoard); sb++)
|
|
{
|
|
sbp = &SpringBoard[sb];
|
|
|
|
// if empty set up an entry to close the sb later
|
|
if (sbp->Sector != -1)
|
|
{
|
|
if ((sbp->TimeOut -= synctics) <= 0)
|
|
{
|
|
int destz;
|
|
|
|
destz = sector[nextsectorneighborz(sbp->Sector, sector[sbp->Sector].floorz, 1, 1)].floorz;
|
|
|
|
AnimSet(§or[sbp->Sector].floorz, destz, 256);
|
|
|
|
sector[sbp->Sector].lotag = TAG_SPRING_BOARD;
|
|
|
|
sbp->Sector = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
short
|
|
FindSectorByTag(int x, int y, int tag)
|
|
{
|
|
short i = 0, near_sector = -1;
|
|
int diff, near_diff = 9999999;
|
|
short wallnum;
|
|
|
|
for (i = 0; i < numsectors; i++)
|
|
{
|
|
if (LOW_TAG(i) == tag)
|
|
{
|
|
// get the delta of the door/elevator
|
|
wallnum = sector[i].wallptr;
|
|
|
|
// diff = labs(wall[wallnum].x - x) + labs(wall[wallnum].y - y);
|
|
diff = Distance(wall[wallnum].x, wall[wallnum].y, x, y);
|
|
|
|
// if the door/elevator is closer than the last save it off
|
|
if (diff < near_diff)
|
|
{
|
|
near_diff = diff;
|
|
near_sector = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return near_sector;
|
|
|
|
}
|
|
|
|
short
|
|
FindSectorByTag_Wall(short wallnum, int tag)
|
|
{
|
|
return FindSectorByTag(wall[wallnum].x, wall[wallnum].y, tag);
|
|
}
|
|
|
|
short
|
|
FindSectorByTag_Sprite(short SpriteNum, int tag)
|
|
{
|
|
return FindSectorByTag(sprite[SpriteNum].x, sprite[SpriteNum].y, tag);
|
|
}
|
|
|
|
#if 1
|
|
short
|
|
FindSectorMidByTag(short sectnum, int tag)
|
|
{
|
|
short i = 0, near_sector = -1;
|
|
int diff, near_diff = 9999999, x, y;
|
|
int trash, fx, fy;
|
|
|
|
// Get the mid x,y of the sector
|
|
SectorMidPoint(sectnum, &x, &y, &trash);
|
|
|
|
for (i = 0; i < numsectors; i++)
|
|
{
|
|
if (sector[i].lotag == tag)
|
|
{
|
|
// get the delta of the door/elevator
|
|
SectorMidPoint(i, &fx, &fy, &trash);
|
|
|
|
// diff = labs(wall[wallnum].x - x) + labs(wall[wallnum].y - y);
|
|
diff = Distance(fx, fy, x, y);
|
|
|
|
// if the door/elevator is closer than the last save it off
|
|
if (diff < near_diff)
|
|
{
|
|
near_diff = diff;
|
|
near_sector = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return near_sector;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
short
|
|
FindNextSectorByTag(short sectnum, int tag)
|
|
{
|
|
short next_sectnum, startwall, endwall, j;
|
|
|
|
startwall = sector[sectnum].wallptr;
|
|
endwall = startwall + sector[sectnum].wallnum - 1;
|
|
|
|
for (j = startwall; j <= endwall; j++)
|
|
{
|
|
next_sectnum = wall[j].nextsector;
|
|
|
|
if (next_sectnum >= 0)
|
|
{
|
|
if (sector[next_sectnum].lotag == tag)
|
|
{
|
|
return next_sectnum;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
int
|
|
SectorDistance(short sect1, int sect2)
|
|
{
|
|
short wallnum1, wallnum2;
|
|
|
|
if (sect1 < 0 || sect2 < 0)
|
|
return 9999999;
|
|
|
|
wallnum1 = sector[sect1].wallptr;
|
|
wallnum2 = sector[sect2].wallptr;
|
|
|
|
// return the distance between the two sectors.
|
|
return Distance(wall[wallnum1].x, wall[wallnum1].y, wall[wallnum2].x, wall[wallnum2].y);
|
|
}
|
|
|
|
|
|
int
|
|
SectorDistanceByMid(short sect1, int sect2)
|
|
{
|
|
int sx1, sy1, sx2, sy2, trash;
|
|
|
|
SectorMidPoint(sect1, &sx1, &sy1, &trash);
|
|
SectorMidPoint(sect2, &sx2, &sy2, &trash);
|
|
|
|
// return the distance between the two sectors.
|
|
return Distance(sx1, sy1, sx2, sy2);
|
|
}
|
|
|
|
short
|
|
DoSpawnActorTrigger(short match)
|
|
{
|
|
int i, nexti, pnum;
|
|
short spawn_count = 0, hidden;
|
|
SPRITEp sp;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_SPAWN_TRIGGER], i, nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
|
|
if (sp->hitag == match)
|
|
{
|
|
if (ActorSpawn(sp))
|
|
{
|
|
DoSpawnTeleporterEffectPlace(sp);
|
|
PlaySound(DIGI_PLAYER_TELEPORT, sp, v3df_none);
|
|
spawn_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return spawn_count;
|
|
}
|
|
|
|
int
|
|
OperateSector(short sectnum, short player_is_operating)
|
|
{
|
|
PLAYERp pp = GlobPlayerP;
|
|
|
|
// Don't let actors operate locked or secret doors
|
|
if (!player_is_operating)
|
|
{
|
|
SPRITEp fsp;
|
|
short match;
|
|
short i,nexti;
|
|
|
|
|
|
if (SectUser[sectnum] && SectUser[sectnum]->stag == SECT_LOCK_DOOR)
|
|
return FALSE;
|
|
|
|
TRAVERSE_SPRITE_SECT(headspritesect[sectnum], i, nexti)
|
|
{
|
|
fsp = &sprite[i];
|
|
|
|
if (SectUser[fsp->sectnum] && SectUser[fsp->sectnum]->stag == SECT_LOCK_DOOR)
|
|
return FALSE;
|
|
|
|
if (fsp->statnum == STAT_VATOR && SP_TAG1(fsp) == SECT_VATOR && TEST_BOOL7(fsp))
|
|
return FALSE;
|
|
if (fsp->statnum == STAT_ROTATOR && SP_TAG1(fsp) == SECT_ROTATOR && TEST_BOOL7(fsp))
|
|
return FALSE;
|
|
if (fsp->statnum == STAT_SLIDOR && SP_TAG1(fsp) == SECT_SLIDOR && TEST_BOOL7(fsp))
|
|
return FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
//CON_Message("Operating sectnum %d",sectnum);
|
|
//CON_Message("stag = %d, lock = %d",SectUser[sectnum]->stag,SECT_LOCK_DOOR);
|
|
|
|
switch (LOW_TAG(sectnum))
|
|
{
|
|
|
|
case TAG_VATOR:
|
|
DoVatorOperate(pp, sectnum);
|
|
return TRUE;
|
|
|
|
case TAG_ROTATOR:
|
|
DoRotatorOperate(pp, sectnum);
|
|
return TRUE;
|
|
|
|
case TAG_SLIDOR:
|
|
DoSlidorOperate(pp, sectnum);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
int
|
|
OperateWall(short wallnum, short player_is_operating)
|
|
{
|
|
WALLp wallp = &wall[wallnum];
|
|
|
|
/*
|
|
switch (LOW_TAG_WALL(wallnum))
|
|
{
|
|
}
|
|
*/
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
short
|
|
AnimateSwitch(SPRITEp sp, short tgt_value)
|
|
{
|
|
#define SWITCH_LEVER 581
|
|
#define SWITCH_FUSE 558
|
|
#define SWITCH_FLIP 561
|
|
#define SWITCH_RED_CHAIN 563
|
|
#define SWITCH_GREEN_CHAIN 565
|
|
#define SWITCH_TOUCH 567
|
|
#define SWITCH_DRAGON 569
|
|
|
|
#define SWITCH_LIGHT 551
|
|
#define SWITCH_1 575
|
|
#define SWITCH_3 579
|
|
|
|
#define SWITCH_SHOOTABLE_1 577
|
|
#define SWITCH_4 571
|
|
#define SWITCH_5 573
|
|
#define SWITCH_6 583
|
|
#define EXIT_SWITCH 2470
|
|
|
|
#define SWITCH_SKULL 553
|
|
|
|
// if the value is not ON or OFF
|
|
// then it is a straight toggle
|
|
|
|
switch (sp->picnum)
|
|
{
|
|
// set to TRUE/ON
|
|
case SWITCH_SKULL:
|
|
case SWITCH_LEVER:
|
|
case SWITCH_LIGHT:
|
|
case SWITCH_SHOOTABLE_1:
|
|
case SWITCH_1:
|
|
case SWITCH_3:
|
|
case SWITCH_FLIP:
|
|
case SWITCH_RED_CHAIN:
|
|
case SWITCH_GREEN_CHAIN:
|
|
case SWITCH_TOUCH:
|
|
case SWITCH_DRAGON:
|
|
case SWITCH_4:
|
|
case SWITCH_5:
|
|
case SWITCH_6:
|
|
case EXIT_SWITCH:
|
|
|
|
// dont toggle - return the current state
|
|
if (tgt_value == 999)
|
|
return OFF;
|
|
|
|
sp->picnum += 1;
|
|
|
|
// if the tgt_value should be true
|
|
// flip it again - recursive but only once
|
|
if (tgt_value == OFF)
|
|
{
|
|
AnimateSwitch(sp, tgt_value);
|
|
return OFF;
|
|
}
|
|
|
|
return ON;
|
|
|
|
// set to true
|
|
case SWITCH_SKULL + 1:
|
|
case SWITCH_LEVER + 1:
|
|
case SWITCH_LIGHT + 1:
|
|
case SWITCH_1 + 1:
|
|
case SWITCH_3 + 1:
|
|
case SWITCH_FLIP + 1:
|
|
case SWITCH_RED_CHAIN + 1:
|
|
case SWITCH_GREEN_CHAIN + 1:
|
|
case SWITCH_TOUCH + 1:
|
|
case SWITCH_DRAGON + 1:
|
|
case SWITCH_SHOOTABLE_1 + 1:
|
|
case SWITCH_4+1:
|
|
case SWITCH_5+1:
|
|
case SWITCH_6+1:
|
|
case EXIT_SWITCH+1:
|
|
|
|
// dont toggle - return the current state
|
|
if (tgt_value == 999)
|
|
return ON;
|
|
|
|
sp->picnum -= 1;
|
|
|
|
if (tgt_value == ON)
|
|
{
|
|
AnimateSwitch(sp, tgt_value);
|
|
return ON;
|
|
}
|
|
|
|
return OFF;
|
|
}
|
|
return OFF;
|
|
}
|
|
|
|
|
|
void
|
|
SectorExp(short SpriteNum, short sectnum, short orig_ang, int zh)
|
|
{
|
|
SPRITEp sp = &sprite[SpriteNum];
|
|
USERp u = User[SpriteNum];
|
|
SECT_USERp sectu = SectUser[sectnum];
|
|
SECTORp sectp = §or[sectnum];
|
|
short explosion;
|
|
SPRITEp exp;
|
|
USERp eu;
|
|
int x,y,z;
|
|
|
|
RESET(sp->cstat, CSTAT_SPRITE_ALIGNMENT_WALL|CSTAT_SPRITE_ALIGNMENT_FLOOR);
|
|
SectorMidPoint(sectnum, &x, &y, &z);
|
|
sp->ang = orig_ang;
|
|
sp->x = x;
|
|
sp->y = y;
|
|
sp->z = z;
|
|
|
|
// randomize the explosions
|
|
sp->ang += RANDOM_P2(256) - 128;
|
|
sp->x += RANDOM_P2(1024) - 512;
|
|
sp->y += RANDOM_P2(1024) - 512;
|
|
sp->z = zh;
|
|
|
|
// setup vars needed by SectorExp
|
|
changespritesect(SpriteNum, sectnum);
|
|
//setspritez(SpriteNum, (vec3_t *)sp);
|
|
getzsofslope(sp->sectnum, sp->x, sp->y, &u->hiz, &u->loz);
|
|
|
|
// spawn explosion
|
|
explosion = SpawnSectorExp(SpriteNum);
|
|
ASSERT(explosion >= 0);
|
|
exp = &sprite[explosion];
|
|
eu = User[explosion];
|
|
|
|
exp->xrepeat += (RANDOM_P2(32<<8)>>8) - 16;
|
|
exp->yrepeat += (RANDOM_P2(32<<8)>>8) - 16;
|
|
eu->xchange = MOVEx(92, exp->ang);
|
|
eu->ychange = MOVEy(92, exp->ang);
|
|
}
|
|
|
|
|
|
void
|
|
DoExplodeSector(short match)
|
|
{
|
|
short orig_ang;
|
|
int zh;
|
|
USERp u;
|
|
short cf,nextcf;
|
|
short ed,nexted;
|
|
|
|
int ss, nextss;
|
|
SECTORp dsectp, ssectp;
|
|
SPRITEp src_sp, dest_sp;
|
|
|
|
SPRITEp esp;
|
|
SECTORp sectp;
|
|
|
|
orig_ang = 0; //sp->ang;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_EXPLODING_CEIL_FLOOR], cf, nextcf)
|
|
{
|
|
esp = &sprite[cf];
|
|
|
|
if (match != esp->lotag)
|
|
continue;
|
|
|
|
if (!User[cf])
|
|
u = SpawnUser(cf, 0, NULL);
|
|
|
|
sectp = §or[esp->sectnum];
|
|
|
|
sectp->ceilingz -= Z(SP_TAG4(esp));
|
|
|
|
if (SP_TAG5(esp))
|
|
{
|
|
sectp->floorheinum = SP_TAG5(esp);
|
|
SET(sectp->floorstat, FLOOR_STAT_SLOPE);
|
|
}
|
|
|
|
if (SP_TAG6(esp))
|
|
{
|
|
sectp->ceilingheinum = SP_TAG6(esp);
|
|
SET(sectp->ceilingstat, CEILING_STAT_SLOPE);
|
|
}
|
|
|
|
for (zh = sectp->ceilingz; zh < sectp->floorz; zh += Z(60))
|
|
{
|
|
SectorExp(cf, esp->sectnum, orig_ang, zh + Z(RANDOM_P2(64)) - Z(32));
|
|
}
|
|
|
|
// don't need it any more
|
|
KillSprite(cf);
|
|
}
|
|
}
|
|
|
|
|
|
int DoSpawnSpot(short SpriteNum)
|
|
{
|
|
USERp u = User[SpriteNum];
|
|
SPRITEp sp = u->SpriteP;
|
|
|
|
if ((u->WaitTics -= synctics) < 0)
|
|
{
|
|
change_sprite_stat(SpriteNum, STAT_SPAWN_SPOT);
|
|
SpawnShrap(SpriteNum, -1);
|
|
|
|
if (u->LastDamage == 1)
|
|
{
|
|
KillSprite(SpriteNum);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// spawns shrap when killing an object
|
|
void
|
|
DoSpawnSpotsForKill(short match)
|
|
{
|
|
short sn, next_sn;
|
|
SPRITEp sp;
|
|
USERp u;
|
|
|
|
if (match < 0)
|
|
return;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_SPAWN_SPOT], sn, next_sn)
|
|
{
|
|
sp = &sprite[sn];
|
|
|
|
// change the stat num and set the delay correctly to call SpawnShrap
|
|
if (sp->hitag == SPAWN_SPOT && sp->lotag == match)
|
|
{
|
|
u = User[sn];
|
|
change_sprite_stat(sn, STAT_NO_STATE);
|
|
u->ActorActionFunc = DoSpawnSpot;
|
|
u->WaitTics = SP_TAG5(sp) * 15;
|
|
setspritez(sn, (vec3_t *)sp);
|
|
// setting for Killed
|
|
u->LastDamage = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// spawns shrap when damaging an object
|
|
void
|
|
DoSpawnSpotsForDamage(short match)
|
|
{
|
|
short sn, next_sn;
|
|
SPRITEp sp;
|
|
USERp u;
|
|
|
|
if (match < 0)
|
|
return;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_SPAWN_SPOT], sn, next_sn)
|
|
{
|
|
sp = &sprite[sn];
|
|
|
|
// change the stat num and set the delay correctly to call SpawnShrap
|
|
|
|
if (sp->hitag == SPAWN_SPOT && sp->lotag == match)
|
|
{
|
|
u = User[sn];
|
|
change_sprite_stat(sn, STAT_NO_STATE);
|
|
u->ActorActionFunc = DoSpawnSpot;
|
|
u->WaitTics = SP_TAG7(sp) * 15;
|
|
// setting for Damaged
|
|
u->LastDamage = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DoSoundSpotMatch(short match, short sound_num, short sound_type)
|
|
{
|
|
short sn, next_sn;
|
|
SPRITEp sp;
|
|
int flags;
|
|
short snd2play;
|
|
|
|
//sound_type is not used
|
|
|
|
sound_num--;
|
|
|
|
ASSERT(sound_num >= 0);
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_SOUND_SPOT], sn, next_sn)
|
|
{
|
|
sp = &sprite[sn];
|
|
|
|
if (SP_TAG2(sp) == match && !TEST_BOOL6(sp))
|
|
{
|
|
short snd[3];
|
|
|
|
snd[0] = SP_TAG13(sp); // tag4 is copied to tag13
|
|
snd[1] = SP_TAG5(sp);
|
|
snd[2] = SP_TAG6(sp);
|
|
|
|
snd2play = 0;
|
|
flags = 0;
|
|
|
|
if (TEST_BOOL2(sp))
|
|
flags = v3df_follow|v3df_nolookup|v3df_init;
|
|
|
|
// play once and only once
|
|
if (TEST_BOOL1(sp))
|
|
SET_BOOL6(sp);
|
|
|
|
// don't pan
|
|
if (TEST_BOOL4(sp))
|
|
flags |= v3df_dontpan;
|
|
// add doppler
|
|
if (TEST_BOOL5(sp))
|
|
flags |= v3df_doppler;
|
|
// random
|
|
if (TEST_BOOL3(sp))
|
|
{
|
|
if (snd[0] && snd[1])
|
|
{
|
|
snd2play = snd[RANDOM_RANGE(2)];
|
|
}
|
|
else if (snd[0] && snd[1] && snd[2])
|
|
{
|
|
snd2play = snd[RANDOM_RANGE(3)];
|
|
}
|
|
}
|
|
else if (snd[sound_num])
|
|
{
|
|
snd2play = snd[sound_num];
|
|
}
|
|
|
|
if (snd2play <= 0)
|
|
continue;
|
|
|
|
if (TEST_BOOL7(sp))
|
|
{
|
|
PLAYERp pp = GlobPlayerP;
|
|
|
|
////DSPRINTF(ds,"PlayerSound %d",pp-Player);
|
|
//MONO_PRINT(ds);
|
|
//ASSERT(pp >= Player && pp <= Player+numplayers);
|
|
|
|
if (pp)
|
|
{
|
|
if (pp == Player+myconnectindex)
|
|
PlayerSound(snd2play, v3df_dontpan|v3df_follow,pp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PlaySound(snd2play, sp, flags);
|
|
|
|
//if (TEST(flags, v3df_follow)) // Just set it anyway
|
|
Set3DSoundOwner(sn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DoSoundSpotStopSound(short match)
|
|
{
|
|
short sn, next_sn;
|
|
SPRITEp sp;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_SOUND_SPOT], sn, next_sn)
|
|
{
|
|
sp = &sprite[sn];
|
|
|
|
// found match and is a follow type
|
|
if (SP_TAG2(sp) == match && TEST_BOOL2(sp))
|
|
{
|
|
DeleteNoSoundOwner(sn);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DoStopSoundSpotMatch(short match)
|
|
{
|
|
short sn, next_sn;
|
|
SPRITEp sp;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_STOP_SOUND_SPOT], sn, next_sn)
|
|
{
|
|
sp = &sprite[sn];
|
|
|
|
if (SP_TAG2(sp) == match)
|
|
{
|
|
DoSoundSpotStopSound(SP_TAG5(sp));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
SWBOOL TestKillSectorObject(SECTOR_OBJECTp sop)
|
|
{
|
|
if (TEST(sop->flags, SOBJ_KILLABLE))
|
|
{
|
|
KillMatchingCrackSprites(sop->match_event);
|
|
// get new sectnums
|
|
CollapseSectorObject(sop, sop->xmid, sop->ymid);
|
|
DoSpawnSpotsForKill(sop->match_event);
|
|
KillSectorObjectSprites(sop);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
short
|
|
DoSectorObjectKillMatch(short match)
|
|
{
|
|
SECTOR_OBJECTp sop;
|
|
|
|
for (sop = SectorObject; sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++)
|
|
{
|
|
if (sop->xmid == INT32_MAX)
|
|
continue;
|
|
|
|
if (sop->match_event == match)
|
|
return TestKillSectorObject(sop);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
SWBOOL
|
|
SearchExplodeSectorMatch(short match)
|
|
{
|
|
short i,nexti;
|
|
|
|
// THIS IS ONLY CALLED FROM DoMatchEverything
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_SPRITE_HIT_MATCH], i, nexti)
|
|
{
|
|
SPRITEp sp = &sprite[i];
|
|
|
|
if (sp->hitag == match)
|
|
{
|
|
KillMatchingCrackSprites(match);
|
|
DoExplodeSector(match);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
KillMatchingCrackSprites(short match)
|
|
{
|
|
short i,nexti;
|
|
SPRITEp sp;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_SPRITE_HIT_MATCH], i, nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
|
|
if (sp->hitag == match)
|
|
{
|
|
if (TEST(SP_TAG8(sp), BIT(2)))
|
|
continue;
|
|
|
|
KillSprite(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
WeaponExplodeSectorInRange(short weapon)
|
|
{
|
|
short i, nexti;
|
|
SPRITEp wp = &sprite[weapon];
|
|
USERp wu = User[weapon];
|
|
SPRITEp sp;
|
|
int dist;
|
|
int radius;
|
|
short match;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_SPRITE_HIT_MATCH], i, nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
|
|
// test to see if explosion is close to crack sprite
|
|
dist = FindDistance3D(wp->x - sp->x, wp->y - sp->y, (wp->z - sp->z)>>4);
|
|
|
|
if (sp->clipdist == 0)
|
|
continue;
|
|
|
|
radius = (((int)sp->clipdist) << 2) * 8;
|
|
|
|
if ((unsigned int)dist > (wu->Radius/2) + radius)
|
|
continue;
|
|
|
|
if (!FAFcansee(wp->x,wp->y,wp->z,wp->sectnum,sp->x,sp->y,sp->z,sp->sectnum))
|
|
continue;
|
|
|
|
match = sp->hitag;
|
|
// this and every other crack sprite of this type is now dead
|
|
// don't use them
|
|
#if 0
|
|
KillMatchingCrackSprites(match);
|
|
DoExplodeSector(match);
|
|
DoMatchEverything(NULL, match, -1);
|
|
#else
|
|
// pass in explosion type
|
|
MissileHitMatch(weapon, WPN_ROCKET, i);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ShootableSwitch(short SpriteNum, short Weapon)
|
|
{
|
|
SPRITEp sp = &sprite[SpriteNum];
|
|
|
|
switch (sp->picnum)
|
|
{
|
|
case SWITCH_SHOOTABLE_1:
|
|
//RESET(sp->cstat, CSTAT_SPRITE_BLOCK | CSTAT_SPRITE_BLOCK_HITSCAN);
|
|
OperateSprite(SpriteNum, FALSE);
|
|
sp->picnum = SWITCH_SHOOTABLE_1 + 1;
|
|
break;
|
|
case SWITCH_FUSE:
|
|
case SWITCH_FUSE + 1:
|
|
RESET(sp->cstat, CSTAT_SPRITE_BLOCK | CSTAT_SPRITE_BLOCK_HITSCAN);
|
|
OperateSprite(SpriteNum, FALSE);
|
|
sp->picnum = SWITCH_FUSE + 2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void DoDeleteSpriteMatch(short match)
|
|
{
|
|
static short StatList[] =
|
|
{
|
|
STAT_DEFAULT,
|
|
STAT_VATOR,
|
|
STAT_SPIKE,
|
|
STAT_TRAP,
|
|
STAT_ITEM,
|
|
STAT_LIGHTING,
|
|
STAT_STATIC_FIRE,
|
|
STAT_AMBIENT,
|
|
STAT_FAF
|
|
};
|
|
|
|
int del_x = 0,del_y = 0;
|
|
short i,nexti;
|
|
unsigned stat;
|
|
short found;
|
|
|
|
while (TRUE)
|
|
{
|
|
found = -1;
|
|
|
|
// search for a DELETE_SPRITE with same match tag
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_DELETE_SPRITE], i, nexti)
|
|
{
|
|
if (sprite[i].lotag == match)
|
|
{
|
|
found = i;
|
|
del_x = sprite[i].x;
|
|
del_y = sprite[i].y;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found == -1)
|
|
return;
|
|
|
|
for (stat = 0; stat < SIZ(StatList); stat++)
|
|
{
|
|
TRAVERSE_SPRITE_STAT(headspritestat[StatList[stat]], i, nexti)
|
|
{
|
|
if (del_x == sprite[i].x && del_y == sprite[i].y)
|
|
{
|
|
// special case lighting delete of Fade On/off after fades
|
|
if (StatList[stat] == STAT_LIGHTING)
|
|
{
|
|
// set shade to darkest and then kill it
|
|
sprite[i].shade = SPRITE_TAG6(i);
|
|
sprite[i].pal = 0;
|
|
SectorLightShade(&sprite[i], sprite[i].shade);
|
|
DiffuseLighting(&sprite[i]);
|
|
}
|
|
|
|
////DSPRINTF(ds,"Delete Sprite stat %d, x %d, y %d",sprite[i].statnum, sprite[i].x, sprite[i].y);
|
|
//MONO_PRINT(ds);
|
|
SpriteQueueDelete(i);
|
|
KillSprite(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// kill the DELETE_SPRITE
|
|
KillSprite(found);
|
|
}
|
|
}
|
|
|
|
void
|
|
DoChangorMatch(short match)
|
|
{
|
|
short sn, next_sn;
|
|
SPRITEp sp;
|
|
SECTORp sectp;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_CHANGOR], sn, next_sn)
|
|
{
|
|
sp = &sprite[sn];
|
|
sectp = §or[sp->sectnum];
|
|
|
|
if (SP_TAG2(sp) != match)
|
|
continue;
|
|
|
|
if (TEST_BOOL1(sp))
|
|
{
|
|
sectp->ceilingpicnum = SP_TAG4(sp);
|
|
sectp->ceilingz += Z(SP_TAG5(sp));
|
|
sectp->ceilingheinum += SP_TAG6(sp);
|
|
|
|
if (sectp->ceilingheinum)
|
|
SET(sectp->ceilingstat, CEILING_STAT_SLOPE);
|
|
else
|
|
RESET(sectp->ceilingstat, CEILING_STAT_SLOPE);
|
|
|
|
sectp->ceilingshade += SP_TAG7(sp);
|
|
sectp->ceilingpal += SP_TAG8(sp);
|
|
}
|
|
else
|
|
{
|
|
sectp->floorpicnum = SP_TAG4(sp);
|
|
sectp->floorz += Z(SP_TAG5(sp));
|
|
sectp->floorheinum += SP_TAG6(sp);
|
|
|
|
if (sectp->floorheinum)
|
|
SET(sectp->floorstat, FLOOR_STAT_SLOPE);
|
|
else
|
|
RESET(sectp->floorstat, FLOOR_STAT_SLOPE);
|
|
|
|
sectp->floorshade += SP_TAG7(sp);
|
|
sectp->floorpal += SP_TAG8(sp);
|
|
}
|
|
|
|
sectp->visibility += SP_TAG9(sp);
|
|
|
|
// if not set then go ahead and kill it
|
|
if (TEST_BOOL2(sp) == 0)
|
|
{
|
|
KillSprite(sn);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DoMatchEverything(PLAYERp pp, short match, short state)
|
|
{
|
|
PLAYERp bak;
|
|
|
|
bak = GlobPlayerP;
|
|
GlobPlayerP = pp;
|
|
// CAREFUL! pp == NULL is a valid case for this routine
|
|
DoStopSoundSpotMatch(match);
|
|
DoSoundSpotMatch(match, 1, SOUND_EVERYTHING_TYPE);
|
|
GlobPlayerP = bak;
|
|
|
|
DoLightingMatch(match, state);
|
|
|
|
DoQuakeMatch(match);
|
|
|
|
// make sure all vators are inactive before allowing
|
|
// to repress switch
|
|
if (!TestVatorMatchActive(match))
|
|
DoVatorMatch(pp, match);
|
|
|
|
if (!TestSpikeMatchActive(match))
|
|
DoSpikeMatch(pp, match);
|
|
|
|
if (!TestRotatorMatchActive(match))
|
|
DoRotatorMatch(pp, match, FALSE);
|
|
|
|
if (!TestSlidorMatchActive(match))
|
|
DoSlidorMatch(pp, match, FALSE);
|
|
|
|
DoSectorObjectKillMatch(match);
|
|
DoSectorObjectSetScale(match);
|
|
|
|
DoSOevent(match, state);
|
|
DoSpawnActorTrigger(match);
|
|
|
|
// this may or may not find an exploding sector
|
|
SearchExplodeSectorMatch(match);
|
|
|
|
CopySectorMatch(match);
|
|
DoWallMoveMatch(match);
|
|
DoSpawnSpotsForKill(match);
|
|
|
|
DoTrapReset(match);
|
|
DoTrapMatch(match);
|
|
|
|
SpawnItemsMatch(match);
|
|
DoChangorMatch(match);
|
|
DoDeleteSpriteMatch(match);
|
|
}
|
|
|
|
SWBOOL ComboSwitchTest(short combo_type, short match)
|
|
{
|
|
short i,nexti;
|
|
SPRITEp sp;
|
|
SWBOOL state;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_DEFAULT], i, nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
|
|
if (sp->lotag == combo_type && sp->hitag == match)
|
|
{
|
|
// dont toggle - get the current state
|
|
state = AnimateSwitch(sp, 999);
|
|
|
|
// if any one is not set correctly then switch is not set
|
|
if (state != SP_TAG3(sp))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// NOTE: switches are always wall sprites
|
|
int
|
|
OperateSprite(short SpriteNum, short player_is_operating)
|
|
{
|
|
SPRITEp sp = &sprite[SpriteNum];
|
|
USERp u = User[SpriteNum];
|
|
PLAYERp pp = NULL;
|
|
short state;
|
|
short key_num=0;
|
|
extern STATE s_Pachinko1Operate[];
|
|
extern STATE s_Pachinko2Operate[];
|
|
extern STATE s_Pachinko3Operate[];
|
|
extern STATE s_Pachinko4Operate[];
|
|
|
|
if (Prediction)
|
|
return FALSE;
|
|
|
|
if (sp->picnum == ST1)
|
|
return FALSE;
|
|
|
|
if (player_is_operating)
|
|
{
|
|
pp = GlobPlayerP;
|
|
|
|
if (!FAFcansee(pp->posx, pp->posy, pp->posz, pp->cursectnum, sp->x, sp->y, sp->z - DIV2(SPRITEp_SIZE_Z(sp)), sp->sectnum))
|
|
return FALSE;
|
|
}
|
|
|
|
switch (sp->lotag)
|
|
{
|
|
case TOILETGIRL_R0:
|
|
case WASHGIRL_R0:
|
|
case CARGIRL_R0:
|
|
case MECHANICGIRL_R0:
|
|
case SAILORGIRL_R0:
|
|
case PRUNEGIRL_R0:
|
|
//if(RANDOM_RANGE(1000) < 500) return(TRUE);
|
|
//if(u->FlagOwner == 0)
|
|
{
|
|
short choose_snd;
|
|
|
|
u->FlagOwner = 1;
|
|
u->WaitTics = SEC(4);
|
|
|
|
if (pp != Player+myconnectindex) return TRUE;
|
|
|
|
choose_snd = STD_RANDOM_RANGE(1000);
|
|
if (sp->lotag == CARGIRL_R0)
|
|
{
|
|
if (choose_snd > 700)
|
|
PlayerSound(DIGI_JG44052, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 500)
|
|
PlayerSound(DIGI_JG45014, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 250)
|
|
PlayerSound(DIGI_JG44068, v3df_dontpan|v3df_follow,pp);
|
|
else
|
|
PlayerSound(DIGI_JG45010, v3df_dontpan|v3df_follow,pp);
|
|
}
|
|
else if (sp->lotag == MECHANICGIRL_R0)
|
|
{
|
|
if (choose_snd > 700)
|
|
PlayerSound(DIGI_JG44027, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 500)
|
|
PlayerSound(DIGI_JG44038, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 250)
|
|
PlayerSound(DIGI_JG44039, v3df_dontpan|v3df_follow,pp);
|
|
else
|
|
PlayerSound(DIGI_JG44048, v3df_dontpan|v3df_follow,pp);
|
|
}
|
|
else if (sp->lotag == SAILORGIRL_R0)
|
|
{
|
|
if (choose_snd > 700)
|
|
PlayerSound(DIGI_JG45018, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 500)
|
|
PlayerSound(DIGI_JG45030, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 250)
|
|
PlayerSound(DIGI_JG45033, v3df_dontpan|v3df_follow,pp);
|
|
else
|
|
PlayerSound(DIGI_JG45043, v3df_dontpan|v3df_follow,pp);
|
|
}
|
|
else if (sp->lotag == PRUNEGIRL_R0)
|
|
{
|
|
if (choose_snd > 700)
|
|
PlayerSound(DIGI_JG45053, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 500)
|
|
PlayerSound(DIGI_JG45067, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 250)
|
|
PlayerSound(DIGI_JG46005, v3df_dontpan|v3df_follow,pp);
|
|
else
|
|
PlayerSound(DIGI_JG46010, v3df_dontpan|v3df_follow,pp);
|
|
}
|
|
else if (sp->lotag == TOILETGIRL_R0)
|
|
{
|
|
if (choose_snd > 700)
|
|
PlayerSound(DIGI_WHATYOUEATBABY, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 500)
|
|
PlayerSound(DIGI_WHATDIEDUPTHERE, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 250)
|
|
PlayerSound(DIGI_YOUGOPOOPOO, v3df_dontpan|v3df_follow,pp);
|
|
else
|
|
PlayerSound(DIGI_PULLMYFINGER, v3df_dontpan|v3df_follow,pp);
|
|
}
|
|
else
|
|
{
|
|
if (choose_snd > 700)
|
|
PlayerSound(DIGI_SOAPYOUGOOD, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 500)
|
|
PlayerSound(DIGI_WASHWANG, v3df_dontpan|v3df_follow,pp);
|
|
else if (choose_snd > 250)
|
|
PlayerSound(DIGI_DROPSOAP, v3df_dontpan|v3df_follow,pp);
|
|
else
|
|
PlayerSound(DIGI_REALTITS, v3df_dontpan|v3df_follow,pp);
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
case PACHINKO1:
|
|
|
|
// Don't mess with it if it's already going
|
|
if (u->WaitTics > 0) return TRUE;
|
|
|
|
PlaySound(DIGI_PFLIP, sp, v3df_none);
|
|
u->WaitTics = SEC(3) + SEC(RANDOM_RANGE(10));
|
|
ChangeState(SpriteNum,s_Pachinko1Operate);
|
|
|
|
return TRUE;
|
|
|
|
case PACHINKO2:
|
|
|
|
// Don't mess with it if it's already going
|
|
if (u->WaitTics > 0) return TRUE;
|
|
|
|
PlaySound(DIGI_PFLIP, sp, v3df_none);
|
|
u->WaitTics = SEC(3) + SEC(RANDOM_RANGE(10));
|
|
ChangeState(SpriteNum,s_Pachinko2Operate);
|
|
|
|
return TRUE;
|
|
|
|
case PACHINKO3:
|
|
|
|
// Don't mess with it if it's already going
|
|
if (u->WaitTics > 0) return TRUE;
|
|
|
|
PlaySound(DIGI_PFLIP, sp, v3df_none);
|
|
u->WaitTics = SEC(3) + SEC(RANDOM_RANGE(10));
|
|
ChangeState(SpriteNum,s_Pachinko3Operate);
|
|
|
|
return TRUE;
|
|
|
|
case PACHINKO4:
|
|
|
|
// Don't mess with it if it's already going
|
|
if (u->WaitTics > 0) return TRUE;
|
|
|
|
PlaySound(DIGI_PFLIP, sp, v3df_none);
|
|
u->WaitTics = SEC(3) + SEC(RANDOM_RANGE(10));
|
|
ChangeState(SpriteNum,s_Pachinko4Operate);
|
|
|
|
return TRUE;
|
|
|
|
case SWITCH_LOCKED:
|
|
key_num = sp->hitag;
|
|
if (pp->HasKey[key_num - 1])
|
|
{
|
|
int i;
|
|
for (i=0; i<numsectors; i++)
|
|
{
|
|
if (SectUser[i] && SectUser[i]->stag == SECT_LOCK_DOOR && SectUser[i]->number == key_num)
|
|
SectUser[i]->number = 0; // unlock all doors of this type
|
|
}
|
|
UnlockKeyLock(key_num, SpriteNum);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
case TAG_COMBO_SWITCH_EVERYTHING:
|
|
|
|
// change the switch state
|
|
AnimateSwitch(sp, -1);
|
|
PlaySound(DIGI_REGULARSWITCH, sp, v3df_none);
|
|
|
|
if (ComboSwitchTest(TAG_COMBO_SWITCH_EVERYTHING, sp->hitag))
|
|
{
|
|
DoMatchEverything(pp, sp->hitag, ON);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
case TAG_COMBO_SWITCH_EVERYTHING_ONCE:
|
|
|
|
// change the switch state
|
|
AnimateSwitch(sp, -1);
|
|
PlaySound(DIGI_REGULARSWITCH, sp, v3df_none);
|
|
|
|
if (ComboSwitchTest(TAG_COMBO_SWITCH_EVERYTHING, sp->hitag))
|
|
{
|
|
DoMatchEverything(pp, sp->hitag, ON);
|
|
}
|
|
|
|
sp->lotag = 0;
|
|
sp->hitag = 0;
|
|
return TRUE;
|
|
|
|
case TAG_SWITCH_EVERYTHING:
|
|
state = AnimateSwitch(sp, -1);
|
|
DoMatchEverything(pp, sp->hitag, state);
|
|
return TRUE;
|
|
|
|
case TAG_SWITCH_EVERYTHING_ONCE:
|
|
state = AnimateSwitch(sp, -1);
|
|
DoMatchEverything(pp, sp->hitag, state);
|
|
sp->lotag = 0;
|
|
sp->hitag = 0;
|
|
return TRUE;
|
|
|
|
case TAG_LIGHT_SWITCH:
|
|
|
|
state = AnimateSwitch(sp, -1);
|
|
DoLightingMatch(sp->hitag, state);
|
|
return TRUE;
|
|
|
|
case TAG_SPRITE_SWITCH_VATOR:
|
|
{
|
|
// make sure all vators are inactive before allowing
|
|
// to repress switch
|
|
if (!TestVatorMatchActive(sp->hitag))
|
|
DoVatorMatch(pp, sp->hitag);
|
|
|
|
if (!TestSpikeMatchActive(sp->hitag))
|
|
DoSpikeMatch(pp, sp->hitag);
|
|
|
|
if (!TestRotatorMatchActive(sp->hitag))
|
|
DoRotatorMatch(pp, sp->hitag, FALSE);
|
|
|
|
if (!TestSlidorMatchActive(sp->hitag))
|
|
DoSlidorMatch(pp, sp->hitag, FALSE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case TAG_LEVEL_EXIT_SWITCH:
|
|
{
|
|
extern short Level;
|
|
extern SWBOOL QuitFlag, ExitLevel, FinishedLevel;
|
|
|
|
AnimateSwitch(sp, -1);
|
|
|
|
PlaySound(DIGI_BIGSWITCH, sp, v3df_none);
|
|
|
|
if (sp->hitag)
|
|
Level = sp->hitag;
|
|
else
|
|
Level++;
|
|
ExitLevel = TRUE;
|
|
FinishedLevel = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case TAG_SPRITE_GRATING:
|
|
{
|
|
USERp u;
|
|
|
|
change_sprite_stat(SpriteNum, STAT_NO_STATE);
|
|
|
|
u = SpawnUser(SpriteNum, 0, NULL);
|
|
|
|
u->ActorActionFunc = DoGrating;
|
|
|
|
sp->lotag = 0;
|
|
sp->hitag /= 2;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case TAG_SO_SCALE_SWITCH:
|
|
AnimateSwitch(sp, -1);
|
|
DoSectorObjectSetScale(sp->hitag);
|
|
return TRUE;
|
|
|
|
case TAG_SO_SCALE_ONCE_SWITCH:
|
|
AnimateSwitch(sp, -1);
|
|
DoSectorObjectSetScale(sp->hitag);
|
|
sp->lotag = 0;
|
|
sp->hitag = 0;
|
|
return TRUE;
|
|
|
|
case TAG_SO_EVENT_SWITCH:
|
|
{
|
|
state = AnimateSwitch(sp, -1);
|
|
|
|
DoMatchEverything(NULL, sp->hitag, state);
|
|
|
|
sp->hitag = 0;
|
|
sp->lotag = 0;
|
|
|
|
PlaySound(DIGI_REGULARSWITCH, sp, v3df_none);
|
|
break;
|
|
}
|
|
|
|
case TAG_ROTATE_SO_SWITCH:
|
|
{
|
|
short so_num;
|
|
SECTOR_OBJECTp sop;
|
|
|
|
so_num = sp->hitag;
|
|
|
|
ASSERT(so_num <= 20);
|
|
ASSERT(SectorObject[so_num].num_sectors != -1);
|
|
|
|
AnimateSwitch(sp, -1);
|
|
|
|
sop = &SectorObject[so_num];
|
|
|
|
sop->ang_tgt = NORM_ANGLE(sop->ang_tgt + 512);
|
|
|
|
PlaySound(DIGI_BIGSWITCH, sp, v3df_none);
|
|
|
|
return TRUE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
int DoTrapReset(short match)
|
|
{
|
|
short i, nexti;
|
|
SPRITEp sp;
|
|
USERp u;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_TRAP], i, nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
u = User[i];
|
|
|
|
if (sp->lotag != match)
|
|
continue;
|
|
|
|
// if correct type and matches
|
|
if (sp->hitag == FIREBALL_TRAP)
|
|
u->WaitTics = 0;
|
|
|
|
// if correct type and matches
|
|
if (sp->hitag == BOLT_TRAP)
|
|
u->WaitTics = 0;
|
|
|
|
// if correct type and matches
|
|
if (sp->hitag == SPEAR_TRAP)
|
|
u->WaitTics = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int DoTrapMatch(short match)
|
|
{
|
|
short i, nexti;
|
|
SPRITEp sp;
|
|
USERp u;
|
|
|
|
// may need to be reset to fire immediately
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_TRAP], i, nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
u = User[i];
|
|
|
|
if (sp->lotag != match)
|
|
continue;
|
|
|
|
// if correct type and matches
|
|
if (sp->hitag == FIREBALL_TRAP)
|
|
{
|
|
u->WaitTics -= synctics;
|
|
|
|
if (u->WaitTics <= 0)
|
|
{
|
|
u->WaitTics = 1 * 120;
|
|
InitFireballTrap(i);
|
|
}
|
|
}
|
|
|
|
// if correct type and matches
|
|
if (sp->hitag == BOLT_TRAP)
|
|
{
|
|
u->WaitTics -= synctics;
|
|
|
|
if (u->WaitTics <= 0)
|
|
{
|
|
u->WaitTics = 1 * 120;
|
|
InitBoltTrap(i);
|
|
}
|
|
}
|
|
|
|
// if correct type and matches
|
|
if (sp->hitag == SPEAR_TRAP)
|
|
{
|
|
u->WaitTics -= synctics;
|
|
|
|
if (u->WaitTics <= 0)
|
|
{
|
|
u->WaitTics = 1 * 120;
|
|
InitSpearTrap(i);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
OperateTripTrigger(PLAYERp pp)
|
|
{
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (pp->cursectnum < 0)
|
|
return;
|
|
|
|
SECTORp sectp = §or[pp->cursectnum];
|
|
|
|
#if 0
|
|
// new method
|
|
if (TEST(sectp->extra, SECTFX_TRIGGER))
|
|
{
|
|
SPRITEp sp;
|
|
|
|
TRAVERSE_SPRITE_SECT(headspritesect[*sectp],i,nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
|
|
if (sp->statnum == STAT_TRIGGER && SP_TAG7(sp) == 0)
|
|
{
|
|
switch (SP_TAG3(sp))
|
|
{
|
|
case 1: // Secret Area
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// old method
|
|
switch (LOW_TAG(pp->cursectnum))
|
|
{
|
|
// same tag for sector as for switch
|
|
case TAG_LEVEL_EXIT_SWITCH:
|
|
{
|
|
extern short Level;
|
|
extern SWBOOL QuitFlag, ExitLevel, FinishedLevel;
|
|
|
|
if (sectp->hitag)
|
|
Level = sectp->hitag;
|
|
else
|
|
Level++;
|
|
ExitLevel = TRUE;
|
|
FinishedLevel = TRUE;
|
|
break;
|
|
}
|
|
|
|
case TAG_SECRET_AREA_TRIGGER:
|
|
if (pp == Player+myconnectindex)
|
|
PlayerSound(DIGI_ANCIENTSECRET, v3df_dontpan|v3df_doppler|v3df_follow,pp);
|
|
|
|
sprintf(ds, GStrings("TXTS_SECRET"));
|
|
SECRET_Trigger(pp->cursectnum);
|
|
|
|
PutStringInfo(pp, ds);
|
|
// always give to the first player
|
|
Player->SecretsFound++;
|
|
sectp->lotag = 0;
|
|
sectp->hitag = 0;
|
|
break;
|
|
|
|
case TAG_TRIGGER_EVERYTHING:
|
|
DoMatchEverything(pp, sectp->hitag, -1);
|
|
break;
|
|
|
|
case TAG_TRIGGER_EVERYTHING_ONCE:
|
|
DoMatchEverything(pp, sectp->hitag, -1);
|
|
sectp->lotag = 0;
|
|
sectp->hitag = 0;
|
|
break;
|
|
|
|
case TAG_SECTOR_TRIGGER_VATOR:
|
|
if (!TestVatorMatchActive(sectp->hitag))
|
|
DoVatorMatch(pp, sectp->hitag);
|
|
if (!TestSpikeMatchActive(sectp->hitag))
|
|
DoSpikeMatch(pp, sectp->hitag);
|
|
if (!TestRotatorMatchActive(sectp->hitag))
|
|
DoRotatorMatch(pp, sectp->hitag, FALSE);
|
|
if (!TestSlidorMatchActive(sectp->hitag))
|
|
DoSlidorMatch(pp, sectp->hitag, FALSE);
|
|
break;
|
|
|
|
case TAG_LIGHT_TRIGGER:
|
|
DoLightingMatch(sectp->hitag, -1);
|
|
break;
|
|
|
|
case TAG_SO_SCALE_TRIGGER:
|
|
DoSectorObjectSetScale(sectp->hitag);
|
|
break;
|
|
|
|
case TAG_SO_SCALE_ONCE_TRIGGER:
|
|
DoSectorObjectSetScale(sectp->hitag);
|
|
sectp->lotag = 0;
|
|
sectp->hitag = 0;
|
|
break;
|
|
|
|
case TAG_TRIGGER_ACTORS:
|
|
{
|
|
int dist;
|
|
short i, nexti;
|
|
SPRITEp sp;
|
|
USERp u;
|
|
|
|
dist = sectp->hitag;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_ENEMY], i, nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
u = User[i];
|
|
|
|
if (TEST(u->Flags, SPR_WAIT_FOR_TRIGGER))
|
|
{
|
|
if (Distance(sp->x, sp->y, pp->posx, pp->posy) < dist)
|
|
{
|
|
u->tgt_sp = pp->SpriteP;
|
|
RESET(u->Flags, SPR_WAIT_FOR_TRIGGER);
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case TAG_TRIGGER_MISSILE_TRAP:
|
|
{
|
|
// reset traps so they fire immediately
|
|
DoTrapReset(sector[pp->cursectnum].hitag);
|
|
break;
|
|
}
|
|
|
|
case TAG_TRIGGER_EXPLODING_SECTOR:
|
|
{
|
|
DoMatchEverything(NULL, sector[pp->cursectnum].hitag, -1);
|
|
break;
|
|
}
|
|
|
|
case TAG_SPAWN_ACTOR_TRIGGER:
|
|
{
|
|
DoMatchEverything(NULL, sector[pp->cursectnum].hitag, -1);
|
|
|
|
sector[pp->cursectnum].hitag = 0;
|
|
sector[pp->cursectnum].lotag = 0;
|
|
break;
|
|
}
|
|
|
|
case TAG_SO_EVENT_TRIGGER:
|
|
{
|
|
DoMatchEverything(NULL, sector[pp->cursectnum].hitag, -1);
|
|
|
|
sector[pp->cursectnum].hitag = 0;
|
|
sector[pp->cursectnum].lotag = 0;
|
|
|
|
PlaySound(DIGI_REGULARSWITCH, pp, v3df_none);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
OperateContinuousTrigger(PLAYERp pp)
|
|
{
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (pp->cursectnum < 0)
|
|
return;
|
|
|
|
switch (LOW_TAG(pp->cursectnum))
|
|
{
|
|
case TAG_TRIGGER_MISSILE_TRAP:
|
|
{
|
|
#if 1
|
|
DoTrapMatch(sector[pp->cursectnum].hitag);
|
|
#else
|
|
short i, nexti;
|
|
SPRITEp sp;
|
|
USERp u;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_TRAP], i, nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
u = User[i];
|
|
|
|
// if correct type and matches
|
|
if (sp->hitag == FIREBALL_TRAP && sp->lotag == sector[pp->cursectnum].hitag)
|
|
{
|
|
u->WaitTics -= synctics;
|
|
|
|
if (u->WaitTics <= 0)
|
|
{
|
|
u->WaitTics = 1 * 120;
|
|
InitFireballTrap(i);
|
|
}
|
|
}
|
|
|
|
// if correct type and matches
|
|
if (sp->hitag == BOLT_TRAP && sp->lotag == sector[pp->cursectnum].hitag)
|
|
{
|
|
u->WaitTics -= synctics;
|
|
|
|
if (u->WaitTics <= 0)
|
|
{
|
|
u->WaitTics = 1 * 120;
|
|
InitBoltTrap(i);
|
|
}
|
|
}
|
|
|
|
// if correct type and matches
|
|
if (sp->hitag == SPEAR_TRAP && sp->lotag == sector[pp->cursectnum].hitag)
|
|
{
|
|
u->WaitTics -= synctics;
|
|
|
|
if (u->WaitTics <= 0)
|
|
{
|
|
u->WaitTics = 1 * 120;
|
|
InitSpearTrap(i);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
short PlayerTakeSectorDamage(PLAYERp pp)
|
|
{
|
|
SECT_USERp sectu = SectUser[pp->cursectnum];
|
|
USERp u = User[pp->PlayerSprite];
|
|
|
|
// the calling routine must make sure sectu exists
|
|
if ((u->DamageTics -= synctics) < 0)
|
|
{
|
|
u->DamageTics = DAMAGE_TIME;
|
|
|
|
PlayerUpdateHealth(pp, -sectu->damage);
|
|
PlayerCheckDeath(pp, -1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Needed in order to see if Player should grunt if he can't find a wall to operate on
|
|
// If player is too far away, don't grunt
|
|
#define PLAYER_SOUNDEVENT_TAG 900
|
|
SWBOOL NearThings(PLAYERp pp)
|
|
{
|
|
short sectnum;
|
|
short rndnum;
|
|
int daz;
|
|
short neartagsect, neartagwall, neartagsprite;
|
|
int neartaghitdist;
|
|
|
|
|
|
// Check player's current sector for triggered sound
|
|
if (sector[pp->cursectnum].hitag == PLAYER_SOUNDEVENT_TAG)
|
|
{
|
|
if (pp == Player+myconnectindex)
|
|
PlayerSound(sector[pp->cursectnum].lotag, v3df_follow|v3df_dontpan,pp);
|
|
return FALSE;
|
|
}
|
|
|
|
neartag(pp->posx, pp->posy, pp->posz, pp->cursectnum, pp->pang,
|
|
&neartagsect, &neartagwall, &neartagsprite,
|
|
&neartaghitdist, 1024L, NTAG_SEARCH_LO_HI, NULL);
|
|
|
|
|
|
// hit a sprite? Check to see if it has sound info in it!
|
|
// This can work with any sprite!
|
|
if (neartagsprite >= 0)
|
|
{
|
|
SPRITEp sp = &sprite[neartagsprite];
|
|
|
|
// Go through list of cases
|
|
if (sp->hitag == PLAYER_SOUNDEVENT_TAG)
|
|
{
|
|
if (pp == Player+myconnectindex)
|
|
PlayerSound(sp->lotag, v3df_follow|v3df_dontpan,pp);
|
|
}
|
|
return FALSE; // Return false so he doesn't grunt
|
|
}
|
|
|
|
if (neartagwall >= 0)
|
|
{
|
|
// Check player's current sector for triggered sound
|
|
if (wall[neartagwall].hitag == PLAYER_SOUNDEVENT_TAG)
|
|
{
|
|
if (pp == Player+myconnectindex)
|
|
PlayerSound(wall[neartagwall].lotag, v3df_follow|v3df_dontpan,pp);
|
|
return FALSE; // We are playing a sound so don't return true
|
|
}
|
|
return TRUE;
|
|
}
|
|
// This only gets called if nothing else worked, check for nearness to a wall
|
|
{
|
|
hitdata_t hitinfo = { { 0, 0, 0 }, 0, 0, 0 };
|
|
short dang = pp->pang;
|
|
|
|
FAFhitscan(pp->posx, pp->posy, pp->posz - Z(30), pp->cursectnum, // Start position
|
|
sintable[NORM_ANGLE(dang + 512)], // X vector of 3D ang
|
|
sintable[NORM_ANGLE(dang)], // Y vector of 3D ang
|
|
0, // Z vector of 3D ang
|
|
&hitinfo, CLIPMASK_MISSILE);
|
|
|
|
if (hitinfo.sect < 0)
|
|
return FALSE;
|
|
|
|
if (Distance(hitinfo.pos.x, hitinfo.pos.y, pp->posx, pp->posy) > 1500)
|
|
return FALSE;
|
|
|
|
// hit a sprite?
|
|
if (hitinfo.sprite >= 0)
|
|
return FALSE;
|
|
|
|
if (neartagsect >= 0)
|
|
return TRUE;
|
|
|
|
if (hitinfo.wall >= 0)
|
|
{
|
|
WALLp wp;
|
|
|
|
wp = &wall[hitinfo.wall];
|
|
|
|
// Near a plain old vanilla wall. Can't do anything but grunt.
|
|
if (!TEST(wp->extra, WALLFX_DONT_STICK) && pp == Player+myconnectindex)
|
|
{
|
|
if (STD_RANDOM_RANGE(1000) > 970)
|
|
PlayerSound(DIGI_HITTINGWALLS, v3df_follow|v3df_dontpan,pp);
|
|
else
|
|
PlayerSound(DIGI_SEARCHWALL, v3df_follow|v3df_dontpan,pp);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0 // Move to sector.h file because .def files could not find declaration!
|
|
typedef struct
|
|
{
|
|
int dist;
|
|
short sectnum, wallnum, spritenum;
|
|
} NEAR_TAG_INFO, *NEAR_TAG_INFOp;
|
|
#endif
|
|
short nti_cnt;
|
|
|
|
void
|
|
NearTagList(NEAR_TAG_INFOp ntip, PLAYERp pp, int z, int dist, int type, int count)
|
|
{
|
|
short save_lotag, save_hitag;
|
|
short neartagsector, neartagwall, neartagsprite;
|
|
int neartaghitdist;
|
|
|
|
|
|
neartag(pp->posx, pp->posy, z, pp->cursectnum, pp->pang,
|
|
&neartagsector, &neartagwall, &neartagsprite,
|
|
&neartaghitdist, dist, type, NULL);
|
|
|
|
if (neartagsector >= 0)
|
|
{
|
|
// save off values
|
|
save_lotag = sector[neartagsector].lotag;
|
|
save_hitag = sector[neartagsector].hitag;
|
|
|
|
ntip->dist = neartaghitdist;
|
|
ntip->sectnum = neartagsector;
|
|
ntip->wallnum = -1;
|
|
ntip->spritenum = -1;
|
|
nti_cnt++;
|
|
ntip++;
|
|
|
|
if (nti_cnt >= count)
|
|
return;
|
|
|
|
// remove them
|
|
sector[neartagsector].lotag = 0;
|
|
sector[neartagsector].hitag = 0;
|
|
|
|
NearTagList(ntip, pp, z, dist, type, count);
|
|
|
|
// reset off values
|
|
sector[neartagsector].lotag = save_lotag;
|
|
sector[neartagsector].hitag = save_hitag;
|
|
}
|
|
else if (neartagwall >= 0)
|
|
{
|
|
// save off values
|
|
save_lotag = wall[neartagwall].lotag;
|
|
save_hitag = wall[neartagwall].hitag;
|
|
|
|
ntip->dist = neartaghitdist;
|
|
ntip->sectnum = -1;
|
|
ntip->wallnum = neartagwall;
|
|
ntip->spritenum = -1;
|
|
nti_cnt++;
|
|
ntip++;
|
|
|
|
if (nti_cnt >= count)
|
|
return;
|
|
|
|
// remove them
|
|
wall[neartagwall].lotag = 0;
|
|
wall[neartagwall].hitag = 0;
|
|
|
|
NearTagList(ntip, pp, z, dist, type, count);
|
|
|
|
// reset off values
|
|
wall[neartagwall].lotag = save_lotag;
|
|
wall[neartagwall].hitag = save_hitag;
|
|
}
|
|
else if (neartagsprite >= 0)
|
|
{
|
|
// save off values
|
|
save_lotag = sprite[neartagsprite].lotag;
|
|
save_hitag = sprite[neartagsprite].hitag;
|
|
|
|
ntip->dist = neartaghitdist;
|
|
ntip->sectnum = -1;
|
|
ntip->wallnum = -1;
|
|
ntip->spritenum = neartagsprite;
|
|
nti_cnt++;
|
|
ntip++;
|
|
|
|
if (nti_cnt >= count)
|
|
return;
|
|
|
|
// remove them
|
|
sprite[neartagsprite].lotag = 0;
|
|
sprite[neartagsprite].hitag = 0;
|
|
|
|
NearTagList(ntip, pp, z, dist, type, count);
|
|
|
|
// reset off values
|
|
sprite[neartagsprite].lotag = save_lotag;
|
|
sprite[neartagsprite].hitag = save_hitag;
|
|
}
|
|
else
|
|
{
|
|
ntip->dist = -1;
|
|
ntip->sectnum = -1;
|
|
ntip->wallnum = -1;
|
|
ntip->spritenum = -1;
|
|
nti_cnt++;
|
|
ntip++;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
void
|
|
BuildNearTagList(NEAR_TAG_INFOp ntip, int size, PLAYERp pp, int z, int dist, int type, int count)
|
|
{
|
|
memset(ntip, -1, size);
|
|
nti_cnt = 0;
|
|
NearTagList(ntip, pp, z, dist, type, count);
|
|
}
|
|
|
|
|
|
int DoPlayerGrabStar(PLAYERp pp)
|
|
{
|
|
SPRITEp sp = NULL;
|
|
int i;
|
|
extern short StarQueue[MAX_STAR_QUEUE];
|
|
|
|
// MUST check exact z's of each star or it will never work
|
|
for (i = 0; i < MAX_STAR_QUEUE; i++)
|
|
{
|
|
if (StarQueue[i] >= 0)
|
|
{
|
|
sp = &sprite[StarQueue[i]];
|
|
|
|
if (FindDistance3D(sp->x - pp->posx, sp->y - pp->posy, (sp->z - pp->posz + Z(12))>>4) < 500)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i < MAX_STAR_QUEUE)
|
|
{
|
|
// Pull a star out of wall and up your ammo
|
|
PlayerUpdateAmmo(pp, WPN_STAR, 1);
|
|
PlaySound(DIGI_ITEM, sp, v3df_none);
|
|
KillSprite(StarQueue[i]);
|
|
StarQueue[i] = -1;
|
|
if (TEST(pp->WpnFlags, BIT(WPN_STAR)))
|
|
return TRUE;
|
|
SET(pp->WpnFlags, BIT(WPN_STAR));
|
|
InitWeaponStar(pp);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
PlayerOperateEnv(PLAYERp pp)
|
|
{
|
|
SWBOOL found;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
////DSPRINTF(ds,"dist %d sectnum %d wallnum %d spritenum %d",nti[nt_ndx].dist, nti[nt_ndx].sectnum, nti[nt_ndx].wallnum, nti[nt_ndx].spritenum);
|
|
//MONO_PRINT(ds);
|
|
|
|
//
|
|
// Switch & door activations
|
|
//
|
|
|
|
if (TEST_SYNC_KEY(pp, SK_OPERATE))
|
|
{
|
|
if (FLAG_KEY_PRESSED(pp, SK_OPERATE))
|
|
{
|
|
// if space bar pressed
|
|
short nt_ndx;
|
|
NEAR_TAG_INFO nti[16];
|
|
|
|
if (DoPlayerGrabStar(pp))
|
|
{
|
|
FLAG_KEY_RELEASE(pp, SK_OPERATE);
|
|
}
|
|
else
|
|
{
|
|
NearThings(pp); // Check for player sound specified in a level sprite
|
|
}
|
|
|
|
BuildNearTagList(nti, sizeof(nti), pp, pp->posz, 2048L, NTAG_SEARCH_LO_HI, 8);
|
|
|
|
found = FALSE;
|
|
|
|
// try and find a sprite
|
|
for (nt_ndx = 0; nti[nt_ndx].dist >= 0; nt_ndx++)
|
|
{
|
|
if (nti[nt_ndx].spritenum >= 0 && nti[nt_ndx].dist < 1024 + 768)
|
|
{
|
|
if (OperateSprite(nti[nt_ndx].spritenum, TRUE))
|
|
{
|
|
FLAG_KEY_RELEASE(pp, SK_OPERATE);
|
|
found = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if not found look at different z positions
|
|
if (!found)
|
|
{
|
|
int z[3];
|
|
unsigned i;
|
|
NEAR_TAG_INFO nti[16];
|
|
short nt_ndx;
|
|
|
|
|
|
z[0] = pp->SpriteP->z - SPRITEp_SIZE_Z(pp->SpriteP) - Z(10);
|
|
z[1] = pp->SpriteP->z;
|
|
z[2] = DIV2(z[0] + z[1]);
|
|
|
|
for (i = 0; i < SIZ(z); i++)
|
|
{
|
|
BuildNearTagList(nti, sizeof(nti), pp, z[i], 1024 + 768L, NTAG_SEARCH_LO_HI, 8);
|
|
|
|
for (nt_ndx = 0; nti[nt_ndx].dist >= 0; nt_ndx++)
|
|
{
|
|
if (nti[nt_ndx].spritenum >= 0 && nti[nt_ndx].dist < 1024 + 768)
|
|
{
|
|
if (OperateSprite(nti[nt_ndx].spritenum, TRUE))
|
|
{
|
|
FLAG_KEY_RELEASE(pp, SK_OPERATE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
int neartaghitdist;
|
|
short neartagsector, neartagsprite, neartagwall;
|
|
|
|
neartaghitdist = nti[0].dist;
|
|
neartagsector = nti[0].sectnum;
|
|
neartagwall = nti[0].wallnum;
|
|
neartagsprite = nti[0].spritenum;
|
|
|
|
if (neartagsector >= 0 && neartaghitdist < 1024)
|
|
{
|
|
if (OperateSector(neartagsector, TRUE))
|
|
{
|
|
// Release the key
|
|
FLAG_KEY_RELEASE(pp, SK_OPERATE);
|
|
}
|
|
}
|
|
|
|
if (neartagwall >= 0 && neartaghitdist < 1024)
|
|
{
|
|
if (OperateWall(neartagwall, TRUE))
|
|
{
|
|
FLAG_KEY_RELEASE(pp, SK_OPERATE);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Trigger operations
|
|
//
|
|
|
|
switch (LOW_TAG(pp->cursectnum))
|
|
{
|
|
case TAG_VATOR:
|
|
DoVatorOperate(pp, pp->cursectnum);
|
|
DoSpikeOperate(pp, pp->cursectnum);
|
|
DoRotatorOperate(pp, pp->cursectnum);
|
|
DoSlidorOperate(pp, pp->cursectnum);
|
|
break;
|
|
case TAG_SPRING_BOARD:
|
|
DoSpringBoard(pp, pp->cursectnum);
|
|
FLAG_KEY_RELEASE(pp, SK_OPERATE);
|
|
break;
|
|
case TAG_DOOR_ROTATE:
|
|
if (OperateSector(pp->cursectnum, TRUE))
|
|
FLAG_KEY_RELEASE(pp, SK_OPERATE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Reset the key when syncbit key is not in use
|
|
FLAG_KEY_RESET(pp, SK_OPERATE);
|
|
}
|
|
|
|
// ////////////////////////////
|
|
//
|
|
// Sector Damage
|
|
//
|
|
// ////////////////////////////
|
|
|
|
SECT_USERp sectu;
|
|
if (pp->cursectnum >= 0 && (sectu = SectUser[pp->cursectnum]) && sectu->damage)
|
|
{
|
|
SECTORp sectp = §or[pp->cursectnum];
|
|
if (TEST(sectu->flags, SECTFU_DAMAGE_ABOVE_SECTOR))
|
|
{
|
|
PlayerTakeSectorDamage(pp);
|
|
}
|
|
else if ((SPRITEp_BOS(pp->SpriteP) >= sectp->floorz) && !TEST(pp->Flags, PF_DIVING))
|
|
{
|
|
PlayerTakeSectorDamage(pp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
USERp u = User[pp->PlayerSprite];
|
|
u->DamageTics = 0;
|
|
}
|
|
|
|
|
|
// ////////////////////////////
|
|
//
|
|
// Trigger stuff
|
|
//
|
|
// ////////////////////////////
|
|
|
|
OperateContinuousTrigger(pp);
|
|
|
|
// just changed sectors
|
|
if (pp->lastcursectnum != pp->cursectnum)
|
|
{
|
|
OperateTripTrigger(pp);
|
|
|
|
if (pp->cursectnum >= 0 && TEST(sector[pp->cursectnum].extra, SECTFX_WARP_SECTOR))
|
|
{
|
|
if (!TEST(pp->Flags2, PF2_TELEPORTED))
|
|
{
|
|
DoPlayerWarpTeleporter(pp);
|
|
}
|
|
}
|
|
|
|
RESET(pp->Flags2, PF2_TELEPORTED);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
DoSineWaveFloor(void)
|
|
{
|
|
SINE_WAVE_FLOOR *swf;
|
|
int newz;
|
|
short wave;
|
|
char flags;
|
|
|
|
for (wave = 0; wave < MAX_SINE_WAVE; wave++)
|
|
{
|
|
for (swf = &SineWaveFloor[wave][0], flags = swf->flags; swf->sector >= 0 && swf < &SineWaveFloor[wave][SIZ(SineWaveFloor[wave])]; swf++)
|
|
{
|
|
|
|
swf->sintable_ndx = NORM_ANGLE(swf->sintable_ndx + (synctics << swf->speed_shift));
|
|
|
|
if (TEST(flags, SINE_FLOOR))
|
|
{
|
|
newz = swf->floor_origz + ((swf->range * sintable[swf->sintable_ndx]) >> 14);
|
|
sector[swf->sector].floorz = newz;
|
|
}
|
|
|
|
if (TEST(flags, SINE_CEILING))
|
|
{
|
|
newz = swf->ceiling_origz + ((swf->range * sintable[swf->sintable_ndx]) >> 14);
|
|
sector[swf->sector].ceilingz = newz;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/* SLOPED SIN-WAVE FLOORS:
|
|
|
|
It's best to program sloped sin-wave floors in 2 steps:
|
|
1. First set the floorz of the floor as the sin code normally does it.
|
|
2. Adjust the slopes by calling alignflorslope once for each sector.
|
|
|
|
Note: For this to work, the first wall of each sin-wave sector must be
|
|
aligned on the same side of each sector for the entire strip.
|
|
*/
|
|
|
|
for (wave = 0; wave < MAX_SINE_WAVE; wave++)
|
|
{
|
|
for (swf = &SineWaveFloor[wave][0], flags = swf->flags; swf->sector >= 0 && swf < &SineWaveFloor[wave][SIZ(SineWaveFloor[wave])]; swf++)
|
|
{
|
|
if (!TEST(sector[swf->sector].floorstat, FLOOR_STAT_SLOPE))
|
|
continue;
|
|
|
|
if (TEST(flags, SINE_SLOPED))
|
|
{
|
|
WALLp wal;
|
|
if (sector[swf->sector].wallnum == 4)
|
|
{
|
|
//Set wal to the wall on the opposite side of the sector
|
|
wal = &wall[sector[swf->sector].wallptr+2];
|
|
|
|
//Pass (Sector, x, y, z)
|
|
alignflorslope(swf->sector,wal->x,wal->y,
|
|
sector[wal->nextsector].floorz);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DoSineWaveWall(void)
|
|
{
|
|
SINE_WALL *sw;
|
|
int New;
|
|
short sw_num;
|
|
|
|
for (sw_num = 0; sw_num < MAX_SINE_WAVE; sw_num++)
|
|
{
|
|
for (sw = &SineWall[sw_num][0]; sw->wall >= 0 && sw < &SineWall[sw_num][MAX_SINE_WALL_POINTS]; sw++)
|
|
{
|
|
// move through the sintable
|
|
sw->sintable_ndx = NORM_ANGLE(sw->sintable_ndx + (synctics << sw->speed_shift));
|
|
|
|
if (!sw->type)
|
|
{
|
|
New = sw->orig_xy + ((sw->range * sintable[sw->sintable_ndx]) >> 14);
|
|
// wall[sw->wall].y = New;
|
|
dragpoint(sw->wall, wall[sw->wall].x, New, 0);
|
|
}
|
|
else
|
|
{
|
|
New = sw->orig_xy + ((sw->range * sintable[sw->sintable_ndx]) >> 14);
|
|
// wall[sw->wall].x = New;
|
|
dragpoint(sw->wall, New, wall[sw->wall].y, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DoAnim(int numtics)
|
|
{
|
|
int i, animval;
|
|
|
|
for (i = AnimCnt - 1; i >= 0; i--)
|
|
{
|
|
animval = *Anim[i].ptr;
|
|
|
|
// if LESS THAN goal
|
|
if (animval < Anim[i].goal)
|
|
{
|
|
// move it
|
|
animval += (numtics * PIXZ(Anim[i].vel));
|
|
|
|
Anim[i].vel += Anim[i].vel_adj * numtics;
|
|
|
|
// if the other way make it equal
|
|
if (animval > Anim[i].goal)
|
|
animval = Anim[i].goal;
|
|
}
|
|
|
|
// if GREATER THAN goal
|
|
if (animval > Anim[i].goal)
|
|
{
|
|
animval -= (numtics * PIXZ(Anim[i].vel));
|
|
|
|
Anim[i].vel += Anim[i].vel_adj * numtics;
|
|
|
|
if (animval < Anim[i].goal)
|
|
animval = Anim[i].goal;
|
|
}
|
|
|
|
*Anim[i].ptr = animval;
|
|
|
|
// EQUAL this entry has finished
|
|
if (animval == Anim[i].goal)
|
|
{
|
|
ANIM_CALLBACKp acp = Anim[i].callback;
|
|
|
|
// do a callback when done if not NULL
|
|
if (Anim[i].callback)
|
|
(*Anim[i].callback)(&Anim[i], Anim[i].callbackdata);
|
|
|
|
// only delete it if the callback has not changed
|
|
// Logic here is that if the callback changed then something
|
|
// else must be happening with it - dont delete it
|
|
if (Anim[i].callback == acp)
|
|
{
|
|
// decrement the count
|
|
AnimCnt--;
|
|
|
|
// move the last entry to the current one to free the last
|
|
// entry up
|
|
Anim[i] = Anim[AnimCnt];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
AnimClear(void)
|
|
{
|
|
int i, animval;
|
|
|
|
#if 1
|
|
AnimCnt = 0;
|
|
#else
|
|
for (i = AnimCnt - 1; i >= 0; i--)
|
|
{
|
|
if (Anim[i].extra)
|
|
{
|
|
FreeMem(Anim[i].extra);
|
|
Anim[i].extra = 0;
|
|
}
|
|
}
|
|
|
|
AnimCnt = 0;
|
|
#endif
|
|
}
|
|
|
|
short
|
|
AnimGetGoal(int *animptr)
|
|
{
|
|
int i, j;
|
|
|
|
j = -1;
|
|
for (i = 0; i < AnimCnt; i++)
|
|
{
|
|
if (animptr == Anim[i].ptr)
|
|
{
|
|
j = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
void
|
|
AnimDelete(int *animptr)
|
|
{
|
|
int i, j;
|
|
|
|
j = -1;
|
|
for (i = 0; i < AnimCnt; i++)
|
|
{
|
|
if (animptr == Anim[i].ptr)
|
|
{
|
|
j = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (j == -1)
|
|
return;
|
|
|
|
// decrement the count
|
|
AnimCnt--;
|
|
|
|
// move the last entry to the current one to free the last entry up
|
|
Anim[j] = Anim[AnimCnt];
|
|
|
|
//DSPRINTF(ds, "Deleted a Anim");
|
|
MONO_PRINT(ds);
|
|
|
|
}
|
|
|
|
|
|
short
|
|
AnimSet(int *animptr, int thegoal, int thevel)
|
|
{
|
|
int i, j;
|
|
|
|
ASSERT(AnimCnt < MAXANIM - 1);
|
|
|
|
j = AnimCnt;
|
|
|
|
// look for existing animation and reset it
|
|
for (i = 0; i < AnimCnt; i++)
|
|
{
|
|
if (animptr == Anim[i].ptr)
|
|
{
|
|
j = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Anim[j].ptr = animptr;
|
|
Anim[j].goal = thegoal;
|
|
Anim[j].vel = Z(thevel);
|
|
Anim[j].vel_adj = 0;
|
|
Anim[j].callback = NULL;
|
|
Anim[j].callbackdata = NULL;
|
|
|
|
if (j == AnimCnt)
|
|
AnimCnt++;
|
|
|
|
return j;
|
|
}
|
|
|
|
short
|
|
AnimSetCallback(short anim_ndx, ANIM_CALLBACKp call, ANIM_DATAp data)
|
|
{
|
|
ASSERT(anim_ndx < AnimCnt);
|
|
|
|
if (anim_ndx == -1)
|
|
return anim_ndx;
|
|
|
|
Anim[anim_ndx].callback = call;
|
|
Anim[anim_ndx].callbackdata = data;
|
|
|
|
return anim_ndx;
|
|
}
|
|
|
|
short
|
|
AnimSetVelAdj(short anim_ndx, short vel_adj)
|
|
{
|
|
ASSERT(anim_ndx < AnimCnt);
|
|
|
|
if (anim_ndx == -1)
|
|
return anim_ndx;
|
|
|
|
Anim[anim_ndx].vel_adj = vel_adj;
|
|
|
|
return anim_ndx;
|
|
}
|
|
|
|
|
|
void initlava(void)
|
|
{
|
|
#if 0
|
|
int x, y, z, r;
|
|
int i;
|
|
|
|
//char lavabakpic[(LAVASIZ + 2) * (LAVASIZ + 2)], lavainc[LAVASIZ];
|
|
//int lavanumdrops, lavanumframes;
|
|
//int lavadropx[LAVAMAXDROPS], lavadropy[LAVAMAXDROPS];
|
|
//int lavadropsiz[LAVAMAXDROPS], lavadropsizlookup[LAVAMAXDROPS];
|
|
//int lavaradx[32][128], lavarady[32][128], lavaradcnt[32];
|
|
|
|
|
|
UPDATE TO NEW CODE
|
|
|
|
static int lavaradx[24][96];
|
|
static int lavarady[24][96];
|
|
|
|
for
|
|
lavaradcnt[z] = 0;
|
|
|
|
for (x = -16; x <= 16; x++)
|
|
for (y = -16; y <= 16; y++)
|
|
{
|
|
// r should only be between 0 and 31
|
|
// lavaradcnt[r] should be less 127
|
|
r = ksqrt(x * x + y * y);
|
|
lavaradx[r][lavaradcnt[r]] = x;
|
|
lavarady[r][lavaradcnt[r]] = y;
|
|
// this was causing an overwrite in ElevatorAuto structure
|
|
lavaradcnt[r]++;
|
|
}
|
|
|
|
// for(z=0;z<16;z++)
|
|
// lavadropsizlookup[z] = 8 / (ksqrt(z)+1);
|
|
|
|
for (z = 0; z < 16; z++)
|
|
{
|
|
lavadropsizlookup[z] = 8 / (ksqrt(16 - z) + 1);
|
|
}
|
|
|
|
for (z = 0; z < LAVASIZ; z++)
|
|
{
|
|
lavainc[z] = klabs((((z ^ 17) >> 4) & 7) - 4) + 12;
|
|
}
|
|
|
|
lavanumdrops = 0;
|
|
lavanumframes = 0;
|
|
#endif
|
|
}
|
|
|
|
void movelava(char *dapic)
|
|
{
|
|
#if 0
|
|
// #define COLOR_OFFSET 192
|
|
#define COLOR_OFFSET LT_BROWN
|
|
|
|
char dat, *ptr;
|
|
int x, y, z, zx, dalavadropsiz, dadropsizlookup;
|
|
intptr_t offs, offs2;
|
|
int dalavax, dalavay;
|
|
|
|
z = 3;
|
|
if (lavanumdrops + z >= LAVAMAXDROPS)
|
|
z = LAVAMAXDROPS - lavanumdrops - 1;
|
|
while (z >= 0)
|
|
{
|
|
lavadropx[lavanumdrops] = (rand() & (LAVASIZ - 1));
|
|
lavadropy[lavanumdrops] = (rand() & (LAVASIZ - 1));
|
|
lavadropsiz[lavanumdrops] = 1;
|
|
lavanumdrops++;
|
|
z--;
|
|
}
|
|
|
|
z = lavanumdrops - 1;
|
|
while (z >= 0)
|
|
{
|
|
dadropsizlookup = lavadropsizlookup[lavadropsiz[z]] * (((z & 1) << 1) - 1);
|
|
dalavadropsiz = lavadropsiz[z];
|
|
dalavax = lavadropx[z];
|
|
dalavay = lavadropy[z];
|
|
for (zx = lavaradcnt[lavadropsiz[z]] - 1; zx >= 0; zx--)
|
|
{
|
|
offs = (((lavaradx[dalavadropsiz][zx] + dalavax) & (LAVASIZ - 1)) << LAVALOGSIZ);
|
|
offs += ((lavarady[dalavadropsiz][zx] + dalavay) & (LAVASIZ - 1));
|
|
|
|
dapic[offs] += dadropsizlookup;
|
|
|
|
if (dapic[offs] < COLOR_OFFSET)
|
|
dapic[offs] = COLOR_OFFSET;
|
|
}
|
|
|
|
lavadropsiz[z]++;
|
|
if (lavadropsiz[z] > 10)
|
|
{
|
|
lavanumdrops--;
|
|
lavadropx[z] = lavadropx[lavanumdrops];
|
|
lavadropy[z] = lavadropy[lavanumdrops];
|
|
lavadropsiz[z] = lavadropsiz[lavanumdrops];
|
|
}
|
|
z--;
|
|
}
|
|
|
|
// Back up dapic with 1 pixel extra on each boundary
|
|
// (to prevent anding for wrap-around)
|
|
offs = ((intptr_t) dapic);
|
|
offs2 = (LAVASIZ + 2) + 1 + ((intptr_t) lavabakpic);
|
|
for (x = 0; x < LAVASIZ; x++)
|
|
{
|
|
copybuf(offs, offs2, LAVASIZ >> 2);
|
|
offs += LAVASIZ;
|
|
offs2 += LAVASIZ + 2;
|
|
}
|
|
for (y = 0; y < LAVASIZ; y++)
|
|
{
|
|
lavabakpic[y + 1] = dapic[y + ((LAVASIZ - 1) << LAVALOGSIZ)];
|
|
lavabakpic[y + 1 + (LAVASIZ + 1) * (LAVASIZ + 2)] = dapic[y];
|
|
}
|
|
for (x = 0; x < LAVASIZ; x++)
|
|
{
|
|
lavabakpic[(x + 1) * (LAVASIZ + 2)] = dapic[(x << LAVALOGSIZ) + (LAVASIZ - 1)];
|
|
lavabakpic[(x + 1) * (LAVASIZ + 2) + (LAVASIZ + 1)] = dapic[x << LAVALOGSIZ];
|
|
}
|
|
lavabakpic[0] = dapic[LAVASIZ * LAVASIZ - 1];
|
|
lavabakpic[LAVASIZ + 1] = dapic[LAVASIZ * (LAVASIZ - 1)];
|
|
lavabakpic[(LAVASIZ + 2) * (LAVASIZ + 1)] = dapic[LAVASIZ - 1];
|
|
lavabakpic[(LAVASIZ + 2) * (LAVASIZ + 2) - 1] = dapic[0];
|
|
|
|
for (z = (LAVASIZ + 2) * (LAVASIZ + 2) - 4; z >= 0; z -= 4)
|
|
{
|
|
lavabakpic[z + 0] &= 31;
|
|
lavabakpic[z + 1] &= 31;
|
|
lavabakpic[z + 2] &= 31;
|
|
lavabakpic[z + 3] &= 31;
|
|
}
|
|
|
|
for (x = LAVASIZ - 1; x >= 0; x--)
|
|
{
|
|
offs = (x + 1) * (LAVASIZ + 2) + 1;
|
|
ptr = (char *)((x << LAVALOGSIZ) + (intptr_t) dapic);
|
|
|
|
zx = ((x + lavanumframes) & (LAVASIZ - 1));
|
|
|
|
offs2 = LAVASIZ - 1;
|
|
for (y = offs; y < offs + LAVASIZ; y++)
|
|
{
|
|
dat = lavainc[(offs2--) & zx];
|
|
|
|
dat += lavabakpic[y - (LAVASIZ + 2) - 1];
|
|
dat += lavabakpic[y - (LAVASIZ + 2)];
|
|
dat += lavabakpic[y - (LAVASIZ + 2) + 1];
|
|
dat += lavabakpic[y - 1];
|
|
dat += lavabakpic[y + 1];
|
|
dat += lavabakpic[y + (LAVASIZ + 2)];
|
|
dat += lavabakpic[y + (LAVASIZ + 2) - 1];
|
|
|
|
*ptr++ = (dat >> 3) + COLOR_OFFSET;
|
|
}
|
|
}
|
|
|
|
lavanumframes++;
|
|
#endif
|
|
}
|
|
|
|
|
|
void
|
|
DoPanning(void)
|
|
{
|
|
int nx, ny;
|
|
short i,nexti;
|
|
SPRITEp sp;
|
|
SECTORp sectp;
|
|
WALLp wallp;
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_FLOOR_PAN], i, nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
sectp = §or[sp->sectnum];
|
|
|
|
nx = (((int) sintable[NORM_ANGLE(sp->ang + 512)]) * sp->xvel) >> 20;
|
|
ny = (((int) sintable[sp->ang]) * sp->xvel) >> 20;
|
|
|
|
sectp->floorxpanning += nx;
|
|
sectp->floorypanning += ny;
|
|
|
|
sectp->floorxpanning &= 255;
|
|
sectp->floorypanning &= 255;
|
|
}
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_CEILING_PAN], i, nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
sectp = §or[sp->sectnum];
|
|
|
|
nx = (((int) sintable[NORM_ANGLE(sp->ang + 512)]) * sp->xvel) >> 20;
|
|
ny = (((int) sintable[sp->ang]) * sp->xvel) >> 20;
|
|
|
|
sectp->ceilingxpanning += nx;
|
|
sectp->ceilingypanning += ny;
|
|
|
|
sectp->ceilingxpanning &= 255;
|
|
sectp->ceilingypanning &= 255;
|
|
}
|
|
|
|
TRAVERSE_SPRITE_STAT(headspritestat[STAT_WALL_PAN], i, nexti)
|
|
{
|
|
sp = &sprite[i];
|
|
wallp = &wall[sp->owner];
|
|
|
|
nx = (((int) sintable[NORM_ANGLE(sp->ang + 512)]) * sp->xvel) >> 20;
|
|
ny = (((int) sintable[sp->ang]) * sp->xvel) >> 20;
|
|
|
|
wallp->xpanning += nx;
|
|
wallp->ypanning += ny;
|
|
|
|
wallp->xpanning &= 255;
|
|
wallp->ypanning &= 255;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DoSector(void)
|
|
{
|
|
short i;
|
|
SECTOR_OBJECTp sop;
|
|
SWBOOL riding;
|
|
extern SWBOOL DebugActorFreeze;
|
|
int sync_flag;
|
|
short pnum;
|
|
int min_dist,dist,a,b,c;
|
|
PLAYERp pp;
|
|
|
|
if (DebugActorFreeze)
|
|
return;
|
|
|
|
#if 0
|
|
MoveSectorObjects(synctics);
|
|
#endif
|
|
|
|
#if 0
|
|
if (MoveSkip2 == 0)
|
|
MoveSectorObjects(synctics * 2);
|
|
#endif
|
|
|
|
#if 0
|
|
TRAVERSE_CONNECT(pnum)
|
|
{
|
|
pp = Player + pnum;
|
|
pp->sop_riding = NULL;
|
|
}
|
|
|
|
for (sop = SectorObject; sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++)
|
|
{
|
|
if (MoveSkip2 == 0)
|
|
MoveSectorObjects(sop, synctics * 2);
|
|
}
|
|
#endif
|
|
|
|
#if 1
|
|
for (sop = SectorObject; sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++)
|
|
{
|
|
|
|
if (sop->xmid == INT32_MAX /*|| sop->xmid == MAXSO*/)
|
|
continue;
|
|
|
|
|
|
riding = FALSE;
|
|
min_dist = 999999;
|
|
|
|
TRAVERSE_CONNECT(pnum)
|
|
{
|
|
pp = &Player[pnum];
|
|
|
|
if (pp->sop_riding == sop)
|
|
{
|
|
riding = TRUE;
|
|
pp->sop_riding = NULL;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
DISTANCE(pp->posx, pp->posy, sop->xmid, sop->ymid, dist, a, b, c);
|
|
if (dist < min_dist)
|
|
min_dist = dist;
|
|
}
|
|
}
|
|
|
|
if (sop->Animator)
|
|
{
|
|
(*sop->Animator)(sop);
|
|
continue;
|
|
}
|
|
|
|
// force sync SOs to be updated regularly
|
|
if ((sync_flag = TEST(sop->flags, SOBJ_SYNC1|SOBJ_SYNC2)) != 0)
|
|
{
|
|
if (sync_flag == SOBJ_SYNC1)
|
|
MoveSectorObjects(sop, synctics);
|
|
else
|
|
{
|
|
if (MoveSkip2 == 0)
|
|
MoveSectorObjects(sop, synctics*2);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (riding)
|
|
{
|
|
// if riding move smoothly
|
|
// update every time
|
|
MoveSectorObjects(sop, synctics);
|
|
}
|
|
else
|
|
{
|
|
if (min_dist < 15000)
|
|
{
|
|
// if close update every other time
|
|
if (MoveSkip2 == 0)
|
|
MoveSectorObjects(sop, synctics * 2);
|
|
}
|
|
else
|
|
{
|
|
// if further update every 4th time
|
|
if (MoveSkip4 == 0)
|
|
MoveSectorObjects(sop, synctics * 4);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DoPanning();
|
|
DoLighting();
|
|
DoSineWaveFloor();
|
|
DoSineWaveWall();
|
|
DoSpringBoardDown();
|
|
}
|
|
|
|
#if 0
|
|
int inside(int x, int y, short sectnum)
|
|
{
|
|
WALLp wal;
|
|
int i, x1, y1, x2, y2;
|
|
char cnt;
|
|
|
|
if ((sectnum < 0) || (sectnum >= numsectors))
|
|
return -1;
|
|
cnt = 0;
|
|
|
|
wal = &wall[sector[sectnum].wallptr];
|
|
for (i = sector[sectnum].wallnum; i > 0; i--)
|
|
{
|
|
y1 = wal->y - y;
|
|
y2 = wall[wal->point2].y - y;
|
|
if ((y1 ^ y2) < 0)
|
|
{
|
|
x1 = wal->x - x;
|
|
x2 = wall[wal->point2].x - x;
|
|
|
|
if ((x1 ^ x2) < 0)
|
|
cnt ^= (x1 * y2 < x2 * y1) ^ (y1 < y2);
|
|
else if (x1 >= 0)
|
|
cnt ^= 1;
|
|
}
|
|
wal++;
|
|
}
|
|
return cnt;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#include "saveable.h"
|
|
|
|
static saveable_code saveable_sector_code[] =
|
|
{
|
|
SAVE_CODE(WallSetupDontMove),
|
|
SAVE_CODE(WallSetup),
|
|
SAVE_CODE(SectorLiquidSet),
|
|
SAVE_CODE(SectorSetup),
|
|
SAVE_CODE(DoSpringBoard),
|
|
SAVE_CODE(DoSpringBoardDown),
|
|
SAVE_CODE(DoSpawnActorTrigger),
|
|
SAVE_CODE(OperateSector),
|
|
SAVE_CODE(OperateWall),
|
|
SAVE_CODE(AnimateSwitch),
|
|
SAVE_CODE(SectorExp),
|
|
SAVE_CODE(DoExplodeSector),
|
|
SAVE_CODE(DoSpawnSpot),
|
|
SAVE_CODE(DoSpawnSpotsForKill),
|
|
SAVE_CODE(DoSpawnSpotsForDamage),
|
|
SAVE_CODE(DoSoundSpotMatch),
|
|
SAVE_CODE(DoSoundSpotStopSound),
|
|
SAVE_CODE(DoStopSoundSpotMatch),
|
|
SAVE_CODE(DoSectorObjectKillMatch),
|
|
SAVE_CODE(DoDeleteSpriteMatch),
|
|
SAVE_CODE(DoChangorMatch),
|
|
SAVE_CODE(DoMatchEverything),
|
|
SAVE_CODE(DoTrapReset),
|
|
SAVE_CODE(DoTrapMatch),
|
|
SAVE_CODE(OperateTripTrigger),
|
|
SAVE_CODE(OperateContinuousTrigger),
|
|
SAVE_CODE(PlayerTakeSectorDamage),
|
|
SAVE_CODE(NearThings),
|
|
SAVE_CODE(NearTagList),
|
|
SAVE_CODE(BuildNearTagList),
|
|
SAVE_CODE(DoPlayerGrabStar),
|
|
SAVE_CODE(PlayerOperateEnv),
|
|
SAVE_CODE(DoSineWaveFloor),
|
|
SAVE_CODE(DoSineWaveWall),
|
|
SAVE_CODE(DoAnim),
|
|
SAVE_CODE(AnimClear),
|
|
SAVE_CODE(AnimGetGoal),
|
|
SAVE_CODE(AnimDelete),
|
|
SAVE_CODE(AnimSet),
|
|
SAVE_CODE(AnimSetCallback),
|
|
SAVE_CODE(AnimSetVelAdj),
|
|
SAVE_CODE(DoPanning),
|
|
SAVE_CODE(DoSector),
|
|
};
|
|
|
|
saveable_module saveable_sector =
|
|
{
|
|
// code
|
|
saveable_sector_code,
|
|
SIZ(saveable_sector_code),
|
|
|
|
// data
|
|
NULL,
|
|
0
|
|
};
|
|
|
|
|
|
END_SW_NS
|