/*******************************************************************************
* 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.logic.map.loading.original;
import java.util.BitSet;
import jsettlers.algorithms.partitions.IBlockingProvider;
import jsettlers.algorithms.partitions.PartitionCalculatorAlgorithm;
import jsettlers.common.landscape.ELandscapeType;
import jsettlers.common.landscape.EResourceType;
import jsettlers.common.logging.MilliStopWatch;
import jsettlers.common.map.IMapData;
import jsettlers.common.map.object.BuildingObject;
import jsettlers.common.map.object.MapObject;
import jsettlers.common.map.object.MovableObject;
import jsettlers.common.map.object.StackObject;
import jsettlers.common.position.ShortPoint2D;
import jsettlers.logic.map.loading.original.OriginalMapFileDataStructs.EMapBuildingType;
import jsettlers.logic.map.loading.original.OriginalMapFileDataStructs.EMapResources;
import jsettlers.logic.map.loading.original.OriginalMapFileDataStructs.EMapSettlersType;
import jsettlers.logic.map.loading.original.OriginalMapFileDataStructs.EMapStackType;
/**
* @author Thomas Zeugner
* @author codingberlin
*/
public class OriginalMapFileContent implements IMapData {
// - Heigh of original maps are 0..225 and of remake 0..127
private final static float ORIGINAL_TO_REMAKE_HEIGHT_FACTOR = 127f / 225f;
private final static float ORIGINAL_TO_REMAKE_RESOURCE_AMOUNT_FACTOR = 127f / 15f;
// --------------------------------------------------//
public static class MapPlayerInfo {
public int startX;
public int startY;
public String playerName;
public OriginalMapFileDataStructs.EMapNations nation;
public MapPlayerInfo(int x, int y, String playerName, int nationInt) {
this.startX = x;
this.startY = y;
this.playerName = playerName;
this.nation = OriginalMapFileDataStructs.EMapNations.fromMapValue(nationInt);
}
public MapPlayerInfo(int x, int y) {
this.startX = x;
this.startY = y;
this.playerName = "";
this.nation = OriginalMapFileDataStructs.EMapNations.ROMANS;
}
}
// --------------------------------------------------//
public int fileChecksum = 0;
// - original maps are squared
private int widthHeight = 0;
private int dataCount = 0;
private byte[] height = null;
private ELandscapeType[] landscapeType = null;
private MapObject[] mapObject = null;
private byte[] accessible = null;
private EResourceType[] resources = null;
private byte[] resourceAmount = null;
private short[] blockedPartitions = null;
private MapPlayerInfo[] mapPlayerInfos;
public OriginalMapFileContent(int widthHeight) {
setWidthHeight(widthHeight);
}
public void setWidthHeight(int widthHeight) {
this.widthHeight = widthHeight;
dataCount = widthHeight * widthHeight;
height = new byte[dataCount];
landscapeType = new ELandscapeType[dataCount];
mapObject = new MapObject[dataCount];
accessible = new byte[dataCount];
resources = new EResourceType[dataCount];
resourceAmount = new byte[dataCount];
blockedPartitions = new short[dataCount];
}
public void setLandscapeHeight(int pos, int height) {
if ((pos < 0) || (pos > dataCount))
return;
// - apply scaling from original to remake
height = Math.round(height * ORIGINAL_TO_REMAKE_HEIGHT_FACTOR);
if (height < 0)
height = 0;
this.height[pos] = (byte) height;
}
public void setLandscape(int pos, int type) {
if ((pos < 0) || (pos > dataCount))
return;
OriginalMapFileDataStructs.EOriginalLandscapeType originalType = OriginalMapFileDataStructs.EOriginalLandscapeType.getTypeByInt(type);
landscapeType[pos] = originalType.value;
}
public void setMapObject(int pos, int type) {
if ((pos < 0) || (pos > dataCount))
return;
mapObject[pos] = OriginalMapFileDataStructs.EObjectType.getTypeByInt(type).getNewInstance();
}
public void setPlayerCount(int count) {
mapPlayerInfos = new MapPlayerInfo[count];
for (int i = 0; i < count; i++) {
// - init new player with "random" start position
mapPlayerInfos[i] = new MapPlayerInfo(20 + i * 10, 20 + i * 10);
}
}
public void setPlayer(int index, int x, int y, int nationType, String playerName) {
// System.out.println("Player "+ Integer.toString(index) +" : "+ playerName +" @ ("+ x +" , "+ y +")");
if ((index < 0) || (index >= mapPlayerInfos.length))
return;
mapPlayerInfos[index].nation = OriginalMapFileDataStructs.EMapNations.fromMapValue(nationType);
mapPlayerInfos[index].startX = x;
mapPlayerInfos[index].startY = y;
mapPlayerInfos[index].playerName = playerName;
}
public void setMapObject(int x, int y, MapObject newMapObject) {
int pos = y * widthHeight + x;
if ((pos < 0) || (pos >= dataCount))
return;
mapObject[pos] = newMapObject;
}
public void setBuilding(int x, int y, int buildingType, int party, int countSword1, int countSword2, int countSword3, int countArcher1, int countArcher2,
int countArcher3, int countSpear1, int countSpear2, int countSpear3) {
int pos = y * widthHeight + x;
if ((pos < 0) || (pos >= dataCount))
return;
EMapBuildingType mapBuildingType = EMapBuildingType.getTypeByInt(buildingType);
if (mapBuildingType == EMapBuildingType.NOT_A_BUILDING)
return;
if (mapBuildingType.value != null) {
mapObject[pos] = new BuildingObject(mapBuildingType.value, (byte) party);
}
}
public void setSettler(int x, int y, int settlerType, int party) {
int pos = y * widthHeight + x;
if ((pos < 0) || (pos >= dataCount))
return;
EMapSettlersType mapSettlerType = EMapSettlersType.getTypeByInt(settlerType);
if (mapSettlerType == EMapSettlersType.NOT_A_SETTLER)
return;
if (mapSettlerType.value != null) {
mapObject[pos] = new MovableObject(mapSettlerType.value, (byte) party);
}
}
public void setStack(int x, int y, int stackType, int count) {
int pos = y * widthHeight + x;
if ((pos < 0) || (pos >= dataCount))
return;
EMapStackType mapStackType = EMapStackType.getTypeByInt(stackType);
if (mapStackType == EMapStackType.NOT_A_STACK)
return;
if (mapStackType.value != null) {
mapObject[pos] = new StackObject(mapStackType.value, count);
}
}
public void setAccessible(int pos, byte isAccessible) {
if ((pos < 0) || (pos >= dataCount))
return;
accessible[pos] = isAccessible;
}
public void setResources(int pos, int resourcesType, int resourcesAmount) {
if ((pos < 0) || (pos >= dataCount))
return;
EMapResources mapResources = EMapResources.getTypeByInt(resourcesType);
if (resourcesAmount == 0) {
resources[pos] = EResourceType.NOTHING;
resourceAmount[pos] = 0;
} else {
resources[pos] = mapResources.value;
resourceAmount[pos] = (byte) Math.round((resourcesAmount) * ORIGINAL_TO_REMAKE_RESOURCE_AMOUNT_FACTOR);
}
}
// - free the Arrays
public void freeBuffer() {
dataCount = 0;
height = null;
landscapeType = null;
mapObject = null;
blockedPartitions = null;
accessible = null;
resources = null;
resourceAmount = null;
}
// ------------------------//
// -- Interface IMapData --//
// ------------------------//
@Override
public int getWidth() {
return widthHeight;
}
@Override
public int getHeight() {
return widthHeight;
}
@Override
public ELandscapeType getLandscape(int x, int y) {
int pos = y * widthHeight + x;
if ((pos < 0) || (pos >= dataCount))
return ELandscapeType.WATER1;
if (landscapeType[pos] == null)
return ELandscapeType.GRASS;
return landscapeType[pos];
}
@Override
public MapObject getMapObject(int x, int y) {
int pos = y * widthHeight + x;
if ((pos < 0) || (pos >= dataCount))
return null;
return mapObject[pos];
}
@Override
public byte getLandscapeHeight(int x, int y) {
int pos = y * widthHeight + x;
if ((pos < 0) || (pos >= dataCount))
return 0;
return height[pos];
}
/**
* Gets the amount of resources for a given position. In range 0..127
*/
@Override
public byte getResourceAmount(short x, short y) {
int pos = y * widthHeight + x;
if ((pos < 0) || (pos >= dataCount))
return 0;
if (resources[pos] == null)
return 0;
return resourceAmount[pos];
}
@Override
public EResourceType getResourceType(short x, short y) {
int pos = y * widthHeight + x;
if ((pos < 0) || (pos >= dataCount))
return EResourceType.NOTHING;
if (resources[pos] == null)
return EResourceType.NOTHING;
return resources[pos];
}
/**
* Gets the id of the blocked partition of the given position.
*
* @return The id of the blocked partition the given position belongs to.
*/
@Override
public short getBlockedPartition(short x, short y) {
int pos = y * widthHeight + x;
if ((pos < 0) || (pos >= dataCount))
return 0;
return blockedPartitions[pos];
}
public void calculateBlockedPartitions() {
MilliStopWatch watch = new MilliStopWatch();
BitSet notBlockedSet = new BitSet(dataCount);
for (int pos = 0; pos < dataCount; pos++) {
notBlockedSet.set(pos, !landscapeType[pos].isBlocking);
}
PartitionCalculatorAlgorithm partitionCalculator = new PartitionCalculatorAlgorithm(0, 0, widthHeight, widthHeight, notBlockedSet,
IBlockingProvider.DEFAULT_IMPLEMENTATION);
partitionCalculator.calculatePartitions();
for (short y = 0; y < widthHeight; y++) {
for (short x = 0; x < widthHeight; x++) {
blockedPartitions[x + widthHeight * y] = partitionCalculator.getPartitionAt(x, y);
}
}
watch.stop("Calculating partitions needed");
System.out.println("found " + partitionCalculator.getNumberOfPartitions() + " partitions.");
}
@Override
public ShortPoint2D getStartPoint(int player) {
if ((player < 0) || (player >= mapPlayerInfos.length)) {
System.out.print("Error: not a player for getStartPoint(" + player + ")");
return new ShortPoint2D(100, 100);
}
return new ShortPoint2D(mapPlayerInfos[player].startX, mapPlayerInfos[player].startY);
}
@Override
public int getPlayerCount() {
return mapPlayerInfos.length;
}
}