com.lyeeedar.Roguelike3D.Game.Level.XML.MonsterEvolver.java Source code

Java tutorial

Introduction

Here is the source code for com.lyeeedar.Roguelike3D.Game.Level.XML.MonsterEvolver.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Philip Collin.
 * 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:
 *     Philip Collin - initial API and implementation
 ******************************************************************************/
package com.lyeeedar.Roguelike3D.Game.Level.XML;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.lyeeedar.Roguelike3D.Game.GameData;
import com.lyeeedar.Roguelike3D.Game.GameData.Damage_Type;
import com.lyeeedar.Roguelike3D.Game.GameData.Element;
import com.lyeeedar.Roguelike3D.Game.Actor.AI_Enemy_VFFG;
import com.lyeeedar.Roguelike3D.Game.Actor.AI_Package;
import com.lyeeedar.Roguelike3D.Game.Actor.Enemy;
import com.lyeeedar.Roguelike3D.Game.Actor.GameActor;
import com.lyeeedar.Roguelike3D.Game.Item.Component;
import com.lyeeedar.Roguelike3D.Game.Item.Component.Component_Type;
import com.lyeeedar.Roguelike3D.Game.Item.Equipment_HAND;
import com.lyeeedar.Roguelike3D.Game.Item.Equipment_HAND.WeaponType;
import com.lyeeedar.Roguelike3D.Game.Level.Level;

/**
 * Class Used to evolve monsters to attempt to provide variety.
 * 
 * Also couples as the monsters.data xml reader.
 * @author Philip
 *
 */
public class MonsterEvolver extends XMLReader {

    /**
     * 
     */
    private static final long serialVersionUID = 935894653679977084L;
    public transient static final int EVOLVER_WIDTH = 10;
    public transient static final int EVOLVER_HEIGHT = 10;

    public transient static final int EVOLVER_CREATURE_NUM = 10;

    public transient static final int EVOLVER_CREATURE_TURNS = 10;

    public transient static final String DATA = "DATA";

    public transient static final String MONSTERS = "monsters";
    public transient static final String DEPTH_MIN = "depth_min";
    public transient static final String DEPTH_MAX = "depth_max";
    public transient static final String MONSTER_TYPE = "monster_type";
    public transient static final String CREATURES = "creatures";

    public transient static final String VISUAL = "visual";
    public transient static final String DESCRIPTION = "description";
    public transient static final String MODEL = "model";
    public transient static final String MODEL_TYPE = "type";
    public transient static final String MODEL_NAME = "name";
    public transient static final String MODEL_SCALE = "scale";
    public transient static final String TEXTURE = "texture";
    public transient static final String COLOUR = "colour";
    public transient static final String RED = "red";
    public transient static final String GREEN = "green";
    public transient static final String BLUE = "blue";

    public transient static final String STATS = "stats";
    public transient static final String BASE_CALORIES = "base_calories";
    public transient static final String WEIGHT = "weight";
    public transient static final String HEALTH = "health";
    public transient static final String ELEMENT = "element";
    public transient static final String ELE_DEFENSES = "ele_defenses";
    public transient static final String FIRE = "FIRE";
    public transient static final String WATER = "WATER";
    public transient static final String AIR = "AIR";
    public transient static final String WOOD = "WOOD";
    public transient static final String METAL = "METAL";
    public transient static final String AETHER = "AETHER";
    public transient static final String VOID = "VOID";
    public transient static final String DEFENSES = "defenses";
    public transient static final String PIERCE = "PIERCE";
    public transient static final String IMPACT = "IMPACT";
    public transient static final String TOUCH = "TOUCH";
    public transient static final String STRENGTH = "strength";
    public transient static final String ATTACK_SPEED = "attack_speed";
    public transient static final String ATTACK_DIST_MIN = "attack_dist_min";
    public transient static final String ATTACK_DIST_MAX = "attack_dist_max";
    public transient static final String WEAPON_STYLE = "weapon_style";
    public transient static final String WEAPON_VISUAL = "weapon_visual";
    public transient static final String WEAPON_TYPE = "weapon_type";
    public transient static final String AI = "AI";

    public transient static final String MIND = "MIND";
    public transient static final String SKIN = "SKIN";
    public transient static final String BONES = "BONES";
    public transient static final String MUSCLES = "MUSCLES";
    public transient static final String ATTACK = "ATTACK";
    public transient static final String ATTACK_RIGHT = "ATTACK_RIGHT";
    public transient static final String ATTACK_LEFT = "ATTACK_LEFT";

    public transient static final String SCALING = "scaling";
    public transient static final String TYPE = "type";

    public transient static final String ABSTRACT = "abstract";
    public transient static final String CREATURE = "creature";
    public transient static final String CALORIE_USAGE = "calorie_usage";

    public transient static final String ATTRIBUTES = "attributes";

    public transient static final String CALORIES = "calories";

    public transient static final String DIFFICULTY = "difficulty_";

    public transient static final String DROP_LIST = "drop_list";
    public transient static final String DROP = "drop";
    public transient static final String CHANCE = "chance";
    public transient static final String WEIGHT_PER_AMOUNT = "weight_per_amount";
    public transient static final String SOFT_HARD = "soft_hard";
    public transient static final String FLEXIBLE_BRITTLE = "flexible_brittle";
    public transient static final String NAME = "name";
    public transient static final String AMOUNT = "amount";
    public transient static final String RARITY = "rarity";

    public transient static final String FACTIONS = "factions";
    public transient static final String FACTION = "faction";
    public transient static final String ICON = "icon";

    final transient Random ran = new Random();

    final String monster;
    final transient Node selected_monster;
    final transient Node attribute_root;

    final HashMap<String, AbstractCreature_Evolver> creatures = new HashMap<String, AbstractCreature_Evolver>();

    public final String UID;

    public final String type;

