//----------------------------------------------------------------------------- // // $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 ) ); } }