mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-17 18:01:17 +00:00
8f19dc12d8
* a large number of code pointer records were removed because none of these functions ever gets assigned to a pointer * instead of looking up entries by index, do it by name. This is far less fragile and will survive deeper refactoring. The old storage by table index will break as soon as a single entry gets removed. Since the old savegames got broken due to this problem recently it was a good time to change the setup.
711 lines
18 KiB
C++
711 lines
18 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 "names2.h"
|
|
#include "panel.h"
|
|
#include "game.h"
|
|
#include "network.h"
|
|
#include "tags.h"
|
|
#include "sector.h"
|
|
#include "interpolate.h"
|
|
#include "misc.h"
|
|
#include "sprite.h"
|
|
#include "quotemgr.h"
|
|
|
|
BEGIN_SW_NS
|
|
|
|
void ReverseSlidor(short SpriteNum)
|
|
{
|
|
USERp u = User[SpriteNum].Data();
|
|
ROTATORp r;
|
|
|
|
r = u->rotator.Data();
|
|
|
|
// if paused go ahead and start it up again
|
|
if (u->Tics)
|
|
{
|
|
u->Tics = 0;
|
|
SetSlidorActive(SpriteNum);
|
|
return;
|
|
}
|
|
|
|
// moving toward to OFF pos
|
|
if (r->tgt == 0)
|
|
{
|
|
r->tgt = r->open_dest;
|
|
}
|
|
else if (r->tgt == r->open_dest)
|
|
{
|
|
r->tgt = 0;
|
|
}
|
|
|
|
r->vel = -r->vel;
|
|
}
|
|
|
|
|
|
bool
|
|
SlidorSwitch(short match, short setting)
|
|
{
|
|
SPRITEp sp;
|
|
int i;
|
|
bool found = false;
|
|
|
|
StatIterator it(STAT_DEFAULT);
|
|
while ((i = it.NextIndex()) >= 0)
|
|
{
|
|
sp = &sprite[i];
|
|
|
|
if (sp->lotag == TAG_SPRITE_SWITCH_VATOR && sp->hitag == match)
|
|
{
|
|
found = true;
|
|
AnimateSwitch(sp, setting);
|
|
}
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
void SetSlidorActive(short SpriteNum)
|
|
{
|
|
USERp u = User[SpriteNum].Data();
|
|
SPRITEp sp = u->SpriteP;
|
|
ROTATORp r;
|
|
|
|
r = u->rotator.Data();
|
|
|
|
DoSlidorInterp(SpriteNum, StartInterpolation);
|
|
|
|
// play activate sound
|
|
DoSoundSpotMatch(SP_TAG2(sp), 1, SOUND_OBJECT_TYPE);
|
|
|
|
SET(u->Flags, SPR_ACTIVE);
|
|
u->Tics = 0;
|
|
|
|
// moving to the OFF position
|
|
if (r->tgt == 0)
|
|
VatorSwitch(SP_TAG2(sp), OFF);
|
|
else
|
|
VatorSwitch(SP_TAG2(sp), ON);
|
|
}
|
|
|
|
void SetSlidorInactive(short SpriteNum)
|
|
{
|
|
USERp u = User[SpriteNum].Data();
|
|
SPRITEp sp = u->SpriteP;
|
|
|
|
DoSlidorInterp(SpriteNum, StopInterpolation);
|
|
|
|
// play inactivate sound
|
|
DoSoundSpotMatch(SP_TAG2(sp), 2, SOUND_OBJECT_TYPE);
|
|
|
|
RESET(u->Flags, SPR_ACTIVE);
|
|
}
|
|
|
|
// called for operation from the space bar
|
|
short DoSlidorOperate(PLAYERp pp, short sectnum)
|
|
{
|
|
short match;
|
|
|
|
match = sector[sectnum].hitag;
|
|
|
|
|
|
if (match > 0)
|
|
{
|
|
if (TestSlidorMatchActive(match))
|
|
return -1;
|
|
else
|
|
return DoSlidorMatch(pp, match, true);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// called from switches and triggers
|
|
// returns first vator found
|
|
short
|
|
DoSlidorMatch(PLAYERp pp, short match, bool manual)
|
|
{
|
|
USERp fu;
|
|
SPRITEp fsp;
|
|
short sectnum;
|
|
short first_vator = -1;
|
|
|
|
int i;
|
|
|
|
//SlidorSwitch(match, ON);
|
|
|
|
StatIterator it(STAT_SLIDOR);
|
|
while ((i = it.NextIndex()) >= 0)
|
|
{
|
|
fsp = &sprite[i];
|
|
|
|
if (SP_TAG1(fsp) == SECT_SLIDOR && SP_TAG2(fsp) == match)
|
|
{
|
|
fu = User[i].Data();
|
|
|
|
// single play only vator
|
|
// bool 8 must be set for message to display
|
|
if (TEST_BOOL4(fsp) && (gNet.MultiGameType == MULTI_GAME_COMMBAT || gNet.MultiGameType == MULTI_GAME_AI_BOTS))
|
|
{
|
|
if (pp && TEST_BOOL11(fsp)) PutStringInfo(pp, GStrings("TXTS_SPONLY"));
|
|
continue;
|
|
}
|
|
|
|
// switch trigger only
|
|
if (SP_TAG3(fsp) == 1)
|
|
{
|
|
// tried to manually operat a switch/trigger only
|
|
if (manual)
|
|
continue;
|
|
}
|
|
|
|
if (first_vator == -1)
|
|
first_vator = i;
|
|
|
|
sectnum = fsp->sectnum;
|
|
|
|
if (pp && SectUser[sectnum].Data() && SectUser[sectnum]->stag == SECT_LOCK_DOOR && SectUser[sectnum]->number)
|
|
{
|
|
short key_num;
|
|
|
|
key_num = SectUser[sectnum]->number;
|
|
|
|
#if 0
|
|
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);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
PutStringInfo(pp, quoteMgr.GetQuote(QUOTE_DOORMSG + key_num - 1));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (TEST(fu->Flags, SPR_ACTIVE))
|
|
{
|
|
ReverseSlidor(i);
|
|
continue;
|
|
}
|
|
|
|
SetSlidorActive(i);
|
|
}
|
|
}
|
|
|
|
return first_vator;
|
|
}
|
|
|
|
|
|
bool
|
|
TestSlidorMatchActive(short match)
|
|
{
|
|
USERp fu;
|
|
SPRITEp fsp;
|
|
|
|
int i;
|
|
|
|
StatIterator it(STAT_SLIDOR);
|
|
while ((i = it.NextIndex()) >= 0)
|
|
{
|
|
fsp = &sprite[i];
|
|
|
|
if (SP_TAG1(fsp) == SECT_SLIDOR && SP_TAG2(fsp) == match)
|
|
{
|
|
fu = User[i].Data();
|
|
|
|
// Does not have to be inactive to be operated
|
|
if (TEST_BOOL6(fsp))
|
|
continue;
|
|
|
|
if (TEST(fu->Flags, SPR_ACTIVE) || fu->Tics)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void DoSlidorInterp(short SpriteNum, INTERP_FUNC interp_func)
|
|
{
|
|
short w, pw, startwall, endwall;
|
|
|
|
w = startwall = sector[sprite[SpriteNum].sectnum].wallptr;
|
|
endwall = startwall + sector[sprite[SpriteNum].sectnum].wallnum - 1;
|
|
|
|
do
|
|
{
|
|
switch (wall[w].lotag)
|
|
{
|
|
case TAG_WALL_SLIDOR_LEFT:
|
|
{
|
|
// prev wall
|
|
pw = w - 1;
|
|
if (w < startwall)
|
|
pw = endwall;
|
|
|
|
uint16_t const nextwall = wall[w].nextwall;
|
|
if (!validWallIndex(nextwall))
|
|
{
|
|
// white wall - move 4 points
|
|
interp_func(w, Interp_Wall_X);
|
|
interp_func(pw, Interp_Wall_X);
|
|
interp_func(wall[w].point2, Interp_Wall_X);
|
|
interp_func(wall[wall[w].point2].point2, Interp_Wall_X);
|
|
}
|
|
else
|
|
{
|
|
// red wall - move 2 points
|
|
interp_func(w, Interp_Wall_X);
|
|
interp_func(wall[nextwall].point2, Interp_Wall_X);
|
|
interp_func(wall[w].point2, Interp_Wall_X);
|
|
interp_func(wall[wall[wall[w].point2].nextwall].point2, Interp_Wall_X);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case TAG_WALL_SLIDOR_RIGHT:
|
|
{
|
|
// prev wall
|
|
pw = w - 1;
|
|
if (w < startwall)
|
|
pw = endwall;
|
|
|
|
uint16_t const nextwall = wall[w].nextwall;
|
|
if (!validWallIndex(nextwall))
|
|
{
|
|
// white wall - move 4 points
|
|
interp_func(w, Interp_Wall_X);
|
|
interp_func(pw, Interp_Wall_X);
|
|
interp_func(wall[w].point2, Interp_Wall_X);
|
|
interp_func(wall[wall[w].point2].point2, Interp_Wall_X);
|
|
}
|
|
else
|
|
{
|
|
// red wall - move 2 points
|
|
interp_func(w, Interp_Wall_X);
|
|
interp_func(wall[nextwall].point2, Interp_Wall_X);
|
|
interp_func(wall[w].point2, Interp_Wall_X);
|
|
interp_func(wall[wall[wall[w].point2].nextwall].point2, Interp_Wall_X);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case TAG_WALL_SLIDOR_UP:
|
|
{
|
|
// prev wall
|
|
pw = w - 1;
|
|
if (w < startwall)
|
|
pw = endwall;
|
|
|
|
uint16_t const nextwall = wall[w].nextwall;
|
|
if (!validWallIndex(nextwall))
|
|
{
|
|
interp_func(w, Interp_Wall_Y);
|
|
interp_func(pw, Interp_Wall_Y);
|
|
interp_func(wall[w].point2, Interp_Wall_Y);
|
|
interp_func(wall[wall[w].point2].point2, Interp_Wall_Y);
|
|
}
|
|
else
|
|
{
|
|
interp_func(w, Interp_Wall_Y);
|
|
interp_func(wall[nextwall].point2, Interp_Wall_Y);
|
|
interp_func(wall[w].point2, Interp_Wall_Y);
|
|
interp_func(wall[wall[wall[w].point2].nextwall].point2, Interp_Wall_Y);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case TAG_WALL_SLIDOR_DOWN:
|
|
{
|
|
// prev wall
|
|
pw = w - 1;
|
|
if (w < startwall)
|
|
pw = endwall;
|
|
|
|
uint16_t const nextwall = wall[w].nextwall;
|
|
if (!validWallIndex(nextwall))
|
|
{
|
|
interp_func(w, Interp_Wall_Y);
|
|
interp_func(pw, Interp_Wall_Y);
|
|
interp_func(wall[w].point2, Interp_Wall_Y);
|
|
interp_func(wall[wall[w].point2].point2, Interp_Wall_Y);
|
|
}
|
|
else
|
|
{
|
|
interp_func(w, Interp_Wall_Y);
|
|
interp_func(wall[nextwall].point2, Interp_Wall_Y);
|
|
interp_func(wall[w].point2, Interp_Wall_Y);
|
|
interp_func(wall[wall[wall[w].point2].nextwall].point2, Interp_Wall_Y);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
w = wall[w].point2;
|
|
}
|
|
while (w != startwall);
|
|
}
|
|
|
|
int DoSlidorMoveWalls(short SpriteNum, int amt)
|
|
{
|
|
short w, pw, startwall, endwall;
|
|
|
|
w = startwall = sector[sprite[SpriteNum].sectnum].wallptr;
|
|
endwall = startwall + sector[sprite[SpriteNum].sectnum].wallnum - 1;
|
|
|
|
do
|
|
{
|
|
switch (wall[w].lotag)
|
|
{
|
|
case TAG_WALL_SLIDOR_LEFT:
|
|
|
|
// prev wall
|
|
pw = w - 1;
|
|
if (w < startwall)
|
|
pw = endwall;
|
|
|
|
if (!validWallIndex(wall[w].nextwall))
|
|
{
|
|
// white wall - move 4 points
|
|
wall[w].x -= amt;
|
|
wall[pw].x -= amt;
|
|
wall[wall[w].point2].x -= amt;
|
|
wall[wall[wall[w].point2].point2].x -= amt;
|
|
}
|
|
else
|
|
{
|
|
// red wall - move 2 points
|
|
dragpoint(w, wall[w].x - amt, wall[w].y, 0);
|
|
dragpoint(wall[w].point2, wall[wall[w].point2].x - amt, wall[wall[w].point2].y, 0);
|
|
}
|
|
|
|
break;
|
|
|
|
case TAG_WALL_SLIDOR_RIGHT:
|
|
|
|
// prev wall
|
|
pw = w - 1;
|
|
if (w < startwall)
|
|
pw = endwall;
|
|
|
|
if (!validWallIndex(wall[w].nextwall))
|
|
{
|
|
// white wall - move 4 points
|
|
wall[w].x += amt;
|
|
wall[pw].x += amt;
|
|
wall[wall[w].point2].x += amt;
|
|
wall[wall[wall[w].point2].point2].x += amt;
|
|
}
|
|
else
|
|
{
|
|
// red wall - move 2 points
|
|
dragpoint(w, wall[w].x + amt, wall[w].y, 0);
|
|
dragpoint(wall[w].point2, wall[wall[w].point2].x + amt, wall[wall[w].point2].y, 0);
|
|
}
|
|
|
|
break;
|
|
|
|
case TAG_WALL_SLIDOR_UP:
|
|
|
|
// prev wall
|
|
pw = w - 1;
|
|
if (w < startwall)
|
|
pw = endwall;
|
|
|
|
if (!validWallIndex(wall[w].nextwall))
|
|
{
|
|
wall[w].y -= amt;
|
|
wall[pw].y -= amt;
|
|
wall[wall[w].point2].y -= amt;
|
|
wall[wall[wall[w].point2].point2].y -= amt;
|
|
}
|
|
else
|
|
{
|
|
dragpoint(w, wall[w].x, wall[w].y - amt, 0);
|
|
dragpoint(wall[w].point2, wall[wall[w].point2].x, wall[wall[w].point2].y - amt, 0);
|
|
}
|
|
|
|
break;
|
|
|
|
case TAG_WALL_SLIDOR_DOWN:
|
|
|
|
// prev wall
|
|
pw = w - 1;
|
|
if (w < startwall)
|
|
pw = endwall;
|
|
|
|
if (!validWallIndex(wall[w].nextwall))
|
|
{
|
|
wall[w].y += amt;
|
|
wall[pw].y += amt;
|
|
wall[wall[w].point2].y += amt;
|
|
wall[wall[wall[w].point2].point2].y += amt;
|
|
}
|
|
else
|
|
{
|
|
dragpoint(w, wall[w].x, wall[w].y + amt, 0);
|
|
dragpoint(wall[w].point2, wall[wall[w].point2].x, wall[wall[w].point2].y + amt, 0);
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
w = wall[w].point2;
|
|
}
|
|
while (w != startwall);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int DoSlidorInstantClose(short SpriteNum)
|
|
{
|
|
SPRITEp sp = &sprite[SpriteNum];
|
|
short w, startwall;
|
|
int diff;
|
|
|
|
w = startwall = sector[sprite[SpriteNum].sectnum].wallptr;
|
|
|
|
do
|
|
{
|
|
switch (wall[w].lotag)
|
|
{
|
|
case TAG_WALL_SLIDOR_LEFT:
|
|
diff = wall[w].x - sp->x;
|
|
DoSlidorMoveWalls(SpriteNum, diff);
|
|
break;
|
|
|
|
case TAG_WALL_SLIDOR_RIGHT:
|
|
diff = wall[w].x - sp->x;
|
|
DoSlidorMoveWalls(SpriteNum, -diff);
|
|
break;
|
|
|
|
case TAG_WALL_SLIDOR_UP:
|
|
diff = wall[w].y - sp->y;
|
|
DoSlidorMoveWalls(SpriteNum, diff);
|
|
break;
|
|
|
|
case TAG_WALL_SLIDOR_DOWN:
|
|
diff = wall[w].y - sp->y;
|
|
DoSlidorMoveWalls(SpriteNum, -diff);
|
|
break;
|
|
}
|
|
|
|
w = wall[w].point2;
|
|
}
|
|
while (w != startwall);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int DoSlidorMove(short SpriteNum)
|
|
{
|
|
USERp u = User[SpriteNum].Data();
|
|
SPRITEp sp = u->SpriteP;
|
|
ROTATORp r;
|
|
int old_pos;
|
|
bool kill = false;
|
|
|
|
r = u->rotator.Data();
|
|
|
|
// Example - ang pos moves from 0 to 512 <<OR>> from 0 to -512
|
|
|
|
old_pos = r->pos;
|
|
|
|
// control SPEED of swinging
|
|
if (r->pos < r->tgt)
|
|
{
|
|
// Increment swing angle
|
|
r->pos += r->speed;
|
|
r->speed += r->vel;
|
|
|
|
// if the other way make it equal
|
|
if (r->pos > r->tgt)
|
|
r->pos = r->tgt;
|
|
}
|
|
|
|
if (r->pos > r->tgt)
|
|
{
|
|
// Increment swing angle
|
|
r->pos -= r->speed;
|
|
r->speed += r->vel;
|
|
|
|
// if the other way make it equal
|
|
if (r->pos < r->tgt)
|
|
r->pos = r->tgt;
|
|
}
|
|
|
|
if (r->pos == r->tgt)
|
|
{
|
|
// If ang is OPEN
|
|
if (r->pos == r->open_dest)
|
|
{
|
|
// new tgt is CLOSED (0)
|
|
r->tgt = 0;
|
|
r->vel = -r->vel;
|
|
SetSlidorInactive(SpriteNum);
|
|
|
|
if (SP_TAG6(sp) && !TEST_BOOL8(sp))
|
|
DoMatchEverything(nullptr, SP_TAG6(sp), -1);
|
|
|
|
// wait a bit and close it
|
|
if (u->WaitTics)
|
|
u->Tics = u->WaitTics;
|
|
}
|
|
else
|
|
// If ang is CLOSED then
|
|
if (r->pos == 0)
|
|
{
|
|
short match = SP_TAG2(sp);
|
|
|
|
// new tgt is OPEN (open)
|
|
r->speed = r->orig_speed;
|
|
r->vel = labs(r->vel);
|
|
|
|
r->tgt = r->open_dest;
|
|
SetSlidorInactive(SpriteNum);
|
|
|
|
RESET_BOOL8(sp);
|
|
|
|
// set owner swith back to OFF
|
|
// only if ALL vators are inactive
|
|
if (!TestSlidorMatchActive(match))
|
|
{
|
|
//SlidorSwitch(match, OFF);
|
|
}
|
|
|
|
if (SP_TAG6(sp) && TEST_BOOL8(sp))
|
|
DoMatchEverything(nullptr, SP_TAG6(sp), -1);
|
|
}
|
|
|
|
if (TEST_BOOL2(sp))
|
|
kill = true;
|
|
}
|
|
else
|
|
{
|
|
// if heading for the OFF (original) position and should NOT CRUSH
|
|
if (TEST_BOOL3(sp) && r->tgt == 0)
|
|
{
|
|
int i;
|
|
SPRITEp bsp;
|
|
USERp bu;
|
|
bool found = false;
|
|
|
|
SectIterator it(sp->sectnum);
|
|
while ((i = it.NextIndex()) >= 0)
|
|
{
|
|
bsp = &sprite[i];
|
|
bu = User[i].Data();
|
|
|
|
if (bu && TEST(bsp->cstat, CSTAT_SPRITE_BLOCK) && TEST(bsp->extra, SPRX_PLAYER_OR_ENEMY))
|
|
{
|
|
// found something blocking so reverse to ON position
|
|
ReverseSlidor(SpriteNum);
|
|
SET_BOOL8(sp); // tell vator that something blocking door
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
short pnum;
|
|
PLAYERp pp;
|
|
// go ahead and look for players clip box bounds
|
|
TRAVERSE_CONNECT(pnum)
|
|
{
|
|
pp = Player + pnum;
|
|
|
|
if (pp->lo_sectp == §or[sp->sectnum] ||
|
|
pp->hi_sectp == §or[sp->sectnum])
|
|
{
|
|
ReverseSlidor(SpriteNum);
|
|
|
|
u->vel_rate = -u->vel_rate;
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DoSlidorMoveWalls(SpriteNum, r->pos - old_pos);
|
|
|
|
if (kill)
|
|
{
|
|
SetSlidorInactive(SpriteNum);
|
|
KillSprite(SpriteNum);
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int DoSlidor(DSWActor* actor)
|
|
{
|
|
USER* u = actor->u();
|
|
int SpriteNum = u->SpriteNum;
|
|
SPRITEp sp = &sprite[SpriteNum];
|
|
SECTORp sectp = §or[sp->sectnum];
|
|
|
|
DoSlidorMove(SpriteNum);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#include "saveable.h"
|
|
|
|
static saveable_code saveable_slidor_code[] =
|
|
{
|
|
SAVE_CODE(DoSlidor),
|
|
};
|
|
|
|
saveable_module saveable_slidor =
|
|
{
|
|
// code
|
|
saveable_slidor_code,
|
|
SIZ(saveable_slidor_code),
|
|
|
|
// data
|
|
nullptr,0
|
|
};
|
|
END_SW_NS
|