Exit Full View

Itchy / src / main / java / uk / co / nickthecoder / drunkinvaders / Alien.java

/*******************************************************************************
 * Copyright (c) 2013 Nick Robinson 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
 ******************************************************************************/
package uk.co.nickthecoder.drunkinvaders;

import java.util.ArrayList;
import java.util.List;

import uk.co.nickthecoder.itchy.Actor;
import uk.co.nickthecoder.itchy.Costume;
import uk.co.nickthecoder.itchy.Itchy;
import uk.co.nickthecoder.itchy.PlainCostumeFeatures;
import uk.co.nickthecoder.itchy.Role;
import uk.co.nickthecoder.itchy.ZOrderStage;
import uk.co.nickthecoder.itchy.animation.Eases;
import uk.co.nickthecoder.itchy.animation.ScaleAnimation;
import uk.co.nickthecoder.itchy.extras.Fragments;
import uk.co.nickthecoder.itchy.property.DoubleProperty;
import uk.co.nickthecoder.itchy.property.IntegerProperty;
import uk.co.nickthecoder.itchy.property.Property;
import uk.co.nickthecoder.itchy.role.ExplosionBuilder;
import uk.co.nickthecoder.itchy.role.TalkBuilder;
import uk.co.nickthecoder.itchy.util.Util;

public class Alien extends Bouncy implements Shootable
{
    protected static final List<Property<Role, ?>> properties = new ArrayList<Property<Role, ?>>();

    static {
        properties.addAll(Bouncy.properties);
        properties.add(new DoubleProperty<Role>("fireOnceEvery").hint("seconds"));
        properties.add(new IntegerProperty<Role>("shotsRequired"));
    }

    public static final String[] SHOOTABLE_LIST = new String[] { "shootable" };

    public double fireOnceEvery = 1.0; // Average duration between bombs in seconds

    public int shotsRequired = 1;

    public boolean tock = true;

    @Override
    public List<Property<Role, ?>> getProperties()
    {
        return properties;
    }

    @Override
    public void onBirth()
    {
        super.onBirth();
        DrunkInvaders.director.addAliens(1);
        addTag("deadly");
        addTag("shootable");
    }

    @Override
    public void onDeath()
    {
        super.onDeath();
        DrunkInvaders.director.addAliens(-1);
    }

    @Override
    public void tick()
    {
        if (DrunkInvaders.director.metronomeCountdown == 1) {
            if (getActor().getAnimation() == null) {
                this.tock = !this.tock;
                getActor().event(this.tock ? "tock" : "tick");
            }
        }
        if (Util.randomOnceEvery(this.fireOnceEvery)) {
            this.fire();
        }

        super.tick();

        // This isn't neat - can we have a "killable" tag, which Ship and Shield will both have?
        for (Role otherRole : collisions(SHOOTABLE_LIST)) {
            Actor other = otherRole.getActor();
            if ((getActor() != other) && (!otherRole.hasTag("bouncy"))) {
                ((Shootable) other.getRole()).shot(getActor());
            }
        }
    }

    public void fire()
    {
        if (getActor().getAnimation() != null) {
            // Can't fire while the alien is growing from the mothership.
            return;
        }
        this.event("fire");

        Actor bullet = new Actor(DrunkInvaders.director.getGame().resources.getCostume("bomb"));
        bullet.event("default");
        bullet.moveTo(getActor());
        bullet.setDirection(getActor().getAppearance().getDirection());
        ((ZOrderStage) Itchy.getGame().getLayout().findStage("main")).addTop(bullet);
        // Scaled up aliens have scaled up bullets
        bullet.moveForwards(15 * getActor().getAppearance().getScale());
        bullet.getAppearance().setScale(getActor().getAppearance().getScale());
        bullet.setRole(new Bullet("killable"));
    }

    @Override
    public void shot(Actor bullet)
    {
        // Explode pieces outwards
        new ExplosionBuilder(getActor()).fragments(getAlienCostumeProperties().fragments)
            .fade(3).speed(1, 3, 0, 0)
            .spin(-1, 1).create();

        // Particles exploding outwards
        new ExplosionBuilder(getActor())
            .projectiles(40).projectilesPerTick(10)
            .offsetForwards(-10, 10).offsetSidewards(-10, 10)
            .distance(10 * getActor().getAppearance().getScale())
            .speed(5, 9, 0, 0).fade(3).scale(1).eventName("pixel")
            .create();

        double scale = getActor().getAppearance().getScale();

        this.shotsRequired--;
        if (this.shotsRequired > 0) {
            event("shot");

            if (scale > 1) {
                double newScale = 1 + (scale - 1) * (this.shotsRequired) / (this.shotsRequired + 1);
                ScaleAnimation scaleAnimation = new ScaleAnimation(10, Eases.linear, newScale);
                getActor().setAnimation(scaleAnimation);
            }

            return;
        }

        Actor yell = new TalkBuilder(getActor())
            .eventName("death").style("yell")
            .offset(0, 40).direction(0)
            .create().getActor();

        yell.setCostume(getActor().getCostume());

        this.deathEvent("death");
        removeAllTags();

    }

    @Override
    public AlienCostumeProperties createCostumeFeatures(Costume costume)
    {
        return new AlienCostumeProperties(costume);
    }

    AlienCostumeProperties getAlienCostumeProperties()
    {
        return (AlienCostumeProperties) this.getActor().getCostume().getCostumeFeatures();
    }

    public static class AlienCostumeProperties extends PlainCostumeFeatures
    {
        public Fragments fragments;

        public AlienCostumeProperties(Costume costume)
        {
            super();
            this.fragments = new Fragments().create(costume.getPose("default"));
        }
    }
}