package Roguelike.Ability.ActiveAbility;
import Roguelike.Ability.AbilityTree;
import Roguelike.Ability.ActiveAbility.CostType.AbstractCostType;
import Roguelike.Ability.ActiveAbility.EffectType.AbstractEffectType;
import Roguelike.Ability.ActiveAbility.HitType.*;
import Roguelike.Ability.ActiveAbility.MovementType.AbstractMovementType;
import Roguelike.Ability.ActiveAbility.MovementType.MovementTypeBolt;
import Roguelike.Ability.ActiveAbility.MovementType.MovementTypeRay;
import Roguelike.Ability.ActiveAbility.MovementType.MovementTypeSmite;
import Roguelike.Ability.ActiveAbility.TargetingType.AbstractTargetingType;
import Roguelike.Ability.ActiveAbility.TargetingType.TargetingTypeEntity;
import Roguelike.Ability.ActiveAbility.TargetingType.TargetingTypeTile;
import Roguelike.Ability.IAbility;
import Roguelike.AssetManager;
import Roguelike.Entity.Entity;
import Roguelike.Entity.EnvironmentEntity;
import Roguelike.Entity.GameEntity;
import Roguelike.GameEvent.IGameObject;
import Roguelike.Global;
import Roguelike.Global.Direction;
import Roguelike.Global.Passability;
import Roguelike.Items.Item;
import Roguelike.Items.Item.EquipmentSlot;
import Roguelike.Lights.Light;
import Roguelike.Pathfinding.ShadowCaster;
import Roguelike.Screens.GameScreen;
import Roguelike.Sound.SoundInstance;
import Roguelike.Sprite.Sprite;
import Roguelike.Sprite.SpriteAction;
import Roguelike.Sprite.SpriteAnimation.MoveAnimation;
import Roguelike.Sprite.SpriteEffect;
import Roguelike.Tiles.GameTile;
import Roguelike.Tiles.Point;
import Roguelike.UI.Seperator;
import Roguelike.Util.EnumBitflag;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
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 java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
public class ActiveAbility implements IAbility, IGameObject
{
public enum CooldownType
{
TURN("Turn"),
MOVE("Move"),
ATTACK("Hit"),
WAIT("Wait"),
HURT("Hurt"),
HEALED("Heal");
public final String text;
CooldownType( String text )
{
this.text = text;
}
}
public int cooldownAccumulator;
public int cooldown = 1;
public CooldownType cooldownType = CooldownType.TURN;
public Array<AbstractCostType> costTypes = new Array<AbstractCostType>();
public AbstractTargetingType targetingType = new TargetingTypeTile();
public AbstractHitType hitType = new HitTypeAny();
public AbstractMovementType movementType = new MovementTypeSmite();
public Array<AbstractEffectType> effectTypes = new Array<AbstractEffectType>();
public Array<GameTile> AffectedTiles = new Array<GameTile>( false, 16 );
public GameTile source;
private GameEntity caster;
private HashMap<String, Integer> variableMap = new HashMap<String, Integer>();
public EnumBitflag<Passability> abilityPassability = new EnumBitflag<Passability>( Passability.LEVITATE );
public Light light;
public Sprite Icon;
public boolean hasValidTargets = true;
private String name;
private String description;
private int cone = 0;
private int aoe = 0;
private int range = 1;
private float screenshake = 0;
private Sprite movementSprite;
private Sprite hitSprite;
private boolean singleSprite = false;
private Sprite useSprite;
private boolean spentCost = false;
public boolean noSprite = false;
public AbilityTree.AbilityStage tree;
public String creationPath;
public Element creationData;
public ActiveAbility()
{
}
// ----------------------------------------------------------------------
@Override
public void setCaster(Entity e)
{
caster = (GameEntity)e;
setVariableMap( caster.getVariableMap() );
}
// ----------------------------------------------------------------------
@Override
public int getLevel()
{
return tree.level;
}
// ----------------------------------------------------------------------
@Override
public void setTree(AbilityTree.AbilityStage tree )
{
this.tree = tree;
}
// ----------------------------------------------------------------------
public GameEntity getCaster()
{
return caster;
}
// ----------------------------------------------------------------------
public void setVariableMap(HashMap<String, Integer> map)
{
variableMap = map;
}
// ----------------------------------------------------------------------
public HashMap<String, Integer> getVariableMap()
{
if (tree != null)
{
variableMap.put("level", tree.level);
}
else
{
variableMap.put("level", 1);
}
return variableMap;
}
// ----------------------------------------------------------------------
public static ActiveAbility load( String name )
{
ActiveAbility ab = new ActiveAbility();
ab.creationPath = name;
ab.internalLoad( name );
return ab;
}
// ----------------------------------------------------------------------
public static ActiveAbility load( Element xml )
{
ActiveAbility ab = new ActiveAbility();
ab.creationData = xml;
ab.internalLoad( xml );
return ab;
}
// ----------------------------------------------------------------------
public boolean isAvailable()
{
if ( !hasValidTargets ) { return false; }
if ( cooldownAccumulator > 0 ) { return false; }
for ( AbstractCostType cost : costTypes )
{
if ( !cost.isCostAvailable( this ) ) { return false; }
}
return true;
}
// ----------------------------------------------------------------------
public ActiveAbility copy()
{
ActiveAbility aa = new ActiveAbility();
aa.name = name;
aa.description = description;
aa.aoe = aoe;
aa.range = range;
aa.cone = cone;
aa.screenshake = screenshake;
aa.noSprite = noSprite;
aa.cooldownType = cooldownType;
aa.targetingType = targetingType.copy();
aa.movementType = movementType.copy();
for ( AbstractCostType cost : costTypes )
{
aa.costTypes.add( cost.copy() );
}
for ( AbstractEffectType effect : effectTypes )
{
aa.effectTypes.add( effect.copy() );
}
for ( GameTile tile : AffectedTiles )
{
aa.AffectedTiles.add( tile );
}
aa.light = light != null ? light.copy() : null;
aa.Icon = Icon != null ? Icon.copy() : null;
aa.movementSprite = movementSprite != null ? movementSprite.copy() : null;
aa.hitSprite = hitSprite != null ? hitSprite.copy() : null;
aa.useSprite = useSprite != null ? useSprite.copy() : null;
aa.singleSprite = singleSprite;
aa.tree = tree;
return aa;
}
// ----------------------------------------------------------------------
public Sprite getSprite()
{
return movementSprite;
}
// ----------------------------------------------------------------------
public boolean isTargetValid( GameTile tile, Array<Point> valid )
{
for ( Point validTile : valid )
{
if ( validTile.x == tile.x && validTile.y == tile.y ) { return true; }
}
return false;
}
// ----------------------------------------------------------------------
public Array<Point> getValidTargets()
{
Array<Point> validTargets = new Array<Point>();
Array<Point> output = caster.visibilityCache.getCurrentShadowCast();
for ( Point tilePos : output )
{
if ( Math.abs(tilePos.x-caster.tile[0][0].x) <= getRange() && Math.abs( tilePos.y-caster.tile[0][0].y ) <= getRange() )
{
GameTile tile = source.level.getGameTile( tilePos );
if ( targetingType.isTargetValid( this, tile ) )
{
if (hitType.isTargetValid( this, tile.entity ))
{
validTargets.add( tilePos.copy() );
}
}
}
}
return validTargets;
}
// ----------------------------------------------------------------------
public int getRange()
{
if ( range > 0 ) { return range; }
Item item = caster.getInventory().getEquip( EquipmentSlot.WEAPON );
//if ( item != null ) { return item.getRange( caster ); }
return 1;
}
// ----------------------------------------------------------------------
public void lockTarget( GameTile tile )
{
int cx = 0;
int cy = 0;
int dst = Integer.MAX_VALUE;
for ( int x = 0; x < caster.size; x++ )
{
for ( int y = 0; y < caster.size; y++ )
{
int tmpdst = Math.abs( tile.x - ( caster.tile[ 0 ][ 0 ].x + x ) ) + Math.abs( tile.y - ( caster.tile[ 0 ][ 0 ].y + y ) );
if ( tmpdst < dst )
{
dst = tmpdst;
cx = x;
cy = y;
}
}
}
source = caster.tile[ cx ][ cy ];
movementType.init( this, tile.x, tile.y );
}
// ----------------------------------------------------------------------
public void updateAccumulators( float cost )
{
movementType.updateAccumulators( cost );
}
// ----------------------------------------------------------------------
public boolean needsUpdate()
{
return movementType.needsUpdate();
}
// ----------------------------------------------------------------------
public boolean update()
{
if ( !spentCost )
{
for ( AbstractCostType cost : costTypes )
{
cost.spendCost( this );
}
spentCost = true;
if ( useSprite != null )
{
Sprite sprite = useSprite.copy();
sprite.size[0] = caster.size;
sprite.size[1] = caster.size;
caster.tile[ 0 ][ 0 ].spriteEffects.add( new SpriteEffect( sprite, Direction.CENTER, light != null ? light.copyNoFlag() : null ) );
}
}
boolean finished = movementType.update( this );
if ( movementSprite != null )
{
movementSprite.rotation = movementType.direction.getAngle();
}
if ( finished )
{
// play move sprites, if applicable
if ( !( movementType instanceof MovementTypeBolt ) )
{
if ( movementSprite != null )
{
for ( GameTile tile : AffectedTiles )
{
int[] diff = tile.getPosDiff( source );
Sprite sprite = movementSprite.copy();
if ( sprite.spriteAnimation == null && movementType instanceof MovementTypeSmite )
{
sprite.spriteAnimation = new MoveAnimation();
}
if ( sprite.spriteAnimation != null )
{
int distMoved = ( Math.abs( diff[ 0 ] ) + Math.abs( diff[ 1 ] ) ) / Global.TileSize;
sprite.spriteAnimation.set( 0.05f * distMoved, diff );
}
Vector2 vec = new Vector2( diff[ 0 ] * -1, diff[ 1 ] * -1 );
vec.nor();
float x = vec.x;
float y = vec.y;
double dot = 0 * x + 1 * y; // dot product
double det = 0 * y - 1 * x; // determinant
float angle = (float) Math.atan2( det, dot ) * MathUtils.radiansToDegrees;
sprite.rotation = angle;
if ( AffectedTiles.size > 1 )
{
sprite.renderDelay = sprite.animationDelay * tile.getDist( source ) + sprite.animationDelay;
}
SpriteEffect effect = new SpriteEffect( sprite, Direction.CENTER, light != null ? light.copyNoFlag() : null );
tile.spriteEffects.add( effect );
}
}
}
GameTile epicenter = AffectedTiles.peek();
if ( movementType instanceof MovementTypeRay )
{
epicenter = AffectedTiles.first();
}
else if ( aoe > 0 )
{
Array<Point> output = new Array<Point>();
ShadowCaster shadow = new ShadowCaster( epicenter.level.getGrid(), aoe, abilityPassability, caster );
shadow.ComputeFOV( epicenter.x, epicenter.y, output );
for ( Point tilePos : output )
{
GameTile tile = epicenter.level.getGameTile( tilePos );
AffectedTiles.add( tile );
}
Global.PointPool.freeAll( output );
}
else if ( cone > 0 )
{
Direction dir = Direction.getDirection( source, epicenter );
Point epicenterPoint = Global.PointPool.obtain().set( epicenter.x, epicenter.y );
Array<Point> cone = Direction.buildCone( dir, epicenterPoint, this.cone );
Global.PointPool.free( epicenterPoint );
Array<Point> output = new Array<Point>();
ShadowCaster shadow = new ShadowCaster( epicenter.level.getGrid(), this.cone, abilityPassability, caster );
shadow.ComputeFOV( epicenter.x, epicenter.y, output );
for ( Point tilePos : cone )
{
GameTile tile = epicenter.level.getGameTile( tilePos );
boolean canAdd = false;
for ( Point visPos : output )
{
GameTile visTile = epicenter.level.getGameTile( visPos );
if ( tile == visTile )
{
canAdd = true;
break;
}
}
if ( canAdd )
{
AffectedTiles.add( tile );
}
}
Global.PointPool.freeAll( output );
}
// minimise list
HashSet<GameTile> added = new HashSet<GameTile>();
Iterator<GameTile> itr = AffectedTiles.iterator();
while ( itr.hasNext() )
{
GameTile tile = itr.next();
if ( !hitType.isTargetValid( this, tile.entity ) )
{
itr.remove();
}
else if ( !added.contains( tile ) )
{
added.add( tile );
}
else
{
itr.remove();
}
}
final HashSet<Entity> hitEntities = new HashSet<Entity>( );
for ( GameTile tile : AffectedTiles )
{
if ( getHitSprite() != null && ( aoe == 0 || !singleSprite ) )
{
int[] diff = tile.getPosDiff( epicenter );
Sprite sprite = getHitSprite().copy();
if ( sprite.spriteAnimation != null )
{
int distMoved = ( Math.abs( diff[ 0 ] ) + Math.abs( diff[ 1 ] ) ) / Global.TileSize;
sprite.spriteAnimation.set( 0.05f * distMoved, diff );
}
Vector2 vec = new Vector2( diff[ 0 ] * -1, diff[ 1 ] * -1 );
vec.nor();
float x = vec.x;
float y = vec.y;
double dot = 0 * x + 1 * y; // dot product
double det = 0 * y - 1 * x; // determinant
float angle = (float) Math.atan2( det, dot ) * MathUtils.radiansToDegrees;
sprite.rotation = angle;
boolean isMoving = sprite.spriteAnimation != null && sprite.spriteAnimation instanceof MoveAnimation;
final GameTile hitTile = tile;
final GameEntity hitEntity = !hitEntities.contains( hitTile.entity ) ? hitTile.entity : null;
final EnvironmentEntity hitEnvEntity = !hitEntities.contains( hitTile.environmentEntity ) ? hitTile.environmentEntity : null;
final ActiveAbility thisAbility = this;
if (hitEntity != null)
{
hitEntities.add( hitEntity );
}
if (hitEnvEntity != null)
{
hitEntities.add( hitEnvEntity );
}
sprite.spriteAction = new SpriteAction( isMoving ? SpriteAction.FirePoint.End : SpriteAction.FirePoint.Start) {
@Override
public void evaluate()
{
for ( AbstractEffectType effect : effectTypes )
{
effect.update( thisAbility, 1, hitTile, hitEntity, hitEnvEntity );
}
}
};
SpriteEffect effect = new SpriteEffect( sprite, Direction.CENTER, light != null ? light.copyNoFlag() : null );
sprite.renderDelay = sprite.animationDelay * tile.getDist( epicenter ) + sprite.animationDelay;
SoundInstance sound = sprite.sound;
if ( sound != null )
{
sound.play( tile );
}
tile.spriteEffects.add( effect );
}
else
{
for ( AbstractEffectType effect : effectTypes )
{
effect.update( this, 1, tile,
!hitEntities.contains( tile.entity ) ? tile.entity : null,
!hitEntities.contains( tile.environmentEntity ) ? tile.environmentEntity : null );
if (tile.entity != null)
{
hitEntities.add( tile.entity );
}
if (tile.environmentEntity != null)
{
hitEntities.add( tile.environmentEntity );
}
}
}
}
if ( getHitSprite() != null && aoe > 0 && singleSprite )
{
int ex = epicenter.x - aoe;
int ey = epicenter.y - aoe;
GameTile tile = epicenter.level.getGameTile( ex, ey );
if (tile != null)
{
int[] diff = tile.getPosDiff( epicenter );
Sprite sprite = getHitSprite().copy();
if ( sprite.spriteAnimation != null )
{
int distMoved = ( Math.abs( diff[ 0 ] ) + Math.abs( diff[ 1 ] ) ) / Global.TileSize;
sprite.spriteAnimation.set( 0.05f * distMoved, diff );
}
sprite.size[0] = aoe * 2 + 1;
sprite.size[1] = aoe * 2 + 1;
SpriteEffect effect = new SpriteEffect( sprite, Direction.CENTER, light != null ? light.copyNoFlag() : null );
SoundInstance sound = sprite.sound;
if ( sound != null )
{
sound.play( tile );
}
tile.spriteEffects.add( effect );
}
}
if ( screenshake > 0 )
{
// check distance for screenshake
float dist = Vector2.dst( epicenter.x, epicenter.y, epicenter.level.player.tile[ 0 ][ 0 ].x, epicenter.level.player.tile[ 0 ][ 0 ].y );
float shakeRadius = screenshake;
if ( aoe != 0 && dist > aoe )
{
shakeRadius *= ( dist - aoe ) / ( aoe * 2 );
}
if ( shakeRadius > 2 )
{
GameScreen.Instance.screenShakeRadius = shakeRadius;
GameScreen.Instance.screenShakeAngle = MathUtils.random() * 360;
}
}
}
return finished;
}
// ----------------------------------------------------------------------
public Sprite getHitSprite()
{
if (noSprite) { return null; }
if ( hitSprite != null ) { return hitSprite; }
Item wep = caster.getInventory().getEquip( EquipmentSlot.WEAPON );
if ( wep != null ) { return wep.getWeaponHitEffect(); }
return caster.defaultHitEffect;
}
// ----------------------------------------------------------------------
private void internalLoad( String name )
{
XmlReader xml = new XmlReader();
Element xmlElement = null;
try
{
xmlElement = xml.parse( Gdx.files.internal( "Abilities/" + 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 );
}
this.name = xmlElement.get( "Name", this.name );
description = xmlElement.get( "Description", description );
Element aoeElement = xmlElement.getChildByName( "AOE" );
if ( aoeElement != null )
{
aoe = Integer.parseInt( aoeElement.getText() );
}
cone = xmlElement.getInt( "Cone", cone );
range = xmlElement.getInt( "Range", range );
cooldown = xmlElement.getInt( "Cooldown", cooldown );
cooldownType = CooldownType.valueOf( xmlElement.get( "CooldownType", ""+cooldownType ).toUpperCase() );
screenshake = xmlElement.getFloat( "ScreenShake", screenshake );
noSprite = xmlElement.getBoolean( "NoSprite", noSprite );
Icon = xmlElement.getChildByName( "Icon" ) != null ? AssetManager.loadSprite( xmlElement.getChildByName( "Icon" ) ) : Icon;
movementSprite = xmlElement.getChildByName( "MovementSprite" ) != null ? AssetManager.loadSprite( xmlElement.getChildByName( "MovementSprite" ) ) : movementSprite;
useSprite = xmlElement.getChildByName( "UseSprite" ) != null ? AssetManager.loadSprite( xmlElement.getChildByName( "UseSprite" ) ) : useSprite;
Element hitSpriteEl = xmlElement.getChildByName( "HitSprite" );
if ( hitSpriteEl != null )
{
hitSprite = AssetManager.loadSprite( xmlElement.getChildByName( "HitSprite" ) );
singleSprite = hitSpriteEl.getBoolean( "SingleSprite", false );
}
Element lightElement = xmlElement.getChildByName( "Light" );
if ( lightElement != null )
{
light = Roguelike.Lights.Light.load( lightElement );
}
Element costsElement = xmlElement.getChildByName( "Cost" );
if ( costsElement != null )
{
for ( int i = 0; i < costsElement.getChildCount(); i++ )
{
Element costElement = costsElement.getChild( i );
costTypes.add( AbstractCostType.load( costElement ) );
}
}
Element hitTypeElement = xmlElement.getChildByName( "HitType" );
if (hitTypeElement != null)
{
hitType = AbstractHitType.load( hitTypeElement.getChild( 0 ) );
if ( hitType instanceof HitTypeSelf || hitType instanceof HitTypeEnemy || hitType instanceof HitTypeAlly )
{
targetingType = new TargetingTypeEntity();
}
}
Element targetingElement = xmlElement.getChildByName( "Targeting" );
if ( targetingElement != null )
{
targetingType = AbstractTargetingType.load( targetingElement.getChild( 0 ) );
}
Element movementElement = xmlElement.getChildByName( "Movement" );
if ( movementElement != null )
{
movementType = AbstractMovementType.load( movementElement.getChild( 0 ) );
}
Element effectsElement = xmlElement.getChildByName( "Effect" );
if ( effectsElement != null )
{
for ( int i = 0; i < effectsElement.getChildCount(); i++ )
{
Element effectElement = effectsElement.getChild( i );
effectTypes.add( AbstractEffectType.load( effectElement ) );
}
}
Element passabilityElement = xmlElement.getChildByName( "Passability" );
if ( passabilityElement != null )
{
abilityPassability = Passability.parseArray( passabilityElement.getText() );
}
}
// ----------------------------------------------------------------------
@Override
public String getDescription()
{
return description;
}
// ----------------------------------------------------------------------
@Override
public String getName()
{
return name;
}
// ----------------------------------------------------------------------
@Override
public void onTurn()
{
if (cooldownType == CooldownType.TURN)
{
cooldownAccumulator--;
if ( cooldownAccumulator < 0 )
{
cooldownAccumulator = 0;
}
}
}
// ----------------------------------------------------------------------
@Override
public void onMove()
{
if (cooldownType == CooldownType.MOVE)
{
cooldownAccumulator--;
if ( cooldownAccumulator < 0 )
{
cooldownAccumulator = 0;
}
}
}
// ----------------------------------------------------------------------
@Override
public void onAttack()
{
if (cooldownType == CooldownType.ATTACK)
{
cooldownAccumulator--;
if ( cooldownAccumulator < 0 )
{
cooldownAccumulator = 0;
}
}
}
// ----------------------------------------------------------------------
@Override
public void onWait()
{
if (cooldownType == CooldownType.WAIT)
{
cooldownAccumulator--;
if ( cooldownAccumulator < 0 )
{
cooldownAccumulator = 0;
}
}
}
// ----------------------------------------------------------------------
@Override
public void onDamaged()
{
if (cooldownType == CooldownType.HURT )
{
cooldownAccumulator--;
if ( cooldownAccumulator < 0 )
{
cooldownAccumulator = 0;
}
}
}
// ----------------------------------------------------------------------
@Override
public void onHealed()
{
if (cooldownType == CooldownType.HEALED)
{
cooldownAccumulator--;
if ( cooldownAccumulator < 0 )
{
cooldownAccumulator = 0;
}
}
}
// ----------------------------------------------------------------------
@Override
public int getCooldown()
{
return cooldownAccumulator;
}
// ----------------------------------------------------------------------
@Override
public void setCooldown( int val )
{
cooldownAccumulator = val;
}
// ----------------------------------------------------------------------
@Override
public Table createTable( Skin skin, Entity entity )
{
Table table = new Table();
Table header = new Table();
header.add( new Label( name, skin, "title" ) ).expandX().left();
{
Label label = new Label( "Active", skin );
label.setFontScale( 0.7f );
header.add( label ).expandX().right();
}
table.add(header).expandX().fillX().left();
table.row();
String level = "Level: " + tree.level;
if (tree.level == 10)
{
if (tree.branch1 != null)
{
level += " ( Mutate )";
}
else
{
level += " ( Max )";
}
}
else
{
float per = (float) tree.exp / (float) tree.expToNextLevel;
per *= 100;
level += " ( " + (int)per + "% )";
}
table.add(new Label(level, skin)).left();
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( "Cooldown: " + cooldown, skin ) ).expandX().left();
table.row();
table.add( new Label( "Cooldown Type: " + Global.capitalizeString( ""+cooldownType ), skin ) ).expandX().left();
table.row();
table.add( new Label( "Range: " + getRange(), skin ) ).expandX().left();
table.row();
if (aoe > 0)
{
table.add( new Label( "AOE: " + aoe, skin ) ).expandX().left();
table.row();
}
if (cone > 0)
{
table.add( new Label( "Cone: " + cone, skin ) ).expandX().left();
table.row();
}
for ( AbstractCostType cost : costTypes )
{
String string = cost.toString( this );
Label label = new Label( string, skin );
label.setWrap( true );
table.add( label ).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 ( AbstractEffectType effect : effectTypes )
{
Array<String> lines = effect.toString( this );
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 ) ).padBottom( 5 );
table.row();
}
table.row();
}
}
if ( !hasValidTargets )
{
table.add( new Label( "[RED]No valid targets", skin ) ).expandX().left();
table.row();
}
if ( cooldownAccumulator > 0 )
{
table.add( new Label( "[RED]On cooldown", skin ) ).expandX().left();
table.row();
}
return table;
}
// ----------------------------------------------------------------------
@Override
public Sprite getIcon()
{
return Icon;
}
}