    public MonsterEvolver(String monster_type, int depth) {

        super("data/xml/monsters.data");

        this.type = monster_type;

        UID = this.toString() + this.hashCode() + System.currentTimeMillis() + System.nanoTime();

        System.out.println("Creating for type " + monster_type + " at depth " + depth);

        attribute_root = getNode(ATTRIBUTES, getNode(DATA, root_node.getChildNodes()).getChildNodes());

        SortedMap<Integer, ArrayList<Node>> valid = new TreeMap<Integer, ArrayList<Node>>();

        Node monsters = getNode(MONSTERS, getNode(DATA, root_node.getChildNodes()).getChildNodes());

        for (int i = 0; i < monsters.getChildNodes().getLength(); i++) {
            Node n = monsters.getChildNodes().item(i);
            if (n.getNodeType() == Node.TEXT_NODE)
                continue;

            String mon_type = getNodeValue(MONSTER_TYPE, n.getChildNodes());

            if (mon_type.equalsIgnoreCase(monster_type)) {
                int d_min = Integer.parseInt(getNodeValue(getNode(DEPTH_MIN, n.getChildNodes())));
                int d_max = Integer.parseInt(getNodeValue(getNode(DEPTH_MAX, n.getChildNodes())));

                if (depth < d_min) {
                    if (valid.containsKey(0))
                        valid.get(d_min - depth).add(n);
                    else {
                        ArrayList<Node> nodes = new ArrayList<Node>();
                        nodes.add(n);
                        valid.put(d_min - depth, nodes);
                    }
                } else if (depth > d_max) {
                    if (valid.containsKey(0))
                        valid.get(depth - d_max).add(n);
                    else {
                        ArrayList<Node> nodes = new ArrayList<Node>();
                        nodes.add(n);
                        valid.put(depth - d_max, nodes);
                    }
                } else {
                    if (valid.containsKey(0))
                        valid.get(0).add(n);
                    else {
                        ArrayList<Node> nodes = new ArrayList<Node>();
                        nodes.add(n);
                        valid.put(0, nodes);
                    }
                }
            }
        }

        if (valid.size() == 0) {
            selected_monster = null;
            monster = null;
            System.err.println("Failed to select a monster!");
            return;
        }

        ArrayList<Node> ns = valid.get(valid.firstKey());

        selected_monster = ns.get(ran.nextInt(ns.size()));
        monster = selected_monster.getNodeName();

        ArrayList<String> factions = new ArrayList<String>();

        Node faction = getNode(FACTIONS, selected_monster.getChildNodes());

        for (int i = 0; i < faction.getChildNodes().getLength(); i++) {
            Node n = faction.getChildNodes().item(i);

            if (!n.getNodeName().equalsIgnoreCase(FACTION))
                continue;

            factions.add(getNodeValue(n));
        }

        Node creatures = getNode(CREATURES, selected_monster.getChildNodes());

        for (int i = 0; i < creatures.getChildNodes().getLength(); i++) {
            Node n = creatures.getChildNodes().item(i);

            if (n.getNodeType() == Node.TEXT_NODE)
                continue;

            AbstractCreature_Evolver ac_e = new AbstractCreature_Evolver(n.getNodeName(), factions);

            // Add visual

            Node visual = getNode(VISUAL, n.getChildNodes());
            NodeList description = getNode(DESCRIPTION, visual.getChildNodes()).getChildNodes();

            Node model = getNode(MODEL, visual.getChildNodes());
            String model_type = getNodeValue(MODEL_TYPE, model.getChildNodes());
            String model_name = getNodeValue(MODEL_NAME, model.getChildNodes());
            String model_scale = getNodeValue(MODEL_SCALE, model.getChildNodes());

            String texture = getNodeValue(TEXTURE, visual.getChildNodes());

            Node colour = getNode(COLOUR, visual.getChildNodes());
            String red = getNodeValue(RED, colour.getChildNodes());
            String green = getNodeValue(GREEN, colour.getChildNodes());
            String blue = getNodeValue(BLUE, colour.getChildNodes());

            ac_e.addVisual(description, model_type, model_name, model_scale, texture, red, green, blue);

            // Add stats

            Node stats = getNode(STATS, n.getChildNodes());

            String base_calories = getNodeValue(BASE_CALORIES, stats.getChildNodes());
            String weight = getNodeValue(WEIGHT, stats.getChildNodes());
            String health = getNodeValue(HEALTH, stats.getChildNodes());
            String strength = getNodeValue(STRENGTH, stats.getChildNodes());

            ac_e.addStats(base_calories, weight, health, strength);

            // Add Elemental Defenses

            Node eleDef = getNode(ELE_DEFENSES, stats.getChildNodes());

            String f = getNodeValue(FIRE, eleDef.getChildNodes());
            String wa = getNodeValue(WATER, eleDef.getChildNodes());
            String ai = getNodeValue(AIR, eleDef.getChildNodes());
            String wo = getNodeValue(WOOD, eleDef.getChildNodes());
            String m = getNodeValue(METAL, eleDef.getChildNodes());
            String ae = getNodeValue(AETHER, eleDef.getChildNodes());
            String v = getNodeValue(VOID, eleDef.getChildNodes());

            ac_e.addEleDef(f, wa, ai, wo, m, ae, v);

            // Add Damage Defenses

            Node damDef = getNode(DEFENSES, stats.getChildNodes());

            String pierce = getNodeValue(PIERCE, damDef.getChildNodes());
            String impact = getNodeValue(IMPACT, damDef.getChildNodes());
            String touch = getNodeValue(TOUCH, damDef.getChildNodes());

            ac_e.addDamDef(pierce, impact, touch);

            // Add Mind info

            Node mind = getNode(MIND, stats.getChildNodes());

            String mind_scale = getNodeValue(SCALING, mind.getChildNodes());
            String mind_type = getNodeValue(TYPE, mind.getChildNodes());

            ac_e.addMind(mind_scale, mind_type);

            // Add Skin info

            Node skin = getNode(SKIN, stats.getChildNodes());

            String skin_scale = getNodeValue(SCALING, skin.getChildNodes());
            String skin_type = getNodeValue(TYPE, skin.getChildNodes());
            ArrayList<Component> skinDrops = getDrops(getNode(DROP_LIST, skin.getChildNodes()));

            ac_e.addSkin(skin_scale, skin_type, skinDrops);

            // Add Bones info

            Node bones = getNode(BONES, stats.getChildNodes());

            String bones_scale = getNodeValue(SCALING, bones.getChildNodes());
            String bones_type = getNodeValue(TYPE, bones.getChildNodes());
            ArrayList<Component> boneDrops = getDrops(getNode(DROP_LIST, bones.getChildNodes()));

            ac_e.addBones(bones_scale, bones_type, boneDrops);

            // Add Muscles info

            Node muscles = getNode(MUSCLES, stats.getChildNodes());

            String muscles_scale = getNodeValue(SCALING, muscles.getChildNodes());
            String muscles_type = getNodeValue(TYPE, muscles.getChildNodes());

            ac_e.addMuscles(muscles_scale, muscles_type);

            // Add Attack info

            Node attack_right = getNode(ATTACK_RIGHT, stats.getChildNodes());

            if (attack_right != null) {
                String attack_scale = getNodeValue(SCALING, attack_right.getChildNodes());
                String attack_type = getNodeValue(TYPE, attack_right.getChildNodes());
                ArrayList<Component> attRDrops = getDrops(getNode(DROP_LIST, attack_right.getChildNodes()));

                ac_e.addAttack_Right(attack_scale, attack_type, attRDrops);
            }

            Node attack_left = getNode(ATTACK_LEFT, stats.getChildNodes());

            if (attack_left != null) {
                String attack_scale = getNodeValue(SCALING, attack_left.getChildNodes());
                String attack_type = getNodeValue(TYPE, attack_left.getChildNodes());
                ArrayList<Component> attLDrops = getDrops(getNode(DROP_LIST, attack_left.getChildNodes()));

                ac_e.addAttack_Left(attack_scale, attack_type, attLDrops);
            }

            this.creatures.put(ac_e.name, ac_e);

        }
    }

    private ArrayList<Component> getDrops(Node dropList) {
        ArrayList<Component> drops = new ArrayList<Component>();

        if (dropList == null)
            return drops;

        for (int i = 0; i < dropList.getChildNodes().getLength(); i++) {
            Node n = dropList.getChildNodes().item(i);

            if (n.getNodeName().equalsIgnoreCase(DROP)) {
                drops.add(getComponent(n));
            }
        }

        return drops;
    }

    private Component getComponent(Node dropNode) {
        String typeString = getNodeValue(TYPE, dropNode.getChildNodes());
        Component_Type type = Component.convertComponentType(typeString);

        String name = getNodeValue(NAME, dropNode.getChildNodes());

        String icon = getNodeValue(ICON, dropNode.getChildNodes());

        String rarityString = getNodeValue(RARITY, dropNode.getChildNodes());
        int rarity = Integer.parseInt(rarityString);

        String chanceString = getNodeValue(CHANCE, dropNode.getChildNodes());
        int chance = Integer.parseInt(chanceString);

        String description = getNodeValue(DESCRIPTION, dropNode.getChildNodes());

        String weightString = getNodeValue(WEIGHT_PER_AMOUNT, dropNode.getChildNodes());
        int weight_per_amount = Integer.parseInt(weightString);

        String amountString = getNodeValue(AMOUNT, dropNode.getChildNodes());
        int amount = Integer.parseInt(amountString);

        String softString = getNodeValue(SOFT_HARD, dropNode.getChildNodes());
        int soft_hard = Integer.parseInt(softString);

        String flexibleString = getNodeValue(FLEXIBLE_BRITTLE, dropNode.getChildNodes());
        int flexible_brittle = Integer.parseInt(flexibleString);

        Node ele = getNode(ELEMENT, dropNode.getChildNodes());
        String f = getNodeValue(FIRE, ele.getChildNodes());
        String wa = getNodeValue(WATER, ele.getChildNodes());
        String ai = getNodeValue(AIR, ele.getChildNodes());
        String wo = getNodeValue(WOOD, ele.getChildNodes());
        String m = getNodeValue(METAL, ele.getChildNodes());
        String ae = getNodeValue(AETHER, ele.getChildNodes());
        String v = getNodeValue(VOID, ele.getChildNodes());
        HashMap<Element, Integer> element = new HashMap<Element, Integer>();
        element.put(Element.FIRE, Integer.parseInt(f));
        element.put(Element.WATER, Integer.parseInt(wa));
        element.put(Element.AIR, Integer.parseInt(ai));
        element.put(Element.WOOD, Integer.parseInt(wo));
        element.put(Element.METAL, Integer.parseInt(m));
        element.put(Element.AETHER, Integer.parseInt(ae));
        element.put(Element.VOID, Integer.parseInt(v));

        Component drop = new Component(type, name, rarity, chance, description, weight_per_amount, amount,
                soft_hard, flexible_brittle, element, icon);

        return drop;
    }

