/******************************************************************************* * 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.Item; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Table; 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.Item.Component.Component_Type; import com.lyeeedar.Roguelike3D.Game.Item.Equipment_HAND.WeaponType; import com.lyeeedar.Roguelike3D.Game.Item.Item.Item_Type; import com.lyeeedar.Roguelike3D.Game.Item.MeleeWeapon.Melee_Weapon_Style; import com.lyeeedar.Roguelike3D.Game.Level.XML.RecipeReader; public class Recipe implements Comparable<Recipe>, Serializable { /** * */ private static final long serialVersionUID = 9091235160551539915L; // The recipe rarity public int rarity; // The type of the resulting item (armour, weapon etc) public Item_Type type; // The components required to create the item public HashMap<Character, Recipe_Component> components; // The layout of the visual recipe (will be converted by the UI into a usuable grid) public char[][] visualGrid; // The actual recipe private Recipe_Type recipe; public String recipeName; public Recipe(RecipeReader reader) { recipeName = reader.getRecipeName(); type = reader.getItemType(); rarity = reader.getRecipeRarity(); visualGrid = reader.getVisual(); components = new HashMap<Character, Recipe_Component>(); for (int x = 0; x < visualGrid.length; x++) { for (int y = 0; y < visualGrid[0].length; y++) { char c = visualGrid[x][y]; if (c == ' ') continue; components.put(c, new Recipe_Component(c, reader.getComponentName(c), reader.getComponentAmount(c), reader.getComponentConstraints(c))); } } if (reader.getItemType() == Item_Type.WEAPON) { this.recipe = new Recipe_Melee_Weapon(reader); } } public boolean checkAll(Component c) { for (int x = 0; x < visualGrid.length; x++) { for (int y = 0; y < visualGrid[0].length; y++) { if (checkComponent(c, visualGrid[x][y])) return true; } } return false; } public boolean checkComponent(Component c, char slot) { if (slot == ' ') return false; if (!components.get(slot).check(c.type)) return false; return (c.amount >= components.get(slot).amount); } @Override public int compareTo(Recipe r) { if (r.hashCode() < this.hashCode()) return -1; else if (r.hashCode() > this.hashCode()) return 1; return 0; } public Table getComponentDescription(char ref, Skin skin) { return components.get(ref).getUIDescription(skin); } public int getComponentAmount(char ref) { return components.get(ref).amount; } public Item craft(HashMap<Character, Component> components) { return recipe.finalise(components, this); } } class Recipe_Component implements Serializable { /** * */ private static final long serialVersionUID = 3513926494850238989L; char tag; String name; int amount; // If components is size 0 it will take any type of material, otherwise only those in this list ArrayList<Component_Type> constraints = new ArrayList<Component_Type>(); public Recipe_Component(char tag, String name, int amount, ArrayList<Component_Type> constraints) { this.tag = tag; this.name = name; this.amount = amount; this.constraints = constraints; } public boolean check(Component_Type type) { if (constraints.size() == 0) return true; for (Component_Type ct : constraints) { if (ct == type) return true; } return false; } public Table getUIDescription(Skin skin) { Table t = new Table(); t.add(new Label("Recipe Ingredient", skin)); t.row(); t.add(new Label("Name: ", skin)); t.add(new Label(name, skin)); t.row(); t.add(new Label("Amount: ", skin)); t.add(new Label(""+amount, skin)); t.row(); t.add(new Label("Allowed Types: ", skin)); Table types = new Table(); if (constraints.size() == 0) types.add(new Label("Any", skin)); else { for (Component_Type ct : constraints) { types.add(new Label(""+ct, skin)); types.row(); } } t.add(types); return t; } } abstract class Recipe_Type implements Serializable { /** * */ private static final long serialVersionUID = 5871516507153188509L; public Recipe_Type(RecipeReader reader) { read(reader); } public int calculate(ArrayList<ArrayList<String>> eqn, float scale, HashMap<Character, Component> components, Recipe recipe) { System.out.println("start calculating"); System.out.println("eqn size = "+eqn.size()); float value = 0; for (ArrayList<String> block : eqn) { float temp = 1; for (String s : block) { System.out.println(s); float temp2 = 0; try { temp2 = Float.parseFloat(s); } catch (Exception e) { Component c = components.get(s.charAt(0)); char attribute = s.charAt(1); if (attribute == 'w') temp2 = c.weight_per_amount * recipe.getComponentAmount(s.charAt(0)); else if (attribute == 'h') temp2 = c.soft_hard; else if (attribute == 'b') temp2 = c.flexible_brittle; else System.err.println("Equation error! Invalid pseudonym: " + attribute); } if (temp2 != 0) temp *= temp2; System.out.println("temp2="+temp2); } if (temp != 1) value += temp; System.out.println("temp="+temp); } if (value < 0) return 0; return (int) (value * scale); } public HashMap<Element, Integer> calculateElemental(ArrayList<ArrayList<String>> eqn, float scale, HashMap<Character, Component> components) { HashMap<Element, Integer> elemental = new HashMap<Element, Integer>(); elemental.put(Element.FIRE, calcEle(eqn, scale, Element.FIRE, components)); elemental.put(Element.WATER, calcEle(eqn, scale, Element.WATER, components)); elemental.put(Element.AIR, calcEle(eqn, scale, Element.AIR, components)); elemental.put(Element.WOOD, calcEle(eqn, scale, Element.WOOD, components)); elemental.put(Element.METAL, calcEle(eqn, scale, Element.METAL, components)); elemental.put(Element.AETHER, calcEle(eqn, scale, Element.AETHER, components)); elemental.put(Element.VOID, calcEle(eqn, scale, Element.VOID, components)); return elemental; } private int calcEle(ArrayList<ArrayList<String>> eqn, float scale, Element element, HashMap<Character, Component> components) { float value = 0; for (ArrayList<String> block : eqn) { float temp = 1; for (String s : block) { float temp2 = 0; try { temp2 = Float.parseFloat(s); } catch (Exception e) { Component c = components.get(s.charAt(0)); temp2 = c.element.get(element); } if (temp2 != 0) temp *= temp2; } if (temp != 1) value += temp; } if (value < 0) return 0; return (int) (value * scale); } protected abstract void read(RecipeReader reader); public abstract Item finalise(HashMap<Character, Component> components, Recipe recipe); } /** * A recipe for a weapon. It has components for the weapon style, the strength bonus, * the Dam_type amounts, the elemental amounts and the attack speed **/ class Recipe_Melee_Weapon extends Recipe_Type { /** * */ private static final long serialVersionUID = 4282943162832212160L; Melee_Weapon_Style style; HashMap<String, String> styleMeta; String visualType; int strength; float strengthScale; ArrayList<ArrayList<String>> strengthEqn; int pierce; float pierceScale; ArrayList<ArrayList<String>> pierceEqn; int impact; float impactScale; ArrayList<ArrayList<String>> impactEqn; int touch; float touchScale; ArrayList<ArrayList<String>> touchEqn; HashMap<Element, Integer> elemental; float elementalScale; ArrayList<ArrayList<String>> elementalEqn; float attackSpeed; float attackSpeedScale; ArrayList<ArrayList<String>> attackSpeedEqn; float weight; public Recipe_Melee_Weapon(RecipeReader reader) { super(reader); } protected void read(RecipeReader reader) { this.style = reader.getWeaponStyle(); this.styleMeta = reader.getWeaponStyleMeta(); this.visualType = reader.getVisualType(); this.strengthScale = reader.getScale(RecipeReader.STRENGTH); this.strengthEqn = reader.getEqn(RecipeReader.STRENGTH); this.pierceScale = reader.getScale(RecipeReader.PIERCE); this.pierceEqn = reader.getEqn(RecipeReader.PIERCE); this.impactScale = reader.getScale(RecipeReader.IMPACT); this.impactEqn = reader.getEqn(RecipeReader.IMPACT); this.touchScale = reader.getScale(RecipeReader.TOUCH); this.touchEqn = reader.getEqn(RecipeReader.TOUCH); this.elementalScale = reader.getScale(RecipeReader.ELEMENTAL); this.elementalEqn = reader.getEqn(RecipeReader.ELEMENTAL); this.attackSpeedScale = reader.getScale(RecipeReader.ATTACK_SPEED); this.attackSpeedEqn = reader.getEqn(RecipeReader.ATTACK_SPEED); } public Item finalise(HashMap<Character, Component> components, Recipe recipe) { System.out.println("Crafting item"); this.strength = calculate(strengthEqn, strengthScale, components, recipe); this.pierce = calculate(pierceEqn, pierceScale, components, recipe); this.impact = calculate(impactEqn, impactScale, components, recipe); this.touch = calculate(touchEqn, touchScale, components, recipe); this.attackSpeed = calculate(attackSpeedEqn, attackSpeedScale, components, recipe); this.elemental = calculateElemental(elementalEqn, elementalScale, components); HashMap<Damage_Type, Integer> damage = new HashMap<Damage_Type, Integer>(); damage.put(Damage_Type.PIERCE, pierce); damage.put(Damage_Type.IMPACT, impact); damage.put(Damage_Type.TOUCH, touch); float weight = 0; for (Map.Entry<Character, Component> entry : components.entrySet()) { weight += recipe.getComponentAmount(entry.getKey()) * entry.getValue().weight_per_amount; } return Equipment_HAND.getWeapon(WeaponType.MELEE, visualType, ""+style, strength, elemental, damage, attackSpeed, weight, false, 2, 1, GameData.level); } }