org.jtrfp.trcl.beh.ProjectileBehavior.java Source code

Java tutorial

Introduction

Here is the source code for org.jtrfp.trcl.beh.ProjectileBehavior.java

Source

/*******************************************************************************
 * This file is part of TERMINAL RECALL
 * Copyright (c) 2012-2014 Chuck Ritola
 * Part of the jTRFP.org project
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     chuck - initial API and implementation
 ******************************************************************************/
package org.jtrfp.trcl.beh;

import java.lang.ref.WeakReference;
import java.util.List;

import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.jtrfp.trcl.AbstractSubmitter;
import org.jtrfp.trcl.beh.AutoLeveling.LevelingAxis;
import org.jtrfp.trcl.beh.DamageListener.ProjectileDamage;
import org.jtrfp.trcl.beh.phy.MovesByVelocity;
import org.jtrfp.trcl.obj.DEFObject;
import org.jtrfp.trcl.obj.Explosion.ExplosionType;
import org.jtrfp.trcl.obj.Player;
import org.jtrfp.trcl.obj.Projectile;
import org.jtrfp.trcl.obj.WorldObject;

public class ProjectileBehavior extends Behavior
        implements SurfaceImpactListener, DEFObjectCollisionListener, PlayerCollisionListener {
    public static final long LIFESPAN_MILLIS = 4500;
    private final int damageOnImpact;
    private final DeathBehavior deathBehavior;
    private final Projectile parent;
    private WeakReference<WorldObject> honingTarget = new WeakReference<WorldObject>(null);
    private int honingAdjustmentUpdate = 0;
    private boolean honing = false;
    private double speed;
    private final MovesByVelocity movesByVelocity;

    public ProjectileBehavior(WorldObject parent, int damageOnImpact, ExplosionType explosionType, boolean honing) {
        this.damageOnImpact = damageOnImpact;
        this.parent = (Projectile) parent;
        this.honing = honing;
        movesByVelocity = new MovesByVelocity();
        parent.addBehavior(movesByVelocity);
        parent.addBehavior(new CollidesWithTunnelWalls(false, false));
        parent.addBehavior(new CollidesWithTerrain());
        deathBehavior = parent.addBehavior(new DeathBehavior());
        parent.addBehavior(new ExplodesOnDeath(explosionType));
        parent.addBehavior(new CollidesWithDEFObjects(2000));
        parent.addBehavior(new CollidesWithPlayer(2000));
        parent.addBehavior(new LimitedLifeSpan().reset(LIFESPAN_MILLIS));
        parent.addBehavior(new LoopingPositionBehavior());
        if (honing) {
            parent.addBehavior(
                    new AutoLeveling().setRetainmentCoeff(.88, .88, .88).setLevelingAxis(LevelingAxis.HEADING));
        } // end if(honingTarget)
    }// end constructor

    public void reset(Vector3D heading, double speed) {
        this.speed = speed;
        honingTarget = null;
        final WorldObject parent = getParent();
        final Behavior beh = parent.getBehavior();
        parent.setHeading(heading);
        if (honing) {
            // Find target
            WorldObject closestObject = null;
            double closestDistance = Double.POSITIVE_INFINITY;
            List<WorldObject> possibleTargets = getParent().getTr().getCollisionManager()
                    .getCurrentlyActiveCollisionList();
            synchronized (possibleTargets) {
                for (WorldObject possibleTarget : possibleTargets) {
                    if (possibleTarget instanceof DEFObject) {
                        DEFObject possibleDEFTarget = (DEFObject) possibleTarget;
                        if (!possibleDEFTarget.isIgnoringProjectiles() && !possibleDEFTarget.isRuin()) {
                            final Vector3D targetPos = new Vector3D(possibleTarget.getPositionWithOffset());
                            final Vector3D delta = targetPos.subtract(new Vector3D(getParent().getPosition()));
                            final double dist = delta.getNorm();
                            final Vector3D proposedHeading = delta.normalize();
                            final Vector3D headingDelta = getParent().getHeading().subtract(proposedHeading);
                            final double compositeHeadingDelta = headingDelta.getNorm();
                            if (compositeHeadingDelta < .5) {
                                final double compositeDistance = dist;
                                if (compositeDistance < closestDistance) {
                                    closestDistance = dist;
                                    closestObject = possibleTarget;
                                    parent.setHeading(proposedHeading);
                                    getParent().getBehavior().probeForBehavior(AutoLeveling.class)
                                            .setLevelingVector(heading);
                                } // end if(closesObject)
                            } // end if(headingDelta<1)
                        } // end if(isIgnoringProjectiles)
                    } // end if(DEFObject)
                }
            } // end for(WorldObject others)
            honingTarget = new WeakReference<WorldObject>(closestObject);
            // if(honingTarget==null){
            getParent().getBehavior().probeForBehavior(AutoLeveling.class).setLevelingVector(heading);
            movesByVelocity.setVelocity(getParent().getHeading().scalarMultiply(speed));
            //   }//end if(honingTarget==null)
        } // end if(honingTarget)
        beh.probeForBehavior(LimitedLifeSpan.class).reset(LIFESPAN_MILLIS);
        beh.probeForBehavior(DeathBehavior.class).reset();
    }// end reset()

    @Override
    public void _tick(long tickTimeMillis) {
        if (honingTarget != null) {
            if (honingTarget.get() == null)
                return;
            if (honingAdjustmentUpdate++ % 5 == 0) {
                if (!honingTarget.get().isVisible())
                    return;// Dead or otherwise.
                final Vector3D honingVector = new Vector3D(honingTarget.get().getPositionWithOffset())
                        .subtract(new Vector3D(getParent().getPosition())).normalize();
                //Sanity check
                if (Double.isNaN(honingVector.getX()))
                    return;
                if (Double.isNaN(honingVector.getY()))
                    return;
                if (Double.isNaN(honingVector.getZ()))
                    return;
                getParent().getBehavior().probeForBehavior(AutoLeveling.class).setLevelingVector(honingVector);
                movesByVelocity.setVelocity(getParent().getHeading().scalarMultiply(speed));
            } // end if(updateHoningVector)
        } // end if(honingTarget)
    }//end _tick()

    @Override
    public void collidedWithSurface(WorldObject wo, double[] surfaceNormal) {
        deathBehavior.die();
    }

    @Override
    public void collidedWithDEFObject(DEFObject other) {
        if (other.isIgnoringProjectiles())
            return;
        if (other == parent.getObjectOfOrigin())
            return;// Don't shoot yourself.
        if (parent.getObjectOfOrigin() instanceof DEFObject)
            return;// Don't shoot your buddy.
        other.getBehavior().probeForBehaviors(new AbstractSubmitter<DamageableBehavior>() {
            @Override
            public void submit(DamageableBehavior item) {
                item.proposeDamage(new ProjectileDamage(damageOnImpact));
            }
        }, DamageableBehavior.class);
        deathBehavior.die();
    }//end collidedWithDEFObject

    public void forceCollision(WorldObject other) {
        other.getBehavior().probeForBehaviors(new AbstractSubmitter<DamageableBehavior>() {
            @Override
            public void submit(DamageableBehavior item) {
                item.proposeDamage(new ProjectileDamage(damageOnImpact));
            }
        }, DamageableBehavior.class);
        deathBehavior.die();
    }//end forceCollision(...)

    @Override
    public void collidedWithPlayer(Player other) {
        if (other == parent.getObjectOfOrigin())
            return;// Don't shoot yourself.
        other.getBehavior().probeForBehaviors(new AbstractSubmitter<DamageableBehavior>() {
            @Override
            public void submit(DamageableBehavior item) {
                item.proposeDamage(new ProjectileDamage(damageOnImpact));
            }
        }, DamageableBehavior.class);
        deathBehavior.die();
    }
    /*
     * if(other instanceof DEFObject){
     * 
     * }//end if(DEFObject)
     */
}// end ProjectileBehavior