com.vlaaad.dice.game.actions.imp.ChainLightning.java Source code

Java tutorial

Introduction

Here is the source code for com.vlaaad.dice.game.actions.imp.ChainLightning.java

Source

/*
 * Dice heroes is a turn based rpg-strategy game where characters are dice.
 * Copyright (C) 2016 Vladislav Protsenko
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.vlaaad.dice.game.actions.imp;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectIntMap;
import com.badlogic.gdx.utils.ObjectSet;
import com.vlaaad.common.util.MapHelper;
import com.vlaaad.common.util.Numbers;
import com.vlaaad.common.util.futures.Future;
import com.vlaaad.common.util.futures.IFuture;
import com.vlaaad.common.util.futures.IFutureListener;
import com.vlaaad.dice.game.actions.AttackType;
import com.vlaaad.dice.game.actions.CreatureAction;
import com.vlaaad.dice.game.actions.results.IActionResult;
import com.vlaaad.dice.game.actions.results.imp.ChainLightningResult;
import com.vlaaad.dice.game.config.abilities.Ability;
import com.vlaaad.dice.game.config.attributes.Attribute;
import com.vlaaad.dice.game.objects.Creature;
import com.vlaaad.dice.game.objects.WorldObject;
import com.vlaaad.dice.game.util.ExpHelper;
import com.vlaaad.dice.game.world.World;
import com.vlaaad.dice.game.world.behaviours.BehaviourRequest;
import com.vlaaad.dice.game.world.behaviours.params.AbilityCreatureParams;
import com.vlaaad.dice.game.world.controllers.BehaviourController;
import com.vlaaad.dice.game.world.controllers.RandomController;

import java.util.Iterator;
import java.util.Map;

/**
 * Created 12.01.14 by vlaaad
 */
public class ChainLightning extends CreatureAction {

    private static final Vector2 tmp1 = new Vector2();
    private static final Vector2 tmp2 = new Vector2();
    private static final ObjectSet<Creature> tmpSet = new ObjectSet<Creature>();
    private static final Array<Creature> tmpArray2 = new Array<Creature>();
    private static final Array<Creature> tmpArray3 = new Array<Creature>();

    private int distance;
    private int targets;
    private int attackLevel;
    private AttackType attackType;

    public ChainLightning(Ability owner) {
        super(owner);
    }

    @Override
    protected void doInit(Object setup) {
        Map data = (Map) setup;
        distance = MapHelper.get(data, "distance", Numbers.ONE).intValue();
        targets = MapHelper.get(data, "targets", Numbers.ONE).intValue();
        attackLevel = MapHelper.get(data, "level", Numbers.ONE).intValue();
        attackType = AttackType.valueOf(MapHelper.get(data, "type", "weapon"));
    }

    @Override
    public IFuture<IActionResult> apply(final Creature creature, final World world) {
        Array<Creature> targets = findTargets(creature, Creature.CreatureRelation.enemy, creature.getX(),
                creature.getY(), world, distance);
        if (targets.size == 0) {
            return Future.completed(IActionResult.NOTHING);
        } else if (targets.size == 1) {
            return Future.completed(calcResult(owner, creature, targets.first(), world));
        } else {
            final Future<IActionResult> future = new Future<IActionResult>();
            world.getController(BehaviourController.class).get(creature)
                    .request(BehaviourRequest.CREATURE, new AbilityCreatureParams(creature, owner, targets))
                    .addListener(new IFutureListener<Creature>() {
                        @Override
                        public void onHappened(Creature target) {
                            future.happen(calcResult(owner, creature, target, world));
                        }
                    });
            return future;
        }
    }

    private IActionResult calcResult(Ability ability, Creature caster, Creature target, World world) {
        ObjectSet<Creature> affected = tmpSet;
        Array<Creature> chain = new Array<Creature>();
        chain.add(target);
        affected.add(target);

        // i == 1 because we already have initial target
        RandomController random = world.getController(RandomController.class);

        for (int i = 1; i < targets; i++) {
            Creature last = chain.peek();
            tmpArray2.clear();
            Array<Creature> neighbours = getNeighbourCreatures(world, last.getX(), last.getY(), tmpArray2);
            Iterator<Creature> it = neighbours.iterator();
            while (it.hasNext()) {
                Creature toCheck = it.next();
                if (affected.contains(toCheck))
                    it.remove();
            }
            if (neighbours.size == 0) {
                break;
            } else if (neighbours.size == 1) {
                addToChain(affected, chain, neighbours.first());
            } else {
                Array<Creature> betterTargets = tmpArray3;
                betterTargets.clear();
                for (Creature toCheck : neighbours) {
                    if (toCheck.get(Attribute.defenceFor(attackType)) < attackLevel) {
                        betterTargets.add(toCheck);
                    }
                }
                if (betterTargets.size > 0) {
                    addToChain(affected, chain, random.random(betterTargets));
                } else {
                    addToChain(affected, chain, random.random(neighbours));
                }
            }
        }

        ObjectIntMap<Creature> expResults = new ObjectIntMap<Creature>();
        Array<Creature> killed = new Array<Creature>();

        for (Creature creature : chain) {
            if (creature.get(Attribute.defenceFor(attackType)) < attackLevel) { // killed
                if (creature.player != caster.player) {
                    expResults.getAndIncrement(caster, 0, ExpHelper.expForKill(caster, creature));
                }
                killed.add(creature);
            } else { // survived
                expResults.put(creature, ExpHelper.expForDefence(caster, creature));
            }
        }

        tmpSet.clear();
        tmpArray2.clear();
        tmpArray3.clear();

        return new ChainLightningResult(caster, ability, chain, killed, expResults);
    }

    private void addToChain(ObjectSet<Creature> affected, Array<Creature> chain, Creature toAdd) {
        if (!affected.add(toAdd))
            throw new IllegalStateException(toAdd + " should not be affected now!");
        chain.add(toAdd);
    }

    private Array<Creature> getNeighbourCreatures(World world, int x, int y, Array<Creature> creatures) {
        for (int i = x - 1; i <= x + 1; i++) {
            for (int j = y - 1; j <= y + 1; j++) {
                if (i == x && j == y)
                    continue;
                WorldObject object = world.get(i, j);
                if (object instanceof Creature && ((Creature) object).get(Attribute.canBeSelected)) {
                    creatures.add((Creature) object);
                }
            }
        }
        return creatures;
    }

    public static Array<Creature> findTargets(Creature creature, Creature.CreatureRelation relation, int x, int y,
            World world, int distance) {
        Vector2 creaturePos = tmp1.set(x, y);
        Array<Creature> result = new Array<Creature>();
        for (WorldObject object : world) {
            if (!(object instanceof Creature))
                continue;
            if (object.getX() == x && object.getY() == y)
                continue;

            Creature check = (Creature) object;
            if (!check.get(Attribute.canBeSelected) || !creature.inRelation(relation, check))
                continue;
            Vector2 checkPos = tmp2.set(check.getX(), check.getY());
            if (checkPos.dst(creaturePos) > distance)
                continue;
            result.add(check);
        }
        return result;
    }
}