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

510 lines
11 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"
#include "game.h"
#include "tags.h"
#include "sector.h"
#include "sprite.h"
#include "interpolate.h"
BEGIN_SW_NS
short DoSpikeMatch(short match);
2020-09-09 18:32:24 +00:00
bool TestSpikeMatchActive(short match);
int DoVatorMove(short SpriteNum, int *lptr);
2020-09-09 18:32:24 +00:00
void InterpSectorSprites(short sectnum, bool state);
void ReverseSpike(short SpriteNum)
{
USERp u = User[SpriteNum].Data();
SPRITEp sp = u->SpriteP;
// if paused go ahead and start it up again
if (u->Tics)
{
u->Tics = 0;
SetSpikeActive(SpriteNum);
return;
}
// moving toward to OFF pos
if (u->z_tgt == u->oz)
{
if (sp->z == u->oz)
u->z_tgt = u->sz;
else if (u->sz == u->oz)
u->z_tgt = sp->z;
}
else if (u->z_tgt == u->sz)
{
if (sp->z == u->oz)
u->z_tgt = sp->z;
else if (u->sz == u->oz)
u->z_tgt = u->sz;
}
u->vel_rate = -u->vel_rate;
}
2020-09-09 18:32:24 +00:00
bool
SpikeSwitch(short match, short setting)
{
SPRITEp sp;
2020-10-15 15:45:07 +00:00
int i;
2020-09-09 18:32:24 +00:00
bool found = false;
2020-10-15 15:40:22 +00:00
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 SetSpikeActive(short SpriteNum)
{
USERp u = User[SpriteNum].Data();
SPRITEp sp = u->SpriteP;
SECTORp sectp = &sector[sp->sectnum];
if (TEST(sp->cstat, CSTAT_SPRITE_YFLIP))
StartInterpolation(sp->sectnum, Interp_Sect_Ceilingheinum);
else
StartInterpolation(sp->sectnum, Interp_Sect_Floorheinum);
InterpSectorSprites(sp->sectnum, true);
// play activate sound
DoSoundSpotMatch(SP_TAG2(sp), 1, SOUND_OBJECT_TYPE);
SET(u->Flags, SPR_ACTIVE);
u->Tics = 0;
// moving to the ON position
if (u->z_tgt == sp->z)
VatorSwitch(SP_TAG2(sp), ON);
else
// moving to the OFF position
if (u->z_tgt == u->sz)
VatorSwitch(SP_TAG2(sp), OFF);
}
void SetSpikeInactive(short SpriteNum)
{
USERp u = User[SpriteNum].Data();
SPRITEp sp = u->SpriteP;
SECTORp sectp = &sector[sp->sectnum];
if (TEST(sp->cstat, CSTAT_SPRITE_YFLIP))
StopInterpolation(sp->sectnum, Interp_Sect_Ceilingheinum);
else
StopInterpolation(sp->sectnum, Interp_Sect_Floorheinum);
InterpSectorSprites(sp->sectnum, false);
// play activate sound
DoSoundSpotMatch(SP_TAG2(sp), 2, SOUND_OBJECT_TYPE);
RESET(u->Flags, SPR_ACTIVE);
}
// called for operation from the space bar
short DoSpikeOperate(short sectnum)
{
SPRITEp fsp;
short match;
2020-10-15 15:45:07 +00:00
int i;
2020-10-15 15:40:22 +00:00
SectIterator it(sectnum);
while ((i = it.NextIndex()) >= 0)
{
fsp = &sprite[i];
if (fsp->statnum == STAT_SPIKE && SP_TAG1(fsp) == SECT_SPIKE && SP_TAG3(fsp) == 0)
{
sectnum = fsp->sectnum;
match = SP_TAG2(fsp);
if (match > 0)
{
if (TestSpikeMatchActive(match))
return -1;
else
return DoSpikeMatch(match);
}
SetSpikeActive(i);
break;
}
}
return i;
}
// called from switches and triggers
// returns first spike found
short
DoSpikeMatch(short match)
{
USERp fu;
SPRITEp fsp;
short first_spike = -1;
2020-10-15 15:45:07 +00:00
int i;
//SpikeSwitch(match, ON);
2020-10-15 15:40:22 +00:00
StatIterator it(STAT_SPIKE);
while ((i = it.NextIndex()) >= 0)
{
fsp = &sprite[i];
if (SP_TAG1(fsp) == SECT_SPIKE && SP_TAG2(fsp) == match)
{
fu = User[i].Data();
if (first_spike == -1)
first_spike = i;
if (TEST(fu->Flags, SPR_ACTIVE))
{
ReverseSpike(i);
continue;
}
SetSpikeActive(i);
}
}
return first_spike;
}
2020-09-09 18:32:24 +00:00
bool
TestSpikeMatchActive(short match)
{
USERp fu;
SPRITEp fsp;
2020-10-15 15:45:07 +00:00
int i;
2020-10-15 15:40:22 +00:00
StatIterator it(STAT_SPIKE);
while ((i = it.NextIndex()) >= 0)
{
fsp = &sprite[i];
if (SP_TAG1(fsp) == SECT_SPIKE && SP_TAG2(fsp) == match)
{
fu = User[i].Data();
// door war
if (TEST_BOOL6(fsp))
continue;
if (TEST(fu->Flags, SPR_ACTIVE) || fu->Tics)
return true;
}
}
return false;
}
int DoSpikeMove(short SpriteNum, int *lptr)
{
USERp u = User[SpriteNum].Data();
int zval;
zval = *lptr;
// if LESS THAN goal
if (zval < u->z_tgt)
{
// move it DOWN
zval += (synctics * u->jump_speed);
u->jump_speed += u->vel_rate * synctics;
// if the other way make it equal
if (zval > u->z_tgt)
zval = u->z_tgt;
}
// if GREATER THAN goal
if (zval > u->z_tgt)
{
// move it UP
zval -= (synctics * u->jump_speed);
u->jump_speed += u->vel_rate * synctics;
if (zval < u->z_tgt)
zval = u->z_tgt;
}
*lptr = zval;
return 0;
}
void SpikeAlign(short SpriteNum)
{
USERp u = User[SpriteNum].Data();
SPRITEp sp = u->SpriteP;
// either work on single sector or all tagged in SOBJ
if ((int8_t)SP_TAG7(sp) < 0)
{
if (TEST(sp->cstat, CSTAT_SPRITE_YFLIP))
alignceilslope(sp->sectnum, sp->x, sp->y, u->zclip);
else
alignflorslope(sp->sectnum, sp->x, sp->y, u->zclip);
}
else
{
if (TEST(sp->cstat, CSTAT_SPRITE_YFLIP))
SOBJ_AlignCeilingToPoint(&SectorObject[SP_TAG7(sp)], sp->x, sp->y, u->zclip);
else
SOBJ_AlignFloorToPoint(&SectorObject[SP_TAG7(sp)], sp->x, sp->y, u->zclip);
}
}
void MoveSpritesWithSpike(short sectnum)
{
SPRITEp sp;
2020-10-15 15:45:07 +00:00
int i;
int cz,fz;
2020-10-15 15:40:22 +00:00
SectIterator it(sectnum);
while ((i = it.NextIndex()) >= 0)
{
sp = &sprite[i];
if (User[i].Data())
continue;
if (TEST(sp->extra, SPRX_STAY_PUT_VATOR))
continue;
getzsofslope(sectnum, sp->x, sp->y, &cz, &fz);
sp->z = fz;
}
}
int DoSpike(DSWActor* actor)
{
USER* u = actor->u();
int SpriteNum = u->SpriteNum;
SPRITEp sp = u->SpriteP;
int *lptr;
// zclip = floor or ceiling z
// oz = original z
// z_tgt = target z - on pos
// sz = starting z - off pos
lptr = &u->zclip;
DoSpikeMove(SpriteNum, lptr);
MoveSpritesWithSpike(sp->sectnum);
SpikeAlign(SpriteNum);
// EQUAL this entry has finished
if (*lptr == u->z_tgt)
{
// in the ON position
if (u->z_tgt == sp->z)
{
// change target
u->z_tgt = u->sz;
u->vel_rate = -u->vel_rate;
SetSpikeInactive(SpriteNum);
if (SP_TAG6(sp))
DoMatchEverything(nullptr, SP_TAG6(sp), -1);
}
else
// in the OFF position
if (u->z_tgt == u->sz)
{
short match = SP_TAG2(sp);
// change target
u->jump_speed = u->vel_tgt;
2021-05-12 14:50:20 +00:00
u->vel_rate = (short)abs(u->vel_rate);
u->z_tgt = sp->z;
SetSpikeInactive(SpriteNum);
// set owner swith back to OFF
// only if ALL spikes are inactive
if (!TestSpikeMatchActive(match))
{
//SpikeSwitch(match, OFF);
}
if (SP_TAG6(sp) && TEST_BOOL5(sp))
DoMatchEverything(nullptr, SP_TAG6(sp), -1);
}
// operate only once
if (TEST_BOOL2(sp))
{
SetSpikeInactive(SpriteNum);
2021-10-30 20:53:24 +00:00
KillActor(actor);
return 0;
}
// setup to go back to the original z
if (*lptr != u->oz)
{
if (u->WaitTics)
u->Tics = u->WaitTics;
}
}
else // if (*lptr == u->z_tgt)
{
// if heading for the OFF (original) position and should NOT CRUSH
if (TEST_BOOL3(sp) && u->z_tgt == u->oz)
{
2020-10-15 15:45:07 +00:00
int i;
SPRITEp bsp;
USERp bu;
2020-09-09 18:32:24 +00:00
bool found = false;
2020-10-15 15:40:22 +00:00
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))
{
ReverseSpike(SpriteNum);
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 == &sector[sp->sectnum] ||
pp->hi_sectp == &sector[sp->sectnum])
{
ReverseSpike(SpriteNum);
found = true;
}
}
}
}
}
return 0;
}
int DoSpikeAuto(DSWActor* actor)
{
USER* u = actor->u();
int SpriteNum = u->SpriteNum;
SPRITEp sp = u->SpriteP;
int *lptr;
lptr = &u->zclip;
DoSpikeMove(SpriteNum, lptr);
MoveSpritesWithSpike(sp->sectnum);
SpikeAlign(SpriteNum);
// EQUAL this entry has finished
if (*lptr == u->z_tgt)
{
// in the UP position
if (u->z_tgt == sp->z)
{
// change target
u->z_tgt = u->sz;
u->vel_rate = -u->vel_rate;
u->Tics = u->WaitTics;
if (SP_TAG6(sp))
DoMatchEverything(nullptr, SP_TAG6(sp), -1);
}
else
// in the DOWN position
if (u->z_tgt == u->sz)
{
// change target
u->jump_speed = u->vel_tgt;
2021-05-12 14:50:20 +00:00
u->vel_rate = (short)abs(u->vel_rate);
u->z_tgt = sp->z;
u->Tics = u->WaitTics;
if (SP_TAG6(sp) && TEST_BOOL5(sp))
DoMatchEverything(nullptr, SP_TAG6(sp), -1);
}
}
return 0;
}
#include "saveable.h"
static saveable_code saveable_spike_code[] =
{
SAVE_CODE(DoSpike),
SAVE_CODE(DoSpikeAuto),
};
saveable_module saveable_spike =
{
// code
saveable_spike_code,
SIZ(saveable_spike_code),
// data
nullptr,0
};
END_SW_NS