Package de.christopherstock.shooter.game.objects

Source Code of de.christopherstock.shooter.game.objects.Bot$BotUseAction

/*  $Id: Bot.java 1296 2014-10-12 20:14:13Z jenetic.bytemare $
*  =======================================================================================
*/
    package de.christopherstock.shooter.game.objects;

    import  java.awt.geom.*;
    import  java.util.*;
    import  de.christopherstock.lib.g3d.*;
    import  de.christopherstock.lib.g3d.face.*;
    import  de.christopherstock.lib.game.*;
    import  de.christopherstock.lib.game.LibShot.*;
    import  de.christopherstock.lib.math.*;
    import  de.christopherstock.lib.ui.*;
    import  de.christopherstock.shooter.*;
    import  de.christopherstock.shooter.ShooterSettings.BotSettings;
    import  de.christopherstock.shooter.ShooterSettings.FxSettings;
    import  de.christopherstock.shooter.ShooterSettings.General;
    import  de.christopherstock.shooter.ShooterSettings.PlayerSettings;
    import  de.christopherstock.shooter.base.ShooterD3ds.*;
    import  de.christopherstock.shooter.g3d.*;
    import  de.christopherstock.shooter.g3d.mesh.*;
    import  de.christopherstock.shooter.g3d.mesh.BotMeshes.*;
import de.christopherstock.shooter.game.artefact.Artefact;
import de.christopherstock.shooter.game.artefact.ArtefactSet;
import de.christopherstock.shooter.game.artefact.ArtefactType;
import de.christopherstock.shooter.game.artefact.firearm.*;
import de.christopherstock.shooter.game.artefact.gadget.Gadget;
    import  de.christopherstock.shooter.game.bot.*;
    import  de.christopherstock.shooter.io.sound.*;
