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

586 lines
15 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 "names2.h"
#include "panel.h"
#include "tags.h"
#include "sector.h"
#include "ai.h"
#include "player.h"
#include "game.h"
BEGIN_SW_NS
void ScaleSectorObject(SECTOR_OBJECTp);
short
DoSectorObjectSetScale(short match)
{
SECTOR_OBJECTp sop;
for (sop = SectorObject; sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++)
{
if (SO_EMPTY(sop))
continue;
if (sop->match_event == match)
{
SET(sop->flags, SOBJ_DYNAMIC);
sop->PreMoveAnimator = ScaleSectorObject;
switch (sop->scale_active_type)
{
case SO_SCALE_RANDOM_POINT:
if (sop->scale_type == SO_SCALE_HOLD || sop->scale_type == SO_SCALE_NONE)
{
// if holding start it up
sop->scale_type = sop->scale_active_type;
}
else
{
// if moving set to hold
sop->scale_type = SO_SCALE_HOLD;
}
break;
case SO_SCALE_DEST:
sop->scale_type = sop->scale_active_type;
if (sop->scale_dist == sop->scale_dist_max)
{
// make it negative
if (sop->scale_speed > 0)
sop->scale_speed = -sop->scale_speed;
}
else if (sop->scale_dist == sop->scale_dist_min)
{
// make it positive
if (sop->scale_speed < 0)
sop->scale_speed = -sop->scale_speed;
}
else
{
// make it positive
if (sop->scale_speed < 0)
sop->scale_speed = -sop->scale_speed;
}
break;
case SO_SCALE_RANDOM:
case SO_SCALE_CYCLE:
if (sop->scale_type == SO_SCALE_HOLD)
{
// if holding start it up
sop->scale_type = sop->scale_active_type;
}
else
{
// if moving set to hold
sop->scale_type = SO_SCALE_HOLD;
}
break;
}
}
}
return 0;
}
short
DoSOevent(short match, short state)
{
SECTOR_OBJECTp sop;
SPRITEp me_sp;
short vel_adj=0, spin_adj=0;
for (sop = SectorObject; sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++)
{
if (SO_EMPTY(sop))
continue;
if (sop->match_event == match)
{
if (TEST(sop->flags, SOBJ_WAIT_FOR_EVENT))
{
if (sop->save_vel > 0 || sop->save_spin_speed > 0)
{
RESET(sop->flags, SOBJ_WAIT_FOR_EVENT);
sop->vel = sop->save_vel;
sop->spin_speed = sop->save_spin_speed;
}
}
if (sop->match_event_actor == nullptr)
continue;
me_sp = &sop->match_event_actor->s();
// toggle
if (state == -1)
{
if (TEST_BOOL3(me_sp))
{
RESET_BOOL3(me_sp);
state = OFF;
}
else
{
SET_BOOL3(me_sp);
state = ON;
}
}
if (state == ON)
{
spin_adj = (int)SP_TAG3(me_sp);
vel_adj = SP_TAG7(me_sp);
}
else if (state == OFF)
{
spin_adj = -(int)SP_TAG3(me_sp);
vel_adj = -SP_TAG7(me_sp);
}
sop->spin_speed += spin_adj;
if (TEST_BOOL1(me_sp))
sop->vel_tgt += vel_adj;
else
sop->vel += vel_adj;
if (TEST_BOOL2(me_sp))
{
sop->dir *= -1;
}
}
}
return 0;
}
//
// SCALING - PreAnimator
//
void ScaleSectorObject(SECTOR_OBJECTp sop)
{
switch (sop->scale_type)
{
case SO_SCALE_NONE:
break;
case SO_SCALE_HOLD:
break;
// to dest
case SO_SCALE_DEST:
sop->scale_dist += sop->scale_speed;
if (sop->scale_dist > sop->scale_dist_max)
{
sop->scale_dist = sop->scale_dist_max;
sop->scale_type = SO_SCALE_HOLD;
}
else if (sop->scale_dist < sop->scale_dist_min)
{
sop->scale_dist = sop->scale_dist_min;
sop->scale_type = SO_SCALE_HOLD;
}
break;
// random direction change
case SO_SCALE_RANDOM:
sop->scale_dist += sop->scale_speed;
if (sop->scale_dist > sop->scale_dist_max)
{
sop->scale_speed *= -1;
sop->scale_dist = sop->scale_dist_max;
}
else if (sop->scale_dist < sop->scale_dist_min)
{
sop->scale_speed *= -1;
sop->scale_dist = sop->scale_dist_min;
}
if (RANDOM_P2(1024) < sop->scale_rand_freq<<3)
{
sop->scale_speed *= -1;
}
break;
// cycle through max and min
case SO_SCALE_CYCLE:
sop->scale_dist += sop->scale_speed;
if (sop->scale_dist > sop->scale_dist_max)
{
sop->scale_speed *= -1;
sop->scale_dist = sop->scale_dist_max;
}
else if (sop->scale_dist < sop->scale_dist_min)
{
sop->scale_speed *= -1;
sop->scale_dist = sop->scale_dist_min;
}
break;
}
}
void ScaleRandomPoint(SECTOR_OBJECTp sop, short k, short ang, int x, int y, int *dx, int *dy)
{
int xmul,ymul;
sop->scale_point_dist[k] += sop->scale_point_speed[k];
if (sop->scale_point_dist[k] > sop->scale_point_dist_max)
{
sop->scale_point_speed[k] *= -1;
sop->scale_point_dist[k] = sop->scale_point_dist_max;
}
else if (sop->scale_point_dist[k] < sop->scale_point_dist_min)
{
sop->scale_point_speed[k] *= -1;
sop->scale_point_dist[k] = sop->scale_point_dist_min;
}
if (RANDOM_P2(1024) < sop->scale_point_rand_freq)
{
sop->scale_point_speed[k] *= -1;
}
// change up speed at random
if (RANDOM_P2(1024) < (sop->scale_point_rand_freq/2))
{
//sop->scale_point_speed[k] = SCALE_POINT_SPEED;
short half = sop->scale_point_base_speed/2;
short quart = sop->scale_point_base_speed/4;
sop->scale_point_speed[k] = sop->scale_point_base_speed + (RandomRange(half) - quart);
}
xmul = (sop->scale_point_dist[k] * sop->scale_x_mult)>>8;
ymul = (sop->scale_point_dist[k] * sop->scale_y_mult)>>8;
*dx = x + MulScale(xmul, bcos(ang), 14);
*dy = y + MulScale(ymul, bsin(ang), 14);
}
//
// Morph point - move point around
//
void
MorphTornado(SECTOR_OBJECTp sop)
{
int mx, my;
int ceilingz;
int floorz;
SECTORp *sectp;
int j;
int x,y,sx,sy;
// z direction
ASSERT(sop->op_main_sector >= 0);
sop->morph_z += Z(sop->morph_z_speed);
// move vector
if (sop->morph_wall_point < 0)
return;
// place at correct x,y offset from center
x = sop->xmid - sop->morph_xoff;
y = sop->ymid - sop->morph_yoff;
sx = x;
sy = y;
// move it from last x,y
mx = x + MulScale(sop->morph_speed, bcos(sop->morph_ang), 14);
my = y + MulScale(sop->morph_speed, bsin(sop->morph_ang), 14);
// bound check radius
if (ksqrt(SQ(sop->xmid - mx) + SQ(sop->ymid - my)) > sop->morph_dist_max + sop->scale_dist)
{
// find angle
sop->morph_ang = NORM_ANGLE(getangle(mx - sop->xmid, my - sop->ymid));
// reverse angle
sop->morph_ang = NORM_ANGLE(sop->morph_ang + 1024);
// move back some from last point
mx = sx + MulScale(sop->morph_speed << 1, bcos(sop->morph_ang), 14);
my = sy + MulScale(sop->morph_speed << 1, bsin(sop->morph_ang), 14);
sop->morph_xoff = sop->xmid - mx;
sop->morph_yoff = sop->ymid - my;
}
// save x,y back as offset info
sop->morph_xoff = sop->xmid - mx;
sop->morph_yoff = sop->ymid - my;
if ((RANDOM_P2(1024<<4)>>4) < sop->morph_rand_freq)
sop->morph_ang = RANDOM_P2(2048);
// move it x,y
dragpoint(sop->morph_wall_point, mx, my);
// bound the Z
ceilingz = sector[sop->op_main_sector].ceilingz;
floorz = sector[sop->op_main_sector].floorz;
for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
{
if (SectUser[sectnum(*sectp)].Data() &&
TEST(SectUser[sectnum(*sectp)]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
{
#define TOR_LOW (floorz)
if (sop->morph_z > TOR_LOW)
{
sop->morph_z_speed *= -1;
sop->morph_z = TOR_LOW;
}
else if (sop->morph_z < ceilingz)
{
sop->morph_z_speed *= -1;
sop->morph_z = ceilingz;
}
alignceilslope(sectnum(*sectp), mx, my, sop->morph_z);
}
}
}
// moves center point around and aligns slope
void
MorphFloor(SECTOR_OBJECTp sop)
{
int mx, my;
int floorz;
SECTORp *sectp;
int j;
int x,y;
// z direction
ASSERT(sop->op_main_sector >= 0);
sop->morph_z -= Z(sop->morph_z_speed);
// move vector
if (sop->morph_wall_point < 0)
return;
// place at correct x,y offset from center
x = sop->xmid - sop->morph_xoff;
y = sop->ymid - sop->morph_yoff;
// move it from last x,y
mx = x + MulScale(sop->morph_speed, bcos(sop->morph_ang), 14);
my = y + MulScale(sop->morph_speed, bsin(sop->morph_ang), 14);
// save x,y back as offset info
sop->morph_xoff = sop->xmid - mx;
sop->morph_yoff = sop->ymid - my;
// bound check radius
if (Distance(sop->xmid, sop->ymid, mx, my) > sop->morph_dist_max)
{
// go in the other direction
//sop->morph_speed *= -1;
sop->morph_ang = NORM_ANGLE(sop->morph_ang + 1024);
// back it up and save it off
mx = x + MulScale(sop->morph_speed, bcos(sop->morph_ang), 14);
my = y + MulScale(sop->morph_speed, bsin(sop->morph_ang), 14);
sop->morph_xoff = sop->xmid - mx;
sop->morph_yoff = sop->ymid - my;
// turn it all the way around and then do a random -512 to 512 from there
//sop->morph_ang = NORM_ANGLE(sop->morph_ang + 1024 + (RANDOM_P2(1024) - 512));
}
if ((RANDOM_P2(1024<<4)>>4) < sop->morph_rand_freq)
sop->morph_ang = RANDOM_P2(2048);
// move x,y point "just like in build"
dragpoint(sop->morph_wall_point, mx, my);
// bound the Z
floorz = sector[sop->op_main_sector].floorz;
#define MORPH_FLOOR_ZRANGE Z(300)
if (sop->morph_z > MORPH_FLOOR_ZRANGE)
{
sop->morph_z = MORPH_FLOOR_ZRANGE;
//sop->morph_ang = NORM_ANGLE(sop->morph_ang + 1024);
sop->morph_z_speed *= -1;
}
else if (sop->morph_z < -MORPH_FLOOR_ZRANGE)
{
sop->morph_z = -MORPH_FLOOR_ZRANGE;
//sop->morph_ang = NORM_ANGLE(sop->morph_ang + 1024);
sop->morph_z_speed *= -1;
}
for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
{
if (SectUser[sectnum(*sectp)].Data() &&
TEST(SectUser[sectnum(*sectp)]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
{
alignflorslope(sectnum(*sectp), mx, my, floorz + sop->morph_z);
}
}
}
void
SOBJ_AlignFloorToPoint(SECTOR_OBJECTp sop, int x, int y, int z)
{
SECTORp *sectp;
int j;
for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
{
if (SectUser[sectnum(*sectp)].Data() &&
TEST(SectUser[sectnum(*sectp)]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
{
alignflorslope(int16_t(sectnum(*sectp)), x, y, z);
}
}
}
void
SOBJ_AlignCeilingToPoint(SECTOR_OBJECTp sop, int x, int y, int z)
{
SECTORp *sectp;
int j;
for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
{
if (SectUser[sectnum(*sectp)].Data() &&
TEST(SectUser[sectnum(*sectp)]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
{
alignceilslope(int16_t(sectnum(*sectp)), x, y, z);
}
}
}
void
SOBJ_AlignFloorCeilingToPoint(SECTOR_OBJECTp sop, int x, int y, int z)
{
SECTORp *sectp;
int j;
for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
{
if (SectUser[sectnum(*sectp)].Data() &&
TEST(SectUser[sectnum(*sectp)]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
{
alignflorslope(sectnum(*sectp), x, y, z);
alignceilslope(sectnum(*sectp), x, y, z);
}
}
}
// moves center point around and aligns slope
void
SpikeFloor(SECTOR_OBJECTp sop)
{
int mx, my;
int floorz;
int x,y;
// z direction
ASSERT(sop->op_main_sector >= 0);
sop->morph_z -= Z(sop->morph_z_speed);
// move vector
if (sop->morph_wall_point < 0)
return;
// place at correct x,y offset from center
x = sop->xmid - sop->morph_xoff;
y = sop->ymid - sop->morph_yoff;
// move it from last x,y
mx = x;
my = y;
// bound the Z
floorz = sector[sop->op_main_sector].floorz;
#define MORPH_FLOOR_ZRANGE Z(300)
if (sop->morph_z > MORPH_FLOOR_ZRANGE)
{
sop->morph_z = MORPH_FLOOR_ZRANGE;
sop->morph_z_speed *= -1;
}
else if (sop->morph_z < -MORPH_FLOOR_ZRANGE)
{
sop->morph_z = -MORPH_FLOOR_ZRANGE;
sop->morph_z_speed *= -1;
}
SOBJ_AlignFloorToPoint(sop, mx, my, floorz + sop->morph_z);
#if 0
SECTORp *sectp;
int j;
for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
{
if (SectUser[*sectp - sector] &&
TEST(SectUser[*sectp - sector]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
{
alignflorslope(*sectp - sector, mx, my, floorz + sop->morph_z);
}
}
#endif
}
#include "saveable.h"
static saveable_code saveable_morph_code[] =
{
SAVE_CODE(ScaleSectorObject),
SAVE_CODE(MorphTornado),
SAVE_CODE(MorphFloor),
SAVE_CODE(SpikeFloor),
};
saveable_module saveable_morph =
{
// code
saveable_morph_code,
SIZ(saveable_morph_code),
// data
nullptr,0
};
END_SW_NS