mirror of
https://github.com/badvision/lawless-legends.git
synced 2024-06-08 02:29:30 +00:00
821 lines
29 KiB
Java
821 lines
29 KiB
Java
/*
|
|
* Copyright (C) 2015 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
|
|
* (the "License"); you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-1.1>.
|
|
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
|
* ANY KIND, either express or implied. See the License for the specific language
|
|
* governing permissions and limitations under the License.
|
|
*/
|
|
package org.badvision.outlaweditor;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import java.util.stream.Collectors;
|
|
|
|
import org.badvision.outlaweditor.api.ApplicationState;
|
|
import org.badvision.outlaweditor.data.TileMap;
|
|
import org.badvision.outlaweditor.data.TileUtils;
|
|
import org.badvision.outlaweditor.data.xml.Map;
|
|
import org.badvision.outlaweditor.data.xml.Script;
|
|
import org.badvision.outlaweditor.data.xml.Scripts;
|
|
import org.badvision.outlaweditor.data.xml.Tile;
|
|
import org.badvision.outlaweditor.ui.TileSelectModal;
|
|
import org.badvision.outlaweditor.ui.ToolType;
|
|
|
|
import jakarta.xml.bind.JAXBException;
|
|
import javafx.application.Platform;
|
|
import javafx.beans.property.SimpleStringProperty;
|
|
import javafx.beans.property.StringProperty;
|
|
import javafx.beans.value.ObservableValue;
|
|
import javafx.event.EventHandler;
|
|
import javafx.scene.Cursor;
|
|
import javafx.scene.Group;
|
|
import javafx.scene.ImageCursor;
|
|
import javafx.scene.Scene;
|
|
import javafx.scene.canvas.Canvas;
|
|
import javafx.scene.canvas.GraphicsContext;
|
|
import javafx.scene.effect.DropShadow;
|
|
import javafx.scene.effect.Glow;
|
|
import javafx.scene.image.Image;
|
|
import javafx.scene.image.ImageView;
|
|
import javafx.scene.image.WritableImage;
|
|
import javafx.scene.input.Clipboard;
|
|
import javafx.scene.input.DataFormat;
|
|
import javafx.scene.input.MouseEvent;
|
|
import javafx.scene.input.ScrollEvent;
|
|
import javafx.scene.layout.Pane;
|
|
import javafx.scene.paint.Color;
|
|
import javafx.scene.paint.Paint;
|
|
import javafx.scene.shape.Rectangle;
|
|
import javafx.stage.Stage;
|
|
|
|
/**
|
|
*
|
|
* @author brobert
|
|
*/
|
|
public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventHandler<MouseEvent> {
|
|
|
|
Pane anchorPane;
|
|
Canvas drawCanvas;
|
|
private Tile currentTile;
|
|
int posX = 0;
|
|
int posY = 0;
|
|
double zoom = 1.0;
|
|
DrawMode drawMode = DrawMode.Pencil1px;
|
|
TileMap currentMap;
|
|
double tileWidth = getCurrentPlatform().tileRenderer.getWidth() * zoom;
|
|
double tileHeight = getCurrentPlatform().tileRenderer.getHeight() * zoom;
|
|
Color cursorAssistColor = new Color(0.2, 0.2, 1.0, 0.4);
|
|
Script highlightedScript = null;
|
|
|
|
@Override
|
|
protected void onEntityUpdated() {
|
|
currentMap = new TileMap(getEntity());
|
|
}
|
|
|
|
public TileMap getCurrentMap() {
|
|
return currentMap;
|
|
}
|
|
|
|
EventHandler<ScrollEvent> scrollHandler = (ScrollEvent t) -> {
|
|
if (t.isShiftDown()) {
|
|
t.consume();
|
|
if (t.getDeltaY() > 0) {
|
|
zoomIn();
|
|
} else {
|
|
zoomOut();
|
|
}
|
|
}
|
|
};
|
|
|
|
public DrawMode getDrawMode() {
|
|
return drawMode;
|
|
}
|
|
|
|
@Override
|
|
public void setDrawMode(DrawMode drawMode) {
|
|
this.drawMode = drawMode;
|
|
switch (drawMode) {
|
|
case TileEraser:
|
|
ImageCursor cursor = new ImageCursor(new Image(MapEditor.class.getResourceAsStream("/images/eraser.png")));
|
|
drawCanvas.setCursor(cursor);
|
|
break;
|
|
case Select:
|
|
drawCanvas.setCursor(Cursor.CROSSHAIR);
|
|
break;
|
|
case ScriptPencil:
|
|
drawCanvas.setCursor(Cursor.CLOSED_HAND);
|
|
break;
|
|
case ScriptEraser:
|
|
drawCanvas.setCursor(Cursor.OPEN_HAND);
|
|
break;
|
|
default:
|
|
setCurrentTile(getCurrentTile());
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void showShiftUI() {
|
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
|
}
|
|
|
|
public void moveMapByY(int amt) {
|
|
getCurrentMap().shift(0, amt);
|
|
redraw();
|
|
}
|
|
|
|
public void moveMapByX(int amt) {
|
|
getCurrentMap().shift(amt, 0);
|
|
redraw();
|
|
}
|
|
|
|
@Override
|
|
public void buildEditorUI(Pane tileEditorAnchorPane) {
|
|
anchorPane = tileEditorAnchorPane;
|
|
initCanvas();
|
|
redraw();
|
|
}
|
|
|
|
@Override
|
|
public void showSelectorModal() {
|
|
String category = null;
|
|
if (currentTile != null) {
|
|
category = currentTile.getCategory();
|
|
}
|
|
if (this.equals(ApplicationState.getInstance().getController().getVisibleEditor())) {
|
|
TileSelectModal.showTileSelectModal(anchorPane, category, this::setCurrentTile);
|
|
}
|
|
}
|
|
|
|
public void initCanvas() {
|
|
if (drawCanvas != null) {
|
|
anchorPane.getChildren().remove(drawCanvas);
|
|
}
|
|
drawCanvas = new Canvas();
|
|
drawCanvas.heightProperty().bind(ApplicationState.getInstance().getPrimaryStage().heightProperty().subtract(120));
|
|
drawCanvas.widthProperty().bind(ApplicationState.getInstance().getPrimaryStage().widthProperty().subtract(200));
|
|
// drawCanvas.widthProperty().bind(anchorPane.widthProperty());
|
|
drawCanvas.widthProperty().addListener((ObservableValue<? extends Number> ov, Number t, Number t1) -> {
|
|
redraw();
|
|
});
|
|
drawCanvas.heightProperty().addListener((ObservableValue<? extends Number> ov, Number t, Number t1) -> {
|
|
redraw();
|
|
});
|
|
drawCanvas.addEventFilter(ScrollEvent.ANY, scrollHandler);
|
|
drawCanvas.setOnMousePressed(this);
|
|
drawCanvas.setOnMouseMoved(this);
|
|
drawCanvas.setOnMouseDragged(this);
|
|
drawCanvas.setOnMouseDragReleased(this);
|
|
drawCanvas.setOnMouseReleased(this);
|
|
anchorPane.getChildren().add(0, drawCanvas);
|
|
cursorAssistant = new Rectangle(tileWidth, tileHeight, cursorAssistColor);
|
|
cursorAssistant.setMouseTransparent(true);
|
|
cursorAssistant.setEffect(new Glow(1.0));
|
|
anchorPane.getChildren().add(cursorAssistant);
|
|
}
|
|
|
|
@Override
|
|
public void addScript(Script script) {
|
|
if (getCurrentMap().getBackingMap().getScripts() == null) {
|
|
getCurrentMap().getBackingMap().setScripts(new Scripts());
|
|
}
|
|
getCurrentMap().getBackingMap().getScripts().getScript().add(script);
|
|
}
|
|
|
|
Script selectedScript = null;
|
|
|
|
public void setSelectedScript(Script script) {
|
|
selectedScript = script;
|
|
highlightedScript = script;
|
|
}
|
|
|
|
public Script getSelectedScript() {
|
|
return selectedScript;
|
|
}
|
|
|
|
private void drawScript(double x, double y, Script script) {
|
|
if (script != null) {
|
|
getCurrentMap().putLocationScript((int) x, (int) y, script);
|
|
} else {
|
|
getCurrentMap().removeLocationScripts((int) x, (int) y);
|
|
}
|
|
redraw();
|
|
}
|
|
|
|
public void assignScript(Script script, double x, double y) {
|
|
int xx = (int) (x / tileWidth) + posX;
|
|
int yy = (int) (y / tileHeight) + posY;
|
|
getCurrentMap().putLocationScript(xx, yy, script);
|
|
redraw();
|
|
}
|
|
|
|
public void unassignScripts(double x, double y) {
|
|
int xx = (int) (x / tileWidth) + posX;
|
|
int yy = (int) (y / tileHeight) + posY;
|
|
getCurrentMap().removeLocationScripts(xx, yy);
|
|
redraw();
|
|
}
|
|
|
|
public void clearScriptTriggers(Script s) {
|
|
getCurrentMap().clearScriptTriggersFromMap(s);
|
|
redraw();
|
|
}
|
|
|
|
public void togglePanZoom() {
|
|
anchorPane.getChildren().stream().filter((n) -> !(n == drawCanvas)).forEach((n) -> {
|
|
n.setVisible(!n.isVisible());
|
|
});
|
|
}
|
|
|
|
public void scrollBy(int deltaX, int deltaY) {
|
|
posX += deltaX * (drawCanvas.getWidth() / tileWidth / 2);
|
|
posY += deltaY * (drawCanvas.getHeight() / tileWidth / 2);
|
|
posX = Math.max(0, posX);
|
|
posY = Math.max(0, posY);
|
|
redraw();
|
|
}
|
|
|
|
public void zoomOut() {
|
|
if (zoom <= 1) {
|
|
zoom(-0.1);
|
|
} else {
|
|
zoom(-0.25);
|
|
}
|
|
}
|
|
|
|
public void zoomIn() {
|
|
if (zoom >= 1) {
|
|
zoom(0.25);
|
|
} else {
|
|
zoom(0.1);
|
|
}
|
|
}
|
|
|
|
private void zoom(double delta) {
|
|
zoom += delta;
|
|
zoom = Math.min(Math.max(0.15, zoom), 4.0);
|
|
tileWidth = getCurrentPlatform().tileRenderer.getWidth() * zoom;
|
|
tileHeight = getCurrentPlatform().tileRenderer.getHeight() * zoom;
|
|
fullRedraw.set(true);
|
|
redraw();
|
|
}
|
|
|
|
@Override
|
|
public void observedObjectChanged(Map object) {
|
|
redraw();
|
|
}
|
|
private AtomicBoolean fullRedraw = new AtomicBoolean(true);
|
|
private long redrawRequested;
|
|
private Thread redrawThread;
|
|
|
|
@Override
|
|
public void redraw() {
|
|
redrawRequested = System.nanoTime();
|
|
if (redrawThread == null || !redrawThread.isAlive()) {
|
|
redrawThread = new Thread(() -> {
|
|
long test = 0;
|
|
while (test != redrawRequested) {
|
|
test = redrawRequested;
|
|
try {
|
|
Thread.sleep(10);
|
|
} catch (InterruptedException ex) {
|
|
Logger.getLogger(MapEditor.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
}
|
|
Platform.runLater(() -> {
|
|
doRedraw(fullRedraw.getAndSet(false));
|
|
});
|
|
redrawThread = null;
|
|
});
|
|
redrawThread.start();
|
|
}
|
|
}
|
|
|
|
private synchronized void doRedraw(boolean fullRedraw) {
|
|
prepareCanvas(fullRedraw);
|
|
int cols = (int) (drawCanvas.getWidth() / tileWidth);
|
|
int rows = (int) (drawCanvas.getHeight() / tileHeight);
|
|
for (int x = 0; x <= cols; x++) {
|
|
for (int y = 0; y <= rows; y++) {
|
|
Tile tile = currentMap.get(posX + x, posY + y);
|
|
String id = (tile == null) ? null : tile.getId();
|
|
boolean notSimilar = (id == null) != (tiles[x][y] == null);
|
|
notSimilar |= (id != null && !id.equals(tiles[x][y]));
|
|
if (notSimilar) {
|
|
tiles[x][y] = id;
|
|
doDraw(x, y, tile);
|
|
}
|
|
}
|
|
}
|
|
for (int x = 0; x <= cols; x++) {
|
|
for (int y = 0; y <= rows; y++) {
|
|
if (highlightScripts(x, y, currentMap.getLocationScripts(posX + x, posY + y), highlightedScript)) {
|
|
tiles[x][y] = "SCRIPT";
|
|
}
|
|
}
|
|
}
|
|
// Reposition arrows
|
|
anchorPane.getChildren().get(1).setLayoutX((drawCanvas.getWidth() - 30) / 2);
|
|
anchorPane.getChildren().get(2).setLayoutY((drawCanvas.getHeight() - 30) / 2);
|
|
anchorPane.getChildren().get(3).setLayoutX((drawCanvas.getWidth() - 30) / 2);
|
|
anchorPane.getChildren().get(4).setLayoutY((drawCanvas.getHeight() - 30) / 2);
|
|
}
|
|
|
|
String[][] tiles = null;
|
|
|
|
private void prepareCanvas(boolean forceReset) {
|
|
int cols = (int) (drawCanvas.getWidth() / tileWidth);
|
|
int rows = (int) (drawCanvas.getHeight() / tileHeight);
|
|
|
|
boolean reset = tiles == null || tiles.length <= cols || tiles[0] == null || tiles[0].length <= rows;
|
|
if (forceReset || reset) {
|
|
tiles = new String[cols + 1][rows + 1];
|
|
fillEmpty(0, 0, drawCanvas.getWidth(), drawCanvas.getHeight());
|
|
}
|
|
}
|
|
|
|
private Paint getFillPattern(double x, double y) {
|
|
boolean oddEven = (x % 20) < 10;
|
|
oddEven ^= (y % 20) < 10;
|
|
return oddEven ? Color.BLACK : Color.NAVY;
|
|
}
|
|
|
|
private void doDraw(int x, int y, Tile tile) {
|
|
double xx = x * tileWidth;
|
|
double yy = y * tileHeight;
|
|
if (tile != null) {
|
|
drawCanvas.getGraphicsContext2D().drawImage(TileUtils.getImage(tile, getCurrentPlatform()), xx, yy, tileWidth, tileHeight);
|
|
} else {
|
|
fillEmpty(xx, yy, xx + tileWidth, yy + tileHeight);
|
|
}
|
|
}
|
|
|
|
int patternSize = 10;
|
|
|
|
private void fillEmpty(double startX, double startY, double endX, double endY) {
|
|
for (double x = startX; x < endX; x = x - (x % patternSize) + patternSize) {
|
|
for (double y = startY; y < endY; y = y - (y % patternSize) + patternSize) {
|
|
double width = Math.min(patternSize, endX - x);
|
|
double height = Math.min(patternSize, endY - y);
|
|
drawCanvas.getGraphicsContext2D().setFill(getFillPattern(x, y));
|
|
drawCanvas.getGraphicsContext2D().fillRect(x, y, width, height);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static final int DASH_LENGTH = 3;
|
|
|
|
private final Set<Script> invisibleScripts = new HashSet<>();
|
|
|
|
public boolean isScriptVisible(Script script) {
|
|
return !invisibleScripts.contains(script);
|
|
}
|
|
|
|
public void setScriptVisible(Script script, boolean visible) {
|
|
setScriptVisible(script, visible, true);
|
|
}
|
|
|
|
public void setScriptVisible(Script script, boolean visible, boolean redraw) {
|
|
if (visible) {
|
|
invisibleScripts.remove(script);
|
|
} else {
|
|
invisibleScripts.add(script);
|
|
}
|
|
if (redraw) {
|
|
redraw();
|
|
}
|
|
}
|
|
|
|
private boolean highlightScripts(int x, int y, List<Script> scripts, Script extraHighlight) {
|
|
if (scripts == null || scripts.isEmpty()) {
|
|
return false;
|
|
}
|
|
List<Script> visibleScripts = scripts.stream().filter(this::isScriptVisible).collect(Collectors.toList());
|
|
if (visibleScripts.isEmpty()) {
|
|
return false;
|
|
}
|
|
GraphicsContext gc = drawCanvas.getGraphicsContext2D();
|
|
if (highlightedScript != null && visibleScripts.contains(extraHighlight)) {
|
|
Color color = currentMap.getScriptColor(extraHighlight).get().brighter();
|
|
color = Color.color(color.getRed(), color.getGreen(), color.getBlue(), 0.5);
|
|
gc.setFill(color);
|
|
double xx = x * tileWidth;
|
|
double yy = y * tileHeight;
|
|
gc.fillRect(xx, yy, tileWidth, tileHeight);
|
|
}
|
|
int idx = 0;
|
|
double xx = x * tileWidth;
|
|
double yy = y * tileHeight;
|
|
gc.setLineWidth(4);
|
|
for (int i = 0; i < tileWidth - 2; i += DASH_LENGTH) {
|
|
idx = (idx + 1) % visibleScripts.size();
|
|
gc.beginPath();
|
|
gc.moveTo(xx, yy);
|
|
currentMap.getScriptColor(visibleScripts.get(idx)).ifPresent(gc::setStroke);
|
|
xx += DASH_LENGTH;
|
|
gc.lineTo(xx, yy);
|
|
gc.setEffect(new DropShadow(2, Color.BLACK));
|
|
gc.stroke();
|
|
}
|
|
for (int i = 0; i < tileHeight - 2; i += DASH_LENGTH) {
|
|
idx = (idx + 1) % visibleScripts.size();
|
|
gc.beginPath();
|
|
gc.moveTo(xx, yy);
|
|
currentMap.getScriptColor(visibleScripts.get(idx)).ifPresent(gc::setStroke);
|
|
yy += DASH_LENGTH;
|
|
gc.lineTo(xx, yy);
|
|
gc.setEffect(new DropShadow(2, Color.BLACK));
|
|
gc.stroke();
|
|
}
|
|
for (int i = 0; i < tileWidth - 2; i += DASH_LENGTH) {
|
|
idx = (idx + 1) % visibleScripts.size();
|
|
gc.beginPath();
|
|
gc.moveTo(xx, yy);
|
|
currentMap.getScriptColor(visibleScripts.get(idx)).ifPresent(gc::setStroke);
|
|
xx -= DASH_LENGTH;
|
|
gc.lineTo(xx, yy);
|
|
gc.setEffect(new DropShadow(2, Color.BLACK));
|
|
gc.stroke();
|
|
}
|
|
for (int i = 0; i < tileHeight - 2; i += DASH_LENGTH) {
|
|
idx = (idx + 1) % visibleScripts.size();
|
|
gc.beginPath();
|
|
gc.moveTo(xx, yy);
|
|
currentMap.getScriptColor(visibleScripts.get(idx)).ifPresent(gc::setStroke);
|
|
yy -= DASH_LENGTH;
|
|
gc.lineTo(xx, yy);
|
|
gc.setEffect(new DropShadow(2, Color.BLACK));
|
|
gc.stroke();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void setupDragDrop(TransferHelper<Script> scriptHelper, TransferHelper<ToolType> toolHelper) {
|
|
scriptHelper.registerDropSupport(drawCanvas, (Script script, double x, double y) -> {
|
|
assignScript(script, x, y);
|
|
});
|
|
toolHelper.registerDropSupport(drawCanvas, (ToolType tool, double x, double y) -> {
|
|
unassignScripts(x, y);
|
|
});
|
|
|
|
}
|
|
|
|
@Override
|
|
public void unregister() {
|
|
drawCanvas.widthProperty().unbind();
|
|
drawCanvas.heightProperty().unbind();
|
|
anchorPane.getChildren().remove(drawCanvas);
|
|
currentMap.updateBackingMap();
|
|
}
|
|
|
|
/**
|
|
* @return the currentTile
|
|
*/
|
|
public Tile getCurrentTile() {
|
|
return currentTile;
|
|
}
|
|
|
|
/**
|
|
* @param currentTile the currentTile to set
|
|
* @return Same tile (necessary for callback support)
|
|
*/
|
|
public Tile setCurrentTile(Tile currentTile) {
|
|
if (drawMode == DrawMode.TileEraser) {
|
|
drawMode = DrawMode.Pencil1px;
|
|
}
|
|
this.currentTile = currentTile;
|
|
ImageCursor cursor = new ImageCursor(TileUtils.getImage(currentTile, getCurrentPlatform()), 2, 2);
|
|
drawCanvas.setCursor(cursor);
|
|
return currentTile;
|
|
}
|
|
|
|
public void showPreview() {
|
|
byte[] data = getCurrentPlatform().imageRenderer.renderPreview(currentMap, posX, posY, getCurrentPlatform().maxImageWidth, getCurrentPlatform().maxImageHeight);
|
|
WritableImage img = getCurrentPlatform().imageRenderer.renderImage(null, data, getCurrentPlatform().maxImageWidth, getCurrentPlatform().maxImageHeight);
|
|
Stage stage = new Stage();
|
|
stage.setTitle("Preview");
|
|
ImageView imgView = new ImageView(img);
|
|
Group root = new Group(imgView);
|
|
stage.setScene(new Scene(root, img.getWidth(), img.getHeight()));
|
|
stage.show();
|
|
}
|
|
|
|
public void copyScript(Script s) {
|
|
java.util.Map<DataFormat, Object> clip = new HashMap<>();
|
|
clip.put(DataFormat.PLAIN_TEXT, "selection/map/" +
|
|
ApplicationState.getInstance().getGameData().getMap().indexOf(getEntity()) +
|
|
"/script/" + getEntity().getScripts().getScript().indexOf(s));
|
|
Clipboard.getSystemClipboard().setContent(clip);
|
|
}
|
|
|
|
@Override
|
|
public void copy() {
|
|
byte[] data = getCurrentPlatform().imageRenderer.renderPreview(currentMap, posX, posY, getCurrentPlatform().maxImageWidth, getCurrentPlatform().maxImageHeight);
|
|
WritableImage img = getCurrentPlatform().imageRenderer.renderImage(null, data, getCurrentPlatform().maxImageWidth, getCurrentPlatform().maxImageHeight);
|
|
java.util.Map<DataFormat, Object> clip = new HashMap<>();
|
|
clip.put(DataFormat.IMAGE, img);
|
|
if (drawMode != DrawMode.Select || startX >= 0) {
|
|
clip.put(DataFormat.PLAIN_TEXT, "selection/map/" + ApplicationState.getInstance().getGameData().getMap().indexOf(getEntity()) + "/" + getSelectionInfo());
|
|
}
|
|
Clipboard.getSystemClipboard().setContent(clip);
|
|
clearSelection();
|
|
}
|
|
|
|
@Override
|
|
public String getSelectedAllInfo() {
|
|
setSelectionArea(posX, posY, posX + 19, posY + 11);
|
|
String result = getSelectionInfo();
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public void paste() {
|
|
if (Clipboard.getSystemClipboard().hasContent(DataFormat.PLAIN_TEXT)) {
|
|
String clipboardInfo = (String) Clipboard.getSystemClipboard().getContent(DataFormat.PLAIN_TEXT);
|
|
java.util.Map<String, Integer> selection = TransferHelper.getSelectionDetails(clipboardInfo);
|
|
if (selection.containsKey("script")) {
|
|
Map sourceMap = ApplicationState.getInstance().getGameData().getMap().get(selection.get("map"));
|
|
Script sourceScript = sourceMap.getScripts().getScript().get(selection.get("script"));
|
|
try {
|
|
Script cloneScript = TransferHelper.cloneObject(sourceScript, Script.class, "script");
|
|
if (sourceMap.equals(getEntity())) {
|
|
cloneScript.setName(cloneScript.getName() + " CLONE");
|
|
}
|
|
addScript(cloneScript);
|
|
ApplicationState.getInstance().getApplicationUI().redrawScripts();
|
|
} catch (JAXBException ex) {
|
|
Logger.getLogger(MapEditor.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
} else {
|
|
if (selection.containsKey("map")) {
|
|
trackState();
|
|
Map sourceMap = ApplicationState.getInstance().getGameData().getMap().get(selection.get("map"));
|
|
TileMap source = getCurrentMap();
|
|
if (!sourceMap.equals(getCurrentMap().getBackingMap())) {
|
|
source = new TileMap(sourceMap);
|
|
} else {
|
|
source.updateBackingMap();
|
|
}
|
|
int height = selection.get("y2") - selection.get("y1");
|
|
int width = selection.get("x2") - selection.get("x1");
|
|
int x1 = selection.get("x1");
|
|
int y1 = selection.get("y1");
|
|
for (int y = 0; y < height; y++) {
|
|
for (int x = 0; x < width; x++) {
|
|
plot(x + lastX, y + lastY, source.get(x + x1, y + y1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void select() {
|
|
setDrawMode(DrawMode.Select);
|
|
}
|
|
|
|
@Override
|
|
public void selectNone() {
|
|
clearSelection();
|
|
}
|
|
|
|
Rectangle cursorAssistant;
|
|
|
|
private void updateCursorAssistant(MouseEvent t) {
|
|
if (t.getEventType() == MouseEvent.MOUSE_EXITED) {
|
|
cursorAssistant.setVisible(false);
|
|
} else {
|
|
cursorAssistant.setVisible(true);
|
|
cursorAssistant.setWidth(tileWidth);
|
|
cursorAssistant.setHeight(tileHeight);
|
|
cursorAssistant.setTranslateX(t.getX() - (t.getX() % tileWidth));
|
|
cursorAssistant.setTranslateY(t.getY() - (t.getY() % tileHeight));
|
|
}
|
|
}
|
|
|
|
public void removeScript(Script script) {
|
|
getCurrentMap().removeScriptFromMap(script);
|
|
redraw();
|
|
}
|
|
|
|
private org.badvision.outlaweditor.api.Platform getCurrentPlatform() {
|
|
return ApplicationState.getInstance().getCurrentPlatform();
|
|
}
|
|
|
|
@Override
|
|
public void copyData() {
|
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
|
}
|
|
|
|
private boolean hasScriptsAt(int x, int y) {
|
|
List<Script> scripts = currentMap.getLocationScripts(x, y);
|
|
return scripts != null && !scripts.isEmpty();
|
|
}
|
|
|
|
public static enum DrawMode {
|
|
|
|
Pencil1px, Pencil3px, Pencil5px, FilledRect, TileEraser(false), ScriptPencil(false), Select(false), ScriptEraser(false);
|
|
|
|
boolean requireTile = false;
|
|
|
|
DrawMode() {
|
|
this(true);
|
|
}
|
|
|
|
DrawMode(boolean require) {
|
|
requireTile = require;
|
|
}
|
|
|
|
public boolean requiresCurrentTile() {
|
|
return requireTile;
|
|
}
|
|
};
|
|
|
|
public void plot(final int x, final int y, final Tile t) {
|
|
if (x < 0) {
|
|
return;
|
|
}
|
|
if (y < 0) {
|
|
return;
|
|
}
|
|
if (x >= getEntity().getWidth()) {
|
|
System.out.println("X out of bounds " + getEntity().getWidth());
|
|
return;
|
|
}
|
|
if (y >= getEntity().getHeight()) {
|
|
System.out.println("Y out of bounds " + getEntity().getHeight());
|
|
return;
|
|
}
|
|
currentMap.put(x, y, t);
|
|
doDraw(x - posX, y - posY, t);
|
|
}
|
|
|
|
public void drawBrush(int x, int y, int size, Tile t) {
|
|
for (int xx = x - size; xx <= x + size; xx++) {
|
|
for (int yy = y - size; yy <= y + size; yy++) {
|
|
if (Math.sqrt((xx - x) * (xx - x) + (yy - y) * (yy - y)) > size) {
|
|
continue;
|
|
}
|
|
plot(xx, yy, getCurrentTile());
|
|
}
|
|
}
|
|
}
|
|
|
|
StringProperty cursorInfo = new SimpleStringProperty();
|
|
|
|
public StringProperty cursorInfoProperty() {
|
|
return cursorInfo;
|
|
}
|
|
|
|
public static Rectangle selectRect = null;
|
|
public double selectScreenStartX = 0;
|
|
public double selectScreenStartY = 0;
|
|
|
|
private void startSelection(double x, double y) {
|
|
selectRect = new Rectangle(1, 1, Color.NAVY);
|
|
selectRect.setTranslateX(x);
|
|
selectRect.setTranslateY(y);
|
|
selectRect.setOpacity(0.5);
|
|
selectScreenStartX = x;
|
|
selectScreenStartY = y;
|
|
anchorPane.getChildren().add(selectRect);
|
|
}
|
|
|
|
private void updateSelection(double x, double y) {
|
|
if (selectRect == null || selectScreenStartX < 0 || selectScreenStartY < 0) {
|
|
clearSelection();
|
|
startSelection(x, y);
|
|
}
|
|
|
|
double minX = Math.min(selectScreenStartX, x);
|
|
double minY = Math.min(selectScreenStartY, y);
|
|
double maxX = Math.max(selectScreenStartX, x);
|
|
double maxY = Math.max(selectScreenStartY, y);
|
|
selectRect.setTranslateX(minX);
|
|
selectRect.setTranslateY(minY);
|
|
selectRect.setWidth(maxX - minX);
|
|
selectRect.setHeight(maxY - minY);
|
|
setSelectionArea(
|
|
(int) (minX / tileWidth + posX),
|
|
(int) (minY / tileHeight + posY),
|
|
(int) (maxX / tileWidth + posX),
|
|
(int) (maxY / tileHeight + posY)
|
|
);
|
|
}
|
|
|
|
private void fillSelection() {
|
|
for (int yy = startY; yy <= endY; yy++) {
|
|
for (int xx = startX; xx <= endX; xx++) {
|
|
plot(xx, yy, getCurrentTile());
|
|
}
|
|
}
|
|
clearSelection();
|
|
}
|
|
|
|
private void clearSelection() {
|
|
anchorPane.getChildren().remove(selectRect);
|
|
selectRect = null;
|
|
setSelectionArea(-1, -1, -1, -1);
|
|
}
|
|
|
|
public static int lastX = -1;
|
|
public static int lastY = -1;
|
|
DrawMode lastDrawMode = null;
|
|
Tile lastTile = null;
|
|
|
|
@Override
|
|
protected void trackState() {
|
|
currentMap.updateBackingMap();
|
|
super.trackState();
|
|
}
|
|
|
|
@Override
|
|
public void handle(MouseEvent t) {
|
|
int x = (int) (t.getX() / tileWidth) + posX;
|
|
int y = (int) (t.getY() / tileHeight) + posY;
|
|
updateCursorAssistant(t);
|
|
cursorInfo.set("X=" + x + " Y=" + y);
|
|
if (!t.isPrimaryButtonDown() && t.getEventType() != MouseEvent.MOUSE_RELEASED && drawMode != DrawMode.FilledRect) {
|
|
return;
|
|
}
|
|
if (getCurrentTile() == null && drawMode.requiresCurrentTile()) {
|
|
return;
|
|
}
|
|
t.consume();
|
|
boolean canSkip = false;
|
|
if (getCurrentTile() == lastTile && x == lastX && y == lastY && drawMode == lastDrawMode) {
|
|
canSkip = true;
|
|
}
|
|
lastX = x;
|
|
lastY = y;
|
|
lastDrawMode = drawMode;
|
|
lastTile = getCurrentTile();
|
|
switch (drawMode) {
|
|
case TileEraser: {
|
|
if (canSkip) {
|
|
return;
|
|
}
|
|
trackState();
|
|
plot(x, y, null);
|
|
redraw();
|
|
break;
|
|
}
|
|
case Pencil1px:
|
|
if (canSkip) {
|
|
return;
|
|
}
|
|
trackState();
|
|
plot(x, y, getCurrentTile());
|
|
break;
|
|
case Pencil3px:
|
|
if (canSkip) {
|
|
return;
|
|
}
|
|
trackState();
|
|
drawBrush(x, y, 2, getCurrentTile());
|
|
break;
|
|
case Pencil5px:
|
|
if (canSkip) {
|
|
return;
|
|
}
|
|
trackState();
|
|
drawBrush(x, y, 5, getCurrentTile());
|
|
break;
|
|
case FilledRect:
|
|
updateSelection(t.getX(), t.getY());
|
|
if (t.getEventType().equals(MouseEvent.MOUSE_RELEASED)) {
|
|
trackState();
|
|
fillSelection();
|
|
}
|
|
case ScriptPencil:
|
|
if (canSkip) {
|
|
return;
|
|
}
|
|
trackState();
|
|
drawScript(x, y, getSelectedScript());
|
|
break;
|
|
case ScriptEraser:
|
|
if (canSkip || !hasScriptsAt(x, y)) {
|
|
return;
|
|
}
|
|
trackState();
|
|
drawScript(x, y, null);
|
|
break;
|
|
case Select:
|
|
updateSelection(t.getX(), t.getY());
|
|
if (t.getEventType().equals(MouseEvent.MOUSE_RELEASED)) {
|
|
selectScreenStartX = selectScreenStartY = -1;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|