import  de.christopherstock.shooter.level.*;

    /**************************************************************************************
    *   The superclass of all non-player-characters.
    *
    *   @author     Christopher Stock
    *   @version    0.3.11
    **************************************************************************************/
    public class Bot implements LibGameObject, ShotSpender
    {
        public enum BotAliveState
        {
            EAlive,
            ETranquilized,
            EDead,
            ;
        }

        public enum BotBodyType
        {
            EMaleNormal,
            EFemaleNormal,
            ;
        }

        public enum BotType
        {
            ETypeEnemy,
            ETypeFriend,
            ;
        }

        public enum BotHanded
        {
            ELeftHanded,
            ERightHanded,
            //EBothHanded,
            ;
        }

        public enum BotSkinType
        {
            ERose,
            ELightBrown,
            EBrown,
            EBlack,
            EYellow,
            ;

            public  static  final   BotSkinType[]   SET_GLOBAL          = BotSkinType.values();
            public  static  final   BotSkinType[]   SET_NORTH_EUROPEAN  = new BotSkinType[] { ERose,        ELightBrown,    };
            public  static  final   BotSkinType[]   SET_SOUTH_EUROPEAN  = new BotSkinType[] { ELightBrown,  EBrown,         };
            public  static  final   BotSkinType[]   SET_NORTH_AFRICAN   = new BotSkinType[] { EBrown,       EBlack,         };
            public  static  final   BotSkinType[]   SET_SOUTH_AFRICAN   = new BotSkinType[] { EBlack,                       };
            public  static  final   BotSkinType[]   SET_ASIAN           = new BotSkinType[] { EYellow,                      };
        }

        public enum BotJob
        {
            ELeadPlayerToLastWaypoint,
            EWalkWaypoints,
            EWatchPlayer,
            EStandStill,
            EDying,
            EAttackPlayerFire,
            EAttackPlayerReload,

            //sequenced jobs require a non-sequenced job at the end!
            ESequenceDelay,
            ESequenceTurnToPlayer,
            ESequenceNodOnce,
            ESequenceNodTwice,
            ESequenceGrabSpringRight,
            ESequenceFlushRightEquippedItem,
            ESequenceDeliverRightEquippedItem,
            ESequenceGrabBackDownRight,
            ESequenceGrabSpringLeft,
            ESequenceFlushLeftEquippedItem,
            ESequenceDeliverLeftEquippedItem,
            ESequenceGrabBackDownLeft,
            ESequenceReloadHandUp,
            ESequenceReloadHandDown,
            ;
        }

        public enum BotState
        {
            EDying,
            EWalkTowardsPlayer,
            EWatchPlayer,
            EStandStill,
            EWalkToNextWayPoint,
            ;
        }

        public enum BotHealth
        {
            ECivilian(          30  ),
            ESecurity(          100 ),
            EPrivateSoldier(    150 ),
            ;

            public      int     iEnergy     = 0;

            private BotHealth( int aEnergy )
            {
                iEnergy = aEnergy;
            }
        }

        public enum DyingDirection
        {
            EFront,
            EBack,
            ;
        }

        public static interface BotAction
        {
        }

        public static final class BotUseAction implements BotAction
        {
            public          BotEvent        iEvent        = null;

            public BotUseAction( BotEvent aEvent )
            {
                iEvent = aEvent;
            }
        }

        public static final class BotGiveAction implements BotAction
        {
            public          ArtefactType        iKey        = null;
            public          BotEvent            iEvent      = null;

            public BotGiveAction( ArtefactType aKey, BotEvent aEvent )
            {
                iKey = aKey;
                iEvent = aEvent;
            }
        }

        public                      BotMeshes           iBotMeshes                  = null;

        public                      AmmoSet             iAmmoSet                    = null;

        public                      ArtefactSet         iArtefactSet                = null;


        /** current facing angle ( z axis ). */
        private                     float               iFacingAngle                = 0.0f;

        /** current drop dead angle ( x axis ). */
        private                     boolean             iFaceAngleChanged           = false;

        private                     Vector<BotJob>      iJobs                       = null;

        private                     BotType             iType                       = null;
        private                     BotState            iState                      = null;
        private                     Point2D.Float[]     iWayPoints                  = null;
        private                     int                 iCurrentWayPointIndex       = 0;
        private                     int                 iHealth                     = 0;

        private                     float               iTargetOffsetZ              = 0.0f;
        private                     float               iOffsetZ                    = 0.0f;

        private                     BotAliveState       iAliveState                 = null;

        private                     DyingDirection      iDyingDirection             = null;
        private                     float               iDyingAngle                 = 0.0f;
        public                      long                iDisappearTimer             = 0;

        /** the collision unit for simple collisions */
        private                     Cylinder            iCylinder                   = null;

        private                     long                iNextEyeChange              = 0;
        private                     boolean             iEyesOpen                   = true;

        private                     BotPattern   iTemplate                   = null;
        private                     LibVertex           iStartPosition              = null;
        private                     BotAction[]         iActions                    = null;
        public                      int                 iID                         = 0;

        private                     int                 iInterAnimationsDelay       = 0;
        private                     BotHanded           iHanded                     = null;

        public                      Items               iNextItemToDeliverLeftHand  = null;
        public                      Items               iNextItemToDeliverRightHand = null;

        public Bot( BotPattern aTemplate, BotType aType, LibVertex aStartPosition, Point2D.Float[] aWayPoints, BotJob aJob, Artefact[] aArtefacts, float aFacingAngle, BotAction[] aActions, BotHealth aBotHealth, int aID, BotHanded aBotHanded )
        {
            iType           = aType;
            iStartPosition  = aStartPosition.copy();
            iCylinder       = new Cylinder( this, iStartPosition, aTemplate.iBase.iRadius, aTemplate.iBase.iHeight, 0, ShooterDebug.bot, ShooterDebug.DEBUG_DRAW_BOT_CIRCLES, 0.0f, 0.0f, ShooterSettings.Performance.ELLIPSE_SEGMENTS, Material.EHumanFlesh );
            iWayPoints      = aWayPoints;
            iJobs           = new Vector<BotJob>();
            iJobs.add(      aJob );
            iHealth         = aBotHealth.iEnergy;
            iTemplate       = aTemplate;
            iActions        = aActions;
            iID             = aID;
            iHanded         = aBotHanded;
            iAliveState     = BotAliveState.EAlive;

            //set startup facing angle
            iFacingAngle    = aFacingAngle;

            iAmmoSet        = new AmmoSet();
            iArtefactSet    = new ArtefactSet();

            //deliver all artefacts if given
            if ( aArtefacts != null )
            {
                for ( Artefact a : aArtefacts )
                {
                    iArtefactSet.deliverArtefact( a );
                }

                iArtefactSet.chooseNextWearponOrGadget( false );
                iArtefactSet.iCurrentArtefact.reload( iAmmoSet, false, false, null );
            }

            Items leftItem  = null;
            Items rightItem = null;

            switch ( iHanded )
            {
                case ELeftHanded:
                {
                    leftItem = iArtefactSet.iCurrentArtefact.iArtefactType.iItemMesh;
                    break;
                }

                case ERightHanded:
                {
                    rightItem = iArtefactSet.iCurrentArtefact.iArtefactType.iItemMesh;
                    break;
                }
            }

            //init mesh-collection
            iBotMeshes      = new BotMeshes( iTemplate, iStartPosition, this, leftItem, rightItem );

            //set next eye blink
            iEyesOpen       = true;
            setNextEyeChange();

            //animate 1st tick? .. triggers onRun :/ not required!
            boolean deprecatedAnimateOnCreate = false;
            if ( deprecatedAnimateOnCreate ) animate();
        }

        private final void setNextEyeChange()
        {
            //only if not dead
            if ( iAliveState == BotAliveState.EAlive )
            {
                iNextEyeChange =
                (
                        System.currentTimeMillis()
                    +   (
                                iEyesOpen
                            ?   LibMath.getRandom( BotSettings.EYE_BLINK_INTERVAL_MIN, BotSettings.EYE_BLINK_INTERVAL_MAX )
                            :   BotSettings.EYE_CLOSED_INTERVAL
                        )
                );
            }
        }

        public final boolean checkCollision( Cylinder aCylinder )
        {
            return ( iAliveState == BotAliveState.EAlive ? iCylinder.checkCollisionHorz( aCylinder ) : false );
        }

        @Override
        public final void launchAction( LibCylinder aCylinder, Object artefact, float faceAngle )
        {
            //only if alive
            if ( iAliveState == BotAliveState.EAlive )
            {
                //check if collision appears
                if ( iCylinder.checkCollisionHorz( aCylinder ) )
                {
                    float anglePlayerToWall = LibMath.getAngleCorrect( Level.currentPlayer().getCylinder().getCenterHorz(), iCylinder.getCenterHorz() );
                    anglePlayerToWall = LibMath.normalizeAngle( -anglePlayerToWall );
                    float angleDistance     = LibMath.getAngleDistanceAbsolute( faceAngle, anglePlayerToWall );

                    //ShooterDebug.bugfix.out( "faceAngle [" + ( faceAngle ) + "] wall [" + anglePlayerToWall + "] " );
                    //ShooterDebug.bugfix.out( " delta [" + angleDistance + "]" );

                    //clip angle distance
                    if ( angleDistance < PlayerSettings.MAX_ACTION_VIEW_ANGLE )
                    {
                        if ( artefact == null )
                        {
                            ShooterDebug.playerAction.out( "launch action on bot" );

                            //LAUNCH all USE-actions
                            if ( iActions != null )
                            {
                                for ( BotAction action : iActions )
                                {
                                    if ( action instanceof BotUseAction )
                                    {
                                        BotUseAction ga = (BotUseAction)action;
                                        ga.iEvent.perform( this );
                                    }
                                }
                            }
                        }
                        else
                        {
                            ShooterDebug.playerAction.out( "launch gadget-action on bot" );

                            //CHECK all GIVE-actions
                            if ( iActions != null )
                            {
                                for ( BotAction action : iActions )
                                {
                                    if ( action instanceof BotGiveAction )
                                    {
                                        BotGiveAction ga = (BotGiveAction)action;

                                        //LAUNCH if KEY matches
                                        if ( ga.iKey == ( (Gadget)artefact ).iParentKind )
                                        {
                                            ga.iEvent.perform( this );
                                            Level.currentPlayer().iArtefactSet.extractArtefact( artefact );
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        protected final boolean checkCollision( Ellipse2D.Float aEllipse )
        {
            return ( iAliveState == BotAliveState.EAlive ? iCylinder.checkCollision( aEllipse ) : false );
        }

        public final Point2D.Float getCenterHorz()
        {
            return iCylinder.getCenterHorz();
        }

        protected final void drawDebugCircles()
        {
            if ( ShooterDebug.DEBUG_DRAW_BOT_CIRCLES )
            {
                //Debug.bot.out( "drawing bot .." );
                int VERTICAL_SLICES = 4;
                LibVertex ank = getAnchor();
                LibColors col = null;
                switch ( iType )
                {
                    case ETypeFriend:   col = LibColors.EBlueLight;    break;
                    case ETypeEnemy:    col = LibColors.EBlueDark;      break;
                }
                for ( int i = 0; i <= VERTICAL_SLICES; ++i )
                {
                    new LibFaceEllipseFloor( ShooterDebug.face, null, col, ank.x, ank.y, ank.z + ( i * iCylinder.getHeight() / VERTICAL_SLICES ), iCylinder.getRadius(), iCylinder.getRadius(), ShooterSettings.Performance.ELLIPSE_SEGMENTS ).draw();
                }
            }
        }

        protected final float getHeight()
        {
            return iCylinder.getHeight();
        }

        protected final void setCenterHorz( float newX, float newY )
        {
            iCylinder.setNewAnchor( new LibVertex( newX, newY, iCylinder.getAnchor().z ), false, null );
        }

        public final Cylinder getCylinder()
        {
            return iCylinder;
        }

        protected final boolean checkCollisionsToOtherBots()
        {
            for ( Bot bot : Level.currentSection().getBots() )
            {
                //skip own !
                if ( this == bot ) continue;

                //check bot-collision with other bot
                if ( bot.checkCollision( iCylinder ) )
                {
                    ShooterDebug.bot.out( "own bot touched" );
                    return true;

                    //sleep if being touched
                    //bot.state = BotState.EStateSleeping;
                }
            }

            return false;
        }

        protected final boolean checkCollisionsToPlayer()
        {
            //check bot-collision with player
            if ( checkCollision( Level.currentPlayer().getCylinder().getCircle() ) )
            {
                ShooterDebug.bot.out( "player touched" );
                return true;

                //sleep if being touched
                //bot.state = BotState.EStateSleeping;
            }

            return false;
        }

        public final void animate()
        {
            boolean playerMoved         = false;

            switch ( iType )
            {
                case ETypeEnemy:
                case ETypeFriend:
                {

                    //Debug.bot.out( "angle player to bot is: " + anglePlayerToBot );
                    //Debug.bot.out( "angle bot to player is: " + angleBotToPlayer );

                    Point2D.Float bot = getCenterHorz();

                    float   nextPosX            = 0.0f;
                    float   nextPosY            = 0.0f;
                            iFaceAngleChanged   = false;

                    //check the bot's current job
                    switch ( iJobs.elementAt( 0 ) )
                    {
                        case ELeadPlayerToLastWaypoint:
                        {
                            //calculate bot's angle and distance to the player
                            Point2D.Float   player           = Level.currentPlayer().getCylinder().getCenterHorz();

                            //check distance from player to next waypoint and from bot to next waypoint
                            float   distancePlayerToNextWaypoint = (float)player.distance( iWayPoints[ iCurrentWayPointIndex ] );
                            float   distanceBotToNextWaypoint    = (float)bot.distance(    iWayPoints[ iCurrentWayPointIndex ] );
                            boolean playerOutOfBotReach          = ( (float)player.distance( bot ) > ShooterSettings.BotSettings.MAX_LEADING_DISTANCE_TO_PLAYER );

                            //wait for player if he is out of reach and farer from the next waypoint than the bot
                            if ( playerOutOfBotReach && distancePlayerToNextWaypoint > distanceBotToNextWaypoint )
                            {
                                //wait for player
                                iState = BotState.EWatchPlayer;
                            }
                            else
                            {
                                //walk to next waypoint
                                iState = BotState.EWalkToNextWayPoint;
                            }
                            break;
                        }

                        case EWalkWaypoints:
                        {
                            iState = BotState.EWalkToNextWayPoint;
                            break;
                        }

                        case EWatchPlayer:
                        {
                            iState = BotState.EWatchPlayer;
                            break;
                        }

                        case EStandStill:
                        {
                            iState = BotState.EStandStill;
                            break;
                        }

                        case EDying:
                        {
                            iState = BotState.EDying;
                            break;
                        }

                        case EAttackPlayerReload:
                        {
                            iState = BotState.EStandStill;

//                            iArtefactSet.iCurrentArtefact.reload( iAmmoSet, false, true, iCylinder.getCenterHorz() );
                            iArtefactSet.iCurrentArtefact.performReload( iAmmoSet, true, iCylinder.getCenterHorz(), true );

                            //init reload action
                            setNewJobQueue
                            (
                                new BotJob[]
                                {
                                    BotJob.ESequenceDelay,
                                    BotJob.ESequenceDelay,
                                    BotJob.ESequenceDelay,
                                    BotJob.EAttackPlayerFire,
                                }
                            );

                            break;
                        }

                        case EAttackPlayerFire:
                        {
                            iState = BotState.EWatchPlayer;

                            //check if bot's wearpon is delayed
                            if ( iArtefactSet.isWearponDelayed() )
                            {
                                //do nothing if the wearpon is delayed

                            }
                            //check if bot's wearpon is empty
                            else if ( iArtefactSet.isMagazineEmpty() )
                            {
                                //perform reload animation
                                setNewJobQueue
                                (
                                    new BotJob[]
                                    {
                                        BotJob.ESequenceReloadHandUp,
                                        BotJob.ESequenceDelay,
                                        BotJob.ESequenceReloadHandDown,
                                        BotJob.ESequenceDelay,
                                        BotJob.EAttackPlayerReload,
                                    }
                                );
                            }
                            else
                            {
                                //check if bot sees the player now
                                Point2D.Float   player           = Level.currentPlayer().getCylinder().getCenterHorz();
                                float           anglePlayerToBot = LibMath.getAngleCorrect( player, bot );
                                float           angleBotToPlayer = LibMath.normalizeAngle( anglePlayerToBot - 180.0f ); //checked normalizing - also works wothout :)

                                //ShooterDebug.bugfix.out( "angle [" + angleBotToPlayer + "] facing: " + iFacingAngle );
                                //ShooterDebug.bugfix.out( "attacking bot holds " + iArtefactSet.iCurrentArtefact.iArtefactType );

                                //check if bot looks into player's direction
                                if ( Math.abs( angleBotToPlayer - iFacingAngle ) <= BotSettings.TARGET_TURNING_TOLERANCE )
                                {
                                    if ( iBotMeshes.isAssignedArmsPosition( ( iHanded == BotHanded.ELeftHanded ? ArmsPosition.EAimHighLeft : ArmsPosition.EAimHighRight ) ) )
                                    {
                                        if
                                        (
                                                ( iBotMeshes.completedTargetPitchesLeftArm  && iHanded == BotHanded.ELeftHanded  )
                                            ||  ( iBotMeshes.completedTargetPitchesRightArm && iHanded == BotHanded.ERightHanded )
                                        )
                                        {
                                            //fire if bot sees the player and player is alive
                                            if
                                            (
                                                    !Level.currentPlayer().isDeadAnimationOver()
                                                &&  botSeesThePlayer()
                                            )
                                            {
                                                //fire
                                                iArtefactSet.iCurrentArtefact.fire( this, iCylinder.getCenterHorz() );
                                            }
                                        }
                                    }
                                    else
                                    {
                                        //assign
                                        iBotMeshes.assignArmsPosition( ( iHanded == BotHanded.ELeftHanded ? ArmsPosition.EAimHighLeft : ArmsPosition.EAimHighRight ) );
                                    }
                                }
                            }
                            break;
                        }

                        case ESequenceDelay:
                        {
                            if ( iInterAnimationsDelay <= 0 )
                            {
                                iInterAnimationsDelay = BotSettings.INTER_ANIMATIONS_DELAY;
                            }
                            else
                            {
                                if ( --iInterAnimationsDelay <= 0 )
                                {
                                    iInterAnimationsDelay = 0;
                                    iJobs.remove( 0 );
                                }
                            }
                            break;
                        }

                        case ESequenceTurnToPlayer:
                        {
                            //turn to player
                            iState = BotState.EWatchPlayer;

                            //check if bot sees the player now
                            Point2D.Float   player           = Level.currentPlayer().getCylinder().getCenterHorz();
                            float           anglePlayerToBot = LibMath.getAngleCorrect( player, bot );
                            float           angleBotToPlayer = LibMath.normalizeAngle( anglePlayerToBot - 180.0f ); //checked normalizing - also works wothout :)

                            //check if bot looks into player's direction
                            if ( Math.abs( angleBotToPlayer - iFacingAngle ) <= BotSettings.TARGET_TURNING_TOLERANCE )
                            {
                                iJobs.remove( 0 );
                            }
                            break;
                        }

                        case ESequenceNodOnce:
                        {
                            //check if assigned
                            if ( iBotMeshes.isAssignedHeadPosition( HeadPosition.ENodOnce ) )
                            {
                                if ( iBotMeshes.completedTargetPitchesHead )
                                {
                                    iBotMeshes.assignHeadPosition( HeadPosition.EStill );
                                    iJobs.remove( 0 );
                                }
                            }
                            else
                            {
                                //assign
                                iBotMeshes.assignHeadPosition( HeadPosition.ENodOnce );
                            }
                            break;
                        }

                        case ESequenceNodTwice:
                        {
                            //check if assigned
                            if ( iBotMeshes.isAssignedHeadPosition( HeadPosition.ENodTwice ) )
                            {
                                if ( iBotMeshes.completedTargetPitchesHead )
                                {
                                    iBotMeshes.assignHeadPosition( HeadPosition.EStill );
                                    iJobs.remove( 0 );
                                }
                            }
                            else
                            {
                                //assign
                                iBotMeshes.assignHeadPosition( HeadPosition.ENodTwice );
                            }
                            break;
                        }

                        case ESequenceGrabSpringRight:
                        {
                            //check if assigned
                            if ( iBotMeshes.isAssignedArmsPosition( ArmsPosition.EPickUpRight ) )
                            {
                                if ( iBotMeshes.completedTargetPitchesRightArm )
                                {
                                    iJobs.remove( 0 );
                                }
                            }
                            else
                            {
                                //assign
                                iBotMeshes.assignArmsPosition( ArmsPosition.EPickUpRight );
                            }
                            break;
                        }

                        case ESequenceFlushRightEquippedItem:
                        {
                            //draw item to bot
                            iBotMeshes.setItem( Arm.ERight, null,  getAnchor(), this );

                            //next job
                            iJobs.remove( 0 );

                            break;
                        }

                        case ESequenceDeliverRightEquippedItem:
                        {
                            //give item to bot
                            iBotMeshes.setItem( Arm.ERight, iNextItemToDeliverRightHand,  getAnchor(), this );

                            //next job
                            iJobs.remove( 0 );

                            break;
                        }

                        case ESequenceGrabBackDownRight:
                        {
                            //check if assigned
                            if ( iBotMeshes.isAssignedArmsPosition( ArmsPosition.EBackDownRight ) )
                            {
                                if ( iBotMeshes.completedTargetPitchesRightArm )
                                {
                                    iJobs.remove( 0 );
                                }
                            }
                            else
                            {
                                //assign
                                iBotMeshes.assignArmsPosition( ArmsPosition.EBackDownRight );
                            }
                            break;
                        }

                        case ESequenceGrabSpringLeft:
                        {
                            //check if assigned
                            if ( iBotMeshes.isAssignedArmsPosition( ArmsPosition.EPickUpLeft ) )
                            {
                                if ( iBotMeshes.completedTargetPitchesLeftArm )
                                {
                                    iJobs.remove( 0 );
                                }
                            }
                            else
                            {
                                //assign
                                iBotMeshes.assignArmsPosition( ArmsPosition.EPickUpLeft );
                            }
                            break;
                        }

                        case ESequenceFlushLeftEquippedItem:
                        {
                            //draw item to bot
                            iBotMeshes.setItem( Arm.ELeft, null,  getAnchor(), this );

                            //next job
                            iJobs.remove( 0 );

                            break;
                        }

                        case ESequenceDeliverLeftEquippedItem:
                        {
                            //give item to bot
                            iBotMeshes.setItem( Arm.ELeft, iNextItemToDeliverLeftHand,  getAnchor(), this );

                            //next job
                            iJobs.remove( 0 );

                            break;
                        }

                        case ESequenceGrabBackDownLeft:
                        {
                            //check if assigned
                            if ( iBotMeshes.isAssignedArmsPosition( ArmsPosition.EBackDownLeft ) )
                            {
                                if ( iBotMeshes.completedTargetPitchesLeftArm )
                                {
                                    iJobs.remove( 0 );
                                }
                            }
                            else
                            {
                                //assign
                                iBotMeshes.assignArmsPosition( ArmsPosition.EBackDownLeft );
                            }
                            break;
                        }

                        case ESequenceReloadHandUp:
                        {
                            iState = BotState.EStandStill;

                            //check if assigned
                            if ( iBotMeshes.isAssignedArmsPosition( ( iHanded == BotHanded.ELeftHanded ? ArmsPosition.EReloadLeftUp : ArmsPosition.EReloadRightUp ) ) )
                            {
                                if ( iHanded == BotHanded.ELeftHanded && iBotMeshes.completedTargetPitchesLeftArm )
                                {
                                    iJobs.remove( 0 );
                                }
                                else if ( iHanded == BotHanded.ERightHanded && iBotMeshes.completedTargetPitchesRightArm )
                                {
                                    iJobs.remove( 0 );
                                }
                            }
                            else
                            {
                                //assign
                                iBotMeshes.assignArmsPosition( ( iHanded == BotHanded.ELeftHanded ? ArmsPosition.EReloadLeftUp : ArmsPosition.EReloadRightUp ) );
                            }
                            break;
                        }

                        case ESequenceReloadHandDown:
                        {
                            iState = BotState.EStandStill;

                            //check if assigned
                            if ( iBotMeshes.isAssignedArmsPosition( ( iHanded == BotHanded.ELeftHanded ? ArmsPosition.EReloadLeftDown : ArmsPosition.EReloadRightDown ) ) )
                            {
                                if ( iHanded == BotHanded.ELeftHanded && iBotMeshes.completedTargetPitchesLeftArm )
                                {
                                    iJobs.remove( 0 );
                                }
                                else if ( iHanded == BotHanded.ERightHanded && iBotMeshes.completedTargetPitchesRightArm )
                                {
                                    iJobs.remove( 0 );
                                }
                            }
                            else
                            {
                                //assign
                                iBotMeshes.assignArmsPosition( ( iHanded == BotHanded.ELeftHanded ? ArmsPosition.EReloadLeftDown : ArmsPosition.EReloadRightDown ) );
                            }
                            break;
                        }
                    }

                    //perform action according to current state
                    switch ( iState )
                    {
                        case EStandStill:
                        {
                            //remain on position and do not change angle
                            nextPosX = bot.x;
                            nextPosY = bot.y;
                            break;
                        }

                        case EDying:
                        {
                            //bot is still
                            nextPosX = bot.x;
                            nextPosY = bot.y;
/*
                            //no use for turning to player!
                            if ( !iLeaveDeadZ )
                            {
                               //turn bot to player
                                Point2D.Float   player           = ShooterGameLevel.currentPlayer().getCylinder().getCenterHorz();
                                float           angleBotToPlayer = LibMath.getAngleCorrect( getCenterHorz(), player );

                                rotateBotTo( angleBotToPlayer );

                                if ( !iFaceAngleChanged )
                                {
                                    iLeaveDeadZ = true;
                                }
                            }
*/
                            break;
                        }

                        case EWatchPlayer:
                        {
                            //calculate bot's angle and distance to the player
                            Point2D.Float   player           = Level.currentPlayer().getCylinder().getCenterHorz();
                            float           anglePlayerToBot = LibMath.getAngleCorrect( player, bot );
                            float           angleBotToPlayer = LibMath.normalizeAngle( anglePlayerToBot - 180.0f ); //checked normalizing - also works wothout :)

                            //bot is standing still turning to the player
                            nextPosX = bot.x;
                            nextPosY = bot.y;

                            final float MAX_BOT_WATCH_RADIUS = 10.0f;

                            float botDistanceToPlayer = (float)player.distance( bot );
                            if ( angleBotToPlayer != iFacingAngle && botDistanceToPlayer < MAX_BOT_WATCH_RADIUS )
                            {
                                rotateBotTo( angleBotToPlayer );
                            }
                            break;
                        }

                        case EWalkTowardsPlayer:
                        {
                            //calculate bot's angle and distance to the player
                            Point2D.Float   player           = Level.currentPlayer().getCylinder().getCenterHorz();
                            float           anglePlayerToBot = LibMath.getAngleCorrect( player, bot );
                            float           angleBotToPlayer = LibMath.normalizeAngle( anglePlayerToBot - 180.0f ); //checked normalizing - also works wothout :)

                            //bot walks towards the player - turning to him
                            nextPosX = bot.x - LibMath.sinDeg( -angleBotToPlayer ) * BotSettings.SPEED_WALKING;
                            nextPosY = bot.y - LibMath.cosDeg( -angleBotToPlayer ) * BotSettings.SPEED_WALKING;
                            if ( angleBotToPlayer != iFacingAngle ) iFaceAngleChanged = true;
                            iFacingAngle = angleBotToPlayer;
                            break;
                        }

                        case EWalkToNextWayPoint:
                        {
                            //shouldn't have been initialized without wayPoints ..
                            if ( iWayPoints != null )
                            {
                                //check if the current wayPoint has been reached?
                                if ( checkCollision( new Ellipse2D.Float( iWayPoints[ iCurrentWayPointIndex ].x - BotSettings.WAY_POINT_RADIUS, iWayPoints[ iCurrentWayPointIndex ].y - BotSettings.WAY_POINT_RADIUS, 2 * BotSettings.WAY_POINT_RADIUS, 2 * BotSettings.WAY_POINT_RADIUS ) ) )
                                {
                                    //wayPoint has been reached
                                    //Debug.info( "wayPoint reached" );

                                    //target next wayPoint
                                    ++iCurrentWayPointIndex;

                                    //begin with 1st waypoint
                                    if ( iCurrentWayPointIndex >= iWayPoints.length ) iCurrentWayPointIndex = 0;
                                }

                                //set arms and legs walking
                                if ( !iBotMeshes.isAssignedLegsPosition( LegsPosition.EWalk ) )
                                {
                                    iBotMeshes.assignLegsPosition( LegsPosition.EWalk );
                                }
                                if ( !iBotMeshes.isAssignedArmsPosition( ArmsPosition.EWalk ) )
                                {
                                    iBotMeshes.assignArmsPosition( ArmsPosition.EWalk );
                                }

                                //move player towards current waypoint
                                Point2D.Float currentWayPoint = iWayPoints[ iCurrentWayPointIndex ];

                                //move bot towards the wayPoint
                                float angleWaypointToBot = LibMath.getAngleCorrect( currentWayPoint, bot );
                                float angleBotToWayPoint = LibMath.normalizeAngle( angleWaypointToBot - 180.0f );
                                //Debug.bot.out( "angle player to bot is: " + anglePlayerToBot );
                                //Debug.bot.out( "angle bot to player is: " + angleBotToPlayer );

                                //bot walks towards current waypoint - turning to him
                                nextPosX = bot.x - LibMath.sinDeg( -angleBotToWayPoint ) * BotSettings.SPEED_WALKING;
                                nextPosY = bot.y - LibMath.cosDeg( -angleBotToWayPoint ) * BotSettings.SPEED_WALKING;

                                //order rotation to
                                rotateBotTo( angleBotToWayPoint );
                            }
/*
                            //check if this bot sees the player
                            if ( botSeesThePlayer( -angleBotToPlayer ) )
                            {
                                System.out.println( "player sighted" );
                            }
*/
                            break;
                        }
                    }

                    //check collisions
                    float oldPosX = getCenterHorz().x;
                    float oldPosY = getCenterHorz().y;

                    //set to new position ( if position changed! )
                    if ( oldPosX != nextPosX || oldPosY != nextPosY )
                    {
                        setCenterHorz( nextPosX, nextPosY );

                        //check collisions to other bots
                        if ( checkCollisionsToOtherBots() )
                        {
                            //set back to old position
                            setCenterHorz( oldPosX, oldPosY );
                            playerMoved = false;
                        }
                        //check collisions to player
                        else if ( checkCollisionsToPlayer() )
                        {
                            //undo setting to new position
                            setCenterHorz( oldPosX, oldPosY );
                            playerMoved = false;
                        }
                        else
                        {
                            //leave the new position
                            playerMoved = true;

                            //translate all bullet holes to new position
                            BulletHole.translateAll( this, nextPosX - oldPosX, nextPosY - oldPosY, 0.0f );
                        }
                    }

                    //rotate if faceAngle changed
                    if ( iFaceAngleChanged )
                    {
                        BulletHole.rotateForBot( this, iFacingAngle );
                    }
                    break;
                }
            }

            //perform transformations here

            //let eyes blink ( or close on dying )
            blinkEyes();

            //translate and rotate the bot's mesh
            LibVertex botAnchor = getAnchor().copy();

            //translate anchor if desired
            botAnchor.z += iOffsetZ;

            //set anchors for all meshes!
            iBotMeshes.setNewAnchor( botAnchor, false, null );

            //animate dying
            animateDying();

            //transform bot's limbs
            iBotMeshes.transformLimbs( iFacingAngle, iDyingAngle, iFaceAngleChanged, playerMoved );
        }

        public final void draw()
        {
            switch ( iType )
            {
                case ETypeEnemy:
                case ETypeFriend:
                {
                    //turn bullet holes?? :(

                    //draw bot's mesh
                    iBotMeshes.draw();

                    //draw bot's debug-circles
                    drawDebugCircles();

                    break;
                }
            }
        }

        @Override
        public final LibShot getShot( float modZ )
        {
            return new LibShot
            (
                ShotType.ESharpAmmo,
                LibShot.ShotOrigin.EEnemies,

                LibMath.getRandom( -10, 10 ) + modZ,       // 0.0f,   //irregularityHorz
                LibMath.getRandom( -2),       // 0.0f,   //irregularityVert

                getAnchor().x,
                getAnchor().y,
                getAnchor().z + PlayerSettings.DEPTH_HAND_STANDING,   // take hand height from player
                180.0f + ( 180.0f - iFacingAngle ),     //rotZ
                0.0f,                                   //rotX
                BotSettings.SHOT_RANGE,    // bot has constant shot range ???
                LibHoleSize.E44mm,   // bot always fires 9mm    ??
                ShooterDebug.shotAndHit,
                ArtefactType.EMagnum357.iArtefactKind.getSliverParticleQuantity(),
                FxSettings.SLIVER_ANGLE_MOD,
                10,
                ArtefactType.EMagnum357.iArtefactKind.getSliverParticleSize(),
                ArtefactType.EMagnum357.getBreaksWalls(),
                ( (FireArm)ArtefactType.EMagnum357.iArtefactKind ).getProjectile(),
                General.FADE_OUT_FACES_TOTAL_TICKS
            );
        }

        public final LibShot getViewShot()
        {
            return new LibShot
            (
                ShotType.EViewOnly,
                LibShot.ShotOrigin.EEnemies,
                0.0f,   //irregularityHorz
                0.0f,   //irregularityVert
                getAnchor().x,
                getAnchor().y,
                getAnchor().z + ( getHeight() * 3 / 4 ),
                180.0f + ( 180.0f - iFacingAngle ),     //rotZ
                0.0f,                                   //rotX
                BotSettings.VIEW_RANGE,
                LibHoleSize.ENone,
                ShooterDebug.shotAndHit,
                ArtefactType.EMagnum357.iArtefactKind.getSliverParticleQuantity(),
                FxSettings.SLIVER_ANGLE_MOD,
                0,
                ArtefactType.EMagnum357.iArtefactKind.getSliverParticleSize(),
                false,
                null,
                General.FADE_OUT_FACES_TOTAL_TICKS
            );
        }

        public final boolean botSeesThePlayer()
        {
            //check if this enemy bot sees the player - copy current angle
            LibShot       shot     = getViewShot();
            LibHitPoint[] hitPoint = Level.currentSection().launchShot( shot );

            //draw view shot line
            //shot.drawShotLine( FxSettings.LIFETIME_DEBUG );

            return ( hitPoint.length > 0 && hitPoint[ 0 ].iCarrier.getHitPointCarrier() == HitPointCarrier.EPlayer );
        }

        @Override
        public final LibVertex getAnchor()
        {
            return iCylinder.getAnchor();
        }

        @Override
        public final float getCarriersFaceAngle()
        {
            return iFacingAngle;
        }

        @Override
        public final Vector<LibHitPoint> launchShot( LibShot shot )
        {
            return iBotMeshes.launchShot( shot );
        }

        public final boolean isDead()
        {
            return ( iAliveState == BotAliveState.EDead );
        }

        @Override
        public HitPointCarrier getHitPointCarrier()
        {
            return HitPointCarrier.EBot;
        }

        private void rotateBotTo( float targetAngle )
        {
            //get the rotation of the bot
            float angleDistance   = LibMath.getAngleDistanceRelative( iFacingAngle, targetAngle );
            float turningDistance = Math.abs( angleDistance );

            if ( turningDistance >= BotSettings.SPEED_TURNING_MIN )
            {
                //clip turning distance
                if ( turningDistance > BotSettings.SPEED_TURNING_MAX ) turningDistance = BotSettings.SPEED_TURNING_MAX;

                //ShooterDebug.bot.out( "turning bot, src ["+iFacingAngle+"] target ["+targetAngle+"] distance is [" + angleDistance + "]" );

                iFaceAngleChanged = true;

                if ( angleDistance < 0 )
                {
                    iFacingAngle = LibMath.normalizeAngle( iFacingAngle - turningDistance );
                }
                else if ( angleDistance > 0 )
                {
                    iFacingAngle = LibMath.normalizeAngle( iFacingAngle + turningDistance );
                }
            }
        }

        public void makeDistancedSound( SoundFg fx )
        {
            fx.playDistancedFx( getCenterHorz() );
        }

        private void blinkEyes()
        {
            if ( iAliveState != BotAliveState.EAlive )
            {
                if ( iEyesOpen )
                {
                    iBotMeshes.changeFaceTexture( iBotMeshes.iTemplate.iTexFaceEyesOpen.getTexture(), iBotMeshes.iTemplate.iTexFaceEyesShut.getTexture() );
                    iEyesOpen = false;
                }
            }
            //let eyes blink
            else if ( System.currentTimeMillis() >= iNextEyeChange )
            {
                iEyesOpen = !iEyesOpen;
                if ( iEyesOpen )
                {
                    iBotMeshes.changeFaceTexture( iBotMeshes.iTemplate.iTexFaceEyesShut.getTexture(), iBotMeshes.iTemplate.iTexFaceEyesOpen.getTexture() );
                }
                else
                {
                    iBotMeshes.changeFaceTexture( iBotMeshes.iTemplate.iTexFaceEyesOpen.getTexture(), iBotMeshes.iTemplate.iTexFaceEyesShut.getTexture() );
                }
                setNextEyeChange();
            }
        }

        public void fallAsleep()
        {
            if ( iAliveState == BotAliveState.EAlive )
            {
                killOrTranquilize( BotAliveState.ETranquilized );
            }
        }

        public void hurt( int damage )
        {
            iHealth -= damage;

            //bot dies?
            if ( iAliveState != BotAliveState.EDead && iHealth <= 0 )
            {
                killOrTranquilize( BotAliveState.EDead );
            }
        }

        private void animateDying()
        {
            switch ( iAliveState )
            {
                case EAlive:
                {
                    break;
                }

                case ETranquilized:
                case EDead:
                {
                    switch ( iDyingDirection )
                    {
                        case EFront:
                        {
                            if ( iDyingAngle < 10.0f  )
                            {
                                iDyingAngle += 1.0f;

                                if ( iOffsetZ < iTargetOffsetZ )
                                {
                                    iOffsetZ += iTargetOffsetZ / 45;
                                }
                            }
                            else
                            {
                                iDyingAngle += 10.0f;

                                if ( iOffsetZ < iTargetOffsetZ )
                                {
                                    iOffsetZ += iTargetOffsetZ / 9;
                                }
                            }

                            if ( iDyingAngle >= 90.0f ) iDyingAngle = 90.0f;
                            break;
                        }

                        case EBack:
                        {
                            if ( iDyingAngle > -10.0f  )
                            {
                                iDyingAngle -= 1.0f;

                                if ( iOffsetZ < iTargetOffsetZ )
                                {
                                    iOffsetZ += iTargetOffsetZ / 45;
                                }
                            }
                            else
                            {
                                iDyingAngle -= 10.0f;

                                if ( iOffsetZ < iTargetOffsetZ )
                                {
                                    iOffsetZ += iTargetOffsetZ / 9;
                                }
                            }
                            if ( iDyingAngle <= -90.0f ) iDyingAngle = -90.0f;
                            break;
                        }
                    }
                }
            }
        }

        public void killOrTranquilize( BotAliveState newState )
        {
            if ( iAliveState != BotAliveState.ETranquilized )
            {
                //start disappear timer ( will only count for dead bots ) - only if bot was
                iDisappearTimer = FxSettings.LIFETIME_CORPSE;
                iDyingDirection = DyingDirection.values()[ LibMath.getRandom( 0, DyingDirection.values().length - 1 ) ];
                iBotMeshes.assignArmsPosition( ArmsPosition.EDownBoth           );
                iBotMeshes.assignLegsPosition( LegsPosition.EStandSpreadLegged  );
                iBotMeshes.assignHeadPosition( HeadPosition.EStill              );
                switch ( iDyingDirection )
                {
                    case EBack:
                    {
                        iTargetOffsetZ = 0.05f;
                        break;
                    }
                    case EFront:
                    {
                        iTargetOffsetZ = 0.15f;
                        break;
                    }
                }
            }

            //let bot die
            iHealth         = 0;
            iAliveState     = newState;

            //drop all artefacts and set dying
            dropAllArtefacts();
            setNewJobQueue( new BotJob[] { BotJob.EDying } );
        }

        public void setNewJobQueue( BotJob[] newJobs )
        {
            iJobs.removeAllElements();
            iJobs.addAll( Arrays.asList( newJobs ) );
        }

        public void fadeOutAllFaces()
        {
            iBotMeshes.fadeOutAllFaces();
        }

        public final int getHealth()
        {
            return iHealth;
        }

        public final void dropAllArtefacts()
        {
            //turn artefacts to pickable items
            for ( Artefact toDrop : iArtefactSet.iArtefacts )
            {
                ItemToPickUp p = toDrop.getPickUpItem( getAnchor() );
                if ( p != null )
                {
                    //p.loadD3ds(); //old solution
                    iBotMeshes.iEquippedItemRight.setTranslatedAsOriginalVertices();
                    p.assignMesh( iBotMeshes.iEquippedItemRight );
                    p.iDropTarget = getAnchor().z;
                    p.iDropBegin  = iBotMeshes.iEquippedItemRight.getCenterZ();
                    Level.currentSection().addItem( p );
                }
            }

            //strip off artefacts
            iBotMeshes.setItem( Arm.ERight, null,  getAnchor(), this );
            iBotMeshes.setItem( Arm.ELeft,  null,  getAnchor(), this );
        }
    }
TOP

Related Classes of de.christopherstock.shooter.game.objects.Bot$BotUseAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.