ef2gamesource/dlls/game/teleportToEntity.cpp

299 lines
7.8 KiB
C++

//-----------------------------------------------------------------------------
//
// $Logfile:: /EF2/Code/DLLs/game/teleportToEntity.cpp $
// $Revision:: 5 $
// $Author:: Singlis $
// $Date:: 9/26/03 2:36p $
//
// Copyright (C) 2002 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
//
// DESCRIPTION:
// TeleportToEntity Behavior Implementation.
// -- Currently, this is misnamed as a result of the transition to individual
// files for each behavior. Additionally, this behavior needs much refactoring
// to make it more generalized and flexible
//
// -- What it does RIGHT NOW
// The Behavior grabs the player's position, offsets it ( Preferring to go behind )
// It checks if this new position will hold the actor. If that is true, then
// it plays the "start" animation. When that animation is completed, it rechecks
// the spot -- If it's still good, then it sets the actor's origin to that spot
// and plays the "end" animation
//
// ANIMATIONS:
// Start Animation : Parameter
// End Animation : Parameter
//--------------------------------------------------------------------------------
#include "actor.h"
#include "player.h"
#include "teleportToEntity.hpp"
//--------------------------------------------------------------
//
// Class Declaration and Event Registration
//
//--------------------------------------------------------------
CLASS_DECLARATION( Behavior, AnimatedTeleportToPlayer, NULL )
{
{ &EV_Behavior_Args, &AnimatedTeleportToPlayer::SetArgs },
{ NULL, NULL }
};
//--------------------------------------------------------------
// Name: SetArgs()
// Class: AnimatedTeleportToPlayer
//
// Description: Sets Variables based on arguments inside the event
//
// Parameters: Event *ev
//
// Returns: None
//--------------------------------------------------------------
void AnimatedTeleportToPlayer::SetArgs( Event *ev )
{
_startAnim = ev->GetString( 1 );
_endAnim = ev->GetString( 2 );
}
//--------------------------------------------------------------
// Name: Begin()
// Class: AnimatedTeleportToPlayer
//
// Description: Initializes the behavior
//
// Parameters: Actor &self
//
// Returns: None
//--------------------------------------------------------------
void AnimatedTeleportToPlayer::Begin( Actor & )
{
_state = ANIM_TELEPORT_BEGIN;
}
//--------------------------------------------------------------
// Name: Evaluate()
// Class: AnimatedTeleportToPlayer
//
// Description: Update for this behavior -- called every server frame
//
// Parameters: Actor &self
//
// Returns: None
//--------------------------------------------------------------
BehaviorReturnCode_t AnimatedTeleportToPlayer::Evaluate ( Actor &self )
{
int current_position;
qboolean teleport_position_found;
Vector new_position;
int i;
Vector dir;
Vector angles;
Player *player = NULL;
Player *temp_player = NULL;
// Make sure the player is alive and well
for(i = 0; i < game.maxclients; i++)
{
player = GetPlayer(i);
// don't target while player is not in the game or he's in notarget
if ( temp_player && !( temp_player->flags & FL_NOTARGET ) )
{
player = temp_player;
break;
}
}
if ( !player )
return BEHAVIOR_SUCCESS;
switch ( _state )
{
case ANIM_TELEPORT_BEGIN:
// Default the teleport position to where we are now
_teleportPosition = self.origin;
teleport_position_found = false;
// Always teleport BEHIND the player - - we don't want him to see us pop in.
current_position = TELEPORT_BEHIND;
// Test this position
if ( testPosition( self, current_position, new_position, player, true ) )
{
_teleportPosition = new_position;
teleport_position_found = true;
}
else
{
if ( testPosition( self, current_position, new_position, player, false ) )
{
_teleportPosition = new_position;
teleport_position_found = true;
}
}
if ( !teleport_position_found )
return BEHAVIOR_FAILED;
_state = ANIM_TELEPORT_START_ANIM;
break;
case ANIM_TELEPORT_START_ANIM:
self.SetAnim( _startAnim , EV_Anim_Done , legs );
_state = ANIM_TELEPORT_START_ANIMATING;
break;
case ANIM_TELEPORT_START_ANIMATING:
if ( self.GetActorFlag( ACTOR_FLAG_ANIM_DONE ) )
_state = ANIM_TELEPORT_TELEPORT;
break;
case ANIM_TELEPORT_TELEPORT:
_teleportPosition = self.origin;
teleport_position_found = false;
// Always teleport BEHIND the player - - we don't want him to see us pop in.
current_position = TELEPORT_BEHIND;
// Test this position
if ( testPosition( self, current_position, new_position, player, true ) )
{
_teleportPosition = new_position;
teleport_position_found = true;
}
else
{
if ( testPosition( self, current_position, new_position, player, false ) )
{
_teleportPosition = new_position;
teleport_position_found = true;
}
}
if ( !teleport_position_found )
{
_state = ANIM_TELEPORT_END_ANIM;
break;
}
self.setOrigin( _teleportPosition );
self.NoLerpThisFrame();
dir = player->origin - _teleportPosition;
angles = dir.toAngles();
angles[ROLL] = 0.0f;
angles[PITCH] = 0.0f;
self.setAngles( angles );
_state = ANIM_TELEPORT_END_ANIM;
break;
case ANIM_TELEPORT_END_ANIM:
self.SetAnim( _endAnim , EV_Anim_Done , legs );
_state = ANIM_TELEPORT_END_ANIMATING;
break;
case ANIM_TELEPORT_END_ANIMATING:
if ( self.GetActorFlag( ACTOR_FLAG_ANIM_DONE ) )
return BEHAVIOR_SUCCESS;
break;
}
return BEHAVIOR_EVALUATING;
}
//--------------------------------------------------------------
// Name: End()
// Class: AnimatedTeleportToPlayer
//
// Description: Ends this behavior -- cleans things up
//
// Parameters: Actor &self
//
// Returns: None
//--------------------------------------------------------------
void AnimatedTeleportToPlayer::End( Actor & )
{
}
//--------------------------------------------------------------
// Name: testPosition()
// Class: AnimatedTeleportToPlayer
//
// Description: Tests if the given position is valid for teleporting into
//
// Parameters: Actor &self
// int test_pos
// Vector &good_position
// Entity *player,
// bool use_player_dir
//
// Returns: true or false
//--------------------------------------------------------------
bool AnimatedTeleportToPlayer::testPosition( Actor &self, int test_pos, Vector &good_position, Entity* player, bool use_player_dir )
{
Vector test_position;
Vector player_angles;
Vector player_forward;
Vector player_left;
trace_t trace;
Q_UNUSED(test_pos);
// Get the position to test
test_position = player->origin;
if ( use_player_dir )
{
// Get the player direction info
player_angles = player->angles;
player_angles.AngleVectors( &player_forward, &player_left );
// Check Behind the Player
test_position -= player_forward * 128.0f;
}
else
{
// Check Behind the Player
test_position += Vector(-128, 0, 0);
}
// Final Tweaking
test_position += Vector(0, 0, 64);
// Test to see if we can fit at the new position
trace = G_Trace( test_position, self.mins, self.maxs, test_position - Vector( "0 0 250" ), &self, self.edict->clipmask, false, "Teleport::TestPosition" );
if ( trace.allsolid || trace.startsolid )
return false;
if ( trace.fraction == 1.0 )
return false;
// Make sure we can see the Player from this position
/*if ( !self.IsEntityAlive( player ) || !self.sensoryPerception->CanSeeEntity( Vector( trace.endpos ), player , true , true ) )
return false;*/
// This is a good position
good_position = trace.endpos;
return true;
}