package Roguelike.Items; import Roguelike.Ability.AbilityTree; import Roguelike.Ability.ActiveAbility.ActiveAbility; import Roguelike.Ability.IAbility; import Roguelike.Ability.PassiveAbility.PassiveAbility; import Roguelike.AssetManager; import Roguelike.Entity.Entity; import Roguelike.Entity.GameEntity; import Roguelike.GameEvent.GameEventHandler; import Roguelike.Global; import Roguelike.Global.Statistic; import Roguelike.Lights.Light; import Roguelike.Sound.SoundInstance; import Roguelike.Sprite.Sprite; import Roguelike.Sprite.SpriteAnimation.MoveAnimation; import Roguelike.Tiles.Point; import Roguelike.UI.Seperator; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.math.MathUtils; 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.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.XmlReader; import com.badlogic.gdx.utils.XmlReader.Element; import exp4j.Helpers.EquationHelper; import net.objecthunter.exp4j.Expression; import net.objecthunter.exp4j.ExpressionBuilder; import java.io.IOException; import java.util.HashMap; public final class Item extends GameEventHandler { /* * IDEAS: * * Unlock extra power after condition (absorb x essence, kill x enemy) */ public String name = ""; public String description = ""; public Sprite hitEffect; public Array<EquipmentSlot> slots = new Array<EquipmentSlot>(); public ItemCategory category; public String type = ""; public boolean canStack; public int count = 1; public Light light; public boolean canDrop = true; public String dropChanceEqn; public AbilityTree ability; public WeaponDefinition wepDef; public int quality = 1; public int upgradeCount = 1; public int value; public Array<SpriteGroup> spriteGroups = new Array<SpriteGroup>( ); // ---------------------------------------------------------------------- public Item() { } // ---------------------------------------------------------------------- @Override protected void appendExtraVariables(HashMap<String, Integer> variableMap ) { variableMap.put("upgrade", upgradeCount-1); for (Object[] data : extraData) { variableMap.put( (String)data[0], (Integer)data[1] ); } } // ---------------------------------------------------------------------- public void upgrade() { upgradeCount++; if ( slots.contains( EquipmentSlot.WEAPON, true ) ) { // only upgrade attack String currentAtk = constantEvent.equations.get( Statistic.ATTACK ); if (!currentAtk.endsWith( "upgrade)" )) { currentAtk = "(" + currentAtk + ")*(1+0.1*upgrade)"; } constantEvent.putStatistic( Statistic.ATTACK, currentAtk ); } else { for (Statistic stat : Statistic.values()) { if (constantEvent.equations.containsKey( stat )) { String currentVal = constantEvent.equations.get( stat ); if (!currentVal.endsWith( "upgrade)" )) { currentVal = "(" + currentVal + ")*(1+0.1*upgrade)"; } constantEvent.putStatistic( stat, currentVal ); } } } } // ---------------------------------------------------------------------- public static Item load( String name ) { Item item = new Item(); item.internalLoad( name ); return item; } // ---------------------------------------------------------------------- public static Item load( String recipe, Element xml ) { String material = xml.get( "Material" ); int quality = xml.getInt( "Quality" ); Item materialItem = TreasureGenerator.getMaterial( material, quality, MathUtils.random ); Item item = Recipe.createRecipe( recipe, materialItem ); item.getIcon().colour.mul( materialItem.getIcon().colour ); Element prefixElement = xml.getChildByName( "Prefix" ); if ( prefixElement != null ) { String[] prefixes = prefixElement.getText().split( "," ); for (String prefix : prefixes) { Recipe.applyModifer( item, prefix, materialItem.quality, true ); } } Element suffixElement = xml.getChildByName( "Suffix" ); if ( suffixElement != null ) { String[] suffixes = suffixElement.getText().split( "," ); for (String suffix : suffixes) { Recipe.applyModifer( item, suffix, materialItem.quality, false ); } } item.value = xml.getInt( "Value", 0 ); return item; } // ---------------------------------------------------------------------- public static Item load( Element xml ) { Item item = null; if (xml.getChildCount() == 0) { item = Item.load( xml.getText() ); item.count = xml.getIntAttribute( "Count", 1 ); } else if ( xml.getChildByName( "Recipe" ) != null ) { String recipe = Global.capitalizeString( xml.getChildByName( "Recipe" ).getText() ); item = Item.load( recipe, xml ); } else { item = new Item(); item.internalLoad( xml ); } item.value = xml.getInt( "Value", 0 ); return item; } // ---------------------------------------------------------------------- public boolean shouldDrop() { if ( dropChanceEqn == null ) { return true; } return EquationHelper.evaluate( dropChanceEqn ) > 0; } // ---------------------------------------------------------------------- public Table createTable( Skin skin, GameEntity entity ) { if ( ability != null ) { return ability.current.current.createTable( skin, entity ); } Inventory inventory = entity.getInventory(); if ( slots.contains( EquipmentSlot.WEAPON, true ) ) { Item other = inventory.getEquip( EquipmentSlot.WEAPON ); return createWeaponTable( other, entity, skin ); } else if ( slots.size > 0 ) { Item other = inventory.getEquip( slots.get( 0 ) ); return createArmourTable( other, entity, skin ); } Table table = new Table(); table.add( new Label( getName(), skin, "title" ) ).left(); if ( count > 1 ) { table.add( new Label( "x" + count, skin ) ).left().padLeft( 20 ); } table.row(); Label descLabel = new Label( description, skin ); descLabel.setWrap( true ); table.add( descLabel ).expand().left().width( com.badlogic.gdx.scenes.scene2d.ui.Value.percentWidth( 1, table ) ); table.row(); return table; } // ---------------------------------------------------------------------- private Table createArmourTable( Item other, GameEntity entity, Skin skin ) { Table table = new Table(); Table titleRow = new Table(); titleRow.add( new Label( name, skin, "title" ) ).expandX().left(); if ( type != null && type.length() > 0 ) { Label label = new Label( type, skin ); label.setFontScale( 0.7f ); titleRow.add( label ).expandX().right(); } table.add( titleRow ).expandX().fillX(); table.row(); Label descLabel = new Label( description, skin ); descLabel.setWrap( true ); table.add( descLabel ).expand().left().width( com.badlogic.gdx.scenes.scene2d.ui.Value.percentWidth( 1, table ) ); table.row(); table.add( new Seperator( skin, false ) ).expandX().fillX(); table.row(); for (Statistic stat : Statistic.values()) { int val = getStatistic( entity.getVariableMap(), stat ); int otherVal = other != null ? other.getStatistic( entity.getVariableMap(), stat ) : 0; if (val > 0 || val != otherVal) { String value = ""+val; if (val < otherVal) { value = value + "[RED] " + (val - otherVal) + "[]"; } else if (val > otherVal) { value = value + "[GREEN] +" + (val - otherVal) + "[]"; } Label statLabel = new Label( Global.capitalizeString( stat.toString() ) + ": " + value, skin ); table.add( statLabel ).expandX().left().width( com.badlogic.gdx.scenes.scene2d.ui.Value.percentWidth( 1, table ) ); table.row(); } } Array<String> lines = toString( entity.getVariableMap(), true ); for (String line : lines) { if (line.equals( "---" )) { table.add( new Seperator( skin, false ) ).expandX().fillX(); } else { Label lineLabel = new Label( line, skin ); lineLabel.setWrap( true ); table.add( lineLabel ).expandX().left().width( com.badlogic.gdx.scenes.scene2d.ui.Value.percentWidth( 1, table ) ); table.row(); } table.row(); } return table; } // ---------------------------------------------------------------------- private Table createWeaponTable( Item other, GameEntity entity, Skin skin ) { Table table = new Table(); Table titleRow = new Table(); titleRow.add( new Label( name, skin, "title" ) ).expandX().left(); if ( type != null && type.length() > 0 ) { Label label = new Label( type, skin ); label.setFontScale( 0.7f ); titleRow.add( label ).expandX().right(); } table.add( titleRow ).expandX().fillX(); table.row(); Label descLabel = new Label( description, skin ); descLabel.setWrap( true ); table.add( descLabel ).expand().left().width( com.badlogic.gdx.scenes.scene2d.ui.Value.percentWidth( 1, table ) ); table.row(); table.add( new Seperator( skin, false ) ).expandX().fillX(); table.row(); table.add( new Label("HitCount: " + wepDef.hitCount, skin) ).expandX().fillX(); table.row(); table.add( new Label("HitPercent: " + wepDef.hitPercent, skin) ).expandX().fillX(); table.row(); table.add( new Seperator( skin, false ) ).expandX().fillX(); table.row(); int oldDam = other != null ? Global.calculateScaledAttack( Statistic.statsBlockToVariableBlock( other.getStatistics( entity.getVariableMap() ) ), entity.getVariableMap() ) : 0; int newDam = Global.calculateScaledAttack( Statistic.statsBlockToVariableBlock( getStatistics( entity.getVariableMap() ) ), entity.getVariableMap() ); String damText = "Damage: " + newDam; if ( newDam != oldDam ) { int diff = newDam - oldDam; if ( diff > 0 ) { damText += "[GREEN] +" + diff; } else { damText += "[RED] " + diff; } } table.add( new Label( damText, skin ) ).expandX().left(); table.row(); table.add( new Seperator( skin, false ) ).expandX().fillX(); table.row(); table.add( new Label( "Scales with:", skin ) ).expandX().left(); table.row(); for (Statistic stat : Statistic.values()) { int val = getStatistic( entity.getVariableMap(), stat ); int otherVal = other != null ? other.getStatistic( entity.getVariableMap(), stat ) : 0; if ( stat == Statistic.ATTACK || stat == Statistic.DEFENSE ) { continue; } if (val > 0 || val != otherVal) { String scale = val > 0 ? Global.ScaleLevel.values()[ val - 1 ].toString() : "--"; if (val < otherVal) { scale = "[RED] " + scale + "[]"; } else if (val > otherVal) { scale = "[GREEN] " + scale + "[]"; } Label statLabel = new Label( Global.capitalizeString( stat.toString() ) + ": " + scale, skin ); table.add( statLabel ).expandX().left().width( com.badlogic.gdx.scenes.scene2d.ui.Value.percentWidth( 1, table ) ); table.row(); } } Array<String> lines = toString( entity.getVariableMap(), true ); for (String line : lines) { if (line.equals( "---" )) { table.add( new Seperator( skin, false ) ).expandX().fillX(); } else { Label lineLabel = new Label( line, skin ); lineLabel.setWrap( true ); table.add( lineLabel ).expandX().left().width( com.badlogic.gdx.scenes.scene2d.ui.Value.percentWidth( 1, table ) ); table.row(); } table.row(); } return table; } // ---------------------------------------------------------------------- @Override public String getName() { if ( ability != null ) { return ability.current.current.getName(); } return name; } // ---------------------------------------------------------------------- @Override public String getDescription() { if ( ability != null ) { return ability.current.current.getDescription(); } return description; } // ---------------------------------------------------------------------- @Override public Sprite getIcon() { if ( spriteGroups.size > 0 ) { for (int i = spriteGroups.size - 1; i >= 0; i--) { if (spriteGroups.get( i ).stacks < count) { return spriteGroups.get( i ).sprite; } } return spriteGroups.get( 0 ).sprite; } if ( ability != null) { return ability.current.current.getIcon(); } if ( spriteGroups.size == 0 ) { Sprite icon = AssetManager.loadSprite( "white" ); spriteGroups.add( new SpriteGroup( 0, icon ) ); } return spriteGroups.get( 0 ).sprite; } // ---------------------------------------------------------------------- private void internalLoad( String name ) { XmlReader xml = new XmlReader(); Element xmlElement = null; try { xmlElement = xml.parse( Gdx.files.internal( "Items/" + name + ".xml" ) ); } catch ( IOException e ) { e.printStackTrace(); } internalLoad( xmlElement ); } // ---------------------------------------------------------------------- private void internalLoad( Element xmlElement ) { String extendsElement = xmlElement.getAttribute( "Extends", null ); if ( extendsElement != null ) { internalLoad( extendsElement ); } name = xmlElement.get( "Name", name ); description = xmlElement.get( "Description", description ); canStack = xmlElement.getBoolean( "CanStack", canStack ); String countEqn = xmlElement.get( "Count", "" + count ); count = EquationHelper.evaluate( countEqn, Statistic.emptyMap ); Element iconElement = xmlElement.getChildByName( "Icon" ); if ( iconElement != null ) { if (iconElement.getChildByName( "Name" ) != null) { Sprite icon = AssetManager.loadSprite( iconElement ); spriteGroups.add( new SpriteGroup( 0, icon ) ); } for (Element el : iconElement.getChildrenByName( "Sprite" )) { int count = el.getIntAttribute( "Count" ); Sprite icon = AssetManager.loadSprite( el ); spriteGroups.add( new SpriteGroup( count, icon ) ); } } Element hitElement = xmlElement.getChildByName( "HitEffect" ); if ( hitElement != null ) { hitEffect = AssetManager.loadSprite( hitElement ); } Element eventsElement = xmlElement.getChildByName( "Events" ); if ( eventsElement != null ) { super.parse( eventsElement ); } Element lightElement = xmlElement.getChildByName( "Light" ); if ( lightElement != null ) { light = Light.load( lightElement ); } String slotsElement = xmlElement.get( "Slot", null ); if ( slotsElement != null ) { String[] split = slotsElement.split( "," ); for ( String s : split ) { slots.add( EquipmentSlot.valueOf( s.toUpperCase() ) ); } } category = xmlElement.get( "Category", null ) != null ? ItemCategory.valueOf( xmlElement.get( "Category" ).toUpperCase() ) : category; type = xmlElement.get( "Type", type ).toLowerCase(); quality = xmlElement.getInt( "Quality", quality ); value = xmlElement.getInt( "Value", value ); // Load the wep def if (slots.contains( EquipmentSlot.WEAPON, true ) && type != null) { wepDef = WeaponDefinition.load( type ); } Element abilityElement = xmlElement.getChildByName( "Ability" ); if ( abilityElement != null ) { ability = new AbilityTree(abilityElement.getText()); } // Preload sprites if ( type != null ) { getWeaponHitEffect(); getIcon(); } } // ---------------------------------------------------------------------- public EquipmentSlot getMainSlot() { return slots.size > 0 ? slots.get( 0 ) : null; } // ---------------------------------------------------------------------- public Sprite getWeaponHitEffect() { if ( hitEffect != null ) { return hitEffect; } if ( wepDef != null && wepDef.hitSprite != null ) { return wepDef.hitSprite; } return AssetManager.loadSprite( "EffectSprites/Strike/Strike", 0.1f, "Hit" ); } // ---------------------------------------------------------------------- public enum EquipmentSlot { // Weapons WEAPON, // Armour HEAD, BODY, LEGS } // ---------------------------------------------------------------------- public enum ItemCategory { ARMOUR, WEAPON, JEWELRY, TREASURE, MATERIAL, MISC, ALL } // ---------------------------------------------------------------------- public static class WeaponDefinition { public enum HitType { ALL, CLOSEST, RANDOM } public HitType hitType; public String hitData; public Sprite hitSprite; public int hitCount; public int hitPercent; public Array<Point> hitPoints = new Array<Point>( ); public static WeaponDefinition load( String name ) { WeaponDefinition wepDef = new WeaponDefinition(); name = Global.capitalizeString( name ); XmlReader reader = new XmlReader(); XmlReader.Element xml = null; try { xml = reader.parse( Gdx.files.internal( "Items/Weapons/" + name + ".xml" ) ); } catch ( IOException e ) { e.printStackTrace(); } Element spriteElement = xml.getChildByName( "HitSprite" ); if ( spriteElement != null ) { wepDef.hitSprite = AssetManager.loadSprite( spriteElement ); } String[] hitTypeData = xml.get( "HitType" ).split( "[\\(\\)]" ); wepDef.hitType = HitType.valueOf( hitTypeData[0].toUpperCase() ); wepDef.hitData = hitTypeData.length > 1 ? hitTypeData[1] : null; wepDef.hitPercent = xml.getInt( "HitPercent", 100 ); wepDef.hitCount = xml.getInt( "HitCount", 1 ); Element hitPatternElement = xml.getChildByName( "HitPattern" ); char[][] hitGrid = new char[hitPatternElement.getChildCount()][]; Point centralPoint = new Point(); for (int y = 0; y < hitPatternElement.getChildCount(); y++) { Element lineElement = hitPatternElement.getChild( y ); String text = lineElement.getText(); hitGrid[ y ] = text.toCharArray(); for (int x = 0; x < hitGrid[ y ].length; x++) { if (hitGrid[ y ][ x ] == 'x') { centralPoint.x = x; centralPoint.y = y; } } } for (int y = 0; y < hitGrid.length; y++) { for (int x = 0; x < hitGrid[0].length; x++) { if (hitGrid[y][x] == '#') { int dx = x - centralPoint.x; int dy = centralPoint.y - y; wepDef.hitPoints.add( new Point(dx, dy) ); } } } return wepDef; } } // ---------------------------------------------------------------------- public static class SpriteGroup { public int stacks; public Sprite sprite; public SpriteGroup() { } public SpriteGroup(int stacks, Sprite sprite) { this.stacks = stacks; this.sprite = sprite; } } }