    public GameActor getMonster(int difficulty, Level level) {
        Creature_Evolver ce = EVOLVED_CREATURES[difficulty];

        float scale = ce.creature.model_scale;
        Color colour = ce.creature.colour;
        String texture = ce.creature.texture;

        GameActor ga = new Enemy(colour, texture, 0, 0, 0, scale, GL20.GL_TRIANGLES, "file",
                ce.creature.model_name);
        for (Component c : ce.creature.skinDrops) {
            ga.INVENTORY.put(c.drop_chance, c);
        }
        for (Component c : ce.creature.boneDrops) {
            ga.INVENTORY.put(c.drop_chance, c);
        }
        if (ce.attack_right != null) {
            ga.R_HAND = Equipment_HAND.getWeapon(ce.attack_right.wep_type, ce.attack_right.wep_visual,
                    ce.attack_right.wep_style, ce.attack_right.strength, ce.attack_right.ele_amount,
                    ce.attack_right.dam_amount, ce.attack_right.atk_speed, ce.attack_right.weight, false, 2, 1,
                    level);
            for (Component c : ce.creature.attRDrops) {
                ga.INVENTORY.put(c.drop_chance, c);
            }
        }
        if (ce.attack_left != null) {
            ga.L_HAND = Equipment_HAND.getWeapon(ce.attack_left.wep_type, ce.attack_left.wep_visual,
                    ce.attack_left.wep_style, ce.attack_left.strength, ce.attack_left.ele_amount,
                    ce.attack_left.dam_amount, ce.attack_left.atk_speed, ce.attack_left.weight, false, 2, 1, level);
            for (Component c : ce.creature.attLDrops) {
                ga.INVENTORY.put(c.drop_chance, c);
            }
        }

        ga.setStats(ce.health, ce.weight, ce.strength, ce.ele_defenses, ce.dam_defenses, ce.creature.factions);

        ga.ai = ce.mind.ai.getAI(ga);

        return ga;
    }

    transient EvolverTile[][] grid = new EvolverTile[EVOLVER_WIDTH][EVOLVER_HEIGHT];

    public void createMap() {
        for (int x = 0; x < EVOLVER_WIDTH; x++) {
            for (int y = 0; y < EVOLVER_HEIGHT; y++) {
                grid[x][y] = new EvolverTile(x, y);
            }
        }
    }

    public Creature_Evolver[] EVOLVED_CREATURES = new Creature_Evolver[10];

    public void Evolve_Creature() {
        for (int j = 0; j < 10; j++) {

            Creature_Evolver best = null;
            while (true) {

                for (int ii = 0; ii < EVOLVER_CREATURE_TURNS; ii++) {
                    for (int x = 0; x < EVOLVER_WIDTH; x++) {
                        for (int y = 0; y < EVOLVER_HEIGHT; y++) {
                            grid[x][y].food = false;
                            grid[x][y].creature = null;
                        }
                    }
                }

                for (int i = 0; i < 25; i++) {
                    grid[ran.nextInt(EVOLVER_WIDTH)][ran.nextInt(EVOLVER_HEIGHT)].food = true;
                }

                for (int ii = 0; ii < EVOLVER_CREATURE_NUM; ii++) {
                    int x = ran.nextInt(EVOLVER_WIDTH);
                    int y = ran.nextInt(EVOLVER_HEIGHT);
                    if (j == 0)
                        grid[x][y].creature = createCreature(j);
                    else
                        grid[x][y].creature = recreateCreature(j);

                    grid[x][y].creature.x = x;
                    grid[x][y].creature.y = y;
                }

                ArrayList<Creature_Evolver> creatures = new ArrayList<Creature_Evolver>();
                for (int ii = 0; ii < EVOLVER_CREATURE_TURNS; ii++) {
                    for (int x = 0; x < EVOLVER_WIDTH; x++) {
                        for (int y = 0; y < EVOLVER_HEIGHT; y++) {
                            if (grid[x][y].creature != null) {
                                creatures.add(grid[x][y].creature);
                            }
                        }
                    }

                    for (Creature_Evolver c_e : creatures) {
                        c_e.update(grid);
                    }
                }

                int best_points = 0;

                for (int x = 0; x < EVOLVER_WIDTH; x++) {
                    for (int y = 0; y < EVOLVER_HEIGHT; y++) {
                        if (grid[x][y].creature != null && grid[x][y].creature.points >= best_points) {
                            best = grid[x][y].creature;
                            best_points = best.points;
                        }
                    }
                }

                if (best != null)
                    break;
            }

            EVOLVED_CREATURES[j] = best;
            System.out.println("Creature Evolved for Difficulty " + j);
            System.out.println(EVOLVED_CREATURES[j]);

        }
    }

    private Creature_Evolver createCreature(int difficulty) {
        Node abs = getNode(ABSTRACT, selected_monster.getChildNodes());
        Node abstractList = getNode(DIFFICULTY + difficulty, abs.getChildNodes());
        AbstractCreature_Evolver creature = creatures.get(getNodeValue(CREATURE, abstractList.getChildNodes()));
        int calorie_usage = Integer.parseInt(getNodeValue(CALORIE_USAGE, abstractList.getChildNodes()));

        Creature_Evolver c_e = new Creature_Evolver(creature, calorie_usage, 0, 0);
        c_e.addAttributes(getMind(creature), getSkin(creature), getBones(creature), getMuscles(creature),
                getAttackRight(creature), getAttackLeft(creature));

        while (c_e.calorie_usage_base < c_e.calorie_usage) {
            c_e = new Creature_Evolver(creature, calorie_usage, 0, 0);
            c_e.addAttributes(getMind(creature), getSkin(creature), getBones(creature), getMuscles(creature),
                    getAttackRight(creature), getAttackLeft(creature));
        }

        return c_e;
    }

    private Creature_Evolver recreateCreature(int difficulty) {
        Node abstractList = getNode(DIFFICULTY + difficulty,
                getNode(ABSTRACT, selected_monster.getChildNodes()).getChildNodes());
        AbstractCreature_Evolver creature = creatures.get(getNodeValue(CREATURE, abstractList.getChildNodes()));
        int calorie_usage = Integer.parseInt(getNodeValue(CALORIE_USAGE, abstractList.getChildNodes()));

        Creature_Evolver c_e = new Creature_Evolver(creature, calorie_usage, 0, 0);
        EVOLVED_CREATURES[difficulty - 1].nextEvolution(c_e, this);

        while (c_e.calorie_usage_base < c_e.calorie_usage) {
            EVOLVED_CREATURES[difficulty - 1].nextEvolution(c_e, this);
        }

        return c_e;
    }

    public Mind_Evolver getMind(AbstractCreature_Evolver creature) {
        Node mind = getNode(creature.mind_type, getNode(MIND, attribute_root.getChildNodes()).getChildNodes());

        ArrayList<Node> valid = new ArrayList<Node>();
        for (int i = 0; i < mind.getChildNodes().getLength(); i++) {
            Node n = mind.getChildNodes().item(i);

            if (n.getNodeType() == Node.TEXT_NODE)
                continue;

            valid.add(n);
        }

        Node selected = valid.get(ran.nextInt(valid.size()));

        Mind_Evolver m_e = new Mind_Evolver(selected.getNodeName());

        m_e.addAI(getNodeValue(AI, selected.getChildNodes()));

        return m_e;
    }

