/*******************************************************************************
* Copyright (c) 2015
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*******************************************************************************/
package jsettlers.graphics.sound;
import jsettlers.common.landscape.ELandscapeType;
import jsettlers.common.map.shapes.MapRectangle;
import jsettlers.common.mapobject.EMapObjectType;
import jsettlers.common.mapobject.IMapObject;
import jsettlers.graphics.map.MapDrawContext;
/**
* Plays the background sound for birds and landscapes.
*
* @author michael
*/
public class BackgroundSound implements Runnable {
private static final int BACKGROUND_SLEEP_TIME = 50;
private static final double BIRDS1_FRACTION = .25;
private static final double BIRDS_FREQUENCY = .3;
private static final float BIRDS_VOLUME = .4f;
private static final float WATER_VOLUME = .1f;
private static final float DESERT_VOLUME = .05f;
private static final float RIVER_VOLUME = .03f;
private static final float MOUNTAIN_VOLUME = .003f;
private static final int INDEX_BIRDS1 = 69;
private static final int INDEX_BIRDS2 = 70;
private static final int INDEX_WATER = 68;
private static final int INDEX_DESERT = 67;
private static final int INDEX_RIVER = 71;
private static final int INDEX_MOUNTAIN = 73;
private final MapDrawContext map;
private final SoundManager sound;
private final Object waitMutex = new Object();
private boolean stopped = false;
/**
* Creates a new background sound player.
*
* @param map
* The map draw context to generate sounds for.
* @param sound
* The sound manager to use.
*/
public BackgroundSound(MapDrawContext map, SoundManager sound) {
this.map = map;
this.sound = sound;
}
@Override
public void run() {
try {
while (!stopped) {
waitTime(BACKGROUND_SLEEP_TIME);
if (stopped) {
break;
}
MapRectangle screen = map.getScreenArea();
if (screen == null) {
continue;
}
sound.setMap(map);
int line = (int) (Math.random() * screen.getLines());
int x0 = screen.getLineStartX(line);
int x = x0 + (int) (Math.random() * screen.getLineLength());
int y = screen.getLineY(line);
if (hasTree(x, y) && Math.random() < BIRDS_FREQUENCY) {
if (Math.random() < BIRDS1_FRACTION) {
sound.playSound(INDEX_BIRDS1, BIRDS_VOLUME, x, y);
} else {
sound.playSound(INDEX_BIRDS2, BIRDS_VOLUME, x, y);
}
} else if (hasDesert(x, y)) {
sound.playSound(INDEX_DESERT, DESERT_VOLUME, x, y);
} else if (hasWater(x, y)) {
sound.playSound(INDEX_WATER, WATER_VOLUME, x, y);
} else if (hasMountain(x, y)) {
sound.playSound(INDEX_MOUNTAIN, MOUNTAIN_VOLUME, x, y);
} else for (int x1 = 0; x1 < screen.getLineLength(); x1++) {
if (hasRiver(x0 + x1, y)) {
sound.playSound(INDEX_RIVER, RIVER_VOLUME, x0 + x1, y);;
}
}
}
} catch (Throwable e) {
System.out.println("Sound thread died because of an exception.");
e.printStackTrace();
}
}
private void waitTime(int time) {
synchronized (waitMutex) {
try {
waitMutex.wait(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private boolean hasDesert(int x, int y) {
return map.checkMapCoordinates(x, y) && map.getVisibleStatus(x, y) != 0
&& map.getLandscape(x, y) == ELandscapeType.DESERT;
}
private boolean hasWater(int x, int y) {
return map.checkMapCoordinates(x, y) && map.getVisibleStatus(x, y) != 0
&& map.getLandscape(x, y) == ELandscapeType.WATER1;
}
private boolean hasRiver(int x, int y) {
return map.checkMapCoordinates(x, y) && map.getVisibleStatus(x, y) != 0
&& map.getLandscape(x, y) == ELandscapeType.RIVER1;
}
private boolean hasMountain(int x, int y) {
return map.checkMapCoordinates(x, y) && map.getVisibleStatus(x, y) != 0
&& map.getLandscape(x, y) == ELandscapeType.MOUNTAIN;
}
private boolean hasTree(int cx, int cy) {
for (int x = cx - 2; x <= cx + 2; x++) {
for (int y = cy - 2; y <= cy + 2; y++) {
if (map.checkMapCoordinates(x, y)
&& map.getVisibleStatus(x, y) != 0
&& hasTreeObject(x, y)) {
return true;
}
}
}
return false;
}
private boolean hasTreeObject(int x, int y) {
IMapObject o = map.getMap().getMapObjectsAt(x, y);
while (o != null) {
EMapObjectType type = o.getObjectType();
if (type == EMapObjectType.TREE_ADULT
|| type == EMapObjectType.TREE_DEAD) {
return true;
}
o = o.getNextObject();
}
return false;
}
/**
* Starts the sound player.
*/
public void start() {
Thread thread = new Thread(this, "background-sound");
thread.start();
}
/**
* Stops the sound player.
*/
public void stop() {
synchronized (waitMutex) {
stopped = true;
waitMutex.notifyAll();
}
}
}