mirror of
https://github.com/DrBeef/Raze.git
synced 2025-02-09 09:11:02 +00:00
* 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.
464 lines
11 KiB
C++
464 lines
11 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 "misc.h"
|
|
#include "network.h"
|
|
#include "tags.h"
|
|
#include "sector.h"
|
|
#include "interpolate.h"
|
|
#include "sprite.h"
|
|
#include "quotemgr.h"
|
|
|
|
BEGIN_SW_NS
|
|
|
|
short DoRotatorMatch(PLAYERp pp, short match, bool);
|
|
bool TestRotatorMatchActive(short match);
|
|
void InterpSectorSprites(short sectnum, bool state);
|
|
void DoMatchEverything(PLAYERp pp, short match, short state);
|
|
void DoRotatorSetInterp(short SpriteNum);
|
|
void DoRotatorStopInterp(short SpriteNum);
|
|
|
|
void ReverseRotator(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;
|
|
SetRotatorActive(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
|
|
RotatorSwitch(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 SetRotatorActive(short SpriteNum)
|
|
{
|
|
USERp u = User[SpriteNum].Data();
|
|
SPRITEp sp = u->SpriteP;
|
|
ROTATORp r;
|
|
|
|
r = u->rotator.Data();
|
|
|
|
DoRotatorSetInterp(SpriteNum);
|
|
|
|
// 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 SetRotatorInactive(short SpriteNum)
|
|
{
|
|
USERp u = User[SpriteNum].Data();
|
|
SPRITEp sp = u->SpriteP;
|
|
|
|
DoRotatorStopInterp(SpriteNum);
|
|
|
|
// play inactivate sound
|
|
DoSoundSpotMatch(SP_TAG2(sp), 2, SOUND_OBJECT_TYPE);
|
|
|
|
RESET(u->Flags, SPR_ACTIVE);
|
|
}
|
|
|
|
// called for operation from the space bar
|
|
short DoRotatorOperate(PLAYERp pp, short sectnum)
|
|
{
|
|
short match;
|
|
|
|
match = sector[sectnum].hitag;
|
|
|
|
if (match > 0)
|
|
{
|
|
if (TestRotatorMatchActive(match))
|
|
return -1;
|
|
else
|
|
return DoRotatorMatch(pp, match, true);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// called from switches and triggers
|
|
// returns first vator found
|
|
short
|
|
DoRotatorMatch(PLAYERp pp, short match, bool manual)
|
|
{
|
|
USERp fu;
|
|
SPRITEp fsp;
|
|
short sectnum;
|
|
short first_vator = -1;
|
|
|
|
int i;
|
|
|
|
//RotatorSwitch(match, ON);
|
|
|
|
StatIterator it(STAT_ROTATOR);
|
|
while ((i = it.NextIndex()) >= 0)
|
|
{
|
|
fsp = &sprite[i];
|
|
|
|
if (SP_TAG1(fsp) == SECT_ROTATOR && 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("TXT_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))
|
|
{
|
|
ReverseRotator(i);
|
|
continue;
|
|
}
|
|
|
|
SetRotatorActive(i);
|
|
}
|
|
}
|
|
|
|
return first_vator;
|
|
}
|
|
|
|
|
|
bool
|
|
TestRotatorMatchActive(short match)
|
|
{
|
|
USERp fu;
|
|
SPRITEp fsp;
|
|
|
|
int i;
|
|
|
|
StatIterator it(STAT_ROTATOR);
|
|
while ((i = it.NextIndex()) >= 0)
|
|
{
|
|
fsp = &sprite[i];
|
|
|
|
if (SP_TAG1(fsp) == SECT_ROTATOR && 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 DoRotatorSetInterp(short SpriteNum)
|
|
{
|
|
SPRITEp sp = &sprite[SpriteNum];
|
|
short w,startwall,endwall;
|
|
|
|
startwall = sector[sp->sectnum].wallptr;
|
|
endwall = startwall + sector[sp->sectnum].wallnum - 1;
|
|
|
|
// move points
|
|
for (w = startwall; w <= endwall; w++)
|
|
{
|
|
StartInterpolation(w, Interp_Wall_X);
|
|
StartInterpolation(w, Interp_Wall_Y);
|
|
|
|
uint16_t const nextwall = wall[w].nextwall;
|
|
if (validWallIndex(nextwall))
|
|
{
|
|
StartInterpolation(wall[nextwall].point2, Interp_Wall_X);
|
|
StartInterpolation(wall[nextwall].point2, Interp_Wall_Y);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DoRotatorStopInterp(short SpriteNum)
|
|
{
|
|
SPRITEp sp = &sprite[SpriteNum];
|
|
short w,startwall,endwall;
|
|
|
|
startwall = sector[sp->sectnum].wallptr;
|
|
endwall = startwall + sector[sp->sectnum].wallnum - 1;
|
|
|
|
// move points
|
|
for (w = startwall; w <= endwall; w++)
|
|
{
|
|
StopInterpolation(w, Interp_Wall_X);
|
|
StopInterpolation(w, Interp_Wall_Y);
|
|
|
|
uint16_t const nextwall = wall[w].nextwall;
|
|
if (validWallIndex(nextwall))
|
|
{
|
|
StopInterpolation(wall[nextwall].point2, Interp_Wall_X);
|
|
StopInterpolation(wall[nextwall].point2, Interp_Wall_Y);
|
|
}
|
|
}
|
|
}
|
|
|
|
int DoRotatorMove(short SpriteNum)
|
|
{
|
|
USERp u = User[SpriteNum].Data();
|
|
SPRITEp sp = u->SpriteP;
|
|
ROTATORp r;
|
|
short ndx,w,startwall,endwall;
|
|
SPRITEp pivot = nullptr;
|
|
int i;
|
|
vec2_t nxy;
|
|
int dist,closest;
|
|
bool kill = false;
|
|
|
|
r = u->rotator.Data();
|
|
|
|
// Example - ang pos moves from 0 to 512 <<OR>> from 0 to -512
|
|
|
|
// 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;
|
|
SetRotatorInactive(SpriteNum);
|
|
|
|
if (SP_TAG6(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->tgt = r->open_dest;
|
|
r->speed = r->orig_speed;
|
|
r->vel = labs(r->vel);
|
|
|
|
SetRotatorInactive(SpriteNum);
|
|
|
|
// set owner swith back to OFF
|
|
// only if ALL vators are inactive
|
|
if (!TestRotatorMatchActive(match))
|
|
{
|
|
//RotatorSwitch(match, OFF);
|
|
}
|
|
|
|
if (SP_TAG6(sp) && TEST_BOOL5(sp))
|
|
DoMatchEverything(nullptr, SP_TAG6(sp), -1);
|
|
}
|
|
|
|
if (TEST_BOOL2(sp))
|
|
kill = true;
|
|
}
|
|
|
|
closest = 99999;
|
|
StatIterator it(STAT_ROTATOR_PIVOT);
|
|
while ((i = it.NextIndex()) >= 0)
|
|
{
|
|
if (sprite[i].lotag == sp->lotag)
|
|
{
|
|
dist = Distance(sp->x, sp->y, sprite[i].x, sprite[i].y);
|
|
if (dist < closest)
|
|
{
|
|
closest = dist;
|
|
pivot = &sprite[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pivot)
|
|
return 0;
|
|
|
|
startwall = sector[sp->sectnum].wallptr;
|
|
endwall = startwall + sector[sp->sectnum].wallnum - 1;
|
|
|
|
// move points
|
|
for (w = startwall, ndx = 0; w <= endwall; w++)
|
|
{
|
|
vec2_t const orig = { r->origX[ndx], r->origY[ndx] };
|
|
rotatepoint(pivot->pos.vec2, orig, r->pos, &nxy);
|
|
|
|
dragpoint(w, nxy.x, nxy.y, 0);
|
|
ndx++;
|
|
}
|
|
|
|
if (kill)
|
|
{
|
|
SetRotatorInactive(SpriteNum);
|
|
KillSprite(SpriteNum);
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int DoRotator(DSWActor* actor)
|
|
{
|
|
USER* u = actor->u();
|
|
int SpriteNum = u->SpriteNum;
|
|
|
|
// could move this inside sprite control
|
|
DoRotatorMove(SpriteNum);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#include "saveable.h"
|
|
|
|
static saveable_code saveable_rotator_code[] =
|
|
{
|
|
SAVE_CODE(DoRotator)
|
|
};
|
|
|
|
saveable_module saveable_rotator =
|
|
{
|
|
// code
|
|
saveable_rotator_code,
|
|
SIZ(saveable_rotator_code),
|
|
|
|
// data
|
|
nullptr,0
|
|
};
|
|
|
|
END_SW_NS
|