    public Skin_Evolver getSkin(AbstractCreature_Evolver creature) {
        Node skin = getNode(creature.skin_type, getNode(SKIN, attribute_root.getChildNodes()).getChildNodes());
        ArrayList<Node> valid = new ArrayList<Node>();
        for (int i = 0; i < skin.getChildNodes().getLength(); i++) {
            Node n = skin.getChildNodes().item(i);

            if (n.getNodeType() == Node.TEXT_NODE)
                continue;

            valid.add(n);
        }

        Node selected = valid.get(ran.nextInt(valid.size()));

        Skin_Evolver s_e = new Skin_Evolver(selected.getNodeName());

        s_e.addDescription(getNodeValue(DESCRIPTION, selected.getChildNodes()));

        s_e.addStats(getNodeValue(CALORIES, selected.getChildNodes()),
                getNodeValue(WEIGHT, selected.getChildNodes()), getNodeValue(HEALTH, selected.getChildNodes()),
                getNodeValue(STRENGTH, selected.getChildNodes()));

        Node ele_def = getNode(ELE_DEFENSES, selected.getChildNodes());
        s_e.addEleDef(getNodeValue(FIRE, ele_def.getChildNodes()), getNodeValue(WATER, ele_def.getChildNodes()),
                getNodeValue(AIR, ele_def.getChildNodes()), getNodeValue(WOOD, ele_def.getChildNodes()),
                getNodeValue(METAL, ele_def.getChildNodes()), getNodeValue(AETHER, ele_def.getChildNodes()),
                getNodeValue(VOID, ele_def.getChildNodes()));

        Node dam_def = getNode(DEFENSES, selected.getChildNodes());
        s_e.addDamDef(getNodeValue(PIERCE, dam_def.getChildNodes()), getNodeValue(IMPACT, dam_def.getChildNodes()),
                getNodeValue(TOUCH, dam_def.getChildNodes()));

        return s_e;
    }

    public Bones_Evolver getBones(AbstractCreature_Evolver creature) {
        Node bones = getNode(creature.bones_type, getNode(BONES, attribute_root.getChildNodes()).getChildNodes());

        ArrayList<Node> valid = new ArrayList<Node>();
        for (int i = 0; i < bones.getChildNodes().getLength(); i++) {
            Node n = bones.getChildNodes().item(i);

            if (n.getNodeType() == Node.TEXT_NODE)
                continue;

            valid.add(n);
        }

        Node selected = valid.get(ran.nextInt(valid.size()));

        Bones_Evolver b_e = new Bones_Evolver(selected.getNodeName());

        b_e.addStats(getNodeValue(CALORIES, selected.getChildNodes()),
                getNodeValue(WEIGHT, selected.getChildNodes()), getNodeValue(HEALTH, selected.getChildNodes()));

        Node dam_def = getNode(DEFENSES, selected.getChildNodes());
        b_e.addDamDef(getNodeValue(PIERCE, dam_def.getChildNodes()), getNodeValue(IMPACT, dam_def.getChildNodes()),
                getNodeValue(TOUCH, dam_def.getChildNodes()));

        return b_e;
    }

    public Muscles_Evolver getMuscles(AbstractCreature_Evolver creature) {
        Node muscles = getNode(creature.muscles_type,
                getNode(MUSCLES, attribute_root.getChildNodes()).getChildNodes());

        ArrayList<Node> valid = new ArrayList<Node>();
        for (int i = 0; i < muscles.getChildNodes().getLength(); i++) {
            Node n = muscles.getChildNodes().item(i);

            if (n.getNodeType() == Node.TEXT_NODE)
                continue;

            valid.add(n);
        }

        Node selected = valid.get(ran.nextInt(valid.size()));

        Muscles_Evolver m_e = new Muscles_Evolver(selected.getNodeName());

        m_e.addStats(getNodeValue(CALORIES, selected.getChildNodes()),
                getNodeValue(WEIGHT, selected.getChildNodes()), getNodeValue(STRENGTH, selected.getChildNodes()));

        return m_e;
    }

    public Attack_Evolver getAttackLeft(AbstractCreature_Evolver creature) {
        Node attack = null;

        if (creature.left_equipped)
            attack = getNode(creature.attack_left_type,
                    getNode(ATTACK, attribute_root.getChildNodes()).getChildNodes());

        if (attack == null)
            return null;

        ArrayList<Node> valid = new ArrayList<Node>();
        for (int i = 0; i < attack.getChildNodes().getLength(); i++) {
            Node n = attack.getChildNodes().item(i);

            if (n.getNodeType() == Node.TEXT_NODE)
                continue;

            valid.add(n);
        }

        Node selected = valid.get(ran.nextInt(valid.size()));

        Attack_Evolver a_e = new Attack_Evolver(selected.getNodeName());

        a_e.addDescription(getNodeValue(DESCRIPTION, selected.getChildNodes()));

        a_e.addStats(getNodeValue(CALORIES, selected.getChildNodes()),
                getNodeValue(WEIGHT, selected.getChildNodes()), getNodeValue(STRENGTH, selected.getChildNodes()),
                getNodeValue(ATTACK_SPEED, selected.getChildNodes()),
                getNodeValue(ATTACK_DIST_MIN, selected.getChildNodes()),
                getNodeValue(ATTACK_DIST_MAX, selected.getChildNodes()),
                getNodeValue(WEAPON_TYPE, selected.getChildNodes()),
                getNodeValue(WEAPON_VISUAL, selected.getChildNodes()),
                getNodeValue(WEAPON_STYLE, selected.getChildNodes()));

        Node element = getNode(ELEMENT, selected.getChildNodes());
        a_e.addElements(getNodeValue(PIERCE, selected.getChildNodes()),
                getNodeValue(IMPACT, selected.getChildNodes()), getNodeValue(TOUCH, selected.getChildNodes()),
                getNodeValue(FIRE, element.getChildNodes()), getNodeValue(WATER, element.getChildNodes()),
                getNodeValue(AIR, element.getChildNodes()), getNodeValue(WOOD, element.getChildNodes()),
                getNodeValue(METAL, element.getChildNodes()), getNodeValue(AETHER, element.getChildNodes()),
                getNodeValue(VOID, element.getChildNodes()));

        return a_e;
    }

    public Attack_Evolver getAttackRight(AbstractCreature_Evolver creature) {
        Node attack = null;

        if (creature.right_equipped)
            attack = getNode(creature.attack_right_type,
                    getNode(ATTACK, attribute_root.getChildNodes()).getChildNodes());

        if (attack == null)
            return null;

        ArrayList<Node> valid = new ArrayList<Node>();
        for (int i = 0; i < attack.getChildNodes().getLength(); i++) {
            Node n = attack.getChildNodes().item(i);

            if (n.getNodeType() == Node.TEXT_NODE)
                continue;

            valid.add(n);
        }

        Node selected = valid.get(ran.nextInt(valid.size()));

        Attack_Evolver a_e = new Attack_Evolver(selected.getNodeName());

        a_e.addDescription(getNodeValue(DESCRIPTION, selected.getChildNodes()));

        a_e.addStats(getNodeValue(CALORIES, selected.getChildNodes()),
                getNodeValue(WEIGHT, selected.getChildNodes()), getNodeValue(STRENGTH, selected.getChildNodes()),
                getNodeValue(ATTACK_SPEED, selected.getChildNodes()),
                getNodeValue(ATTACK_DIST_MIN, selected.getChildNodes()),
                getNodeValue(ATTACK_DIST_MAX, selected.getChildNodes()),
                getNodeValue(WEAPON_TYPE, selected.getChildNodes()),
                getNodeValue(WEAPON_VISUAL, selected.getChildNodes()),
                getNodeValue(WEAPON_STYLE, selected.getChildNodes()));

        Node element = getNode(ELEMENT, selected.getChildNodes());
        a_e.addElements(getNodeValue(PIERCE, selected.getChildNodes()),
                getNodeValue(IMPACT, selected.getChildNodes()), getNodeValue(TOUCH, selected.getChildNodes()),
                getNodeValue(FIRE, element.getChildNodes()), getNodeValue(WATER, element.getChildNodes()),
                getNodeValue(AIR, element.getChildNodes()), getNodeValue(WOOD, element.getChildNodes()),
                getNodeValue(METAL, element.getChildNodes()), getNodeValue(AETHER, element.getChildNodes()),
                getNodeValue(VOID, element.getChildNodes()));

        return a_e;
    }
}

