package Roguelike.DungeonGeneration;
import java.io.IOException;
import java.util.Random;
import Roguelike.Util.FastEnumMap;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.XmlReader;
import com.badlogic.gdx.utils.XmlReader.Element;
public class FactionParser
{
public enum FeaturePlacementType
{
FURTHEST, WALL, CENTRE, ANY
}
public String name;
public Array<DungeonFileParser.DFPRoom> rooms = new Array<DungeonFileParser.DFPRoom>( );
public Array<Creature> creatures = new Array<Creature>();
public Array<String> bosses = new Array<String>();
public Array<String> minibosses = new Array<String>( );
public FastEnumMap<FeaturePlacementType, Array<Feature>> features = new FastEnumMap<FeaturePlacementType, Array<Feature>>( FeaturePlacementType.class );
private FactionParser()
{
for ( FeaturePlacementType type : FeaturePlacementType.values() )
{
features.put( type, new Array<Feature>() );
}
}
public Array<Creature> getCreatures( Random ran, float difficulty, int influence )
{
Array<Creature> validCreatures = new Array<Creature>();
for ( Creature creature : creatures )
{
if ( creature.minInfluence <= influence && creature.maxInfluence >= influence )
{
validCreatures.add( creature );
}
}
Array<Creature> chosen = new Array<Creature>();
float maxCost = difficulty;
if ( maxCost < 1 )
{
maxCost = 1;
}
while ( maxCost >= 0 && validCreatures.size > 0 )
{
int index = ran.nextInt( validCreatures.size );
Creature creature = validCreatures.get( index );
if ( maxCost < creature.cost )
{
validCreatures.removeIndex( index );
}
else
{
maxCost -= creature.cost;
chosen.add( creature );
}
}
System.out.println( "Difficulty: " + difficulty + " Num Spawned: " + chosen.size );
return chosen;
}
private void internalLoad( String faction, String path )
{
name = faction;
XmlReader xml = new XmlReader();
Element xmlElement = null;
try
{
xmlElement = xml.parse( Gdx.files.internal( "Entities/" + path + "/" + faction + ".xml" ) );
}
catch ( IOException e )
{
e.printStackTrace();
}
Element featuresElement = xmlElement.getChildByName( "Features" );
if ( featuresElement != null )
{
for ( Element featureElement : featuresElement.getChildrenByName( "Feature" ) )
{
Feature feature = Feature.load( featureElement );
features.get( feature.type ).add( feature );
}
}
Element creaturesElement = xmlElement.getChildByName( "Creatures" );
if ( creaturesElement != null )
{
for ( int i = 0; i < creaturesElement.getChildCount(); i++ )
{
Element creatureElement = creaturesElement.getChild( i );
creatures.add( Creature.load( creatureElement, path ) );
}
}
Element bossesElement = xmlElement.getChildByName( "Bosses" );
if ( bossesElement != null )
{
for ( int i = 0; i < bossesElement.getChildCount(); i++ )
{
Element bossElement = bossesElement.getChild( i );
bosses.add( path + "/" + bossElement.getName() );
}
}
Element miniBossesElement = xmlElement.getChildByName( "MiniBosses" );
if ( miniBossesElement != null )
{
for ( int i = 0; i < miniBossesElement.getChildCount(); i++ )
{
Element miniBossElement = miniBossesElement.getChild( i );
minibosses.add( path + "/" + miniBossElement.getName() );
}
}
Element roomsElement = xmlElement.getChildByName( "Rooms" );
if (roomsElement != null)
{
for (int i = 0; i < roomsElement.getChildCount(); i++)
{
Element roomElement = roomsElement.getChild( i );
DungeonFileParser.DFPRoom room = DungeonFileParser.DFPRoom.parse( roomElement );
// Fill in full creature paths
for ( Symbol s : room.symbolMap.values() )
{
if (s.entityData != null)
{
// Attempt to find the creature
String creaturePath = path + "/" + s.entityData;
boolean found = false;
if (!found)
{
for (Creature c : creatures)
{
if (c.entityName.equals( creaturePath ))
{
found = true;
break;
}
}
}
if (!found)
{
for (String c : minibosses)
{
if (c.equals( creaturePath ))
{
found = true;
break;
}
}
}
if (!found)
{
for (String c : bosses)
{
if (c.equals( creaturePath ))
{
found = true;
break;
}
}
}
if (found)
{
s.entityData = creaturePath;
}
}
}
rooms.add(room);
}
}
}
public static FactionParser load( String faction )
{
String path = "Enemies/" + faction;
if ( !Gdx.files.internal( "Entities/" + path + "/" + faction + ".xml" ).exists() )
{
path = "NPC/" + faction;
if ( !Gdx.files.internal( "Entities/" + path + "/" + faction + ".xml" ).exists() ) { return null; }
}
FactionParser fp = new FactionParser();
fp.internalLoad( faction, path );
return fp;
}
public static class Creature
{
public String entityName;
public float cost;
public int minInfluence;
public int maxInfluence;
public static Creature load( Element xml, String path )
{
Creature creature = new Creature();
creature.entityName = path + "/" + xml.getName();
creature.cost = xml.getFloat( "Cost", 1 );
creature.minInfluence = xml.getInt( "MinInfluence", 0 );
creature.maxInfluence = xml.getInt( "MaxInfluence", 100 );
return creature;
}
}
public static class Feature
{
public Element tileData;
public Element environmentData;
public Element fieldData;
public int minRange;
public int maxRange;
public int coverage;
public float minCoverage = 0;
public float maxCoverage = 100;
public FeaturePlacementType type;
public static Feature load( Element xml )
{
Feature feature = new Feature();
feature.minRange = xml.getInt( "RangeMin", 0 );
feature.maxRange = xml.getInt( "RangeMax", 100 );
Element coverageElement = xml.getChildByName( "Coverage" );
if ( coverageElement != null )
{
feature.coverage = Integer.parseInt( coverageElement.getText() );
feature.minCoverage = coverageElement.getFloatAttribute( "Min", feature.minCoverage );
feature.maxCoverage = coverageElement.getFloatAttribute( "Max", feature.maxCoverage );
}
else
{
feature.coverage = 50;
}
feature.tileData = xml.getChildByName( "TileData" );
feature.environmentData = xml.getChildByName( "EnvironmentData" );
feature.fieldData = xml.getChildByName( "FieldData" );
feature.type = FeaturePlacementType.valueOf( xml.get( "Placement" ).toUpperCase() );
return feature;
}
public Symbol getAsSymbol( Symbol current )
{
Symbol symbol = current.copy();
symbol.character = 'F';
symbol.tileData = tileData != null ? tileData : current.tileData;
symbol.environmentData = environmentData != null ? environmentData : current.environmentData;
symbol.fieldData = fieldData != null ? fieldData : current.fieldData;
return symbol;
}
public int getNumTilesToPlace( int influence, int numValidTiles )
{
float currentInfluence = (float) ( influence - minRange ) / (float) ( maxRange - minRange );
float currentCoverage = ( coverage * currentInfluence ) / 100;
currentCoverage = MathUtils.clamp( currentCoverage, minCoverage, maxCoverage );
int numTilesToPlace = (int) Math.floor( numValidTiles * currentCoverage );
return numTilesToPlace;
}
}
}