raze/source/games/sw/src/rotator.cpp

413 lines
9.3 KiB
C++
Raw Normal View History

//-------------------------------------------------------------------------
/*
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"
2020-08-05 22:18:45 +00:00
#include "misc.h"
#include "network.h"
#include "tags.h"
#include "sector.h"
#include "interpolate.h"
#include "sprite.h"
#include "quotemgr.h"
BEGIN_SW_NS
2021-11-02 18:53:03 +00:00
void DoRotatorMatch(PLAYERp pp, short match, bool);
2020-09-09 18:32:24 +00:00
bool TestRotatorMatchActive(short match);
void InterpSectorSprites(short sectnum, bool state);
void DoMatchEverything(PLAYERp pp, short match, short state);
2021-11-02 18:53:03 +00:00
void DoRotatorSetInterp(DSWActor*);
void DoRotatorStopInterp(DSWActor*);
2021-11-02 18:41:37 +00:00
void ReverseRotator(DSWActor* actor)
{
2021-11-02 18:41:37 +00:00
USERp u = actor->u();
ROTATORp r;
r = u->rotator.Data();
// if paused go ahead and start it up again
if (u->Tics)
{
u->Tics = 0;
2021-11-02 18:41:37 +00:00
SetRotatorActive(actor);
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;
}
2021-11-02 18:41:37 +00:00
bool RotatorSwitch(short match, short setting)
{
SPRITEp sp;
2020-09-09 18:32:24 +00:00
bool found = false;
2021-11-02 18:41:37 +00:00
SWStatIterator it(STAT_DEFAULT);
while (auto actor = it.Next())
{
2021-11-02 18:41:37 +00:00
sp = &actor->s();
if (sp->lotag == TAG_SPRITE_SWITCH_VATOR && sp->hitag == match)
{
found = true;
AnimateSwitch(sp, setting);
}
}
return found;
}
2021-11-02 18:41:37 +00:00
void SetRotatorActive(DSWActor* actor)
{
2021-11-02 18:41:37 +00:00
USERp u = actor->u();
SPRITEp sp = &actor->s();
ROTATORp r;
r = u->rotator.Data();
2021-11-02 18:53:03 +00:00
DoRotatorSetInterp(actor);
// 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);
}
2021-11-02 18:53:03 +00:00
void SetRotatorInactive(DSWActor* actor)
{
2021-11-02 18:53:03 +00:00
USERp u = actor->u();
SPRITEp sp = &actor->s();
2021-11-02 18:53:03 +00:00
DoRotatorStopInterp(actor);
// play inactivate sound
DoSoundSpotMatch(SP_TAG2(sp), 2, SOUND_OBJECT_TYPE);
RESET(u->Flags, SPR_ACTIVE);
}
// called for operation from the space bar
2021-11-02 18:53:03 +00:00
void DoRotatorOperate(PLAYERp pp, short sectnum)
{
2021-11-02 18:53:03 +00:00
short match = sector[sectnum].hitag;
if (match > 0)
{
2021-11-02 18:53:03 +00:00
if (!TestRotatorMatchActive(match))
DoRotatorMatch(pp, match, true);
}
}
// called from switches and triggers
// returns first vator found
2021-11-02 18:53:03 +00:00
void DoRotatorMatch(PLAYERp pp, short match, bool manual)
{
USERp fu;
SPRITEp fsp;
short sectnum;
2021-11-02 18:41:37 +00:00
DSWActor* firstVator = nullptr;
//RotatorSwitch(match, ON);
2021-11-02 18:41:37 +00:00
SWStatIterator it(STAT_ROTATOR);
while (auto actor = it.Next())
{
2021-11-02 18:41:37 +00:00
fsp = &actor->s();
if (SP_TAG1(fsp) == SECT_ROTATOR && SP_TAG2(fsp) == match)
{
2021-11-02 18:41:37 +00:00
fu = actor->u();
// single play only vator
2020-09-09 18:32:24 +00:00
// 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;
}
2021-11-02 18:41:37 +00:00
if (firstVator == nullptr)
firstVator = actor;
auto sect = fsp->sector();
2021-11-20 22:20:43 +00:00
if (pp && sect->hasU() && sect->stag == SECT_LOCK_DOOR && sect->number)
{
2021-11-20 22:20:43 +00:00
int key_num = sect->number;
{
PutStringInfo(pp, quoteMgr.GetQuote(QUOTE_DOORMSG + key_num - 1));
2021-11-02 18:53:03 +00:00
return;
}
}
if (TEST(fu->Flags, SPR_ACTIVE))
{
2021-11-02 18:41:37 +00:00
ReverseRotator(actor);
continue;
}
2021-11-02 18:41:37 +00:00
SetRotatorActive(actor);
}
}
}
2021-11-02 18:53:03 +00:00
bool TestRotatorMatchActive(short match)
{
USERp fu;
SPRITEp fsp;
2021-11-02 18:53:03 +00:00
SWStatIterator it(STAT_ROTATOR);
while (auto actor = it.Next())
{
2021-11-02 18:53:03 +00:00
fsp = &actor->s();
if (SP_TAG1(fsp) == SECT_ROTATOR && SP_TAG2(fsp) == match)
{
2021-11-02 18:53:03 +00:00
fu = actor->u();
// 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;
}
2021-11-02 18:53:03 +00:00
void DoRotatorSetInterp(DSWActor* actor)
{
2021-11-02 18:53:03 +00:00
SPRITEp sp = &actor->s();
for(auto& wal : wallsofsector(sp->sector()))
{
StartInterpolation(&wal, Interp_Wall_X);
StartInterpolation(&wal, Interp_Wall_Y);
if (wal.twoSided())
{
auto w2 = wal.nextWall()->point2Wall();
StartInterpolation(w2, Interp_Wall_X);
StartInterpolation(w2, Interp_Wall_Y);
}
}
}
2021-11-02 18:53:03 +00:00
void DoRotatorStopInterp(DSWActor* actor)
{
2021-11-02 18:53:03 +00:00
SPRITEp sp = &actor->s();
for (auto& wal : wallsofsector(sp->sector()))
{
StopInterpolation(&wal, Interp_Wall_X);
StopInterpolation(&wal, Interp_Wall_Y);
if (wal.twoSided())
{
auto w2 = wal.nextWall()->point2Wall();
StopInterpolation(w2, Interp_Wall_X);
StopInterpolation(w2, Interp_Wall_Y);
}
}
}
2021-11-02 18:53:03 +00:00
int DoRotator(DSWActor* actor)
{
2021-10-30 20:53:24 +00:00
USERp u = actor->u();
SPRITEp sp = &actor->s();
ROTATORp r;
short ndx,w,startwall,endwall;
SPRITEp pivot = nullptr;
vec2_t nxy;
int dist,closest;
2020-09-09 18:32:24 +00:00
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;
2021-11-02 18:53:03 +00:00
SetRotatorInactive(actor);
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);
2021-11-02 18:53:03 +00:00
SetRotatorInactive(actor);
2021-11-02 23:14:09 +00:00
// 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;
2021-11-06 08:29:38 +00:00
SWStatIterator it(STAT_ROTATOR_PIVOT);
while (auto itActor = it.Next())
{
2021-11-06 08:29:38 +00:00
auto itsp = &itActor->s();
if (itsp->lotag == sp->lotag)
{
2021-11-06 08:29:38 +00:00
dist = Distance(sp->x, sp->y, itsp->x, itsp->y);
if (dist < closest)
{
closest = dist;
2021-11-06 08:29:38 +00:00
pivot = itsp;
}
}
}
if (!pivot)
return 0;
startwall = sp->sector()->wallptr;
endwall = startwall + sp->sector()->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);
ndx++;
}
if (kill)
{
2021-11-02 18:53:03 +00:00
SetRotatorInactive(actor);
2021-10-30 20:53:24 +00:00
KillActor(actor);
return 0;
}
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