2015-05-19 21:54:34 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
2019-10-09 16:09:05 +00:00
|
|
|
#include "ns.h"
|
2015-05-19 21:54:34 +00:00
|
|
|
#include "build.h"
|
|
|
|
|
|
|
|
#include "names2.h"
|
|
|
|
#include "panel.h"
|
2020-08-05 22:18:45 +00:00
|
|
|
#include "misc.h"
|
2019-03-21 02:24:19 +00:00
|
|
|
#include "network.h"
|
2015-05-19 21:54:34 +00:00
|
|
|
#include "tags.h"
|
|
|
|
#include "sector.h"
|
2020-11-26 17:05:49 +00:00
|
|
|
#include "interpolate.h"
|
2015-05-19 21:54:34 +00:00
|
|
|
#include "sprite.h"
|
2019-12-09 17:40:07 +00:00
|
|
|
#include "quotemgr.h"
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2019-10-09 16:09:05 +00:00
|
|
|
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);
|
2015-05-19 21:58:29 +00:00
|
|
|
void DoMatchEverything(PLAYERp pp, short match, short state);
|
2021-11-02 18:53:03 +00:00
|
|
|
void DoRotatorSetInterp(DSWActor*);
|
|
|
|
void DoRotatorStopInterp(DSWActor*);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-11-02 18:41:37 +00:00
|
|
|
void ReverseRotator(DSWActor* actor)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
ROTATORp r;
|
|
|
|
|
2021-12-25 22:16:26 +00:00
|
|
|
r = actor->user.rotator.Data();
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
// if paused go ahead and start it up again
|
2021-12-25 22:16:26 +00:00
|
|
|
if (actor->user.Tics)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-12-25 22:16:26 +00:00
|
|
|
actor->user.Tics = 0;
|
2021-11-02 18:41:37 +00:00
|
|
|
SetRotatorActive(actor);
|
2015-05-19 21:54:34 +00:00
|
|
|
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)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-09-09 18:32:24 +00:00
|
|
|
bool found = false;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-11-02 18:41:37 +00:00
|
|
|
SWStatIterator it(STAT_DEFAULT);
|
|
|
|
while (auto actor = it.Next())
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-12-24 21:19:22 +00:00
|
|
|
if (actor->spr.lotag == TAG_SPRITE_SWITCH_VATOR && actor->spr.hitag == match)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-09-09 17:52:52 +00:00
|
|
|
found = true;
|
2021-12-24 16:32:27 +00:00
|
|
|
AnimateSwitch(actor, setting);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2021-11-02 18:41:37 +00:00
|
|
|
void SetRotatorActive(DSWActor* actor)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
ROTATORp r;
|
|
|
|
|
2021-12-25 22:16:26 +00:00
|
|
|
r = actor->user.rotator.Data();
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-11-02 18:53:03 +00:00
|
|
|
DoRotatorSetInterp(actor);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
// play activate sound
|
2021-12-24 13:12:21 +00:00
|
|
|
DoSoundSpotMatch(SP_TAG2(actor), 1, SOUND_OBJECT_TYPE);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-12-25 22:16:26 +00:00
|
|
|
SET(actor->user.Flags, SPR_ACTIVE);
|
|
|
|
actor->user.Tics = 0;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
// moving to the OFF position
|
|
|
|
if (r->tgt == 0)
|
2021-12-24 13:12:21 +00:00
|
|
|
VatorSwitch(SP_TAG2(actor), false);
|
2015-05-19 21:54:34 +00:00
|
|
|
else
|
2021-12-24 13:12:21 +00:00
|
|
|
VatorSwitch(SP_TAG2(actor), true);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
2021-11-02 18:53:03 +00:00
|
|
|
void SetRotatorInactive(DSWActor* actor)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-11-02 18:53:03 +00:00
|
|
|
DoRotatorStopInterp(actor);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
// play inactivate sound
|
2021-12-24 13:12:21 +00:00
|
|
|
DoSoundSpotMatch(SP_TAG2(actor), 2, SOUND_OBJECT_TYPE);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-12-25 22:16:26 +00:00
|
|
|
RESET(actor->user.Flags, SPR_ACTIVE);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// called for operation from the space bar
|
2021-11-25 15:55:46 +00:00
|
|
|
void DoRotatorOperate(PLAYERp pp, sectortype* sect)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-11-25 15:55:46 +00:00
|
|
|
short match = sect->hitag;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
if (match > 0)
|
|
|
|
{
|
2021-11-02 18:53:03 +00:00
|
|
|
if (!TestRotatorMatchActive(match))
|
|
|
|
DoRotatorMatch(pp, match, true);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-11-02 18:41:37 +00:00
|
|
|
DSWActor* firstVator = nullptr;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
//RotatorSwitch(match, ON);
|
|
|
|
|
2021-11-02 18:41:37 +00:00
|
|
|
SWStatIterator it(STAT_ROTATOR);
|
|
|
|
while (auto actor = it.Next())
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-12-24 13:12:21 +00:00
|
|
|
if (SP_TAG1(actor) == SECT_ROTATOR && SP_TAG2(actor) == match)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
// single play only vator
|
2020-09-09 18:32:24 +00:00
|
|
|
// bool 8 must be set for message to display
|
2021-12-24 23:32:23 +00:00
|
|
|
if (TEST_BOOL4(actor) && (gNet.MultiGameType == MULTI_GAME_COMMBAT || gNet.MultiGameType == MULTI_GAME_AI_BOTS))
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-12-24 23:32:23 +00:00
|
|
|
if (pp && TEST_BOOL11(actor)) PutStringInfo(pp, GStrings("TXT_SPONLY"));
|
2015-05-19 21:54:34 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// switch trigger only
|
2021-12-24 23:32:23 +00:00
|
|
|
if (SP_TAG3(actor) == 1)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
// tried to manually operat a switch/trigger only
|
|
|
|
if (manual)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-11-02 18:41:37 +00:00
|
|
|
if (firstVator == nullptr)
|
|
|
|
firstVator = actor;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-12-24 23:32:23 +00:00
|
|
|
auto sect = actor->spr.sector();
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-11-20 22:20:43 +00:00
|
|
|
if (pp && sect->hasU() && sect->stag == SECT_LOCK_DOOR && sect->number)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-11-20 22:20:43 +00:00
|
|
|
int key_num = sect->number;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
{
|
2020-01-24 18:50:44 +00:00
|
|
|
PutStringInfo(pp, quoteMgr.GetQuote(QUOTE_DOORMSG + key_num - 1));
|
2021-11-02 18:53:03 +00:00
|
|
|
return;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-25 22:16:26 +00:00
|
|
|
if (TEST(actor->user.Flags, SPR_ACTIVE))
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-11-02 18:41:37 +00:00
|
|
|
ReverseRotator(actor);
|
2015-05-19 21:54:34 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-11-02 18:41:37 +00:00
|
|
|
SetRotatorActive(actor);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-02 18:53:03 +00:00
|
|
|
bool TestRotatorMatchActive(short match)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-11-02 18:53:03 +00:00
|
|
|
SWStatIterator it(STAT_ROTATOR);
|
|
|
|
while (auto actor = it.Next())
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-12-24 13:12:21 +00:00
|
|
|
if (SP_TAG1(actor) == SECT_ROTATOR && SP_TAG2(actor) == match)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
// Does not have to be inactive to be operated
|
2021-12-24 23:32:23 +00:00
|
|
|
if (TEST_BOOL6(actor))
|
2015-05-19 21:54:34 +00:00
|
|
|
continue;
|
|
|
|
|
2021-12-25 22:16:26 +00:00
|
|
|
if (TEST(actor->user.Flags, SPR_ACTIVE) || actor->user.Tics)
|
2020-09-09 17:52:52 +00:00
|
|
|
return true;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-09 17:52:52 +00:00
|
|
|
return false;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-02 18:53:03 +00:00
|
|
|
void DoRotatorSetInterp(DSWActor* actor)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-12-24 21:19:22 +00:00
|
|
|
for(auto& wal : wallsofsector(actor->spr.sector()))
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-11-24 15:39:29 +00:00
|
|
|
StartInterpolation(&wal, Interp_Wall_X);
|
|
|
|
StartInterpolation(&wal, Interp_Wall_Y);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-11-24 15:39:29 +00:00
|
|
|
if (wal.twoSided())
|
2019-11-27 07:33:34 +00:00
|
|
|
{
|
2021-11-24 15:39:29 +00:00
|
|
|
auto w2 = wal.nextWall()->point2Wall();
|
|
|
|
StartInterpolation(w2, Interp_Wall_X);
|
|
|
|
StartInterpolation(w2, Interp_Wall_Y);
|
2019-11-27 07:33:34 +00:00
|
|
|
}
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-02 18:53:03 +00:00
|
|
|
void DoRotatorStopInterp(DSWActor* actor)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-12-24 21:19:22 +00:00
|
|
|
for (auto& wal : wallsofsector(actor->spr.sector()))
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-11-24 15:39:29 +00:00
|
|
|
StopInterpolation(&wal, Interp_Wall_X);
|
|
|
|
StopInterpolation(&wal, Interp_Wall_Y);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-11-24 15:39:29 +00:00
|
|
|
if (wal.twoSided())
|
2019-11-27 07:33:34 +00:00
|
|
|
{
|
2021-11-24 15:39:29 +00:00
|
|
|
auto w2 = wal.nextWall()->point2Wall();
|
|
|
|
StopInterpolation(w2, Interp_Wall_X);
|
|
|
|
StopInterpolation(w2, Interp_Wall_Y);
|
2019-11-27 07:33:34 +00:00
|
|
|
}
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-02 18:53:03 +00:00
|
|
|
int DoRotator(DSWActor* actor)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
ROTATORp r;
|
|
|
|
short ndx,w,startwall,endwall;
|
2021-12-24 23:45:19 +00:00
|
|
|
DSWActor* pivot = nullptr;
|
2016-05-23 04:46:30 +00:00
|
|
|
vec2_t nxy;
|
2015-05-19 21:54:34 +00:00
|
|
|
int dist,closest;
|
2020-09-09 18:32:24 +00:00
|
|
|
bool kill = false;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-12-25 22:16:26 +00:00
|
|
|
r = actor->user.rotator.Data();
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
// 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);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-12-24 21:19:22 +00:00
|
|
|
if (SP_TAG6(actor))
|
|
|
|
DoMatchEverything(nullptr, SP_TAG6(actor), -1);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
// wait a bit and close it
|
2021-12-25 22:16:26 +00:00
|
|
|
if (actor->user.WaitTics)
|
|
|
|
actor->user.Tics = actor->user.WaitTics;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
// If ang is CLOSED then
|
|
|
|
if (r->pos == 0)
|
|
|
|
{
|
2021-12-24 13:12:21 +00:00
|
|
|
short match = SP_TAG2(actor);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
|
|
|
// 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);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-11-02 23:14:09 +00:00
|
|
|
// set Owner swith back to OFF
|
2015-05-19 21:54:34 +00:00
|
|
|
// only if ALL vators are inactive
|
|
|
|
if (!TestRotatorMatchActive(match))
|
|
|
|
{
|
|
|
|
//RotatorSwitch(match, OFF);
|
|
|
|
}
|
|
|
|
|
2021-12-24 21:19:22 +00:00
|
|
|
if (SP_TAG6(actor) && TEST_BOOL5(actor))
|
|
|
|
DoMatchEverything(nullptr, SP_TAG6(actor), -1);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
2021-12-24 21:19:22 +00:00
|
|
|
if (TEST_BOOL2(actor))
|
2020-09-09 17:52:52 +00:00
|
|
|
kill = true;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
closest = 99999;
|
2021-11-06 08:29:38 +00:00
|
|
|
SWStatIterator it(STAT_ROTATOR_PIVOT);
|
|
|
|
while (auto itActor = it.Next())
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-12-24 23:45:19 +00:00
|
|
|
if (itActor->spr.lotag == actor->spr.lotag)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-12-24 23:45:19 +00:00
|
|
|
dist = Distance(actor->spr.pos.X, actor->spr.pos.Y, itActor->spr.pos.X, itActor->spr.pos.Y);
|
2015-05-19 21:54:34 +00:00
|
|
|
if (dist < closest)
|
|
|
|
{
|
|
|
|
closest = dist;
|
2021-12-24 23:45:19 +00:00
|
|
|
pivot = itActor;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pivot)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// move points
|
2021-11-24 21:08:41 +00:00
|
|
|
ndx = 0;
|
2021-12-24 21:19:22 +00:00
|
|
|
for(auto& wal : wallsofsector(actor->spr.sector()))
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2021-04-02 08:44:41 +00:00
|
|
|
vec2_t const orig = { r->origX[ndx], r->origY[ndx] };
|
2021-12-24 23:45:19 +00:00
|
|
|
rotatepoint(pivot->spr.pos.vec2, orig, r->pos, &nxy);
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2021-12-22 09:28:51 +00:00
|
|
|
dragpoint(&wal, nxy.X, nxy.Y);
|
2015-05-19 21:54:34 +00:00
|
|
|
ndx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (kill)
|
|
|
|
{
|
2021-11-02 18:53:03 +00:00
|
|
|
SetRotatorInactive(actor);
|
2021-10-30 20:53:24 +00:00
|
|
|
KillActor(actor);
|
2015-05-19 21:54:34 +00:00
|
|
|
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
|
2021-07-10 12:25:18 +00:00
|
|
|
nullptr,0
|
2015-05-19 21:54:34 +00:00
|
|
|
};
|
|
|
|
|
2019-10-09 16:09:05 +00:00
|
|
|
END_SW_NS
|