Real rename
This commit is contained in:
parent
aa3dd87076
commit
cafb36cb26
68 changed files with 0 additions and 0 deletions
128
Projektgruppe_175/src/game/map/Castle.java
Normal file
128
Projektgruppe_175/src/game/map/Castle.java
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
package game.map;
|
||||
|
||||
import game.Player;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Diese Klasse representiert eine Burg.
|
||||
* Jede Burg hat Koordinaten auf der Karte und einen Namen.
|
||||
* Falls die Burg einen Besitzer hat, hat sie auch eine Anzahl von zugewiesenen Truppen.
|
||||
* Die Burg kann weiterhin Teil eines Königreichs sein.
|
||||
*/
|
||||
public class Castle {
|
||||
|
||||
private int troopCount;
|
||||
private Player owner;
|
||||
private Kingdom kingdom;
|
||||
private Point location;
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Eine neue Burg erstellen
|
||||
* @param location die Koordinaten der Burg
|
||||
* @param name der Name der Burg
|
||||
*/
|
||||
public Castle(Point location, String name) {
|
||||
this.location = location;
|
||||
this.troopCount = 0;
|
||||
this.owner = null;
|
||||
this.kingdom = null;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Player getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
public Kingdom getKingdom() {
|
||||
return this.kingdom;
|
||||
}
|
||||
|
||||
public int getTroopCount() {
|
||||
return this.troopCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truppen von dieser Burg zur angegebenen Burg bewegen.
|
||||
* Dies funktioniert nur, wenn die Besitzer übereinstimmen und bei der aktuellen Burg mindestens eine Truppe übrig bleibt
|
||||
* @param target
|
||||
* @param troops
|
||||
*/
|
||||
public void moveTroops(Castle target, int troops) {
|
||||
|
||||
// Troops can only be moved to own regions
|
||||
if(target.owner != this.owner)
|
||||
return;
|
||||
|
||||
// At least one unit must remain in the source region
|
||||
if(this.troopCount - troops < 1)
|
||||
return;
|
||||
|
||||
this.troopCount -= troops;
|
||||
target.troopCount += troops;
|
||||
}
|
||||
|
||||
public Point getLocationOnMap() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die eukldische Distanz zu dem angegebenen Punkt
|
||||
* @param dest die Zielkoordinate
|
||||
* @return die euklidische Distanz
|
||||
*/
|
||||
public double distance(Point dest) {
|
||||
return Math.sqrt(Math.pow(this.location.x - dest.x, 2) + Math.pow(this.location.y - dest.y, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die eukldische Distanz zu der angegebenen Burg
|
||||
* @param next die Zielburg
|
||||
* @return die euklidische Distanz
|
||||
* @see #distance(Point)
|
||||
*/
|
||||
public double distance(Castle next) {
|
||||
Point otherLocation = next.getLocationOnMap();
|
||||
return this.distance(otherLocation);
|
||||
}
|
||||
|
||||
public void setOwner(Player player) {
|
||||
this.owner = player;
|
||||
}
|
||||
|
||||
public void addTroops(int i) {
|
||||
if(i <= 0)
|
||||
return;
|
||||
|
||||
this.troopCount += i;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void removeTroops(int i) {
|
||||
this.troopCount = Math.max(0, this.troopCount - i);
|
||||
if(this.troopCount == 0)
|
||||
this.owner = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Burg-Typen zurück. Falls die Burg einem Königreich angehört, wird der Typ des Königreichs zurückgegeben, ansonsten 0
|
||||
* @return der Burg-Typ für die Anzeige
|
||||
*/
|
||||
public int getType() {
|
||||
return this.kingdom == null ? 0 : this.kingdom.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Burg einem Königreich zuordnen
|
||||
* @param kingdom Ein Königreich oder null
|
||||
*/
|
||||
public void setKingdom(Kingdom kingdom) {
|
||||
this.kingdom = kingdom;
|
||||
if(kingdom != null)
|
||||
kingdom.addCastle(this);
|
||||
}
|
||||
}
|
||||
40
Projektgruppe_175/src/game/map/Clustering.java
Normal file
40
Projektgruppe_175/src/game/map/Clustering.java
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package game.map;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Diese Klasse teilt Burgen in Königreiche auf
|
||||
*/
|
||||
public class Clustering {
|
||||
|
||||
private Random random;
|
||||
private final List<Castle> allCastles;
|
||||
private final int kingdomCount;
|
||||
|
||||
/**
|
||||
* Ein neues Clustering-Objekt erzeugen.
|
||||
* @param castles Die Liste von Burgen, die aufgeteilt werden sollen
|
||||
* @param kingdomCount Die Anzahl von Königreichen die generiert werden sollen
|
||||
*/
|
||||
public Clustering(List<Castle> castles, int kingdomCount) {
|
||||
if (kingdomCount < 2)
|
||||
throw new IllegalArgumentException("Ungültige Anzahl an Königreichen");
|
||||
|
||||
this.random = new Random();
|
||||
this.kingdomCount = kingdomCount;
|
||||
this.allCastles = Collections.unmodifiableList(castles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt eine Liste von Königreichen zurück.
|
||||
* Jedes Königreich sollte dabei einen Index im Bereich 0-5 bekommen, damit die Burg richtig angezeigt werden kann.
|
||||
* Siehe auch {@link Kingdom#getType()}
|
||||
*/
|
||||
public List<Kingdom> getPointsClusters() {
|
||||
// TODO Clustering#getPointsClusters()
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
256
Projektgruppe_175/src/game/map/GameMap.java
Normal file
256
Projektgruppe_175/src/game/map/GameMap.java
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
package game.map;
|
||||
|
||||
import base.*;
|
||||
import game.GameConstants;
|
||||
import gui.Resources;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Diese Klasse representiert das Spielfeld. Sie beinhaltet das Hintergrundbild, welches mit Perlin noise erzeugt wurde,
|
||||
* eine Liste mit Königreichen und alle Burgen und deren Verbindungen als Graphen.
|
||||
*
|
||||
* Die Karte wird in mehreren Schritten generiert, siehe dazu {@link #generateRandomMap(int, int, int, int, int)}
|
||||
*/
|
||||
public class GameMap {
|
||||
|
||||
private BufferedImage backgroundImage;
|
||||
private Graph<Castle> castleGraph;
|
||||
private List<Kingdom> kingdoms;
|
||||
|
||||
// Map Generation
|
||||
private double[][] noiseValues;
|
||||
private int width, height, scale;
|
||||
|
||||
/**
|
||||
* Erzeugt eine neue leere Karte. Der Konstruktor sollte niemals direkt aufgerufen werden.
|
||||
* Um eine neue Karte zu erstellen, muss {@link #generateRandomMap(int, int, int, int, int)} verwendet werden
|
||||
* @param width die Breite der Karte
|
||||
* @param height die Höhe der Karte
|
||||
* @param scale der Skalierungsfaktor
|
||||
*/
|
||||
private GameMap(int width, int height, int scale) {
|
||||
this.castleGraph = new Graph<>();
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wandelt einen Noise-Wert in eine Farbe um. Die Methode kann nach belieben angepasst werden
|
||||
* @param value der Perlin-Noise-Wert
|
||||
* @return die resultierende Farbe
|
||||
*/
|
||||
private Color doubleToColor(double value) {
|
||||
if (value <= 0.40)
|
||||
return GameConstants.COLOR_WATER;
|
||||
else if (value <= 0.5)
|
||||
return GameConstants.COLOR_SAND;
|
||||
else if (value <= 0.7)
|
||||
return GameConstants.COLOR_GRASS;
|
||||
else if (value <= 0.8)
|
||||
return GameConstants.COLOR_STONE;
|
||||
else
|
||||
return GameConstants.COLOR_SNOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hier wird das Hintergrund-Bild mittels Perlin-Noise erzeugt.
|
||||
* Siehe auch: {@link PerlinNoise}
|
||||
*/
|
||||
private void generateBackground() {
|
||||
PerlinNoise perlinNoise = new PerlinNoise(width, height, scale);
|
||||
Dimension realSize = perlinNoise.getRealSize();
|
||||
|
||||
noiseValues = new double[realSize.width][realSize.height];
|
||||
backgroundImage = new BufferedImage(realSize.width, realSize.height, BufferedImage.TYPE_INT_RGB);
|
||||
for (int x = 0; x < realSize.width; x++) {
|
||||
for (int y = 0; y < realSize.height; y++) {
|
||||
double noiseValue = perlinNoise.getNoise(x, y);
|
||||
noiseValues[x][y] = noiseValue;
|
||||
backgroundImage.setRGB(x, y, doubleToColor(noiseValue).getRGB());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hier werden die Burgen erzeugt.
|
||||
* Dabei wir die Karte in Felder unterteilt, sodass auf jedes Fals maximal eine Burg kommt.
|
||||
* Sollte auf einem Feld keine Position für eine Burg existieren (z.B. aufgrund von Wasser oder angrenzenden Burgen), wird dieses übersprungen.
|
||||
* Dadurch kann es vorkommen, dass nicht alle Burgen generiert werden
|
||||
* @param castleCount die maximale Anzahl der zu generierenden Burgen
|
||||
*/
|
||||
private void generateCastles(int castleCount) {
|
||||
double square = Math.ceil(Math.sqrt(castleCount));
|
||||
double length = width + height;
|
||||
|
||||
int tilesX = (int) Math.max(1, (width / length + 0.5) * square) + 5;
|
||||
int tilesY = (int) Math.max(1, (height / length + 0.5) * square) + 5;
|
||||
int tileW = (width * scale / tilesX);
|
||||
int tileH = (height * scale / tilesY);
|
||||
|
||||
if (tilesX * tilesY < castleCount) {
|
||||
throw new IllegalArgumentException(String.format("CALCULATION Error: tilesX=%d * tilesY=%d < castles=%d", tilesX, tilesY, castleCount));
|
||||
}
|
||||
|
||||
// Add possible tiles
|
||||
List<Point> possibleFields = new ArrayList<>(tilesX * tilesY);
|
||||
for (int x = 0; x < tilesX - 1; x++) {
|
||||
for (int y = 0; y < tilesY - 1; y++) {
|
||||
possibleFields.add(new Point(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
// Generate castles
|
||||
List<String> possibleNames = generateCastleNames();
|
||||
int castlesGenerated = 0;
|
||||
while (possibleFields.size() > 0 && castlesGenerated < castleCount) {
|
||||
Point randomField = possibleFields.remove((int) (Math.random() * possibleFields.size()));
|
||||
int x0 = (int) ((randomField.x + 0.5) * tileW);
|
||||
int y0 = (int) ((randomField.y + 0.5) * tileH);
|
||||
|
||||
for (int x = (int) (0.5 * tileW); x >= 0; x--) {
|
||||
boolean positionFound = false;
|
||||
for (int y = (int) (0.5 * tileH); y >= 0; y--) {
|
||||
int x_mid = (int) (x0 + x + 0.5 * tileW);
|
||||
int y_mid = (int) (y0 + y + 0.5 * tileH);
|
||||
if (noiseValues[x_mid][y_mid] >= 0.6) {
|
||||
String name = possibleNames.isEmpty() ? "Burg " + (castlesGenerated + 1) :
|
||||
possibleNames.get((int) (Math.random() * possibleNames.size()));
|
||||
Castle newCastle = new Castle(new Point(x0 + x, y0 + y), name);
|
||||
boolean doesIntersect = false;
|
||||
|
||||
for (Castle r : castleGraph.getAllValues()) {
|
||||
if (r.distance(newCastle) < Math.max(tileW, tileH)) {
|
||||
doesIntersect = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!doesIntersect) {
|
||||
possibleNames.remove(name);
|
||||
castleGraph.addNode(newCastle);
|
||||
castlesGenerated++;
|
||||
positionFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (positionFound)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hier werden die Kanten erzeugt. Dazu werden zunächst alle Burgen durch eine Linie verbunden und anschließend
|
||||
* jede Burg mit allen anderen in einem bestimmten Radius nochmals verbunden
|
||||
*/
|
||||
private void generateEdges() {
|
||||
// TODO: GameMap#generateEdges()
|
||||
}
|
||||
|
||||
/**
|
||||
* Hier werden die Burgen in Königreiche unterteilt. Dazu wird der {@link Clustering} Algorithmus aufgerufen.
|
||||
* @param kingdomCount die Anzahl der zu generierenden Königreiche
|
||||
*/
|
||||
private void generateKingdoms(int kingdomCount) {
|
||||
if(kingdomCount > 0 && kingdomCount < castleGraph.getAllValues().size()) {
|
||||
Clustering clustering = new Clustering(castleGraph.getAllValues(), kingdomCount);
|
||||
kingdoms = clustering.getPointsClusters();
|
||||
} else {
|
||||
kingdoms = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Eine neue Spielfeldkarte generieren.
|
||||
* Dazu werden folgende Schritte abgearbeitet:
|
||||
* 1. Das Hintergrundbild generieren
|
||||
* 2. Burgen generieren
|
||||
* 3. Kanten hinzufügen
|
||||
* 4. Burgen in Köngireiche unterteilen
|
||||
* @param width die Breite des Spielfelds
|
||||
* @param height die Höhe des Spielfelds
|
||||
* @param scale die Skalierung
|
||||
* @param castleCount die maximale Anzahl an Burgen
|
||||
* @param kingdomCount die Anzahl der Königreiche
|
||||
* @return eine neue GameMap-Instanz
|
||||
*/
|
||||
public static GameMap generateRandomMap(int width, int height, int scale, int castleCount, int kingdomCount) {
|
||||
|
||||
width = Math.max(width, 15);
|
||||
height = Math.max(height, 10);
|
||||
|
||||
if (scale <= 0 || castleCount <= 0)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
System.out.println(String.format("Generating new map, castles=%d, width=%d, height=%d, kingdoms=%d", castleCount, width, height, kingdomCount));
|
||||
GameMap gameMap = new GameMap(width, height, scale);
|
||||
gameMap.generateBackground();
|
||||
gameMap.generateCastles(castleCount);
|
||||
gameMap.generateEdges();
|
||||
gameMap.generateKingdoms(kingdomCount);
|
||||
|
||||
if(!gameMap.getGraph().allNodesConnected()) {
|
||||
System.out.println("Fehler bei der Verifikation: Es sind nicht alle Knoten miteinander verbunden!");
|
||||
return null;
|
||||
}
|
||||
|
||||
return gameMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert eine Liste von Zufallsnamen für Burgen. Dabei wird ein Prefix (Schloss, Burg oder Festung) an einen
|
||||
* vorhandenen Namen aus den Resourcen angefügt. Siehe auch: {@link Resources#getcastleNames()}
|
||||
* @return eine Liste mit Zufallsnamen
|
||||
*/
|
||||
private List<String> generateCastleNames() {
|
||||
String[] prefixes = {"Schloss", "Burg", "Festung"};
|
||||
List<String> names = Resources.getInstance().getCastleNames();
|
||||
List<String> nameList = new ArrayList<>(names.size());
|
||||
|
||||
for (String name : names) {
|
||||
String prefix = prefixes[(int) (Math.random() * prefixes.length)];
|
||||
nameList.add(prefix + " " + name);
|
||||
}
|
||||
|
||||
return nameList;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return this.backgroundImage.getWidth();
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return this.backgroundImage.getHeight();
|
||||
}
|
||||
|
||||
public BufferedImage getBackgroundImage() {
|
||||
return this.backgroundImage;
|
||||
}
|
||||
|
||||
public Dimension getSize() {
|
||||
return new Dimension(this.getWidth(), this.getHeight());
|
||||
}
|
||||
|
||||
public List<Castle> getCastles() {
|
||||
return castleGraph.getAllValues();
|
||||
}
|
||||
|
||||
public Graph<Castle> getGraph() {
|
||||
return this.castleGraph;
|
||||
}
|
||||
|
||||
public List<Edge<Castle>> getEdges() {
|
||||
return this.castleGraph.getEdges();
|
||||
}
|
||||
|
||||
public List<Kingdom> getKingdoms() {
|
||||
return this.kingdoms;
|
||||
}
|
||||
}
|
||||
75
Projektgruppe_175/src/game/map/Kingdom.java
Normal file
75
Projektgruppe_175/src/game/map/Kingdom.java
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
package game.map;
|
||||
|
||||
import game.Player;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Diese Klasse representiert ein Königreich. Jedes Königreich hat eine Liste von Burgen sowie einen Index {@link #type} im Bereich von 0-5
|
||||
*
|
||||
*/
|
||||
public class Kingdom {
|
||||
|
||||
private List<Castle> castles;
|
||||
private int type;
|
||||
|
||||
/**
|
||||
* Erstellt ein neues Königreich
|
||||
* @param type der Typ des Königreichs (im Bereich 0-5)
|
||||
*/
|
||||
public Kingdom(int type) {
|
||||
this.castles = new LinkedList<>();
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eine Burg zum Königreich hinzufügen
|
||||
* @param castle die Burg, die hinzugefügt werden soll
|
||||
*/
|
||||
public void addCastle(Castle castle) {
|
||||
this.castles.add(castle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Typen des Königreichs zurück. Dies wird zur korrekten Anzeige benötigt
|
||||
* @return der Typ des Königreichs.
|
||||
*/
|
||||
public int getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eine Burg aus dem Königreich entfernen
|
||||
* @param castle die zu entfernende Burg
|
||||
*/
|
||||
public void removeCastle(Castle castle) {
|
||||
this.castles.remove(castle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Spieler zurück, der alle Burgen in dem Köngreich besitzt.
|
||||
* Sollte es keinen Spieler geben, der alle Burgen besitzt, wird null zurückgegeben.
|
||||
* @return der Besitzer oder null
|
||||
*/
|
||||
public Player getOwner() {
|
||||
if(castles.isEmpty())
|
||||
return null;
|
||||
|
||||
Player owner = castles.get(0).getOwner();
|
||||
for(Castle castle : castles) {
|
||||
if(castle.getOwner() != owner)
|
||||
return null;
|
||||
}
|
||||
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle Burgen zurück, die in diesem Königreich liegen
|
||||
* @return Liste von Burgen im Königreich
|
||||
*/
|
||||
public List<Castle> getCastles() {
|
||||
return this.castles;
|
||||
}
|
||||
}
|
||||
27
Projektgruppe_175/src/game/map/MapSize.java
Normal file
27
Projektgruppe_175/src/game/map/MapSize.java
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package game.map;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Vector;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum MapSize {
|
||||
|
||||
SMALL("Klein"),
|
||||
MEDIUM("Mittel"),
|
||||
LARGE("Groß");
|
||||
|
||||
private String label;
|
||||
MapSize(String lbl) {
|
||||
this.label = lbl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.label;
|
||||
}
|
||||
|
||||
public static Vector<String> getMapSizes() {
|
||||
return Arrays.stream(values()).map(MapSize::toString).collect(Collectors.toCollection(Vector::new));
|
||||
}
|
||||
|
||||
}
|
||||
58
Projektgruppe_175/src/game/map/PathFinding.java
Normal file
58
Projektgruppe_175/src/game/map/PathFinding.java
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package game.map;
|
||||
|
||||
import base.GraphAlgorithm;
|
||||
import base.Edge;
|
||||
import base.Graph;
|
||||
import game.Player;
|
||||
import game.map.Castle;
|
||||
import gui.components.MapPanel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PathFinding extends GraphAlgorithm<Castle> {
|
||||
|
||||
private MapPanel.Action action;
|
||||
private Player currentPlayer;
|
||||
|
||||
public PathFinding(Graph<Castle> graph, Castle sourceCastle, MapPanel.Action action, Player currentPlayer) {
|
||||
super(graph, graph.getNode(sourceCastle));
|
||||
this.action = action;
|
||||
this.currentPlayer = currentPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double getValue(Edge<Castle> edge) {
|
||||
Castle castleA = edge.getNodeA().getValue();
|
||||
Castle castleB = edge.getNodeB().getValue();
|
||||
return castleA.distance(castleB);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPassable(Edge<Castle> edge) {
|
||||
|
||||
Castle castleA = edge.getNodeA().getValue();
|
||||
Castle castleB = edge.getNodeB().getValue();
|
||||
|
||||
// One of the regions should belong to the current player
|
||||
if(castleA.getOwner() != currentPlayer && castleB.getOwner() != currentPlayer)
|
||||
return false;
|
||||
|
||||
if(action == MapPanel.Action.ATTACKING) {
|
||||
return castleA.getOwner() != null && castleB.getOwner() != null;
|
||||
} else if(action == MapPanel.Action.MOVING) {
|
||||
|
||||
// One of the regions may be empty
|
||||
if(castleA.getOwner() == null || castleB.getOwner() == null)
|
||||
return true;
|
||||
|
||||
// Else both regions should belong to the current player
|
||||
return castleA.getOwner() == castleB.getOwner() && castleA.getOwner() == currentPlayer;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Edge<Castle>> getPath(Castle targetCastle) {
|
||||
return this.getPath(getGraph().getNode(targetCastle));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue