//----------------------------------------------------------------------------- // // $Logfile:: /EF2/Code/DLLs/game/doAttack.cpp $ // $Revision:: 11 $ // $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: // DoAttack Behavior Implementation // -- DoAttack will rotate the actor to face his current enemy, after the // the rotation( with optional animation ) has completed, it will check // if the actor is able to hit its current enemy with an attack. If that // check is successful, then it will play its specified attack animation. // // Currently, you must put the attack commands inside the animation. // // ANIMATIONS: // Attack Animation : Parameter // Rotation Animation : Optional //-------------------------------------------------------------------------------- #include "actor.h" #include "doAttack.hpp" #include //-------------------------------------------------------------- // // Class Declaration and Event Registration // //-------------------------------------------------------------- CLASS_DECLARATION( Behavior, DoAttack, NULL ) { { &EV_Behavior_Args, &DoAttack::SetArgs }, { &EV_Behavior_AnimDone, &DoAttack::AnimDone }, { NULL, NULL } }; //-------------------------------------------------------------- // // Name: SetArgs() // Class: DoAttack // // Description: // // Parameters: Event *ev -- Event containing the string // // Returns: None // //-------------------------------------------------------------- void DoAttack::SetArgs( Event *ev ) { _anim = ev->GetString( 1 ); if ( ev->NumArgs() > 1 ) _turnspeed = ev->GetFloat( 2 ); else _turnspeed = 30.0f; if ( ev->NumArgs() > 2 ) _forceAttack = ev->GetBoolean( 3 ); else _forceAttack = false; if ( ev->NumArgs() > 3 ) _rotateAnim = ev->GetString( 4 ); else _rotateAnim = ""; } //-------------------------------------------------------------- // Name: AnimDone() // Class: DoAttack // // Description: AnimDone Event Handler // // Parameters: Event *ev -- The AnimDone event // // Returns: None //-------------------------------------------------------------- void DoAttack::AnimDone( Event *ev ) { _state = ATTACK_STATE_COMPLETE; } //-------------------------------------------------------------- // // Name: Begin() // Class: DoAttack // // Description: Initializes the behavior // // Parameters: Actor &self -- The actor executing this behavior // // Returns: None // //-------------------------------------------------------------- void DoAttack::Begin( Actor &self ) { init ( self ); _setupRotate( self ); _state = ATTACK_STATE_ROTATE; } //-------------------------------------------------------------- // // Name: Evaluate() // Class: DoAttack // // Description: Update for this behavior -- called every server frame // // Parameters: Actor &self -- Actor executing this behavior // // Returns: BehaviorReturnCode_t // //-------------------------------------------------------------- BehaviorReturnCode_t DoAttack::Evaluate( Actor &self ) { if ( _state != ATTACK_STATE_ANIMATING ) _rotate( self ); if ( _state == ATTACK_STATE_START_ANIM ) { _playAttackAnim( self ); _state = ATTACK_STATE_ANIMATING; } if ( _state == ATTACK_STATE_FAILED ) return BEHAVIOR_FAILED; if ( _state == ATTACK_STATE_COMPLETE ) return BEHAVIOR_SUCCESS; return BEHAVIOR_EVALUATING; } //-------------------------------------------------------------- // // Name: End() // Class: DoAttack // // Description: Ends this behavior -- cleans things up // // Parameters: Actor &self -- Actor executing this behavior // // Returns: None // //-------------------------------------------------------------- void DoAttack::End(Actor &self) { _rotateBehavior.End(self); } //-------------------------------------------------------------- // Name: _setupRotate() // Class: DoAttack // // Description: Sets up the Rotate Component Behavior // // Parameters: Actor &self -- Actor executing this behavior // // Returns: None //-------------------------------------------------------------- void DoAttack::_setupRotate( Actor &self ) { Entity *currentEnemy; currentEnemy = self.enemyManager->GetCurrentEnemy(); if ( currentEnemy ) { _rotateBehavior.SetEntity( currentEnemy ); _rotateBehavior.SetTurnSpeed( _turnspeed ); if ( _rotateAnim.length() ) _rotateBehavior.SetAnim( _rotateAnim ); _rotateBehavior.Begin( self ); } } //-------------------------------------------------------------- // Name: _rotate() // Class: DoAttack // // Description: Evaluates the Rotate Component Behavior // // Parameters: Actor &self -- Actor executing this behavior // // Returns: None //-------------------------------------------------------------- void DoAttack::_rotate( Actor &self ) { BehaviorReturnCode_t result; result = _rotateBehavior.Evaluate( self ); // If we get a failure from rotate, chances are it didn't have // an entity to rotate to... Let's give it one more shot. if ( result == BEHAVIOR_FAILED ) { _setupRotate( self ); result = _rotateBehavior.Evaluate( self ); // If we have a failure again, then we DO have a serious // problem if ( result == BEHAVIOR_FAILED ) { str failureReason; failureReason = "Rotate Component Failed: Returned -- "; failureReason += _rotateBehavior.GetFailureReason(); SetFailureReason( failureReason ); _state = ATTACK_STATE_FAILED; } } if ( result == BEHAVIOR_SUCCESS ) { if ( _canAttack( self ) ) { if ( _state != ATTACK_STATE_ANIMATING && _state != ATTACK_STATE_COMPLETE ) { _state = ATTACK_STATE_START_ANIM; return; } } else _state = ATTACK_STATE_FAILED; } } //-------------------------------------------------------------- // Name: _playAttackAnim() // Class: DoAttack // // Description: Plays the specified attack animation // // Parameters: Actor &self -- Actor executing this behavior // // Returns: None //-------------------------------------------------------------- void DoAttack::_playAttackAnim( Actor &self ) { self.ClearTorsoAnim(); self.SetAnim( _anim , EV_Actor_NotifyBehavior); _state = ATTACK_STATE_ANIMATING; } //-------------------------------------------------------------- // Name: _canAttack() // Class: DoAttack // // Description: Checks if the actor can attack // // Parameters: Actor &self -- Actor executing this behavior // // Returns: None //-------------------------------------------------------------- bool DoAttack::_canAttack( Actor &self ) { Entity *currentEnemy; currentEnemy = self.enemyManager->GetCurrentEnemy(); if ( _forceAttack ) return true; if ( !currentEnemy) return false; if ( self.combatSubsystem->CanAttackTarget( currentEnemy ) ) return true; else return false; } void DoAttack::init( Actor &self ) { GameplayManager *gpm = GameplayManager::getTheGameplayManager(); if ( !gpm->hasObject(self.getArchetype()) ) return; if ( !self.combatSubsystem->HaveWeapon() ) return; str objname = self.combatSubsystem->GetActiveWeaponArchetype(); objname = "Hold" + objname; if ( gpm->hasProperty(objname, "Melee") ) _anim = gpm->getStringValue( objname , "Melee" ); else { str weaponName = self.combatSubsystem->GetActiveWeaponName(); if ( !weaponName.length() ) { weaponName = "UNSPECIFIED"; } gi.WDPrintf( "\n\n\nDoAttack: TargetName %s ( Entnum %i ) has a weapon, but does not have a MeleeProperty ( Trying Weapon: %s ) in the GPD, Please notify a programmer of this error\n\n\n" , self.TargetName() , self.entnum, weaponName.c_str() ); //gi.Error( ERR_DROP , "\n\n\nDoAttack: TargetName %s ( Entnum %i ) has a weapon, but does not have a MeleeProperty ( Trying Weapon: %s ) in the GPD, Please notify a programmer of this error\n\n\n" , self.TargetName() , self.entnum, weaponName.c_str() ); } }