class EvolverTile {
    int x;
    int y;

    public EvolverTile(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public boolean food = false;

    public Creature_Evolver creature = null;
}

class Creature_Evolver implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 7925461195208826620L;
    public transient static final int FEED_DURATION = 5;
    public transient static final int FOOD_CALORIES = 200;

    public transient final Random ran = new Random();

    public int consumed_calories = 100;
    public int points = 0;

    public Mind_Evolver mind;
    public Skin_Evolver skin;
    public Bones_Evolver bones;
    public Muscles_Evolver muscles;
    public Attack_Evolver attack_right;
    public Attack_Evolver attack_left;

    public final AbstractCreature_Evolver creature;

    public final int calorie_usage_base;

    public int calorie_usage;
    public int health;
    public int weight;
    public int strength;

    public HashMap<Element, Integer> ele_defenses;
    public HashMap<Damage_Type, Integer> dam_defenses;

    public float atk_cooldown_right;
    public float atk_cooldown_left;
    public int current_health;

    /**
     * up, down, left, right
     */
    public transient boolean[] rotation = new boolean[4];

    public transient int x;
    public transient int y;

    public Creature_Evolver(AbstractCreature_Evolver creature, int calorie_usage, int x, int y) {
        this.x = x;
        this.y = y;
        this.calorie_usage_base = calorie_usage + creature.base_calories;
        this.creature = creature;

        rotation[ran.nextInt(4)] = true;
    }

    transient int feedCountdown = 0;

    public void update(EvolverTile[][] grid) {
        //      if (calorie_usage/10 > consumed_calories)
        //      {
        //         consumed_calories = 0;
        //         current_health -= calorie_usage/10;
        //
        //         if (current_health < 0)
        //         {
        //            //System.out.println("Creature died of Starvation!");
        //            //System.out.println(this);
        //            grid[x][y].creature = null;
        //            return;
        //         }
        //      }
        //      else
        //      {
        //         consumed_calories -= calorie_usage/10;
        //      }

        if (feedCountdown > 0) {
            feedCountdown--;

            if (feedCountdown == 0) {
                points++;
                consumed_calories += FOOD_CALORIES;
                grid[x][y].food = false;
            }

            return;
        }

        if (grid[x][y].food) {
            feedCountdown = FEED_DURATION;
        }

        int[] move = mind.ai.evaluate(grid, this);

        if (move[0] == 0 && move[1] == 0)
            return;
        if (x + move[0] < 0 || x + move[0] >= grid.length || y + move[1] < 0 || y + move[1] >= grid[0].length) {
            return;
        }

        grid[x][y].creature = null;

        x += move[0];
        y += move[1];

        if (move[0] == 1) {
            rotation[0] = false;
            rotation[1] = false;
            rotation[2] = false;
            rotation[3] = true;
        } else if (move[0] == -1) {
            rotation[0] = false;
            rotation[1] = false;
            rotation[2] = true;
            rotation[3] = false;
        } else if (move[1] == 1) {
            rotation[0] = true;
            rotation[1] = false;
            rotation[2] = false;
            rotation[3] = false;
        } else if (move[1] == -1) {
            rotation[0] = false;
            rotation[1] = true;
            rotation[2] = false;
            rotation[3] = false;
        }

        if (grid[x][y].creature == null)
            grid[x][y].creature = this;
        else {
            Evolver_Combat combat = new Evolver_Combat(this, grid[x][y].creature);

            if (combat.didC1WIN()) {
                // kill
                if (grid[x][y].creature.current_health <= 0) {
                    //System.out.println("Died!");
                    //System.out.println(grid[x][y].creature);
                    points += grid[x][y].creature.points;
                    consumed_calories += grid[x][y].creature.consumed_calories;
                    grid[x][y].creature = this;
                }
                // flee
                else {
                    if (checkFree(grid, x + 1, y)) {
                        grid[x][y].creature.x += 1;
                        grid[x + 1][y].creature = grid[x][y].creature;
                        grid[x][y].creature = this;
                    } else if (checkFree(grid, x - 1, y)) {
                        grid[x][y].creature.x -= 1;
                        grid[x - 1][y].creature = grid[x][y].creature;
                        grid[x][y].creature = this;
                    } else if (checkFree(grid, x, y + 1)) {
                        grid[x][y].creature.y += 1;
                        grid[x][y + 1].creature = grid[x][y].creature;
                        grid[x][y].creature = this;
                    } else if (checkFree(grid, x, y - 1)) {
                        grid[x][y].creature.y -= 1;
                        grid[x][y - 1].creature = grid[x][y].creature;
                        grid[x][y].creature = this;
                    } else {
                        points += grid[x][y].creature.points;
                        consumed_calories += grid[x][y].creature.consumed_calories;
                        grid[x][y].creature = this;
                    }
                }
            } else {
                // kill
                if (current_health <= 0) {
                    //System.out.println("Died!");
                    //System.out.println(this);
                    grid[x][y].creature.points += points;
                    grid[x][y].creature.consumed_calories += consumed_calories;
                } else {
                    if (checkFree(grid, x + 1, y)) {
                        x += 1;
                        grid[x][y].creature = this;
                    } else if (checkFree(grid, x - 1, y)) {
                        x -= 1;
                        grid[x][y].creature = this;
                    } else if (checkFree(grid, x, y + 1)) {
                        y += 1;
                        grid[x][y].creature = this;
                    } else if (checkFree(grid, x, y - 1)) {
                        y -= 1;
                        grid[x][y].creature = this;
                    } else {
                        grid[x][y].creature.points += points;
                        grid[x][y].creature.consumed_calories += consumed_calories;
                    }
                }
            }
        }
    }

    private boolean checkFree(EvolverTile[][] grid, int x, int y) {
        //System.out.println("Check free evolver width/height "+ grid.length + "   " + grid[0].length);
        if (x < 0 || x >= grid.length - 1)
            return false;
        if (y < 0 || y >= grid[0].length - 1)
            return false;
        if (grid[x][y].creature != null)
            return false;

        return true;
    }

    public void addAttributes(Mind_Evolver mind, Skin_Evolver skin, Bones_Evolver bones, Muscles_Evolver muscles,
            Attack_Evolver attack_right, Attack_Evolver attack_left) {
        this.mind = mind;
        this.skin = skin;
        this.bones = bones;
        this.muscles = muscles;
        this.attack_right = attack_right;
        this.attack_left = attack_left;

        calculateStats();

        current_health = health;
        if (attack_right != null)
            atk_cooldown_right = attack_right.atk_speed;
        if (attack_left != null)
            atk_cooldown_left = attack_left.atk_speed;
    }

    public void calculateStats() {
        calorie_usage = (int) ((skin.calories * creature.skin_scale) + (bones.calories * creature.bones_scale)
                + (muscles.calories * creature.muscles_scale));
        if (attack_right != null)
            calorie_usage += (attack_right.calories * creature.attack_right_scale);
        if (attack_left != null)
            calorie_usage += (attack_left.calories * creature.attack_left_scale);

        health = creature.health + skin.health + bones.health;

        weight = creature.weight + skin.weight + bones.weight + muscles.weight;
        if (attack_right != null)
            weight += attack_right.weight;
        if (attack_left != null)
            weight += attack_left.weight;

        strength = creature.strength + skin.strength + muscles.strength;

        ele_defenses = new HashMap<Element, Integer>();
        Element element = Element.FIRE;
        ele_defenses.put(element, creature.eleDef.get(element) + skin.eleDef.get(element));
        element = Element.WATER;
        ele_defenses.put(element, creature.eleDef.get(element) + skin.eleDef.get(element));
        element = Element.AIR;
        ele_defenses.put(element, creature.eleDef.get(element) + skin.eleDef.get(element));
        element = Element.WOOD;
        ele_defenses.put(element, creature.eleDef.get(element) + skin.eleDef.get(element));
        element = Element.METAL;
        ele_defenses.put(element, creature.eleDef.get(element) + skin.eleDef.get(element));
        element = Element.AETHER;
        ele_defenses.put(element, creature.eleDef.get(element) + skin.eleDef.get(element));
        element = Element.VOID;
        ele_defenses.put(element, creature.eleDef.get(element) + skin.eleDef.get(element));

        dam_defenses = new HashMap<Damage_Type, Integer>();
        Damage_Type dam_type = Damage_Type.PIERCE;
        dam_defenses.put(dam_type,
                creature.damDef.get(dam_type) + skin.damDef.get(dam_type) + bones.damDef.get(dam_type));
        dam_type = Damage_Type.IMPACT;
        dam_defenses.put(dam_type,
                creature.damDef.get(dam_type) + skin.damDef.get(dam_type) + bones.damDef.get(dam_type));
        dam_type = Damage_Type.TOUCH;
        dam_defenses.put(dam_type,
                creature.damDef.get(dam_type) + skin.damDef.get(dam_type) + bones.damDef.get(dam_type));
    }

