egordorichev/LastTry

View on GitHub
core/src/org/egordorichev/lasttry/entity/CreatureInfo.java

Summary

Maintainability
C
1 day
Test Coverage
package org.egordorichev.lasttry.entity;

import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.JsonValue;
import org.egordorichev.lasttry.Globals;
import org.egordorichev.lasttry.entity.ai.AI;
import org.egordorichev.lasttry.entity.ai.AIManager;
import org.egordorichev.lasttry.entity.components.CreatureStateComponent;
import org.egordorichev.lasttry.entity.drop.Drop;
import org.egordorichev.lasttry.graphics.Animation;
import org.egordorichev.lasttry.graphics.AnimationFrame;
import org.egordorichev.lasttry.graphics.Assets;
import org.egordorichev.lasttry.injection.CoreRegistry;
import org.egordorichev.lasttry.injection.InjectionHelper;
import org.egordorichev.lasttry.item.Item;
import org.egordorichev.lasttry.item.ItemManager;
import org.egordorichev.lasttry.util.Rectangle;
import java.util.ArrayList;

/**
 * Because every creature is an instance, this json handler
 * is very different from other ones.
 * It loads all data into CreatureInfo fields, and creates
 * Creature from it
 */

public class CreatureInfo {
    /**
     * Creature ai
     */
    public AI ai;
    /**
     * Info about hp: normal, expert, hardmode
     */
    public int[] hp = new int[3];
    /**
     * Info about defense: normal, expert, hardmode
     */
    public int[] defense = new int[3];
    /**
     * Info about damage: normal, expert, hardmode
     */
    public int[] damage = new int[3];
    /**
     * Info about resistance to knockback
     */
    public float[] kbResist = new float[3];
    /**
     * Creature speed
     */
    public float speed = 1;
    /**
     * How much spawn will creature "eat"
     */
    public byte spawnWeight = 1;
    /**
     * Creature type: enemy, creature, npc, etc.
     * TODO: replace with string?
     */
    public byte type = 1;
    /**
     * Creature id
     */
    public String id;
    /**
     * Creature texture
     */
    public TextureRegion image;
    /**
     * Items, that creature drops on death
     */
    public ArrayList<Drop> drops = new ArrayList<>();
    /**
     * Creature hitbox (can be different from renderBounds)
     */
    public Rectangle hitbox = new Rectangle(0, 0, 16, 16);
    /**
     * Creature render bounds
     */
    public Rectangle renderBounds = new Rectangle(0, 0, 16, 16);
    /**
     * Animations of creature
     */
    public Animation[] animations = new Animation[CreatureStateComponent.State.values().length];
    /**
     * If the creature was copied from another one
     */
    private boolean copied = false;

    public CreatureInfo(JsonValue root, String id) throws Exception {
        this.id = id;

        for (int i = 0; i < this.animations.length; i++) {
            this.animations[i] = new Animation(true);
        }

        try {
            if (root.has("copy")) {
                String from = root.getString("copy");

                if (from.equals(id)) {
                    throw new Exception("You can't copy creature from it self");
                }

                this.copy(from);
            }

            this.load(root);
        } catch (Exception exception) {
            throw exception;
        }
    }

    /**
     * Copies all info from another creature
     *
     * @param from Creature, to copy from
     * @throws Exception Exception, containing parse error
     */
    private void copy(String from) throws Exception {
        this.copied = true;


        CreatureInfo info = CoreRegistry.get(CreatureManager.class).getCreatureInfo(from);

        if (info == null) {
            throw new Exception("Creature for copy " + from + " is not found");
        }

        this.hp = info.hp.clone();
        this.defense = info.defense.clone();
        this.damage = info.damage.clone();
        this.speed = info.speed;
        this.spawnWeight = info.spawnWeight;
        this.type = info.type;

        for (Drop drop : info.drops) {
            this.drops.add(drop.clone());
        }

        this.ai = info.ai;
        this.kbResist = info.kbResist.clone();
        this.hitbox = info.hitbox.copy();
        this.renderBounds = info.renderBounds.copy();

        for (int i = 0; i < info.animations.length; i++) {
            this.animations[i] = info.animations[i].copy();
        }
    }

