raze/source/games/sw/src/rotator.cpp
Christoph Oelckers 8f19dc12d8 - SW: code/data pointer saving cleanup.
* 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.
2021-11-11 23:28:28 +01:00

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