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

586 lines
16 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 "network.h"
#include "tags.h"
#include "sector.h"
#include "interpolate.h"
2020-08-05 22:18:45 +00:00
#include "misc.h"
#include "sprite.h"
#include "weapon.h"
#include "quotemgr.h"
BEGIN_SW_NS
2021-12-31 14:59:11 +00:00
void DoVatorMatch(PLAYER* pp, short match);
2020-09-09 18:32:24 +00:00
bool TestVatorMatchActive(short match);
2021-11-02 23:45:43 +00:00
void ReverseVator(DSWActor* actor)
{
// if paused go ahead and start it up again
2021-12-25 22:13:35 +00:00
if (actor->user.Tics)
{
2021-12-25 22:13:35 +00:00
actor->user.Tics = 0;
2021-11-02 23:45:43 +00:00
SetVatorActive(actor);
return;
}
// moving toward to OFF pos
2021-12-25 22:13:35 +00:00
if (actor->user.z_tgt == actor->user.oz)
{
2021-12-25 22:13:35 +00:00
if (actor->spr.pos.Z == actor->user.oz)
actor->user.z_tgt = actor->user.pos.Z;
else if (actor->user.pos.Z == actor->user.oz)
2021-12-25 22:13:35 +00:00
actor->user.z_tgt = actor->spr.pos.Z;
}
else if (actor->user.z_tgt == actor->user.pos.Z)
{
2021-12-25 22:13:35 +00:00
if (actor->spr.pos.Z == actor->user.oz)
actor->user.z_tgt = actor->spr.pos.Z;
else if (actor->user.pos.Z == actor->user.oz)
actor->user.z_tgt = actor->user.pos.Z;
}
2021-12-25 22:13:35 +00:00
actor->user.vel_rate = -actor->user.vel_rate;
}
2021-11-02 23:45:43 +00:00
bool VatorSwitch(short match, short setting)
{
2020-09-09 18:32:24 +00:00
bool found = false;
2021-11-02 23:45:43 +00:00
SWStatIterator it(STAT_DEFAULT);
while (auto actor = it.Next())
{
2021-12-24 22:05:45 +00:00
if (actor->spr.lotag == TAG_SPRITE_SWITCH_VATOR && actor->spr.hitag == match)
{
found = true;
2021-12-24 16:32:27 +00:00
AnimateSwitch(actor, setting);
}
}
return found;
}
2021-11-02 23:45:43 +00:00
void SetVatorActive(DSWActor* actor)
{
2021-12-31 14:43:47 +00:00
sectortype* sectp = actor->sector();
2021-12-27 18:34:06 +00:00
if (actor->spr.cstat & (CSTAT_SPRITE_YFLIP))
StartInterpolation(actor->sector(), Interp_Sect_Ceilingz);
else
StartInterpolation(actor->sector(), Interp_Sect_Floorz);
InterpSectorSprites(actor->sector(), true);
// play activate sound
DoSoundSpotMatch(SP_TAG2(actor), 1, SOUND_OBJECT_TYPE);
actor->user.Flags |= (SPR_ACTIVE);
2021-12-25 22:13:35 +00:00
actor->user.Tics = 0;
// moving to the ON position
2021-12-25 22:13:35 +00:00
if (actor->user.z_tgt == actor->spr.pos.Z)
VatorSwitch(SP_TAG2(actor), true);
else
// moving to the OFF position
if (actor->user.z_tgt == actor->user.pos.Z)
VatorSwitch(SP_TAG2(actor), false);
}
2021-11-02 23:45:43 +00:00
void SetVatorInactive(DSWActor* actor)
{
2021-12-31 14:43:47 +00:00
sectortype* sectp = actor->sector();
2021-12-27 18:34:06 +00:00
if (actor->spr.cstat & (CSTAT_SPRITE_YFLIP))
StopInterpolation(actor->sector(), Interp_Sect_Ceilingz);
else
StopInterpolation(actor->sector(), Interp_Sect_Floorz);
InterpSectorSprites(actor->sector(), false);
// play inactivate sound
DoSoundSpotMatch(SP_TAG2(actor), 2, SOUND_OBJECT_TYPE);
2021-12-27 17:58:15 +00:00
actor->user.Flags &= ~(SPR_ACTIVE);
}
// called for operation from the space bar
2021-12-31 14:59:11 +00:00
void DoVatorOperate(PLAYER* pp, sectortype* sect)
{
short match;
2021-11-25 15:55:46 +00:00
SWSectIterator it(sect);
2021-11-02 23:45:43 +00:00
while (auto actor = it.Next())
{
2021-12-24 22:08:14 +00:00
if (actor->spr.statnum == STAT_VATOR && SP_TAG1(actor) == SECT_VATOR && SP_TAG3(actor) == 0)
{
auto fsect = actor->sector();
// single play only vator
2020-09-09 18:32:24 +00:00
// bool 8 must be set for message to display
2021-12-24 22:08:14 +00:00
if (TEST_BOOL4(actor) && (gNet.MultiGameType == MULTI_GAME_COMMBAT || gNet.MultiGameType == MULTI_GAME_AI_BOTS))
{
2021-12-24 22:08:14 +00:00
if (pp && TEST_BOOL11(actor)) PutStringInfo(pp,"This only opens in single play.");
continue;
}
match = SP_TAG2(actor);
if (match > 0)
{
2021-11-02 23:45:43 +00:00
if (!TestVatorMatchActive(match))
DoVatorMatch(pp, match);
return;
}
2021-11-20 22:20:43 +00:00
if (pp && fsect->hasU() && fsect->stag == SECT_LOCK_DOOR && fsect->number)
{
short key_num;
2021-11-20 22:20:43 +00:00
key_num = fsect->number;
{
PutStringInfo(pp, quoteMgr.GetQuote(QUOTE_DOORMSG + key_num - 1));
2021-11-02 23:45:43 +00:00
return;
}
}
2021-11-02 23:45:43 +00:00
SetVatorActive(actor);
break;
}
}
}
// called from switches and triggers
// returns first vator found
2021-12-31 14:59:11 +00:00
void DoVatorMatch(PLAYER* pp, short match)
{
2021-11-02 23:45:43 +00:00
SWStatIterator it(STAT_VATOR);
while (auto actor = it.Next())
{
if (SP_TAG1(actor) == SECT_VATOR && SP_TAG2(actor) == match)
{
// single play only vator
2020-09-09 18:32:24 +00:00
// bool 8 must be set for message to display
2021-12-24 22:08:14 +00:00
if (TEST_BOOL4(actor) && (gNet.MultiGameType == MULTI_GAME_COMMBAT || gNet.MultiGameType == MULTI_GAME_AI_BOTS))
{
2021-12-24 22:08:14 +00:00
if (pp && TEST_BOOL11(actor)) PutStringInfo(pp, GStrings("TXTS_SPONLY"));
continue;
}
// lock code
auto fsect = actor->sector();
2021-11-20 22:20:43 +00:00
if (pp && fsect->hasU() && fsect->stag == SECT_LOCK_DOOR && fsect->number)
{
2021-11-20 22:20:43 +00:00
int key_num = fsect->number;
{
PutStringInfo(pp, quoteMgr.GetQuote(QUOTE_DOORMSG + key_num - 1));
2021-11-02 23:45:43 +00:00
return;
}
}
// remember the player than activated it
2021-12-25 22:13:35 +00:00
actor->user.PlayerP = pp;
2021-12-27 18:34:06 +00:00
if (actor->user.Flags & (SPR_ACTIVE))
{
2021-11-02 23:45:43 +00:00
ReverseVator(actor);
continue;
}
2021-11-02 23:45:43 +00:00
SetVatorActive(actor);
}
}
}
2021-11-02 23:45:43 +00:00
bool TestVatorMatchActive(short match)
{
2021-11-02 23:45:43 +00:00
SWStatIterator it(STAT_VATOR);
while (auto actor = it.Next())
{
if (SP_TAG1(actor) == SECT_VATOR && SP_TAG2(actor) == match)
{
// Does not have to be inactive to be operated
2021-12-24 22:08:14 +00:00
if (TEST_BOOL6(actor))
continue;
2021-12-27 18:34:06 +00:00
if (actor->user.Flags & (SPR_ACTIVE) || actor->user.Tics)
return true;
}
}
return false;
}
void InterpSectorSprites(sectortype* sect, bool state)
{
SWSectIterator it(sect);
2021-11-02 23:45:43 +00:00
while (auto actor = it.Next())
{
2021-11-02 23:45:43 +00:00
if (actor->hasU())
{
2021-12-27 18:34:06 +00:00
if (actor->user.Flags & (SPR_SKIP4) && actor->spr.statnum <= STAT_SKIP4_INTERP_END)
continue;
2021-12-27 18:34:06 +00:00
if (actor->user.Flags & (SPR_SKIP2) && actor->spr.statnum <= STAT_SKIP2_INTERP_END)
continue;
}
}
}
2021-11-25 17:16:56 +00:00
void MoveSpritesWithSector(sectortype* sect, int z_amt, bool type)
{
2020-09-09 18:32:24 +00:00
bool both = false;
if ( sect->hasU())
both = !!(sect->flags & SECTFU_VATOR_BOTH);
2021-11-25 17:16:56 +00:00
SWSectIterator it(sect);
2021-11-02 23:45:43 +00:00
while (auto actor = it.Next())
{
2021-11-02 23:45:43 +00:00
if (actor->hasU())
{
2021-12-24 22:05:45 +00:00
switch (actor->spr.statnum)
{
case STAT_ITEM:
case STAT_NO_STATE:
case STAT_MINE_STUCK:
case STAT_WALLBLOOD_QUEUE:
case STAT_FLOORBLOOD_QUEUE:
case STAT_STATIC_FIRE:
break;
default:
continue;
}
}
else
{
2021-12-24 22:05:45 +00:00
switch (actor->spr.statnum)
{
case STAT_STAR_QUEUE:
case STAT_HOLE_QUEUE:
// case STAT_WALLBLOOD_QUEUE:
// case STAT_FLOORBLOOD_QUEUE:
continue;
}
}
if ((actor->spr.extra & SPRX_STAY_PUT_VATOR))
continue;
if (both)
{
// sprite started close to floor
2021-12-27 18:34:06 +00:00
if (actor->spr.cstat & (CSTAT_SPRITE_CLOSE_FLOOR))
{
// this is a ceiling
if (type == 1)
continue;
}
else
{
// this is a floor
if (type == 0)
continue;
}
}
2021-12-24 22:05:45 +00:00
actor->spr.pos.Z += z_amt;
}
}
2021-11-02 23:45:43 +00:00
int DoVatorMove(DSWActor* actor, int *lptr)
{
int zval;
int move_amt;
zval = *lptr;
// if LESS THAN goal
2021-12-25 22:13:35 +00:00
if (zval < actor->user.z_tgt)
{
// move it DOWN
2021-12-25 22:13:35 +00:00
zval += (synctics * actor->user.jump_speed);
2021-12-25 22:13:35 +00:00
actor->user.jump_speed += actor->user.vel_rate * synctics;
// if the other way make it equal
2021-12-25 22:13:35 +00:00
if (zval > actor->user.z_tgt)
zval = actor->user.z_tgt;
}
// if GREATER THAN goal
2021-12-25 22:13:35 +00:00
if (zval > actor->user.z_tgt)
{
// move it UP
2021-12-25 22:13:35 +00:00
zval -= (synctics * actor->user.jump_speed);
2021-12-25 22:13:35 +00:00
actor->user.jump_speed += actor->user.vel_rate * synctics;
2021-12-25 22:13:35 +00:00
if (zval < actor->user.z_tgt)
zval = actor->user.z_tgt;
}
move_amt = zval - *lptr;
*lptr = zval;
return move_amt;
}
int DoVator(DSWActor* actor)
{
2021-12-31 14:43:47 +00:00
sectortype* sectp = actor->sector();
int *lptr;
int amt;
2021-12-25 22:13:35 +00:00
// actor->user.sz - where the sector z started
// actor->user.z_tgt - current target z
// actor->user.oz - original z - where it initally starts off
2021-12-24 22:05:45 +00:00
// actor->spr.z - z of the sprite
2021-12-25 22:13:35 +00:00
// actor->user.vel_rate - velocity
2021-12-27 18:34:06 +00:00
if (actor->spr.cstat & (CSTAT_SPRITE_YFLIP))
{
lptr = sectp->ceilingzptr();
2021-11-02 23:45:43 +00:00
amt = DoVatorMove(actor, lptr);
MoveSpritesWithSector(actor->sector(), amt, true); // ceiling
}
else
{
lptr = sectp->floorzptr();
2021-11-02 23:45:43 +00:00
amt = DoVatorMove(actor, lptr);
MoveSpritesWithSector(actor->sector(), amt, false); // floor
}
// EQUAL this entry has finished
2021-12-25 22:13:35 +00:00
if (*lptr == actor->user.z_tgt)
{
// in the ON position
2021-12-25 22:13:35 +00:00
if (actor->user.z_tgt == actor->spr.pos.Z)
{
// change target
actor->user.z_tgt = actor->user.pos.Z;
2021-12-25 22:13:35 +00:00
actor->user.vel_rate = -actor->user.vel_rate;
2021-11-02 23:45:43 +00:00
SetVatorInactive(actor);
// if tag6 and nothing blocking door
2021-12-24 22:08:14 +00:00
if (SP_TAG6(actor) && !TEST_BOOL8(actor))
2021-12-25 22:13:35 +00:00
DoMatchEverything(actor->user.PlayerP, SP_TAG6(actor), -1);
}
else
// in the OFF position
if (actor->user.z_tgt == actor->user.pos.Z)
{
short match = SP_TAG2(actor);
// change target
2021-12-25 22:13:35 +00:00
actor->user.jump_speed = actor->user.vel_tgt;
actor->user.vel_rate = short(abs(actor->user.vel_rate));
actor->user.z_tgt = actor->spr.pos.Z;
2021-12-24 22:08:14 +00:00
RESET_BOOL8(actor);
2021-11-02 23:45:43 +00:00
SetVatorInactive(actor);
2021-11-02 18:07:05 +00:00
// set Owner swith back to OFF
// only if ALL vators are inactive
if (!TestVatorMatchActive(match))
{
//VatorSwitch(match, OFF);
}
2021-12-24 22:08:14 +00:00
if (SP_TAG6(actor) && TEST_BOOL5(actor))
2021-12-25 22:13:35 +00:00
DoMatchEverything(actor->user.PlayerP, SP_TAG6(actor), -1);
}
// operate only once
2021-12-24 22:08:14 +00:00
if (TEST_BOOL2(actor))
{
2021-11-02 23:45:43 +00:00
SetVatorInactive(actor);
2021-10-30 20:53:24 +00:00
KillActor(actor);
return 0;
}
// setup to go back to the original z
2021-12-25 22:13:35 +00:00
if (*lptr != actor->user.oz)
{
2021-12-25 22:13:35 +00:00
if (actor->user.WaitTics)
actor->user.Tics = actor->user.WaitTics;
}
}
2021-12-25 22:13:35 +00:00
else // if (*lptr == actor->user.z_tgt)
{
// if heading for the OFF (original) position and should NOT CRUSH
2021-12-25 22:13:35 +00:00
if (TEST_BOOL3(actor) && actor->user.z_tgt == actor->user.oz)
{
2020-10-15 15:45:07 +00:00
int i;
2020-09-09 18:32:24 +00:00
bool found = false;
SWSectIterator it(actor->sector());
2021-11-02 23:45:43 +00:00
while (auto itActor = it.Next())
{
2021-12-24 19:55:10 +00:00
if (itActor->spr.statnum == STAT_ENEMY)
{
2021-12-24 19:55:10 +00:00
if (labs(sectp->ceilingz - sectp->floorz) < ActorSizeZ(itActor))
{
2021-11-01 10:57:51 +00:00
InitBloodSpray(itActor, true, -1);
2021-10-30 19:07:15 +00:00
UpdateSinglePlayKills(itActor);
2021-11-01 10:57:51 +00:00
KillActor(itActor);
continue;
}
}
if (itActor->hasU() && (itActor->spr.cstat & CSTAT_SPRITE_BLOCK) && (itActor->spr.extra & SPRX_PLAYER_OR_ENEMY))
{
// found something blocking so reverse to ON position
2021-11-02 23:45:43 +00:00
ReverseVator(actor);
2021-12-24 22:08:14 +00:00
SET_BOOL8(actor); // tell vator that something blocking door
found = true;
break;
}
}
if (!found)
{
short pnum;
2021-12-31 14:59:11 +00:00
PLAYER* pp;
// go ahead and look for players clip box bounds
TRAVERSE_CONNECT(pnum)
{
pp = Player + pnum;
if (pp->lo_sectp == actor->sector() ||
pp->hi_sectp == actor->sector())
{
2021-11-02 23:45:43 +00:00
ReverseVator(actor);
2021-12-25 22:13:35 +00:00
actor->user.vel_rate = -actor->user.vel_rate;
found = true;
}
}
}
}
else
{
SWSectIterator it(actor->sector());
2021-11-02 23:45:43 +00:00
while (auto itActor = it.Next())
{
2021-12-24 19:55:10 +00:00
if (itActor->spr.statnum == STAT_ENEMY)
{
2021-12-24 19:55:10 +00:00
if (labs(sectp->ceilingz - sectp->floorz) < ActorSizeZ(itActor))
{
2021-11-01 10:57:51 +00:00
InitBloodSpray(itActor, true, -1);
2021-10-30 19:07:15 +00:00
UpdateSinglePlayKills(itActor);
2021-11-01 10:57:51 +00:00
KillActor(itActor);
continue;
}
}
}
}
}
return 0;
}
int DoVatorAuto(DSWActor* actor)
{
2021-12-31 14:43:47 +00:00
sectortype* sectp = actor->sector();
int *lptr;
int amt;
2021-12-27 18:34:06 +00:00
if (actor->spr.cstat & (CSTAT_SPRITE_YFLIP))
{
lptr = sectp->ceilingzptr();
2021-11-02 23:45:43 +00:00
amt = DoVatorMove(actor, lptr);
MoveSpritesWithSector(actor->sector(), amt, true); // ceiling
}
else
{
lptr = sectp->floorzptr();
2021-11-02 23:45:43 +00:00
amt = DoVatorMove(actor, lptr);
MoveSpritesWithSector(actor->sector(), amt, false); // floor
}
// EQUAL this entry has finished
2021-12-25 22:13:35 +00:00
if (*lptr == actor->user.z_tgt)
{
// in the UP position
2021-12-25 22:13:35 +00:00
if (actor->user.z_tgt == actor->spr.pos.Z)
{
// change target
actor->user.z_tgt = actor->user.pos.Z;
2021-12-25 22:13:35 +00:00
actor->user.vel_rate = -actor->user.vel_rate;
actor->user.Tics = actor->user.WaitTics;
2021-12-24 22:08:14 +00:00
if (SP_TAG6(actor))
2021-12-25 22:13:35 +00:00
DoMatchEverything(actor->user.PlayerP, SP_TAG6(actor), -1);
}
else
// in the DOWN position
if (actor->user.z_tgt == actor->user.pos.Z)
{
// change target
2021-12-25 22:13:35 +00:00
actor->user.jump_speed = actor->user.vel_tgt;
actor->user.vel_rate = short(abs(actor->user.vel_rate));
actor->user.z_tgt = actor->spr.pos.Z;
actor->user.Tics = actor->user.WaitTics;
2021-12-24 22:08:14 +00:00
if (SP_TAG6(actor) && TEST_BOOL5(actor))
DoMatchEverything(nullptr, SP_TAG6(actor), -1);
}
}
return 0;
}
#include "saveable.h"
static saveable_code saveable_vator_code[] =
{
SAVE_CODE(DoVator),
SAVE_CODE(DoVatorAuto),
};
saveable_module saveable_vator =
{
// code
saveable_vator_code,
SIZ(saveable_vator_code),
// data
nullptr,0
};
END_SW_NS