sin-sdk/box.cpp
1998-12-20 00:00:00 +00:00

410 lines
9.5 KiB
C++

//-----------------------------------------------------------------------------
//
// $Logfile:: /Quake 2 Engine/Sin/code/game/box.cpp $
// $Revision:: 36 $
// $Author:: Markd $
// $Date:: 11/15/98 7:51p $
//
// Copyright (C) 1997 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// $Log:: /Quake 2 Engine/Sin/code/game/box.cpp $
//
// 36 11/15/98 7:51p Markd
// fixed boxes so that they wouldn't be case as Item's
//
// 35 11/13/98 2:41p Markd
// fixed box precaching
//
// 34 11/09/98 12:13a Aldie
// Do a modelindex on stuff in boxes
//
// 33 10/26/98 12:28a Markd
// Put in no jc support
//
// 32 10/25/98 2:38a Markd
// put in dialog time in box code
//
// 31 10/25/98 12:47a Markd
// fixed mutant flag for dialog
//
// 30 10/25/98 12:24a Markd
// Put in sounds when blade blows up boxes
//
// 29 10/19/98 12:10a Jimdose
// made all code use fast checks for inheritance (no text lookups when
// possible)
// isSubclassOf no longer requires ::_classinfo()
//
// 28 10/17/98 7:35p Jimdose
// Changed G_CallSpawn to G_CallSpawn2
//
// 27 8/29/98 5:27p Markd
// added specialfx, replaced misc with specialfx where appropriate
//
// 26 8/18/98 11:08p Markd
// Added new Alias System
//
// 25 8/18/98 5:50p Aldie
// Added target activation to box killed function
//
// 24 8/12/98 3:18p Aldie
//
// 23 8/09/98 6:10p Aldie
// New box behavior
//
// 22 8/08/98 9:02p Aldie
// Removed unused var
//
// 21 8/08/98 8:22p Markd
// Took out random items from box code
//
// 20 7/14/98 6:56p Aldie
// Updated healths
//
// 19 6/24/98 12:39p Markd
// Added default tesselation percentage
//
// 18 6/18/98 5:41p Markd
// Fixed crash with boxes
//
// 17 6/18/98 2:00p Markd
// rewrote tesselation code
//
// 16 6/10/98 1:19p Markd
// Removed 357 bullets
//
// 15 5/27/98 9:04p Markd
// weighted boxes with more ammo
//
// 14 5/27/98 8:34p Markd
// Put more health in boxes
//
// 13 5/27/98 5:01a Markd
// Put in dynamic spawning of goodies when box is destroyed
//
// 12 5/25/98 7:51p Jimdose
// Made TellNeighborsToFall use G_NextEntity to check all entities
//
// 11 5/24/98 8:46p Jimdose
// Made a lot of functions more str-friendly.
// Got rid of a lot of char * based strings
// Cleaned up get spawn arg functions and sound functions
// sound functions now use consistant syntax
//
// 10 5/24/98 1:03a Jimdose
// Added breaking sound event when killed
//
// 9 5/11/98 3:51p Markd
// Changed crate blowup sound
//
// 8 5/01/98 11:09a Markd
// Added sound to tesselation event
//
// 7 4/14/98 6:55p Markd
// Added thickness to tesselation
//
// 6 4/08/98 4:19p Jimdose
// Converted to Q2
//
// 4 10/31/97 7:18p Markd
// Changed triagulate call and added a hidemodel call when blowing up
//
// 3 10/31/97 4:32p Markd
// Added shatter sound and also fixed a swapped MOVETYPE/SOLIDTYPE bug
//
// 2 10/30/97 7:42p Jimdose
// Created file
//
// DESCRIPTION:
// Explodable box that falls when boxes below it are destroyed.
//
#include "g_local.h"
#include "entity.h"
#include "box.h"
#include "ammo.h"
#include "health.h"
#include "specialfx.h"
Event EV_Box_Think( "think" );
ResponseDef Box::Responses[] =
{
{ &EV_Box_Think, ( Response )Box::Falling },
{ &EV_Killed, ( Response )Box::Killed },
{ NULL, NULL }
};
/*****************************************************************************/
/*SINED func_box (0 .5 .8) ?
Explodable box that falls when boxes below it are destroyed.
"items" - List of classnames to spawn when the box is destroyed. Separate
each classname by spaces (E.g. Adrenaline RocketLauncher). Default is NULL.
"angles" - Orientation of the item that is spawned.
"health" - Health of the box ( default is 60 )
/*****************************************************************************/
CLASS_DECLARATION( Entity, Box, "func_box" );
EXPORT_FROM_DLL void Box::StartFalling
(
void
)
{
movetime = 0;
velocity += "0 0 100";
setMoveType( MOVETYPE_TOSS );
setSolidType( SOLID_BBOX );
setOrigin( worldorigin + Vector( 0, 0, 1 ) );
PostEvent( EV_Box_Think, FRAMETIME );
}
EXPORT_FROM_DLL void Box::Falling
(
Event *ev
)
{
if ( velocity != vec_zero )
{
movetime = level.time + 1;
}
if ( movetime < level.time )
{
setMoveType( MOVETYPE_PUSH );
setSolidType( SOLID_BSP );
}
else
{
PostEvent( EV_Box_Think, FRAMETIME );
}
}
void Box::TellNeighborsToFall
(
void
)
{
Entity *ent;
//Event *e;
Vector min;
Vector max;
Entity *next;
min = absmin + Vector( 6, 6, 6 );
max = absmax + Vector( -6, -6, 0 );
for( ent = G_NextEntity( world ); ent != NULL; ent = next )
{
next = G_NextEntity( ent );
if ( ( ent != this ) && ent->isSubclassOf( Box ) )
{
if ( !( ( ent->absmax[ 0 ] < min[ 0 ] ) ||
( ent->absmax[ 1 ] < min[ 1 ] ) ||
( ent->absmax[ 2 ] < min[ 2 ] ) ||
( ent->absmin[ 0 ] > max[ 0 ] ) ||
( ent->absmin[ 1 ] > max[ 1 ] ) ||
( ent->absmin[ 2 ] > max[ 2 ] ) ) )
{
if ( ent->takedamage != DAMAGE_NO )
( ( Box * )ent )->StartFalling();
// Ok, it's a hack.
//if ( ent->takedamage != DAMAGE_NO )
// {
// e = new Event( ev );
// ent->ProcessEvent( e );
// }
}
}
}
}
void Box::Killed
(
Event *ev
)
{
Entity *attacker;
Vector dir;
Vector org;
Entity *ent;
const char *s;
const char *token;
int width = 0;
int depth = 0;
int boxwidth;
char temp[ 128 ];
const char *name;
int num;
Event *event;
qboolean spawned;
static float last_dialog_time = 0;
hideModel();
RandomGlobalSound( "impact_crateexplo", 1, CHAN_BODY, ATTN_NORM );
takedamage = DAMAGE_NO;
TellNeighborsToFall();
ProcessEvent( EV_BreakingSound );
attacker = ev->GetEntity( 1 );
dir = worldorigin - attacker->worldorigin;
TesselateModel
(
this,
tess_min_size,
tess_max_size,
dir,
ev->GetInteger( 2 ),
tess_percentage,
tess_thickness,
vec3_origin
);
//
// fire off targets
//
name = Target();
if ( name && strcmp( name, "" ) )
{
num = 0;
do
{
num = G_FindTarget( num, name );
if ( !num )
{
break;
}
ent = G_GetEntity( num );
event = new Event( EV_Activate );
event->AddEntity( attacker );
ent->PostEvent( event, 0 );
}
while ( 1 );
}
// items holds the list of def files to spawn
s = items.c_str();
G_InitSpawnArguments();
if ( setangles )
{
sprintf( temp, "%f %f %f", angles[ 0 ],angles[ 1 ],angles[ 2 ] );
G_SetSpawnArg( "angles", temp );
}
spawned = false;
boxwidth = maxs[0];
while (1)
{
token = COM_Parse(&s);
if (!token[0])
break;
G_SetSpawnArg( "model", token );
if ( ( width * 32 ) > boxwidth )
{
width = 0;
depth++;
}
// Calculate and set the origin
org = worldorigin + Vector("0 0 32") + Vector("32 0 0") * width + Vector("0 32 0") * depth;
width++;
sprintf( temp, "%f %f %f", org[ 0 ], org[ 1 ], org[ 2 ] );
G_SetSpawnArg( "origin", temp );
// Create the item
ent = ( Entity * )G_CallSpawn();
spawned = true;
// Postpone the Drop because the box is still there.
ent->PostponeEvent( EV_Item_DropToFloor, 0.1f );
}
G_InitSpawnArguments();
if (
spawned &&
attacker->isClient() &&
( last_dialog_time < level.time ) &&
( !( attacker->flags & FL_SP_MUTANT ) ) &&
( !deathmatch->value )
)
{
char name[ 128 ];
int num;
last_dialog_time = level.time + 25;
if ( level.no_jc )
{
num = (int)G_Random( 3 ) + 1;
}
else
{
num = (int)G_Random( 5 ) + 1;
}
sprintf( name, "global/universal_script.scr::blade_finds_item%d", num );
ExecuteThread( name, true );
}
PostEvent( EV_Remove, 0 );
}
Box::Box()
{
const char *text;
const char *s;
char token[ MAX_TOKEN_CHARS ];
movetime = 0;
showModel();
setMoveType( MOVETYPE_PUSH );
setSolidType( SOLID_BSP );
setOrigin( origin );
health = G_GetIntArg( "health", 60 );
max_health = health;
takedamage = DAMAGE_YES;
tess_thickness = 20;
text = G_GetSpawnArg( "items" );
if ( text )
{
items = text;
s = items.c_str();
while ( 1 )
{
strcpy( token, COM_Parse(&s) );
if ( !token[0] )
break;
modelIndex( token );
}
}
setangles = ( G_GetSpawnArg( "angle" ) || G_GetSpawnArg( "angles" ) );
if ( setangles )
{
float angle;
angle = G_GetFloatArg( "angle", 0 );
angles = G_GetVectorArg( "angles", Vector( 0, angle, 0 ) );
}
}