    public Creature_Evolver cpy() {
        Creature_Evolver c_e = new Creature_Evolver(creature, calorie_usage_base - creature.base_calories, 0, 0);
        c_e.addAttributes(mind, skin, bones, muscles, attack_right, attack_left);

        return c_e;
    }

    public void matchAttributes(Creature_Evolver creature) {
        creature.addAttributes(mind, skin, bones, muscles, attack_right, attack_left);
    }

    public void nextEvolution(Creature_Evolver c_e, MonsterEvolver evolver) {
        Skin_Evolver nSkin = skin;
        Bones_Evolver nBones = bones;
        Muscles_Evolver nMuscles = muscles;
        Attack_Evolver nLeft_Attack = attack_left;
        Attack_Evolver nRight_Attack = attack_right;

        for (int i = 0; i < 2; i++) {
            int change = ran.nextInt(4);

            if (change == 0) {
                nSkin = evolver.getSkin(c_e.creature);
            } else if (change == 1) {
                nBones = evolver.getBones(c_e.creature);
            } else if (change == 2) {
                nMuscles = evolver.getMuscles(c_e.creature);
            } else {
                nLeft_Attack = evolver.getAttackLeft(c_e.creature);
                nRight_Attack = evolver.getAttackRight(c_e.creature);
            }
        }

        c_e.addAttributes(mind, nSkin, nBones, nMuscles, nRight_Attack, nLeft_Attack);
    }

    @Override
    public String toString() {
        return "--------------------------------------------" + "\n" + "Creature name: " + creature.name + "\n"
                + "Points earned: " + points + "\n" + "Total Calories: " + calorie_usage + "\n" + "Max Health: "
                + health + "\n" + "Weight: " + weight + "\n" + "Strength: " + strength + "\n" + "Mind: " + mind
                + "\n" + "Skin: " + skin + "\n" + "Bones: " + bones + "\n" + "Muscles: " + muscles + "\n"
                + "Attack Left: " + attack_left + "\n" + "Attack Right: " + attack_right + "\n"
                + "--------------------------------------------";
    }
}

class AbstractCreature_Evolver implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 5735799594872194576L;
    public final String name;
    public final ArrayList<String> factions;

    public AbstractCreature_Evolver(String name, ArrayList<String> factions) {
        this.factions = factions;
        this.name = name;
    }

    transient NodeList description;
    String model_type;
    String model_name;
    float model_scale;
    String texture;
    Color colour;

    public void addVisual(NodeList description, String model_type, String model_name, String model_scale,
            String texture, String r, String g, String b) {
        this.description = description;
        this.model_type = model_type;
        this.model_name = model_name;
        this.model_scale = Float.parseFloat(model_scale);
        this.texture = texture;
        this.colour = new Color(Float.parseFloat(r), Float.parseFloat(g), Float.parseFloat(b), 1.0f);
    }

    int base_calories;
    int weight;
    int health;
    int strength;

    public void addStats(String base_calories, String weight, String health, String strength) {
        this.base_calories = Integer.parseInt(base_calories);
        this.weight = Integer.parseInt(weight);
        this.health = Integer.parseInt(health);
        this.strength = Integer.parseInt(strength);
    }

    HashMap<Element, Integer> eleDef;

    public void addEleDef(String fire, String water, String air, String wood, String metal, String aether,
            String VOID) {
        eleDef = new HashMap<Element, Integer>();

        eleDef.put(Element.FIRE, Integer.parseInt(fire));
        eleDef.put(Element.WATER, Integer.parseInt(water));
        eleDef.put(Element.AIR, Integer.parseInt(air));
        eleDef.put(Element.WOOD, Integer.parseInt(wood));
        eleDef.put(Element.METAL, Integer.parseInt(metal));
        eleDef.put(Element.AETHER, Integer.parseInt(aether));
        eleDef.put(Element.VOID, Integer.parseInt(VOID));
    }

    HashMap<Damage_Type, Integer> damDef;

    public void addDamDef(String pierce, String impact, String touch) {
        damDef = new HashMap<Damage_Type, Integer>();

        damDef.put(Damage_Type.PIERCE, Integer.parseInt(pierce));
        damDef.put(Damage_Type.IMPACT, Integer.parseInt(impact));
        damDef.put(Damage_Type.TOUCH, Integer.parseInt(touch));

    }

    float mind_scale;
    String mind_type;

    public void addMind(String scale, String type) {
        this.mind_scale = Float.parseFloat(scale);
        this.mind_type = type;
    }

    float skin_scale;
    String skin_type;
    ArrayList<Component> skinDrops;

    public void addSkin(String scale, String type, ArrayList<Component> drops) {
        this.skin_scale = Float.parseFloat(scale);
        this.skin_type = type;
        this.skinDrops = drops;
    }

    float bones_scale;
    String bones_type;
    ArrayList<Component> boneDrops;

    public void addBones(String scale, String type, ArrayList<Component> drops) {
        this.bones_scale = Float.parseFloat(scale);
        this.bones_type = type;
        this.boneDrops = drops;
    }

    float muscles_scale;
    String muscles_type;

    public void addMuscles(String scale, String type) {
        this.muscles_scale = Float.parseFloat(scale);
        this.muscles_type = type;
    }

    float attack_right_scale;
    String attack_right_type;
    boolean right_equipped = false;
    ArrayList<Component> attRDrops;

    public void addAttack_Right(String scale, String type, ArrayList<Component> drops) {
        this.right_equipped = true;
        this.attack_right_scale = Float.parseFloat(scale);
        this.attack_right_type = type;
        this.attRDrops = drops;
    }

    float attack_left_scale;
    String attack_left_type;
    boolean left_equipped = false;
    ArrayList<Component> attLDrops;

    public void addAttack_Left(String scale, String type, ArrayList<Component> drops) {
        this.left_equipped = true;
        this.attack_left_scale = Float.parseFloat(scale);
        this.attack_left_type = type;
        this.attLDrops = drops;
    }
}

class Mind_Evolver implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = -2447742508198331316L;
    String name;

    public Mind_Evolver(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name + "\n" + ai;
    }

    public enum AI_Evolver {
        VFFG
    }

    AI_Evolver ai_type;
    AI_Evolver_Package ai;

    public void addAI(String ai) {
        Random ran = new Random();
        if (ai.equalsIgnoreCase("VFFG")) {
            this.ai_type = AI_Evolver.VFFG;
            this.ai = new AI_Evolver_VFFG(ran.nextInt(101), ran.nextInt(101), ran.nextInt(101), ran.nextInt(101));
        }
    }
}

