package Roguelike.Entity;
import java.util.HashMap;
import java.util.Iterator;
import Roguelike.AssetManager;
import Roguelike.GameEvent.AdditionalSprite;
import Roguelike.GameEvent.IGameObject;
import Roguelike.Global;
import Roguelike.Global.Direction;
import Roguelike.Global.Passability;
import Roguelike.Global.Statistic;
import Roguelike.GameEvent.GameEventHandler;
import Roguelike.Items.Inventory;
import Roguelike.Items.Item;
import Roguelike.Items.Item.EquipmentSlot;
import Roguelike.Lights.Light;
import Roguelike.Pathfinding.ShadowCastCache;
import Roguelike.Sprite.TilingSprite;
import Roguelike.Sprite.Sprite;
import Roguelike.StatusEffect.StatusEffect;
import Roguelike.Tiles.GameTile;
import Roguelike.UI.Message;
import Roguelike.Util.EnumBitflag;
import Roguelike.Util.FastEnumMap;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.XmlReader.Element;
public abstract class Entity implements IGameObject
{
// ----------------------------------------------------------------------
public abstract void update( float delta );
// ----------------------------------------------------------------------
public abstract int getStatistic( Statistic stat );
// ----------------------------------------------------------------------
protected abstract void internalLoad( String file );
// ----------------------------------------------------------------------
public abstract Array<GameEventHandler> getAllHandlers();
// ----------------------------------------------------------------------
protected void baseInternalLoad( Element xml )
{
name = xml.get( "Name", name );
size = xml.getInt( "Size", size );
if ( size < 1 )
{
size = 1;
}
tile = new GameTile[size][size];
quality = xml.getInt( "Quality", quality );
Element spriteElement = xml.getChildByName( "Sprite" );
if ( spriteElement != null )
{
sprite = AssetManager.loadSprite( xml.getChildByName( "Sprite" ) );
}
if ( sprite != null )
{
sprite.size[0] = size;
sprite.size[1] = size;
}
Element raisedSpriteElement = xml.getChildByName( "TilingSprite" );
if ( raisedSpriteElement != null )
{
tilingSprite = TilingSprite.load( raisedSpriteElement );
}
if ( tilingSprite != null )
{
//for (Sprite sprite : tilingSprite.sprites)
//{
// sprite.size = size;
//}
}
Element lightElement = xml.getChildByName( "Light" );
if ( lightElement != null )
{
light = Roguelike.Lights.Light.load( lightElement );
}
Element statElement = xml.getChildByName( "Statistics" );
if ( statElement != null )
{
Statistic.load( statElement, statistics );
HP = getMaxHP();
statistics.put( Statistic.WALK, 1 );
//statistics.put( Statistic.ENTITY, 1 );
}
Element inventoryElement = xml.getChildByName( "Inventory" );
if ( inventoryElement != null )
{
inventory.load( inventoryElement );
}
Element immuneElement = xml.getChildByName( "Immune" );
if ( immuneElement != null )
{
immune = immuneElement.getText().toLowerCase().split( "," );
}
canTakeDamage = xml.getBoolean( "CanTakeDamage", canTakeDamage );
UID = getClass().getSimpleName() + " " + name + ": ID " + hashCode();
}
// ----------------------------------------------------------------------
public int getVariable( Statistic stat )
{
return getVariableMap().get( stat.toString().toLowerCase() );
}
// ----------------------------------------------------------------------
private FastEnumMap<Statistic, Integer> getStatistics()
{
FastEnumMap<Statistic, Integer> newMap = new FastEnumMap<Statistic, Integer>( Statistic.class );
for ( Statistic stat : Statistic.values() )
{
newMap.put( stat, getStatistic( stat ) );
}
return newMap;
}
// ----------------------------------------------------------------------
public HashMap<String, Integer> getVariableMap()
{
recalculateMaps();
return variableMap;
}
// ----------------------------------------------------------------------
public HashMap<String, Integer> getBaseVariableMap()
{
recalculateMaps();
return baseVariableMap;
}
// ----------------------------------------------------------------------
public void recalculateMaps()
{
if ( isVariableMapDirty )
{
isVariableMapDirty = false;
calculateBaseVariableMap();
calculateVariableMap();
travelType = Passability.variableMapToTravelType( variableMap );
}
}
// ----------------------------------------------------------------------
protected void calculateVariableMap()
{
variableMap.clear();
for ( Statistic s : Statistic.values() )
{
variableMap.put( s.toString().toLowerCase(), statistics.get( s ) );
}
for ( GameEventHandler handler : getAllHandlers() )
{
for ( Statistic s : Statistic.values() )
{
String key = s.toString().toLowerCase();
variableMap.put( key, variableMap.get( key ) + handler.getStatistic( baseVariableMap, s ) );
}
}
variableMap.put( "hp", HP );
for ( EquipmentSlot slot : EquipmentSlot.values() )
{
Item equipped = inventory.getEquip( slot );
if ( equipped != null && equipped.type != null )
{
variableMap.put( equipped.type, 1 );
}
}
for ( StatusEffectStack s : stacks )
{
variableMap.put( s.effect.name.toLowerCase(), s.count );
}
for ( Statistic s : Statistic.values() )
{
variableMap.put( s.toString().toLowerCase(), getStatistic( s ) );
}
variableMap.put( "maxhp", variableMap.get( Statistic.CONSTITUTION.toString().toLowerCase() ) * 10 );
if (inventory.getEquip( EquipmentSlot.WEAPON ) != null)
{
Item wep = inventory.getEquip( EquipmentSlot.WEAPON );
int atk = Global.calculateScaledAttack( Statistic.statsBlockToVariableBlock( wep.getStatistics( variableMap ) ), variableMap );
String key = Statistic.ATTACK.toString().toLowerCase();
variableMap.put( key, variableMap.get( key ) + atk );
}
}
// ----------------------------------------------------------------------
protected void calculateBaseVariableMap()
{
baseVariableMap.clear();
for ( Statistic s : Statistic.values() )
{
baseVariableMap.put( s.toString().toLowerCase(), statistics.get( s ) + inventory.getStatistic( Statistic.emptyMap, s ) );
}
baseVariableMap.put( "maxhp", baseVariableMap.get( Statistic.CONSTITUTION.toString().toLowerCase() ) * 10 );
baseVariableMap.put( "hp", HP );
for ( EquipmentSlot slot : EquipmentSlot.values() )
{
Item equipped = inventory.getEquip( slot );
if ( equipped != null && equipped.type != null )
{
baseVariableMap.put( equipped.type, 1 );
}
}
for ( StatusEffectStack s : stacks )
{
baseVariableMap.put( s.effect.name.toLowerCase(), s.count );
}
}
// ----------------------------------------------------------------------
public Inventory getInventory()
{
return inventory;
}
// ----------------------------------------------------------------------
public void applyDamage( int dam, Entity damager )
{
if ( !canTakeDamage || HP == 0 ) { return; }
HP = Math.max( HP - dam, 0 );
if ( HP == 0 )
{
for ( GameEventHandler handler : getAllHandlers() )
{
handler.onDeath( this, damager );
}
}
damageAccumulator += dam;
hasDamage = true;
extraUIHP += dam;
if (HP + extraUIHP > getMaxHP() )
{
extraUIHP = getMaxHP() - HP;
}
if ( dam != 0 )
{
isVariableMapDirty = true;
}
}
// ----------------------------------------------------------------------
public void applyHealing( int heal )
{
if ( !canTakeDamage ) { return; }
int appliedHeal = Math.min( heal, getMaxHP() - HP );
HP += appliedHeal;
extraUIHP -= appliedHeal;
if (extraUIHP < 0) { extraUIHP = 0; }
healingAccumulator += appliedHeal;
if ( heal != 0 )
{
isVariableMapDirty = true;
}
}
// ----------------------------------------------------------------------
public int getMaxHP()
{
return getVariable( Statistic.CONSTITUTION ) * 10;
}
// ----------------------------------------------------------------------
public Array<StatusEffectStack> stackStatusEffects()
{
Array<StatusEffectStack> stacks = new Array<StatusEffectStack>();
for ( StatusEffect se : statusEffects )
{
boolean found = false;
for ( StatusEffectStack stack : stacks )
{
if ( stack.effect.name.equals( se.name ) )
{
stack.count++;
found = true;
break;
}
}
if ( !found )
{
StatusEffectStack stack = new StatusEffectStack();
stack.count = 1;
stack.effect = se;
stacks.add( stack );
}
}
return stacks;
}
// ----------------------------------------------------------------------
public boolean isImmune( String name )
{
if ( immune == null ) { return false; }
for ( String s : immune )
{
if ( s.equalsIgnoreCase( name ) )
{
return true;
}
}
return false;
}
// ----------------------------------------------------------------------
public void addStatusEffect( StatusEffect se )
{
if ( !canTakeDamage ) { return; }
if ( isImmune( se.getName().toLowerCase() ) ) { return; }
pendingStatusEffects.add( se );
}
// ----------------------------------------------------------------------
public void processStatuses()
{
processPendingStatuses();
boolean removedStatusEffect = false;
Iterator<StatusEffect> itr = statusEffects.iterator();
while ( itr.hasNext() )
{
StatusEffect se = itr.next();
if ( se.duration <= 0 )
{
se.onExpire( this );
itr.remove();
isVariableMapDirty = true;
}
}
if (removedStatusEffect)
{
stacks = stackStatusEffects();
}
processPendingStatuses();
replacementSprite = null;
additionalSprites.clear();
for (StatusEffect se : statusEffects)
{
if (se.replacementSprite != null)
{
replacementSprite = se.replacementSprite;
}
for (AdditionalSprite as : se.additionalSprites)
{
additionalSprites.add( as );
}
}
}
// ----------------------------------------------------------------------
public void processPendingStatuses()
{
if (pendingStatusEffects.size > 0)
{
for (StatusEffect se : pendingStatusEffects)
{
boolean needsAdding = true;
if (!se.stackable)
{
for (StatusEffect ose : statusEffects)
{
if (ose.name.equals( se.name ))
{
ose.duration = Math.max( ose.duration, se.duration );
needsAdding = false;
break;
}
}
}
if ( needsAdding )
{
statusEffects.add( se );
}
}
stacks = stackStatusEffects();
isVariableMapDirty = true;
pendingStatusEffects.clear();
}
}
// ----------------------------------------------------------------------
public void removeStatusEffect( String se )
{
for ( int i = 0; i < statusEffects.size; i++ )
{
if ( statusEffects.get( i ).name.equals( se ) )
{
statusEffects.removeIndex( i );
isVariableMapDirty = true;
break;
}
}
stacks = stackStatusEffects();
}
// ----------------------------------------------------------------------
public void setPopupText( String text, float duration )
{
if (popup != null && popup.equals( text ))
{
return;
}
popup = text;
displayedPopup = "";
popupDuration = duration;
popupFade = 1;
popupAccumulator = 0;
}
// ----------------------------------------------------------------------
public abstract void removeFromTile();
// ----------------------------------------------------------------------
public void updateShadowCast()
{
visibilityCache.getShadowCast( tile[0][0].level.Grid, tile[0][0].x, tile[0][0].y, getStatistic( Statistic.PERCEPTION ), this );
}
// ----------------------------------------------------------------------
@Override
public String getName()
{
return name;
}
// ----------------------------------------------------------------------
@Override
public String getDescription()
{
return "";
}
// ----------------------------------------------------------------------
@Override
public Sprite getIcon()
{
return sprite;
}
// ----------------------------------------------------------------------
public Sprite replacementSprite;
public Array<AdditionalSprite> additionalSprites = new Array<AdditionalSprite>( );
// ----------------------------------------------------------------------
public boolean weaponSheathed = false;
// ----------------------------------------------------------------------
public boolean isVariableMapDirty = true;
// ----------------------------------------------------------------------
protected HashMap<String, Integer> baseVariableMap = new HashMap<String, Integer>();
protected HashMap<String, Integer> variableMap = new HashMap<String, Integer>();
protected EnumBitflag<Passability> travelType = new EnumBitflag<Passability>();
// ----------------------------------------------------------------------
public int damageAccumulator = 0;
public int healingAccumulator = 0;
public boolean hasDamage = false;
// ----------------------------------------------------------------------
public Array<Message> pendingMessages = new Array<Message>( );
public float messageAccumulator = 0;
public static final float MESSAGE_DELAY = 0.4f;
// ----------------------------------------------------------------------
public String[] immune;
public FastEnumMap<Statistic, Integer> statistics = Statistic.getStatisticsBlock();
public Array<StatusEffect> statusEffects = new Array<StatusEffect>( false, 16 );
public Array<StatusEffect> pendingStatusEffects = new Array<StatusEffect>( );
public Array<StatusEffectStack> stacks = new Array<StatusEffectStack>();
public Inventory inventory = new Inventory();
// ----------------------------------------------------------------------
public String name = "";
// ----------------------------------------------------------------------
public String popup;
public String displayedPopup;
public float popupDuration = 0;
public float popupFade = 0;
public float popupAccumulator = 0;
// ----------------------------------------------------------------------
public Sprite sprite;
public TilingSprite tilingSprite;
public Light light;
// ----------------------------------------------------------------------
public GameTile[][] tile = new GameTile[1][1];
public int size = 1;
public Direction location = Direction.CENTER;
// ----------------------------------------------------------------------
public int HP = 1;
public int extraUIHP = 0;
public float extraUIHPAccumulator = 0;
public int essence = 0;
// ----------------------------------------------------------------------
public boolean canTakeDamage = true;
// ----------------------------------------------------------------------
public int quality = 1;
// ----------------------------------------------------------------------
public String UID;
// ----------------------------------------------------------------------
public ShadowCastCache visibilityCache = new ShadowCastCache( );
// ----------------------------------------------------------------------
public static class StatusEffectStack
{
public StatusEffect effect;
public int count;
}
}