mirror of
https://github.com/UberGames/EF2GameSource.git
synced 2024-11-10 06:31:42 +00:00
2578 lines
52 KiB
C++
2578 lines
52 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Logfile:: /EF2/Code/DLLs/game/vehicle.cpp $
|
|
// $Revision:: 34 $
|
|
// $Author:: Singlis $
|
|
// $Date:: 9/26/03 2:36p $
|
|
//
|
|
// 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.
|
|
//
|
|
//
|
|
// DESCRIPTION:
|
|
// Script controlled Vehicles.
|
|
//
|
|
|
|
#include "_pch_cpp.h"
|
|
#include "scriptslave.h"
|
|
#include "vehicle.h"
|
|
#include "player.h"
|
|
#include "specialfx.h"
|
|
#include "explosion.h"
|
|
#include "earthquake.h"
|
|
#include "gibs.h"
|
|
#include "player.h"
|
|
|
|
Event EV_Vehicle_Start
|
|
(
|
|
"start",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Initialize the vehicle."
|
|
);
|
|
Event EV_Vehicle_Enter
|
|
(
|
|
"enter",
|
|
EV_CODEONLY,
|
|
"eS",
|
|
"vehicle driver_anim",
|
|
"Called when someone gets into a vehicle."
|
|
);
|
|
Event EV_Vehicle_Exit
|
|
(
|
|
"exit",
|
|
EV_DEFAULT,
|
|
"e",
|
|
"vehicle",
|
|
"Called when driver gets out of the vehicle."
|
|
);
|
|
Event EV_Vehicle_Drivable
|
|
(
|
|
"drivable",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Make the vehicle drivable"
|
|
);
|
|
Event EV_Vehicle_UnDrivable
|
|
(
|
|
"undriveable",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Make the vehicle undrivable"
|
|
);
|
|
Event EV_Vehicle_Jumpable
|
|
(
|
|
"canjump",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"jumpable",
|
|
"Sets whether or not the vehicle can jump"
|
|
);
|
|
Event EV_Vehicle_Lock
|
|
(
|
|
"lock",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Sets the vehicle to be locked"
|
|
);
|
|
Event EV_Vehicle_UnLock
|
|
(
|
|
"unlock",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Sets the vehicle to be unlocked"
|
|
);
|
|
Event EV_Vehicle_SeatAnglesOffset
|
|
(
|
|
"seatanglesoffset",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"angles",
|
|
"Set the angles offset of the seat"
|
|
);
|
|
Event EV_Vehicle_SeatOffset
|
|
(
|
|
"seatoffset",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"offset",
|
|
"Set the offset of the seat"
|
|
);
|
|
Event EV_Vehicle_DriverAnimation
|
|
(
|
|
"driveranim",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"animation",
|
|
"Set the animation of the driver to use when the driver is in the vehicle"
|
|
);
|
|
Event EV_Vehicle_SetWeapon
|
|
(
|
|
"setweapon",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"weaponname",
|
|
"Set the weapon for the vehicle"
|
|
);
|
|
Event EV_Vehicle_SetSpeed
|
|
(
|
|
"vehiclespeed",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"speed",
|
|
"Set the speed of the vehicle"
|
|
);
|
|
Event EV_Vehicle_SetTurnRate
|
|
(
|
|
"turnrate",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"rate",
|
|
"Set the turning rate of the vehicle"
|
|
);
|
|
Event EV_Vehicle_SteerInPlace
|
|
(
|
|
"steerinplace",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Set the vehicle to turn in place"
|
|
);
|
|
Event EV_Vehicle_ShowWeapon
|
|
(
|
|
"showweapon",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Set the weapon to be show in the view"
|
|
);
|
|
Event EV_Vehicle_RestrictPitch
|
|
(
|
|
"restrictpitch",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"pitchDelta",
|
|
"The max and minimum pitch of the driver"
|
|
);
|
|
Event EV_Vehicle_RestrictRotation
|
|
(
|
|
"restrictrotation",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"rotateDelta",
|
|
"The max and min rotation of the driver"
|
|
);
|
|
Event EV_Vehicle_NoPrediction
|
|
(
|
|
"noprediction",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"bool",
|
|
"Turns no prediction on or off"
|
|
);
|
|
|
|
Event EV_Vehicle_DisableInventory
|
|
(
|
|
"disableinventory",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Disables the inventory when the player uses this vehicle"
|
|
);
|
|
|
|
extern Event EV_Player_DisableUseWeapon;
|
|
extern Event EV_Player_PutawayWeapon;
|
|
|
|
CLASS_DECLARATION( ScriptModel, VehicleBase, NULL )
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
VehicleBase::VehicleBase()
|
|
{
|
|
if ( LoadingSavegame )
|
|
{
|
|
// Archive function will setup all necessary data
|
|
return;
|
|
}
|
|
|
|
takedamage = DAMAGE_NO;
|
|
showModel();
|
|
setSolidType( SOLID_NOT );
|
|
setMoveType( MOVETYPE_NONE );
|
|
setOrigin( GetLocalOrigin() + Vector( "0 0 30") );
|
|
|
|
//
|
|
// we want the bounds of this model auto-rotated
|
|
//
|
|
flags |= FL_ROTATEDBOUNDS;
|
|
|
|
//
|
|
// rotate the mins and maxs for the model
|
|
//
|
|
setSize( mins, maxs );
|
|
|
|
vlink = NULL;
|
|
offset = Vector(0, 0, 0);
|
|
|
|
PostEvent( EV_BecomeNonSolid, EV_POSTSPAWN );
|
|
}
|
|
|
|
CLASS_DECLARATION( VehicleBase, BackWheels, "script_wheelsback" )
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
CLASS_DECLARATION( VehicleBase, FrontWheels, "script_wheelsfront" )
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
CLASS_DECLARATION( VehicleBase, Vehicle, "script_vehicle" )
|
|
{
|
|
{ &EV_Blocked, &Vehicle::VehicleBlocked },
|
|
{ &EV_Touch, &Vehicle::VehicleTouched },
|
|
{ &EV_Use, &Vehicle::DriverUse },
|
|
{ &EV_Vehicle_Start, &Vehicle::VehicleStart },
|
|
{ &EV_Vehicle_Drivable, &Vehicle::Drivable },
|
|
{ &EV_Vehicle_UnDrivable, &Vehicle::UnDrivable },
|
|
{ &EV_Vehicle_Jumpable, &Vehicle::Jumpable },
|
|
{ &EV_Vehicle_SeatAnglesOffset, &Vehicle::SeatAnglesOffset},
|
|
{ &EV_Vehicle_SeatOffset, &Vehicle::SeatOffset },
|
|
{ &EV_Vehicle_Lock, &Vehicle::Lock },
|
|
{ &EV_Vehicle_UnLock, &Vehicle::UnLock },
|
|
{ &EV_Vehicle_SetWeapon, &Vehicle::SetWeapon },
|
|
{ &EV_Vehicle_DriverAnimation, &Vehicle::DriverAnimation },
|
|
{ &EV_Vehicle_SetSpeed, &Vehicle::SetSpeed },
|
|
{ &EV_Vehicle_SetTurnRate, &Vehicle::SetTurnRate },
|
|
{ &EV_Vehicle_SteerInPlace, &Vehicle::SteerInPlace },
|
|
{ &EV_Vehicle_ShowWeapon, &Vehicle::ShowWeaponEvent },
|
|
{ &EV_Vehicle_RestrictPitch, &Vehicle::RestrictPitch },
|
|
{ &EV_Vehicle_RestrictRotation, &Vehicle::RestrictRotation},
|
|
{ &EV_Vehicle_NoPrediction, &Vehicle::SetNoPrediction },
|
|
{ &EV_Vehicle_DisableInventory, &Vehicle::DisableInventory},
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
Vehicle::Vehicle()
|
|
{
|
|
if ( LoadingSavegame )
|
|
{
|
|
// Archive function will setup all necessary data
|
|
return;
|
|
}
|
|
takedamage = DAMAGE_YES;
|
|
seatangles = vec_zero;
|
|
driveroffset = vec_zero;
|
|
seatoffset = vec_zero;
|
|
driver = 0;
|
|
lastdriver = 0;
|
|
currentspeed = 0;
|
|
turnangle = 0;
|
|
turnimpulse = 0;
|
|
moveimpulse = 0;
|
|
jumpimpulse = 0;
|
|
conesize = 75;
|
|
hasweapon = false;
|
|
locked = false;
|
|
steerinplace = false;
|
|
drivable = true;
|
|
jumpable = false;
|
|
showweapon = false;
|
|
flags |= FL_DIE_EXPLODE;
|
|
// touch triggers by default
|
|
flags |= FL_TOUCH_TRIGGERS;
|
|
gravity = 1;
|
|
mass = size.length() * 10.0f;
|
|
|
|
health = 1000;
|
|
speed = 1200;
|
|
maxturnrate = 40.0f;
|
|
|
|
usetime = 0.0f;
|
|
|
|
maxtracedist = 0;
|
|
|
|
|
|
_restrictPitch = false;
|
|
_restrictYaw = false;
|
|
_noPrediction = false;
|
|
|
|
_disableInventory = false;
|
|
|
|
PostEvent( EV_Vehicle_Start, FRAMETIME );
|
|
}
|
|
|
|
void Vehicle::VehicleStart( Event *ev )
|
|
{
|
|
Entity *ent;
|
|
VehicleBase *last;
|
|
Vector drivemins, drivemaxs;
|
|
float max;
|
|
float width,height;
|
|
orientation_t orn;
|
|
|
|
// become solid
|
|
setSolidType( SOLID_BBOX );
|
|
|
|
last = this;
|
|
|
|
for( ent = G_NextEntity( NULL ); ent != NULL; ent = G_NextEntity( ent ) )
|
|
{
|
|
if ( ( ent != this ) && ( ent->isSubclassOf( VehicleBase ) ) )
|
|
{
|
|
if ( ( ent->absmax.x >= absmin.x ) && ( ent->absmax.y >= absmin.y ) && ( ent->absmax.z >= absmin.z ) &&
|
|
( ent->absmin.x <= absmax.x ) && ( ent->absmin.y <= absmax.y ) && ( ent->absmin.z <= absmax.z ) )
|
|
{
|
|
last->vlink = ( VehicleBase * )ent;
|
|
last = ( VehicleBase * )ent;
|
|
last->offset = last->origin - origin;
|
|
last->offset = getLocalVector( last->offset );
|
|
last->edict->s.scale *= edict->s.scale;
|
|
}
|
|
}
|
|
}
|
|
|
|
last->vlink = NULL;
|
|
|
|
//
|
|
// get the seat offset
|
|
//
|
|
if ( GetRawTag( "tag_rider", &orn ) )
|
|
{
|
|
driveroffset = Vector( orn.origin );
|
|
}
|
|
driveroffset += seatoffset * edict->s.scale;
|
|
|
|
SetDriverAngles( angles + seatangles );
|
|
|
|
|
|
|
|
max_health = health;
|
|
|
|
//
|
|
// calculate drive mins and maxs
|
|
//
|
|
max = 0;
|
|
if ( fabs( mins[ 0 ] ) > max )
|
|
max = fabs( mins[ 0 ] );
|
|
if ( fabs( maxs[ 0 ] ) > max )
|
|
max = fabs( maxs[ 0 ] );
|
|
if ( fabs( mins[ 1 ] ) > max )
|
|
max = fabs( mins[ 1 ] );
|
|
if ( fabs( maxs[ 1 ] ) > max )
|
|
max = fabs( maxs[ 1 ] );
|
|
drivemins = Vector( -max, -max, mins[ 2 ] ) * edict->s.scale;
|
|
drivemaxs = Vector( max, max, maxs[ 2 ] ) * edict->s.scale;
|
|
|
|
width = maxs[ 1 ] - mins[ 1 ];
|
|
height = maxs[ 0 ] - mins[ 0 ];
|
|
|
|
maxtracedist = height;
|
|
|
|
Corners[ 0 ][ 0 ] = -( width / 4.0f );
|
|
Corners[ 0 ][ 1 ] = ( height / 4.0f );
|
|
Corners[ 0 ][ 2 ] = 0.0f;
|
|
|
|
Corners[ 1 ][ 0 ] = ( width / 4.0f );
|
|
Corners[ 1 ][ 1 ] = ( height / 4.0f );
|
|
Corners[ 1 ][ 2 ] = 0.0f;
|
|
|
|
Corners[ 2 ][ 0 ] = -( width / 4.0f );
|
|
Corners[ 2 ][ 1 ] = -( height / 4.0f );
|
|
Corners[ 2 ][ 2 ] = 0.0f;
|
|
|
|
Corners[ 3 ][ 0 ] = ( width / 4.0f );
|
|
Corners[ 3 ][ 1 ] = -( height / 4.0f );
|
|
Corners[ 3 ][ 2 ] = 0.0f;
|
|
if ( drivable )
|
|
{
|
|
// drop everything back to the floor
|
|
//droptofloor( 250.0f );
|
|
Postthink();
|
|
}
|
|
last_origin = origin;
|
|
setSize( drivemins, drivemaxs );
|
|
}
|
|
|
|
void Vehicle::Drivable( Event *ev )
|
|
{
|
|
setMoveType( MOVETYPE_NONE );
|
|
drivable = true;
|
|
}
|
|
|
|
void Vehicle::UnDrivable( Event *ev )
|
|
{
|
|
setMoveType( MOVETYPE_PUSH );
|
|
drivable = false;
|
|
}
|
|
|
|
void Vehicle::Jumpable( Event *ev )
|
|
{
|
|
jumpable = true;
|
|
}
|
|
|
|
void Vehicle::Lock( Event *ev )
|
|
{
|
|
locked = true;
|
|
}
|
|
|
|
void Vehicle::UnLock( Event *ev )
|
|
{
|
|
locked = false;
|
|
}
|
|
|
|
void Vehicle::SteerInPlace( Event *ev )
|
|
{
|
|
steerinplace = true;
|
|
}
|
|
|
|
void Vehicle::SeatAnglesOffset( Event *ev )
|
|
{
|
|
seatangles = ev->GetVector( 1 );
|
|
}
|
|
|
|
void Vehicle::SeatOffset( Event *ev )
|
|
{
|
|
seatoffset = ev->GetVector( 1 );
|
|
}
|
|
|
|
void Vehicle::SetWeapon( Event *ev )
|
|
{
|
|
showweapon = true;
|
|
hasweapon = true;
|
|
weaponName = ev->GetString( 1 );
|
|
}
|
|
|
|
void Vehicle::ShowWeaponEvent( Event *ev )
|
|
{
|
|
showweapon = true;
|
|
}
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: RestrictPitch
|
|
// Class: Vehicle
|
|
//
|
|
// Description: Restricts the drivers pitch while in the vehicle. This calculates the pitchSeam.
|
|
// A seam is the location where the normalized angle range boundary. For example
|
|
// on a normalized range of -180, 180, the seam is located at -180/180. To solve the seam
|
|
// problem, the seam is always positioned directly (-180 degrees) behind the starting pitch.
|
|
//
|
|
// Parameters: event - event containing the pitch restrictions
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Vehicle::RestrictPitch(Event* event)
|
|
{
|
|
_startPitch = angles[PITCH];
|
|
_pitchSeam = _startPitch - 180.0f;
|
|
|
|
_minimumPitch = AngleNormalizeArbitrary( _startPitch - event->GetFloat(1), _pitchSeam);
|
|
_maximumPitch = AngleNormalizeArbitrary( _startPitch + event->GetFloat(1), _pitchSeam);
|
|
|
|
_restrictPitch = true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: RestrictRotation
|
|
// Class: Vehicle
|
|
//
|
|
// Description: Restricts the drivers rotation while in the vehicle.This calculates the yawSeam.
|
|
// A seam is the location where the normalized angle range boundary. For example
|
|
// on a normalized range of -180, 180, the seam is located at -180/180. To solve the seam
|
|
// problem, the seam is always positioned directly (-180 degrees) behind the starting yaw.
|
|
//
|
|
// Parameters: event - the event containing the rotation restrictions
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Vehicle::RestrictRotation(Event* event)
|
|
{
|
|
_startYaw = angles[YAW];
|
|
_yawSeam = _startYaw - 180.0f;
|
|
|
|
_minimumYaw = AngleNormalizeArbitrary( _startYaw - event->GetFloat(1), _yawSeam);
|
|
_maximumYaw = AngleNormalizeArbitrary( _startYaw + event->GetFloat(1), _yawSeam);
|
|
|
|
_restrictYaw = true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name: SetNoPrediction
|
|
// Class: Vehicle
|
|
//
|
|
// Description: Turns the no prediction flag
|
|
//
|
|
// Parameters: event - the event that turns no prediction on or off
|
|
//
|
|
// Returns: None
|
|
//-----------------------------------------------------
|
|
void Vehicle::SetNoPrediction(Event* event)
|
|
{
|
|
_noPrediction = event->GetBoolean(1);
|
|
}
|
|
|
|
|
|
void Vehicle::DisableInventory(Event* event)
|
|
{
|
|
_disableInventory = true;
|
|
}
|
|
|
|
|
|
void Vehicle::DriverAnimation( Event *ev )
|
|
{
|
|
driveranim = ev->GetString( 1 );
|
|
}
|
|
|
|
qboolean Vehicle::HasWeapon( void )
|
|
{
|
|
return hasweapon;
|
|
}
|
|
|
|
qboolean Vehicle::ShowWeapon( void )
|
|
{
|
|
return showweapon;
|
|
}
|
|
|
|
void Vehicle::SetDriverAngles( const Vector &angles )
|
|
{
|
|
int i;
|
|
|
|
if ( !driver )
|
|
return;
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
{
|
|
driver->client->ps.delta_angles[ i ] = ANGLE2SHORT( angles[ i ] - driver->client->cmd_angles[ i ] );
|
|
}
|
|
}
|
|
|
|
void Vehicle::HandleEvent( Event *ev )
|
|
{
|
|
|
|
}
|
|
|
|
/*
|
|
=============
|
|
CheckWater
|
|
=============
|
|
*/
|
|
void Vehicle::CheckWater( void )
|
|
{
|
|
Vector point;
|
|
int cont;
|
|
int sample1;
|
|
int sample2;
|
|
VehicleBase *v;
|
|
|
|
unlink();
|
|
v = this;
|
|
while( v->vlink )
|
|
{
|
|
v = v->vlink;
|
|
v->unlink();
|
|
}
|
|
|
|
if ( driver )
|
|
{
|
|
driver->unlink();
|
|
}
|
|
|
|
//
|
|
// get waterlevel
|
|
//
|
|
waterlevel = 0;
|
|
watertype = 0;
|
|
|
|
sample2 = maxs[ 2 ] - mins[ 2 ];
|
|
sample1 = sample2 / 2;
|
|
|
|
point = origin;
|
|
point[ 2 ] += mins[ 2 ];
|
|
cont = gi.pointcontents( point, 0 );
|
|
|
|
if ( cont & MASK_WATER )
|
|
{
|
|
watertype = cont;
|
|
waterlevel = 1;
|
|
point[ 2 ] = origin[ 2 ] + mins[ 2 ] + sample1;
|
|
cont = gi.pointcontents( point, 0 );
|
|
if ( cont & MASK_WATER )
|
|
{
|
|
waterlevel = 2;
|
|
point[ 2 ] = origin[ 2 ] + mins[ 2 ] + sample2;
|
|
cont = gi.pointcontents( point, 0 );
|
|
if ( cont & MASK_WATER )
|
|
{
|
|
waterlevel = 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
link();
|
|
v = this;
|
|
while( v->vlink )
|
|
{
|
|
v = v->vlink;
|
|
v->link();
|
|
}
|
|
|
|
if ( driver )
|
|
{
|
|
driver->link();
|
|
driver->waterlevel = waterlevel;
|
|
driver->watertype = watertype;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============
|
|
WorldEffects
|
|
=============
|
|
*/
|
|
void Vehicle::WorldEffects( void )
|
|
{
|
|
//
|
|
// Check for earthquakes
|
|
//
|
|
/* if ( groundentity && ( level.earthquake > level.time ) )
|
|
{
|
|
velocity += Vector
|
|
(
|
|
level.earthquake_magnitude * EARTHQUAKE_STRENGTH * G_CRandom(),
|
|
level.earthquake_magnitude * EARTHQUAKE_STRENGTH * G_CRandom(),
|
|
level.earthquake_magnitude * 1.5f * G_Random()
|
|
);
|
|
} */
|
|
|
|
//
|
|
// check for lava
|
|
//
|
|
if ( watertype & CONTENTS_LAVA )
|
|
{
|
|
Damage( world, world, 20.0f * waterlevel, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_LAVA );
|
|
}
|
|
}
|
|
|
|
void Vehicle::DriverUse( Event *ev )
|
|
{
|
|
Event *event;
|
|
Entity *other;
|
|
|
|
other = ev->GetEntity( 1 );
|
|
if ( level.time < ( usetime + 1.0f ) )
|
|
return;
|
|
else
|
|
usetime = level.time;
|
|
|
|
if ( !other || !other->isSubclassOf( Sentient ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( driver )
|
|
{
|
|
// int height;
|
|
// int ang;
|
|
Vector angles;
|
|
Vector forward;
|
|
Vector pos;
|
|
// float ofs;
|
|
// trace_t trace;
|
|
|
|
if ( other != driver )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( locked )
|
|
return;
|
|
/*
|
|
//
|
|
// place the driver on the ground
|
|
//
|
|
ofs = size.length() * 0.5f;
|
|
for ( height = 0; height < 100; height += 16 )
|
|
{
|
|
for ( ang = 0; ang < 360; ang += 30 )
|
|
{
|
|
angles[ 1 ] = driver->angles[ 1 ] + ang + 90.0f;
|
|
angles.AngleVectors( &forward, NULL, NULL );
|
|
pos = origin + (forward * ofs);
|
|
pos[2] += height;
|
|
trace = G_Trace( pos, driver->mins, driver->maxs, pos, NULL, MASK_PLAYERSOLID, false, "Vehicle::DriverUse 1" );
|
|
if ( !trace.startsolid && !trace.allsolid )
|
|
{
|
|
Vector end;
|
|
|
|
end = pos;
|
|
end[ 2 ] -= 128.0f;
|
|
trace = G_Trace( pos, driver->mins, driver->maxs, end, NULL, MASK_PLAYERSOLID, false, "Vehicle::DriverUse 2" );
|
|
if ( trace.fraction < 1.0f )
|
|
{
|
|
driver->setOrigin( pos );
|
|
goto foundpos;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// return;
|
|
|
|
//foundpos:
|
|
|
|
turnimpulse = 0;
|
|
moveimpulse = 0;
|
|
jumpimpulse = 0;
|
|
|
|
event = new Event( EV_Vehicle_Exit );
|
|
event->AddEntity( this );
|
|
driver->ProcessEvent( event );
|
|
|
|
if ( drivable )
|
|
{
|
|
StopLoopSound();
|
|
Sound( "snd_dooropen", CHAN_BODY );
|
|
Sound( "snd_stop", CHAN_VOICE );
|
|
driver->setSolidType( SOLID_BBOX );
|
|
}
|
|
|
|
driver->setOrigin(_oldOrigin);
|
|
|
|
enableDriverInventory();
|
|
|
|
if( hasweapon )
|
|
{
|
|
driver->DeactivateWeapon( WEAPON_DUAL );
|
|
driver->takeItem( weaponName.c_str() );
|
|
}
|
|
|
|
driver = NULL;
|
|
|
|
}
|
|
else
|
|
{
|
|
driver = ( Sentient * )other;
|
|
VectorCopy(driver->edict->client->ps.origin, _oldOrigin);
|
|
|
|
lastdriver = driver;
|
|
|
|
|
|
if ( drivable )
|
|
setMoveType( MOVETYPE_VEHICLE );
|
|
|
|
if ( hasweapon )
|
|
{
|
|
driver->giveItem( weaponName.c_str() );
|
|
driver->useWeapon(weaponName.c_str(), WEAPON_DUAL);
|
|
}
|
|
|
|
disableDriverInventory();
|
|
|
|
if ( drivable )
|
|
{
|
|
Sound( "snd_doorclose", CHAN_BODY );
|
|
Sound( "snd_start", CHAN_VOICE );
|
|
driver->setSolidType( SOLID_NOT );
|
|
}
|
|
|
|
event = new Event( EV_Vehicle_Enter );
|
|
event->AddEntity( this );
|
|
if ( driveranim.length() )
|
|
event->AddString( driveranim );
|
|
driver->ProcessEvent( event );
|
|
|
|
offset = other->origin - origin;
|
|
|
|
flags |= FL_POSTTHINK;
|
|
SetDriverAngles( angles + seatangles );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name:
|
|
// Class:
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Vehicle::disableDriverInventory( void )
|
|
{
|
|
if( _disableInventory == false )
|
|
return;
|
|
|
|
if(driver != 0 && driver->isSubclassOf(Player))
|
|
{
|
|
((Player*)driver.Pointer())->disableInventory();
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------
|
|
//
|
|
// Name:
|
|
// Class:
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//-----------------------------------------------------
|
|
void Vehicle::enableDriverInventory( void )
|
|
{
|
|
if( driver != 0 && driver->isSubclassOf(Player))
|
|
{
|
|
((Player*)driver.Pointer())->enableInventory();
|
|
}
|
|
}
|
|
|
|
qboolean Vehicle::Drive( usercmd_t *ucmd )
|
|
{
|
|
Vector i, j, k;
|
|
|
|
if ( !driver || !driver->isClient() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( !drivable )
|
|
{
|
|
driver->client->ps.pm_flags |= PMF_FROZEN;
|
|
ucmd->forwardmove = 0;
|
|
ucmd->rightmove = 0;
|
|
return false;
|
|
}
|
|
|
|
if(_noPrediction )
|
|
{
|
|
driver->client->ps.pm_flags |= PMF_NO_PREDICTION;
|
|
}
|
|
|
|
moveimpulse = ( ( float )ucmd->forwardmove ) * 3.0f;
|
|
//turnimpulse = ( ( float )-ucmd->rightmove ) * 3.0f;
|
|
jumpimpulse = ( ( float )ucmd->upmove * gravity ) / 350.0f;
|
|
|
|
ucmd->lean = 0;
|
|
|
|
if ( ( jumpimpulse < 0.0f ) || ( !jumpable ) )
|
|
jumpimpulse = 0.0f;
|
|
|
|
turnimpulse = 10.0f * angledist( SHORT2ANGLE( ucmd->angles[ 1 ] ) - driver->client->cmd_angles[ 1 ] );
|
|
|
|
return true;
|
|
}
|
|
|
|
void Vehicle::Postthink( void )
|
|
{
|
|
float turn;
|
|
Vector i, j, k;
|
|
Vector normalsum;
|
|
Vector temp;
|
|
Vector pitch;
|
|
Vector roll;
|
|
VehicleBase *v;
|
|
VehicleBase *last;
|
|
float drivespeed;
|
|
|
|
|
|
if ( drivable )
|
|
{
|
|
currentspeed = moveimpulse / 4.0f;
|
|
|
|
turnangle = turnangle * 0.25f + turnimpulse;
|
|
if ( turnangle > maxturnrate )
|
|
{
|
|
turnangle = maxturnrate;
|
|
}
|
|
else if ( turnangle < -maxturnrate )
|
|
{
|
|
turnangle = -maxturnrate;
|
|
}
|
|
else if ( fabs( turnangle ) < 2.0f )
|
|
{
|
|
turnangle = 0;
|
|
}
|
|
|
|
CalculateOrientation();
|
|
|
|
turn = turnangle * ( 1.0f / 200.0f );
|
|
|
|
if ( groundentity )
|
|
{
|
|
float dot;
|
|
Vector newvel;
|
|
Vector flatvel;
|
|
|
|
velocity[ 0 ] *= 0.925f;
|
|
velocity[ 1 ] *= 0.925f;
|
|
flatvel = Vector( orientation[ 0 ] );
|
|
velocity += flatvel * currentspeed;
|
|
flatvel[ 2 ] = 0;
|
|
dot = velocity * flatvel;
|
|
if ( dot > speed )
|
|
{
|
|
dot = speed;
|
|
}
|
|
else if ( dot < -speed )
|
|
{
|
|
dot = -speed;
|
|
}
|
|
else if ( fabs( dot ) < 20.0f )
|
|
{
|
|
dot = 0;
|
|
}
|
|
newvel = flatvel * dot;
|
|
velocity[ 0 ] = newvel[ 0 ];
|
|
velocity[ 1 ] = newvel[ 1 ];
|
|
velocity[ 2 ] += dot * jumpimpulse;
|
|
|
|
avelocity *= 0.05f;
|
|
if ( steerinplace )
|
|
{
|
|
if ( dot < 350.0f )
|
|
dot = 350.0f;
|
|
avelocity.y += turn * dot;
|
|
}
|
|
else
|
|
{
|
|
avelocity.y += turn * dot;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
avelocity *= 0.1f;
|
|
}
|
|
angles += avelocity * level.frametime;
|
|
setAngles( angles );
|
|
}
|
|
|
|
drivespeed = velocity * Vector( orientation[ 0 ] );
|
|
|
|
if ( drivable && driver )
|
|
{
|
|
str sound_name;
|
|
|
|
if ( currentspeed > 0.0f )
|
|
sound_name = "snd_forward";
|
|
else if ( currentspeed < 0.0f )
|
|
sound_name = "snd_backward";
|
|
else
|
|
sound_name = "snd_idle";
|
|
|
|
LoopSound( sound_name.c_str() );
|
|
}
|
|
|
|
i = Vector( orientation[ 0 ] );
|
|
j = Vector( orientation[ 1 ] );
|
|
k = Vector( orientation[ 2 ] );
|
|
|
|
if ( driver )
|
|
{
|
|
Player * player;
|
|
|
|
if ( driver->isSubclassOf ( Player ) )
|
|
{
|
|
player = ( Player * )( Sentient * )driver;
|
|
player->setOrigin( origin + ( i * driveroffset[0] ) + ( j * driveroffset[1] ) + ( k * driveroffset[2] ) );
|
|
if ( drivable )
|
|
{
|
|
player->velocity = vec_zero;
|
|
Vector playerAngles = player->v_angle;
|
|
Vector viewAngles = angles;
|
|
|
|
if( _restrictPitch )
|
|
{
|
|
if(viewAngles[PITCH] > _maximumPitch)
|
|
viewAngles[PITCH] = _maximumPitch;
|
|
else if(viewAngles[PITCH] < _minimumPitch)
|
|
viewAngles[PITCH] = _minimumPitch;
|
|
}
|
|
|
|
if( _restrictYaw )
|
|
{
|
|
if(viewAngles[YAW] > _maximumYaw)
|
|
viewAngles[YAW] = _maximumYaw;
|
|
else if(viewAngles[YAW] <= _minimumYaw)
|
|
viewAngles[YAW] = _minimumYaw;
|
|
}
|
|
|
|
angles = viewAngles;
|
|
playerAngles.y = angles.y;
|
|
playerAngles.z = angles.z;
|
|
player->SetViewAngles(playerAngles);
|
|
}
|
|
}
|
|
}
|
|
|
|
last = this;
|
|
while( last->vlink )
|
|
{
|
|
v = last->vlink;
|
|
v->setOrigin( origin + ( i * v->offset.x ) + ( j * v->offset.y ) + ( k * v->offset.z ) );
|
|
v->avelocity = avelocity;
|
|
v->velocity = velocity;
|
|
v->angles[ ROLL ] = angles[ ROLL ];
|
|
v->angles[ YAW ] = angles[ YAW ];
|
|
v->angles[ PITCH ] = (float)( (int)( v->angles[ PITCH ] + (drivespeed/4) ) % 360 );
|
|
|
|
if ( v->isSubclassOf( FrontWheels ) )
|
|
{
|
|
v->angles += Vector( 0.0f, turnangle, 0.0f );
|
|
}
|
|
v->setAngles( v->angles );
|
|
|
|
last = v;
|
|
}
|
|
|
|
//CheckWater();
|
|
WorldEffects();
|
|
|
|
// save off last origin
|
|
last_origin = origin;
|
|
|
|
if ( !driver && !velocity.length() && groundentity && !( watertype & CONTENTS_LAVA ) )
|
|
{
|
|
flags &= ~FL_POSTTHINK;
|
|
if ( drivable )
|
|
setMoveType( MOVETYPE_NONE );
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: CalculateOrientation()
|
|
//
|
|
// Description: Calculates the orientation of the vehicle
|
|
// by getting the normals of all the poly's underneath
|
|
// each corner of the vehicle's bounding box, this
|
|
// allows the vehicle to pitch appropriately
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void Vehicle::CalculateOrientation( void )
|
|
{
|
|
Vector temp, pitch, normalsum;
|
|
Vector i, j, k;
|
|
int numnormals;
|
|
trace_t trace;
|
|
|
|
temp[ PITCH ] = 0;
|
|
temp[ YAW ] = angles[ YAW ];
|
|
temp[ ROLL ] = 0;
|
|
temp.AngleVectors( &i, &j, &k );
|
|
j = vec_zero - j;
|
|
|
|
//
|
|
// figure out what our orientation is
|
|
//
|
|
|
|
numnormals = 0;
|
|
for ( int index = 0; index < 4; index++ )
|
|
{
|
|
Vector start, end;
|
|
Vector boxoffset;
|
|
|
|
boxoffset = Corners[ index ];
|
|
start = origin + ( i * boxoffset[0] ) + ( j * boxoffset[1] ) + ( k * boxoffset[2] );
|
|
end = start;
|
|
end[ 2 ] -= maxtracedist;
|
|
trace = G_Trace( start, vec_zero, vec_zero, end, NULL, MASK_SOLID, false, "Vehicle::PostThink Corners" );
|
|
|
|
if ( ( trace.fraction > 0.0f ) && ( trace.fraction != 1.0f ) && !trace.startsolid )
|
|
{
|
|
normalsum += Vector( trace.plane.normal );
|
|
numnormals++;
|
|
}
|
|
}
|
|
|
|
if ( numnormals > 1 )
|
|
{
|
|
temp = normalsum * ( 1.0f/ numnormals );
|
|
temp.normalize();
|
|
i = temp.CrossProduct( temp, j );
|
|
pitch = i;
|
|
|
|
// determine pitch
|
|
angles[ 0 ] = -(pitch.toPitch());
|
|
}
|
|
}
|
|
|
|
void Vehicle::VehicleTouched( Event *ev )
|
|
{
|
|
Entity *other;
|
|
float speed;
|
|
Vector delta;
|
|
Vector dir;
|
|
|
|
other = ev->GetEntity( 1 );
|
|
if ( other == driver )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( other == world )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( drivable && !driver )
|
|
{
|
|
return;
|
|
}
|
|
|
|
delta = origin - last_origin;
|
|
speed = delta.length();
|
|
if ( speed > 2 )
|
|
{
|
|
Sound( "vehicle_crash", true );
|
|
dir = delta * ( 1.0f / speed );
|
|
other->Damage( this, lastdriver, speed * 8.0f, origin, dir, vec_zero, speed * 15, 0, MOD_VEHICLE );
|
|
}
|
|
|
|
}
|
|
|
|
void Vehicle::VehicleBlocked( Event *ev )
|
|
{
|
|
return;
|
|
/*
|
|
Entity *other;
|
|
float speed;
|
|
float damage;
|
|
Vector delta;
|
|
Vector newvel;
|
|
Vector dir;
|
|
|
|
if ( !velocity[0] && !velocity[1] )
|
|
return;
|
|
|
|
other = ev->GetEntity( 1 );
|
|
if ( other == driver )
|
|
{
|
|
return;
|
|
}
|
|
if ( other->isSubclassOf( VehicleBase ) )
|
|
{
|
|
delta = other->origin - origin;
|
|
delta.normalize();
|
|
|
|
newvel = vec_zero - ( velocity) + ( other->velocity * 0.25 );
|
|
if ( newvel * delta < 0 )
|
|
{
|
|
velocity = newvel;
|
|
delta = velocity - other->velocity;
|
|
damage = delta.length()/4;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else if ( ( velocity.length() < 350 ) )
|
|
{
|
|
other->velocity += velocity*1.25f;
|
|
other->velocity[ 2 ] += 100;
|
|
damage = velocity.length()/4;
|
|
}
|
|
else
|
|
{
|
|
damage = other->health + 1000;
|
|
}
|
|
|
|
// Gib 'em outright
|
|
speed = fabs( velocity.length() );
|
|
dir = velocity * ( 1 / speed );
|
|
other->Damage( this, lastdriver, damage, origin, dir, vec_zero, speed, 0, MOD_VEHICLE, -1, -1, 1.0f );
|
|
*/
|
|
}
|
|
|
|
Sentient *Vehicle::Driver( void )
|
|
{
|
|
return driver;
|
|
}
|
|
|
|
qboolean Vehicle::IsDrivable( void )
|
|
{
|
|
return drivable;
|
|
}
|
|
|
|
void Vehicle::SetSpeed( Event *ev )
|
|
{
|
|
speed = ev->GetFloat( 1 );
|
|
}
|
|
|
|
void Vehicle::SetTurnRate( Event *ev )
|
|
{
|
|
maxturnrate = ev->GetFloat( 1 );
|
|
}
|
|
|
|
|
|
CLASS_DECLARATION( Vehicle, DrivableVehicle, "script_drivablevehicle" )
|
|
{
|
|
{ &EV_Damage, &Entity::DamageEvent },
|
|
{ &EV_Killed, &DrivableVehicle::Killed },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
DrivableVehicle::DrivableVehicle()
|
|
{
|
|
if ( LoadingSavegame )
|
|
{
|
|
// Archive function will setup all necessary data
|
|
return;
|
|
}
|
|
|
|
drivable = true;
|
|
flags |= FL_DIE_EXPLODE;
|
|
}
|
|
|
|
void DrivableVehicle::Killed(Event *ev)
|
|
{
|
|
Entity * ent;
|
|
Entity * attacker;
|
|
Vector dir;
|
|
Event * event;
|
|
const char * name;
|
|
VehicleBase *last;
|
|
|
|
takedamage = DAMAGE_NO;
|
|
setSolidType( SOLID_NOT );
|
|
hideModel();
|
|
|
|
attacker = ev->GetEntity( 1 );
|
|
|
|
//
|
|
// kill the driver
|
|
//
|
|
if ( driver )
|
|
{
|
|
Vector dir;
|
|
SentientPtr sent;
|
|
Event * event;
|
|
|
|
velocity = vec_zero;
|
|
sent = driver;
|
|
event = new Event( EV_Use );
|
|
event->AddEntity( sent );
|
|
ProcessEvent( event );
|
|
dir = sent->origin - origin;
|
|
dir[ 2 ] += 64.0f;
|
|
dir.normalize();
|
|
sent->Damage( this, this, sent->health * 2.0f, origin, dir, vec_zero, 50, 0, MOD_VEHICLE );
|
|
}
|
|
|
|
if (flags & FL_DIE_EXPLODE)
|
|
{
|
|
CreateExplosion( origin, 150.0f * edict->s.scale, this, this, this );
|
|
}
|
|
|
|
if (flags & FL_DIE_GIBS)
|
|
{
|
|
setSolidType( SOLID_NOT );
|
|
hideModel();
|
|
|
|
CreateGibs( this, -150.0f, edict->s.scale, 3 );
|
|
}
|
|
//
|
|
// kill all my wheels
|
|
//
|
|
last = this;
|
|
while( last->vlink )
|
|
{
|
|
last->vlink->PostEvent( EV_Remove, 0.0f );
|
|
last = last->vlink;
|
|
}
|
|
|
|
|
|
//
|
|
// 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 );
|
|
}
|
|
|
|
|
|
//===============================================================
|
|
// Horse Vehicle Class
|
|
// New style of vehicle -- Allows the player to drive the vehicle
|
|
// but still mouselook and fire ( turret style )
|
|
// different control configurations ( ie Strafe Only ) etc can
|
|
// be subclassed from movemode and plugged in easily
|
|
//
|
|
//===============================================================
|
|
|
|
Event EV_HorseVehicle_SetSpeed
|
|
(
|
|
"sethorsespeed",
|
|
EV_SCRIPTONLY,
|
|
"f",
|
|
"speed",
|
|
"Set the speed of the horse"
|
|
);
|
|
Event EV_HorseVehicle_SetMoveMode
|
|
(
|
|
"setmovemode",
|
|
EV_SCRIPTONLY,
|
|
"sF",
|
|
"mode angles",
|
|
"Mode ( standard , strafe, or locked ) and a Vector describing the view Angle )"
|
|
);
|
|
Event EV_HorseVehicle_SetForcedForward
|
|
(
|
|
"forceforwardspeed",
|
|
EV_SCRIPTONLY,
|
|
"f",
|
|
"speed",
|
|
"Forces the vehicle to move forward at the specified speed"
|
|
);
|
|
Event EV_Vehicle_AnimDone
|
|
(
|
|
"animdone",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"animdoneevent"
|
|
);
|
|
Event EV_Driver_AnimDone
|
|
(
|
|
"driveranimdone",
|
|
EV_CODEONLY,
|
|
NULL,
|
|
NULL,
|
|
"driveranimdoneevent"
|
|
);
|
|
|
|
CLASS_DECLARATION( Vehicle, HorseVehicle, "script_horsevehicle" )
|
|
{
|
|
{ &EV_HorseVehicle_SetSpeed , &HorseVehicle::SetSpeed },
|
|
{ &EV_HorseVehicle_SetMoveMode , &HorseVehicle::SetVehicleMoveMode },
|
|
{ &EV_HorseVehicle_SetForcedForward, &HorseVehicle::SetForcedForwardSpeed },
|
|
{ &EV_Vehicle_AnimDone, &HorseVehicle::AnimDone },
|
|
{ &EV_Driver_AnimDone, &HorseVehicle::DriverAnimDone },
|
|
|
|
|
|
//Move Mode Events
|
|
{ &EV_FollowPath_SetWayPointName, &HorseVehicle::PassToMoveMode },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: HorseVehicle()
|
|
//
|
|
// Description: Constructor
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
HorseVehicle::HorseVehicle()
|
|
{
|
|
if ( LoadingSavegame )
|
|
{
|
|
// Archive function will setup all necessary data
|
|
return;
|
|
}
|
|
|
|
drivable = true;
|
|
jumpable = true;
|
|
driver = NULL;
|
|
currentspeed = 300;
|
|
|
|
_baseYaw = 0;
|
|
_driverYaw = 0;
|
|
_lastYaw = 0;
|
|
|
|
_driverPitch = 0;
|
|
_lastPitch = 0;
|
|
|
|
_forcedForwardSpeed = 0;
|
|
_jumpflag = false;
|
|
_jumped = false;
|
|
_jumpSpeed = 0;
|
|
|
|
_ducked = false;
|
|
|
|
_minYawThreshold = 90;
|
|
_maxYawThreshold = 90;
|
|
|
|
_minPitchThreshold = 90;
|
|
_maxPitchThreshold = 90;
|
|
|
|
_moveMode = NULL;
|
|
_SetMoveMode( "standard" );
|
|
|
|
_currentCrosshairMode = CROSSHAIR_MODE_STRAIGHT;
|
|
_newCrosshairMode = CROSSHAIR_MODE_STRAIGHT;
|
|
_jumpmode = JUMPMODE_DONE;
|
|
_duckmode = DUCKMODE_DONE;
|
|
_animDone = false;
|
|
_driverAnimDone = false;
|
|
|
|
_ducked = false;
|
|
_duckheld = false;
|
|
|
|
_DriverBBoxMaxs = vec_zero;
|
|
_DriverBBoxMins = vec_zero;
|
|
_originalBBoxMaxs = vec_zero;
|
|
_originalBBoxMins = vec_zero;
|
|
|
|
//Create the Animate Object so that we can set the
|
|
//animation on the vehicle
|
|
if ( !animate )
|
|
animate = new Animate;
|
|
|
|
}
|
|
|
|
HorseVehicle::~HorseVehicle()
|
|
{
|
|
if ( _moveMode )
|
|
{
|
|
delete _moveMode;
|
|
_moveMode = 0;
|
|
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: PassToMoveMode()
|
|
//
|
|
// Description: Hands off the event to the move mode for
|
|
// it to handle -- allows the vehicle to remain dumb in
|
|
// regards to movement specific events
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::PassToMoveMode( Event *ev )
|
|
{
|
|
|
|
if ( _moveMode )
|
|
_moveMode->HandleEvent( ev );
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: Drive()
|
|
//
|
|
// Description: Called from Player->ClientThink
|
|
// Player passes it a ucmd pointer, which points to the
|
|
// latest input data from the user. Drive() uses this
|
|
// data to set up the movement impulses that help control
|
|
// how the vehicle moves
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
qboolean HorseVehicle::Drive( usercmd_t *ucmd )
|
|
{
|
|
Vector i, j, k;
|
|
|
|
if ( !driver || !driver->isClient() )
|
|
return false;
|
|
|
|
if ( !drivable )
|
|
{
|
|
driver->client->ps.pm_flags |= PMF_FROZEN;
|
|
ucmd->forwardmove = 0;
|
|
ucmd->rightmove = 0;
|
|
return false;
|
|
}
|
|
|
|
//Turn off Client Prediction
|
|
//driver->client->ps.pm_flags |= PMF_NO_PREDICTION;
|
|
driver->client->ps.in_vehicle = true;
|
|
driver->client->ps.vehicleoffset[0] = origin[0];
|
|
driver->client->ps.vehicleoffset[1] = origin[1];
|
|
driver->client->ps.vehicleoffset[2] = origin[2] + 160.0f;
|
|
|
|
driver->velocity = velocity;
|
|
|
|
//jumpimpulse is used to calculate a jump value
|
|
//moveimpulse is used to calculate forward and back movement
|
|
//turnimpulse is used to calculate strafe movement
|
|
jumpimpulse = ( ( float )ucmd->upmove * gravity ) / 350.0f;
|
|
moveimpulse = ucmd->forwardmove;
|
|
turnimpulse = ucmd->rightmove;
|
|
|
|
/*
|
|
if ( ( jumpimpulse < 0 ) || ( !jumpable ) )
|
|
jumpimpulse = 0;
|
|
*/
|
|
|
|
return true;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: Postthink()
|
|
//
|
|
// Description: Think Function ( called every frame )
|
|
// Postthink is the master function for the vehicle.
|
|
// it delegates out movement, animation, and FX to
|
|
// subfunctions.
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::Postthink ( void )
|
|
{
|
|
|
|
if ( drivable )
|
|
{
|
|
CalculateOrientation();
|
|
|
|
_moveMode->Move( this );
|
|
|
|
if (driver)
|
|
{
|
|
_PlayMovementSound();
|
|
|
|
if ( !_jumpflag)
|
|
_AnimateVehicle("run");
|
|
|
|
if ( !_duckflag )
|
|
_PositionDriverModel();
|
|
|
|
if ( groundentity && ( jumpimpulse > 0 ) && ( _jumpmode == JUMPMODE_DONE ) && ( _duckmode == DUCKMODE_DONE ) )
|
|
_InitializeJump();
|
|
|
|
if ( _jumpflag )
|
|
_HandleJump();
|
|
|
|
if ( groundentity && ( jumpimpulse < 0 ) && ( _duckmode == DUCKMODE_DONE ) && ( _jumpmode == JUMPMODE_DONE ) && !_duckflag )
|
|
_InitializeDuck();
|
|
|
|
//Released the duck key
|
|
if ( _duckflag && ( jumpimpulse >= 0 ) )
|
|
_ducked = false;
|
|
|
|
if ( _duckflag )
|
|
_HandleDuck();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//Do World Effects ( for earthquakes and the like )
|
|
WorldEffects();
|
|
|
|
Vector flatvel;
|
|
if ( _forcedForwardSpeed )
|
|
{
|
|
flatvel = Vector( orientation[ 0 ] );
|
|
velocity += flatvel * _forcedForwardSpeed;
|
|
}
|
|
|
|
|
|
// Turn off think if we aren't being used
|
|
if ( !driver && !velocity.length() && groundentity && !( watertype & CONTENTS_LAVA ) )
|
|
{
|
|
flags &= ~FL_POSTTHINK;
|
|
if ( drivable )
|
|
setMoveType( MOVETYPE_NONE );
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: DriverUse()
|
|
//
|
|
// Description: Function is called when the player "uses"
|
|
// the vehicle. It handles putting the driver in and
|
|
// taking the driver out of the vehicle.
|
|
//
|
|
// Some sort of use-delay mechanism must be in place or
|
|
// it will be very difficult for the player to get on and
|
|
// off the vehicle, because the use events are stepping
|
|
// on each other
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::DriverUse( Event *ev )
|
|
{
|
|
|
|
Event *event;
|
|
Entity *other;
|
|
|
|
other = ev->GetEntity( 1 );
|
|
if ( level.time < usetime + 1.0f )
|
|
return;
|
|
else
|
|
usetime = level.time;
|
|
|
|
if ( !other || !other->isSubclassOf( Sentient ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( driver )
|
|
{
|
|
int height;
|
|
int ang;
|
|
Vector angles;
|
|
Vector forward;
|
|
Vector pos;
|
|
float ofs;
|
|
trace_t trace;
|
|
|
|
if ( other != driver )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( locked )
|
|
return;
|
|
|
|
//
|
|
// place the driver on the ground
|
|
//
|
|
driver->detach();
|
|
_AnimateDriver( "idle" );
|
|
_AnimateVehicle( "idle" );
|
|
driver->client->ps.in_vehicle = false;
|
|
ofs = size.length() * 0.5f;
|
|
for ( height = 0; height < 100; height += 16 )
|
|
{
|
|
for ( ang = 0; ang < 360; ang += 30 )
|
|
{
|
|
angles[ 1 ] = driver->angles[ 1 ] + ang + 90.0f;
|
|
angles.AngleVectors( &forward, NULL, NULL );
|
|
pos = origin + (forward * ofs);
|
|
pos[2] += height;
|
|
trace = G_Trace( pos, driver->mins, driver->maxs, pos, NULL, MASK_PLAYERSOLID, false, "Vehicle::DriverUse 1" );
|
|
if ( !trace.startsolid && !trace.allsolid )
|
|
{
|
|
Vector end;
|
|
|
|
end = pos;
|
|
end[ 2 ] -= 128.0f;
|
|
trace = G_Trace( pos, driver->mins, driver->maxs, end, NULL, MASK_PLAYERSOLID, false, "Vehicle::DriverUse 2" );
|
|
if ( trace.fraction < 1.0f )
|
|
{
|
|
driver->setOrigin( pos );
|
|
goto foundpos;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
|
|
foundpos:
|
|
|
|
turnimpulse = 0;
|
|
moveimpulse = 0;
|
|
jumpimpulse = 0;
|
|
|
|
event = new Event( EV_Vehicle_Exit );
|
|
event->AddEntity( this );
|
|
driver->ProcessEvent( event );
|
|
if ( hasweapon )
|
|
{
|
|
driver->takeItem( weaponName.c_str() );
|
|
}
|
|
if ( drivable )
|
|
{
|
|
StopLoopSound();
|
|
Sound( "snd_dooropen", CHAN_BODY );
|
|
Sound( "snd_stop", CHAN_VOICE );
|
|
driver->setSolidType( SOLID_BBOX );
|
|
}
|
|
|
|
driver = NULL;
|
|
}
|
|
else
|
|
{
|
|
driver = ( Sentient * )other;
|
|
|
|
lastdriver = driver;
|
|
|
|
|
|
if ( drivable )
|
|
setMoveType( MOVETYPE_VEHICLE );
|
|
|
|
if ( drivable )
|
|
{
|
|
Sound( "snd_doorclose", CHAN_BODY );
|
|
Sound( "snd_start", CHAN_VOICE );
|
|
driver->setSolidType( SOLID_NOT );
|
|
}
|
|
|
|
event = new Event( EV_Vehicle_Enter );
|
|
event->AddEntity( this );
|
|
if ( driveranim.length() )
|
|
event->AddString( driveranim );
|
|
driver->ProcessEvent( event );
|
|
|
|
offset = other->origin - origin;
|
|
|
|
flags |= FL_POSTTHINK;
|
|
SetDriverAngles( angles + seatangles );
|
|
|
|
int tagnum = gi.Tag_NumForName( this->edict->s.modelindex, "tag_rider" );
|
|
|
|
|
|
driver->attach(this->entnum , tagnum , false , seatoffset );
|
|
|
|
if ( driver->isSubclassOf( Player ) )
|
|
{
|
|
Player* player;
|
|
player = ( Player * )( Sentient * )driver;
|
|
player->v_angle = angles;
|
|
|
|
_lastYaw = player->client->cmd_angles[YAW];
|
|
_DriverBBoxMaxs = player->maxs;
|
|
_DriverBBoxMins = player->mins;
|
|
}
|
|
|
|
_driverYaw = angles[YAW];
|
|
_driverPitch = angles[PITCH];
|
|
|
|
_originalBBoxMaxs = _DriverBBoxMaxs;
|
|
_originalBBoxMins = _DriverBBoxMins;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: _PlayMovementSound()
|
|
//
|
|
// Description: Plays a sound based on movement
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::_PlayMovementSound()
|
|
{
|
|
str sound_name;
|
|
|
|
if ( currentspeed > 0.0f )
|
|
sound_name = "snd_forward";
|
|
else if ( currentspeed < 0.0f )
|
|
sound_name = "snd_backward";
|
|
else
|
|
sound_name = "snd_idle";
|
|
|
|
LoopSound( sound_name.c_str() );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: _AnimateVehicle()
|
|
//
|
|
// Description: Sets the animation on the vehicle
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::_AnimateVehicle(const str &anim , qboolean useEvent )
|
|
{
|
|
if ( animate )
|
|
{
|
|
int anim_num = gi.Anim_Random ( this->edict->s.modelindex, anim.c_str() );
|
|
if ( anim_num != -1 )
|
|
{
|
|
if ( animate->CurrentAnim() != anim_num )
|
|
{
|
|
animate->ClearLegsAnim();
|
|
animate->ClearTorsoAnim();
|
|
animate->NewAnim( anim_num );
|
|
|
|
if ( useEvent )
|
|
{
|
|
Event *ev = new Event( EV_Vehicle_AnimDone );
|
|
animate->SetAnimDoneEvent( ev );
|
|
_animDone = false;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: _AnimateDriver()
|
|
//
|
|
// Description: Sets the animation on the vehicle
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::_AnimateDriver(const str &anim , qboolean useEvent )
|
|
{
|
|
if ( !driver )
|
|
return;
|
|
|
|
Player *player;
|
|
player = ( Player * )( Sentient * )driver;
|
|
|
|
|
|
if ( player->animate )
|
|
{
|
|
int anim_num = gi.Anim_Random ( player->edict->s.modelindex, anim.c_str() );
|
|
if ( anim_num != -1 )
|
|
{
|
|
if ( player->animate->CurrentAnim() != anim_num )
|
|
{
|
|
player->animate->ClearLegsAnim();
|
|
player->animate->ClearTorsoAnim();
|
|
player->animate->NewAnim( anim_num );
|
|
|
|
if ( useEvent )
|
|
{
|
|
Event *ev = new Event( EV_Driver_AnimDone );
|
|
player->animate->SetAnimDoneEvent( ev );
|
|
_driverAnimDone = false;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: _PositionDriverModel()
|
|
//
|
|
// Description: Places the driver model in the correct position
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::_PositionDriverModel()
|
|
{
|
|
Vector i, j, k;
|
|
|
|
i = Vector( orientation[ 0 ] );
|
|
j = Vector( orientation[ 1 ] );
|
|
k = Vector( orientation[ 2 ] );
|
|
|
|
if ( driver )
|
|
{
|
|
Player *player;
|
|
player = ( Player * )( Sentient * )driver;
|
|
|
|
if ( drivable )
|
|
{
|
|
player->velocity = vec_zero;
|
|
player->setAngles( angles );
|
|
|
|
float delta;
|
|
delta = AngleDelta(_lastYaw , player->client->cmd_angles[YAW] );
|
|
|
|
|
|
_driverYaw += ( delta * -1.0f );
|
|
_lastYaw = player->client->cmd_angles[YAW];
|
|
_newCrosshairMode = CROSSHAIR_MODE_STRAIGHT;
|
|
|
|
if ( _driverYaw >= ( angles[YAW] + _maxYawThreshold ) )
|
|
{
|
|
_driverYaw = angles[YAW] + _maxYawThreshold;
|
|
_newCrosshairMode = CROSSHAIR_MODE_RIGHT;
|
|
|
|
}
|
|
|
|
if ( _driverYaw <= ( angles[YAW] - _minYawThreshold ) )
|
|
{
|
|
_driverYaw = angles[YAW] - _minYawThreshold;
|
|
_newCrosshairMode = CROSSHAIR_MODE_LEFT;
|
|
}
|
|
|
|
delta = AngleDelta(_lastPitch , player->client->cmd_angles[PITCH] );
|
|
|
|
_driverPitch += ( delta * -1.0f );
|
|
_lastPitch = player->client->cmd_angles[PITCH];
|
|
|
|
if ( _driverPitch > ( angles[PITCH] + _maxPitchThreshold ) )
|
|
_driverPitch = angles[PITCH] + _maxPitchThreshold;
|
|
|
|
if ( _driverPitch < ( angles[PITCH] - _minPitchThreshold ) )
|
|
_driverPitch = angles[PITCH] - _minPitchThreshold;
|
|
|
|
_SetCrossHairMode();
|
|
player->v_angle = player->client->cmd_angles;
|
|
player->v_angle[YAW] = _driverYaw;
|
|
player->v_angle[PITCH] = _driverPitch;
|
|
|
|
if ( !_duckflag )
|
|
player->SetAnim( "ride" , legs );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: _SetSpeed()
|
|
//
|
|
// Description: Specifies the speed that the vehicle will move
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::_SetSpeed ( Event *ev )
|
|
{
|
|
currentspeed = ev->GetFloat( 1 );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: SetVehicleMoveMode()
|
|
//
|
|
// Description: Script Interface to set the moveMode object
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::SetVehicleMoveMode( Event *ev )
|
|
{
|
|
str modeName = ev->GetString( 1 );
|
|
_SetMoveMode( modeName );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: SetForcedForwardSpeed()
|
|
//
|
|
// Description: Script interface for setting the
|
|
// _forcedForwardSpeed
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::SetForcedForwardSpeed( Event *ev )
|
|
{
|
|
_forcedForwardSpeed = ev->GetFloat( 1 );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: _HandleJump()
|
|
//
|
|
// Description: Takes care of jumping
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::_HandleJump()
|
|
{
|
|
|
|
if ( groundentity && _jumped && ( _jumpmode == JUMPMODE_DONE ) )
|
|
{
|
|
velocity[2] = 0;
|
|
_jumpflag = false;
|
|
_jumped = false;
|
|
_jumpSpeed = 0;
|
|
return;
|
|
|
|
}
|
|
|
|
switch ( _jumpmode )
|
|
{
|
|
case JUMPMODE_START:
|
|
flags |= FL_FLY;
|
|
_jumpSpeed += 100.0f;
|
|
if ( _jumpSpeed > 600.0f )
|
|
_jumpSpeed = 600.0f;
|
|
|
|
velocity[2] = _jumpSpeed;
|
|
_AnimateVehicle ( "jump_to_rise" , true );
|
|
|
|
if ( _animDone )
|
|
{
|
|
_jumpSpeed = 0;
|
|
_animDone = false;
|
|
_jumpmode = JUMPMODE_HOLD;
|
|
}
|
|
|
|
break;
|
|
|
|
case JUMPMODE_HOLD:
|
|
if ( level.time < _holdtime )
|
|
{
|
|
_jumpSpeed += 10.0f;
|
|
velocity[2] = _jumpSpeed;
|
|
_AnimateVehicle("rise" , true);
|
|
}
|
|
else
|
|
{
|
|
_jumpSpeed = 0;
|
|
_animDone = false;
|
|
_jumpmode = JUMPMODE_LAND;
|
|
}
|
|
|
|
break;
|
|
|
|
case JUMPMODE_LAND:
|
|
_jumpSpeed -= 100.0f;
|
|
if ( _jumpSpeed < -600.0f )
|
|
_jumpSpeed = -600.0f;
|
|
|
|
velocity[2] = _jumpSpeed;
|
|
_AnimateVehicle( "rise_to_land" , true );
|
|
|
|
if ( _animDone )
|
|
{
|
|
flags &= ~FL_FLY;
|
|
_jumpmode = JUMPMODE_DONE;
|
|
_AnimateVehicle( "run" );
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
//Should never get here, but you know... It's code.
|
|
break;
|
|
|
|
}
|
|
|
|
_jumped = true;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: _InitializeDuck()
|
|
//
|
|
// Description: Starts Jump
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
void HorseVehicle::_InitializeDuck()
|
|
{
|
|
if ( !driver )
|
|
return;
|
|
|
|
|
|
_duckflag = true;
|
|
_duckmode = DUCKMODE_START;
|
|
_driverAnimDone = false;
|
|
_ducked = true;
|
|
|
|
//Player *player;
|
|
//player = ( Player * )( Sentient * )driver;
|
|
|
|
_DriverBBoxMaxs[2] -= 64.0f;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: _HandleDuck()
|
|
//
|
|
// Description: Starts Jump
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
void HorseVehicle::_HandleDuck()
|
|
{
|
|
//Going to position torso Forward
|
|
//_driverYaw = 0;
|
|
//_lastYaw = 0;
|
|
|
|
//_driverPitch = 0;
|
|
//_lastPitch = 0;
|
|
|
|
if ( !driver )
|
|
return;
|
|
|
|
Player *player;
|
|
player = ( Player * )( Sentient * )driver;
|
|
player->v_angle = angles;
|
|
player->setAngles( angles );
|
|
|
|
_driverYaw = angles[YAW];
|
|
_lastYaw = player->client->cmd_angles[YAW];
|
|
|
|
Vector tempMins;
|
|
Vector tempMaxs;
|
|
|
|
switch ( _duckmode )
|
|
{
|
|
case DUCKMODE_START:
|
|
_AnimateDriver("ride_to_duck" , true );
|
|
|
|
if ( _driverAnimDone )
|
|
_duckmode = DUCKMODE_HOLD;
|
|
break;
|
|
|
|
case DUCKMODE_HOLD:
|
|
if ( _ducked )
|
|
_AnimateDriver("ride_duck_hold" , true );
|
|
else
|
|
_duckmode = DUCKMODE_FINISH;
|
|
break;
|
|
|
|
case DUCKMODE_FINISH:
|
|
_AnimateDriver("duck_to_ride" , true );
|
|
if ( _driverAnimDone )
|
|
_duckmode = DUCKMODE_DONE;
|
|
break;
|
|
|
|
case DUCKMODE_DONE:
|
|
_AnimateDriver( "ride" );
|
|
|
|
tempMaxs[2] +=64.0f;
|
|
|
|
player->setSize(_DriverBBoxMaxs, _DriverBBoxMaxs );
|
|
_DriverBBoxMaxs = _originalBBoxMaxs;
|
|
_DriverBBoxMins = _originalBBoxMins;
|
|
_duckflag = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: _InitializeJump()
|
|
//
|
|
// Description: Starts Jump
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::_InitializeJump()
|
|
{
|
|
_jumptime = level.time + .25f;
|
|
_holdtime = _jumptime + .15f;
|
|
|
|
_jumpflag = true;
|
|
_jumpmode = JUMPMODE_START;
|
|
_animDone = false;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
//
|
|
// Name: _SetMoveMode()
|
|
//
|
|
// Description: _moveMode Factory
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
void HorseVehicle::_SetMoveMode( const str &modeName )
|
|
{
|
|
if ( _moveMode )
|
|
{
|
|
delete _moveMode;
|
|
_moveMode = 0;
|
|
}
|
|
|
|
if ( !Q_stricmp(modeName.c_str() , "standard" ) )
|
|
_moveMode = new HVMoveMode_Standard;
|
|
|
|
else if ( !Q_stricmp(modeName.c_str() , "strafe" ) )
|
|
_moveMode = new HVMoveMode_Strafe;
|
|
|
|
else if ( !Q_stricmp(modeName.c_str() , "locked" ) )
|
|
_moveMode = new HVMoveMode_Locked;
|
|
|
|
else if ( !Q_stricmp(modeName.c_str() , "waypoint" ) )
|
|
_moveMode = new HVMoveMode_FollowPath;
|
|
}
|
|
|
|
void HorseVehicle::_SetCrossHairMode()
|
|
{
|
|
if ( _newCrosshairMode == _currentCrosshairMode )
|
|
return;
|
|
|
|
switch ( _newCrosshairMode )
|
|
{
|
|
case CROSSHAIR_MODE_STRAIGHT:
|
|
gi.cvar_set("cl_chright", "100" );
|
|
gi.cvar_set("cl_chleft" , "-100" );
|
|
_currentCrosshairMode = CROSSHAIR_MODE_STRAIGHT;
|
|
break;
|
|
|
|
case CROSSHAIR_MODE_LEFT:
|
|
gi.cvar_set("cl_chright", "310" );
|
|
gi.cvar_set("cl_chleft" , "-100" );
|
|
_currentCrosshairMode = CROSSHAIR_MODE_LEFT;
|
|
break;
|
|
|
|
case CROSSHAIR_MODE_RIGHT:
|
|
gi.cvar_set("cl_chright", "100" );
|
|
gi.cvar_set("cl_chleft" , "-310" );
|
|
_currentCrosshairMode = CROSSHAIR_MODE_RIGHT;
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
void HorseVehicle::AnimDone( Event *ev )
|
|
{
|
|
_animDone = true;
|
|
}
|
|
|
|
void HorseVehicle::DriverAnimDone( Event *ev )
|
|
{
|
|
_driverAnimDone = true;
|
|
}
|
|
|
|
void HorseVehicle::HandleEvent( Event *ev )
|
|
{
|
|
Event *new_event;
|
|
new_event = new Event( ev );
|
|
ProcessEvent(new_event);
|
|
}
|
|
|
|
void HorseVehicle::_SetBaseYaw()
|
|
{
|
|
if ( !driver )
|
|
return;
|
|
|
|
|
|
Player *player;
|
|
player = ( Player * )( Sentient * )driver;
|
|
_baseYaw = player->client->cmd_angles[YAW];
|
|
_lastYaw = _baseYaw;
|
|
|
|
}
|
|
|
|
//===============================================================================
|
|
//
|
|
// Vehicle Move Mode Classes:
|
|
// These classes act as movement handling strategies for vehicles. This way
|
|
// we can specify multiple different ways a single vehicle reacts, based on
|
|
// the context of the game.
|
|
//
|
|
//===============================================================================
|
|
CLASS_DECLARATION( Listener, VehicleMoveMode, "MoveModeBaseClass" )
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
VehicleMoveMode::VehicleMoveMode()
|
|
{
|
|
|
|
}
|
|
|
|
void VehicleMoveMode::Move( Vehicle *vehicle )
|
|
{
|
|
|
|
}
|
|
|
|
void VehicleMoveMode::HandleEvent( Event *ev )
|
|
{
|
|
|
|
}
|
|
|
|
//==============================================================================
|
|
//
|
|
// HVMoveMode_Standard
|
|
//
|
|
// Standard Move Strategy for the Horse Vehicle. This is the strategy that is
|
|
// instaniated by default
|
|
//
|
|
//===============================================================================
|
|
HVMoveMode_Standard::HVMoveMode_Standard()
|
|
{
|
|
|
|
}
|
|
|
|
void HVMoveMode_Standard::Move( Vehicle *base_vehicle )
|
|
{
|
|
HorseVehicle *vehicle;
|
|
vehicle = (HorseVehicle*)base_vehicle;
|
|
|
|
Vector flatvel;
|
|
|
|
//Zero Out our Velocity
|
|
vehicle->velocity = vec_zero;
|
|
|
|
if ( vehicle->moveimpulse > 0.0f )
|
|
{
|
|
if ( vehicle->currentspeed < 0.0f )
|
|
vehicle->currentspeed *= -1.0f;
|
|
|
|
flatvel = Vector( vehicle->orientation[ 0 ] );
|
|
vehicle->velocity += flatvel * vehicle->currentspeed;
|
|
}
|
|
|
|
if ( vehicle->moveimpulse < 0.0f )
|
|
{
|
|
if ( vehicle->currentspeed > 0.0f )
|
|
vehicle->currentspeed *= -1.0f;
|
|
|
|
flatvel = Vector( vehicle->orientation[ 0 ] );
|
|
vehicle->velocity += flatvel * vehicle->currentspeed;
|
|
}
|
|
|
|
if ( vehicle->turnimpulse > 0.0f )
|
|
{
|
|
if ( vehicle->currentspeed > 0.0f )
|
|
vehicle->currentspeed *= -1.0f;
|
|
|
|
flatvel = Vector( vehicle->orientation[ 1 ] );
|
|
vehicle->velocity += flatvel * vehicle->currentspeed;
|
|
}
|
|
|
|
if ( vehicle->turnimpulse < 0.0f )
|
|
{
|
|
if ( vehicle->currentspeed < 0.0f )
|
|
vehicle->currentspeed *= -1.0f;
|
|
|
|
flatvel = Vector( vehicle->orientation[ 1 ] );
|
|
vehicle->velocity += flatvel * vehicle->currentspeed;
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
//
|
|
// HVMoveMode_Strafe
|
|
//
|
|
// The only movement allowed by the horse is strafing left and right
|
|
//
|
|
//===============================================================================
|
|
HVMoveMode_Strafe::HVMoveMode_Strafe()
|
|
{
|
|
|
|
}
|
|
|
|
void HVMoveMode_Strafe::Move( Vehicle *base_vehicle )
|
|
{
|
|
HorseVehicle *vehicle;
|
|
vehicle = (HorseVehicle*)base_vehicle;
|
|
|
|
Vector flatvel;
|
|
|
|
//Zero Out our Velocity
|
|
vehicle->velocity = vec_zero;
|
|
|
|
if ( vehicle->turnimpulse > 0)
|
|
{
|
|
if ( vehicle->currentspeed > 0 )
|
|
vehicle->currentspeed*=-1;
|
|
|
|
flatvel = Vector( vehicle->orientation[ 1 ] );
|
|
vehicle->velocity += flatvel * vehicle->currentspeed;
|
|
}
|
|
|
|
if ( vehicle->turnimpulse < 0)
|
|
{
|
|
if ( vehicle->currentspeed < 0 )
|
|
vehicle->currentspeed*=-1;
|
|
|
|
flatvel = Vector( vehicle->orientation[ 1 ] );
|
|
vehicle->velocity += flatvel * vehicle->currentspeed;
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
//
|
|
// HVMoveMode_Locked
|
|
//
|
|
// A bit strange... Allows No Movement at all
|
|
//
|
|
//===============================================================================
|
|
HVMoveMode_Locked::HVMoveMode_Locked()
|
|
{
|
|
|
|
}
|
|
|
|
void HVMoveMode_Locked::Move( Vehicle *base_vehicle )
|
|
{
|
|
|
|
}
|
|
|
|
//==============================================================================
|
|
//
|
|
// HVMoveMode_FollowPath
|
|
//
|
|
// Makes the Vehicle Follow WayPointNodes -- There is currently NO collision
|
|
// avoidance here
|
|
//
|
|
//===============================================================================
|
|
Event EV_FollowPath_SetWayPointName
|
|
(
|
|
"waypointname",
|
|
EV_SCRIPTONLY,
|
|
"s",
|
|
"waypoint_target_name",
|
|
"Set the waypoint node name to go to first"
|
|
);
|
|
|
|
CLASS_DECLARATION( VehicleMoveMode, HVMoveMode_FollowPath, "FollowPath_MoveModeStrategy" )
|
|
{
|
|
{ &EV_FollowPath_SetWayPointName, &HVMoveMode_FollowPath::SetWaypointName },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
HVMoveMode_FollowPath::HVMoveMode_FollowPath()
|
|
{
|
|
_pathcompleted = false;
|
|
_currentWaypoint = NULL;
|
|
}
|
|
|
|
void HVMoveMode_FollowPath::Move( Vehicle *base_vehicle )
|
|
{
|
|
HorseVehicle *vehicle;
|
|
vehicle = (HorseVehicle*)base_vehicle;
|
|
|
|
|
|
//Zero Out our Velocity
|
|
vehicle->velocity = vec_zero;
|
|
if ( vehicle->currentspeed < 0.0f )
|
|
vehicle->currentspeed *= -1.0f;
|
|
|
|
//First Check if we are at a way point;
|
|
Vector dest;
|
|
Vector check;
|
|
|
|
if ( _pathcompleted )
|
|
return;
|
|
|
|
if (!_currentWaypoint)
|
|
{
|
|
_SetWayPoint( _currentWaypointName );
|
|
if (!_currentWaypoint)
|
|
return;
|
|
}
|
|
|
|
//Paranoia check, as it keeps crashing one particular box
|
|
if ( !_currentWaypoint )
|
|
return;
|
|
|
|
dest = _currentWaypoint->origin;
|
|
check = dest - vehicle->origin;
|
|
|
|
// Take care of Z - Differences
|
|
check[2] = 0;
|
|
|
|
// Check if we're close enough
|
|
if ( check.length() < 25.0f )
|
|
{
|
|
// Run Our Thread
|
|
str waypointThread;
|
|
waypointThread = _currentWaypoint->GetThread();
|
|
|
|
if (waypointThread.length() )
|
|
_RunThread( waypointThread );
|
|
|
|
// See if we have another point to go to
|
|
if ( _currentWaypoint->target.length() == 0 )
|
|
{
|
|
vehicle->velocity = vec_zero;
|
|
_currentWaypoint = NULL;
|
|
_pathcompleted = true;
|
|
return;
|
|
}
|
|
|
|
// Go To the Next Point
|
|
_currentWaypointName = _currentWaypoint->target;
|
|
_SetWayPoint( _currentWaypointName );
|
|
|
|
if (!_currentWaypoint)
|
|
return;
|
|
}
|
|
|
|
if ( _currentWaypoint )
|
|
{
|
|
vehicle->velocity = check;
|
|
vehicle->velocity.normalize();
|
|
vehicle->velocity *= vehicle->currentspeed;
|
|
}
|
|
}
|
|
|
|
void HVMoveMode_FollowPath::SetWaypointName( Event *ev )
|
|
{
|
|
_currentWaypointName = ev->GetString( 1 );
|
|
_pathcompleted = false;
|
|
}
|
|
|
|
void HVMoveMode_FollowPath::_SetWayPoint( const str& name )
|
|
{
|
|
Entity* ent_in_range;
|
|
gentity_t *ed;
|
|
|
|
for ( int i = 0; i < MAX_GENTITIES; i++ )
|
|
{
|
|
ed = &g_entities[i];
|
|
|
|
if ( !ed->inuse || !ed->entity )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
|
|
ent_in_range = g_entities[i].entity;
|
|
|
|
if( ent_in_range->isSubclassOf( WayPointNode ) )
|
|
{
|
|
if (!Q_stricmp(ent_in_range->targetname.c_str() , name.c_str() ))
|
|
{
|
|
_currentWaypoint = (WayPointNode*)ent_in_range;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
_currentWaypoint = NULL;
|
|
}
|
|
|
|
void HVMoveMode_FollowPath::_RunThread( const str &thread_name )
|
|
{
|
|
if ( thread_name.length() <= 0 )
|
|
return;
|
|
|
|
CThread *thread;
|
|
|
|
thread = Director.CreateThread( thread_name );
|
|
|
|
if ( thread )
|
|
thread->DelayedStart( 0.0f );
|
|
}
|
|
|
|
void HVMoveMode_FollowPath::HandleEvent( Event *ev )
|
|
{
|
|
Event *new_event;
|
|
new_event = new Event( ev );
|
|
ProcessEvent(new_event);
|
|
}
|