class Skin_Evolver implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = -8441346867369627207L;
    String name;

    public Skin_Evolver(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }

    String description;

    public void addDescription(String description) {
        this.description = description;
    }

    int calories;
    int weight;
    int health;
    int strength;

    public void addStats(String calories, String weight, String health, String strength) {
        this.calories = Integer.parseInt(calories);
        this.weight = Integer.parseInt(weight);
        this.health = Integer.parseInt(health);
        this.strength = Integer.parseInt(strength);
    }

    HashMap<Element, Integer> eleDef;

    public void addEleDef(String fire, String water, String air, String wood, String metal, String aether,
            String VOID) {
        eleDef = new HashMap<Element, Integer>();

        eleDef.put(Element.FIRE, Integer.parseInt(fire));
        eleDef.put(Element.WATER, Integer.parseInt(water));
        eleDef.put(Element.AIR, Integer.parseInt(air));
        eleDef.put(Element.WOOD, Integer.parseInt(wood));
        eleDef.put(Element.METAL, Integer.parseInt(metal));
        eleDef.put(Element.AETHER, Integer.parseInt(aether));
        eleDef.put(Element.VOID, Integer.parseInt(VOID));
    }

    HashMap<Damage_Type, Integer> damDef;

    public void addDamDef(String pierce, String impact, String touch) {
        damDef = new HashMap<Damage_Type, Integer>();

        damDef.put(Damage_Type.PIERCE, Integer.parseInt(pierce));
        damDef.put(Damage_Type.IMPACT, Integer.parseInt(impact));
        damDef.put(Damage_Type.TOUCH, Integer.parseInt(touch));

    }
}

class Bones_Evolver implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 2354864208762217473L;
    String name;

    public Bones_Evolver(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }

    int calories;
    int weight;
    int health;

    public void addStats(String calories, String weight, String health) {
        this.calories = Integer.parseInt(calories);
        this.weight = Integer.parseInt(weight);
        this.health = Integer.parseInt(health);
    }

    HashMap<Damage_Type, Integer> damDef;

    public void addDamDef(String pierce, String impact, String touch) {
        damDef = new HashMap<Damage_Type, Integer>();

        damDef.put(Damage_Type.PIERCE, Integer.parseInt(pierce));
        damDef.put(Damage_Type.IMPACT, Integer.parseInt(impact));
        damDef.put(Damage_Type.TOUCH, Integer.parseInt(touch));

    }
}

class Muscles_Evolver implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = -4784108714291815658L;
    String name;

    public Muscles_Evolver(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }

    int calories;
    int weight;
    int strength;

    public void addStats(String calories, String weight, String strength) {
        this.calories = Integer.parseInt(calories);
        this.weight = Integer.parseInt(weight);
        this.strength = Integer.parseInt(strength);
    }
}

class Attack_Evolver implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 6632103730316200474L;
    String name;

    public Attack_Evolver(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }

    String description;

    public void addDescription(String description) {
        this.description = description;
    }

    int calories;
    int weight;
    int strength;
    float atk_speed;
    float atk_dst_min;
    float atk_dst_max;
    WeaponType wep_type;
    String wep_style;
    String wep_visual;

    public void addStats(String calories, String weight, String strength, String atk_speed, String atk_dst_min,
            String atk_dst_max, String wep_type, String wep_visual, String wep_style) {
        this.calories = Integer.parseInt(calories);
        this.weight = Integer.parseInt(weight);
        this.strength = Integer.parseInt(strength);
        this.atk_speed = Float.parseFloat(atk_speed);
        this.atk_dst_min = Float.parseFloat(atk_dst_min);
        this.atk_dst_max = Float.parseFloat(atk_dst_max);
        this.wep_type = Equipment_HAND.convertStringtoWepType(wep_type);
        this.wep_visual = wep_visual;
        this.wep_style = wep_style;
    }

    public HashMap<Element, Integer> ele_amount = new HashMap<Element, Integer>();
    public HashMap<Damage_Type, Integer> dam_amount = new HashMap<Damage_Type, Integer>();

    public void addElements(String pierce, String impact, String touch, String FIRE, String WATER, String AIR,
            String WOOD, String METAL, String AETHER, String VOID) {
        dam_amount.put(Damage_Type.PIERCE, Integer.parseInt(pierce));
        dam_amount.put(Damage_Type.IMPACT, Integer.parseInt(impact));
        dam_amount.put(Damage_Type.TOUCH, Integer.parseInt(touch));
        ele_amount.put(Element.FIRE, Integer.parseInt(FIRE));
        ele_amount.put(Element.WATER, Integer.parseInt(WATER));
        ele_amount.put(Element.AIR, Integer.parseInt(AIR));
        ele_amount.put(Element.WOOD, Integer.parseInt(WOOD));
        ele_amount.put(Element.METAL, Integer.parseInt(METAL));
        ele_amount.put(Element.AETHER, Integer.parseInt(AETHER));
        ele_amount.put(Element.VOID, Integer.parseInt(VOID));
    }
}

abstract class AI_Evolver_Package implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 6268009811093340625L;
    public transient static final int SIGHT_DIST = 4;

    public abstract int[] evaluate(EvolverTile[][] grid, Creature_Evolver entity);

    public abstract int evaluateCombatAttack();

    public abstract int evaluateCombatFlee();

    public abstract String getToString();

    public abstract AI_Package getAI(GameActor actor);

    @Override
    public String toString() {
        return getToString();
    }

    transient int[] array = new int[2];
    transient int view = SIGHT_DIST;
    transient int startx = 0;
    transient int starty = 0;
    transient int x = startx;
    transient int y = starty;

    public ArrayList<EvolverTile> getInterestingTiles(EvolverTile[][] grid, Creature_Evolver entity) {
        ArrayList<EvolverTile> interesting = new ArrayList<EvolverTile>();

        view = SIGHT_DIST;

        startx = entity.x;
        starty = entity.y;

        x = startx;
        y = starty;

        for (int i = 0; i < view; i++) {
            int[] move = iterateDir(entity.rotation, array);
            x += move[0];
            y += move[1];

            if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length)
                break;

            EvolverTile tile = grid[x][y];

            if (tile.food)
                interesting.add(tile);
            else if (tile.creature != null)
                interesting.add(tile);
        }

        view = SIGHT_DIST;
        startx = entity.x;
        starty = entity.y;
        for (int j = 0; j < SIGHT_DIST; j++) {
            int[] offset = iterateFOVSide1(entity.rotation, array);

            startx += offset[0];
            starty += offset[1];

            x = startx;
            y = starty;

            view -= 1;

            for (int i = 0; i < view; i++) {
                int[] move = iterateDir(entity.rotation, array);
                x += move[0];
                y += move[1];

                if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length)
                    break;

                EvolverTile tile = grid[x][y];

                if (tile.food)
                    interesting.add(tile);
                else if (tile.creature != null)
                    interesting.add(tile);
            }
        }

        view = SIGHT_DIST;
        startx = entity.x;
        starty = entity.y;
        for (int j = 0; j < SIGHT_DIST; j++) {
            int[] offset = iterateFOVSide2(entity.rotation, array);

            startx += offset[0];
            starty += offset[1];

            x = startx;
            y = starty;

            view -= 1;

            for (int i = 0; i < view; i++) {
                int[] move = iterateDir(entity.rotation, array);
                x += move[0];
                y += move[1];

                if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length)
                    break;

                EvolverTile tile = grid[x][y];

                if (tile.food)
                    interesting.add(tile);
                else if (tile.creature != null)
                    interesting.add(tile);
            }
        }

        return interesting;
    }

    private int[] iterateFOVSide1(boolean[] rotation, int[] itr) {
        if (rotation[0]) {
            itr[1] = 1;
            itr[0] = 1;
        } else if (rotation[1]) {
            itr[1] = -1;
            itr[0] = 1;
        } else if (rotation[2]) {
            itr[0] = -1;
            itr[1] = 1;
        } else {
            itr[0] = 1;
            itr[1] = 1;
        }

        return itr;
    }

    private int[] iterateFOVSide2(boolean[] rotation, int[] itr) {
        if (rotation[0]) {
            itr[1] = 1;
            itr[0] = -1;
        } else if (rotation[1]) {
            itr[1] = -1;
            itr[0] = -1;
        } else if (rotation[2]) {
            itr[0] = -1;
            itr[1] = -1;
        } else {
            itr[0] = 1;
            itr[1] = -1;
        }

        return itr;
    }

    private int[] iterateDir(boolean[] rotation, int[] itr) {
        if (rotation[0])
            itr[1] = 1;
        else if (rotation[1])
            itr[1] = -1;
        else if (rotation[2])
            itr[0] = -1;
        else
            itr[0] = 1;

        return itr;
    }
}

