483 lines
9.4 KiB
C++
483 lines
9.4 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Logfile:: /EF2/Code/DLLs/game/object.cpp $
|
|
// $Revision:: 9 $
|
|
// $Author:: Singlis $
|
|
// $Date:: 9/26/03 2:36p $
|
|
//
|
|
// Copyright (C) 1998 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.
|
|
//
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
|
|
|
|
#include "_pch_cpp.h"
|
|
#include "object.h"
|
|
#include "sentient.h"
|
|
#include "misc.h"
|
|
#include "explosion.h"
|
|
#include "gibs.h"
|
|
#include "specialfx.h"
|
|
|
|
Event EV_Object_Setup
|
|
(
|
|
"_setup",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"Sets up an object."
|
|
);
|
|
Event EV_Object_SetAnim
|
|
(
|
|
"anim",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"animname",
|
|
"Sets up the object with the specified animname."
|
|
);
|
|
Event EV_Object_Shootable
|
|
(
|
|
"shootable",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Make the object shootable but not necessarily solid to the player."
|
|
);
|
|
|
|
CLASS_DECLARATION( Entity, Object, "object" )
|
|
{
|
|
{ &EV_Killed, &Object::Killed },
|
|
{ &EV_Object_Setup, &Object::Setup },
|
|
{ &EV_Object_SetAnim, &Object::SetAnim },
|
|
{ &EV_Object_Shootable, &Object::MakeShootable },
|
|
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
Object::Object()
|
|
{
|
|
animate = new Animate( this );
|
|
|
|
if ( LoadingSavegame )
|
|
{
|
|
// Archive function will setup all necessary data
|
|
return;
|
|
}
|
|
//
|
|
// all objects default to not solid
|
|
//
|
|
setSolidType( SOLID_NOT );
|
|
|
|
health = 0;
|
|
|
|
takedamage = ( spawnflags & 2 ) ? DAMAGE_NO : DAMAGE_YES;
|
|
|
|
//
|
|
// we want the bounds of this model auto-rotated
|
|
//
|
|
flags |= FL_ROTATEDBOUNDS;
|
|
|
|
if ( !com_blood->integer )
|
|
{
|
|
flags &= ~FL_BLOOD;
|
|
flags &= ~FL_DIE_GIBS;
|
|
}
|
|
|
|
PostEvent( EV_Object_Setup, EV_POSTSPAWN );
|
|
}
|
|
|
|
void Object::SetAnim( Event *ev )
|
|
{
|
|
int animnum;
|
|
|
|
if ( ( ev->NumArgs() >= 1 ) && gi.IsModel( edict->s.modelindex ) )
|
|
{
|
|
animnum = gi.Anim_Random( edict->s.modelindex, ev->GetString( 1 ) );
|
|
if ( animnum >= 0 )
|
|
{
|
|
animate->NewAnim( animnum );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Object::Setup( Event *ev )
|
|
{
|
|
if ( !health )
|
|
{
|
|
health = ( maxs - mins ).length();
|
|
max_health = health;
|
|
}
|
|
}
|
|
|
|
void Object::MakeShootable( Event *ev )
|
|
{
|
|
setContents( CONTENTS_SHOOTABLE_ONLY );
|
|
link();
|
|
}
|
|
|
|
void Object::Killed(Event *ev)
|
|
{
|
|
Entity * ent;
|
|
Entity * attacker;
|
|
Vector dir;
|
|
Event * event;
|
|
const char * name;
|
|
|
|
takedamage = DAMAGE_NO;
|
|
setSolidType( SOLID_NOT );
|
|
hideModel();
|
|
|
|
attacker = ev->GetEntity( 1 );
|
|
|
|
if (flags & FL_DIE_EXPLODE)
|
|
{
|
|
CreateExplosion( origin, 50.0f, this, this, this );
|
|
}
|
|
|
|
if (flags & FL_DIE_GIBS)
|
|
{
|
|
setSolidType( SOLID_NOT );
|
|
hideModel();
|
|
|
|
CreateGibs( this, -150.0f, edict->s.scale, 3 );
|
|
}
|
|
|
|
//
|
|
// kill the killtargets
|
|
//
|
|
name = KillTarget();
|
|
if ( name && strcmp( name, "" ) )
|
|
{
|
|
ent = NULL;
|
|
do
|
|
{
|
|
ent = G_FindTarget( ent, name );
|
|
if ( !ent )
|
|
{
|
|
break;
|
|
}
|
|
ent->PostEvent( EV_Remove, 0.0f );
|
|
}
|
|
while ( 1 );
|
|
}
|
|
|
|
//
|
|
// fire targets
|
|
//
|
|
name = Target();
|
|
if ( name && strcmp( name, "" ) )
|
|
{
|
|
ent = NULL;
|
|
do
|
|
{
|
|
ent = G_FindTarget( ent, name );
|
|
if ( !ent )
|
|
{
|
|
break;
|
|
}
|
|
event = new Event( EV_Activate );
|
|
event->AddEntity( attacker );
|
|
ent->ProcessEvent( event );
|
|
}
|
|
while ( 1 );
|
|
}
|
|
|
|
PostEvent( EV_Remove, 0.0f );
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*QUAKED func_throwobject (0 0.25 0.5) (-16 -16 0) (16 16 32)
|
|
|
|
This is an object you can pickup and throw at people
|
|
******************************************************************************/
|
|
|
|
Event EV_ThrowObject_Pickup
|
|
(
|
|
"pickup",
|
|
EV_DEFAULT,
|
|
"es",
|
|
"entity tag_name",
|
|
"Picks up this throw object and attaches it to the entity."
|
|
);
|
|
Event EV_ThrowObject_Throw
|
|
(
|
|
"throw",
|
|
EV_DEFAULT,
|
|
"efeF",
|
|
"owner speed targetent grav",
|
|
"Throw this throw object."
|
|
);
|
|
Event EV_ThrowObject_PickupOffset
|
|
(
|
|
"pickupoffset",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"pickup_offset",
|
|
"Sets the pickup_offset."
|
|
);
|
|
Event EV_ThrowObject_ThrowSound
|
|
(
|
|
"throwsound",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"throw_sound",
|
|
"Sets the sound to play when object is thrown."
|
|
);
|
|
|
|
CLASS_DECLARATION( Object, ThrowObject, "func_throwobject" )
|
|
{
|
|
{ &EV_Touch, &ThrowObject::Touch },
|
|
{ &EV_ThrowObject_Pickup, &ThrowObject::Pickup },
|
|
{ &EV_ThrowObject_Throw, &ThrowObject::Throw },
|
|
{ &EV_ThrowObject_PickupOffset, &ThrowObject::PickupOffset },
|
|
{ &EV_ThrowObject_ThrowSound, &ThrowObject::ThrowSound },
|
|
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
ThrowObject::ThrowObject()
|
|
{
|
|
if ( LoadingSavegame )
|
|
{
|
|
// Archive function will setup all necessary data
|
|
return;
|
|
}
|
|
pickup_offset = vec_zero;
|
|
damage = 0;
|
|
hurt_target = false;
|
|
owner = NULL;
|
|
}
|
|
|
|
void ThrowObject::PickupOffset( Event *ev )
|
|
{
|
|
pickup_offset = edict->s.scale * ev->GetVector( 1 );
|
|
}
|
|
|
|
void ThrowObject::ThrowSound( Event *ev )
|
|
{
|
|
throw_sound = ev->GetString( 1 );
|
|
}
|
|
|
|
void ThrowObject::Touch( Event *ev )
|
|
{
|
|
Entity *other;
|
|
|
|
if ( movetype != MOVETYPE_BOUNCE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
other = ev->GetEntity( 1 );
|
|
assert( other );
|
|
|
|
if ( other->isSubclassOf( Teleporter ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( other->entnum == owner )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( throw_sound.length() )
|
|
{
|
|
StopLoopSound();
|
|
}
|
|
|
|
if ( other->takedamage && !hurt_target )
|
|
{
|
|
// other->Damage( this, G_GetEntity( owner ), size.length() * velocity.length() / 400, origin, velocity,
|
|
// level.impact_trace.plane.normal, 32, 0, MOD_THROWNOBJECT );
|
|
|
|
other->Damage( this, G_GetEntity( owner ), damage, origin, velocity,
|
|
level.impact_trace.plane.normal, 32, 0, MOD_THROWNOBJECT );
|
|
hurt_target = true;
|
|
}
|
|
|
|
//Damage( this, this, max_health, origin, velocity, level.impact_trace.plane.normal, 32, 0, MOD_THROWNOBJECT );
|
|
Damage( this, this, 0.0f, origin, velocity, level.impact_trace.plane.normal, 32, 0, MOD_THROWNOBJECT );
|
|
}
|
|
|
|
void ThrowObject::Throw( const Entity *owner, float speed, const Sentient *targetent, float gravity, float throw_damage )
|
|
{
|
|
float traveltime;
|
|
float vertical_speed;
|
|
Vector target;
|
|
Vector dir;
|
|
Vector xydir;
|
|
Event *e;
|
|
|
|
|
|
e = new Event( EV_Detach );
|
|
ProcessEvent( e );
|
|
|
|
this->owner = owner->entnum;
|
|
edict->ownerNum = owner->entnum;
|
|
|
|
damage = throw_damage;
|
|
target = targetent->origin;
|
|
target.z += targetent->viewheight;
|
|
|
|
setMoveType( MOVETYPE_BOUNCE );
|
|
setSolidType( SOLID_BBOX );
|
|
edict->clipmask = MASK_PROJECTILE;
|
|
|
|
dir = target - origin;
|
|
xydir = dir;
|
|
xydir.z = 0;
|
|
traveltime = xydir.length() / speed;
|
|
vertical_speed = ( dir.z / traveltime ) + ( 0.5f * gravity * sv_currentGravity->value * traveltime );
|
|
xydir.normalize();
|
|
|
|
// setup ambient flying sound
|
|
if ( throw_sound.length() )
|
|
{
|
|
LoopSound( throw_sound.c_str() );
|
|
}
|
|
|
|
velocity = speed * xydir;
|
|
velocity.z = vertical_speed;
|
|
|
|
angles = velocity.toAngles();
|
|
setAngles( angles );
|
|
|
|
avelocity.x = crandom() * 200.0f;
|
|
avelocity.y = crandom() * 200.0f;
|
|
takedamage = DAMAGE_YES;
|
|
}
|
|
|
|
void ThrowObject::Throw( Event *ev )
|
|
{
|
|
Entity *owner;
|
|
Sentient *targetent;
|
|
float speed;
|
|
float grav;
|
|
float throw_damage;
|
|
|
|
owner = ev->GetEntity( 1 );
|
|
assert( owner );
|
|
|
|
if ( !owner )
|
|
{
|
|
return;
|
|
}
|
|
|
|
speed = ev->GetFloat( 2 );
|
|
if ( !speed )
|
|
{
|
|
speed = 1;
|
|
}
|
|
|
|
targetent = ( Sentient * )ev->GetEntity( 3 );
|
|
assert( targetent );
|
|
if (!targetent)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( ev->NumArgs() > 3 )
|
|
{
|
|
grav = ev->GetFloat( 4 );
|
|
}
|
|
else
|
|
{
|
|
grav = 1;
|
|
}
|
|
|
|
if ( ev->NumArgs() > 4 )
|
|
throw_damage = ev->GetFloat( 5 );
|
|
else
|
|
throw_damage = 0;
|
|
|
|
Throw( owner, speed, targetent, grav, throw_damage );
|
|
|
|
/*
|
|
e = new Event( EV_Detach );
|
|
ProcessEvent( e );
|
|
|
|
this->owner = owner->entnum;
|
|
edict->ownerNum = owner->entnum;
|
|
|
|
gravity = grav;
|
|
|
|
|
|
target = targetent->origin;
|
|
target.z += targetent->viewheight;
|
|
|
|
setMoveType( MOVETYPE_BOUNCE );
|
|
setSolidType( SOLID_BBOX );
|
|
edict->clipmask = MASK_PROJECTILE;
|
|
|
|
dir = target - origin;
|
|
xydir = dir;
|
|
xydir.z = 0;
|
|
traveltime = xydir.length() / speed;
|
|
vertical_speed = ( dir.z / traveltime ) + ( 0.5f * gravity * sv_currentGravity->value * traveltime );
|
|
xydir.normalize();
|
|
|
|
// setup ambient flying sound
|
|
if ( throw_sound.length() )
|
|
{
|
|
LoopSound( throw_sound.c_str() );
|
|
}
|
|
|
|
velocity = speed * xydir;
|
|
velocity.z = vertical_speed;
|
|
|
|
angles = velocity.toAngles();
|
|
setAngles( angles );
|
|
|
|
avelocity.x = crandom() * 200;
|
|
avelocity.y = crandom() * 200;
|
|
takedamage = DAMAGE_YES;
|
|
*/
|
|
}
|
|
|
|
void ThrowObject::Pickup( Entity *ent, const str &bone )
|
|
{
|
|
Event *e;
|
|
|
|
setOrigin( pickup_offset );
|
|
|
|
e = new Event( EV_Attach );
|
|
e->AddEntity( ent );
|
|
e->AddString( bone );
|
|
ProcessEvent( e );
|
|
hurt_target = false;
|
|
edict->s.renderfx &= ~RF_FRAMELERP;
|
|
}
|
|
|
|
void ThrowObject::Pickup( Event *ev )
|
|
{
|
|
Entity * ent;
|
|
//Event * e;
|
|
str bone;
|
|
|
|
ent = ev->GetEntity( 1 );
|
|
|
|
assert( ent );
|
|
if ( !ent )
|
|
{
|
|
return;
|
|
}
|
|
bone = ev->GetString( 2 );
|
|
|
|
/*
|
|
setOrigin( pickup_offset );
|
|
|
|
e = new Event( EV_Attach );
|
|
e->AddEntity( ent );
|
|
e->AddString( bone );
|
|
ProcessEvent( e );
|
|
|
|
edict->s.renderfx &= ~RF_FRAMELERP;
|
|
*/
|
|
|
|
Pickup( ent , bone );
|
|
}
|