package Roguelike.Sound;
import java.io.IOException;
import java.util.HashSet;
import Roguelike.AssetManager;
import Roguelike.Entity.ActivationAction.ActivationActionGroup;
import Roguelike.Global;
import Roguelike.Global.Passability;
import Roguelike.Pathfinding.AStarPathfind;
import Roguelike.Tiles.GameTile;
import Roguelike.Tiles.Point;
import Roguelike.Util.EnumBitflag;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.XmlReader;
import com.badlogic.gdx.utils.XmlReader.Element;
public class SoundInstance
{
private static final EnumBitflag<Passability> SoundPassability = new EnumBitflag<Passability>( new Passability[] { Passability.LEVITATE, Passability.ENTITY } );
public Sound sound;
public String name;
public float minPitch = 0.7f;
public float maxPitch = 1.5f;
public float volume = 0.5f;
public int range = 10;
public int falloffMin = 5;
public HashSet<String> shoutFaction;
public String key;
public Object value;
public SoundInstance()
{
}
public SoundInstance( Sound sound )
{
this.sound = sound;
}
public static SoundInstance load( Element xml )
{
SoundInstance sound = new SoundInstance();
sound.name = xml.get( "Name" );
sound.sound = AssetManager.loadSound( sound.name );
sound.range = xml.getInt( "Range", sound.range );
sound.falloffMin = xml.getInt( "FalloffMin", sound.falloffMin );
sound.volume = xml.getFloat( "Volume", sound.volume );
sound.minPitch = xml.getFloat( "Pitch", sound.minPitch );
sound.minPitch = xml.getFloat( "Pitch", sound.maxPitch );
sound.minPitch = xml.getFloat( "MinPitch", sound.minPitch );
sound.maxPitch = xml.getFloat( "MaxPitch", sound.maxPitch );
return sound;
}
public SoundInstance copy()
{
SoundInstance soundInstance = new SoundInstance( );
soundInstance.sound = sound;
soundInstance.name = name;
soundInstance.minPitch = minPitch;
soundInstance.maxPitch = maxPitch;
soundInstance.volume = volume;
soundInstance.range = range;
soundInstance.falloffMin = falloffMin;
soundInstance.shoutFaction = shoutFaction;
soundInstance.key = key;
soundInstance.value = value;
return soundInstance;
}
public void play( GameTile tile )
{
// calculate data propogation
float playerDist = Integer.MAX_VALUE;
Point shoutSource = Global.PointPool.obtain().set( tile.x, tile.y );
int maxAudibleDist = range;// ( range / 4 ) * 3;
if ( key != null )
{
for ( int x = tile.x - range; x < tile.x + range; x++ )
{
for ( int y = tile.y - range; y < tile.y + range; y++ )
{
if ( x >= 0 && x < tile.level.width && y >= 0 && y < tile.level.height )
{
GameTile t = tile.level.getGameTile( x, y );
if ( t.entity != null )
{
AStarPathfind astar = new AStarPathfind( tile.level.getGrid(), tile.x, tile.y, x, y, Global.CanMoveDiagonal, false, 1, SoundPassability, null );
Array<Point> path = astar.getPath();
if ( path != null && path.size < maxAudibleDist )
{
if ( t.entity == tile.level.player )
{
playerDist = path.size;
}
else if ( tile.entity != null && tile.entity.isAllies( shoutFaction ) )
{
t.entity.AI.setData( key, value );
}
else
{
t.entity.AI.setData( "EnemyPos", shoutSource );
}
}
if ( path != null )
{
Global.PointPool.freeAll( path );
}
}
if ( t.environmentEntity != null && t.environmentEntity.onHearActions.size > 0 )
{
boolean hasActive = false;
for ( ActivationActionGroup group : t.environmentEntity.onHearActions )
{
if (group.enabled)
{
hasActive = true;
break;
}
}
if (hasActive)
{
AStarPathfind astar = new AStarPathfind( tile.level.getGrid(), tile.x, tile.y, x, y, true, false, 1, SoundPassability, null );
Array<Point> path = astar.getPath();
if ( path != null && path.size < maxAudibleDist )
{
for ( ActivationActionGroup group : t.environmentEntity.onHearActions )
{
group.activate( t.environmentEntity, null, 1 );
}
}
if ( path != null )
{
Global.PointPool.freeAll( path );
}
}
}
}
}
}
}
else
{
playerDist = Vector2.dst( tile.x, tile.y, tile.level.player.tile[0][0].x, tile.level.player.tile[0][0].y );
}
if (Global.EffectVolume > 0)
{
// calculate sound play volume
if ( playerDist <= range && sound != null )
{
float vol = volume * Global.EffectVolume;
if ( playerDist > falloffMin )
{
float alpha = 1 - ( playerDist - falloffMin ) / ( range - falloffMin );
vol *= alpha;
}
float xdiff = tile.x - tile.level.player.tile[0][0].x;
xdiff /= range;
sound.play( vol, minPitch + MathUtils.random() * ( maxPitch - minPitch ), xdiff );
}
}
}
private static final ObjectMap<String, Element> soundMap = new ObjectMap<String, Element>( );
private static boolean loaded = false;
public static SoundInstance getSound( String name )
{
if ( !loaded )
{
loaded = true;
XmlReader reader = new XmlReader();
Element xml = null;
try
{
xml = reader.parse( Gdx.files.internal( "Sound/SoundMap.xml" ) );
}
catch ( IOException e )
{
e.printStackTrace();
}
for ( int i = 0; i < xml.getChildCount(); i++ )
{
Element el = xml.getChild( i );
soundMap.put( el.getName(), el );
}
}
if ( soundMap.containsKey( name ) )
{
return SoundInstance.load( soundMap.get( name ) );
}
else
{
SoundInstance sound = new SoundInstance( );
sound.name = name;
sound.sound = AssetManager.loadSound( name );
return sound;
}
}
}