    /**
     * Loads creature info from json root
     *
     * @param root Json root
     * @throws Exception Exception, containing parse error
     */
    private void load(JsonValue root) throws Exception {
        if (root.has("hp")) {
            this.hp = root.get("hp").asIntArray();
        }

        if (root.has("defense")) {
            this.defense = root.get("defense").asIntArray();
        }

        if (root.has("damage")) {
            this.damage = root.get("damage").asIntArray();
        }

        if (root.has("speed")) {
            this.speed = root.get("speed").asFloat();
        }

        short ai = 0;

        if (root.has("ai")) {
            ai = root.get("ai").asShort();
        }

        if (root.has("ai")) {
            ai = root.get("ai").asShort();
        }


        this.ai = CoreRegistry.get(AIManager.class).get(ai);

        if (this.ai == null) {
            throw new Exception("AI with id " + ai + " is not found");
        }

        if (root.has("spawnWeight")) {
            this.spawnWeight = root.get("spawnWeight").asByte();
        }

        if (root.has("type")) {
            this.type = root.get("type").asByte();
        }

        if (root.has("kb_resist")) {
            this.kbResist = root.get("kb_resist").asFloatArray();
        }

        if (root.has("hitbox")) {
            JsonValue hitbox = root.get("hitbox");

            this.hitbox.x = hitbox.getInt(0);
            this.hitbox.y = hitbox.getInt(1);
            this.hitbox.width = hitbox.getInt(2);
            this.hitbox.height = hitbox.getInt(3);
        }

        if (root.has("size")) {
            JsonValue hitbox = root.get("size");

            this.renderBounds.width = hitbox.getInt(0);
            this.renderBounds.height = hitbox.getInt(1);
        } else if (!this.copied) {
            this.renderBounds = this.hitbox.copy();
        }

        if (root.has("drop")) {
            JsonValue drops = root.get("drop");

            for (JsonValue drop : drops) {

                Item item = CoreRegistry.get(ItemManager.class).getItem(drop.getString("id"));

                if (item == null) {
                    throw new Exception("Item with id " + drop.getString("id") + " is not found");
                }

                short chance = drop.getShort("chance", (short) 1);

                short min = 1;
                short max = 1;

                try {
                    max = drop.get("count").getShort(1);
                    min = drop.get("count").getShort(0);
                } catch (Exception exception) {
                    exception.printStackTrace();
                }

                this.drops.add(new Drop(item, chance, min, max));
            }
        }

        this.image = Assets.getTexture(this.id.replace(':', '_'));

        if (root.has("animation")) {
            JsonValue animation = root.get("animation");

            this.loadAnimation(animation, "idle");
            this.loadAnimation(animation, "moving");
            this.loadAnimation(animation, "jumping");
            this.loadAnimation(animation, "falling");
            this.loadAnimation(animation, "dead");
            this.loadAnimation(animation, "acting");
        }
    }

    /**
     * Loads animation with given type
     * @param root Json root
     * @param type Animation type
     */
    private void loadAnimation(JsonValue root, String type) {
        JsonValue animation = root.get(type);
        Animation to = this.animations[this.toID(type)];

        if (animation.has("copy")) {
            to.copyFrom(this.animations[this.toID(animation.get("copy").asString())]);
        } else {
            if (animation.has("looping")) {
                to.setLooped(animation.get("looping").asBoolean());
            }

            if (animation.has("stopped")) {
                to.setStopped(animation.get("stopped").asBoolean());
            }

            if (!animation.has("frames")) {
                return;
            }

            for (JsonValue frame : animation.get("frames")) {
                this.loadFrame(frame, to);
            }
        }
    }

    /**
     * Loads animation from
     *
     * @param frame Json root for frame
     * @param to Animation, that will receive that frame
     */
    private void loadFrame(JsonValue frame, Animation to) {
        JsonValue rect = frame.get("rect");

        to.addFrame(new AnimationFrame(new TextureRegion(this.image, rect.get(0).asInt(),
            rect.get(1).asInt(), rect.get(2).asInt(), rect.get(3).asInt()), frame.getInt("time", 10)));
    }

    /**
     * Converts string to animation number
     *
     * @param animation String, containing animation type
     * @return Animation number
     */
    private int toID(String animation) {
        switch (animation) {
            case "moving": return CreatureStateComponent.State.MOVING.getID();
            case "jumping": return CreatureStateComponent.State.JUMPING.getID();
            case "falling": return CreatureStateComponent.State.FALLING.getID();
            case "dead": return CreatureStateComponent.State.DEAD.getID();
            case "acting": return CreatureStateComponent.State.ACTING.getID();
            default: return CreatureStateComponent.State.IDLE.getID();
        }
    }

    /**
     * @return New creature
     */
    public Creature create() {
        Enemy creature = new Enemy(this.id, this.ai);

        int hp = this.hp[0];
        int defense = this.damage[0];
        int damage = this.damage[0];

        if (Globals.getWorld().flags.isHardmode()) {
            hp = this.hp[2];
            defense = this.defense[2];
            damage = this.damage[2];
        } else if (Globals.getWorld().flags.isExpertMode()) {
            hp = this.hp[1];
            defense = this.defense[1];
            damage = this.damage[1];
        }

        creature.stats.set(hp, 0, defense, damage);
        creature.physics.setHitbox(this.hitbox.copy());
        creature.physics.setSize((int) this.renderBounds.width, (int) this.renderBounds.height);
        creature.physics.setSpeed(this.speed);

        for (int i = 0; i < this.animations.length; i++) {
            creature.graphics.animations[i] = this.animations[i].copy();
            creature.graphics.animations[i].setTexture(this.image);
        }

        for (int i = 0; i < this.drops.size(); i++) {
            creature.drops.drop();
            creature.drops.add(this.drops.get(i).clone());
        }

        creature.setSpawnWeight(spawnWeight);

        return creature;

        /*
        switch (this.type) {
            case 0: // Creature

            break;
            case 1: // Enemy

            break;
            // todo: npc's
        }

        return null;*/ // FIXME
    }
}