class AI_Evolver_VFFG extends AI_Evolver_Package {
    /**
     * 
     */
    private static final long serialVersionUID = 2161904739892927372L;

    int violence;
    int flee;
    int feed;
    int guard;

    public AI_Evolver_VFFG(int violence, int flee, int feed, int guard) {
        this.violence = violence;
        this.flee = flee;
        this.feed = feed;
        this.guard = guard;
    }

    public String getToString() {
        return "   Violence=" + violence + "\n" + "   Flee=" + flee + "\n" + "   Feed=" + feed + "\n" + "   Guard="
                + guard + "\n";
    }

    transient int[] target = new int[2];
    transient int wantMagnitude;
    transient int[] returnMove = new int[2];
    transient int diffX = 0;
    transient int diffY = 0;

    @Override
    public int[] evaluate(EvolverTile[][] grid, Creature_Evolver entity) {
        ArrayList<EvolverTile> interesting = super.getInterestingTiles(grid, entity);
        returnMove[0] = 0;
        returnMove[1] = 0;

        if (interesting.size() == 0) {
            diffX = (grid.length / 2) - entity.x;
            diffY = (grid[0].length / 2) - entity.y;

            if (diffX > diffY) {
                if (diffX > 0) {
                    returnMove[0] = 1;
                } else {
                    returnMove[0] = -1;
                }
            } else {
                if (diffY > 0) {
                    returnMove[1] = 1;
                } else {
                    returnMove[1] = -1;
                }
            }

            return returnMove;
        }

        wantMagnitude = calculateWantMagnitude(grid[target[0]][target[1]], entity.x, entity.y);
        wantMagnitude += (wantMagnitude / 100) * guard;

        for (EvolverTile t : interesting) {
            mag = calculateWantMagnitude(t, entity.x, entity.y);

            if (mag > wantMagnitude) {
                wantMagnitude = mag;
                target[0] = t.x;
                target[y] = t.y;
            }
        }

        diffX = target[0] - entity.x;
        diffY = target[1] - entity.y;

        if (diffX > diffY) {
            if (diffX > 0) {
                returnMove[0] = 1;
            } else {
                returnMove[0] = -1;
            }
        } else {
            if (diffY > 0) {
                returnMove[1] = 1;
            } else {
                returnMove[1] = -1;
            }
        }

        return returnMove;
    }

    transient int dist;
    transient int mag;

    public int calculateWantMagnitude(EvolverTile tile, int ex, int ey) {
        mag = 0;

        dist = ((tile.x - ex) * (tile.x - ex)) + ((tile.y - ey) * (tile.y - ey));

        if (tile.creature != null) {
            mag += (dist / 100) * violence;
        }
        if (tile.food) {
            mag += (dist / 100) * feed;
        }

        return mag;
    }

    @Override
    public int evaluateCombatAttack() {
        return violence;
    }

    @Override
    public int evaluateCombatFlee() {
        return flee;
    }

    @Override
    public AI_Package getAI(GameActor actor) {
        return new AI_Enemy_VFFG(actor, violence, flee, feed, guard);
    }

}

class Evolver_Combat {
    public static final int COMBAT_STEPS = 15;
    final Random ran = new Random();
    public static final float STAGE_LENGTH = 25;
    public static final float TIME_STEP = 0.5f;

    Creature_Evolver c1;
    Creature_Evolver c2;

    float c1X = 0;
    float c2X = STAGE_LENGTH;

    public Evolver_Combat(Creature_Evolver c1, Creature_Evolver c2) {
        this.c1 = c1;
        this.c2 = c2;
    }

    public boolean didC1WIN() {
        for (int i = 0; i < COMBAT_STEPS; i++) {
            c1.atk_cooldown_left -= TIME_STEP;
            c2.atk_cooldown_right -= TIME_STEP;
            c1X += evaluateAI(c1, c2, c1X, c2X);
            c2X += evaluateAI(c2, c1, c2X, c1X);

            if (c1.current_health <= 0) {
                //System.out.println("C1 died!");
                return false;
            } else if (c1X < 0 || c1X > STAGE_LENGTH) {
                //System.out.println("C1 fled!");
                return false;
            } else if (c2.current_health <= 0) {
                //System.out.println("C2 died!");
                return true;
            } else if (c2X < 0 || c2X > STAGE_LENGTH) {
                //System.out.println("C2 fled!");
                return true;
            }

        }

        return (c1.points > c2.points) ? true : false;
    }

    int v;
    int f;
    float move;

    public float evaluateAI(Creature_Evolver activeCreature, Creature_Evolver opponentCreature,
            float positionActive, float positionOpponent) {
        if (activeCreature.current_health <= 0 || opponentCreature.current_health <= 0)
            return 0;

        v = ran.nextInt(101) * activeCreature.mind.ai.evaluateCombatAttack()
                * (opponentCreature.health / opponentCreature.current_health);
        f = ran.nextInt(101) * activeCreature.mind.ai.evaluateCombatFlee()
                * (activeCreature.health / activeCreature.current_health);

        move = 1;
        if (v > f) {
            if (activeCreature.attack_left != null && activeCreature.atk_cooldown_left < 0) {
                if (Math.abs(positionActive - positionOpponent) < activeCreature.attack_left.atk_dst_max) {
                    if (Math.abs(positionActive - positionOpponent) > activeCreature.attack_left.atk_dst_min) {
                        int damage = GameData.calculateDamage(
                                activeCreature.strength + activeCreature.attack_left.strength,
                                activeCreature.attack_left.ele_amount, activeCreature.attack_left.dam_amount,
                                opponentCreature.ele_defenses, opponentCreature.dam_defenses);
                        opponentCreature.current_health -= damage;

                        activeCreature.atk_cooldown_left = activeCreature.attack_left.atk_speed;
                    } else {
                        if (positionActive > positionOpponent) {
                            move = GameData.calculateSpeed(activeCreature.weight, activeCreature.strength);
                        } else {
                            move = -GameData.calculateSpeed(activeCreature.weight, activeCreature.strength);
                        }
                    }
                } else {
                    if (positionActive < positionOpponent) {
                        move = GameData.calculateSpeed(activeCreature.weight, activeCreature.strength);
                    } else {
                        move = -GameData.calculateSpeed(activeCreature.weight, activeCreature.strength);
                    }
                }
            }

            if (activeCreature.attack_right != null && activeCreature.atk_cooldown_right < 0) {
                if (Math.abs(positionActive - positionOpponent) < activeCreature.attack_right.atk_dst_max) {
                    if (Math.abs(positionActive - positionOpponent) > activeCreature.attack_right.atk_dst_min) {
                        int damage = GameData.calculateDamage(
                                activeCreature.strength + activeCreature.attack_right.strength,
                                activeCreature.attack_right.ele_amount, activeCreature.attack_right.dam_amount,
                                opponentCreature.ele_defenses, opponentCreature.dam_defenses);
                        opponentCreature.current_health -= damage;

                        activeCreature.atk_cooldown_right = activeCreature.attack_right.atk_speed;
                    } else {
                        if (positionActive > positionOpponent) {
                            move = GameData.calculateSpeed(activeCreature.weight, activeCreature.strength);
                        } else {
                            move = -GameData.calculateSpeed(activeCreature.weight, activeCreature.strength);
                        }
                    }
                } else {
                    if (positionActive < positionOpponent) {
                        move = GameData.calculateSpeed(activeCreature.weight, activeCreature.strength);
                    } else {
                        move = -GameData.calculateSpeed(activeCreature.weight, activeCreature.strength);
                    }
                }
            }
        } else {
            if (positionActive > positionOpponent) {
                return GameData.calculateSpeed(activeCreature.weight, activeCreature.strength);
            } else {
                return -GameData.calculateSpeed(activeCreature.weight, activeCreature.strength);
            }
        }

        return move;
    }
}