raze/source/games/sw/src/quake.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

345 lines
8 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 "gamecontrol.h"
#include "names2.h"
#include "game.h"
#include "tags.h"
#include "break.h"
#include "sprite.h"
BEGIN_SW_NS
#define QUAKE_Match(sp) (SP_TAG2(sp))
#define QUAKE_Zamt(sp) (SP_TAG3(sp))
#define QUAKE_Radius(sp) (SP_TAG4(sp))
#define QUAKE_Duration(sp) (SP_TAG5(sp))
#define QUAKE_WaitSecs(sp) (SP_TAG6(sp))
#define QUAKE_AngAmt(sp) (SP_TAG7(sp))
#define QUAKE_PosAmt(sp) (SP_TAG8(sp))
#define QUAKE_RandomTest(sp) (SP_TAG9(sp))
#define QUAKE_WaitTics(sp) (SP_TAG13(sp))
#define QUAKE_TestDontTaper(sp) (TEST_BOOL1(sp))
#define QUAKE_KillAfterQuake(sp) (TEST_BOOL2(sp))
// only for timed quakes
#define QUAKE_WaitForTrigger(sp) (TEST_BOOL3(sp))
short CopyQuakeSpotToOn(SPRITEp sp)
{
short New;
SPRITEp np;
New = COVERinsertsprite(sp->sectnum, STAT_QUAKE_SPOT);
np = &sprite[New];
memcpy(np, sp, sizeof(SPRITE));
np->sectnum = sp->sectnum;
np->statnum = sp->statnum;
np->cstat = 0;
np->extra = 0;
np->owner = -1;
change_sprite_stat(New, STAT_QUAKE_ON);
QUAKE_Duration(np) *= 120;
return New;
}
void DoQuakeMatch(short match)
{
int i;
SPRITEp sp;
StatIterator it(STAT_QUAKE_SPOT);
while ((i = it.NextIndex()) >= 0)
{
sp = &sprite[i];
if (QUAKE_Match(sp) == match)
{
if ((int16_t)QUAKE_WaitTics(sp) > 0)
{
// its not waiting any more
RESET_BOOL3(sp);
}
else
{
CopyQuakeSpotToOn(sp);
if (QUAKE_KillAfterQuake(sp))
{
KillSprite(i);
continue;
}
}
}
}
}
void ProcessQuakeOn(void)
{
int i;
SPRITEp sp;
StatIterator it(STAT_QUAKE_ON);
while ((i = it.NextIndex()) >= 0)
{
sp = &sprite[i];
// get rid of quake when timer runs out
QUAKE_Duration(sp) -= synctics*4;
if (QUAKE_Duration(sp) < 0)
{
KillSprite(i);
continue;
}
}
}
void ProcessQuakeSpot(void)
{
int i;
SPRITEp sp;
int rand_test;
// check timed quakes and random quakes
StatIterator it(STAT_QUAKE_SPOT);
while ((i = it.NextIndex()) >= 0)
{
sp = &sprite[i];
// not a timed quake
if (!QUAKE_WaitSecs(sp))
continue;
// don't process unless triggered
if (QUAKE_WaitForTrigger(sp))
continue;
// spawn a quake if time is up
//QUAKE_WaitTics(sp) -= 4*synctics;
SET_SP_TAG13(sp, (QUAKE_WaitTics(sp)-4*synctics));
if ((int16_t)QUAKE_WaitTics(sp) < 0)
{
// reset timer - add in Duration of quake
//QUAKE_WaitTics(sp) = ((QUAKE_WaitSecs(sp)*10L) + QUAKE_Duration(sp)) * 120L;
SET_SP_TAG13(sp, (((QUAKE_WaitSecs(sp)*10L) + QUAKE_Duration(sp)) * 120L));
// spawn a quake if condition is met
rand_test = QUAKE_RandomTest(sp);
// wrong - all quakes need to happen at the same time on all computerssg
//if (!rand_test || (rand_test && STD_RANDOM_RANGE(128) < rand_test))
if (!rand_test || (rand_test && RandomRange(128) < rand_test))
{
CopyQuakeSpotToOn(sp);
// kill quake spot if needed
if (QUAKE_KillAfterQuake(sp))
{
DeleteNoSoundOwner(i);
KillSprite(i);
continue;
}
}
}
}
}
void QuakeViewChange(PLAYERp pp, int *z_diff, int *x_diff, int *y_diff, short *ang_diff)
{
int i;
SPRITEp sp;
SPRITEp save_sp = nullptr;
int dist,save_dist = 999999;
int dist_diff, scale_value;
int ang_amt;
int radius;
int pos_amt;
*z_diff = 0;
*x_diff = 0;
*y_diff = 0;
*ang_diff = 0;
if (paused)
return;
// find the closest quake - should be a strength value
StatIterator it(STAT_QUAKE_ON);
while ((i = it.NextIndex()) >= 0)
{
sp = &sprite[i];
dist = FindDistance3D(pp->posx - sp->x, pp->posy - sp->y, pp->posz - sp->z);
// shake whole level
if (QUAKE_TestDontTaper(sp))
{
save_dist = dist;
save_sp = sp;
break;
}
if (dist < save_dist)
{
save_dist = dist;
save_sp = sp;
}
}
if (!save_sp)
return;
else
sp = save_sp;
radius = QUAKE_Radius(sp) * 8L;
if (save_dist > radius)
return;
*z_diff = Z(STD_RANDOM_RANGE(QUAKE_Zamt(sp)) - (QUAKE_Zamt(sp)/2));
ang_amt = QUAKE_AngAmt(sp) * 4L;
*ang_diff = STD_RANDOM_RANGE(ang_amt) - (ang_amt/2);
pos_amt = QUAKE_PosAmt(sp) * 4L;
*x_diff = STD_RANDOM_RANGE(pos_amt) - (pos_amt/2);
*y_diff = STD_RANDOM_RANGE(pos_amt) - (pos_amt/2);
if (!QUAKE_TestDontTaper(sp))
{
// scale values from epicenter
dist_diff = radius - save_dist;
scale_value = DivScale(dist_diff, radius, 16);
*z_diff = MulScale(*z_diff, scale_value, 16);
*ang_diff = MulScale(*ang_diff, scale_value, 16);
*x_diff = MulScale(*x_diff, scale_value, 16);
*y_diff = MulScale(*y_diff, scale_value, 16);
}
}
int SpawnQuake(short sectnum, int x, int y, int z,
short tics, short amt, int radius)
{
short SpriteNum;
SPRITEp sp;
SpriteNum = COVERinsertsprite(sectnum, STAT_QUAKE_ON);
sp = &sprite[SpriteNum];
ASSERT(SpriteNum >= 0);
sp->x = x;
sp->y = y;
sp->z = z;
sp->cstat = 0;
sp->owner = -1;
sp->extra = 0;
QUAKE_Match(sp) = -1;
QUAKE_Zamt(sp) = uint8_t(amt);
QUAKE_Radius(sp) = radius/8;
QUAKE_Duration(sp) = tics;
QUAKE_AngAmt(sp) = 8;
QUAKE_PosAmt(sp) = 0;
PlaySound(DIGI_ERUPTION, sp, v3df_follow|v3df_dontpan);
Set3DSoundOwner(SpriteNum);
return SpriteNum;
}
bool
SetQuake(PLAYERp pp, short tics, short amt)
{
SpawnQuake(pp->cursectnum, pp->posx, pp->posy, pp->posz, tics, amt, 30000);
return false;
}
int
SetExpQuake(int16_t Weapon)
{
SPRITEp sp = &sprite[Weapon];
SpawnQuake(sp->sectnum, sp->x, sp->y, sp->z, 40, 4, 20000); // !JIM! was 8, 40000
return 0;
}
int
SetGunQuake(int16_t SpriteNum)
{
SPRITEp sp = &sprite[SpriteNum];
SpawnQuake(sp->sectnum, sp->x, sp->y, sp->z, 40, 8, 40000);
return 0;
}
int
SetPlayerQuake(PLAYERp pp)
{
SpawnQuake(pp->cursectnum, pp->posx, pp->posy, pp->posz, 40, 8, 40000);
return 0;
}
int
SetNuclearQuake(int16_t Weapon)
{
SPRITEp sp = &sprite[Weapon];
SpawnQuake(sp->sectnum, sp->x, sp->y, sp->z, 400, 8, 64000);
return 0;
}
int
SetSumoQuake(int16_t SpriteNum)
{
SPRITEp sp = &sprite[SpriteNum];
SpawnQuake(sp->sectnum, sp->x, sp->y, sp->z, 120, 4, 20000);
return 0;
}
int
SetSumoFartQuake(int16_t SpriteNum)
{
SPRITEp sp = &sprite[SpriteNum];
SpawnQuake(sp->sectnum, sp->x, sp->y, sp->z, 60, 4, 4000);
return 0;
}
END_SW_NS