From 9c6d63ee02e6b6bf412227041e22c66d0c9d9951 Mon Sep 17 00:00:00 2001 From: Grimm Date: Mon, 2 May 2022 00:24:22 +0200 Subject: [PATCH 01/66] Adventure: fixed shopList attribute in towns --- forge-gui-mobile/src/forge/adventure/stage/MapStage.java | 1 + 1 file changed, 1 insertion(+) diff --git a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java index d4e9027ec55..e2bc875f7db 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java @@ -372,6 +372,7 @@ public class MapStage extends GameStage { break; case "shop": String shopList = prop.get("shopList").toString(); + shopList=shopList.replaceAll("\\s",""); List possibleShops = Arrays.asList(shopList.split(",")); Array shops; if (possibleShops.size() == 0 || shopList.equals("")) From 9b8dba2169e796e982edd999ebab7cd23ae25284 Mon Sep 17 00:00:00 2001 From: Grimm Date: Fri, 10 Jun 2022 23:25:45 +0200 Subject: [PATCH 02/66] AdventureEditor: added editors --- forge-adventure/pom.xml | 2 +- .../forge/adventure/editor/BiomeEdit.java | 122 ++++++++++++++ .../adventure/editor/BiomeTerrainEdit.java | 14 ++ .../java/forge/adventure/editor/ItemEdit.java | 3 +- .../adventure/editor/PointOfInterestEdit.java | 88 ++++++++++ .../editor/PointOfInterestEditor.java | 129 ++++++++++++++- .../forge/adventure/editor/RewardEdit.java | 114 ++----------- .../forge/adventure/editor/RewardsEditor.java | 31 +--- .../adventure/editor/TerrainsEditor.java | 138 ++++++++++++++++ .../forge/adventure/editor/TextListEdit.java | 7 + .../forge/adventure/editor/WorldEditor.java | 151 +++++++++++++++++- .../src/forge/adventure/data/BiomeData.java | 2 +- .../adventure/data/BiomeTerrainData.java | 12 ++ .../adventure/data/PointOfInterestData.java | 14 ++ .../src/forge/adventure/data/WorldData.java | 7 +- 15 files changed, 699 insertions(+), 135 deletions(-) create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java diff --git a/forge-adventure/pom.xml b/forge-adventure/pom.xml index 9b2fd342fe3..9ddea05130a 100644 --- a/forge-adventure/pom.xml +++ b/forge-adventure/pom.xml @@ -17,7 +17,7 @@ - src + src/main/java ${project.basedir} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java new file mode 100644 index 00000000000..70c595437a9 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java @@ -0,0 +1,122 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; + +import javax.swing.*; +import java.awt.*; +import java.util.Arrays; + +public class BiomeEdit extends JComponent { + BiomeData currentData; + + public JSpinner startPointX= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner startPointY= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner noiseWeight= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner distWeight= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JTextField name=new JTextField(); + public FilePicker tilesetAtlas=new FilePicker(new String[]{"atlas"}); + public JTextField tilesetName=new JTextField(); + public JSpinner width= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner height= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JTextField color=new JTextField(); + public TextListEdit spriteNames =new TextListEdit(); + public TextListEdit enemies =new TextListEdit(); + public TextListEdit pointsOfInterest =new TextListEdit(); + + public TerrainsEditor terrain =new TerrainsEditor(); + + private boolean updating=false; + + public BiomeEdit() + { + + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(14,2)); + + center.add(new JLabel("startPointX:")); center.add(startPointX); + center.add(new JLabel("startPointY:")); center.add(startPointY); + center.add(new JLabel("noiseWeight:")); center.add(noiseWeight); + center.add(new JLabel("distWeight:")); center.add(distWeight); + center.add(new JLabel("name:")); center.add(name); + center.add(new JLabel("tilesetAtlas:")); center.add(tilesetAtlas); + center.add(new JLabel("tilesetName:")); center.add(tilesetName); + center.add(new JLabel("width:")); center.add(width); + center.add(new JLabel("height:")); center.add(height); + center.add(new JLabel("spriteNames:")); center.add(spriteNames); + center.add(new JLabel("enemies:")); center.add(enemies); + center.add(new JLabel("pointsOfInterest:")); center.add(pointsOfInterest); + center.add(new JLabel("color:")); center.add(color); + center.add(new JLabel("terrain:")); center.add(terrain); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(center,BorderLayout.PAGE_START); + add(terrain,BorderLayout.CENTER); + + name.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + tilesetName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + color.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + spriteNames.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + enemies.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + terrain.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + + + startPointX.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + startPointY.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + noiseWeight.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + distWeight.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + tilesetAtlas.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + width.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + height.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + refresh(); + } + + private void updateTerrain() { + if(currentData==null||updating) + return; + currentData.startPointX = (Float) startPointX.getValue(); + currentData.startPointY = (Float) startPointY.getValue(); + currentData.noiseWeight = (Float) noiseWeight.getValue(); + currentData.distWeight = (Float)distWeight.getValue(); + currentData.name = name.getText(); + currentData.tilesetAtlas = tilesetAtlas.edit.getText(); + currentData.tilesetName = tilesetName.getName(); + currentData.terrain = terrain.getBiomeTerrainData(); + currentData.width = (Float) width.getValue(); + currentData.height = (Float) height.getValue(); + currentData.color = color.getText(); + currentData.spriteNames = spriteNames.getList(); + currentData.enemies = Arrays.asList(enemies.getList()); + currentData.pointsOfInterest = Arrays.asList(pointsOfInterest.getList()); + } + + public void setCurrentBiome(BiomeData data) + { + currentData=data; + refresh(); + } + + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + startPointX.setValue(currentData.startPointX); + startPointY.setValue(currentData.startPointY); + noiseWeight.setValue(currentData.noiseWeight); + distWeight.setValue(currentData.distWeight); + name.setText(currentData.name); + tilesetAtlas.edit.setText( currentData.tilesetAtlas); + tilesetName.setText(currentData.tilesetName); + terrain.setTerrains(currentData.terrain); + width.setValue(currentData.width); + height.setValue(currentData.height); + color.setText(currentData.color); + spriteNames.setText(currentData.spriteNames); + enemies.setText(currentData.enemies); + color.setText(currentData.color); + pointsOfInterest.setText(currentData.pointsOfInterest); + updating=false; + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java new file mode 100644 index 00000000000..24791aa585d --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java @@ -0,0 +1,14 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeTerrainData; + +import javax.swing.*; +import javax.swing.event.ChangeListener; + +public class BiomeTerrainEdit extends JComponent { + public void setCurrentTerrain(BiomeTerrainData biomeTerrainData) { + } + public void addChangeListener(ChangeListener listener) { + + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java index 248bd275914..26f9f30923d 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java @@ -10,8 +10,6 @@ import java.awt.*; */ public class ItemEdit extends JComponent { ItemData currentData; - - JTextField nameField=new JTextField(); JTextField equipmentSlot=new JTextField(); JTextField iconName=new JTextField(); @@ -39,6 +37,7 @@ public class ItemEdit extends JComponent { add(parameters); add(effect); + add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); nameField.getDocument().addDocumentListener(new DocumentChangeListener(() -> ItemEdit.this.updateItem())); equipmentSlot.getDocument().addDocumentListener(new DocumentChangeListener(() -> ItemEdit.this.updateItem())); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java new file mode 100644 index 00000000000..045777feb94 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java @@ -0,0 +1,88 @@ +package forge.adventure.editor; + +import forge.adventure.data.PointOfInterestData; + +import javax.swing.*; +import java.awt.*; + +public class PointOfInterestEdit extends JComponent { + + PointOfInterestData currentData; + + + JTextField name = new JTextField(); + JTextField type = new JTextField(); + JSpinner count = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); + FilePicker spriteAtlas = new FilePicker(new String[]{"atlas"}); + JTextField sprite = new JTextField(); + FilePicker map = new FilePicker(new String[]{"tmx"}); + JSpinner radiusFactor= new JSpinner(new SpinnerNumberModel(0.0f, 0.0f, 2.0f, 0.1f)); + + + private boolean updating=false; + + public PointOfInterestEdit() + { + + setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); + JPanel parameters=new JPanel(); + parameters.setBorder(BorderFactory.createTitledBorder("Parameter")); + parameters.setLayout(new GridLayout(7,2)) ; + + parameters.add(new JLabel("Name:")); parameters.add(name); + parameters.add(new JLabel("Type:")); parameters.add(type); + parameters.add(new JLabel("Count:")); parameters.add(count); + parameters.add(new JLabel("Sprite atlas:")); parameters.add(spriteAtlas); + parameters.add(new JLabel("Sprite:")); parameters.add(sprite); + parameters.add(new JLabel("Map:")); parameters.add(map); + parameters.add(new JLabel("Radius factor:")); parameters.add(radiusFactor); + + add(parameters); + add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); + + name.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + type.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + count.addChangeListener(e -> PointOfInterestEdit.this.updateItem()); + spriteAtlas.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + sprite.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + map.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + radiusFactor.addChangeListener(e -> PointOfInterestEdit.this.updateItem()); + refresh(); + } + + private void updateItem() { + if(currentData==null||updating) + return; + currentData.name=name.getText(); + currentData.type= type.getText(); + currentData.count= ((Integer) count.getValue()).intValue(); + currentData.spriteAtlas=spriteAtlas.getEdit().getText(); + currentData.sprite=sprite.getText(); + currentData.map=map.getEdit().getText(); + currentData.radiusFactor=((Float) radiusFactor.getValue()).floatValue(); + } + + public void setCurrent(PointOfInterestData data) + { + currentData=data; + refresh(); + } + + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + name.setText(currentData.name); + type.setText(currentData.type); + count.setValue(currentData.count); + spriteAtlas.getEdit().setText(currentData.spriteAtlas); + sprite.setText(currentData.sprite); + map.getEdit().setText(currentData.map); + radiusFactor.setValue(currentData.radiusFactor); + + updating=false; + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java index 83ff548e68e..4fa4b0e9209 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java @@ -1,6 +1,131 @@ package forge.adventure.editor; -import java.awt.*; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter; +import forge.adventure.data.PointOfInterestData; +import forge.adventure.util.Config; +import forge.adventure.util.Paths; -public class PointOfInterestEditor extends Component { +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionListener; +import java.util.HashMap; + +public class PointOfInterestEditor extends JComponent { + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + PointOfInterestEdit edit=new PointOfInterestEdit(); + static HashMap atlas=new HashMap<>(); + + + + public class PointOfInterestRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof PointOfInterestData)) + return label; + PointOfInterestData poi=(PointOfInterestData) value; + // Get the renderer component from parent class + + label.setText(poi.name); + if(!atlas.containsKey(poi.spriteAtlas)) + atlas.put(poi.spriteAtlas,new SwingAtlas(Config.instance().getFile(poi.spriteAtlas))); + + SwingAtlas poiAtlas = atlas.get(poi.spriteAtlas); + + if(poiAtlas.has(poi.sprite)) + label.setIcon(poiAtlas.get(poi.sprite)); + else + { + ImageIcon img=poiAtlas.getAny(); + if(img!=null) + label.setIcon(img); + } + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + public PointOfInterestEditor() + { + + list.setCellRenderer(new PointOfInterestEditor.PointOfInterestRenderer()); + list.addListSelectionListener(e -> PointOfInterestEditor.this.updateEdit()); + addButton("add", e -> PointOfInterestEditor.this.addItem()); + addButton("remove", e -> PointOfInterestEditor.this.remove()); + addButton("copy", e -> PointOfInterestEditor.this.copy()); + addButton("load", e -> PointOfInterestEditor.this.load()); + addButton("save", e -> PointOfInterestEditor.this.save()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(new JScrollPane(list), BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + load(); + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + PointOfInterestData data=new PointOfInterestData(model.get(selected)); + model.add(model.size(),data); + } + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrent(model.get(selected)); + } + + void save() + { + Array allEnemies=new Array<>(); + for(int i=0;i allEnemies=new Array<>(); + Json json = new Json(); + FileHandle handle = Config.instance().getFile(Paths.POINTS_OF_INTEREST); + if (handle.exists()) + { + Array readEnemies=json.fromJson(Array.class, PointOfInterestData.class, handle); + allEnemies = readEnemies; + } + for (int i=0;i RewardEdit.this.updateReward())); + probability.addChangeListener(e -> RewardEdit.this.updateReward()); + count.addChangeListener(e -> RewardEdit.this.updateReward()); + addMaxCount.addChangeListener(e -> RewardEdit.this.updateReward()); + cardName.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + itemName.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + editions.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + colors.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + rarity.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + subTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + cardTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + superTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + manaCosts.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + keyWords.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + colorType.addActionListener((e -> RewardEdit.this.updateReward())); + cardText.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java index a2d6cc0f617..786128f6bad 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java @@ -5,10 +5,7 @@ import forge.adventure.data.RewardData; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import java.awt.*; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** @@ -59,30 +56,10 @@ public class RewardsEditor extends JComponent{ { list.setCellRenderer(new RewardDataRenderer()); - list.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - RewardsEditor.this.updateEdit(); - } - }); - addButton("add", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.addReward(); - } - }); - addButton("remove", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.remove(); - } - }); - addButton("copy", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.copy(); - } - }); + list.addListSelectionListener(e -> RewardsEditor.this.updateEdit()); + addButton("add", e -> RewardsEditor.this.addReward()); + addButton("remove", e -> RewardsEditor.this.remove()); + addButton("copy", e -> RewardsEditor.this.copy()); BorderLayout layout=new BorderLayout(); setLayout(layout); add(list, BorderLayout.LINE_START); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java new file mode 100644 index 00000000000..69a7578a13d --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java @@ -0,0 +1,138 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeTerrainData; +import forge.adventure.data.RewardData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.ActionListener; + +/** + * Editor class to edit configuration, maybe moved or removed + */ +public class TerrainsEditor extends JComponent{ + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + BiomeTerrainEdit edit=new BiomeTerrainEdit(); + + + + public class TerrainDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof RewardData)) + return label; + RewardData reward=(RewardData) value; + StringBuilder builder=new StringBuilder(); + if(reward.type==null||reward.type.isEmpty()) + builder.append("Terrain"); + else + builder.append(reward.type); + builder.append(" "); + builder.append(reward.count); + if(reward.addMaxCount>0) + { + builder.append("-"); + builder.append(reward.count+reward.addMaxCount); + } + label.setText(builder.toString()); + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + + public TerrainsEditor() + { + + list.setCellRenderer(new TerrainDataRenderer()); + list.addListSelectionListener(e -> TerrainsEditor.this.updateEdit()); + addButton("add", e -> TerrainsEditor.this.addReward()); + addButton("remove", e -> TerrainsEditor.this.remove()); + addButton("copy", e -> TerrainsEditor.this.copy()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(list, BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + + + edit.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + emitChanged(); + } + }); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + BiomeTerrainData data=new BiomeTerrainData(model.get(selected)); + model.add(model.size(),data); + } + + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrentTerrain(model.get(selected)); + } + + void addReward() + { + BiomeTerrainData data=new BiomeTerrainData(); + model.add(model.size(),data); + } + void remove() + { + int selected=list.getSelectedIndex(); + if(selected<0) + return; + model.remove(selected); + } + public void setTerrains(BiomeTerrainData[] terrain) { + + model.clear(); + if(terrain==null) + return; + for (int i=0;i itemNames) { + if(itemNames==null) + edit.setText(""); + else + edit.setText(String.join(";",itemNames)); + } public void setText(String[] itemName) { if(itemName==null) edit.setText(""); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java index 221ac5d64ae..e1fde6621e9 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java @@ -1,6 +1,153 @@ package forge.adventure.editor; -import java.awt.*; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter; +import forge.adventure.data.BiomeData; +import forge.adventure.data.WorldData; +import forge.adventure.util.Config; +import forge.adventure.util.Paths; -public class WorldEditor extends Component { +import javax.swing.*; +import java.awt.*; +import java.util.HashMap; + +public class WorldEditor extends JComponent { + + WorldData currentData; + + + JSpinner width= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + JSpinner height= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + JSpinner playerStartPosX= new JSpinner(new SpinnerNumberModel(0, 0, 1, .1)); + JSpinner playerStartPosY= new JSpinner(new SpinnerNumberModel(0, 0, 1, .1)); + JSpinner noiseZoomBiome= new JSpinner(new SpinnerNumberModel(0, 0, 1000f, 1f)); + JSpinner tileSize= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + + JTextField biomesSprites = new JTextField(); + JSpinner maxRoadDistance = new JSpinner(new SpinnerNumberModel(0, 0, 100000f, 1f)); + TextListEdit biomesNames = new TextListEdit(); + + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + BiomeEdit edit=new BiomeEdit(); + JTabbedPane tabs =new JTabbedPane(); + static HashMap atlas=new HashMap<>(); + + public class BiomeDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof BiomeData)) + return label; + BiomeData biome=(BiomeData) value; + // Get the renderer component from parent class + + label.setText(biome.name); + if(!atlas.containsKey(biome.tilesetAtlas)) + atlas.put(biome.tilesetAtlas,new SwingAtlas(Config.instance().getFile(biome.tilesetAtlas))); + + SwingAtlas poiAtlas = atlas.get(biome.tilesetAtlas); + + if(poiAtlas.has(biome.tilesetName)) + label.setIcon(poiAtlas.get(biome.tilesetName)); + else + { + ImageIcon img=poiAtlas.getAny(); + if(img!=null) + label.setIcon(img); + } + return label; + } + } + public WorldEditor() { + list.setCellRenderer(new BiomeDataRenderer()); + BorderLayout layout = new BorderLayout(); + setLayout(layout); + add(tabs); + JPanel worldPanel=new JPanel(); + JPanel biomeData=new JPanel(); + tabs.addTab("BiomeData", biomeData); + tabs.addTab("WorldData", worldPanel); + + + JPanel worldData=new JPanel(); + worldData.setLayout(new GridLayout(9,2)) ; + + worldData.add(new JLabel("width:")); worldData.add(width); + worldData.add(new JLabel("height:")); worldData.add(height); + worldData.add(new JLabel("playerStartPosX:")); worldData.add(playerStartPosX); + worldData.add(new JLabel("playerStartPosY:")); worldData.add(playerStartPosY); + worldData.add(new JLabel("noiseZoomBiome:")); worldData.add(noiseZoomBiome); + worldData.add(new JLabel("tileSize:")); worldData.add(tileSize); + worldData.add(new JLabel("biomesSprites:")); worldData.add(biomesSprites); + worldData.add(new JLabel("maxRoadDistance:")); worldData.add(maxRoadDistance); + worldData.add(new JLabel("biomesNames:")); worldData.add(biomesNames); + + + worldPanel.setLayout(new BoxLayout(worldPanel,BoxLayout.Y_AXIS)); + worldPanel.add(worldData); + worldPanel.add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); + + + biomeData.setLayout(new GridLayout(1,2)) ; + biomeData.add(list); biomeData.add(edit); + + load(); + + JToolBar toolBar = new JToolBar("toolbar"); + add(toolBar, BorderLayout.PAGE_START); + JButton newButton=new JButton("save"); + newButton.addActionListener(e -> WorldEditor.this.save()); + toolBar.add(newButton); + newButton=new JButton("load"); + newButton.addActionListener(e -> WorldEditor.this.load()); + toolBar.add(newButton); + } + + void save() + { + Json json = new Json(JsonWriter.OutputType.json); + FileHandle handle = Config.instance().getFile(Paths.WORLD); + handle.writeString(json.prettyPrint(json.toJson(currentData,Array.class, WorldData.class)),false); + + } + void load() + { + model.clear(); + Json json = new Json(); + FileHandle handle = Config.instance().getFile(Paths.WORLD); + if (handle.exists()) + { + currentData=json.fromJson(WorldData.class, WorldData.class, handle); + } + update(); + } + + private void update() { + width.setValue(currentData.width); + height.setValue(currentData.height); + playerStartPosX.setValue(currentData.playerStartPosX); + playerStartPosY.setValue(currentData.playerStartPosY); + noiseZoomBiome.setValue(currentData.noiseZoomBiome); + tileSize.setValue(currentData.tileSize); + biomesSprites.setText(currentData.biomesSprites); + maxRoadDistance.setValue(currentData.maxRoadDistance); + biomesNames.setText(currentData.biomesNames); + + for(String path:currentData.biomesNames) + { + Json json = new Json(); + FileHandle handle = Config.instance().getFile(path); + if (handle.exists()) + { + BiomeData data=json.fromJson(BiomeData.class, BiomeData.class, handle); + model.addElement(data); + } + } + + } } diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java index 51176c3a8b4..3aa7fb92d8f 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java @@ -15,7 +15,6 @@ import java.util.Random; * contains the information for the biomes */ public class BiomeData implements Serializable { - private final Random rand = MyRandom.getRandom(); public float startPointX; public float startPointY; public float noiseWeight; @@ -35,6 +34,7 @@ public class BiomeData implements Serializable { private ArrayList enemyList; private ArrayList pointOfInterestList; + private final Random rand = MyRandom.getRandom(); public Color GetColor() { return Color.valueOf(color); } diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java index 1ccaee59ce8..19c6b39f72b 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java @@ -16,4 +16,16 @@ public class BiomeTerrainData { // factor for the noise resolution public float resolution; + public BiomeTerrainData() + { + + } + public BiomeTerrainData(BiomeTerrainData other) + { + spriteName=other.spriteName; + min=other.min; + max=other.max; + resolution=other.resolution; + } + } diff --git a/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java b/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java index 06e285a9d86..f2921e8d32a 100644 --- a/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java +++ b/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java @@ -42,4 +42,18 @@ public class PointOfInterestData { } return null; } + public PointOfInterestData() + { + + } + public PointOfInterestData(PointOfInterestData other) + { + name=other.name; + type=other.type; + count=other.count; + spriteAtlas=other.spriteAtlas; + sprite=other.sprite; + map=other.map; + radiusFactor=other.radiusFactor; + } } diff --git a/forge-gui-mobile/src/forge/adventure/data/WorldData.java b/forge-gui-mobile/src/forge/adventure/data/WorldData.java index 908c857fdba..d5be45f2bc8 100644 --- a/forge-gui-mobile/src/forge/adventure/data/WorldData.java +++ b/forge-gui-mobile/src/forge/adventure/data/WorldData.java @@ -17,19 +17,22 @@ import java.util.List; */ public class WorldData implements Serializable { - static Array allEnemies; public int width; public int height; public float playerStartPosX; public float playerStartPosY; public float noiseZoomBiome; public int tileSize; - public List biomesNames; public BiomeData roadTileset; public String biomesSprites; public float maxRoadDistance; + public List biomesNames; + + private BiomeSprites sprites; private List biomes; + + private static Array allEnemies; private static Array shopList; From cee28bb62aa598ef14f9c13c180e6044750b82bb Mon Sep 17 00:00:00 2001 From: Grimm Date: Thu, 28 Jul 2022 04:12:17 +0200 Subject: [PATCH 03/66] wavefunction collapse first integration --- .../src/main/java/forge/adventure/Main.java | 8 +- .../forge/adventure/editor/BiomeEdit.java | 11 +- .../adventure/editor/BiomeStructureEdit.java | 98 +++++++++++++ .../adventure/editor/BiomeTerrainEdit.java | 80 ++++++++++- .../adventure/editor/EditorMainWindow.java | 2 +- .../forge/adventure/editor/EnemyEdit.java | 2 - .../forge/adventure/editor/FloatSpinner.java | 19 +++ .../forge/adventure/editor/IntSpinner.java | 20 +++ .../adventure/editor/StructureEditor.java | 133 ++++++++++++++++++ .../forge/adventure/editor/SwingAtlas.java | 21 ++- .../adventure/editor/SwingAtlasPreview.java | 43 ++++-- .../adventure/editor/TerrainsEditor.java | 36 ++--- .../forge/adventure/editor/WorldEditor.java | 56 ++++++++ forge-gui-mobile/pom.xml | 5 + forge-gui-mobile/src/forge/Forge.java | 1 + .../src/forge/adventure/data/BiomeData.java | 1 + .../adventure/data/BiomeStructureData.java | 38 +++++ .../forge/adventure/scene/NewGameScene.java | 5 + .../src/forge/adventure/scene/StartScene.java | 9 ++ .../src/forge/adventure/stage/GameStage.java | 10 +- .../src/forge/adventure/stage/WorldStage.java | 14 +- .../src/forge/adventure/util/RewardActor.java | 5 + .../forge/adventure/world/BiomeStructure.java | 114 +++++++++++++++ .../forge/adventure/world/BiomeTexture.java | 31 +++- .../src/forge/adventure/world/World.java | 74 +++++++--- .../src/forge/adventure/world/WorldSave.java | 2 + .../src/forge/screens/SplashScreen.java | 8 ++ .../res/adventure/Shandalar/world/green.json | 8 ++ .../Shandalar/world/tilesets/autotiles.png | Bin 30516 -> 43326 bytes .../Shandalar/world/tilesets/forest.atlas | 20 +++ .../Shandalar/world/tilesets/forest.png | Bin 0 -> 16786 bytes 31 files changed, 791 insertions(+), 83 deletions(-) create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java create mode 100644 forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java create mode 100644 forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/forest.png diff --git a/forge-adventure/src/main/java/forge/adventure/Main.java b/forge-adventure/src/main/java/forge/adventure/Main.java index dcac01e5c85..54809bbe61d 100644 --- a/forge-adventure/src/main/java/forge/adventure/Main.java +++ b/forge-adventure/src/main/java/forge/adventure/Main.java @@ -106,7 +106,13 @@ public class Main { } }); - + for(int i=0;i BiomeEdit.this.updateTerrain())); tilesetName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); @@ -81,6 +82,7 @@ public class BiomeEdit extends JComponent { currentData.tilesetAtlas = tilesetAtlas.edit.getText(); currentData.tilesetName = tilesetName.getName(); currentData.terrain = terrain.getBiomeTerrainData(); + currentData.structures = structures.getBiomeStructureData(); currentData.width = (Float) width.getValue(); currentData.height = (Float) height.getValue(); currentData.color = color.getText(); @@ -109,7 +111,8 @@ public class BiomeEdit extends JComponent { name.setText(currentData.name); tilesetAtlas.edit.setText( currentData.tilesetAtlas); tilesetName.setText(currentData.tilesetName); - terrain.setTerrains(currentData.terrain); + terrain.setTerrains(currentData); + structures.setStructures(currentData); width.setValue(currentData.width); height.setValue(currentData.height); color.setText(currentData.color); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java new file mode 100644 index 00000000000..2fd8bcfb592 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java @@ -0,0 +1,98 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; +import forge.adventure.data.BiomeStructureData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +public class BiomeStructureEdit extends JComponent { + SwingAtlasPreview preview=new SwingAtlasPreview(128); + private boolean updating=false; + BiomeStructureData currentData; + BiomeData currentBiomeData; + public JTextField structureAtlasPath=new JTextField(); + public FloatSpinner x= new FloatSpinner(); + public FloatSpinner y= new FloatSpinner(); + public FloatSpinner size= new FloatSpinner(); + public JCheckBox randomPosition=new JCheckBox(); + public JCheckBox collision=new JCheckBox(); + + public BiomeStructureEdit() + { + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(6,2)); + + center.add(new JLabel("structureAtlasPath:")); center.add(structureAtlasPath); + center.add(new JLabel("x:")); center.add(x); + center.add(new JLabel("y:")); center.add(y); + center.add(new JLabel("size:")); center.add(size); + center.add(new JLabel("randomPosition:")); center.add(randomPosition); + center.add(new JLabel("collision:")); center.add(collision); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(preview,BorderLayout.LINE_START); + add(center,BorderLayout.CENTER); + + structureAtlasPath.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureEdit.this.updateStructure())); + + + x.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + y.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + size.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + randomPosition.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + collision.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + refresh(); + } + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + structureAtlasPath.setText(currentData.structureAtlasPath); + x.setValue(currentData.x); + y.setValue(currentData.y); + size.setValue(currentData.size); + randomPosition.setSelected(currentData.randomPosition); + collision.setSelected(currentData.collision); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.structureAtlasPath); + updating=false; + } + public void updateStructure() + { + + if(currentData==null||updating) + return; + currentData.structureAtlasPath=structureAtlasPath.getText(); + + currentData.x= x.floatValue(); + currentData.y= y.floatValue(); + currentData.size= size.floatValue(); + currentData.randomPosition=randomPosition.isSelected(); + currentData.collision=collision.isSelected(); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.structureAtlasPath); + emitChanged(); + } + public void setCurrentStructure(BiomeStructureData biomeTerrainData, BiomeData data) { + currentData =biomeTerrainData; + currentBiomeData=data; + refresh(); + } + + public void addChangeListener(ChangeListener listener) { + listenerList.add(ChangeListener.class, listener); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java index 24791aa585d..8986a2e6701 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java @@ -1,14 +1,88 @@ package forge.adventure.editor; +import forge.adventure.data.BiomeData; import forge.adventure.data.BiomeTerrainData; import javax.swing.*; +import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import java.awt.*; public class BiomeTerrainEdit extends JComponent { - public void setCurrentTerrain(BiomeTerrainData biomeTerrainData) { - } - public void addChangeListener(ChangeListener listener) { + SwingAtlasPreview preview=new SwingAtlasPreview(128); + private boolean updating=false; + BiomeTerrainData currentData; + BiomeData currentBiomeData; + public JTextField spriteName=new JTextField(); + public JSpinner min= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner max= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner resolution= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public BiomeTerrainEdit() + { + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(4,2)); + + center.add(new JLabel("spriteName:")); center.add(spriteName); + center.add(new JLabel("min:")); center.add(min); + center.add(new JLabel("max:")); center.add(max); + center.add(new JLabel("resolution:")); center.add(resolution); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(preview,BorderLayout.LINE_START); + add(center,BorderLayout.CENTER); + + spriteName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeTerrainEdit.this.updateTerrain())); + + min.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + max.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + resolution.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + + + refresh(); + } + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + spriteName.setText(currentData.spriteName); + min.setValue(currentData.min); + max.setValue(currentData.max); + resolution.setValue(currentData.resolution); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.spriteName); + updating=false; + } + public void updateTerrain() + { + + if(currentData==null||updating) + return; + currentData.spriteName=spriteName.getText(); + currentData.min= (float) min.getValue(); + currentData.max= (float) max.getValue(); + currentData.resolution= (float) resolution.getValue(); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.spriteName); + emitChanged(); + } + public void setCurrentTerrain(BiomeTerrainData biomeTerrainData, BiomeData data) { + currentData =biomeTerrainData; + currentBiomeData=data; + refresh(); + } + + public void addChangeListener(ChangeListener listener) { + listenerList.add(ChangeListener.class, listener); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } } } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java index 50f0d877cc9..fdfe775d914 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java @@ -14,8 +14,8 @@ public class EditorMainWindow extends JFrame { BorderLayout layout=new BorderLayout(); setLayout(layout); add(tabs); - tabs.addTab("POI",new PointOfInterestEditor()); tabs.addTab("World",new WorldEditor()); + tabs.addTab("POI",new PointOfInterestEditor()); tabs.addTab("Items",new ItemsEditor()); tabs.addTab("Enemies",new EnemyEditor()); setVisible(true); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java index 399d7c88334..3ef2d72a92c 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java @@ -10,8 +10,6 @@ import java.awt.*; */ public class EnemyEdit extends JComponent { EnemyData currentData; - - JTextField nameField=new JTextField(); JTextField colorField=new JTextField(); JSpinner lifeFiled= new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java b/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java new file mode 100644 index 00000000000..7fad0e3bad3 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java @@ -0,0 +1,19 @@ +package forge.adventure.editor; + +import javax.swing.*; + +public class FloatSpinner extends JSpinner{ + + public FloatSpinner() + { + this( 0.f, 1f, 0.1f); + } + public FloatSpinner(float min,float max,float stepSize) + { + super(new SpinnerNumberModel(new Float(0.0f), new Float(min), new Float (max), new Float(stepSize))); + } + public float floatValue() + { + return ((Float)getValue()).floatValue(); + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java b/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java new file mode 100644 index 00000000000..132817d3891 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java @@ -0,0 +1,20 @@ +package forge.adventure.editor; + +import javax.swing.*; + + +public class IntSpinner extends JSpinner { + + public IntSpinner() + { + this( 0, 100, 1); + } + public IntSpinner(int min,int max,int stepSize) + { + super(new SpinnerNumberModel(new Integer(0), new Integer(min), new Integer (max), new Integer(stepSize))); + } + public int intValue() + { + return ((Integer)getValue()).intValue(); + } +} \ No newline at end of file diff --git a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java new file mode 100644 index 00000000000..1b301ebebd7 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java @@ -0,0 +1,133 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; +import forge.adventure.data.BiomeStructureData; +import forge.adventure.data.BiomeTerrainData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.ActionListener; + +/** + * Editor class to edit configuration, maybe moved or removed + */ +public class StructureEditor extends JComponent{ + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + BiomeStructureEdit edit=new BiomeStructureEdit(); + + BiomeData currentData; + + public class StructureDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof BiomeTerrainData)) + return label; + BiomeTerrainData structureData=(BiomeTerrainData) value; + StringBuilder builder=new StringBuilder(); + builder.append("Structure"); + builder.append(" "); + builder.append(structureData.spriteName); + label.setText(builder.toString()); + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + + public StructureEditor() + { + + list.setCellRenderer(new StructureDataRenderer()); + list.addListSelectionListener(e -> StructureEditor.this.updateEdit()); + addButton("add", e -> StructureEditor.this.addStructure()); + addButton("remove", e -> StructureEditor.this.remove()); + addButton("copy", e -> StructureEditor.this.copy()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(list, BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + + + edit.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + emitChanged(); + } + }); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + BiomeStructureData data=new BiomeStructureData(model.get(selected)); + model.add(model.size(),data); + } + + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrentStructure(model.get(selected),currentData); + } + + void addStructure() + { + BiomeStructureData data=new BiomeStructureData(); + model.add(model.size(),data); + } + void remove() + { + int selected=list.getSelectedIndex(); + if(selected<0) + return; + model.remove(selected); + } + public void setStructures(BiomeData data) { + + currentData=data; + model.clear(); + if(data==null||data.structures==null) + return; + for (int i=0;i> images=new HashMap<>(); public HashMap> getImages() { return images; } - public SwingAtlas(FileHandle path) + public SwingAtlas(FileHandle path,int imageSize) { + this.imageSize=imageSize; if(!path.exists()||!path.toString().endsWith(".atlas")) return; TextureAtlas.TextureAtlasData data=new TextureAtlas.TextureAtlasData(path,path.parent(),false); @@ -37,17 +39,28 @@ public class SwingAtlas { images.put(name,new ArrayList<>()); } ArrayList imageList=images.get(name); - try { + try + { imageList.add(spriteToImage(region)); - } catch (IOException e) { + } + catch (IOException e) + { e.printStackTrace(); } } } + public SwingAtlas(FileHandle path) + { + this(path,32); + } private ImageIcon spriteToImage(TextureAtlas.TextureAtlasData.Region sprite) throws IOException { BufferedImage img = ImageIO.read(sprite.page.textureFile.file()); - return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(32,32,SCALE_FAST)); + if(sprite.width== sprite.height) + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize,imageSize,SCALE_FAST)); + if(sprite.width>sprite.height) + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize, (int) (imageSize*(sprite.height/(float)sprite.width)),SCALE_FAST)); + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance((int) (imageSize*(sprite.width/(float)sprite.height)),imageSize,SCALE_FAST)); } public ImageIcon get(String name) { diff --git a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java index 3631e133a8c..63d08c62f24 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java @@ -13,11 +13,12 @@ import java.util.Map; * Editor class to edit configuration, maybe moved or removed */ public class SwingAtlasPreview extends Box { + int imageSize=32; private String sprite=""; + private String spriteName=""; Timer timer; public SwingAtlasPreview() { super(BoxLayout.Y_AXIS); - timer = new Timer(200, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { @@ -28,25 +29,51 @@ public class SwingAtlasPreview extends Box { } }); } + public SwingAtlasPreview(int size) { + this(); + imageSize=size; + } int counter=0; List>> labels=new ArrayList<>(); public void setSpritePath(String sprite) { - if(this.sprite==null||this.sprite.equals(sprite)) + setSpritePath(sprite,null); + } + public void setSpritePath(String sprite,String name) { + + if(this.sprite==null||name==null||sprite==null||(this.sprite.equals(sprite)&&(spriteName==null&&spriteName.equals(name)))) return; removeAll(); counter=0; labels.clear(); this.sprite=sprite; - SwingAtlas atlas=new SwingAtlas(Config.instance().getFile(sprite)); + this.spriteName=name; + SwingAtlas atlas=new SwingAtlas(Config.instance().getFile(sprite),imageSize); + int maxCount=0; for(Map.Entry> element:atlas.getImages().entrySet()) { - JLabel image=new JLabel(element.getValue().get(0)); - add(new JLabel(element.getKey())); - add(image); - labels.add(Pair.of(image, element.getValue())); + if(name==null||element.getKey().equals(name)) + { + JLabel image=new JLabel(element.getValue().get(0)); + if(maxCount0) - { - builder.append("-"); - builder.append(reward.count+reward.addMaxCount); - } + builder.append(terrainData.spriteName); label.setText(builder.toString()); return label; } @@ -58,7 +50,7 @@ public class TerrainsEditor extends JComponent{ list.setCellRenderer(new TerrainDataRenderer()); list.addListSelectionListener(e -> TerrainsEditor.this.updateEdit()); - addButton("add", e -> TerrainsEditor.this.addReward()); + addButton("add", e -> TerrainsEditor.this.addTerrain()); addButton("remove", e -> TerrainsEditor.this.remove()); addButton("copy", e -> TerrainsEditor.this.copy()); BorderLayout layout=new BorderLayout(); @@ -98,10 +90,10 @@ public class TerrainsEditor extends JComponent{ int selected=list.getSelectedIndex(); if(selected<0) return; - edit.setCurrentTerrain(model.get(selected)); + edit.setCurrentTerrain(model.get(selected),currentData); } - void addReward() + void addTerrain() { BiomeTerrainData data=new BiomeTerrainData(); model.add(model.size(),data); @@ -113,14 +105,16 @@ public class TerrainsEditor extends JComponent{ return; model.remove(selected); } - public void setTerrains(BiomeTerrainData[] terrain) { + public void setTerrains(BiomeData data) { + currentData=data; model.clear(); - if(terrain==null) + if(data==null||data.terrain==null) return; - for (int i=0;i WorldEditor.this.save()); toolBar.add(newButton); + newButton=new JButton("load"); newButton.addActionListener(e -> WorldEditor.this.load()); toolBar.add(newButton); + + toolBar.addSeparator(); + + newButton=new JButton("test map"); + newButton.addActionListener(e -> WorldEditor.this.test()); + toolBar.add(newButton); + } + + private void test() { + + String javaHome = System.getProperty("java.home"); + String javaBin = javaHome + File.separator + "bin" + File.separator + "java"; + String classpath = System.getProperty("java.class.path"); + String className = forge.adventure.Main.class.getName(); + + ArrayList command = new ArrayList<>(); + command.add(javaBin); + command.add("-cp"); + command.add(classpath); + command.add(className); + + command.add("testMap"); + + ProcessBuilder build= new ProcessBuilder(command); + build .redirectInput(ProcessBuilder.Redirect.INHERIT) + .redirectOutput(ProcessBuilder.Redirect.INHERIT) + .redirectError(ProcessBuilder.Redirect.INHERIT); + try { + Process process= build.start(); + } catch (IOException e) { + throw new RuntimeException(e); + } } void save() diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml index 0c4ef128e59..e34f7d42fa7 100644 --- a/forge-gui-mobile/pom.xml +++ b/forge-gui-mobile/pom.xml @@ -55,6 +55,11 @@ gdx-freetype 1.11.0 + + com.github.sjcasey21 + wavefunctioncollapse + 0.2.2 + diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 7a692d8cb6e..ea5c49f4d97 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -123,6 +123,7 @@ public class Forge implements ApplicationListener { private static Cursor cursor0, cursor1, cursor2, cursorA0, cursorA1, cursorA2; public static boolean forcedEnglishonCJKMissing = false; public static boolean adventureLoaded = false; + public static boolean createNewAdventureMap = false; private static Localizer localizer; public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value, boolean androidOrientation, int totalRAM, boolean isTablet, int AndroidAPI, String AndroidRelease, String deviceName) { diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java index 3aa7fb92d8f..61a2b1a5193 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java @@ -30,6 +30,7 @@ public class BiomeData implements Serializable { public String[] spriteNames; public List enemies; public List pointsOfInterest; + public BiomeStructureData[] structures; private ArrayList enemyList; private ArrayList pointOfInterestList; diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java new file mode 100644 index 00000000000..50df63f6157 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java @@ -0,0 +1,38 @@ +package forge.adventure.data; + +import java.awt.image.BufferedImage; + +public class BiomeStructureData { + public int N = 3; + public float x; + public float y; + public float size; + public boolean randomPosition; + public boolean collision; + + public String structureAtlasPath; + public boolean periodicInput; + public float height; + public float width; + public int ground; + public int symmetry; + public boolean periodicOutput; + + public BiomeStructureData( ) + { + + } + public BiomeStructureData(BiomeStructureData biomeStructureData) { + this.structureAtlasPath=biomeStructureData.structureAtlasPath; + this.x=biomeStructureData.x; + this.y=biomeStructureData.y; + this.size=biomeStructureData.size; + this.randomPosition=biomeStructureData.randomPosition; + this.collision=biomeStructureData.collision; + } + + public BufferedImage sourceImage() { + + return null; + } +} diff --git a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java index 6f836cbe6ea..126b36cd98a 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java @@ -226,6 +226,11 @@ public class NewGameScene extends UIScene { public void enter() { updateAvatar(); Gdx.input.setInputProcessor(stage); //Start taking input from the ui + + if(Forge.createNewAdventureMap) + { + start(); + } } @Override diff --git a/forge-gui-mobile/src/forge/adventure/scene/StartScene.java b/forge-gui-mobile/src/forge/adventure/scene/StartScene.java index 38f4dc0b770..042ce5d13a0 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/StartScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/StartScene.java @@ -7,9 +7,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.utils.Align; import forge.Forge; import forge.adventure.stage.GameHUD; +import forge.adventure.stage.GameStage; import forge.adventure.stage.MapStage; import forge.adventure.util.Config; import forge.adventure.util.Controls; +import forge.adventure.util.Current; import forge.adventure.world.WorldSave; import forge.screens.TransitionScreen; @@ -102,6 +104,13 @@ public class StartScene extends UIScene { } Gdx.input.setInputProcessor(stage); //Start taking input from the ui + + if(Forge.createNewAdventureMap) + { + this.NewGame(); + Current.setDebug(true); + GameStage.maximumScrollDistance=4f; + } } @Override diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java index d904c379224..daa2b3370f6 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java @@ -36,6 +36,8 @@ public abstract class GameStage extends Stage { private float touchY = -1; private final float timer = 0; private float animationTimeout = 0; + public static float maximumScrollDistance=1.5f; + public static float minimumScrollDistance=0.3f; public void startPause(float i) { startPause(i, null); @@ -222,10 +224,10 @@ public abstract class GameStage extends Stage { if (isPaused()) return true; camera.zoom += (amountY * 0.03); - if (camera.zoom < 0.3f) - camera.zoom = 0.3f; - if (camera.zoom > 1.5f) - camera.zoom = 1.5f; + if (camera.zoom < minimumScrollDistance) + camera.zoom = minimumScrollDistance; + if (camera.zoom > maximumScrollDistance) + camera.zoom = maximumScrollDistance; return super.scrolled(amountX, amountY); } diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java index c7e14a7f550..7fa6d0ce2f5 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java @@ -176,19 +176,7 @@ public class WorldStage extends GameStage implements SaveFileContent { public boolean isColliding(Rectangle boundingRect) { - World world = WorldSave.getCurrentSave().getWorld(); - int currentBiome = World.highestBiome(world.getBiome((int) boundingRect.getX() / world.getTileSize(), (int) boundingRect.getY() / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) (boundingRect.getX()+boundingRect.getWidth()) / world.getTileSize(), (int) boundingRect.getY() / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) (boundingRect.getX()+boundingRect.getWidth())/ world.getTileSize(), (int) (boundingRect.getY()+boundingRect.getHeight()) / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) boundingRect.getX() / world.getTileSize(), (int) (boundingRect.getY()+boundingRect.getHeight()) / world.getTileSize())); - - return (currentBiome==0); + return WorldSave.getCurrentSave().getWorld().collidingTile(boundingRect); } private void HandleMonsterSpawn(float delta) { diff --git a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java index f2220bdd37d..fb3f27d17c9 100644 --- a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java +++ b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java @@ -202,6 +202,11 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb } private void setCardImage(Texture img) { + if(img==null) + { + System.err.print("Null texture loaded for " +reward); + return; + } image = img; if (Forge.isTextureFilteringEnabled()) image.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); diff --git a/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java new file mode 100644 index 00000000000..e991e52f183 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java @@ -0,0 +1,114 @@ +package forge.adventure.world; + +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.github.sjcasey21.wavefunctioncollapse.OverlappingModel; +import forge.adventure.data.BiomeStructureData; +import forge.adventure.util.Config; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + +public class BiomeStructure { + + private BiomeStructureData data; + long seed; + private int biomeWidth; + private int biomeHeight; + private int dataMap[][]; + boolean init=false; + private TextureAtlas structureAtlas; + public BiomeStructure(BiomeStructureData data,long seed,int width,int height) + { + this.data=data; + this.seed=seed; + this.biomeWidth = width; + this.biomeHeight = height; + } + public TextureAtlas atlas() { + if(structureAtlas==null) + { + structureAtlas = Config.instance().getAtlas(data.structureAtlasPath); + } + return structureAtlas; + } + public int structureObjectCount() { + int count=0; + for(TextureAtlas.AtlasRegion region:atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + count++; + } + } + return count; + } + + public int objectID(int x, int y) { + + if(!init) + { + init=true; + initialize(); + } + if(x>biomeWidth*data.width) + return -1; + if(y>biomeHeight*data.height) + return -1; + if(x colorIdMap=new HashMap<>(); + int counter=0; + for(TextureAtlas.AtlasRegion region:atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + String[] split= region.name.split("_"); + if(split.length<2) + continue; + int rgb=Integer.parseInt(split[1],16); + colorIdMap.put(rgb,counter); + counter++; + } + } + BufferedImage image=model.graphics(); + dataMap=new int[image.getWidth()][image.getHeight()]; + for(int x=0;x> images = new ArrayList<>(); ArrayList> smallImages = new ArrayList<>(); ArrayList> edgeImages = new ArrayList<>(); @@ -45,7 +46,6 @@ public class BiomeTexture implements Serializable { FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public void run() { - Pixmap completePicture = null; if (images != null) { for (ArrayList val : images) { @@ -79,22 +79,38 @@ public class BiomeTexture implements Serializable { edgeImages = new ArrayList<>(); ArrayList regions =new ArrayList<>(); + ArrayList source =new ArrayList<>(); regions.add(Config.instance().getAtlas(data.tilesetAtlas).findRegion(data.tilesetName)); + source.add(Config.instance().getAtlas(data.tilesetAtlas)); if(data.terrain!=null) { for(BiomeTerrainData terrain:data.terrain) { regions.add(Config.instance().getAtlas(data.tilesetAtlas).findRegion(terrain.spriteName)); + source.add(Config.instance().getAtlas(data.tilesetAtlas)); } } + if(data.structures!=null) + { + for(BiomeStructureData structureData:data.structures) + { + BiomeStructure structure=new BiomeStructure(structureData,0,0,0); + for(TextureAtlas.AtlasRegion region:structure.atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + regions.add(region); + source.add(structure.atlas()); + } + } + } + } + for (TextureAtlas.AtlasRegion region : regions) { ArrayList pics = new ArrayList<>(); ArrayList spics = new ArrayList<>(); - if (completePicture == null) { region.getTexture().getTextureData().prepare(); - completePicture = region.getTexture().getTextureData().consumePixmap(); - } - + Pixmap completePicture = region.getTexture().getTextureData().consumePixmap(); for (int y = 0; y < 4; y++) { for (int x = 0; x < 3; x++) { int px = region.getRegionX() + (x * tileSize); @@ -117,6 +133,7 @@ public class BiomeTexture implements Serializable { smallImages.add(spics); edgeImages.add(new IntMap<>()); + completePicture.dispose(); } } }); @@ -124,6 +141,8 @@ public class BiomeTexture implements Serializable { public Pixmap getPixmap(int biomeSubIndex) { if (biomeSubIndex >= edgeImages.size() || biomeSubIndex < 0) { + if(emptyPixmap==null) + emptyPixmap=new Pixmap(1, 1, Pixmap.Format.RGBA8888); return emptyPixmap; } return images.get(biomeSubIndex).get(BigPictures.Center.value); diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index a7ecf515a65..c450f067507 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -9,11 +9,7 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.Json; -import forge.adventure.data.BiomeData; -import forge.adventure.data.BiomeSpriteData; -import forge.adventure.data.BiomeTerrainData; -import forge.adventure.data.PointOfInterestData; -import forge.adventure.data.WorldData; +import forge.adventure.data.*; import forge.adventure.pointofintrest.PointOfInterest; import forge.adventure.pointofintrest.PointOfInterestMap; import forge.adventure.scene.Scene; @@ -24,10 +20,7 @@ import forge.adventure.util.SaveFileContent; import forge.adventure.util.SaveFileData; import org.apache.commons.lang3.tuple.Pair; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Random; +import java.util.*; /** * Class that will create the world from the configuration @@ -55,6 +48,26 @@ public class World implements Disposable, SaveFileContent { return (int) (Math.log(Long.highestOneBit(biome)) / Math.log(2)); } + public boolean collidingTile(Rectangle boundingRect) + { + Set> points=new HashSet<>(); + + int xLeft=(int) boundingRect.getX() / getTileSize(); + int yTop=(int) boundingRect.getY() / getTileSize(); + int xRight=(int) (boundingRect.getX()+boundingRect.getWidth()) / getTileSize(); + int yBottom= (int) (boundingRect.getY()+boundingRect.getHeight()) / getTileSize(); + + if(getBiome(xLeft,yTop)==0) + return true; + if(getBiome(xLeft,yBottom)==0) + return true; + if(getBiome(xRight,yBottom)==0) + return true; + if(getBiome(xRight,yTop)==0) + return true; + + return false; + } public void loadWorldData() { if(worldDataLoaded) return; @@ -85,6 +98,9 @@ public class World implements Disposable, SaveFileContent { biomeImage=saveFileData.readPixmap("biomeImage"); biomeMap=(long[][])saveFileData.readObject("biomeMap"); terrainMap=(int[][])saveFileData.readObject("terrainMap"); + + + width=saveFileData.readInt("width"); height=saveFileData.readInt("height"); mapObjectIds = new SpritesDataMap(getChunkSize(), this.data.tileSize, this.data.width / getChunkSize()); @@ -269,6 +285,7 @@ public class World implements Disposable, SaveFileContent { endX = width; endY = height; } + HashMap structureDataMap=new HashMap<>(); for (int x = beginX; x < endX; x++) { for (int y = beginY; y < endY; y++) { //value 0-1 based on noise @@ -288,16 +305,34 @@ public class World implements Disposable, SaveFileContent { pix.drawPixel(x, y); biomeMap[x][y] |= (1L << biomeIndex); int terrainCounter=1; - if(biome.terrain==null) - continue; - for(BiomeTerrainData terrain:biome.terrain) + if(biome.terrain!=null) { - float terrainNoise = ((float)noise.eval(x / (float) width * (noiseZoom*terrain.resolution), y / (float) height * (noiseZoom*terrain.resolution)) + 1) / 2; - if(terrainNoise>=terrain.min&&terrainNoise<=terrain.max) + for(BiomeTerrainData terrain:biome.terrain) { - terrainMap[x][y]=terrainCounter; + float terrainNoise = ((float)noise.eval(x / (float) width * (noiseZoom*terrain.resolution), y / (float) height * (noiseZoom*terrain.resolution)) + 1) / 2; + if(terrainNoise>=terrain.min&&terrainNoise<=terrain.max) + { + terrainMap[x][y]=terrainCounter; + } + terrainCounter++; + } + } + if(biome.structures!=null) + { + for(BiomeStructureData data:biome.structures) + { + BiomeStructure structure; + if(!structureDataMap.containsKey(data)) + { + structureDataMap.put(data,new BiomeStructure(data,seed,biomeWidth,biomeHeight)); + } + structure=structureDataMap.get(data); + int structureIndex=structure.objectID(x-biomeXStart,y-biomeYStart); + if(structureIndex>=0) + terrainMap[x][y]=terrainCounter+structureIndex; + + terrainCounter+=structure.structureObjectCount(); } - terrainCounter++; } } @@ -432,6 +467,9 @@ public class World implements Disposable, SaveFileContent { for (int y = (int) currentPoint.y - 1; y < currentPoint.y + 2; y++) { if(x<0||y<=0||x>=width||y>height)continue; biomeMap[x][height - y] |= (1L << biomeIndex); + terrainMap[x][height-y]=0; + + pix.drawPixel(x, height-y); } } @@ -465,7 +503,9 @@ public class World implements Disposable, SaveFileContent { if( (int)currentPoint.x<0|| (int)currentPoint.y<=0|| (int)currentPoint.x>=width|| (int)currentPoint.y>height)continue; biomeMap[(int) currentPoint.x][height - (int) currentPoint.y] |= (1L << biomeIndex); + terrainMap[(int) currentPoint.x][height - (int) currentPoint.y]=0; pix.drawPixel((int) currentPoint.x, height - (int) currentPoint.y); + } } @@ -482,6 +522,8 @@ public class World implements Disposable, SaveFileContent { BiomeSpriteData sprite = data.GetBiomeSprites().getSpriteData(name); double spriteNoise = (noise.eval(x / (double) width * noiseZoom*sprite.resolution, y / (double) invertedHeight * noiseZoom*sprite.resolution) + 1) / 2; if (spriteNoise >= sprite.startArea && spriteNoise <= sprite.endArea) { + if(terrainMap[x][invertedHeight]>biome.terrain.length) + continue; if (random.nextFloat() <= sprite.density) { String spriteKey = sprite.key(); int key; diff --git a/forge-gui-mobile/src/forge/adventure/world/WorldSave.java b/forge-gui-mobile/src/forge/adventure/world/WorldSave.java index 228f878d15f..a28af044f85 100644 --- a/forge-gui-mobile/src/forge/adventure/world/WorldSave.java +++ b/forge-gui-mobile/src/forge/adventure/world/WorldSave.java @@ -57,6 +57,8 @@ public class WorldSave { static public boolean load(int currentSlot) { String fileName = WorldSave.getSaveFile(currentSlot); + if(!new File(fileName).exists()) + return false; new File(getSaveDir()).mkdirs(); try { try(FileInputStream fos = new FileInputStream(fileName); diff --git a/forge-gui-mobile/src/forge/screens/SplashScreen.java b/forge-gui-mobile/src/forge/screens/SplashScreen.java index d43f57bc13d..d20f8ea6522 100644 --- a/forge-gui-mobile/src/forge/screens/SplashScreen.java +++ b/forge-gui-mobile/src/forge/screens/SplashScreen.java @@ -265,6 +265,14 @@ public class SplashScreen extends FContainer { add(btnHome); btnAdventure.setBounds(btn_x, btn_y + height + padding / 2, btn_w, height); add(btnAdventure); + + if(Forge.createNewAdventureMap) + { + bgAnimation.progress = 1; + bgAnimation.openAdventure = true; + Forge.openAdventure(); + Forge.clearSplashScreen(); + } } } diff --git a/forge-gui/res/adventure/Shandalar/world/green.json b/forge-gui/res/adventure/Shandalar/world/green.json index bf0dca678ba..def5769876c 100644 --- a/forge-gui/res/adventure/Shandalar/world/green.json +++ b/forge-gui/res/adventure/Shandalar/world/green.json @@ -19,6 +19,14 @@ "resolution": 10 } ], + "structures":[ + { + "structureAtlasPath":"world/tilesets/forest.atlas", + "x": 0.5, + "y": 0.5, + "size": 0.3 + } + ], "width": 0.7, "height": 0.7, "color": "59a650", diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/autotiles.png b/forge-gui/res/adventure/Shandalar/world/tilesets/autotiles.png index 8c651dffb0897c7d0bfa57a3f936ebe3e38a04ec..c10104d2528f02593787acc2cf3f9c9e4be79fad 100644 GIT binary patch delta 12980 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 B5Iz6^ diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas new file mode 100644 index 00000000000..bb08300ae21 --- /dev/null +++ b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas @@ -0,0 +1,20 @@ + +forest.png +size: 96,64 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +Source + rotate: false + xy: 0, 0 + size: 16, 16 + orig: 0, 0 + offset: 0, 0 + index: 0 +structure_000000 + rotate: false + xy: 48, 0 + size: 48, 64 + orig: 0, 0 + offset: 0, 0 + index: 0 \ No newline at end of file diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png new file mode 100644 index 0000000000000000000000000000000000000000..cf8dd71e0c9d2cb2327c33398a99d087c459cf34 GIT binary patch literal 16786 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 literal 0 HcmV?d00001 From dbbc065eadf86855ec82d43adc60695b3d203ff2 Mon Sep 17 00:00:00 2001 From: Grimm Date: Fri, 10 Jun 2022 23:25:45 +0200 Subject: [PATCH 04/66] AdventureEditor: added editors --- forge-adventure/pom.xml | 2 +- .../forge/adventure/editor/BiomeEdit.java | 122 ++++++++++++++ .../adventure/editor/BiomeTerrainEdit.java | 14 ++ .../java/forge/adventure/editor/ItemEdit.java | 3 +- .../adventure/editor/PointOfInterestEdit.java | 88 ++++++++++ .../editor/PointOfInterestEditor.java | 129 ++++++++++++++- .../forge/adventure/editor/RewardEdit.java | 114 ++----------- .../forge/adventure/editor/RewardsEditor.java | 31 +--- .../adventure/editor/TerrainsEditor.java | 138 ++++++++++++++++ .../forge/adventure/editor/TextListEdit.java | 7 + .../forge/adventure/editor/WorldEditor.java | 151 +++++++++++++++++- .../src/forge/adventure/data/BiomeData.java | 2 +- .../adventure/data/BiomeTerrainData.java | 12 ++ .../adventure/data/PointOfInterestData.java | 14 ++ .../src/forge/adventure/data/WorldData.java | 7 +- 15 files changed, 699 insertions(+), 135 deletions(-) create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java diff --git a/forge-adventure/pom.xml b/forge-adventure/pom.xml index 9b2fd342fe3..9ddea05130a 100644 --- a/forge-adventure/pom.xml +++ b/forge-adventure/pom.xml @@ -17,7 +17,7 @@ - src + src/main/java ${project.basedir} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java new file mode 100644 index 00000000000..70c595437a9 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java @@ -0,0 +1,122 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; + +import javax.swing.*; +import java.awt.*; +import java.util.Arrays; + +public class BiomeEdit extends JComponent { + BiomeData currentData; + + public JSpinner startPointX= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner startPointY= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner noiseWeight= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner distWeight= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JTextField name=new JTextField(); + public FilePicker tilesetAtlas=new FilePicker(new String[]{"atlas"}); + public JTextField tilesetName=new JTextField(); + public JSpinner width= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner height= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JTextField color=new JTextField(); + public TextListEdit spriteNames =new TextListEdit(); + public TextListEdit enemies =new TextListEdit(); + public TextListEdit pointsOfInterest =new TextListEdit(); + + public TerrainsEditor terrain =new TerrainsEditor(); + + private boolean updating=false; + + public BiomeEdit() + { + + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(14,2)); + + center.add(new JLabel("startPointX:")); center.add(startPointX); + center.add(new JLabel("startPointY:")); center.add(startPointY); + center.add(new JLabel("noiseWeight:")); center.add(noiseWeight); + center.add(new JLabel("distWeight:")); center.add(distWeight); + center.add(new JLabel("name:")); center.add(name); + center.add(new JLabel("tilesetAtlas:")); center.add(tilesetAtlas); + center.add(new JLabel("tilesetName:")); center.add(tilesetName); + center.add(new JLabel("width:")); center.add(width); + center.add(new JLabel("height:")); center.add(height); + center.add(new JLabel("spriteNames:")); center.add(spriteNames); + center.add(new JLabel("enemies:")); center.add(enemies); + center.add(new JLabel("pointsOfInterest:")); center.add(pointsOfInterest); + center.add(new JLabel("color:")); center.add(color); + center.add(new JLabel("terrain:")); center.add(terrain); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(center,BorderLayout.PAGE_START); + add(terrain,BorderLayout.CENTER); + + name.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + tilesetName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + color.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + spriteNames.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + enemies.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + terrain.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + + + startPointX.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + startPointY.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + noiseWeight.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + distWeight.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + tilesetAtlas.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + width.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + height.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + refresh(); + } + + private void updateTerrain() { + if(currentData==null||updating) + return; + currentData.startPointX = (Float) startPointX.getValue(); + currentData.startPointY = (Float) startPointY.getValue(); + currentData.noiseWeight = (Float) noiseWeight.getValue(); + currentData.distWeight = (Float)distWeight.getValue(); + currentData.name = name.getText(); + currentData.tilesetAtlas = tilesetAtlas.edit.getText(); + currentData.tilesetName = tilesetName.getName(); + currentData.terrain = terrain.getBiomeTerrainData(); + currentData.width = (Float) width.getValue(); + currentData.height = (Float) height.getValue(); + currentData.color = color.getText(); + currentData.spriteNames = spriteNames.getList(); + currentData.enemies = Arrays.asList(enemies.getList()); + currentData.pointsOfInterest = Arrays.asList(pointsOfInterest.getList()); + } + + public void setCurrentBiome(BiomeData data) + { + currentData=data; + refresh(); + } + + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + startPointX.setValue(currentData.startPointX); + startPointY.setValue(currentData.startPointY); + noiseWeight.setValue(currentData.noiseWeight); + distWeight.setValue(currentData.distWeight); + name.setText(currentData.name); + tilesetAtlas.edit.setText( currentData.tilesetAtlas); + tilesetName.setText(currentData.tilesetName); + terrain.setTerrains(currentData.terrain); + width.setValue(currentData.width); + height.setValue(currentData.height); + color.setText(currentData.color); + spriteNames.setText(currentData.spriteNames); + enemies.setText(currentData.enemies); + color.setText(currentData.color); + pointsOfInterest.setText(currentData.pointsOfInterest); + updating=false; + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java new file mode 100644 index 00000000000..24791aa585d --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java @@ -0,0 +1,14 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeTerrainData; + +import javax.swing.*; +import javax.swing.event.ChangeListener; + +public class BiomeTerrainEdit extends JComponent { + public void setCurrentTerrain(BiomeTerrainData biomeTerrainData) { + } + public void addChangeListener(ChangeListener listener) { + + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java index 248bd275914..26f9f30923d 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java @@ -10,8 +10,6 @@ import java.awt.*; */ public class ItemEdit extends JComponent { ItemData currentData; - - JTextField nameField=new JTextField(); JTextField equipmentSlot=new JTextField(); JTextField iconName=new JTextField(); @@ -39,6 +37,7 @@ public class ItemEdit extends JComponent { add(parameters); add(effect); + add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); nameField.getDocument().addDocumentListener(new DocumentChangeListener(() -> ItemEdit.this.updateItem())); equipmentSlot.getDocument().addDocumentListener(new DocumentChangeListener(() -> ItemEdit.this.updateItem())); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java new file mode 100644 index 00000000000..045777feb94 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java @@ -0,0 +1,88 @@ +package forge.adventure.editor; + +import forge.adventure.data.PointOfInterestData; + +import javax.swing.*; +import java.awt.*; + +public class PointOfInterestEdit extends JComponent { + + PointOfInterestData currentData; + + + JTextField name = new JTextField(); + JTextField type = new JTextField(); + JSpinner count = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); + FilePicker spriteAtlas = new FilePicker(new String[]{"atlas"}); + JTextField sprite = new JTextField(); + FilePicker map = new FilePicker(new String[]{"tmx"}); + JSpinner radiusFactor= new JSpinner(new SpinnerNumberModel(0.0f, 0.0f, 2.0f, 0.1f)); + + + private boolean updating=false; + + public PointOfInterestEdit() + { + + setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); + JPanel parameters=new JPanel(); + parameters.setBorder(BorderFactory.createTitledBorder("Parameter")); + parameters.setLayout(new GridLayout(7,2)) ; + + parameters.add(new JLabel("Name:")); parameters.add(name); + parameters.add(new JLabel("Type:")); parameters.add(type); + parameters.add(new JLabel("Count:")); parameters.add(count); + parameters.add(new JLabel("Sprite atlas:")); parameters.add(spriteAtlas); + parameters.add(new JLabel("Sprite:")); parameters.add(sprite); + parameters.add(new JLabel("Map:")); parameters.add(map); + parameters.add(new JLabel("Radius factor:")); parameters.add(radiusFactor); + + add(parameters); + add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); + + name.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + type.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + count.addChangeListener(e -> PointOfInterestEdit.this.updateItem()); + spriteAtlas.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + sprite.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + map.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + radiusFactor.addChangeListener(e -> PointOfInterestEdit.this.updateItem()); + refresh(); + } + + private void updateItem() { + if(currentData==null||updating) + return; + currentData.name=name.getText(); + currentData.type= type.getText(); + currentData.count= ((Integer) count.getValue()).intValue(); + currentData.spriteAtlas=spriteAtlas.getEdit().getText(); + currentData.sprite=sprite.getText(); + currentData.map=map.getEdit().getText(); + currentData.radiusFactor=((Float) radiusFactor.getValue()).floatValue(); + } + + public void setCurrent(PointOfInterestData data) + { + currentData=data; + refresh(); + } + + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + name.setText(currentData.name); + type.setText(currentData.type); + count.setValue(currentData.count); + spriteAtlas.getEdit().setText(currentData.spriteAtlas); + sprite.setText(currentData.sprite); + map.getEdit().setText(currentData.map); + radiusFactor.setValue(currentData.radiusFactor); + + updating=false; + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java index 83ff548e68e..4fa4b0e9209 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java @@ -1,6 +1,131 @@ package forge.adventure.editor; -import java.awt.*; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter; +import forge.adventure.data.PointOfInterestData; +import forge.adventure.util.Config; +import forge.adventure.util.Paths; -public class PointOfInterestEditor extends Component { +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionListener; +import java.util.HashMap; + +public class PointOfInterestEditor extends JComponent { + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + PointOfInterestEdit edit=new PointOfInterestEdit(); + static HashMap atlas=new HashMap<>(); + + + + public class PointOfInterestRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof PointOfInterestData)) + return label; + PointOfInterestData poi=(PointOfInterestData) value; + // Get the renderer component from parent class + + label.setText(poi.name); + if(!atlas.containsKey(poi.spriteAtlas)) + atlas.put(poi.spriteAtlas,new SwingAtlas(Config.instance().getFile(poi.spriteAtlas))); + + SwingAtlas poiAtlas = atlas.get(poi.spriteAtlas); + + if(poiAtlas.has(poi.sprite)) + label.setIcon(poiAtlas.get(poi.sprite)); + else + { + ImageIcon img=poiAtlas.getAny(); + if(img!=null) + label.setIcon(img); + } + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + public PointOfInterestEditor() + { + + list.setCellRenderer(new PointOfInterestEditor.PointOfInterestRenderer()); + list.addListSelectionListener(e -> PointOfInterestEditor.this.updateEdit()); + addButton("add", e -> PointOfInterestEditor.this.addItem()); + addButton("remove", e -> PointOfInterestEditor.this.remove()); + addButton("copy", e -> PointOfInterestEditor.this.copy()); + addButton("load", e -> PointOfInterestEditor.this.load()); + addButton("save", e -> PointOfInterestEditor.this.save()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(new JScrollPane(list), BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + load(); + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + PointOfInterestData data=new PointOfInterestData(model.get(selected)); + model.add(model.size(),data); + } + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrent(model.get(selected)); + } + + void save() + { + Array allEnemies=new Array<>(); + for(int i=0;i allEnemies=new Array<>(); + Json json = new Json(); + FileHandle handle = Config.instance().getFile(Paths.POINTS_OF_INTEREST); + if (handle.exists()) + { + Array readEnemies=json.fromJson(Array.class, PointOfInterestData.class, handle); + allEnemies = readEnemies; + } + for (int i=0;i RewardEdit.this.updateReward())); + probability.addChangeListener(e -> RewardEdit.this.updateReward()); + count.addChangeListener(e -> RewardEdit.this.updateReward()); + addMaxCount.addChangeListener(e -> RewardEdit.this.updateReward()); + cardName.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + itemName.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + editions.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + colors.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + rarity.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + subTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + cardTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + superTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + manaCosts.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + keyWords.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + colorType.addActionListener((e -> RewardEdit.this.updateReward())); + cardText.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java index a2d6cc0f617..786128f6bad 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java @@ -5,10 +5,7 @@ import forge.adventure.data.RewardData; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import java.awt.*; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** @@ -59,30 +56,10 @@ public class RewardsEditor extends JComponent{ { list.setCellRenderer(new RewardDataRenderer()); - list.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - RewardsEditor.this.updateEdit(); - } - }); - addButton("add", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.addReward(); - } - }); - addButton("remove", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.remove(); - } - }); - addButton("copy", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.copy(); - } - }); + list.addListSelectionListener(e -> RewardsEditor.this.updateEdit()); + addButton("add", e -> RewardsEditor.this.addReward()); + addButton("remove", e -> RewardsEditor.this.remove()); + addButton("copy", e -> RewardsEditor.this.copy()); BorderLayout layout=new BorderLayout(); setLayout(layout); add(list, BorderLayout.LINE_START); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java new file mode 100644 index 00000000000..69a7578a13d --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java @@ -0,0 +1,138 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeTerrainData; +import forge.adventure.data.RewardData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.ActionListener; + +/** + * Editor class to edit configuration, maybe moved or removed + */ +public class TerrainsEditor extends JComponent{ + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + BiomeTerrainEdit edit=new BiomeTerrainEdit(); + + + + public class TerrainDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof RewardData)) + return label; + RewardData reward=(RewardData) value; + StringBuilder builder=new StringBuilder(); + if(reward.type==null||reward.type.isEmpty()) + builder.append("Terrain"); + else + builder.append(reward.type); + builder.append(" "); + builder.append(reward.count); + if(reward.addMaxCount>0) + { + builder.append("-"); + builder.append(reward.count+reward.addMaxCount); + } + label.setText(builder.toString()); + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + + public TerrainsEditor() + { + + list.setCellRenderer(new TerrainDataRenderer()); + list.addListSelectionListener(e -> TerrainsEditor.this.updateEdit()); + addButton("add", e -> TerrainsEditor.this.addReward()); + addButton("remove", e -> TerrainsEditor.this.remove()); + addButton("copy", e -> TerrainsEditor.this.copy()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(list, BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + + + edit.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + emitChanged(); + } + }); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + BiomeTerrainData data=new BiomeTerrainData(model.get(selected)); + model.add(model.size(),data); + } + + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrentTerrain(model.get(selected)); + } + + void addReward() + { + BiomeTerrainData data=new BiomeTerrainData(); + model.add(model.size(),data); + } + void remove() + { + int selected=list.getSelectedIndex(); + if(selected<0) + return; + model.remove(selected); + } + public void setTerrains(BiomeTerrainData[] terrain) { + + model.clear(); + if(terrain==null) + return; + for (int i=0;i itemNames) { + if(itemNames==null) + edit.setText(""); + else + edit.setText(String.join(";",itemNames)); + } public void setText(String[] itemName) { if(itemName==null) edit.setText(""); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java index 221ac5d64ae..e1fde6621e9 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java @@ -1,6 +1,153 @@ package forge.adventure.editor; -import java.awt.*; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter; +import forge.adventure.data.BiomeData; +import forge.adventure.data.WorldData; +import forge.adventure.util.Config; +import forge.adventure.util.Paths; -public class WorldEditor extends Component { +import javax.swing.*; +import java.awt.*; +import java.util.HashMap; + +public class WorldEditor extends JComponent { + + WorldData currentData; + + + JSpinner width= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + JSpinner height= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + JSpinner playerStartPosX= new JSpinner(new SpinnerNumberModel(0, 0, 1, .1)); + JSpinner playerStartPosY= new JSpinner(new SpinnerNumberModel(0, 0, 1, .1)); + JSpinner noiseZoomBiome= new JSpinner(new SpinnerNumberModel(0, 0, 1000f, 1f)); + JSpinner tileSize= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + + JTextField biomesSprites = new JTextField(); + JSpinner maxRoadDistance = new JSpinner(new SpinnerNumberModel(0, 0, 100000f, 1f)); + TextListEdit biomesNames = new TextListEdit(); + + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + BiomeEdit edit=new BiomeEdit(); + JTabbedPane tabs =new JTabbedPane(); + static HashMap atlas=new HashMap<>(); + + public class BiomeDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof BiomeData)) + return label; + BiomeData biome=(BiomeData) value; + // Get the renderer component from parent class + + label.setText(biome.name); + if(!atlas.containsKey(biome.tilesetAtlas)) + atlas.put(biome.tilesetAtlas,new SwingAtlas(Config.instance().getFile(biome.tilesetAtlas))); + + SwingAtlas poiAtlas = atlas.get(biome.tilesetAtlas); + + if(poiAtlas.has(biome.tilesetName)) + label.setIcon(poiAtlas.get(biome.tilesetName)); + else + { + ImageIcon img=poiAtlas.getAny(); + if(img!=null) + label.setIcon(img); + } + return label; + } + } + public WorldEditor() { + list.setCellRenderer(new BiomeDataRenderer()); + BorderLayout layout = new BorderLayout(); + setLayout(layout); + add(tabs); + JPanel worldPanel=new JPanel(); + JPanel biomeData=new JPanel(); + tabs.addTab("BiomeData", biomeData); + tabs.addTab("WorldData", worldPanel); + + + JPanel worldData=new JPanel(); + worldData.setLayout(new GridLayout(9,2)) ; + + worldData.add(new JLabel("width:")); worldData.add(width); + worldData.add(new JLabel("height:")); worldData.add(height); + worldData.add(new JLabel("playerStartPosX:")); worldData.add(playerStartPosX); + worldData.add(new JLabel("playerStartPosY:")); worldData.add(playerStartPosY); + worldData.add(new JLabel("noiseZoomBiome:")); worldData.add(noiseZoomBiome); + worldData.add(new JLabel("tileSize:")); worldData.add(tileSize); + worldData.add(new JLabel("biomesSprites:")); worldData.add(biomesSprites); + worldData.add(new JLabel("maxRoadDistance:")); worldData.add(maxRoadDistance); + worldData.add(new JLabel("biomesNames:")); worldData.add(biomesNames); + + + worldPanel.setLayout(new BoxLayout(worldPanel,BoxLayout.Y_AXIS)); + worldPanel.add(worldData); + worldPanel.add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); + + + biomeData.setLayout(new GridLayout(1,2)) ; + biomeData.add(list); biomeData.add(edit); + + load(); + + JToolBar toolBar = new JToolBar("toolbar"); + add(toolBar, BorderLayout.PAGE_START); + JButton newButton=new JButton("save"); + newButton.addActionListener(e -> WorldEditor.this.save()); + toolBar.add(newButton); + newButton=new JButton("load"); + newButton.addActionListener(e -> WorldEditor.this.load()); + toolBar.add(newButton); + } + + void save() + { + Json json = new Json(JsonWriter.OutputType.json); + FileHandle handle = Config.instance().getFile(Paths.WORLD); + handle.writeString(json.prettyPrint(json.toJson(currentData,Array.class, WorldData.class)),false); + + } + void load() + { + model.clear(); + Json json = new Json(); + FileHandle handle = Config.instance().getFile(Paths.WORLD); + if (handle.exists()) + { + currentData=json.fromJson(WorldData.class, WorldData.class, handle); + } + update(); + } + + private void update() { + width.setValue(currentData.width); + height.setValue(currentData.height); + playerStartPosX.setValue(currentData.playerStartPosX); + playerStartPosY.setValue(currentData.playerStartPosY); + noiseZoomBiome.setValue(currentData.noiseZoomBiome); + tileSize.setValue(currentData.tileSize); + biomesSprites.setText(currentData.biomesSprites); + maxRoadDistance.setValue(currentData.maxRoadDistance); + biomesNames.setText(currentData.biomesNames); + + for(String path:currentData.biomesNames) + { + Json json = new Json(); + FileHandle handle = Config.instance().getFile(path); + if (handle.exists()) + { + BiomeData data=json.fromJson(BiomeData.class, BiomeData.class, handle); + model.addElement(data); + } + } + + } } diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java index 51176c3a8b4..3aa7fb92d8f 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java @@ -15,7 +15,6 @@ import java.util.Random; * contains the information for the biomes */ public class BiomeData implements Serializable { - private final Random rand = MyRandom.getRandom(); public float startPointX; public float startPointY; public float noiseWeight; @@ -35,6 +34,7 @@ public class BiomeData implements Serializable { private ArrayList enemyList; private ArrayList pointOfInterestList; + private final Random rand = MyRandom.getRandom(); public Color GetColor() { return Color.valueOf(color); } diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java index 1ccaee59ce8..19c6b39f72b 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java @@ -16,4 +16,16 @@ public class BiomeTerrainData { // factor for the noise resolution public float resolution; + public BiomeTerrainData() + { + + } + public BiomeTerrainData(BiomeTerrainData other) + { + spriteName=other.spriteName; + min=other.min; + max=other.max; + resolution=other.resolution; + } + } diff --git a/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java b/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java index 06e285a9d86..f2921e8d32a 100644 --- a/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java +++ b/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java @@ -42,4 +42,18 @@ public class PointOfInterestData { } return null; } + public PointOfInterestData() + { + + } + public PointOfInterestData(PointOfInterestData other) + { + name=other.name; + type=other.type; + count=other.count; + spriteAtlas=other.spriteAtlas; + sprite=other.sprite; + map=other.map; + radiusFactor=other.radiusFactor; + } } diff --git a/forge-gui-mobile/src/forge/adventure/data/WorldData.java b/forge-gui-mobile/src/forge/adventure/data/WorldData.java index 908c857fdba..d5be45f2bc8 100644 --- a/forge-gui-mobile/src/forge/adventure/data/WorldData.java +++ b/forge-gui-mobile/src/forge/adventure/data/WorldData.java @@ -17,19 +17,22 @@ import java.util.List; */ public class WorldData implements Serializable { - static Array allEnemies; public int width; public int height; public float playerStartPosX; public float playerStartPosY; public float noiseZoomBiome; public int tileSize; - public List biomesNames; public BiomeData roadTileset; public String biomesSprites; public float maxRoadDistance; + public List biomesNames; + + private BiomeSprites sprites; private List biomes; + + private static Array allEnemies; private static Array shopList; From 97b2fe505fcc40080d433a45bfb02a09e49824b7 Mon Sep 17 00:00:00 2001 From: Grimm Date: Thu, 28 Jul 2022 04:12:17 +0200 Subject: [PATCH 05/66] wavefunction collapse first integration --- .../src/main/java/forge/adventure/Main.java | 8 +- .../forge/adventure/editor/BiomeEdit.java | 11 +- .../adventure/editor/BiomeStructureEdit.java | 98 +++++++++++++ .../adventure/editor/BiomeTerrainEdit.java | 80 ++++++++++- .../adventure/editor/EditorMainWindow.java | 2 +- .../forge/adventure/editor/EnemyEdit.java | 2 - .../forge/adventure/editor/FloatSpinner.java | 19 +++ .../forge/adventure/editor/IntSpinner.java | 20 +++ .../adventure/editor/StructureEditor.java | 133 ++++++++++++++++++ .../forge/adventure/editor/SwingAtlas.java | 21 ++- .../adventure/editor/SwingAtlasPreview.java | 43 ++++-- .../adventure/editor/TerrainsEditor.java | 36 ++--- .../forge/adventure/editor/WorldEditor.java | 56 ++++++++ forge-gui-mobile/pom.xml | 5 + forge-gui-mobile/src/forge/Forge.java | 1 + .../src/forge/adventure/data/BiomeData.java | 1 + .../adventure/data/BiomeStructureData.java | 38 +++++ .../forge/adventure/scene/NewGameScene.java | 5 + .../src/forge/adventure/scene/StartScene.java | 9 ++ .../src/forge/adventure/stage/GameStage.java | 10 +- .../src/forge/adventure/stage/WorldStage.java | 14 +- .../forge/adventure/world/BiomeStructure.java | 114 +++++++++++++++ .../forge/adventure/world/BiomeTexture.java | 31 +++- .../src/forge/adventure/world/World.java | 74 +++++++--- .../src/forge/adventure/world/WorldSave.java | 2 + .../src/forge/screens/SplashScreen.java | 8 ++ .../res/adventure/Shandalar/world/green.json | 8 ++ .../Shandalar/world/tilesets/autotiles.png | Bin 30516 -> 43326 bytes .../Shandalar/world/tilesets/forest.atlas | 20 +++ .../Shandalar/world/tilesets/forest.png | Bin 0 -> 16786 bytes 30 files changed, 786 insertions(+), 83 deletions(-) create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java create mode 100644 forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java create mode 100644 forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/forest.png diff --git a/forge-adventure/src/main/java/forge/adventure/Main.java b/forge-adventure/src/main/java/forge/adventure/Main.java index dcac01e5c85..54809bbe61d 100644 --- a/forge-adventure/src/main/java/forge/adventure/Main.java +++ b/forge-adventure/src/main/java/forge/adventure/Main.java @@ -106,7 +106,13 @@ public class Main { } }); - + for(int i=0;i BiomeEdit.this.updateTerrain())); tilesetName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); @@ -81,6 +82,7 @@ public class BiomeEdit extends JComponent { currentData.tilesetAtlas = tilesetAtlas.edit.getText(); currentData.tilesetName = tilesetName.getName(); currentData.terrain = terrain.getBiomeTerrainData(); + currentData.structures = structures.getBiomeStructureData(); currentData.width = (Float) width.getValue(); currentData.height = (Float) height.getValue(); currentData.color = color.getText(); @@ -109,7 +111,8 @@ public class BiomeEdit extends JComponent { name.setText(currentData.name); tilesetAtlas.edit.setText( currentData.tilesetAtlas); tilesetName.setText(currentData.tilesetName); - terrain.setTerrains(currentData.terrain); + terrain.setTerrains(currentData); + structures.setStructures(currentData); width.setValue(currentData.width); height.setValue(currentData.height); color.setText(currentData.color); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java new file mode 100644 index 00000000000..2fd8bcfb592 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java @@ -0,0 +1,98 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; +import forge.adventure.data.BiomeStructureData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +public class BiomeStructureEdit extends JComponent { + SwingAtlasPreview preview=new SwingAtlasPreview(128); + private boolean updating=false; + BiomeStructureData currentData; + BiomeData currentBiomeData; + public JTextField structureAtlasPath=new JTextField(); + public FloatSpinner x= new FloatSpinner(); + public FloatSpinner y= new FloatSpinner(); + public FloatSpinner size= new FloatSpinner(); + public JCheckBox randomPosition=new JCheckBox(); + public JCheckBox collision=new JCheckBox(); + + public BiomeStructureEdit() + { + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(6,2)); + + center.add(new JLabel("structureAtlasPath:")); center.add(structureAtlasPath); + center.add(new JLabel("x:")); center.add(x); + center.add(new JLabel("y:")); center.add(y); + center.add(new JLabel("size:")); center.add(size); + center.add(new JLabel("randomPosition:")); center.add(randomPosition); + center.add(new JLabel("collision:")); center.add(collision); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(preview,BorderLayout.LINE_START); + add(center,BorderLayout.CENTER); + + structureAtlasPath.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureEdit.this.updateStructure())); + + + x.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + y.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + size.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + randomPosition.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + collision.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + refresh(); + } + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + structureAtlasPath.setText(currentData.structureAtlasPath); + x.setValue(currentData.x); + y.setValue(currentData.y); + size.setValue(currentData.size); + randomPosition.setSelected(currentData.randomPosition); + collision.setSelected(currentData.collision); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.structureAtlasPath); + updating=false; + } + public void updateStructure() + { + + if(currentData==null||updating) + return; + currentData.structureAtlasPath=structureAtlasPath.getText(); + + currentData.x= x.floatValue(); + currentData.y= y.floatValue(); + currentData.size= size.floatValue(); + currentData.randomPosition=randomPosition.isSelected(); + currentData.collision=collision.isSelected(); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.structureAtlasPath); + emitChanged(); + } + public void setCurrentStructure(BiomeStructureData biomeTerrainData, BiomeData data) { + currentData =biomeTerrainData; + currentBiomeData=data; + refresh(); + } + + public void addChangeListener(ChangeListener listener) { + listenerList.add(ChangeListener.class, listener); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java index 24791aa585d..8986a2e6701 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java @@ -1,14 +1,88 @@ package forge.adventure.editor; +import forge.adventure.data.BiomeData; import forge.adventure.data.BiomeTerrainData; import javax.swing.*; +import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import java.awt.*; public class BiomeTerrainEdit extends JComponent { - public void setCurrentTerrain(BiomeTerrainData biomeTerrainData) { - } - public void addChangeListener(ChangeListener listener) { + SwingAtlasPreview preview=new SwingAtlasPreview(128); + private boolean updating=false; + BiomeTerrainData currentData; + BiomeData currentBiomeData; + public JTextField spriteName=new JTextField(); + public JSpinner min= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner max= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner resolution= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public BiomeTerrainEdit() + { + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(4,2)); + + center.add(new JLabel("spriteName:")); center.add(spriteName); + center.add(new JLabel("min:")); center.add(min); + center.add(new JLabel("max:")); center.add(max); + center.add(new JLabel("resolution:")); center.add(resolution); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(preview,BorderLayout.LINE_START); + add(center,BorderLayout.CENTER); + + spriteName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeTerrainEdit.this.updateTerrain())); + + min.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + max.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + resolution.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + + + refresh(); + } + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + spriteName.setText(currentData.spriteName); + min.setValue(currentData.min); + max.setValue(currentData.max); + resolution.setValue(currentData.resolution); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.spriteName); + updating=false; + } + public void updateTerrain() + { + + if(currentData==null||updating) + return; + currentData.spriteName=spriteName.getText(); + currentData.min= (float) min.getValue(); + currentData.max= (float) max.getValue(); + currentData.resolution= (float) resolution.getValue(); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.spriteName); + emitChanged(); + } + public void setCurrentTerrain(BiomeTerrainData biomeTerrainData, BiomeData data) { + currentData =biomeTerrainData; + currentBiomeData=data; + refresh(); + } + + public void addChangeListener(ChangeListener listener) { + listenerList.add(ChangeListener.class, listener); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } } } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java index 50f0d877cc9..fdfe775d914 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java @@ -14,8 +14,8 @@ public class EditorMainWindow extends JFrame { BorderLayout layout=new BorderLayout(); setLayout(layout); add(tabs); - tabs.addTab("POI",new PointOfInterestEditor()); tabs.addTab("World",new WorldEditor()); + tabs.addTab("POI",new PointOfInterestEditor()); tabs.addTab("Items",new ItemsEditor()); tabs.addTab("Enemies",new EnemyEditor()); setVisible(true); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java index 399d7c88334..3ef2d72a92c 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java @@ -10,8 +10,6 @@ import java.awt.*; */ public class EnemyEdit extends JComponent { EnemyData currentData; - - JTextField nameField=new JTextField(); JTextField colorField=new JTextField(); JSpinner lifeFiled= new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java b/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java new file mode 100644 index 00000000000..7fad0e3bad3 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java @@ -0,0 +1,19 @@ +package forge.adventure.editor; + +import javax.swing.*; + +public class FloatSpinner extends JSpinner{ + + public FloatSpinner() + { + this( 0.f, 1f, 0.1f); + } + public FloatSpinner(float min,float max,float stepSize) + { + super(new SpinnerNumberModel(new Float(0.0f), new Float(min), new Float (max), new Float(stepSize))); + } + public float floatValue() + { + return ((Float)getValue()).floatValue(); + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java b/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java new file mode 100644 index 00000000000..132817d3891 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java @@ -0,0 +1,20 @@ +package forge.adventure.editor; + +import javax.swing.*; + + +public class IntSpinner extends JSpinner { + + public IntSpinner() + { + this( 0, 100, 1); + } + public IntSpinner(int min,int max,int stepSize) + { + super(new SpinnerNumberModel(new Integer(0), new Integer(min), new Integer (max), new Integer(stepSize))); + } + public int intValue() + { + return ((Integer)getValue()).intValue(); + } +} \ No newline at end of file diff --git a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java new file mode 100644 index 00000000000..1b301ebebd7 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java @@ -0,0 +1,133 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; +import forge.adventure.data.BiomeStructureData; +import forge.adventure.data.BiomeTerrainData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.ActionListener; + +/** + * Editor class to edit configuration, maybe moved or removed + */ +public class StructureEditor extends JComponent{ + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + BiomeStructureEdit edit=new BiomeStructureEdit(); + + BiomeData currentData; + + public class StructureDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof BiomeTerrainData)) + return label; + BiomeTerrainData structureData=(BiomeTerrainData) value; + StringBuilder builder=new StringBuilder(); + builder.append("Structure"); + builder.append(" "); + builder.append(structureData.spriteName); + label.setText(builder.toString()); + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + + public StructureEditor() + { + + list.setCellRenderer(new StructureDataRenderer()); + list.addListSelectionListener(e -> StructureEditor.this.updateEdit()); + addButton("add", e -> StructureEditor.this.addStructure()); + addButton("remove", e -> StructureEditor.this.remove()); + addButton("copy", e -> StructureEditor.this.copy()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(list, BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + + + edit.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + emitChanged(); + } + }); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + BiomeStructureData data=new BiomeStructureData(model.get(selected)); + model.add(model.size(),data); + } + + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrentStructure(model.get(selected),currentData); + } + + void addStructure() + { + BiomeStructureData data=new BiomeStructureData(); + model.add(model.size(),data); + } + void remove() + { + int selected=list.getSelectedIndex(); + if(selected<0) + return; + model.remove(selected); + } + public void setStructures(BiomeData data) { + + currentData=data; + model.clear(); + if(data==null||data.structures==null) + return; + for (int i=0;i> images=new HashMap<>(); public HashMap> getImages() { return images; } - public SwingAtlas(FileHandle path) + public SwingAtlas(FileHandle path,int imageSize) { + this.imageSize=imageSize; if(!path.exists()||!path.toString().endsWith(".atlas")) return; TextureAtlas.TextureAtlasData data=new TextureAtlas.TextureAtlasData(path,path.parent(),false); @@ -37,17 +39,28 @@ public class SwingAtlas { images.put(name,new ArrayList<>()); } ArrayList imageList=images.get(name); - try { + try + { imageList.add(spriteToImage(region)); - } catch (IOException e) { + } + catch (IOException e) + { e.printStackTrace(); } } } + public SwingAtlas(FileHandle path) + { + this(path,32); + } private ImageIcon spriteToImage(TextureAtlas.TextureAtlasData.Region sprite) throws IOException { BufferedImage img = ImageIO.read(sprite.page.textureFile.file()); - return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(32,32,SCALE_FAST)); + if(sprite.width== sprite.height) + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize,imageSize,SCALE_FAST)); + if(sprite.width>sprite.height) + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize, (int) (imageSize*(sprite.height/(float)sprite.width)),SCALE_FAST)); + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance((int) (imageSize*(sprite.width/(float)sprite.height)),imageSize,SCALE_FAST)); } public ImageIcon get(String name) { diff --git a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java index 3631e133a8c..63d08c62f24 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java @@ -13,11 +13,12 @@ import java.util.Map; * Editor class to edit configuration, maybe moved or removed */ public class SwingAtlasPreview extends Box { + int imageSize=32; private String sprite=""; + private String spriteName=""; Timer timer; public SwingAtlasPreview() { super(BoxLayout.Y_AXIS); - timer = new Timer(200, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { @@ -28,25 +29,51 @@ public class SwingAtlasPreview extends Box { } }); } + public SwingAtlasPreview(int size) { + this(); + imageSize=size; + } int counter=0; List>> labels=new ArrayList<>(); public void setSpritePath(String sprite) { - if(this.sprite==null||this.sprite.equals(sprite)) + setSpritePath(sprite,null); + } + public void setSpritePath(String sprite,String name) { + + if(this.sprite==null||name==null||sprite==null||(this.sprite.equals(sprite)&&(spriteName==null&&spriteName.equals(name)))) return; removeAll(); counter=0; labels.clear(); this.sprite=sprite; - SwingAtlas atlas=new SwingAtlas(Config.instance().getFile(sprite)); + this.spriteName=name; + SwingAtlas atlas=new SwingAtlas(Config.instance().getFile(sprite),imageSize); + int maxCount=0; for(Map.Entry> element:atlas.getImages().entrySet()) { - JLabel image=new JLabel(element.getValue().get(0)); - add(new JLabel(element.getKey())); - add(image); - labels.add(Pair.of(image, element.getValue())); + if(name==null||element.getKey().equals(name)) + { + JLabel image=new JLabel(element.getValue().get(0)); + if(maxCount0) - { - builder.append("-"); - builder.append(reward.count+reward.addMaxCount); - } + builder.append(terrainData.spriteName); label.setText(builder.toString()); return label; } @@ -58,7 +50,7 @@ public class TerrainsEditor extends JComponent{ list.setCellRenderer(new TerrainDataRenderer()); list.addListSelectionListener(e -> TerrainsEditor.this.updateEdit()); - addButton("add", e -> TerrainsEditor.this.addReward()); + addButton("add", e -> TerrainsEditor.this.addTerrain()); addButton("remove", e -> TerrainsEditor.this.remove()); addButton("copy", e -> TerrainsEditor.this.copy()); BorderLayout layout=new BorderLayout(); @@ -98,10 +90,10 @@ public class TerrainsEditor extends JComponent{ int selected=list.getSelectedIndex(); if(selected<0) return; - edit.setCurrentTerrain(model.get(selected)); + edit.setCurrentTerrain(model.get(selected),currentData); } - void addReward() + void addTerrain() { BiomeTerrainData data=new BiomeTerrainData(); model.add(model.size(),data); @@ -113,14 +105,16 @@ public class TerrainsEditor extends JComponent{ return; model.remove(selected); } - public void setTerrains(BiomeTerrainData[] terrain) { + public void setTerrains(BiomeData data) { + currentData=data; model.clear(); - if(terrain==null) + if(data==null||data.terrain==null) return; - for (int i=0;i WorldEditor.this.save()); toolBar.add(newButton); + newButton=new JButton("load"); newButton.addActionListener(e -> WorldEditor.this.load()); toolBar.add(newButton); + + toolBar.addSeparator(); + + newButton=new JButton("test map"); + newButton.addActionListener(e -> WorldEditor.this.test()); + toolBar.add(newButton); + } + + private void test() { + + String javaHome = System.getProperty("java.home"); + String javaBin = javaHome + File.separator + "bin" + File.separator + "java"; + String classpath = System.getProperty("java.class.path"); + String className = forge.adventure.Main.class.getName(); + + ArrayList command = new ArrayList<>(); + command.add(javaBin); + command.add("-cp"); + command.add(classpath); + command.add(className); + + command.add("testMap"); + + ProcessBuilder build= new ProcessBuilder(command); + build .redirectInput(ProcessBuilder.Redirect.INHERIT) + .redirectOutput(ProcessBuilder.Redirect.INHERIT) + .redirectError(ProcessBuilder.Redirect.INHERIT); + try { + Process process= build.start(); + } catch (IOException e) { + throw new RuntimeException(e); + } } void save() diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml index 0c4ef128e59..e34f7d42fa7 100644 --- a/forge-gui-mobile/pom.xml +++ b/forge-gui-mobile/pom.xml @@ -55,6 +55,11 @@ gdx-freetype 1.11.0 + + com.github.sjcasey21 + wavefunctioncollapse + 0.2.2 + diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 7da28d0c317..0cc6f9dabbc 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -123,6 +123,7 @@ public class Forge implements ApplicationListener { private static Cursor cursor0, cursor1, cursor2, cursorA0, cursorA1, cursorA2; public static boolean forcedEnglishonCJKMissing = false; public static boolean adventureLoaded = false; + public static boolean createNewAdventureMap = false; private static Localizer localizer; public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value, boolean androidOrientation, int totalRAM, boolean isTablet, int AndroidAPI, String AndroidRelease, String deviceName) { diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java index 3aa7fb92d8f..61a2b1a5193 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java @@ -30,6 +30,7 @@ public class BiomeData implements Serializable { public String[] spriteNames; public List enemies; public List pointsOfInterest; + public BiomeStructureData[] structures; private ArrayList enemyList; private ArrayList pointOfInterestList; diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java new file mode 100644 index 00000000000..50df63f6157 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java @@ -0,0 +1,38 @@ +package forge.adventure.data; + +import java.awt.image.BufferedImage; + +public class BiomeStructureData { + public int N = 3; + public float x; + public float y; + public float size; + public boolean randomPosition; + public boolean collision; + + public String structureAtlasPath; + public boolean periodicInput; + public float height; + public float width; + public int ground; + public int symmetry; + public boolean periodicOutput; + + public BiomeStructureData( ) + { + + } + public BiomeStructureData(BiomeStructureData biomeStructureData) { + this.structureAtlasPath=biomeStructureData.structureAtlasPath; + this.x=biomeStructureData.x; + this.y=biomeStructureData.y; + this.size=biomeStructureData.size; + this.randomPosition=biomeStructureData.randomPosition; + this.collision=biomeStructureData.collision; + } + + public BufferedImage sourceImage() { + + return null; + } +} diff --git a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java index 6f836cbe6ea..126b36cd98a 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java @@ -226,6 +226,11 @@ public class NewGameScene extends UIScene { public void enter() { updateAvatar(); Gdx.input.setInputProcessor(stage); //Start taking input from the ui + + if(Forge.createNewAdventureMap) + { + start(); + } } @Override diff --git a/forge-gui-mobile/src/forge/adventure/scene/StartScene.java b/forge-gui-mobile/src/forge/adventure/scene/StartScene.java index 7157a93e541..238af360f14 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/StartScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/StartScene.java @@ -7,9 +7,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.utils.Align; import forge.Forge; import forge.adventure.stage.GameHUD; +import forge.adventure.stage.GameStage; import forge.adventure.stage.MapStage; import forge.adventure.util.Config; import forge.adventure.util.Controls; +import forge.adventure.util.Current; import forge.adventure.world.WorldSave; import forge.screens.TransitionScreen; @@ -104,6 +106,13 @@ public class StartScene extends UIScene { } Gdx.input.setInputProcessor(stage); //Start taking input from the ui + + if(Forge.createNewAdventureMap) + { + this.NewGame(); + Current.setDebug(true); + GameStage.maximumScrollDistance=4f; + } } @Override diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java index d904c379224..daa2b3370f6 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java @@ -36,6 +36,8 @@ public abstract class GameStage extends Stage { private float touchY = -1; private final float timer = 0; private float animationTimeout = 0; + public static float maximumScrollDistance=1.5f; + public static float minimumScrollDistance=0.3f; public void startPause(float i) { startPause(i, null); @@ -222,10 +224,10 @@ public abstract class GameStage extends Stage { if (isPaused()) return true; camera.zoom += (amountY * 0.03); - if (camera.zoom < 0.3f) - camera.zoom = 0.3f; - if (camera.zoom > 1.5f) - camera.zoom = 1.5f; + if (camera.zoom < minimumScrollDistance) + camera.zoom = minimumScrollDistance; + if (camera.zoom > maximumScrollDistance) + camera.zoom = maximumScrollDistance; return super.scrolled(amountX, amountY); } diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java index c7e14a7f550..7fa6d0ce2f5 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java @@ -176,19 +176,7 @@ public class WorldStage extends GameStage implements SaveFileContent { public boolean isColliding(Rectangle boundingRect) { - World world = WorldSave.getCurrentSave().getWorld(); - int currentBiome = World.highestBiome(world.getBiome((int) boundingRect.getX() / world.getTileSize(), (int) boundingRect.getY() / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) (boundingRect.getX()+boundingRect.getWidth()) / world.getTileSize(), (int) boundingRect.getY() / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) (boundingRect.getX()+boundingRect.getWidth())/ world.getTileSize(), (int) (boundingRect.getY()+boundingRect.getHeight()) / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) boundingRect.getX() / world.getTileSize(), (int) (boundingRect.getY()+boundingRect.getHeight()) / world.getTileSize())); - - return (currentBiome==0); + return WorldSave.getCurrentSave().getWorld().collidingTile(boundingRect); } private void HandleMonsterSpawn(float delta) { diff --git a/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java new file mode 100644 index 00000000000..e991e52f183 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java @@ -0,0 +1,114 @@ +package forge.adventure.world; + +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.github.sjcasey21.wavefunctioncollapse.OverlappingModel; +import forge.adventure.data.BiomeStructureData; +import forge.adventure.util.Config; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + +public class BiomeStructure { + + private BiomeStructureData data; + long seed; + private int biomeWidth; + private int biomeHeight; + private int dataMap[][]; + boolean init=false; + private TextureAtlas structureAtlas; + public BiomeStructure(BiomeStructureData data,long seed,int width,int height) + { + this.data=data; + this.seed=seed; + this.biomeWidth = width; + this.biomeHeight = height; + } + public TextureAtlas atlas() { + if(structureAtlas==null) + { + structureAtlas = Config.instance().getAtlas(data.structureAtlasPath); + } + return structureAtlas; + } + public int structureObjectCount() { + int count=0; + for(TextureAtlas.AtlasRegion region:atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + count++; + } + } + return count; + } + + public int objectID(int x, int y) { + + if(!init) + { + init=true; + initialize(); + } + if(x>biomeWidth*data.width) + return -1; + if(y>biomeHeight*data.height) + return -1; + if(x colorIdMap=new HashMap<>(); + int counter=0; + for(TextureAtlas.AtlasRegion region:atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + String[] split= region.name.split("_"); + if(split.length<2) + continue; + int rgb=Integer.parseInt(split[1],16); + colorIdMap.put(rgb,counter); + counter++; + } + } + BufferedImage image=model.graphics(); + dataMap=new int[image.getWidth()][image.getHeight()]; + for(int x=0;x> images = new ArrayList<>(); ArrayList> smallImages = new ArrayList<>(); ArrayList> edgeImages = new ArrayList<>(); @@ -45,7 +46,6 @@ public class BiomeTexture implements Serializable { FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public void run() { - Pixmap completePicture = null; if (images != null) { for (ArrayList val : images) { @@ -79,22 +79,38 @@ public class BiomeTexture implements Serializable { edgeImages = new ArrayList<>(); ArrayList regions =new ArrayList<>(); + ArrayList source =new ArrayList<>(); regions.add(Config.instance().getAtlas(data.tilesetAtlas).findRegion(data.tilesetName)); + source.add(Config.instance().getAtlas(data.tilesetAtlas)); if(data.terrain!=null) { for(BiomeTerrainData terrain:data.terrain) { regions.add(Config.instance().getAtlas(data.tilesetAtlas).findRegion(terrain.spriteName)); + source.add(Config.instance().getAtlas(data.tilesetAtlas)); } } + if(data.structures!=null) + { + for(BiomeStructureData structureData:data.structures) + { + BiomeStructure structure=new BiomeStructure(structureData,0,0,0); + for(TextureAtlas.AtlasRegion region:structure.atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + regions.add(region); + source.add(structure.atlas()); + } + } + } + } + for (TextureAtlas.AtlasRegion region : regions) { ArrayList pics = new ArrayList<>(); ArrayList spics = new ArrayList<>(); - if (completePicture == null) { region.getTexture().getTextureData().prepare(); - completePicture = region.getTexture().getTextureData().consumePixmap(); - } - + Pixmap completePicture = region.getTexture().getTextureData().consumePixmap(); for (int y = 0; y < 4; y++) { for (int x = 0; x < 3; x++) { int px = region.getRegionX() + (x * tileSize); @@ -117,6 +133,7 @@ public class BiomeTexture implements Serializable { smallImages.add(spics); edgeImages.add(new IntMap<>()); + completePicture.dispose(); } } }); @@ -124,6 +141,8 @@ public class BiomeTexture implements Serializable { public Pixmap getPixmap(int biomeSubIndex) { if (biomeSubIndex >= edgeImages.size() || biomeSubIndex < 0) { + if(emptyPixmap==null) + emptyPixmap=new Pixmap(1, 1, Pixmap.Format.RGBA8888); return emptyPixmap; } return images.get(biomeSubIndex).get(BigPictures.Center.value); diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index a7ecf515a65..c450f067507 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -9,11 +9,7 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.Json; -import forge.adventure.data.BiomeData; -import forge.adventure.data.BiomeSpriteData; -import forge.adventure.data.BiomeTerrainData; -import forge.adventure.data.PointOfInterestData; -import forge.adventure.data.WorldData; +import forge.adventure.data.*; import forge.adventure.pointofintrest.PointOfInterest; import forge.adventure.pointofintrest.PointOfInterestMap; import forge.adventure.scene.Scene; @@ -24,10 +20,7 @@ import forge.adventure.util.SaveFileContent; import forge.adventure.util.SaveFileData; import org.apache.commons.lang3.tuple.Pair; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Random; +import java.util.*; /** * Class that will create the world from the configuration @@ -55,6 +48,26 @@ public class World implements Disposable, SaveFileContent { return (int) (Math.log(Long.highestOneBit(biome)) / Math.log(2)); } + public boolean collidingTile(Rectangle boundingRect) + { + Set> points=new HashSet<>(); + + int xLeft=(int) boundingRect.getX() / getTileSize(); + int yTop=(int) boundingRect.getY() / getTileSize(); + int xRight=(int) (boundingRect.getX()+boundingRect.getWidth()) / getTileSize(); + int yBottom= (int) (boundingRect.getY()+boundingRect.getHeight()) / getTileSize(); + + if(getBiome(xLeft,yTop)==0) + return true; + if(getBiome(xLeft,yBottom)==0) + return true; + if(getBiome(xRight,yBottom)==0) + return true; + if(getBiome(xRight,yTop)==0) + return true; + + return false; + } public void loadWorldData() { if(worldDataLoaded) return; @@ -85,6 +98,9 @@ public class World implements Disposable, SaveFileContent { biomeImage=saveFileData.readPixmap("biomeImage"); biomeMap=(long[][])saveFileData.readObject("biomeMap"); terrainMap=(int[][])saveFileData.readObject("terrainMap"); + + + width=saveFileData.readInt("width"); height=saveFileData.readInt("height"); mapObjectIds = new SpritesDataMap(getChunkSize(), this.data.tileSize, this.data.width / getChunkSize()); @@ -269,6 +285,7 @@ public class World implements Disposable, SaveFileContent { endX = width; endY = height; } + HashMap structureDataMap=new HashMap<>(); for (int x = beginX; x < endX; x++) { for (int y = beginY; y < endY; y++) { //value 0-1 based on noise @@ -288,16 +305,34 @@ public class World implements Disposable, SaveFileContent { pix.drawPixel(x, y); biomeMap[x][y] |= (1L << biomeIndex); int terrainCounter=1; - if(biome.terrain==null) - continue; - for(BiomeTerrainData terrain:biome.terrain) + if(biome.terrain!=null) { - float terrainNoise = ((float)noise.eval(x / (float) width * (noiseZoom*terrain.resolution), y / (float) height * (noiseZoom*terrain.resolution)) + 1) / 2; - if(terrainNoise>=terrain.min&&terrainNoise<=terrain.max) + for(BiomeTerrainData terrain:biome.terrain) { - terrainMap[x][y]=terrainCounter; + float terrainNoise = ((float)noise.eval(x / (float) width * (noiseZoom*terrain.resolution), y / (float) height * (noiseZoom*terrain.resolution)) + 1) / 2; + if(terrainNoise>=terrain.min&&terrainNoise<=terrain.max) + { + terrainMap[x][y]=terrainCounter; + } + terrainCounter++; + } + } + if(biome.structures!=null) + { + for(BiomeStructureData data:biome.structures) + { + BiomeStructure structure; + if(!structureDataMap.containsKey(data)) + { + structureDataMap.put(data,new BiomeStructure(data,seed,biomeWidth,biomeHeight)); + } + structure=structureDataMap.get(data); + int structureIndex=structure.objectID(x-biomeXStart,y-biomeYStart); + if(structureIndex>=0) + terrainMap[x][y]=terrainCounter+structureIndex; + + terrainCounter+=structure.structureObjectCount(); } - terrainCounter++; } } @@ -432,6 +467,9 @@ public class World implements Disposable, SaveFileContent { for (int y = (int) currentPoint.y - 1; y < currentPoint.y + 2; y++) { if(x<0||y<=0||x>=width||y>height)continue; biomeMap[x][height - y] |= (1L << biomeIndex); + terrainMap[x][height-y]=0; + + pix.drawPixel(x, height-y); } } @@ -465,7 +503,9 @@ public class World implements Disposable, SaveFileContent { if( (int)currentPoint.x<0|| (int)currentPoint.y<=0|| (int)currentPoint.x>=width|| (int)currentPoint.y>height)continue; biomeMap[(int) currentPoint.x][height - (int) currentPoint.y] |= (1L << biomeIndex); + terrainMap[(int) currentPoint.x][height - (int) currentPoint.y]=0; pix.drawPixel((int) currentPoint.x, height - (int) currentPoint.y); + } } @@ -482,6 +522,8 @@ public class World implements Disposable, SaveFileContent { BiomeSpriteData sprite = data.GetBiomeSprites().getSpriteData(name); double spriteNoise = (noise.eval(x / (double) width * noiseZoom*sprite.resolution, y / (double) invertedHeight * noiseZoom*sprite.resolution) + 1) / 2; if (spriteNoise >= sprite.startArea && spriteNoise <= sprite.endArea) { + if(terrainMap[x][invertedHeight]>biome.terrain.length) + continue; if (random.nextFloat() <= sprite.density) { String spriteKey = sprite.key(); int key; diff --git a/forge-gui-mobile/src/forge/adventure/world/WorldSave.java b/forge-gui-mobile/src/forge/adventure/world/WorldSave.java index 228f878d15f..a28af044f85 100644 --- a/forge-gui-mobile/src/forge/adventure/world/WorldSave.java +++ b/forge-gui-mobile/src/forge/adventure/world/WorldSave.java @@ -57,6 +57,8 @@ public class WorldSave { static public boolean load(int currentSlot) { String fileName = WorldSave.getSaveFile(currentSlot); + if(!new File(fileName).exists()) + return false; new File(getSaveDir()).mkdirs(); try { try(FileInputStream fos = new FileInputStream(fileName); diff --git a/forge-gui-mobile/src/forge/screens/SplashScreen.java b/forge-gui-mobile/src/forge/screens/SplashScreen.java index 504530999b8..5b9ffcb8e2b 100644 --- a/forge-gui-mobile/src/forge/screens/SplashScreen.java +++ b/forge-gui-mobile/src/forge/screens/SplashScreen.java @@ -265,6 +265,14 @@ public class SplashScreen extends FContainer { add(btnHome); btnAdventure.setBounds(btn_x, btn_y + height + padding / 2, btn_w, height); add(btnAdventure); + + if(Forge.createNewAdventureMap) + { + bgAnimation.progress = 1; + bgAnimation.openAdventure = true; + Forge.openAdventure(); + Forge.clearSplashScreen(); + } } } diff --git a/forge-gui/res/adventure/Shandalar/world/green.json b/forge-gui/res/adventure/Shandalar/world/green.json index bf0dca678ba..def5769876c 100644 --- a/forge-gui/res/adventure/Shandalar/world/green.json +++ b/forge-gui/res/adventure/Shandalar/world/green.json @@ -19,6 +19,14 @@ "resolution": 10 } ], + "structures":[ + { + "structureAtlasPath":"world/tilesets/forest.atlas", + "x": 0.5, + "y": 0.5, + "size": 0.3 + } + ], "width": 0.7, "height": 0.7, "color": "59a650", diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/autotiles.png b/forge-gui/res/adventure/Shandalar/world/tilesets/autotiles.png index 8c651dffb0897c7d0bfa57a3f936ebe3e38a04ec..c10104d2528f02593787acc2cf3f9c9e4be79fad 100644 GIT binary patch delta 12980 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 B5Iz6^ diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas new file mode 100644 index 00000000000..bb08300ae21 --- /dev/null +++ b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas @@ -0,0 +1,20 @@ + +forest.png +size: 96,64 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +Source + rotate: false + xy: 0, 0 + size: 16, 16 + orig: 0, 0 + offset: 0, 0 + index: 0 +structure_000000 + rotate: false + xy: 48, 0 + size: 48, 64 + orig: 0, 0 + offset: 0, 0 + index: 0 \ No newline at end of file diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png new file mode 100644 index 0000000000000000000000000000000000000000..cf8dd71e0c9d2cb2327c33398a99d087c459cf34 GIT binary patch literal 16786 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 literal 0 HcmV?d00001 From dc06bab33151f1a37a4c1fe4eec8dff221dc5b25 Mon Sep 17 00:00:00 2001 From: Grimm Date: Fri, 10 Jun 2022 23:25:45 +0200 Subject: [PATCH 06/66] AdventureEditor: added editors --- forge-adventure/pom.xml | 2 +- .../forge/adventure/editor/BiomeEdit.java | 122 ++++++++++++++ .../adventure/editor/BiomeTerrainEdit.java | 14 ++ .../java/forge/adventure/editor/ItemEdit.java | 3 +- .../adventure/editor/PointOfInterestEdit.java | 88 ++++++++++ .../editor/PointOfInterestEditor.java | 129 ++++++++++++++- .../forge/adventure/editor/RewardEdit.java | 114 ++----------- .../forge/adventure/editor/RewardsEditor.java | 31 +--- .../adventure/editor/TerrainsEditor.java | 138 ++++++++++++++++ .../forge/adventure/editor/TextListEdit.java | 7 + .../forge/adventure/editor/WorldEditor.java | 151 +++++++++++++++++- .../src/forge/adventure/data/BiomeData.java | 2 +- .../adventure/data/BiomeTerrainData.java | 12 ++ .../adventure/data/PointOfInterestData.java | 14 ++ .../src/forge/adventure/data/WorldData.java | 7 +- 15 files changed, 699 insertions(+), 135 deletions(-) create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java diff --git a/forge-adventure/pom.xml b/forge-adventure/pom.xml index d2bc0fcd175..4d81b150e02 100644 --- a/forge-adventure/pom.xml +++ b/forge-adventure/pom.xml @@ -17,7 +17,7 @@ - src + src/main/java ${project.basedir} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java new file mode 100644 index 00000000000..70c595437a9 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java @@ -0,0 +1,122 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; + +import javax.swing.*; +import java.awt.*; +import java.util.Arrays; + +public class BiomeEdit extends JComponent { + BiomeData currentData; + + public JSpinner startPointX= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner startPointY= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner noiseWeight= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner distWeight= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JTextField name=new JTextField(); + public FilePicker tilesetAtlas=new FilePicker(new String[]{"atlas"}); + public JTextField tilesetName=new JTextField(); + public JSpinner width= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner height= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JTextField color=new JTextField(); + public TextListEdit spriteNames =new TextListEdit(); + public TextListEdit enemies =new TextListEdit(); + public TextListEdit pointsOfInterest =new TextListEdit(); + + public TerrainsEditor terrain =new TerrainsEditor(); + + private boolean updating=false; + + public BiomeEdit() + { + + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(14,2)); + + center.add(new JLabel("startPointX:")); center.add(startPointX); + center.add(new JLabel("startPointY:")); center.add(startPointY); + center.add(new JLabel("noiseWeight:")); center.add(noiseWeight); + center.add(new JLabel("distWeight:")); center.add(distWeight); + center.add(new JLabel("name:")); center.add(name); + center.add(new JLabel("tilesetAtlas:")); center.add(tilesetAtlas); + center.add(new JLabel("tilesetName:")); center.add(tilesetName); + center.add(new JLabel("width:")); center.add(width); + center.add(new JLabel("height:")); center.add(height); + center.add(new JLabel("spriteNames:")); center.add(spriteNames); + center.add(new JLabel("enemies:")); center.add(enemies); + center.add(new JLabel("pointsOfInterest:")); center.add(pointsOfInterest); + center.add(new JLabel("color:")); center.add(color); + center.add(new JLabel("terrain:")); center.add(terrain); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(center,BorderLayout.PAGE_START); + add(terrain,BorderLayout.CENTER); + + name.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + tilesetName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + color.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + spriteNames.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + enemies.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + terrain.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + + + startPointX.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + startPointY.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + noiseWeight.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + distWeight.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + tilesetAtlas.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + width.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + height.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + refresh(); + } + + private void updateTerrain() { + if(currentData==null||updating) + return; + currentData.startPointX = (Float) startPointX.getValue(); + currentData.startPointY = (Float) startPointY.getValue(); + currentData.noiseWeight = (Float) noiseWeight.getValue(); + currentData.distWeight = (Float)distWeight.getValue(); + currentData.name = name.getText(); + currentData.tilesetAtlas = tilesetAtlas.edit.getText(); + currentData.tilesetName = tilesetName.getName(); + currentData.terrain = terrain.getBiomeTerrainData(); + currentData.width = (Float) width.getValue(); + currentData.height = (Float) height.getValue(); + currentData.color = color.getText(); + currentData.spriteNames = spriteNames.getList(); + currentData.enemies = Arrays.asList(enemies.getList()); + currentData.pointsOfInterest = Arrays.asList(pointsOfInterest.getList()); + } + + public void setCurrentBiome(BiomeData data) + { + currentData=data; + refresh(); + } + + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + startPointX.setValue(currentData.startPointX); + startPointY.setValue(currentData.startPointY); + noiseWeight.setValue(currentData.noiseWeight); + distWeight.setValue(currentData.distWeight); + name.setText(currentData.name); + tilesetAtlas.edit.setText( currentData.tilesetAtlas); + tilesetName.setText(currentData.tilesetName); + terrain.setTerrains(currentData.terrain); + width.setValue(currentData.width); + height.setValue(currentData.height); + color.setText(currentData.color); + spriteNames.setText(currentData.spriteNames); + enemies.setText(currentData.enemies); + color.setText(currentData.color); + pointsOfInterest.setText(currentData.pointsOfInterest); + updating=false; + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java new file mode 100644 index 00000000000..24791aa585d --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java @@ -0,0 +1,14 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeTerrainData; + +import javax.swing.*; +import javax.swing.event.ChangeListener; + +public class BiomeTerrainEdit extends JComponent { + public void setCurrentTerrain(BiomeTerrainData biomeTerrainData) { + } + public void addChangeListener(ChangeListener listener) { + + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java index 248bd275914..26f9f30923d 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java @@ -10,8 +10,6 @@ import java.awt.*; */ public class ItemEdit extends JComponent { ItemData currentData; - - JTextField nameField=new JTextField(); JTextField equipmentSlot=new JTextField(); JTextField iconName=new JTextField(); @@ -39,6 +37,7 @@ public class ItemEdit extends JComponent { add(parameters); add(effect); + add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); nameField.getDocument().addDocumentListener(new DocumentChangeListener(() -> ItemEdit.this.updateItem())); equipmentSlot.getDocument().addDocumentListener(new DocumentChangeListener(() -> ItemEdit.this.updateItem())); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java new file mode 100644 index 00000000000..045777feb94 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java @@ -0,0 +1,88 @@ +package forge.adventure.editor; + +import forge.adventure.data.PointOfInterestData; + +import javax.swing.*; +import java.awt.*; + +public class PointOfInterestEdit extends JComponent { + + PointOfInterestData currentData; + + + JTextField name = new JTextField(); + JTextField type = new JTextField(); + JSpinner count = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); + FilePicker spriteAtlas = new FilePicker(new String[]{"atlas"}); + JTextField sprite = new JTextField(); + FilePicker map = new FilePicker(new String[]{"tmx"}); + JSpinner radiusFactor= new JSpinner(new SpinnerNumberModel(0.0f, 0.0f, 2.0f, 0.1f)); + + + private boolean updating=false; + + public PointOfInterestEdit() + { + + setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); + JPanel parameters=new JPanel(); + parameters.setBorder(BorderFactory.createTitledBorder("Parameter")); + parameters.setLayout(new GridLayout(7,2)) ; + + parameters.add(new JLabel("Name:")); parameters.add(name); + parameters.add(new JLabel("Type:")); parameters.add(type); + parameters.add(new JLabel("Count:")); parameters.add(count); + parameters.add(new JLabel("Sprite atlas:")); parameters.add(spriteAtlas); + parameters.add(new JLabel("Sprite:")); parameters.add(sprite); + parameters.add(new JLabel("Map:")); parameters.add(map); + parameters.add(new JLabel("Radius factor:")); parameters.add(radiusFactor); + + add(parameters); + add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); + + name.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + type.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + count.addChangeListener(e -> PointOfInterestEdit.this.updateItem()); + spriteAtlas.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + sprite.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + map.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + radiusFactor.addChangeListener(e -> PointOfInterestEdit.this.updateItem()); + refresh(); + } + + private void updateItem() { + if(currentData==null||updating) + return; + currentData.name=name.getText(); + currentData.type= type.getText(); + currentData.count= ((Integer) count.getValue()).intValue(); + currentData.spriteAtlas=spriteAtlas.getEdit().getText(); + currentData.sprite=sprite.getText(); + currentData.map=map.getEdit().getText(); + currentData.radiusFactor=((Float) radiusFactor.getValue()).floatValue(); + } + + public void setCurrent(PointOfInterestData data) + { + currentData=data; + refresh(); + } + + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + name.setText(currentData.name); + type.setText(currentData.type); + count.setValue(currentData.count); + spriteAtlas.getEdit().setText(currentData.spriteAtlas); + sprite.setText(currentData.sprite); + map.getEdit().setText(currentData.map); + radiusFactor.setValue(currentData.radiusFactor); + + updating=false; + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java index 83ff548e68e..4fa4b0e9209 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java @@ -1,6 +1,131 @@ package forge.adventure.editor; -import java.awt.*; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter; +import forge.adventure.data.PointOfInterestData; +import forge.adventure.util.Config; +import forge.adventure.util.Paths; -public class PointOfInterestEditor extends Component { +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionListener; +import java.util.HashMap; + +public class PointOfInterestEditor extends JComponent { + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + PointOfInterestEdit edit=new PointOfInterestEdit(); + static HashMap atlas=new HashMap<>(); + + + + public class PointOfInterestRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof PointOfInterestData)) + return label; + PointOfInterestData poi=(PointOfInterestData) value; + // Get the renderer component from parent class + + label.setText(poi.name); + if(!atlas.containsKey(poi.spriteAtlas)) + atlas.put(poi.spriteAtlas,new SwingAtlas(Config.instance().getFile(poi.spriteAtlas))); + + SwingAtlas poiAtlas = atlas.get(poi.spriteAtlas); + + if(poiAtlas.has(poi.sprite)) + label.setIcon(poiAtlas.get(poi.sprite)); + else + { + ImageIcon img=poiAtlas.getAny(); + if(img!=null) + label.setIcon(img); + } + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + public PointOfInterestEditor() + { + + list.setCellRenderer(new PointOfInterestEditor.PointOfInterestRenderer()); + list.addListSelectionListener(e -> PointOfInterestEditor.this.updateEdit()); + addButton("add", e -> PointOfInterestEditor.this.addItem()); + addButton("remove", e -> PointOfInterestEditor.this.remove()); + addButton("copy", e -> PointOfInterestEditor.this.copy()); + addButton("load", e -> PointOfInterestEditor.this.load()); + addButton("save", e -> PointOfInterestEditor.this.save()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(new JScrollPane(list), BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + load(); + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + PointOfInterestData data=new PointOfInterestData(model.get(selected)); + model.add(model.size(),data); + } + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrent(model.get(selected)); + } + + void save() + { + Array allEnemies=new Array<>(); + for(int i=0;i allEnemies=new Array<>(); + Json json = new Json(); + FileHandle handle = Config.instance().getFile(Paths.POINTS_OF_INTEREST); + if (handle.exists()) + { + Array readEnemies=json.fromJson(Array.class, PointOfInterestData.class, handle); + allEnemies = readEnemies; + } + for (int i=0;i RewardEdit.this.updateReward())); + probability.addChangeListener(e -> RewardEdit.this.updateReward()); + count.addChangeListener(e -> RewardEdit.this.updateReward()); + addMaxCount.addChangeListener(e -> RewardEdit.this.updateReward()); + cardName.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + itemName.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + editions.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + colors.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + rarity.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + subTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + cardTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + superTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + manaCosts.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + keyWords.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + colorType.addActionListener((e -> RewardEdit.this.updateReward())); + cardText.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java index a2d6cc0f617..786128f6bad 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java @@ -5,10 +5,7 @@ import forge.adventure.data.RewardData; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import java.awt.*; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** @@ -59,30 +56,10 @@ public class RewardsEditor extends JComponent{ { list.setCellRenderer(new RewardDataRenderer()); - list.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - RewardsEditor.this.updateEdit(); - } - }); - addButton("add", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.addReward(); - } - }); - addButton("remove", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.remove(); - } - }); - addButton("copy", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.copy(); - } - }); + list.addListSelectionListener(e -> RewardsEditor.this.updateEdit()); + addButton("add", e -> RewardsEditor.this.addReward()); + addButton("remove", e -> RewardsEditor.this.remove()); + addButton("copy", e -> RewardsEditor.this.copy()); BorderLayout layout=new BorderLayout(); setLayout(layout); add(list, BorderLayout.LINE_START); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java new file mode 100644 index 00000000000..69a7578a13d --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java @@ -0,0 +1,138 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeTerrainData; +import forge.adventure.data.RewardData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.ActionListener; + +/** + * Editor class to edit configuration, maybe moved or removed + */ +public class TerrainsEditor extends JComponent{ + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + BiomeTerrainEdit edit=new BiomeTerrainEdit(); + + + + public class TerrainDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof RewardData)) + return label; + RewardData reward=(RewardData) value; + StringBuilder builder=new StringBuilder(); + if(reward.type==null||reward.type.isEmpty()) + builder.append("Terrain"); + else + builder.append(reward.type); + builder.append(" "); + builder.append(reward.count); + if(reward.addMaxCount>0) + { + builder.append("-"); + builder.append(reward.count+reward.addMaxCount); + } + label.setText(builder.toString()); + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + + public TerrainsEditor() + { + + list.setCellRenderer(new TerrainDataRenderer()); + list.addListSelectionListener(e -> TerrainsEditor.this.updateEdit()); + addButton("add", e -> TerrainsEditor.this.addReward()); + addButton("remove", e -> TerrainsEditor.this.remove()); + addButton("copy", e -> TerrainsEditor.this.copy()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(list, BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + + + edit.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + emitChanged(); + } + }); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + BiomeTerrainData data=new BiomeTerrainData(model.get(selected)); + model.add(model.size(),data); + } + + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrentTerrain(model.get(selected)); + } + + void addReward() + { + BiomeTerrainData data=new BiomeTerrainData(); + model.add(model.size(),data); + } + void remove() + { + int selected=list.getSelectedIndex(); + if(selected<0) + return; + model.remove(selected); + } + public void setTerrains(BiomeTerrainData[] terrain) { + + model.clear(); + if(terrain==null) + return; + for (int i=0;i itemNames) { + if(itemNames==null) + edit.setText(""); + else + edit.setText(String.join(";",itemNames)); + } public void setText(String[] itemName) { if(itemName==null) edit.setText(""); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java index 221ac5d64ae..e1fde6621e9 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java @@ -1,6 +1,153 @@ package forge.adventure.editor; -import java.awt.*; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter; +import forge.adventure.data.BiomeData; +import forge.adventure.data.WorldData; +import forge.adventure.util.Config; +import forge.adventure.util.Paths; -public class WorldEditor extends Component { +import javax.swing.*; +import java.awt.*; +import java.util.HashMap; + +public class WorldEditor extends JComponent { + + WorldData currentData; + + + JSpinner width= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + JSpinner height= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + JSpinner playerStartPosX= new JSpinner(new SpinnerNumberModel(0, 0, 1, .1)); + JSpinner playerStartPosY= new JSpinner(new SpinnerNumberModel(0, 0, 1, .1)); + JSpinner noiseZoomBiome= new JSpinner(new SpinnerNumberModel(0, 0, 1000f, 1f)); + JSpinner tileSize= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + + JTextField biomesSprites = new JTextField(); + JSpinner maxRoadDistance = new JSpinner(new SpinnerNumberModel(0, 0, 100000f, 1f)); + TextListEdit biomesNames = new TextListEdit(); + + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + BiomeEdit edit=new BiomeEdit(); + JTabbedPane tabs =new JTabbedPane(); + static HashMap atlas=new HashMap<>(); + + public class BiomeDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof BiomeData)) + return label; + BiomeData biome=(BiomeData) value; + // Get the renderer component from parent class + + label.setText(biome.name); + if(!atlas.containsKey(biome.tilesetAtlas)) + atlas.put(biome.tilesetAtlas,new SwingAtlas(Config.instance().getFile(biome.tilesetAtlas))); + + SwingAtlas poiAtlas = atlas.get(biome.tilesetAtlas); + + if(poiAtlas.has(biome.tilesetName)) + label.setIcon(poiAtlas.get(biome.tilesetName)); + else + { + ImageIcon img=poiAtlas.getAny(); + if(img!=null) + label.setIcon(img); + } + return label; + } + } + public WorldEditor() { + list.setCellRenderer(new BiomeDataRenderer()); + BorderLayout layout = new BorderLayout(); + setLayout(layout); + add(tabs); + JPanel worldPanel=new JPanel(); + JPanel biomeData=new JPanel(); + tabs.addTab("BiomeData", biomeData); + tabs.addTab("WorldData", worldPanel); + + + JPanel worldData=new JPanel(); + worldData.setLayout(new GridLayout(9,2)) ; + + worldData.add(new JLabel("width:")); worldData.add(width); + worldData.add(new JLabel("height:")); worldData.add(height); + worldData.add(new JLabel("playerStartPosX:")); worldData.add(playerStartPosX); + worldData.add(new JLabel("playerStartPosY:")); worldData.add(playerStartPosY); + worldData.add(new JLabel("noiseZoomBiome:")); worldData.add(noiseZoomBiome); + worldData.add(new JLabel("tileSize:")); worldData.add(tileSize); + worldData.add(new JLabel("biomesSprites:")); worldData.add(biomesSprites); + worldData.add(new JLabel("maxRoadDistance:")); worldData.add(maxRoadDistance); + worldData.add(new JLabel("biomesNames:")); worldData.add(biomesNames); + + + worldPanel.setLayout(new BoxLayout(worldPanel,BoxLayout.Y_AXIS)); + worldPanel.add(worldData); + worldPanel.add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); + + + biomeData.setLayout(new GridLayout(1,2)) ; + biomeData.add(list); biomeData.add(edit); + + load(); + + JToolBar toolBar = new JToolBar("toolbar"); + add(toolBar, BorderLayout.PAGE_START); + JButton newButton=new JButton("save"); + newButton.addActionListener(e -> WorldEditor.this.save()); + toolBar.add(newButton); + newButton=new JButton("load"); + newButton.addActionListener(e -> WorldEditor.this.load()); + toolBar.add(newButton); + } + + void save() + { + Json json = new Json(JsonWriter.OutputType.json); + FileHandle handle = Config.instance().getFile(Paths.WORLD); + handle.writeString(json.prettyPrint(json.toJson(currentData,Array.class, WorldData.class)),false); + + } + void load() + { + model.clear(); + Json json = new Json(); + FileHandle handle = Config.instance().getFile(Paths.WORLD); + if (handle.exists()) + { + currentData=json.fromJson(WorldData.class, WorldData.class, handle); + } + update(); + } + + private void update() { + width.setValue(currentData.width); + height.setValue(currentData.height); + playerStartPosX.setValue(currentData.playerStartPosX); + playerStartPosY.setValue(currentData.playerStartPosY); + noiseZoomBiome.setValue(currentData.noiseZoomBiome); + tileSize.setValue(currentData.tileSize); + biomesSprites.setText(currentData.biomesSprites); + maxRoadDistance.setValue(currentData.maxRoadDistance); + biomesNames.setText(currentData.biomesNames); + + for(String path:currentData.biomesNames) + { + Json json = new Json(); + FileHandle handle = Config.instance().getFile(path); + if (handle.exists()) + { + BiomeData data=json.fromJson(BiomeData.class, BiomeData.class, handle); + model.addElement(data); + } + } + + } } diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java index 51176c3a8b4..3aa7fb92d8f 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java @@ -15,7 +15,6 @@ import java.util.Random; * contains the information for the biomes */ public class BiomeData implements Serializable { - private final Random rand = MyRandom.getRandom(); public float startPointX; public float startPointY; public float noiseWeight; @@ -35,6 +34,7 @@ public class BiomeData implements Serializable { private ArrayList enemyList; private ArrayList pointOfInterestList; + private final Random rand = MyRandom.getRandom(); public Color GetColor() { return Color.valueOf(color); } diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java index 1ccaee59ce8..19c6b39f72b 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java @@ -16,4 +16,16 @@ public class BiomeTerrainData { // factor for the noise resolution public float resolution; + public BiomeTerrainData() + { + + } + public BiomeTerrainData(BiomeTerrainData other) + { + spriteName=other.spriteName; + min=other.min; + max=other.max; + resolution=other.resolution; + } + } diff --git a/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java b/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java index 06e285a9d86..f2921e8d32a 100644 --- a/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java +++ b/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java @@ -42,4 +42,18 @@ public class PointOfInterestData { } return null; } + public PointOfInterestData() + { + + } + public PointOfInterestData(PointOfInterestData other) + { + name=other.name; + type=other.type; + count=other.count; + spriteAtlas=other.spriteAtlas; + sprite=other.sprite; + map=other.map; + radiusFactor=other.radiusFactor; + } } diff --git a/forge-gui-mobile/src/forge/adventure/data/WorldData.java b/forge-gui-mobile/src/forge/adventure/data/WorldData.java index 908c857fdba..d5be45f2bc8 100644 --- a/forge-gui-mobile/src/forge/adventure/data/WorldData.java +++ b/forge-gui-mobile/src/forge/adventure/data/WorldData.java @@ -17,19 +17,22 @@ import java.util.List; */ public class WorldData implements Serializable { - static Array allEnemies; public int width; public int height; public float playerStartPosX; public float playerStartPosY; public float noiseZoomBiome; public int tileSize; - public List biomesNames; public BiomeData roadTileset; public String biomesSprites; public float maxRoadDistance; + public List biomesNames; + + private BiomeSprites sprites; private List biomes; + + private static Array allEnemies; private static Array shopList; From 42ae9dda063e53f1cbc8257aedb75271ab349eb4 Mon Sep 17 00:00:00 2001 From: Grimm Date: Thu, 28 Jul 2022 04:12:17 +0200 Subject: [PATCH 07/66] wavefunction collapse first integration --- .../src/main/java/forge/adventure/Main.java | 8 +- .../forge/adventure/editor/BiomeEdit.java | 11 +- .../adventure/editor/BiomeStructureEdit.java | 98 +++++++++++++ .../adventure/editor/BiomeTerrainEdit.java | 80 ++++++++++- .../adventure/editor/EditorMainWindow.java | 2 +- .../forge/adventure/editor/EnemyEdit.java | 2 - .../forge/adventure/editor/FloatSpinner.java | 19 +++ .../forge/adventure/editor/IntSpinner.java | 20 +++ .../adventure/editor/StructureEditor.java | 133 ++++++++++++++++++ .../forge/adventure/editor/SwingAtlas.java | 21 ++- .../adventure/editor/SwingAtlasPreview.java | 43 ++++-- .../adventure/editor/TerrainsEditor.java | 36 ++--- .../forge/adventure/editor/WorldEditor.java | 56 ++++++++ forge-gui-mobile/pom.xml | 5 + forge-gui-mobile/src/forge/Forge.java | 1 + .../src/forge/adventure/data/BiomeData.java | 1 + .../adventure/data/BiomeStructureData.java | 38 +++++ .../forge/adventure/scene/NewGameScene.java | 5 + .../src/forge/adventure/scene/StartScene.java | 9 ++ .../src/forge/adventure/stage/GameStage.java | 10 +- .../src/forge/adventure/stage/WorldStage.java | 14 +- .../forge/adventure/world/BiomeStructure.java | 114 +++++++++++++++ .../forge/adventure/world/BiomeTexture.java | 31 +++- .../src/forge/adventure/world/World.java | 74 +++++++--- .../src/forge/adventure/world/WorldSave.java | 2 + .../src/forge/screens/SplashScreen.java | 8 ++ .../res/adventure/Shandalar/world/green.json | 8 ++ .../Shandalar/world/tilesets/autotiles.png | Bin 30516 -> 43326 bytes .../Shandalar/world/tilesets/forest.atlas | 20 +++ .../Shandalar/world/tilesets/forest.png | Bin 0 -> 16786 bytes 30 files changed, 786 insertions(+), 83 deletions(-) create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java create mode 100644 forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java create mode 100644 forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/forest.png diff --git a/forge-adventure/src/main/java/forge/adventure/Main.java b/forge-adventure/src/main/java/forge/adventure/Main.java index dcac01e5c85..54809bbe61d 100644 --- a/forge-adventure/src/main/java/forge/adventure/Main.java +++ b/forge-adventure/src/main/java/forge/adventure/Main.java @@ -106,7 +106,13 @@ public class Main { } }); - + for(int i=0;i BiomeEdit.this.updateTerrain())); tilesetName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); @@ -81,6 +82,7 @@ public class BiomeEdit extends JComponent { currentData.tilesetAtlas = tilesetAtlas.edit.getText(); currentData.tilesetName = tilesetName.getName(); currentData.terrain = terrain.getBiomeTerrainData(); + currentData.structures = structures.getBiomeStructureData(); currentData.width = (Float) width.getValue(); currentData.height = (Float) height.getValue(); currentData.color = color.getText(); @@ -109,7 +111,8 @@ public class BiomeEdit extends JComponent { name.setText(currentData.name); tilesetAtlas.edit.setText( currentData.tilesetAtlas); tilesetName.setText(currentData.tilesetName); - terrain.setTerrains(currentData.terrain); + terrain.setTerrains(currentData); + structures.setStructures(currentData); width.setValue(currentData.width); height.setValue(currentData.height); color.setText(currentData.color); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java new file mode 100644 index 00000000000..2fd8bcfb592 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java @@ -0,0 +1,98 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; +import forge.adventure.data.BiomeStructureData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +public class BiomeStructureEdit extends JComponent { + SwingAtlasPreview preview=new SwingAtlasPreview(128); + private boolean updating=false; + BiomeStructureData currentData; + BiomeData currentBiomeData; + public JTextField structureAtlasPath=new JTextField(); + public FloatSpinner x= new FloatSpinner(); + public FloatSpinner y= new FloatSpinner(); + public FloatSpinner size= new FloatSpinner(); + public JCheckBox randomPosition=new JCheckBox(); + public JCheckBox collision=new JCheckBox(); + + public BiomeStructureEdit() + { + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(6,2)); + + center.add(new JLabel("structureAtlasPath:")); center.add(structureAtlasPath); + center.add(new JLabel("x:")); center.add(x); + center.add(new JLabel("y:")); center.add(y); + center.add(new JLabel("size:")); center.add(size); + center.add(new JLabel("randomPosition:")); center.add(randomPosition); + center.add(new JLabel("collision:")); center.add(collision); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(preview,BorderLayout.LINE_START); + add(center,BorderLayout.CENTER); + + structureAtlasPath.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureEdit.this.updateStructure())); + + + x.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + y.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + size.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + randomPosition.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + collision.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + refresh(); + } + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + structureAtlasPath.setText(currentData.structureAtlasPath); + x.setValue(currentData.x); + y.setValue(currentData.y); + size.setValue(currentData.size); + randomPosition.setSelected(currentData.randomPosition); + collision.setSelected(currentData.collision); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.structureAtlasPath); + updating=false; + } + public void updateStructure() + { + + if(currentData==null||updating) + return; + currentData.structureAtlasPath=structureAtlasPath.getText(); + + currentData.x= x.floatValue(); + currentData.y= y.floatValue(); + currentData.size= size.floatValue(); + currentData.randomPosition=randomPosition.isSelected(); + currentData.collision=collision.isSelected(); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.structureAtlasPath); + emitChanged(); + } + public void setCurrentStructure(BiomeStructureData biomeTerrainData, BiomeData data) { + currentData =biomeTerrainData; + currentBiomeData=data; + refresh(); + } + + public void addChangeListener(ChangeListener listener) { + listenerList.add(ChangeListener.class, listener); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java index 24791aa585d..8986a2e6701 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java @@ -1,14 +1,88 @@ package forge.adventure.editor; +import forge.adventure.data.BiomeData; import forge.adventure.data.BiomeTerrainData; import javax.swing.*; +import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import java.awt.*; public class BiomeTerrainEdit extends JComponent { - public void setCurrentTerrain(BiomeTerrainData biomeTerrainData) { - } - public void addChangeListener(ChangeListener listener) { + SwingAtlasPreview preview=new SwingAtlasPreview(128); + private boolean updating=false; + BiomeTerrainData currentData; + BiomeData currentBiomeData; + public JTextField spriteName=new JTextField(); + public JSpinner min= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner max= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner resolution= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public BiomeTerrainEdit() + { + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(4,2)); + + center.add(new JLabel("spriteName:")); center.add(spriteName); + center.add(new JLabel("min:")); center.add(min); + center.add(new JLabel("max:")); center.add(max); + center.add(new JLabel("resolution:")); center.add(resolution); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(preview,BorderLayout.LINE_START); + add(center,BorderLayout.CENTER); + + spriteName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeTerrainEdit.this.updateTerrain())); + + min.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + max.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + resolution.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + + + refresh(); + } + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + spriteName.setText(currentData.spriteName); + min.setValue(currentData.min); + max.setValue(currentData.max); + resolution.setValue(currentData.resolution); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.spriteName); + updating=false; + } + public void updateTerrain() + { + + if(currentData==null||updating) + return; + currentData.spriteName=spriteName.getText(); + currentData.min= (float) min.getValue(); + currentData.max= (float) max.getValue(); + currentData.resolution= (float) resolution.getValue(); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.spriteName); + emitChanged(); + } + public void setCurrentTerrain(BiomeTerrainData biomeTerrainData, BiomeData data) { + currentData =biomeTerrainData; + currentBiomeData=data; + refresh(); + } + + public void addChangeListener(ChangeListener listener) { + listenerList.add(ChangeListener.class, listener); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } } } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java index 50f0d877cc9..fdfe775d914 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java @@ -14,8 +14,8 @@ public class EditorMainWindow extends JFrame { BorderLayout layout=new BorderLayout(); setLayout(layout); add(tabs); - tabs.addTab("POI",new PointOfInterestEditor()); tabs.addTab("World",new WorldEditor()); + tabs.addTab("POI",new PointOfInterestEditor()); tabs.addTab("Items",new ItemsEditor()); tabs.addTab("Enemies",new EnemyEditor()); setVisible(true); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java index 399d7c88334..3ef2d72a92c 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java @@ -10,8 +10,6 @@ import java.awt.*; */ public class EnemyEdit extends JComponent { EnemyData currentData; - - JTextField nameField=new JTextField(); JTextField colorField=new JTextField(); JSpinner lifeFiled= new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java b/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java new file mode 100644 index 00000000000..7fad0e3bad3 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java @@ -0,0 +1,19 @@ +package forge.adventure.editor; + +import javax.swing.*; + +public class FloatSpinner extends JSpinner{ + + public FloatSpinner() + { + this( 0.f, 1f, 0.1f); + } + public FloatSpinner(float min,float max,float stepSize) + { + super(new SpinnerNumberModel(new Float(0.0f), new Float(min), new Float (max), new Float(stepSize))); + } + public float floatValue() + { + return ((Float)getValue()).floatValue(); + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java b/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java new file mode 100644 index 00000000000..132817d3891 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java @@ -0,0 +1,20 @@ +package forge.adventure.editor; + +import javax.swing.*; + + +public class IntSpinner extends JSpinner { + + public IntSpinner() + { + this( 0, 100, 1); + } + public IntSpinner(int min,int max,int stepSize) + { + super(new SpinnerNumberModel(new Integer(0), new Integer(min), new Integer (max), new Integer(stepSize))); + } + public int intValue() + { + return ((Integer)getValue()).intValue(); + } +} \ No newline at end of file diff --git a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java new file mode 100644 index 00000000000..1b301ebebd7 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java @@ -0,0 +1,133 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; +import forge.adventure.data.BiomeStructureData; +import forge.adventure.data.BiomeTerrainData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.ActionListener; + +/** + * Editor class to edit configuration, maybe moved or removed + */ +public class StructureEditor extends JComponent{ + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + BiomeStructureEdit edit=new BiomeStructureEdit(); + + BiomeData currentData; + + public class StructureDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof BiomeTerrainData)) + return label; + BiomeTerrainData structureData=(BiomeTerrainData) value; + StringBuilder builder=new StringBuilder(); + builder.append("Structure"); + builder.append(" "); + builder.append(structureData.spriteName); + label.setText(builder.toString()); + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + + public StructureEditor() + { + + list.setCellRenderer(new StructureDataRenderer()); + list.addListSelectionListener(e -> StructureEditor.this.updateEdit()); + addButton("add", e -> StructureEditor.this.addStructure()); + addButton("remove", e -> StructureEditor.this.remove()); + addButton("copy", e -> StructureEditor.this.copy()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(list, BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + + + edit.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + emitChanged(); + } + }); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + BiomeStructureData data=new BiomeStructureData(model.get(selected)); + model.add(model.size(),data); + } + + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrentStructure(model.get(selected),currentData); + } + + void addStructure() + { + BiomeStructureData data=new BiomeStructureData(); + model.add(model.size(),data); + } + void remove() + { + int selected=list.getSelectedIndex(); + if(selected<0) + return; + model.remove(selected); + } + public void setStructures(BiomeData data) { + + currentData=data; + model.clear(); + if(data==null||data.structures==null) + return; + for (int i=0;i> images=new HashMap<>(); public HashMap> getImages() { return images; } - public SwingAtlas(FileHandle path) + public SwingAtlas(FileHandle path,int imageSize) { + this.imageSize=imageSize; if(!path.exists()||!path.toString().endsWith(".atlas")) return; TextureAtlas.TextureAtlasData data=new TextureAtlas.TextureAtlasData(path,path.parent(),false); @@ -37,17 +39,28 @@ public class SwingAtlas { images.put(name,new ArrayList<>()); } ArrayList imageList=images.get(name); - try { + try + { imageList.add(spriteToImage(region)); - } catch (IOException e) { + } + catch (IOException e) + { e.printStackTrace(); } } } + public SwingAtlas(FileHandle path) + { + this(path,32); + } private ImageIcon spriteToImage(TextureAtlas.TextureAtlasData.Region sprite) throws IOException { BufferedImage img = ImageIO.read(sprite.page.textureFile.file()); - return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(32,32,SCALE_FAST)); + if(sprite.width== sprite.height) + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize,imageSize,SCALE_FAST)); + if(sprite.width>sprite.height) + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize, (int) (imageSize*(sprite.height/(float)sprite.width)),SCALE_FAST)); + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance((int) (imageSize*(sprite.width/(float)sprite.height)),imageSize,SCALE_FAST)); } public ImageIcon get(String name) { diff --git a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java index 3631e133a8c..63d08c62f24 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java @@ -13,11 +13,12 @@ import java.util.Map; * Editor class to edit configuration, maybe moved or removed */ public class SwingAtlasPreview extends Box { + int imageSize=32; private String sprite=""; + private String spriteName=""; Timer timer; public SwingAtlasPreview() { super(BoxLayout.Y_AXIS); - timer = new Timer(200, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { @@ -28,25 +29,51 @@ public class SwingAtlasPreview extends Box { } }); } + public SwingAtlasPreview(int size) { + this(); + imageSize=size; + } int counter=0; List>> labels=new ArrayList<>(); public void setSpritePath(String sprite) { - if(this.sprite==null||this.sprite.equals(sprite)) + setSpritePath(sprite,null); + } + public void setSpritePath(String sprite,String name) { + + if(this.sprite==null||name==null||sprite==null||(this.sprite.equals(sprite)&&(spriteName==null&&spriteName.equals(name)))) return; removeAll(); counter=0; labels.clear(); this.sprite=sprite; - SwingAtlas atlas=new SwingAtlas(Config.instance().getFile(sprite)); + this.spriteName=name; + SwingAtlas atlas=new SwingAtlas(Config.instance().getFile(sprite),imageSize); + int maxCount=0; for(Map.Entry> element:atlas.getImages().entrySet()) { - JLabel image=new JLabel(element.getValue().get(0)); - add(new JLabel(element.getKey())); - add(image); - labels.add(Pair.of(image, element.getValue())); + if(name==null||element.getKey().equals(name)) + { + JLabel image=new JLabel(element.getValue().get(0)); + if(maxCount0) - { - builder.append("-"); - builder.append(reward.count+reward.addMaxCount); - } + builder.append(terrainData.spriteName); label.setText(builder.toString()); return label; } @@ -58,7 +50,7 @@ public class TerrainsEditor extends JComponent{ list.setCellRenderer(new TerrainDataRenderer()); list.addListSelectionListener(e -> TerrainsEditor.this.updateEdit()); - addButton("add", e -> TerrainsEditor.this.addReward()); + addButton("add", e -> TerrainsEditor.this.addTerrain()); addButton("remove", e -> TerrainsEditor.this.remove()); addButton("copy", e -> TerrainsEditor.this.copy()); BorderLayout layout=new BorderLayout(); @@ -98,10 +90,10 @@ public class TerrainsEditor extends JComponent{ int selected=list.getSelectedIndex(); if(selected<0) return; - edit.setCurrentTerrain(model.get(selected)); + edit.setCurrentTerrain(model.get(selected),currentData); } - void addReward() + void addTerrain() { BiomeTerrainData data=new BiomeTerrainData(); model.add(model.size(),data); @@ -113,14 +105,16 @@ public class TerrainsEditor extends JComponent{ return; model.remove(selected); } - public void setTerrains(BiomeTerrainData[] terrain) { + public void setTerrains(BiomeData data) { + currentData=data; model.clear(); - if(terrain==null) + if(data==null||data.terrain==null) return; - for (int i=0;i WorldEditor.this.save()); toolBar.add(newButton); + newButton=new JButton("load"); newButton.addActionListener(e -> WorldEditor.this.load()); toolBar.add(newButton); + + toolBar.addSeparator(); + + newButton=new JButton("test map"); + newButton.addActionListener(e -> WorldEditor.this.test()); + toolBar.add(newButton); + } + + private void test() { + + String javaHome = System.getProperty("java.home"); + String javaBin = javaHome + File.separator + "bin" + File.separator + "java"; + String classpath = System.getProperty("java.class.path"); + String className = forge.adventure.Main.class.getName(); + + ArrayList command = new ArrayList<>(); + command.add(javaBin); + command.add("-cp"); + command.add(classpath); + command.add(className); + + command.add("testMap"); + + ProcessBuilder build= new ProcessBuilder(command); + build .redirectInput(ProcessBuilder.Redirect.INHERIT) + .redirectOutput(ProcessBuilder.Redirect.INHERIT) + .redirectError(ProcessBuilder.Redirect.INHERIT); + try { + Process process= build.start(); + } catch (IOException e) { + throw new RuntimeException(e); + } } void save() diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml index 0c4ef128e59..e34f7d42fa7 100644 --- a/forge-gui-mobile/pom.xml +++ b/forge-gui-mobile/pom.xml @@ -55,6 +55,11 @@ gdx-freetype 1.11.0 + + com.github.sjcasey21 + wavefunctioncollapse + 0.2.2 + diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 7da28d0c317..0cc6f9dabbc 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -123,6 +123,7 @@ public class Forge implements ApplicationListener { private static Cursor cursor0, cursor1, cursor2, cursorA0, cursorA1, cursorA2; public static boolean forcedEnglishonCJKMissing = false; public static boolean adventureLoaded = false; + public static boolean createNewAdventureMap = false; private static Localizer localizer; public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value, boolean androidOrientation, int totalRAM, boolean isTablet, int AndroidAPI, String AndroidRelease, String deviceName) { diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java index 3aa7fb92d8f..61a2b1a5193 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java @@ -30,6 +30,7 @@ public class BiomeData implements Serializable { public String[] spriteNames; public List enemies; public List pointsOfInterest; + public BiomeStructureData[] structures; private ArrayList enemyList; private ArrayList pointOfInterestList; diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java new file mode 100644 index 00000000000..50df63f6157 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java @@ -0,0 +1,38 @@ +package forge.adventure.data; + +import java.awt.image.BufferedImage; + +public class BiomeStructureData { + public int N = 3; + public float x; + public float y; + public float size; + public boolean randomPosition; + public boolean collision; + + public String structureAtlasPath; + public boolean periodicInput; + public float height; + public float width; + public int ground; + public int symmetry; + public boolean periodicOutput; + + public BiomeStructureData( ) + { + + } + public BiomeStructureData(BiomeStructureData biomeStructureData) { + this.structureAtlasPath=biomeStructureData.structureAtlasPath; + this.x=biomeStructureData.x; + this.y=biomeStructureData.y; + this.size=biomeStructureData.size; + this.randomPosition=biomeStructureData.randomPosition; + this.collision=biomeStructureData.collision; + } + + public BufferedImage sourceImage() { + + return null; + } +} diff --git a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java index 6f836cbe6ea..126b36cd98a 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java @@ -226,6 +226,11 @@ public class NewGameScene extends UIScene { public void enter() { updateAvatar(); Gdx.input.setInputProcessor(stage); //Start taking input from the ui + + if(Forge.createNewAdventureMap) + { + start(); + } } @Override diff --git a/forge-gui-mobile/src/forge/adventure/scene/StartScene.java b/forge-gui-mobile/src/forge/adventure/scene/StartScene.java index 7157a93e541..238af360f14 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/StartScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/StartScene.java @@ -7,9 +7,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.utils.Align; import forge.Forge; import forge.adventure.stage.GameHUD; +import forge.adventure.stage.GameStage; import forge.adventure.stage.MapStage; import forge.adventure.util.Config; import forge.adventure.util.Controls; +import forge.adventure.util.Current; import forge.adventure.world.WorldSave; import forge.screens.TransitionScreen; @@ -104,6 +106,13 @@ public class StartScene extends UIScene { } Gdx.input.setInputProcessor(stage); //Start taking input from the ui + + if(Forge.createNewAdventureMap) + { + this.NewGame(); + Current.setDebug(true); + GameStage.maximumScrollDistance=4f; + } } @Override diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java index d904c379224..daa2b3370f6 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java @@ -36,6 +36,8 @@ public abstract class GameStage extends Stage { private float touchY = -1; private final float timer = 0; private float animationTimeout = 0; + public static float maximumScrollDistance=1.5f; + public static float minimumScrollDistance=0.3f; public void startPause(float i) { startPause(i, null); @@ -222,10 +224,10 @@ public abstract class GameStage extends Stage { if (isPaused()) return true; camera.zoom += (amountY * 0.03); - if (camera.zoom < 0.3f) - camera.zoom = 0.3f; - if (camera.zoom > 1.5f) - camera.zoom = 1.5f; + if (camera.zoom < minimumScrollDistance) + camera.zoom = minimumScrollDistance; + if (camera.zoom > maximumScrollDistance) + camera.zoom = maximumScrollDistance; return super.scrolled(amountX, amountY); } diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java index c7e14a7f550..7fa6d0ce2f5 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java @@ -176,19 +176,7 @@ public class WorldStage extends GameStage implements SaveFileContent { public boolean isColliding(Rectangle boundingRect) { - World world = WorldSave.getCurrentSave().getWorld(); - int currentBiome = World.highestBiome(world.getBiome((int) boundingRect.getX() / world.getTileSize(), (int) boundingRect.getY() / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) (boundingRect.getX()+boundingRect.getWidth()) / world.getTileSize(), (int) boundingRect.getY() / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) (boundingRect.getX()+boundingRect.getWidth())/ world.getTileSize(), (int) (boundingRect.getY()+boundingRect.getHeight()) / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) boundingRect.getX() / world.getTileSize(), (int) (boundingRect.getY()+boundingRect.getHeight()) / world.getTileSize())); - - return (currentBiome==0); + return WorldSave.getCurrentSave().getWorld().collidingTile(boundingRect); } private void HandleMonsterSpawn(float delta) { diff --git a/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java new file mode 100644 index 00000000000..e991e52f183 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java @@ -0,0 +1,114 @@ +package forge.adventure.world; + +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.github.sjcasey21.wavefunctioncollapse.OverlappingModel; +import forge.adventure.data.BiomeStructureData; +import forge.adventure.util.Config; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + +public class BiomeStructure { + + private BiomeStructureData data; + long seed; + private int biomeWidth; + private int biomeHeight; + private int dataMap[][]; + boolean init=false; + private TextureAtlas structureAtlas; + public BiomeStructure(BiomeStructureData data,long seed,int width,int height) + { + this.data=data; + this.seed=seed; + this.biomeWidth = width; + this.biomeHeight = height; + } + public TextureAtlas atlas() { + if(structureAtlas==null) + { + structureAtlas = Config.instance().getAtlas(data.structureAtlasPath); + } + return structureAtlas; + } + public int structureObjectCount() { + int count=0; + for(TextureAtlas.AtlasRegion region:atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + count++; + } + } + return count; + } + + public int objectID(int x, int y) { + + if(!init) + { + init=true; + initialize(); + } + if(x>biomeWidth*data.width) + return -1; + if(y>biomeHeight*data.height) + return -1; + if(x colorIdMap=new HashMap<>(); + int counter=0; + for(TextureAtlas.AtlasRegion region:atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + String[] split= region.name.split("_"); + if(split.length<2) + continue; + int rgb=Integer.parseInt(split[1],16); + colorIdMap.put(rgb,counter); + counter++; + } + } + BufferedImage image=model.graphics(); + dataMap=new int[image.getWidth()][image.getHeight()]; + for(int x=0;x> images = new ArrayList<>(); ArrayList> smallImages = new ArrayList<>(); ArrayList> edgeImages = new ArrayList<>(); @@ -45,7 +46,6 @@ public class BiomeTexture implements Serializable { FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public void run() { - Pixmap completePicture = null; if (images != null) { for (ArrayList val : images) { @@ -79,22 +79,38 @@ public class BiomeTexture implements Serializable { edgeImages = new ArrayList<>(); ArrayList regions =new ArrayList<>(); + ArrayList source =new ArrayList<>(); regions.add(Config.instance().getAtlas(data.tilesetAtlas).findRegion(data.tilesetName)); + source.add(Config.instance().getAtlas(data.tilesetAtlas)); if(data.terrain!=null) { for(BiomeTerrainData terrain:data.terrain) { regions.add(Config.instance().getAtlas(data.tilesetAtlas).findRegion(terrain.spriteName)); + source.add(Config.instance().getAtlas(data.tilesetAtlas)); } } + if(data.structures!=null) + { + for(BiomeStructureData structureData:data.structures) + { + BiomeStructure structure=new BiomeStructure(structureData,0,0,0); + for(TextureAtlas.AtlasRegion region:structure.atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + regions.add(region); + source.add(structure.atlas()); + } + } + } + } + for (TextureAtlas.AtlasRegion region : regions) { ArrayList pics = new ArrayList<>(); ArrayList spics = new ArrayList<>(); - if (completePicture == null) { region.getTexture().getTextureData().prepare(); - completePicture = region.getTexture().getTextureData().consumePixmap(); - } - + Pixmap completePicture = region.getTexture().getTextureData().consumePixmap(); for (int y = 0; y < 4; y++) { for (int x = 0; x < 3; x++) { int px = region.getRegionX() + (x * tileSize); @@ -117,6 +133,7 @@ public class BiomeTexture implements Serializable { smallImages.add(spics); edgeImages.add(new IntMap<>()); + completePicture.dispose(); } } }); @@ -124,6 +141,8 @@ public class BiomeTexture implements Serializable { public Pixmap getPixmap(int biomeSubIndex) { if (biomeSubIndex >= edgeImages.size() || biomeSubIndex < 0) { + if(emptyPixmap==null) + emptyPixmap=new Pixmap(1, 1, Pixmap.Format.RGBA8888); return emptyPixmap; } return images.get(biomeSubIndex).get(BigPictures.Center.value); diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index a7ecf515a65..c450f067507 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -9,11 +9,7 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.Json; -import forge.adventure.data.BiomeData; -import forge.adventure.data.BiomeSpriteData; -import forge.adventure.data.BiomeTerrainData; -import forge.adventure.data.PointOfInterestData; -import forge.adventure.data.WorldData; +import forge.adventure.data.*; import forge.adventure.pointofintrest.PointOfInterest; import forge.adventure.pointofintrest.PointOfInterestMap; import forge.adventure.scene.Scene; @@ -24,10 +20,7 @@ import forge.adventure.util.SaveFileContent; import forge.adventure.util.SaveFileData; import org.apache.commons.lang3.tuple.Pair; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Random; +import java.util.*; /** * Class that will create the world from the configuration @@ -55,6 +48,26 @@ public class World implements Disposable, SaveFileContent { return (int) (Math.log(Long.highestOneBit(biome)) / Math.log(2)); } + public boolean collidingTile(Rectangle boundingRect) + { + Set> points=new HashSet<>(); + + int xLeft=(int) boundingRect.getX() / getTileSize(); + int yTop=(int) boundingRect.getY() / getTileSize(); + int xRight=(int) (boundingRect.getX()+boundingRect.getWidth()) / getTileSize(); + int yBottom= (int) (boundingRect.getY()+boundingRect.getHeight()) / getTileSize(); + + if(getBiome(xLeft,yTop)==0) + return true; + if(getBiome(xLeft,yBottom)==0) + return true; + if(getBiome(xRight,yBottom)==0) + return true; + if(getBiome(xRight,yTop)==0) + return true; + + return false; + } public void loadWorldData() { if(worldDataLoaded) return; @@ -85,6 +98,9 @@ public class World implements Disposable, SaveFileContent { biomeImage=saveFileData.readPixmap("biomeImage"); biomeMap=(long[][])saveFileData.readObject("biomeMap"); terrainMap=(int[][])saveFileData.readObject("terrainMap"); + + + width=saveFileData.readInt("width"); height=saveFileData.readInt("height"); mapObjectIds = new SpritesDataMap(getChunkSize(), this.data.tileSize, this.data.width / getChunkSize()); @@ -269,6 +285,7 @@ public class World implements Disposable, SaveFileContent { endX = width; endY = height; } + HashMap structureDataMap=new HashMap<>(); for (int x = beginX; x < endX; x++) { for (int y = beginY; y < endY; y++) { //value 0-1 based on noise @@ -288,16 +305,34 @@ public class World implements Disposable, SaveFileContent { pix.drawPixel(x, y); biomeMap[x][y] |= (1L << biomeIndex); int terrainCounter=1; - if(biome.terrain==null) - continue; - for(BiomeTerrainData terrain:biome.terrain) + if(biome.terrain!=null) { - float terrainNoise = ((float)noise.eval(x / (float) width * (noiseZoom*terrain.resolution), y / (float) height * (noiseZoom*terrain.resolution)) + 1) / 2; - if(terrainNoise>=terrain.min&&terrainNoise<=terrain.max) + for(BiomeTerrainData terrain:biome.terrain) { - terrainMap[x][y]=terrainCounter; + float terrainNoise = ((float)noise.eval(x / (float) width * (noiseZoom*terrain.resolution), y / (float) height * (noiseZoom*terrain.resolution)) + 1) / 2; + if(terrainNoise>=terrain.min&&terrainNoise<=terrain.max) + { + terrainMap[x][y]=terrainCounter; + } + terrainCounter++; + } + } + if(biome.structures!=null) + { + for(BiomeStructureData data:biome.structures) + { + BiomeStructure structure; + if(!structureDataMap.containsKey(data)) + { + structureDataMap.put(data,new BiomeStructure(data,seed,biomeWidth,biomeHeight)); + } + structure=structureDataMap.get(data); + int structureIndex=structure.objectID(x-biomeXStart,y-biomeYStart); + if(structureIndex>=0) + terrainMap[x][y]=terrainCounter+structureIndex; + + terrainCounter+=structure.structureObjectCount(); } - terrainCounter++; } } @@ -432,6 +467,9 @@ public class World implements Disposable, SaveFileContent { for (int y = (int) currentPoint.y - 1; y < currentPoint.y + 2; y++) { if(x<0||y<=0||x>=width||y>height)continue; biomeMap[x][height - y] |= (1L << biomeIndex); + terrainMap[x][height-y]=0; + + pix.drawPixel(x, height-y); } } @@ -465,7 +503,9 @@ public class World implements Disposable, SaveFileContent { if( (int)currentPoint.x<0|| (int)currentPoint.y<=0|| (int)currentPoint.x>=width|| (int)currentPoint.y>height)continue; biomeMap[(int) currentPoint.x][height - (int) currentPoint.y] |= (1L << biomeIndex); + terrainMap[(int) currentPoint.x][height - (int) currentPoint.y]=0; pix.drawPixel((int) currentPoint.x, height - (int) currentPoint.y); + } } @@ -482,6 +522,8 @@ public class World implements Disposable, SaveFileContent { BiomeSpriteData sprite = data.GetBiomeSprites().getSpriteData(name); double spriteNoise = (noise.eval(x / (double) width * noiseZoom*sprite.resolution, y / (double) invertedHeight * noiseZoom*sprite.resolution) + 1) / 2; if (spriteNoise >= sprite.startArea && spriteNoise <= sprite.endArea) { + if(terrainMap[x][invertedHeight]>biome.terrain.length) + continue; if (random.nextFloat() <= sprite.density) { String spriteKey = sprite.key(); int key; diff --git a/forge-gui-mobile/src/forge/adventure/world/WorldSave.java b/forge-gui-mobile/src/forge/adventure/world/WorldSave.java index 228f878d15f..a28af044f85 100644 --- a/forge-gui-mobile/src/forge/adventure/world/WorldSave.java +++ b/forge-gui-mobile/src/forge/adventure/world/WorldSave.java @@ -57,6 +57,8 @@ public class WorldSave { static public boolean load(int currentSlot) { String fileName = WorldSave.getSaveFile(currentSlot); + if(!new File(fileName).exists()) + return false; new File(getSaveDir()).mkdirs(); try { try(FileInputStream fos = new FileInputStream(fileName); diff --git a/forge-gui-mobile/src/forge/screens/SplashScreen.java b/forge-gui-mobile/src/forge/screens/SplashScreen.java index 504530999b8..5b9ffcb8e2b 100644 --- a/forge-gui-mobile/src/forge/screens/SplashScreen.java +++ b/forge-gui-mobile/src/forge/screens/SplashScreen.java @@ -265,6 +265,14 @@ public class SplashScreen extends FContainer { add(btnHome); btnAdventure.setBounds(btn_x, btn_y + height + padding / 2, btn_w, height); add(btnAdventure); + + if(Forge.createNewAdventureMap) + { + bgAnimation.progress = 1; + bgAnimation.openAdventure = true; + Forge.openAdventure(); + Forge.clearSplashScreen(); + } } } diff --git a/forge-gui/res/adventure/Shandalar/world/green.json b/forge-gui/res/adventure/Shandalar/world/green.json index bf0dca678ba..def5769876c 100644 --- a/forge-gui/res/adventure/Shandalar/world/green.json +++ b/forge-gui/res/adventure/Shandalar/world/green.json @@ -19,6 +19,14 @@ "resolution": 10 } ], + "structures":[ + { + "structureAtlasPath":"world/tilesets/forest.atlas", + "x": 0.5, + "y": 0.5, + "size": 0.3 + } + ], "width": 0.7, "height": 0.7, "color": "59a650", diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/autotiles.png b/forge-gui/res/adventure/Shandalar/world/tilesets/autotiles.png index 8c651dffb0897c7d0bfa57a3f936ebe3e38a04ec..c10104d2528f02593787acc2cf3f9c9e4be79fad 100644 GIT binary patch delta 12980 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 B5Iz6^ diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas new file mode 100644 index 00000000000..bb08300ae21 --- /dev/null +++ b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas @@ -0,0 +1,20 @@ + +forest.png +size: 96,64 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +Source + rotate: false + xy: 0, 0 + size: 16, 16 + orig: 0, 0 + offset: 0, 0 + index: 0 +structure_000000 + rotate: false + xy: 48, 0 + size: 48, 64 + orig: 0, 0 + offset: 0, 0 + index: 0 \ No newline at end of file diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png new file mode 100644 index 0000000000000000000000000000000000000000..cf8dd71e0c9d2cb2327c33398a99d087c459cf34 GIT binary patch literal 16786 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 literal 0 HcmV?d00001 From 95fba3d0cbfd9a6df93ad83c2ab1fa59d301cfd0 Mon Sep 17 00:00:00 2001 From: Grimm Date: Tue, 2 Aug 2022 17:59:30 +0200 Subject: [PATCH 08/66] WaveFunctionCollapse editor --- .../src/main/java/forge/adventure/Main.java | 6 +- .../forge/adventure/editor/BiomeEdit.java | 4 +- .../BiomeStructureDataMappingEditor.java | 169 ++++++++++++++++++ .../adventure/editor/BiomeStructureEdit.java | 67 +++++-- .../adventure/editor/BiomeTerrainEdit.java | 5 +- .../adventure/editor/EditorMainWindow.java | 3 +- .../adventure/editor/StructureEditor.java | 62 +++++-- .../adventure/editor/SwingAtlasPreview.java | 2 +- .../forge/adventure/editor/WorldEditor.java | 34 ++-- forge-gui-mobile/src/forge/Forge.java | 2 + .../adventure/data/BiomeStructureData.java | 46 ++++- .../src/forge/adventure/data/WorldData.java | 15 +- .../forge/adventure/world/BiomeStructure.java | 65 ++++--- .../forge/adventure/world/BiomeTexture.java | 11 +- .../src/forge/adventure/world/World.java | 11 +- forge-gui/pom.xml | 6 + .../res/adventure/Shandalar/world/green.json | 12 +- .../Shandalar/world/tilesets/forest.png | Bin 16786 -> 0 bytes .../Shandalar/world/tilesets/forestSource.png | Bin 0 -> 8939 bytes .../{forest.atlas => structures.atlas} | 11 +- .../Shandalar/world/tilesets/structures.png | Bin 0 -> 10426 bytes 21 files changed, 417 insertions(+), 114 deletions(-) create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java delete mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/forest.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/forestSource.png rename forge-gui/res/adventure/Shandalar/world/tilesets/{forest.atlas => structures.atlas} (56%) create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/structures.png diff --git a/forge-adventure/src/main/java/forge/adventure/Main.java b/forge-adventure/src/main/java/forge/adventure/Main.java index 54809bbe61d..f5940d643a2 100644 --- a/forge-adventure/src/main/java/forge/adventure/Main.java +++ b/forge-adventure/src/main/java/forge/adventure/Main.java @@ -2,11 +2,7 @@ package forge.adventure; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application; -import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration; -import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Clipboard; -import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window; -import com.badlogic.gdx.backends.lwjgl3.Lwjgl3WindowListener; +import com.badlogic.gdx.backends.lwjgl3.*; import com.badlogic.gdx.graphics.glutils.HdpiMode; import forge.Forge; import forge.adventure.util.Config; diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java index 569de3a09dc..cbf244b4a7e 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java @@ -46,8 +46,8 @@ public class BiomeEdit extends JComponent { center.add(new JLabel("enemies:")); center.add(enemies); center.add(new JLabel("pointsOfInterest:")); center.add(pointsOfInterest); center.add(new JLabel("color:")); center.add(color); - center.add(new JLabel("terrain/structures:")); - BorderLayout layout=new BorderLayout(); + center.add(new JLabel("terrain/structures:"));center.add(new JLabel("")); + BoxLayout layout=new BoxLayout(this, BoxLayout.Y_AXIS); setLayout(layout); add(center,BorderLayout.NORTH); add(terrain,BorderLayout.CENTER); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java new file mode 100644 index 00000000000..4b92f6d91cb --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java @@ -0,0 +1,169 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeStructureData; +import forge.adventure.util.Config; +import forge.adventure.world.BiomeStructure; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionListener; + +public class BiomeStructureDataMappingEditor extends JComponent { + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + BiomeStructureDataMappingEdit edit=new BiomeStructureDataMappingEdit(); + private BiomeStructureData data; + + public void setCurrent(BiomeStructureData data) { + this.data=data; + model.clear(); + for(int i=0;data.mappingInfo!=null&&i BiomeStructureDataMappingEditor.this.updateEdit()); + addButton("add", e -> BiomeStructureDataMappingEditor.this.add()); + addButton("remove", e -> BiomeStructureDataMappingEditor.this.remove()); + addButton("copy", e -> BiomeStructureDataMappingEditor.this.copy()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(new JScrollPane(list), BorderLayout.WEST); + add(toolBar, BorderLayout.NORTH); + add(edit,BorderLayout.CENTER); + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + BiomeStructureData.BiomeStructureDataMapping data=new BiomeStructureData.BiomeStructureDataMapping(model.get(selected)); + model.add(model.size(),data); + } + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrent(model.get(selected)); + } + + void add() + { + BiomeStructureData.BiomeStructureDataMapping data=new BiomeStructureData.BiomeStructureDataMapping(); + data.name="Structure "+model.getSize(); + model.add(model.size(),data); + } + void remove() + { + int selected=list.getSelectedIndex(); + if(selected<0) + return; + model.remove(selected); + } + + private class BiomeStructureDataMappingEdit extends JComponent{ + BiomeStructureData.BiomeStructureDataMapping currentData; + + + public JTextField name=new JTextField(); + public JTextField color=new JTextField(); + public JCheckBox collision=new JCheckBox(); + private boolean updating=false; + + public BiomeStructureDataMappingEdit() + { + + setLayout(new GridLayout(3,2)); + + add(new JLabel("name:")); add(name); + add(new JLabel("color:")); add(color); + add(new JLabel("collision:")); add(collision); + + name.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureDataMappingEdit.this.update())); + color.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureDataMappingEdit.this.update())); + collision.addChangeListener(e -> BiomeStructureDataMappingEdit.this.update()); + refresh(); + } + + private void update() { + if(currentData==null||updating) + return; + currentData.name = name.getText(); + currentData.color = color.getText(); + currentData.collision = collision.isSelected(); + } + + public void setCurrent(BiomeStructureData.BiomeStructureDataMapping data) + { + currentData=data; + refresh(); + } + + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + name.setText(currentData.name); + color.setText(currentData.color); + collision.setSelected(currentData.collision); + updating=false; + } + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java index 2fd8bcfb592..b6dc2875dfb 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java @@ -7,43 +7,61 @@ import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; +import java.awt.image.BufferedImage; public class BiomeStructureEdit extends JComponent { - SwingAtlasPreview preview=new SwingAtlasPreview(128); private boolean updating=false; BiomeStructureData currentData; BiomeData currentBiomeData; public JTextField structureAtlasPath=new JTextField(); public FloatSpinner x= new FloatSpinner(); public FloatSpinner y= new FloatSpinner(); - public FloatSpinner size= new FloatSpinner(); + public FloatSpinner width= new FloatSpinner(); + public FloatSpinner height= new FloatSpinner(); public JCheckBox randomPosition=new JCheckBox(); - public JCheckBox collision=new JCheckBox(); - + public IntSpinner N= new IntSpinner(); + public JTextField sourcePath= new JTextField(); + public JCheckBox periodicInput= new JCheckBox(); + public IntSpinner ground= new IntSpinner(); + public IntSpinner symmetry= new IntSpinner(); + public JCheckBox periodicOutput= new JCheckBox(); + public BiomeStructureDataMappingEditor data=new BiomeStructureDataMappingEditor(); public BiomeStructureEdit() { JComponent center=new JComponent() { }; - center.setLayout(new GridLayout(6,2)); + center.setLayout(new GridLayout(11,2)); center.add(new JLabel("structureAtlasPath:")); center.add(structureAtlasPath); center.add(new JLabel("x:")); center.add(x); center.add(new JLabel("y:")); center.add(y); - center.add(new JLabel("size:")); center.add(size); - center.add(new JLabel("randomPosition:")); center.add(randomPosition); - center.add(new JLabel("collision:")); center.add(collision); + center.add(new JLabel("width:")); center.add(width); + center.add(new JLabel("height:")); center.add(height); + center.add(new JLabel("N:")); center.add(N); + center.add(new JLabel("sourcePath:")); center.add(sourcePath); + center.add(new JLabel("periodicInput:")); center.add(periodicInput); + center.add(new JLabel("ground:")); center.add(ground); + center.add(new JLabel("symmetry:")); center.add(symmetry); + center.add(new JLabel("periodicOutput:")); center.add(periodicOutput); BorderLayout layout=new BorderLayout(); setLayout(layout); - add(preview,BorderLayout.LINE_START); add(center,BorderLayout.CENTER); + add(data,BorderLayout.SOUTH); structureAtlasPath.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureEdit.this.updateStructure())); x.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); y.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); - size.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + width.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + height.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); randomPosition.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); - collision.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + + N.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + sourcePath.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureEdit.this.updateStructure())); + periodicInput.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + ground.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + symmetry.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + periodicOutput.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); refresh(); } private void refresh() { @@ -56,10 +74,17 @@ public class BiomeStructureEdit extends JComponent { structureAtlasPath.setText(currentData.structureAtlasPath); x.setValue(currentData.x); y.setValue(currentData.y); - size.setValue(currentData.size); + width.setValue(currentData.width); + height.setValue(currentData.height); randomPosition.setSelected(currentData.randomPosition); - collision.setSelected(currentData.collision); - preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.structureAtlasPath); + N.setValue(currentData.N); + sourcePath.setText(currentData.sourcePath); + periodicInput.setSelected(currentData.periodicInput); + ground.setValue(currentData.ground); + symmetry.setValue(currentData.symmetry); + periodicOutput.setSelected(currentData.periodicOutput); + + data.setCurrent(currentData); updating=false; } public void updateStructure() @@ -71,10 +96,17 @@ public class BiomeStructureEdit extends JComponent { currentData.x= x.floatValue(); currentData.y= y.floatValue(); - currentData.size= size.floatValue(); + currentData.width= width.floatValue(); + currentData.height= height.floatValue(); currentData.randomPosition=randomPosition.isSelected(); - currentData.collision=collision.isSelected(); - preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.structureAtlasPath); + currentData.mappingInfo= data.getCurrent(); + + currentData.N= N.intValue(); + currentData.sourcePath= sourcePath.getText(); + currentData.periodicInput= periodicInput.isSelected(); + currentData.ground= ground.intValue(); + currentData.symmetry= symmetry.intValue(); + currentData.periodicOutput= periodicOutput.isSelected(); emitChanged(); } public void setCurrentStructure(BiomeStructureData biomeTerrainData, BiomeData data) { @@ -95,4 +127,5 @@ public class BiomeStructureEdit extends JComponent { } } } + } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java index 8986a2e6701..05a63ee58b7 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java @@ -29,7 +29,7 @@ public class BiomeTerrainEdit extends JComponent { center.add(new JLabel("resolution:")); center.add(resolution); BorderLayout layout=new BorderLayout(); setLayout(layout); - add(preview,BorderLayout.LINE_START); + add(preview,BorderLayout.WEST); add(center,BorderLayout.CENTER); spriteName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeTerrainEdit.this.updateTerrain())); @@ -52,7 +52,8 @@ public class BiomeTerrainEdit extends JComponent { min.setValue(currentData.min); max.setValue(currentData.max); resolution.setValue(currentData.resolution); - preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.spriteName); + if(currentBiomeData!=null&¤tData!= null) + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.spriteName); updating=false; } public void updateTerrain() diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java index fdfe775d914..4c4131f6345 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java @@ -7,6 +7,7 @@ import java.awt.*; * Editor class to edit configuration, maybe moved or removed */ public class EditorMainWindow extends JFrame { + public final static WorldEditor worldEditor = new WorldEditor(); JTabbedPane tabs =new JTabbedPane(); public EditorMainWindow() @@ -14,7 +15,7 @@ public class EditorMainWindow extends JFrame { BorderLayout layout=new BorderLayout(); setLayout(layout); add(tabs); - tabs.addTab("World",new WorldEditor()); + tabs.addTab("World",worldEditor); tabs.addTab("POI",new PointOfInterestEditor()); tabs.addTab("Items",new ItemsEditor()); tabs.addTab("Enemies",new EnemyEditor()); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java index 1b301ebebd7..367a7d35778 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java @@ -2,13 +2,18 @@ package forge.adventure.editor; import forge.adventure.data.BiomeData; import forge.adventure.data.BiomeStructureData; -import forge.adventure.data.BiomeTerrainData; +import forge.adventure.data.WorldData; +import forge.adventure.util.Config; +import forge.adventure.world.BiomeStructure; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; import java.awt.event.ActionListener; +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; /** * Editor class to edit configuration, maybe moved or removed @@ -27,14 +32,11 @@ public class StructureEditor extends JComponent{ JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - if(!(value instanceof BiomeTerrainData)) + if(!(value instanceof BiomeStructureData)) return label; - BiomeTerrainData structureData=(BiomeTerrainData) value; - StringBuilder builder=new StringBuilder(); - builder.append("Structure"); - builder.append(" "); - builder.append(structureData.spriteName); - label.setText(builder.toString()); + BiomeStructureData structureData=(BiomeStructureData) value; + label.setText("Structure"); + label.setIcon(new ImageIcon(Config.instance().getFilePath(structureData.sourcePath))); return label; } } @@ -54,10 +56,11 @@ public class StructureEditor extends JComponent{ addButton("add", e -> StructureEditor.this.addStructure()); addButton("remove", e -> StructureEditor.this.remove()); addButton("copy", e -> StructureEditor.this.copy()); + addButton("test", e -> StructureEditor.this.test()); BorderLayout layout=new BorderLayout(); setLayout(layout); - add(list, BorderLayout.LINE_START); - add(toolBar, BorderLayout.PAGE_START); + add(list, BorderLayout.WEST); + add(toolBar, BorderLayout.NORTH); add(edit,BorderLayout.CENTER); @@ -77,6 +80,45 @@ public class StructureEditor extends JComponent{ } } } + private void test() { + if (list.isSelectionEmpty()) + return; + BiomeStructureData data = model.get(list.getSelectedIndex()); + + try { + + BiomeStructure struct = new BiomeStructure(data, System.currentTimeMillis(), + (int) (currentData.width * EditorMainWindow.worldEditor.width.intValue() * data.width), + (int) (currentData.width * EditorMainWindow.worldEditor.height.intValue() * data.height)); + struct.initialize(); + JLabel label = new JLabel(); + BufferedImage image = struct.image; + if (image.getWidth() < 640 | image.getHeight() < 640) { + if (image.getHeight() > image.getWidth()) { + BufferedImage nimage = new BufferedImage(640, 640 * (image.getWidth() / image.getHeight()), BufferedImage.TYPE_INT_ARGB); + AffineTransform at = new AffineTransform(); + at.scale(640 / image.getHeight(), 640 / image.getHeight()); + AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + image = scaleOp.filter(image, nimage); + } else { + BufferedImage nimage = new BufferedImage(640 * (image.getHeight() / image.getWidth()), 640, BufferedImage.TYPE_INT_ARGB); + AffineTransform at = new AffineTransform(); + at.scale(640 / image.getWidth(), 640 / image.getWidth()); + AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + image = scaleOp.filter(image, nimage); + } + + } + label.setIcon(new ImageIcon(image)); + label.setSize(640, 640); + JOptionPane.showMessageDialog(this, label); + } + catch (Exception e) + { + JOptionPane.showMessageDialog(this, "WaveFunctionCollapse was not successful"); + } + + } private void copy() { int selected=list.getSelectedIndex(); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java index 63d08c62f24..4a01fd30603 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java @@ -4,6 +4,7 @@ import forge.adventure.util.Config; import org.apache.commons.lang3.tuple.Pair; import javax.swing.*; +import java.awt.*; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; @@ -40,7 +41,6 @@ public class SwingAtlasPreview extends Box { setSpritePath(sprite,null); } public void setSpritePath(String sprite,String name) { - if(this.sprite==null||name==null||sprite==null||(this.sprite.equals(sprite)&&(spriteName==null&&spriteName.equals(name)))) return; removeAll(); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java index 8bbde3bb51f..61f45ec0fa1 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java @@ -16,6 +16,7 @@ import java.awt.*; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; public class WorldEditor extends JComponent { @@ -23,15 +24,15 @@ public class WorldEditor extends JComponent { WorldData currentData; - JSpinner width= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); - JSpinner height= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); - JSpinner playerStartPosX= new JSpinner(new SpinnerNumberModel(0, 0, 1, .1)); - JSpinner playerStartPosY= new JSpinner(new SpinnerNumberModel(0, 0, 1, .1)); - JSpinner noiseZoomBiome= new JSpinner(new SpinnerNumberModel(0, 0, 1000f, 1f)); - JSpinner tileSize= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + IntSpinner width= new IntSpinner( 0, 100000, 1); + IntSpinner height= new IntSpinner( 0, 100000, 1); + FloatSpinner playerStartPosX= new FloatSpinner( 0, 1, .1f); + FloatSpinner playerStartPosY= new FloatSpinner(0, 1, .1f); + FloatSpinner noiseZoomBiome= new FloatSpinner( 0, 1000f, 1f); + IntSpinner tileSize= new IntSpinner( 0, 100000, 1); JTextField biomesSprites = new JTextField(); - JSpinner maxRoadDistance = new JSpinner(new SpinnerNumberModel(0, 0, 100000f, 1f)); + FloatSpinner maxRoadDistance = new FloatSpinner( 0, 100000f, 1f); TextListEdit biomesNames = new TextListEdit(); DefaultListModel model = new DefaultListModel<>(); @@ -92,7 +93,7 @@ public class WorldEditor extends JComponent { setLayout(layout); add(tabs); JPanel worldPanel=new JPanel(); - JPanel biomeData=new JPanel(); + JSplitPane biomeData=new JSplitPane(); tabs.addTab("BiomeData", biomeData); tabs.addTab("WorldData", worldPanel); @@ -116,8 +117,8 @@ public class WorldEditor extends JComponent { worldPanel.add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); - biomeData.setLayout(new GridLayout(1,2)) ; - biomeData.add(list); biomeData.add(edit); + JScrollPane pane = new JScrollPane(edit); + biomeData.setLeftComponent(list); biomeData.setRightComponent(pane); load(); @@ -166,6 +167,16 @@ public class WorldEditor extends JComponent { void save() { + currentData.width=width.intValue(); + currentData.height=height.intValue(); + currentData.playerStartPosX=playerStartPosX.floatValue(); + currentData.playerStartPosY=playerStartPosY.floatValue(); + currentData.noiseZoomBiome=noiseZoomBiome.floatValue(); + currentData.tileSize=tileSize.intValue(); + currentData.biomesSprites=biomesSprites.getText(); + currentData.maxRoadDistance=maxRoadDistance.floatValue(); + currentData.biomesNames= Arrays.asList(biomesNames.getList()); + Json json = new Json(JsonWriter.OutputType.json); FileHandle handle = Config.instance().getFile(Paths.WORLD); handle.writeString(json.prettyPrint(json.toJson(currentData,Array.class, WorldData.class)),false); @@ -173,6 +184,9 @@ public class WorldEditor extends JComponent { } void load() { + + + model.clear(); Json json = new Json(); FileHandle handle = Config.instance().getFile(Paths.WORLD); diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 0cc6f9dabbc..830775aa7ed 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -888,6 +888,8 @@ public class Forge implements ApplicationListener { //check if sentry is enabled, if not it will call the gui interface but here we end the graphics so we only send it via sentry.. if (BugReporter.isSentryEnabled()) BugReporter.reportException(ex); + else + ex.printStackTrace(); } if (showFPS) frameRate.render(); diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java index 50df63f6157..a91096d98b2 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java @@ -1,34 +1,62 @@ package forge.adventure.data; +import java.awt.*; import java.awt.image.BufferedImage; public class BiomeStructureData { + + static public class BiomeStructureDataMapping + { + public int getColor() { + return 0xff000000 |(Integer.parseInt(color,16)); + } + public String name; + public String color; + public boolean collision; + + public BiomeStructureDataMapping() { + + } + public BiomeStructureDataMapping(BiomeStructureDataMapping biomeStructureDataMapping) { + this.name=biomeStructureDataMapping.name; + this.color=biomeStructureDataMapping.color; + this.collision=biomeStructureDataMapping.collision; + } + } public int N = 3; public float x; public float y; - public float size; public boolean randomPosition; - public boolean collision; public String structureAtlasPath; - public boolean periodicInput; + public String sourcePath; + public boolean periodicInput=true; public float height; public float width; public int ground; - public int symmetry; - public boolean periodicOutput; + public int symmetry=2; + public boolean periodicOutput=true; + public BiomeStructureDataMapping[] mappingInfo; - public BiomeStructureData( ) - { + public BiomeStructureData( ) { } public BiomeStructureData(BiomeStructureData biomeStructureData) { this.structureAtlasPath=biomeStructureData.structureAtlasPath; + this.sourcePath=biomeStructureData.sourcePath; this.x=biomeStructureData.x; this.y=biomeStructureData.y; - this.size=biomeStructureData.size; + this.width=biomeStructureData.width; + this.height=biomeStructureData.height; this.randomPosition=biomeStructureData.randomPosition; - this.collision=biomeStructureData.collision; + if(biomeStructureData.mappingInfo!=null) + { + this.mappingInfo=new BiomeStructureDataMapping[ biomeStructureData.mappingInfo.length]; + for(int i=0;i GetBiomes() { if (biomes == null) { - biomes = new ArrayList(); - Json json = new Json(); - for (String name : biomesNames) { - biomes.add(json.fromJson(BiomeData.class, Config.instance().getFile(name))); + try + { + biomes = new ArrayList(); + Json json = new Json(); + for (String name : biomesNames) { + biomes.add(json.fromJson(BiomeData.class, Config.instance().getFile(name))); + } + } + catch (SerializationException ex) { + ex.printStackTrace(); } } return biomes; diff --git a/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java index e991e52f183..7c6736e88f1 100644 --- a/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java +++ b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java @@ -20,6 +20,8 @@ public class BiomeStructure { private int dataMap[][]; boolean init=false; private TextureAtlas structureAtlas; + public BufferedImage image; + public BiomeStructure(BiomeStructureData data,long seed,int width,int height) { this.data=data; @@ -35,59 +37,42 @@ public class BiomeStructure { return structureAtlas; } public int structureObjectCount() { - int count=0; - for(TextureAtlas.AtlasRegion region:atlas ().getRegions()) - { - if(region.name.startsWith("structure")) - { - count++; - } - } - return count; + return data.mappingInfo.length; } public int objectID(int x, int y) { if(!init) { - init=true; initialize(); } - if(x>biomeWidth*data.width) - return -1; - if(y>biomeHeight*data.height) - return -1; - if(x=dataMap.length||x<0||y<0||y>=dataMap[0].length) return -1; return dataMap[x][y]; } - private void initialize() { + public void initialize() { + init=true; OverlappingModel model= new OverlappingModel(sourceImage(),data.N, (int) (data.width* biomeWidth), (int) (data.height*biomeHeight),data.periodicInput,data.periodicOutput,data.symmetry,data.ground); HashMap colorIdMap=new HashMap<>(); - int counter=0; - for(TextureAtlas.AtlasRegion region:atlas ().getRegions()) + for(int i=0;i=0) + { + pix.setColor(data.mappingInfo[structureIndex].getColor()); + pix.drawPixel(x, y); terrainMap[x][y]=terrainCounter+structureIndex; + } terrainCounter+=structure.structureObjectCount(); } @@ -395,6 +401,9 @@ public class World implements Disposable, SaveFileContent { foundSolution=true; x=x+xi*data.tileSize; y=y+yi*data.tileSize; + + + } } } diff --git a/forge-gui/pom.xml b/forge-gui/pom.xml index b81def5a7c3..43f21d8d837 100644 --- a/forge-gui/pom.xml +++ b/forge-gui/pom.xml @@ -67,6 +67,12 @@ 5.2.2 compile + + com.github.jetopto1.cling + cling-core + 1.0.0 + compile + diff --git a/forge-gui/res/adventure/Shandalar/world/green.json b/forge-gui/res/adventure/Shandalar/world/green.json index def5769876c..8cda1b185dd 100644 --- a/forge-gui/res/adventure/Shandalar/world/green.json +++ b/forge-gui/res/adventure/Shandalar/world/green.json @@ -21,10 +21,18 @@ ], "structures":[ { - "structureAtlasPath":"world/tilesets/forest.atlas", + "sourcePath" : "world/tilesets/forestSource.png", + "structureAtlasPath":"world/tilesets/structures.atlas", + "mappingInfo":[ + { + "name":"Forest", + "color":"007000" + } + ], "x": 0.5, "y": 0.5, - "size": 0.3 + "width": 0.3 , + "height": 0.3 } ], "width": 0.7, diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png deleted file mode 100644 index cf8dd71e0c9d2cb2327c33398a99d087c459cf34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16786 zcmeIZWl$X57B)J#dvJG$!QGwU4#5U@cOBe45C~2nfgr)%-6245_u%ew$$Px+S9R-D z-S6L-shRFx^6a&rwf64mp50L@N-`*j1c(3t07Xt#QtfSP{Pq!rhkg6r;dDU-0GJni zG<4k5K%QhyE{+z~cIISm-cIIZ=3dqo0D#wGQI>VuHgC1zt1Gr6Lazc79M;57)LOrl zkw_+Y?OOr0_gs?FK3<7r#y2RiAx3+FFA28~KVBbxIPGEn&|g&dE$4aN&haJkyIdA| zjXh;_d}3R*R=Dn3NQhlPhwYOY0r*((%Op+Nu|@ z_SDd^*MD@}?XMO~8|HS&RdmMz-hMro4{;HiwI_T0M0arur?`)l)y@Jz1EQ~Q>G$_KB*Jrk>IhbN;($;X%Dr$_W(F)H)7 z&9tu-lM-f4tBF0Rl&u?nffbc_Ch>dGagHYXZ2qjmC4D5gjQDCdYiIpwK8wFW)N>6- ze0?4LnC(k9z6NV6Bqyyl~Un4)@!eU`E zc79JH%nxtrn-@2xAjPo)UZuNam5I_(JHX<*%BR+O7c}f@>)ovqyx-o5nSZN~EY*__!Wuc?&WiL*&4c-S;5n>Q|{=S+t9J~L-WyKHt_ydM5peo#pe72 z{o4GC9+#p0@dS0SlbSvU4l)ixnU^a9{Qmyu73D#`W|xYEmA+<7d^6`U52rqzEy^#d!(juKmB2=q*Jg)ThhO!0t?k&4L*lg8N@k=YB5gsc zmKM5>!m%;5>r0pyn%xsTuP@5|<2I0=gle0OSUh(Zj{SAt!*&}F`+2Y5Qa_q9wKRD0 z7zUu_^=75E)QH~hfBWUR_o;Bnd3JCn?*8O44%MRfzO2Elqa}x&`SBp|m9`jnO@FUu zME@}^)bo7NwE|nW?AijIJ=^fch3ee@LZ|4&^~bLPb(xFt9rL;iDBxThgX&E!)I+;_ z)}q!?IV9XUKiS}lFLk;F*_~3;Ek*CDkBZ>a+0_HAmRt4Jv7J|mht|e%>-AMco&P28 z#IN@sq84QJcZAr23d<}2M{C&fl<#w`Un*sp7S`GNM@!QTAj$Pd1ez?P?wi-@$D1J9 zJuE=kxjrW{)WEse`150-Jxk|royXp`Bnq!g{z*JhUVN=Z`b8H=RM?^Y-4BZnZCOIt z*jtLFx%WBC591N$w)%DbJwG@Bmqa-QH+aMCYEa3SIg(nD$RQfO2fYY&Mu4O zXUq_~IFQUQJi3^>u%6tniZt<>6n$`C5XCfaQX*vznslmg>3CzV;LX{gIT+fa#FB@} z+qS1ZX*tJ>RU*&y?;?q*PI1scu)jZ5Z8HCI}SMp(wri+P{pZ1ZoQoA7IgnF`Z(HO~ zodMo2`L#J1k!lp-3dP6Z5a{oC-II@zgy;#Ubp!+nq3pG}w2qLq z9UqWKMCe?^llj^^mS0zLOAG~lJk!~>BW%Yrx;n&~QOTOdeo2TtLFP*!Un??*OFl;; zB=J>DM2Fp-XpiyKWRMnI?yQ_rap~-Hg+1xbREH=Wmi9@`u%FsqijrfdqvRa}#i$2Z za?tr)`DdnvTS#*3wdk2wr!$X6kGAnA78I<(T;NDQ(G4Q3Sk0x8)c!`ANj}*g^}O+J zd(vGOzJQC8&QF4_#7#Zv;N5j{NKb1Xxx3YE4@!m%JLAGNFH~UETvQUOrbVbclPyJ^ zbm01ENYZbn&P!~uc8^^w4t)%tkN1BvDL7q^4XQ0wqxmD7{;*MKBj+sMZ{CL|=8EtY=5+>B7k4gAu zOif(boU$G#D0Up58!Yi)*%RF5zLDF#Tk=-HM>F=Ngh#55n4z?a42Rt$XQqsOvL?~0 zU3QX}T%)dp?+i)@$21JMuvpo#xJH=Mo3=XfK#Bb(Rtt?#KBOK=k}^9*I7QtnFW2VW zSz#QC8Wx|O_2T-8TCr+eYTerhPPi;+kFGI|K41~M8@{4oTmzJJ@tDnfaqvIF58^U> z*4|n)rb+gPs^DU~{|40@%Ixg3T4Q#JC~c>5m8C}ZB^1#Q2{eZJ$(zl;H=j@W1PZeR zo!7K1KKJ4#vI2}0gT>WFsPL@M()>e5sfj)v)lC4xS#Hs9JB(~^2`gWy0 zKhOKt^dHb$WOE-x?LiqMj~9NfGjJ>3%waT!A55&it-U zaRH|g>{7MAsk}0vcbz7XX3HJ}MlEN*65z3$jMras7MQQD!1t+f_OTe zXB4T?^lzZ9Ag9aTBbJHD9p^-5dSbvic3UaUq6;`(UYSSEXTsUk-DqU62S=t-*jJ$D zKo?;-#T7504Lhs^>ySn3f|$l)q9By9$O)A;vc&~Uk}uw5bFu$8%#|PTLJUU{sCl$?n?T&BJb&R)1j8?ifr~@EH+Zwk&o=2 zw;LhbGr7V9PH-nh4bws|XjchJr76TL(}_RwZZTjuNA6g+!UhP=(}%Jzd$mAM$1dVM z_h6A}(tb(}KMYe|E12~SQ8h-lIDz;AFu6LE5XE56WeLbo%@G9qCaFR;ZY6f-Sx6Uu zi|N4n+Wd%oJYbL^%g_ch>_^yDmI&a5) z5yK{&C`bF7w_)MLuN**L7mCyvawa(UY!)S@u2M3dm!m8LJw*aZ$%G2pK#GJ6RV{Sr zZ1a#J1D$%3TNgnUA((hKc3$5}7$TxIG^A@CCX&2*{ZaC(o6YKBxe7n|RZLg_^Ffz{ z&ZxogI2Fzv1lf5Zyk9{}l4K>KHL8NK>t~9Tr1ml_VYm}t7CU;4;ZYNMC<6XOI3&Oz zl)u1L3~Qb`P`!){R3C&IZX*PM?ruynsv&_E2q(dy6clm=_X|m?$%BkA%=NSACPal* zMjY8Z35vy;c2>kXAino_ADi4T@s*|XhSBuSL$dI?|Ns-v5F$j-#OJ)G)e0@rI2T%YS@`&v1OWq29@k>qi&I+&3J70})%+@mp#cE51W54@joPrr1i6?N%a)RuTz zL4Uwet$=<=IVnrVP6!$w2oi$}87M|BItX z1hFh|fBkt4nt~C(lKOW0c8Fr?gt~7qfC!I#j42rGUGb^1H}*ykd?V*#7(haxKeIzBVV$<>5Tx%M#S{eQCh!iuJ`nQAsj>Y2*Bm& z+G9c^BG`>E6PZRs9M?+XQ;wnN;};vkrwEzl=y$cf_Xm-q9L2Gh_*y!m+BA9mo5|AM zO8OY1d{dp^T}0c70=BCzJks?ebG^tsE(Lg4s92)qnQ6AT(vHVOAK8{!)--B*GKAht zGMW#lY8R-#D(SyoTHxohJ07`1`X+F5=2I(I^FIRU3Z6>h0D0Am`6;h2 zQ;<#==M;{-mg`eNEjo>u-tOPKhWxC)Ps#*QcdHz8aoomL+j3$%noH=xydRHDoT?*J zFG$0EdB12%cc``bMR~JH#l0j@_eDvSk;b?zbBa!w#!YU5thIi8V|k^e|M)}yQ}Mqwnwad_HZi*V@1tgD-yDLe;e*w zWjtH_&Q^q#yG3+iS(5Ccqvh8MxE&W8@qQ^q9|p70?KUfQ*?03%3O4)qfQiyS!1vUiFq!2IY!xrxKtR(-5p+T09JDrGWE;hoIo0C6$2f_9^g5BgSpafuH~+4%ZzLL2>QTc`dR2MrFb^@gKdG>G-hrZZNHMZ2g!b zk%LGy@S8Dj6Rh2lnshXK{fi(zik0B&!`6tM6^6SMJG#X$Q!ZJxUM|xS`#lJC3?t5d z{6-TJ#6O4%itacf;|+BglWgwk=Cx!D9~Df9aJFtCUY4Q_TV}F%j_Ntd4PMg9BkSTT z2aZMP*sIiI;#PL+>YYouiGM;WfQj`LHHCl~MO;M}!j7V&3*G+x9fe9j7;duo(#PU6 zu~aT$8Yc;mGqBD!DBHW&0^?gO=+jMk%A;<&OoHIOh%-yfmMVHWk_nQ)YFbC7`Px)rJexeaF-3#C85!HMGSWk1No^td zg_a7(fw<7@Wy9_+!;G)jjAqlzR^q7~u1<9q#+Ma``b%(n96lu24%UpPN)nHnNejXj zaZ>rpM!dD;F(e+1z=%qhT@8awXK+01c z9(Cx>w!Q>TxP{5Y*zug=$Mt4d@(*})v(QRZ4eRLbeNv@IQJY)+YuR=RpB=#Z@2%2j zAuwzw)K1BOyT?_x{RY$P0lMpI!6>V4}j% zC5la*Urj%EV|dK3n_2}4%&T`QXbNbuc%vd=I~>KDsiT{ZBF=`7M$OvE2TLz^dxg-T z>(|JJ`aX*Gw(+(URD_emT9zY-cJIsQ;GGJbNfRdMNw|c}ehu%3bkjtr_EAWTbH@56 z@!S2|VL$V?2}6+|2ax1YLN{ZvwU)3JuXz&(rLY@a84ZJAV)P0FFU6gEFBHqqg2f!Ft@=JM-do|N zr-2#T!h*UwES^xu?@SMdhLRlHPELv7xjR1#L_q^v6&{URO@$tU7@7aUYQofJ41?SZ zRuto!@Gv{Kl5BX62)8>LfXXxCpNWyt6xM2_pR+T?&-6P;rkru^_)K)N8|y~NNmKSK zwH9nSh^|BScRW&Saw^27VYPkbQM;_W@5UMsh;Orop!JCrqIU zg~uxawD{e^6>}%<_r58L+Nj|5m!b&pGZ+%^ZWfP&Cft!|d-kZ~pRv!@A0|-4+0z#`H9D)RxYM9~W?|Bl5rF$^Cc_f@AUCS0cNiH{e7}vBm zQQAC?@gxbPR6GCud8$)6$d*$|iBuZ%=>FSa@bRqC5$R2CDEdL%m96bFB6Ez|xjD;X z3b}G4(hbWAB*v~NeeWkb^L;2jQ6~}hI8A3(FA2KBPJ=r7xX>7fUrx-Sgs}1*+9OTc z_XO}tou*kMn(x`kx!>WdSpscoe>ZqwESESl2|or<_|za7e7_L zqF$Ge%(2|HO!TIt<6tszM3HFN$hRI8T|E<3(sU;or#|QWkR&QL6DDUUTx6Fvxnwu1xdDc9esKvpOar#I3-@<36J%?j^!)LiI@DQwU<$M_pT5)lapm0Ca2 zcamoFa!xcfz(#y}w(NO+h#>aFD+YO>K9F8Uf)2T(6>H1egwTDQ9TO5=v7qoOn#rwx z?It}!#$S)>vPg2ET>*L^DAKQjt9%5i#C6au=5?=%zB4aHPm$ZjbfZ6;#FL#~FM606 z$d=g5jY}J~q3rTvw?!~fWx_Mm;h39vuGH=>l zh|jMXFQ;(uqIo+oNe1*l#h-TEmt?DaeS97GoBvf=Yj2|YNg_dcAC1{gB~D5oMdHbc*k?5d1h}*^#Ehg$Tz-PCh2Fe^WmLn zx?1cAC17yNQd5f^f(A?6V!tn&w&1!4UwBcK`Ifd!D`(^KZplbFL%=&P{MJ=W+r3A- zc(d;5>f(0Oc{d~)ot=x|nkN5%0_wTPV<(YT1joYl__*UEbo=7t#8^=j2_{37)qUf_ z>#iS4{$Jpt&nJ4?7se1eNfpIbVQfF*gvSJJtujPI;e$z3^H#Gza5y{b`2QwJ?<`yH z34#8lST@3pbVdHT?Teay)j+q_tzAf}M1_$(HtIMNy<%t5PkXRr%+fcf&r9(eO|X&m zUX=UDPqbnvGT~{%gW-Fs9h>D_GsH~WyhOa6@h9V`6wYn8%Gsxomq!hipK$hRO)y6f z4JGE5>6#r4v~ogPy_UZ?PNOV(eb}aaSxJHL$goqJu3nQ!ZkB7v5Hz7#i}cE-JizKA zfZ?%#?@M?mh0OG!MqCP_vuJXgYgun4_o>zzy!WtBP>k&gQL0D=M;|I!Zw9Qi`!SBS zZDNg!52()Nn)^klrIY0Z^;4YNLqHEvzAt+ujG|1;$3Vx?!OG~sO9XQ{ama_~NnIQw zVHtbAg@ORc$RfKe_~KEDh*!C4ky|!$hmXZvt&gh`&x%{qlAPGMTM5Ew>;r2qX_EQ8 z{VBPh>wS#H!5kUK)E@kafT^@!t`RieST}s4Y2M9$c z>wE8ob@}Gp@(;28eL;;cy<8#?I*lh3gz25DD)l!jwKhY`-3+xB*vUI_-4qFK{>Mnz zkP$n;Tc~%#KiXVn*fm5IBtG3w)&WLTZmWKk=?&NIwJgOV#z^{h8~e+&y_la4MEmJ4 zA4#1mkP>UYTmAaFe><^i84h!hdQ>OQETMwuCJGh8=_EUwpQvi;C*bZRLRr5uM9Djv zWuK$^49stUb~Q?#y8qo{X+0v--=jAhZ;UCF%BEf*EH%D z#wH*O#(eBJ2<4s1^=CO#ahitXv`RvlG%wU3F?rm!ZT#^Mw~?LG6>%$FtblK~$!ulm z;Cr(}s+UB54@=WgQFd>_UnAmr^B1vV64vajC-01<+%+Eib)5(sKYK}Adg+9lfg53O z#`*;xT?z!M4wr5oJvahAx*&<>S&<)Vvw|f=Rgf%Ks^PKZMIm-;i6$&~6M=8;~7 zL(x4->xE8cUuwrq1&-J#7J9_O0u-+NX|cKm0Fo^c9`27ZvdecIzE0=QUdqa^%L{ji zLdKThirsun0gcc059^iB#AFmoLpKXn%S-Aro;9f}%x{HYN~ zTRHL1D)n1_VG@<=^O^$>O}grH#+$215YmJ3A0+~-Ve&KVf+eI-1l(4kDhf{dJHBWW z&0_A+()MdX=I4Gd$NSX2T_r+1H00~x2@poYKEYk+o`%2=?S1!*lT}U`DtNZB1vYyW zFl3u80)};dU!gZc;5`U0Zik5>m=xU`g5Y)Upo{GFNW_~OGx&I92qj;9gLH3$w!hU> zuQV=x=xGIkpCIo5p>NFB1c&Ut4&L<;TB!Ljj+6J^Be11ElE6D#E`nnn3fXgYt=$n< zv&Wf{*dbT(DZ>y##I?6R4YUd zlO`WqA%3+Y#5!Z_C>=uPHF6 z|2o5s>v`KensO{#O?%;7^|9qQJme>L90s^u_a9{mrItYSCimO1j0(Qn^mJGo*;C>ZFw7(C^72aQERZ#0KVA6t2Z3sU9bfcvm0 zn|wSX*|-3ApgI=n^83DVqtR}&r@RY|VbMoobzt|KWg66CFZ54wYTzWdLRw z{_!4mv(8Ju*yN_~df85*Bu<6OrJ5Y)2iOiWpOiua6+pX3owIm&FIFMTMz(~ zLeoHQd~uQ=eY@0O16N5FSqe9mL-;U)ekyr;>lpa_!TzgME8G@Fmd9cK=+S-2I>sgq z%0iiU<-YWq8Q}+~aGYwcJ|umZ`5}9>lCs-FLiyb2P0RCdX>P=Q^U4ia!MX5jG~AJf z0XG!{g5t^dqV+~3nFd`SChvm|kADUZx}^mY5jOTfu!Q*vSIHd=fT zH5efvc*%*jd$b^m6Q3?-rhJc%zE|%~EVClmQ7be6J4+rs)16Lo=s9*E{2dWohBQu9 zVAtXs7*AmMs45!2gMlNMG?t;LY4-&qQ8j~DnfyzQciOh9)L}Wk9Mn@j`pQs^i;KI! zQj#9Wm(g-ccTZ^tWqrDQ)%)An6Ye}l8tCxmuJC~{8loGgc3JojMJyKNQp;AO2_~az zMmO)MbYm=AnVohY{B|^x`%+MpB*;yY7>k*2scwl^NBZPQ`2qHb&%w}Qt|q#jH)B92 z5Z#Dr$kcuP?<4kK*rLp`X{VCPaP#r@xp72HVQcP3cU?H7EkCC(>+%9y;$$eJKI1cp z2&Q@xt*FEI+Ue~d%>+L1B~ovP|Kj9i8DDtvOfiDBG2tqKiQ{M*Yh%6Q8);>J=W{&b zqZfvt9{4TBn9#}{?W-PNKs%*Os;rN2jL&kmRhx_?QbUtSGqsWuI9?|KpL7Ej<{bUU zgPX5&pSH`lCEO?;1CN7FcZYpsMu!2GAjooyse{c`)|;Xf0t7|~52d217bSF?RpuJ$ zR7I-h@@#t(oV(5)40HI?SS4bKe0L_xUVY6@##QbwUX`bkzW(S)TbewmJPc_OMT1^s z%S!Hdx%8Eq&+YI;it7(0k@GLoM9ZghlHe942wd@W5?WtkMFk^#n3CYNT3iOOq0v}zoAo`$1cGR2PMsy&0s;3){-<> z_jlEP#IM}oD6N_#F4PAX0xc81asE`Uq{1Y<-246NY1o@^e8`>aF#)l#!dJe!%zjj@ zQ5_6Z)n!}40&XHT`~H>HU(-7wcH70<#3@CzbtEMai#m3xOxS1&sR!Y-_~c>KrYpw` z2`fEZX0l*7oT%w{V=^r<&fOs&)yMubcv^LHPo$I~hsddtw7QqVI#noKtvZu+_#qVr{AcMt#ghz7l|5rvMpOw`S~ z9O$V4W-O$lE?DJ}GLgQ6%s@^`3#ZKC(H1_ibaF|U4u=S1D+9k!+eN0w!OA%XIU*E} z|NEJ1XqKwxbuI~(1hvSTN0&OOXJZK0(WWyGvRRFG#mQs!_3pfs?FUrDAW>1akGJ3U zqKp7vymYo@MdAHvQCB$hUxAoYwCOp5MrlBGs#fF#& zyRpVk5N+e`TM_5o9G#dJj3&y=1@|j%T1izzG%}|n$wU~z=Y^-xyXCHR`0fu@>+NyW zIn>Ul?@)$(c*FK%^Z0tIlQvzwP;2D<>u01USV=3Als%W;bvZn4AfX7IpmH!0Uj~y~ znmo^hm}$O)*h61+o~q%;{MYR3IoNfBDq4|Eg4Ui5C4;GFJ$kaq%9{2D`@ID&u_ z$&p9G2(U5Xg}3)}89-_xkb`L;74tD+9~kflR?|S*lN6mvpnPB1;=Wz{od~F}I{F^` zqIW&o4#!)B@iCA3`e}#;4&bg40awpq9Q@1`Oq(^&;+T4x#Zn!G%c4*25 z&4625`iM*l$_u1ei>K+Z)p3&PEQazd!IVg%_}*j41o1mgC2>AuMgadr=k>wY8|12Z z8zZ7kP@DE^{0h8T4*GPRQicz)@ArHGwIofQwR+By*oWB9aX-^6r>7gtbgFOls=hxN z^~w_>!5bbLAG3tX9;0DR?%*2&Ifwz@7kc7mJmS7SWWeiaVxRaP$U*eg?kIfJ3G z(^*{npV1+w8k~qa{?2A|-;}`32We)N@q_q6M702bZIp6;>-d z5RF3uz6;tsyPX{b65R4o%5+E%i=5Kb86Mt$nfH8LyhGiZ-#1AOm8;h*OZnbrd=q33 z5YCsRAdjYNOe1v%d?`QsRmG&{ZD-Qt3hfmGgGbJC6!95Q^2FlmeB^h=;cd8?%Ji!u z#aj@0c*xY~seFNa*k@T}Z!G=bv^Qh#UeJ}htVQd|#jE`RW%F>M-iM?$;dx$Yfgf;i zf6t7Pn2}(;hLMk-@Z|m@Yhprhut6)`b>yPW=Yq(hZ9UZ2pH>p9)pLp8l@+CAAYPc% zK(PJ7Jv$^r$0pS53X4y^GR>rP3RSrSkC+=-ud?(NW}K%W=eM+H1~8CJT8fb zhon}0e^sito=%x!)^%wjE>=9J*4dN#lW1sn#ce5LZm1mb%09CaAD)s&S@wgch8X7> z+sZ&7iwHZ!>e+Ci2;;pV$-_wYC#Dcc$3l^FEFq!2C{s+-yrAFZ44hwJ3+O)?5T&$U zqp!@tZ>7=qP&?XVhqsfB88dmlA4O>Q0e)ndFh;{gI^MYdU>I`)ZMwNwQ%LSB%O*?5 zlBJ||g)KtTi-wmTU?fHHIU z#E-GbZ#rmzZi47lNFBaJ6`;V+6Bc(nse^>VV?d0q9 zOc%N`3@y$79@g96GWZjrY;5}?8=D{sakzhhLTIktW~*{3(*ha+Ikt%>Wme?^Zm^-x zb_SJ3m}u<-RurTs>G{blvT-g#@ybnv&@RBG(}V^!x=CsD#r;h8=PCwS{4S4R!-DEmUoW}%+}!EsW#{ID1_OcSU?>#|`ovTJFL&y-0+#~k1J`!d z04z?!6Y(|I#b4PyU7{3rfciZ8DtjYc;$f&vQQ3gI5ZVr1fX<`9Z*4o1{!5F5Ojdn_ zNvqA}by5Ex_Q!L|u?OZQa5+1)BEXO5TrKnV*7!$NS8G0Z&)~R>#Wi82t>#zd+=lZ# zW%$&-2c>VFrguF3r(GLT^S6^fCObTmCPa~2G$&Df2mQpxkJCO!;(VkrK_6`EkO<7V zZP34Z*q}SfhU4o)l9)J(V^81O64#~S9wP3Mkx#e zgG+_*(s!3gh}yL(dJDME==h(1*QCN~^hN1(O4XrEnwH{(?1_0xD~};d^Kg8g%kq#B zkXq7YVcB&kc@(-iTMrK))hLOs+@cnbh#_U4SF=91qmh0#34$ z=X%)khLG}I|lKUwo z|74_Qg|XG;EV8=dyW9p9YLQxEF#(-tla{2^+ovC(iQGy7M(^I2kTm(4GsG~VfBb()_YVW zK@K~!>C0Y_N!3iB3vNwyKBh9347TPMKk~imZts{Hz4DqHp?jnd7<=j-_s^8F#t3qS zWa84q*cu>m=~C(FD9+;np{JgB5h<1oeQcl$QywgK@)q1{$lA*1z7jbedOSEEBfCe_ zckoA$<>B^$q)Q%$&}Sl0+Ij;S4oMFV8?v$JZR|+gm6J4VRBlM!GU@ zi}5|I-xl5LC@S!qI@+^<%p6V3S-k9>-WKHp0D>Z3P9RfTb2l;*b4zOnA&S$M4hk}B zGa(9XE=8cClZ3gIwXBbexw?;%hN+LODW4gIh%lm{7ylc8y}28R%*)=+!Ij@jh~h6? z{x$?*aWEJzO>3o?T#7Gk0}#cQG}W@-TOBqx^RWGt+0ve4z6w>2UGJuP;cNY)^9lGeB2fmrsnL-COkac%$(*tT+ASI zb{=LPZZ-~Xc91CtFAw*>K`6Uezf~p3?%$*O17-FG#m58WHGgwvW;X?yFmtl8n=pfT z%-ESZKpYmPW)|G+93alWpv+A9r5#=DL2v1_wg*|7vpP9g{-yXsIKP;RoDc;&3-DhO z6+4id#hb(17_fFQbM$ommrBFh-dx=c^oLJ2ZY~}^Ha;#6KK8eudD;JEq-E~n`c{j7 zP}zVi9DmdNNeus6ciyN4{i)P9fWJK6dc!Z_Vh(b1bkT5hv=gHE6BOAW&wr{F-v*Q! z$PFY3ax;Ge1+ugA19|w_xHQ-~_}SR`+4vZNZ<2qrcQmuM@c#d@{xf{Y1pk(FS!>s~ z_PzfS{cTLCn>+vQ=x>L1)_)BqGP1vh1wY92Z(VQ&d6=9173Uk)-&CenAO}nHxB27m z1^W-V_5Yz5Ot{&B78Y#g%4n{8#+`kFNjG^$7cC2r^FndI=^dED`Mk{3|~#CI3D9xeFC4yXQ71x1%Dg^TG>Vlw$!^$ug$)Kb3>2e}F6T9g(`s z=}Z<7#yu!(aq#nTBESCkHZyWM7q96W8r zIFuIll=^uBF^1QO65ARyi3(~JtJSfX2OYoEVt^{hvCl(MY?-fwJo_}mlyb|Z-A2-kZ?o=D4m z*m~QB_3`nJ<4v~eJzqbXe1Ny)W6xL)zflVIQ$nEE4m7bmtr0m~TJ&#FySOpiE>bJy>Hfy9tV?Gt^F3@xh1DMqLK*aDO z?Q&&cC)P65CAQi9;3mJHch11K7^&E(!B>w1P%hi{$5h+@81f^P1lZ zfIs|e+MPVhe4=HMg92h@dtLsz#fbaO;mz$RWt*$Qy-*D#lyP>O+#BMY+qty9w^wbj zV?`;S__ls*=YW0{x8d2gDPw4Cc@)}%^Y%W0)Z7p2>(hq%z$v#@JdM9F4@Z;kTDtTm z+4Rqtk+zoBr0?9T0q50^MGx7x{b*KY%$qJHyIA-%_{GhsV(UHcG)6Qw-LLQ4&W_-a zt0oenKc%d{5qBai!VvIQ`l^^G<)o9#LPvD?UwUguI|DlRgP*||(2o#oWJa34)}sNP zi7lizP$oZvt4Z^y=g}g?DoOKn@6AL+O)E*!r!~c*j73D%Eva&ANP#As3uuu+K%Rp) z@SJDB4OBSC<(ouo0VF~e-WAXZ{|1eh_~UyU=gHT-!(PH9@RA^lG|$WUDFl_2`iJ5R zsO}fRx?ukE{^iK)$40yrFH_9P(=8LXt+-n#A0d|h%Zi(~=jrtzF1%+3`u6(?PvMFO dqp@B@$S}&QA$wnA-lh?NoRpGeg}8C>{{!ZxW3>PP diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forestSource.png b/forge-gui/res/adventure/Shandalar/world/tilesets/forestSource.png new file mode 100644 index 0000000000000000000000000000000000000000..bbae35add1f51c50a3a2bf1413d61ffe9d9fbf09 GIT binary patch literal 8939 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 Date: Wed, 3 Aug 2022 16:26:46 +0200 Subject: [PATCH 09/66] adventure Editor rework --- .../forge/adventure/editor/BiomeEdit.java | 50 +++--- .../BiomeStructureDataMappingEditor.java | 15 +- .../adventure/editor/BiomeStructureEdit.java | 38 +++-- .../adventure/editor/BiomeTerrainEdit.java | 18 +- .../forge/adventure/editor/EffectEditor.java | 15 +- .../forge/adventure/editor/EnemyEdit.java | 31 ++-- .../forge/adventure/editor/FormPanel.java | 63 +++++++ .../java/forge/adventure/editor/ItemEdit.java | 16 +- .../adventure/editor/PointOfInterestEdit.java | 18 +- .../forge/adventure/editor/RewardEdit.java | 35 ++-- .../adventure/editor/StructureEditor.java | 3 + .../forge/adventure/editor/WorldEditor.java | 49 +++--- .../src/forge/adventure/data/BiomeData.java | 22 ++- .../src/forge/adventure/data/WorldData.java | 2 +- .../res/adventure/Shandalar/world/green.json | 158 ++++++++++++------ .../res/adventure/Shandalar/world/world.json | 28 ++-- 16 files changed, 348 insertions(+), 213 deletions(-) create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/FormPanel.java diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java index cbf244b4a7e..69a2b89982f 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java @@ -6,7 +6,7 @@ import javax.swing.*; import java.awt.*; import java.util.Arrays; -public class BiomeEdit extends JComponent { +public class BiomeEdit extends FormPanel { BiomeData currentData; public JSpinner startPointX= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); @@ -30,28 +30,26 @@ public class BiomeEdit extends JComponent { public BiomeEdit() { - JComponent center=new JComponent() { }; - center.setLayout(new GridLayout(14,2)); + FormPanel center=new FormPanel() { }; - center.add(new JLabel("startPointX:")); center.add(startPointX); - center.add(new JLabel("startPointY:")); center.add(startPointY); - center.add(new JLabel("noiseWeight:")); center.add(noiseWeight); - center.add(new JLabel("distWeight:")); center.add(distWeight); - center.add(new JLabel("name:")); center.add(name); - center.add(new JLabel("tilesetAtlas:")); center.add(tilesetAtlas); - center.add(new JLabel("tilesetName:")); center.add(tilesetName); - center.add(new JLabel("width:")); center.add(width); - center.add(new JLabel("height:")); center.add(height); - center.add(new JLabel("spriteNames:")); center.add(spriteNames); - center.add(new JLabel("enemies:")); center.add(enemies); - center.add(new JLabel("pointsOfInterest:")); center.add(pointsOfInterest); - center.add(new JLabel("color:")); center.add(color); - center.add(new JLabel("terrain/structures:"));center.add(new JLabel("")); - BoxLayout layout=new BoxLayout(this, BoxLayout.Y_AXIS); - setLayout(layout); - add(center,BorderLayout.NORTH); - add(terrain,BorderLayout.CENTER); - add(structures,BorderLayout.SOUTH); + center.add("startPointX:",startPointX); + center.add("startPointY:",startPointY); + center.add("noiseWeight:",noiseWeight); + center.add("distWeight:",distWeight); + center.add("name:",name); + center.add("tilesetAtlas:",tilesetAtlas); + center.add("tilesetName:",tilesetName); + center.add("width:",width); + center.add("height:",height); + center.add("spriteNames:",spriteNames); + center.add("enemies:",enemies); + center.add("pointsOfInterest:",pointsOfInterest); + center.add("color:",color); + center.add("terrain/structures:",new JLabel("")); + + add(center); + add(terrain); + add(structures); name.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); tilesetName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); @@ -71,7 +69,7 @@ public class BiomeEdit extends JComponent { refresh(); } - private void updateTerrain() { + protected void updateTerrain() { if(currentData==null||updating) return; currentData.startPointX = (Float) startPointX.getValue(); @@ -80,15 +78,15 @@ public class BiomeEdit extends JComponent { currentData.distWeight = (Float)distWeight.getValue(); currentData.name = name.getText(); currentData.tilesetAtlas = tilesetAtlas.edit.getText(); - currentData.tilesetName = tilesetName.getName(); + currentData.tilesetName = tilesetName.getText(); currentData.terrain = terrain.getBiomeTerrainData(); currentData.structures = structures.getBiomeStructureData(); currentData.width = (Float) width.getValue(); currentData.height = (Float) height.getValue(); currentData.color = color.getText(); currentData.spriteNames = spriteNames.getList(); - currentData.enemies = Arrays.asList(enemies.getList()); - currentData.pointsOfInterest = Arrays.asList(pointsOfInterest.getList()); + currentData.enemies = enemies.getList(); + currentData.pointsOfInterest = pointsOfInterest.getList(); } public void setCurrentBiome(BiomeData data) diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java index 4b92f6d91cb..39c1c2cbca8 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java @@ -18,8 +18,12 @@ public class BiomeStructureDataMappingEditor extends JComponent { public void setCurrent(BiomeStructureData data) { this.data=data; model.clear(); - for(int i=0;data.mappingInfo!=null&&i BiomeStructureDataMappingEdit.this.update())); color.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureDataMappingEdit.this.update())); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java index b6dc2875dfb..3d55f5f7a51 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java @@ -9,7 +9,7 @@ import javax.swing.event.ChangeListener; import java.awt.*; import java.awt.image.BufferedImage; -public class BiomeStructureEdit extends JComponent { +public class BiomeStructureEdit extends FormPanel { private boolean updating=false; BiomeStructureData currentData; BiomeData currentBiomeData; @@ -28,24 +28,22 @@ public class BiomeStructureEdit extends JComponent { public BiomeStructureDataMappingEditor data=new BiomeStructureDataMappingEditor(); public BiomeStructureEdit() { - JComponent center=new JComponent() { }; - center.setLayout(new GridLayout(11,2)); + FormPanel center=new FormPanel(); - center.add(new JLabel("structureAtlasPath:")); center.add(structureAtlasPath); - center.add(new JLabel("x:")); center.add(x); - center.add(new JLabel("y:")); center.add(y); - center.add(new JLabel("width:")); center.add(width); - center.add(new JLabel("height:")); center.add(height); - center.add(new JLabel("N:")); center.add(N); - center.add(new JLabel("sourcePath:")); center.add(sourcePath); - center.add(new JLabel("periodicInput:")); center.add(periodicInput); - center.add(new JLabel("ground:")); center.add(ground); - center.add(new JLabel("symmetry:")); center.add(symmetry); - center.add(new JLabel("periodicOutput:")); center.add(periodicOutput); - BorderLayout layout=new BorderLayout(); - setLayout(layout); - add(center,BorderLayout.CENTER); - add(data,BorderLayout.SOUTH); + center.add("structureAtlasPath:",structureAtlasPath); + center.add("x:",x); + center.add("y:",y); + center.add("width:",width); + center.add("height:",height); + center.add("N:",N); + center.add("sourcePath:",sourcePath); + center.add("periodicInput:",periodicInput); + center.add("ground:",ground); + center.add("symmetry:",symmetry); + center.add("periodicOutput:",periodicOutput); + + add(center); + add(data); structureAtlasPath.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureEdit.this.updateStructure())); @@ -68,6 +66,7 @@ public class BiomeStructureEdit extends JComponent { setEnabled(currentData!=null); if(currentData==null) { + data.setCurrent(null); return; } updating=true; @@ -85,6 +84,9 @@ public class BiomeStructureEdit extends JComponent { periodicOutput.setSelected(currentData.periodicOutput); data.setCurrent(currentData); + + + updating=false; } public void updateStructure() diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java index 05a63ee58b7..88bde85698f 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java @@ -8,7 +8,7 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; -public class BiomeTerrainEdit extends JComponent { +public class BiomeTerrainEdit extends FormPanel { SwingAtlasPreview preview=new SwingAtlasPreview(128); private boolean updating=false; BiomeTerrainData currentData; @@ -20,17 +20,13 @@ public class BiomeTerrainEdit extends JComponent { public BiomeTerrainEdit() { - JComponent center=new JComponent() { }; - center.setLayout(new GridLayout(4,2)); + FormPanel center=new FormPanel() { }; - center.add(new JLabel("spriteName:")); center.add(spriteName); - center.add(new JLabel("min:")); center.add(min); - center.add(new JLabel("max:")); center.add(max); - center.add(new JLabel("resolution:")); center.add(resolution); - BorderLayout layout=new BorderLayout(); - setLayout(layout); - add(preview,BorderLayout.WEST); - add(center,BorderLayout.CENTER); + center.add("spriteName:",spriteName); + center.add("min:",min); + center.add("max:",max); + center.add("resolution:",resolution); + add(center,preview); spriteName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeTerrainEdit.this.updateTerrain())); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EffectEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/EffectEditor.java index d483f1fbb82..1221e41a7a4 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EffectEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EffectEditor.java @@ -25,16 +25,15 @@ public class EffectEditor extends JComponent { if(!isOpponentEffect) opponent=new EffectEditor(true); setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); - JPanel parameters=new JPanel(); + FormPanel parameters=new FormPanel(); parameters.setBorder(BorderFactory.createTitledBorder("Effect")); - parameters.setLayout(new GridLayout(7,2)) ; - parameters.add(new JLabel("Name:")); parameters.add(name); - parameters.add(new JLabel("Start with extra cards:")); parameters.add(changeStartCards); - parameters.add(new JLabel("Change life:")); parameters.add(lifeModifier); - parameters.add(new JLabel("Movement speed:")); parameters.add(moveSpeed); - parameters.add(new JLabel("Start battle with cards:")); parameters.add(startBattleWithCard); - parameters.add(new JLabel("color view:")); parameters.add(colorView); + parameters.add("Name:", name); + parameters.add("Start with extra cards:", changeStartCards); + parameters.add("Change life:", lifeModifier); + parameters.add("Movement speed:", moveSpeed); + parameters.add("Start battle with cards:", startBattleWithCard); + parameters.add("color view:", colorView); add(parameters); if(!isOpponentEffect) { add(new JLabel("Opponent:")); add(opponent);} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java index 3ef2d72a92c..1375670a00d 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java @@ -8,7 +8,7 @@ import java.awt.*; /** * Editor class to edit configuration, maybe moved or removed */ -public class EnemyEdit extends JComponent { +public class EnemyEdit extends FormPanel { EnemyData currentData; JTextField nameField=new JTextField(); JTextField colorField=new JTextField(); @@ -26,23 +26,20 @@ public class EnemyEdit extends JComponent { public EnemyEdit() { - JComponent center=new JComponent() { }; - center.setLayout(new GridLayout(9,2)); + FormPanel center=new FormPanel() { }; - center.add(new JLabel("Name:")); center.add(nameField); - center.add(new JLabel("Life:")); center.add(lifeFiled); - center.add(new JLabel("Spawn rate:")); center.add(spawnRate); - center.add(new JLabel("Difficulty:")); center.add(difficulty); - center.add(new JLabel("Speed:")); center.add(speed); - center.add(new JLabel("Deck:")); center.add(deck); - center.add(new JLabel("Sprite:")); center.add(atlas); - center.add(new JLabel("Equipment:")); center.add(equipment); - center.add(new JLabel("Colors:")); center.add(colorField); - BorderLayout layout=new BorderLayout(); - setLayout(layout); - add(center,BorderLayout.PAGE_START); - add(rewards,BorderLayout.CENTER); - add(preview,BorderLayout.LINE_START); + center.add("Name:",nameField); + center.add("Life:",lifeFiled); + center.add("Spawn rate:",spawnRate); + center.add("Difficulty:",difficulty); + center.add("Speed:",speed); + center.add("Deck:",deck); + center.add("Sprite:",atlas); + center.add("Equipment:",equipment); + center.add("Colors:",colorField); + add(center); + add(rewards); + add(preview); equipment.getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy())); atlas.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy())); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/FormPanel.java b/forge-adventure/src/main/java/forge/adventure/editor/FormPanel.java new file mode 100644 index 00000000000..f28e3aea4aa --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/FormPanel.java @@ -0,0 +1,63 @@ +package forge.adventure.editor; + +import javax.swing.*; +import java.awt.*; + +public class FormPanel extends JPanel { + int row=0; + static final int MAXIMUM_LINES=300; + public FormPanel() + { + setLayout(new GridBagLayout()) ; + + + GridBagConstraints constraint=new GridBagConstraints(); + constraint.weightx = 1.0; + constraint.weighty = 1.0; + constraint.gridy=MAXIMUM_LINES; + constraint.gridx=0; + constraint.gridwidth=2; + add(Box.createVerticalGlue(),constraint); + row++; + } + public void add(JComponent name,JComponent element) + { + GridBagConstraints constraint=new GridBagConstraints(); + constraint.ipadx = 5; + constraint.ipady = 5; + constraint.weightx = 1.0; + constraint.weighty = 0.0; + constraint.gridy=row; + constraint.gridx=0; + constraint.anchor=GridBagConstraints.NORTHWEST; + add(name,constraint); + constraint.gridy=row; + constraint.gridx=1; + constraint.fill=GridBagConstraints.HORIZONTAL; + constraint.anchor=GridBagConstraints.NORTHEAST; + add(element,constraint); + + row++; + } + public void add(String name,JComponent element) + { + add(new JLabel(name),element); + } + public void add(JComponent element) + { + GridBagConstraints constraint=new GridBagConstraints(); + constraint.ipadx = 5; + constraint.ipady = 5; + constraint.weightx = 1.0; + constraint.weighty = 0.0; + constraint.gridy=row; + constraint.gridx=0; + constraint.gridwidth=2; + constraint.fill=GridBagConstraints.HORIZONTAL; + constraint.anchor=GridBagConstraints.NORTHEAST; + add(element,constraint); + + row++; + } + +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java index 26f9f30923d..38c7168f807 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java @@ -24,20 +24,18 @@ public class ItemEdit extends JComponent { { setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); - JPanel parameters=new JPanel(); + FormPanel parameters=new FormPanel(); parameters.setBorder(BorderFactory.createTitledBorder("Parameter")); - parameters.setLayout(new GridLayout(6,2)) ; - parameters.add(new JLabel("Name:")); parameters.add(nameField); - parameters.add(new JLabel("equipmentSlot:")); parameters.add(equipmentSlot); - parameters.add(new JLabel("description:")); parameters.add(description); - parameters.add(new JLabel("iconName")); parameters.add(iconName); - parameters.add(new JLabel("questItem")); parameters.add(questItem); - parameters.add(new JLabel("cost")); parameters.add(cost); + parameters.add("Name:",nameField); + parameters.add("equipmentSlot:",equipmentSlot); + parameters.add("description:",description); + parameters.add("iconName",iconName); + parameters.add("questItem",questItem); + parameters.add("cost",cost); add(parameters); add(effect); - add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); nameField.getDocument().addDocumentListener(new DocumentChangeListener(() -> ItemEdit.this.updateItem())); equipmentSlot.getDocument().addDocumentListener(new DocumentChangeListener(() -> ItemEdit.this.updateItem())); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java index 045777feb94..cc7daa8ce70 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java @@ -25,20 +25,18 @@ public class PointOfInterestEdit extends JComponent { { setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); - JPanel parameters=new JPanel(); + FormPanel parameters=new FormPanel(); parameters.setBorder(BorderFactory.createTitledBorder("Parameter")); - parameters.setLayout(new GridLayout(7,2)) ; - parameters.add(new JLabel("Name:")); parameters.add(name); - parameters.add(new JLabel("Type:")); parameters.add(type); - parameters.add(new JLabel("Count:")); parameters.add(count); - parameters.add(new JLabel("Sprite atlas:")); parameters.add(spriteAtlas); - parameters.add(new JLabel("Sprite:")); parameters.add(sprite); - parameters.add(new JLabel("Map:")); parameters.add(map); - parameters.add(new JLabel("Radius factor:")); parameters.add(radiusFactor); + parameters.add("Name:",name); + parameters.add("Type:",type); + parameters.add("Count:",count); + parameters.add("Sprite atlas:",spriteAtlas); + parameters.add("Sprite:",sprite); + parameters.add("Map:",map); + parameters.add("Radius factor:",radiusFactor); add(parameters); - add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); name.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); type.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/RewardEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/RewardEdit.java index 317d9784c60..076261013ce 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/RewardEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/RewardEdit.java @@ -13,7 +13,7 @@ import java.util.Arrays; /** * Editor class to edit configuration, maybe moved or removed */ -public class RewardEdit extends JComponent { +public class RewardEdit extends FormPanel { RewardData currentData; JComboBox typeField =new JComboBox(new String[] { "card", "gold", "life", "deckCard", "item"}); @@ -36,24 +36,23 @@ public class RewardEdit extends JComponent { public RewardEdit() { - setLayout(new GridLayout(16,2)); - add(new JLabel("Type:")); add(typeField); - add(new JLabel("probability:")); add(probability); - add(new JLabel("count:")); add(count); - add(new JLabel("addMaxCount:")); add(addMaxCount); - add(new JLabel("cardName:")); add(cardName); - add(new JLabel("itemName:")); add(itemName); - add(new JLabel("editions:")); add(editions); - add(new JLabel("colors:")); add(colors); - add(new JLabel("rarity:")); add(rarity); - add(new JLabel("subTypes:")); add(subTypes); - add(new JLabel("cardTypes:")); add(cardTypes); - add(new JLabel("superTypes:")); add(superTypes); - add(new JLabel("manaCosts:")); add(manaCosts); - add(new JLabel("keyWords:")); add(keyWords); - add(new JLabel("colorType:")); add(colorType); - add(new JLabel("cardText:")); add(cardText); + add("Type:",typeField); + add("probability:",probability); + add("count:",count); + add("addMaxCount:",addMaxCount); + add("cardName:",cardName); + add("itemName:",itemName); + add("editions:",editions); + add("colors:",colors); + add("rarity:",rarity); + add("subTypes:",subTypes); + add("cardTypes:",cardTypes); + add("superTypes:",superTypes); + add("manaCosts:",manaCosts); + add("keyWords:",keyWords); + add("colorType:",colorType); + add("cardText:",cardText); typeField.addActionListener((e -> RewardEdit.this.updateReward())); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java index 367a7d35778..9181f6392df 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java @@ -153,7 +153,10 @@ public class StructureEditor extends JComponent{ currentData=data; model.clear(); if(data==null||data.structures==null) + { + edit.setCurrentStructure(null,null); return; + } for (int i=0;i WorldEditor.this.save()); + toolBar.add(newButton); + + newButton=new JButton("save selected biome"); + newButton.addActionListener(e -> WorldEditor.this.saveBiome()); toolBar.add(newButton); newButton=new JButton("load"); @@ -165,6 +161,15 @@ public class WorldEditor extends JComponent { } } + void saveBiome() + { + + edit.updateTerrain(); + Json json = new Json(JsonWriter.OutputType.json); + FileHandle handle = Config.instance().getFile(currentData.biomesNames[list.getSelectedIndex()]); + handle.writeString(json.prettyPrint(json.toJson(edit.currentData, BiomeData.class)),false); + + } void save() { currentData.width=width.intValue(); @@ -175,11 +180,11 @@ public class WorldEditor extends JComponent { currentData.tileSize=tileSize.intValue(); currentData.biomesSprites=biomesSprites.getText(); currentData.maxRoadDistance=maxRoadDistance.floatValue(); - currentData.biomesNames= Arrays.asList(biomesNames.getList()); + currentData.biomesNames= (biomesNames.getList()); Json json = new Json(JsonWriter.OutputType.json); FileHandle handle = Config.instance().getFile(Paths.WORLD); - handle.writeString(json.prettyPrint(json.toJson(currentData,Array.class, WorldData.class)),false); + handle.writeString(json.prettyPrint(json.toJson(currentData, WorldData.class)),false); } void load() diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java index 61a2b1a5193..dd08b4443fc 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java @@ -28,8 +28,8 @@ public class BiomeData implements Serializable { public String color; public boolean invertHeight; public String[] spriteNames; - public List enemies; - public List pointsOfInterest; + public String[] enemies; + public String[] pointsOfInterest; public BiomeStructureData[] structures; private ArrayList enemyList; @@ -46,8 +46,13 @@ public class BiomeData implements Serializable { if (enemies == null) return enemyList; for (EnemyData data : new Array.ArrayIterator<>(WorldData.getAllEnemies())) { - if (enemies.contains(data.name)) { - enemyList.add(data); + for (String enemyName:enemies) + { + if(data.name.equals(enemyName)) + { + enemyList.add(data); + break; + } } } } @@ -61,8 +66,13 @@ public class BiomeData implements Serializable { return pointOfInterestList; Array allTowns = PointOfInterestData.getAllPointOfInterest(); for (PointOfInterestData data : new Array.ArrayIterator<>(allTowns)) { - if (pointsOfInterest.contains(data.name)) { - pointOfInterestList.add(data); + for (String poiName:pointsOfInterest) + { + if(data.name.equals(poiName)) + { + pointOfInterestList.add(data); + break; + } } } } diff --git a/forge-gui-mobile/src/forge/adventure/data/WorldData.java b/forge-gui-mobile/src/forge/adventure/data/WorldData.java index a6df717a386..16ae480c029 100644 --- a/forge-gui-mobile/src/forge/adventure/data/WorldData.java +++ b/forge-gui-mobile/src/forge/adventure/data/WorldData.java @@ -27,7 +27,7 @@ public class WorldData implements Serializable { public BiomeData roadTileset; public String biomesSprites; public float maxRoadDistance; - public List biomesNames; + public String[] biomesNames; private BiomeSprites sprites; diff --git a/forge-gui/res/adventure/Shandalar/world/green.json b/forge-gui/res/adventure/Shandalar/world/green.json index 8cda1b185dd..f33e6c135c3 100644 --- a/forge-gui/res/adventure/Shandalar/world/green.json +++ b/forge-gui/res/adventure/Shandalar/world/green.json @@ -1,52 +1,108 @@ -{ - "startPointX": 0.22, - "startPointY": 0.43, - "name": "green", - "noiseWeight": 0.5, - "distWeight": 1.5, - "tilesetName":"Green", - "tilesetAtlas":"world/tilesets/terrain.atlas", - "terrain":[ - { - "spriteName":"Green_1", - "min": 0, - "max": 0.2, - "resolution": 10 - },{ - "spriteName":"Green_2", - "min": 0.8, - "max": 1.0, - "resolution": 10 - } - ], - "structures":[ - { - "sourcePath" : "world/tilesets/forestSource.png", - "structureAtlasPath":"world/tilesets/structures.atlas", - "mappingInfo":[ - { - "name":"Forest", - "color":"007000" - } - ], - "x": 0.5, - "y": 0.5, - "width": 0.3 , - "height": 0.3 - } - ], - "width": 0.7, - "height": 0.7, - "color": "59a650", - "spriteNames":[ "WoodTree","WoodTree2","Bush","Stump","Moss","Stone","Flower","Wood"] , - "enemies":[ "Ape","Bear","Centaur","Centaur Warrior","Dino","Eldraine Faerie","Elf","Elf warrior","Elk","Faerie","Giant Spider","Gorgon","Gorgon 2","Green Beast","Green Wiz1","Green Wiz2","Green Wiz3","High Elf","Hydra","Satyr","Snake","Spider","Treefolk","Treefolk Guardian","Viper","Werewolf","Wurm" ] , - "pointsOfInterest":[ - "Green Castle", - "Forest Town", - "ElfTown", - "WurmPond", - "Grove", "Grove1", "Grove2", "Grove3", "Grove4", "Grove5", "Grove6", "Grove7", "Grove8", - "CatLairG", "CatLairG1", "CatLairG2", - "CaveG", "CaveG1", "CaveG2", "CaveG3", "CaveG4", "CaveG5", "CaveG6", "CaveG8", "CaveG9", "CaveGB" - ] +{ +"startPointX": 0.22, +"startPointY": 0.43, +"noiseWeight": 0.5, +"distWeight": 1.5, +"name": "green", +"tilesetAtlas": "world/tilesets/terrain.atlas", +"tilesetName": "Green", +"terrain": [ + { + "spriteName": "Green_1", + "max": 0.2, + "resolution": 10 + }, + { + "spriteName": "Green_2", + "min": 0.8, + "max": 1, + "resolution": 10 + } +], +"width": 0.7, +"height": 0.7, +"color": "59a650", +"spriteNames": [ + "WoodTree", + "WoodTree2", + "Bush", + "Stump", + "Moss", + "Stone", + "Flower", + "Wood" +], +"enemies": [ + "Ape", + "Bear", + "Centaur", + "Centaur Warrior", + "Dino", + "Eldraine Faerie", + "Elf", + "Elf warrior", + "Elk", + "Faerie", + "Giant Spider", + "Gorgon", + "Gorgon 2", + "Green Beast", + "Green Wiz1", + "Green Wiz2", + "Green Wiz3", + "High Elf", + "Hydra", + "Satyr", + "Snake", + "Spider", + "Treefolk", + "Treefolk Guardian", + "Viper", + "Werewolf", + "Wurm" +], +"pointsOfInterest": [ + "Green Castle", + "Forest Town", + "ElfTown", + "WurmPond", + "Grove", + "Grove1", + "Grove2", + "Grove3", + "Grove4", + "Grove5", + "Grove6", + "Grove7", + "Grove8", + "CatLairG", + "CatLairG1", + "CatLairG2", + "CaveG", + "CaveG1", + "CaveG2", + "CaveG3", + "CaveG4", + "CaveG5", + "CaveG6", + "CaveG8", + "CaveG9", + "CaveGB" +], +"structures": [ + { + "x": 0.5, + "y": 0.5, + "structureAtlasPath": "world/tilesets/structures.atlas", + "sourcePath": "world/tilesets/forestSource.png", + "height": 0.3, + "width": 0.3, + "mappingInfo": [ + { + "name": "Forest", + "color": "007000" + } + ] + } +] } \ No newline at end of file diff --git a/forge-gui/res/adventure/Shandalar/world/world.json b/forge-gui/res/adventure/Shandalar/world/world.json index b81be8b8a79..66fec550a30 100644 --- a/forge-gui/res/adventure/Shandalar/world/world.json +++ b/forge-gui/res/adventure/Shandalar/world/world.json @@ -1,16 +1,24 @@ { "width": 700, "height": 700, -"playerStartPosY": 0.495, "playerStartPosX": 0.5025, -"noiseZoomBiome": 30, -"tileSize": 16, -"maxRoadDistance": 1000, -"roadTileset":{ - "tilesetName":"Road", - "tilesetAtlas":"world/tilesets/terrain.atlas", - "color": "ffffff" +"playerStartPosY": 0.495, +"noiseZoomBiome": 30, +"tileSize": 16, +"roadTileset": { + "tilesetAtlas": "world/tilesets/terrain.atlas", + "tilesetName": "Road", + "color": "ffffff" }, -"biomesSprites":"world/sprites/map_sprites.json", -"biomesNames": [ "world/base.json","world/waste.json","world/white.json","world/blue.json","world/black.json","world/red.json","world/green.json"] +"biomesSprites": "world/sprites/map_sprites.json", +"maxRoadDistance": 1000, +"biomesNames": [ + "world/base.json", + "world/waste.json", + "world/white.json", + "world/blue.json", + "world/black.json", + "world/red.json", + "world/green.json" +] } \ No newline at end of file From ca30c319758d8f32933578d87e9dc954b15658bf Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 4 Aug 2022 19:28:45 +0200 Subject: [PATCH 10/66] View fix --- .../forge/game/ability/effects/AnimateEffectBase.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java index 6df27fae809..02df76cee8b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java @@ -65,10 +65,6 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect { source.addRemembered(c); } - if ((power != null) || (toughness != null)) { - c.addNewPT(power, toughness, timestamp, 0); - } - if (!addType.isEmpty() || !removeType.isEmpty() || addAllCreatureTypes || removeSuperTypes || removeCardTypes || removeSubTypes || removeLandTypes || removeCreatureTypes || removeArtifactTypes || removeEnchantmentTypes) { c.addChangedCardTypes(addType, removeType, addAllCreatureTypes, removeSuperTypes, removeCardTypes, removeSubTypes, @@ -77,6 +73,11 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect { c.addChangedCardKeywords(keywords, removeKeywords, removeAll, timestamp, 0); + // do this after changing types in case it wasn't a creature before + if (power != null || toughness != null) { + c.addNewPT(power, toughness, timestamp, 0); + } + if (sa.hasParam("CantHaveKeyword")) { c.addCantHaveKeyword(timestamp, Keyword.setValueOf(sa.getParam("CantHaveKeyword"))); } From f1fb414ebe7c6501e4ab1c7a7774522b92028b58 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 4 Aug 2022 19:29:22 +0200 Subject: [PATCH 11/66] Fix targeting abilities --- forge-gui/res/cardsfolder/e/ersatz_gnomes.txt | 2 +- forge-gui/res/cardsfolder/f/failure_comply.txt | 2 +- forge-gui/res/cardsfolder/g/gales_redirection.txt | 2 +- forge-gui/res/cardsfolder/h/hullbreaker_horror.txt | 2 +- forge-gui/res/cardsfolder/o/obscura_interceptor.txt | 2 +- forge-gui/res/cardsfolder/p/parallectric_feedback.txt | 2 +- forge-gui/res/cardsfolder/r/refuse_cooperate.txt | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/forge-gui/res/cardsfolder/e/ersatz_gnomes.txt b/forge-gui/res/cardsfolder/e/ersatz_gnomes.txt index 8cae6a8194b..4a3dfbeab8a 100644 --- a/forge-gui/res/cardsfolder/e/ersatz_gnomes.txt +++ b/forge-gui/res/cardsfolder/e/ersatz_gnomes.txt @@ -2,7 +2,7 @@ Name:Ersatz Gnomes ManaCost:3 Types:Artifact Creature Gnome PT:1/1 -A:AB$ Animate | Cost$ T | Colors$ Colorless | OverwriteColors$ True | ValidTgts$ Card | TgtZone$ Stack | TgtPrompt$ Select target spell to make colorless | Duration$ Permanent | SpellDescription$ Target spell becomes colorless. +A:AB$ Animate | Cost$ T | Colors$ Colorless | OverwriteColors$ True | ValidTgts$ Card | TargetType$ Spell | TgtZone$ Stack | TgtPrompt$ Select target spell to make colorless | Duration$ Permanent | SpellDescription$ Target spell becomes colorless. A:AB$ Animate | Cost$ T | Colors$ Colorless | OverwriteColors$ True | ValidTgts$ Permanent | TgtPrompt$ Select target permanent to make colorless | SpellDescription$ Target permanent becomes colorless until end of turn. AI:RemoveDeck:Random AI:RemoveDeck:All diff --git a/forge-gui/res/cardsfolder/f/failure_comply.txt b/forge-gui/res/cardsfolder/f/failure_comply.txt index 78065f5ff40..e4e38eac007 100644 --- a/forge-gui/res/cardsfolder/f/failure_comply.txt +++ b/forge-gui/res/cardsfolder/f/failure_comply.txt @@ -1,7 +1,7 @@ Name:Failure ManaCost:1 U Types:Instant -A:SP$ ChangeZone | Cost$ 1 U | ValidTgts$ Card | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Destination$ Hand | SpellDescription$ Return target spell to its owner's hand. +A:SP$ ChangeZone | Cost$ 1 U | ValidTgts$ Card | TargetType$ Spell | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Destination$ Hand | SpellDescription$ Return target spell to its owner's hand. AlternateMode:Split Oracle:Return target spell to its owner's hand. diff --git a/forge-gui/res/cardsfolder/g/gales_redirection.txt b/forge-gui/res/cardsfolder/g/gales_redirection.txt index 2d85425ef4d..7ed1a535b27 100644 --- a/forge-gui/res/cardsfolder/g/gales_redirection.txt +++ b/forge-gui/res/cardsfolder/g/gales_redirection.txt @@ -1,7 +1,7 @@ Name:Gale's Redirection ManaCost:3 U U Types:Instant -A:SP$ ChangeZone | ValidTgts$ Card | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Destination$ Exile | TgtPrompt$ Choose target spell to exile | RememberChanged$ True | SubAbility$ DBRoll | SpellDescription$ Exile target spell. +A:SP$ ChangeZone | ValidTgts$ Card | TargetType$ Spell | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Destination$ Exile | TgtPrompt$ Choose target spell to exile | RememberChanged$ True | SubAbility$ DBRoll | SpellDescription$ Exile target spell. SVar:DBRoll:DB$ RollDice | Sides$ 20 | Modifier$ Y | ResultSubAbilities$ 1-14:DBMayPlay,Else:DBMayPlayWithoutCost | StackDescription$ SpellDescription | SpellDescription$ Roll a d20 and add that spell's mana value. SVar:DBMayPlay:DB$ Effect | StaticAbilities$ STPlay | RememberObjects$ Remembered | Duration$ Permanent | ExileOnMoved$ Exile | SubAbility$ DBCleanup | SpellDescription$ 1—14 VERT You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast it. SVar:DBMayPlayWithoutCost:DB$ Effect | StaticAbilities$ STPlayWithoutCost | RememberObjects$ Remembered | Duration$ Permanent | ExileOnMoved$ Exile | SubAbility$ DBCleanup | SpellDescription$ 15+ VERT You may cast that card without paying its mana cost for as long as it remains exiled. diff --git a/forge-gui/res/cardsfolder/h/hullbreaker_horror.txt b/forge-gui/res/cardsfolder/h/hullbreaker_horror.txt index 2767f547ed7..3954ba50c29 100644 --- a/forge-gui/res/cardsfolder/h/hullbreaker_horror.txt +++ b/forge-gui/res/cardsfolder/h/hullbreaker_horror.txt @@ -6,6 +6,6 @@ K:Flash K:This spell can't be countered. T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | Execute$ TrigCharm | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast a spell, ABILITY SVar:TrigCharm:DB$ Charm | Choices$ ControlReturn,ControlBounce | MinCharmNum$ 0 | CharmNum$ 1 -SVar:ControlReturn:DB$ ChangeZone | ValidTgts$ Card.YouDontCtrl | TgtPrompt$ Select target spell you don't control | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Destination$ Hand | SpellDescription$ Return target spell you don't control to its owner's hand. +SVar:ControlReturn:DB$ ChangeZone | ValidTgts$ Card.YouDontCtrl | TargetType$ Spell | TgtPrompt$ Select target spell you don't control | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Destination$ Hand | SpellDescription$ Return target spell you don't control to its owner's hand. SVar:ControlBounce:DB$ ChangeZone | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | TgtZone$ Battlefield | Origin$ Battlefield | Destination$ Hand | SpellDescription$ Return target nonland permanent to its owner's hand. Oracle:Flash\nThis spell can't be countered.\nWhenever you cast a spell, choose up to one —\n• Return target spell you don't control to its owner's hand.\n• Return target nonland permanent to its owner's hand. diff --git a/forge-gui/res/cardsfolder/o/obscura_interceptor.txt b/forge-gui/res/cardsfolder/o/obscura_interceptor.txt index ec64d336b6c..0d0d562f9ef 100644 --- a/forge-gui/res/cardsfolder/o/obscura_interceptor.txt +++ b/forge-gui/res/cardsfolder/o/obscura_interceptor.txt @@ -7,6 +7,6 @@ K:Lifelink T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigConnive | TriggerDescription$ When CARDNAME enters the battlefield, it connives. When it connives this way, return up to one target spell to its owner's hand. (To have a creature connive, draw a card, then discard a card. If you discarded a nonland card, put a +1/+1 counter on that creature.) SVar:TrigConnive:DB$ Connive | SubAbility$ DBImmediateTrigger SVar:DBImmediateTrigger:DB$ ImmediateTrigger | Execute$ TrigReturn | TriggerDescription$ When it connives this way, return up to one target spell to its owner's hand. -SVar:TrigReturn:DB$ ChangeZone | ValidTgts$ Card | TgtPrompt$ Select target spell | TargetMax$ 1 | TargetMin$ 0 | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Destination$ Hand +SVar:TrigReturn:DB$ ChangeZone | ValidTgts$ Card | TgtPrompt$ Select target spell | TargetMax$ 1 | TargetMin$ 0 | TgtZone$ Stack | TargetType$ Spell | Origin$ Stack | Fizzle$ True | Destination$ Hand DeckHas:Ability$LifeGain|Discard|Counters Oracle:Flash\nLifelink\nWhen Obscura Interceptor enters the battlefield, it connives. When it connives this way, return up to one target spell to its owner's hand. (To have a creature connive, draw a card, then discard a card. If you discarded a nonland card, put a +1/+1 counter on that creature.) diff --git a/forge-gui/res/cardsfolder/p/parallectric_feedback.txt b/forge-gui/res/cardsfolder/p/parallectric_feedback.txt index 09eb1bdd488..cbc1450ac24 100644 --- a/forge-gui/res/cardsfolder/p/parallectric_feedback.txt +++ b/forge-gui/res/cardsfolder/p/parallectric_feedback.txt @@ -1,7 +1,7 @@ Name:Parallectric Feedback ManaCost:3 R Types:Instant -A:SP$ Pump | Cost$ 3 R | ValidTgts$ Card | TgtZone$ Stack | TgtPrompt$ Select target spell | PumpZone$ Stack | StackDescription$ None | SubAbility$ DBDmg | SpellDescription$ CARDNAME deals damage to target spell's controller equal to that spell's mana value. +A:SP$ Pump | Cost$ 3 R | ValidTgts$ Card | TargetType$ Spell | TgtZone$ Stack | TgtPrompt$ Select target spell | PumpZone$ Stack | StackDescription$ None | SubAbility$ DBDmg | SpellDescription$ CARDNAME deals damage to target spell's controller equal to that spell's mana value. SVar:DBDmg:DB$ DealDamage | Defined$ TargetedController | NumDmg$ X SVar:X:Targeted$CardManaCost AI:RemoveDeck:All diff --git a/forge-gui/res/cardsfolder/r/refuse_cooperate.txt b/forge-gui/res/cardsfolder/r/refuse_cooperate.txt index d6c4e708630..6f1e84ff971 100644 --- a/forge-gui/res/cardsfolder/r/refuse_cooperate.txt +++ b/forge-gui/res/cardsfolder/r/refuse_cooperate.txt @@ -1,7 +1,7 @@ Name:Refuse ManaCost:3 R Types:Instant -A:SP$ Pump | Cost$ 3 R | ValidTgts$ Card | TgtZone$ Stack | TgtPrompt$ Select target spell | PumpZone$ Stack | StackDescription$ None | SubAbility$ DBDmg | SpellDescription$ CARDNAME deals damage to target spell's controller equal to that spell's mana value. +A:SP$ Pump | Cost$ 3 R | ValidTgts$ Card | TargetType$ Spell | TgtZone$ Stack | TgtPrompt$ Select target spell | PumpZone$ Stack | StackDescription$ None | SubAbility$ DBDmg | SpellDescription$ CARDNAME deals damage to target spell's controller equal to that spell's mana value. SVar:DBDmg:DB$ DealDamage | Defined$ TargetedController | NumDmg$ X SVar:X:Targeted$CardManaCost AI:RemoveDeck:All From 189149eb903b14237aa6fc34faddba020149e5d6 Mon Sep 17 00:00:00 2001 From: Simisays <67333662+Simisays@users.noreply.github.com> Date: Thu, 4 Aug 2022 21:09:18 +0200 Subject: [PATCH 12/66] Create syndicate_recruiter.txt --- forge-gui/res/cardsfolder/s/syndicate_recruiter.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 forge-gui/res/cardsfolder/s/syndicate_recruiter.txt diff --git a/forge-gui/res/cardsfolder/s/syndicate_recruiter.txt b/forge-gui/res/cardsfolder/s/syndicate_recruiter.txt new file mode 100644 index 00000000000..3315aff5c26 --- /dev/null +++ b/forge-gui/res/cardsfolder/s/syndicate_recruiter.txt @@ -0,0 +1,11 @@ +Name:Syndicate Recruiter +ManaCost: 2 U B +Types:Creature Vampire Assassin +PT:4/5 +K:Flying +K:Ward:1 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMill | TriggerZones$ Battlefield | TriggerDescription$ When CARDNAME enters the battlefield, mill four cards. Then if there are five or more mana values among cards in your graveyard, conjure a card named Dig Up the Body into your hand. +SVar:TrigMill:DB$ Mill | NumCards$ 4 | Defined$ You | SubAbility$ DBConjure +SVar:DBConjure:DB$ MakeCard | ConditionCheckSVar$ X | ConditionSVarCompare$ GE5 | Name$ Dig Up the Body | Zone$ Hand +SVar:X:Count$ValidGraveyard Card.YouOwn$DifferentCMC +Oracle:Flying\nWard 1\nWhenever Syndicate Recruiter enters the battlefield, mill four cards. Then if there are five or more mana values among cards in your graveyard, conjure a card named Dig Up the Body into your hand. From e75c456524a067b54145eddebe390ef517df9d90 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 4 Aug 2022 21:23:16 +0200 Subject: [PATCH 13/66] Extort fix --- forge-game/src/main/java/forge/game/card/CardFactoryUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index 0d68aae35db..551c18a6290 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1131,7 +1131,7 @@ public class CardFactoryUtil { SpellAbility loseLifeSA = AbilityFactory.getAbility(loseLifeStr, card); AbilitySub gainLifeSA = (AbilitySub) AbilityFactory.getAbility(gainLifeStr, card); - gainLifeSA.setSVar("AFLifeLost", "Number$0"); + loseLifeSA.setSVar("AFLifeLost", "Number$0"); loseLifeSA.setSubAbility(gainLifeSA); loseLifeSA.setIntrinsic(intrinsic); From caad3bff44112125266c2aef5ac295281597c20f Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 4 Aug 2022 23:04:35 +0200 Subject: [PATCH 14/66] Fix logic from refactoring --- forge-ai/src/main/java/forge/ai/ComputerUtilCost.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java index 1c1b88a4313..e2c2998c1a7 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java @@ -778,9 +778,12 @@ public class ComputerUtilCost { // Check if the AI intends to play the card and if it can pay for it with the mana it has boolean willPlay = ComputerUtil.hasReasonToPlayCardThisTurn(payer, c); boolean canPay = c.getManaCost().canBePaidWithAvailable(ColorSet.fromNames(getAvailableManaColors(payer, source)).getColor()); - return canPay && willPlay; + if (canPay && willPlay) { + return true; + } } } + return false; } } } From efc5002bb7a07ed23885ad9ade28f0e05573d064 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Fri, 5 Aug 2022 06:46:02 +0800 Subject: [PATCH 15/66] minor adjustments on tooltips --- .../src/forge/adventure/scene/RewardScene.java | 12 +++++++----- .../src/forge/adventure/util/RewardActor.java | 4 ++-- forge-gui-mobile/src/forge/assets/Assets.java | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java index eee8d441ce3..fbbac29703e 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java @@ -222,9 +222,9 @@ public class RewardScene extends UIScene { float mul = fW/fH < AR ? AR/(fW/fH) : (fW/fH)/AR; if (fW/fH >= 2f) {//tall display mul = (fW/fH) - ((fW/fH)/AR); - if ((fW/fH) >= 2.1f && (fW/fH) < 2.3f) + if ((fW/fH) >= 2.1f && (fW/fH) < 2.2f) mul *= 0.9f; - else if ((fW/fH) > 2.3) //ultrawide 21:9 Galaxy Fold, Huawei X2, Xperia 1 + else if ((fW/fH) > 2.2f) //ultrawide 21:9 Galaxy Fold, Huawei X2, Xperia 1 mul *= 0.8f; } cardHeight = bestCardHeight * 0.90f ; @@ -232,10 +232,12 @@ public class RewardScene extends UIScene { mul *= Forge.isLandscapeMode() ? 0.95f : 1.05f; } else { //immersive | no navigation and/or showing cutout cam - if (fW/fH > 2.3f) + if (fW/fH > 2.2f) mul *= Forge.isLandscapeMode() ? 1.1f : 1.6f; - else if (fW/fH > 2f) - mul *= Forge.isLandscapeMode() ? 1.1f : 1.5f; + else if (fW/fH >= 2.1f) + mul *= Forge.isLandscapeMode() ? 1.05f : 1.5f; + else if (fW/fH >= 2f) + mul *= Forge.isLandscapeMode() ? 1f : 1.4f; } cardWidth = (cardHeight / CARD_WIDTH_TO_HEIGHT)*mul; diff --git a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java index e19d9aa93ee..5d5289a4253 100644 --- a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java +++ b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java @@ -363,9 +363,9 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb float mul = fW/fH < AR ? AR/(fW/fH) : (fW/fH)/AR; if (fW/fH >= 2f) {//tall display mul = (fW/fH) - ((fW/fH)/AR); - if ((fW/fH) >= 2.1f && (fW/fH) < 2.3f) + if ((fW/fH) >= 2.1f && (fW/fH) < 2.2f) mul *= 0.9f; - else if ((fW/fH) > 2.3) //ultrawide 21:9 Galaxy Fold, Huawei X2, Xperia 1 + else if ((fW/fH) > 2.2f) //ultrawide 21:9 Galaxy Fold, Huawei X2, Xperia 1 mul *= 0.8f; } if (Forge.isLandscapeMode()) diff --git a/forge-gui-mobile/src/forge/assets/Assets.java b/forge-gui-mobile/src/forge/assets/Assets.java index a75d067eebf..b03906603ee 100644 --- a/forge-gui-mobile/src/forge/assets/Assets.java +++ b/forge-gui-mobile/src/forge/assets/Assets.java @@ -42,7 +42,7 @@ public class Assets implements Disposable { private ObjectMap tmxMap; private Texture defaultImage, dummy; private TextureParameter textureParameter; - private int cGen = 0, cGenVal = 0, cFB = 0, cFBVal = 0, cTM, cTMVal = 0, cSF = 0, cSFVal = 0, cCF = 0, cCFVal = 0, aDF = 0, cDFVal = 0; + private int cGen = 0, cGenVal = 0, cFB = 0, cFBVal = 0, cTM = 0, cTMVal = 0, cSF = 0, cSFVal = 0, cCF = 0, cCFVal = 0, aDF = 0, cDFVal = 0; public Assets() { //init titlebg fallback fallback_skins().put(0, new Texture(GuiBase.isAndroid() From 745d71745e5d2740f7a1c5ac6b8402bc0da29e6f Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Fri, 5 Aug 2022 10:26:32 +0800 Subject: [PATCH 16/66] setting for card display/tooltip on adventure rewards/shops - add support for various display aspect ratio --- .../src/forge/adventure/data/SettingData.java | 2 + .../forge/adventure/scene/RewardScene.java | 23 +++++++---- .../forge/adventure/scene/SettingsScene.java | 41 +++++++++++++++++++ .../src/forge/adventure/util/Config.java | 6 +++ .../src/forge/adventure/util/Controls.java | 21 ++++++++++ .../src/forge/adventure/util/RewardActor.java | 16 +++++--- 6 files changed, 94 insertions(+), 15 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/data/SettingData.java b/forge-gui-mobile/src/forge/adventure/data/SettingData.java index 018d3d42abd..253d078fab6 100644 --- a/forge-gui-mobile/src/forge/adventure/data/SettingData.java +++ b/forge-gui-mobile/src/forge/adventure/data/SettingData.java @@ -14,4 +14,6 @@ public class SettingData { public boolean fullScreen; public String videomode; public String lastActiveSave; + public Float rewardCardAdj; + public Float cardTooltipAdj; } diff --git a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java index fbbac29703e..28faa6e8b06 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java @@ -14,6 +14,7 @@ import forge.adventure.player.AdventurePlayer; import forge.adventure.pointofintrest.PointOfInterestChanges; import forge.adventure.stage.GameHUD; import forge.adventure.util.CardUtil; +import forge.adventure.util.Config; import forge.adventure.util.Current; import forge.adventure.util.Reward; import forge.adventure.util.RewardActor; @@ -228,17 +229,21 @@ public class RewardScene extends UIScene { mul *= 0.8f; } cardHeight = bestCardHeight * 0.90f ; - if (realX > x || realY > y) { - mul *= Forge.isLandscapeMode() ? 0.95f : 1.05f; + if (Config.instance().getSettingData().rewardCardAdj != 1f) { + mul *= Config.instance().getSettingData().rewardCardAdj; } else { - //immersive | no navigation and/or showing cutout cam - if (fW/fH > 2.2f) - mul *= Forge.isLandscapeMode() ? 1.1f : 1.6f; - else if (fW/fH >= 2.1f) - mul *= Forge.isLandscapeMode() ? 1.05f : 1.5f; - else if (fW/fH >= 2f) - mul *= Forge.isLandscapeMode() ? 1f : 1.4f; + if (realX > x || realY > y) { + mul *= Forge.isLandscapeMode() ? 0.95f : 1.05f; + } else { + //immersive | no navigation and/or showing cutout cam + if (fW/fH > 2.2f) + mul *= Forge.isLandscapeMode() ? 1.1f : 1.6f; + else if (fW/fH >= 2.1f) + mul *= Forge.isLandscapeMode() ? 1.05f : 1.5f; + else if (fW/fH >= 2f) + mul *= Forge.isLandscapeMode() ? 1f : 1.4f; + } } cardWidth = (cardHeight / CARD_WIDTH_TO_HEIGHT)*mul; diff --git a/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java b/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java index 4f7dae601c9..21b42a8c6c1 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java @@ -188,6 +188,34 @@ public class SettingsScene extends UIScene { }); addLabel(Forge.getLocalizer().getMessage("lblVideoMode")); settingGroup.add(videomode).align(Align.right).pad(2); + } + SelectBox rewardCardAdj = Controls.newComboBox(new Float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.8f, 1.9f, 2f}, Config.instance().getSettingData().rewardCardAdj, new Function() { + @Override + public Void apply(Object o) { + Float val = (Float) o; + if (val == null || val == 0f) + val = 1f; + Config.instance().getSettingData().rewardCardAdj = val; + Config.instance().saveSettings(); + return null; + } + }); + addLabel("Reward/Shop Card Display Ratio"); + settingGroup.add(rewardCardAdj).align(Align.right).pad(2); + SelectBox tooltipAdj = Controls.newComboBox(new Float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.8f, 1.9f, 2f}, Config.instance().getSettingData().cardTooltipAdj, new Function() { + @Override + public Void apply(Object o) { + Float val = (Float) o; + if (val == null || val == 0f) + val = 1f; + Config.instance().getSettingData().cardTooltipAdj = val; + Config.instance().saveSettings(); + return null; + } + }); + addLabel("Reward/Shop Card Tooltip Ratio"); + settingGroup.add(tooltipAdj).align(Align.right).pad(2); + if (!GuiBase.isAndroid()) { addSettingField(Forge.getLocalizer().getMessage("lblFullScreen"), Config.instance().getSettingData().fullScreen, new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -202,6 +230,19 @@ public class SettingsScene extends UIScene { } }); } + addSettingField(Forge.getLocalizer().getMessage("lblFullScreen"), Config.instance().getSettingData().fullScreen, new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + boolean value = ((CheckBox) actor).isChecked(); + Config.instance().getSettingData().fullScreen = value; + Config.instance().saveSettings(); + //update + if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_FULLSCREEN_MODE) != value) { + FModel.getPreferences().setPref(ForgePreferences.FPref.UI_LANDSCAPE_MODE, value); + FModel.getPreferences().save(); + } + } + }); addCheckBox(Forge.getLocalizer().getMessage("lblCardName"), ForgePreferences.FPref.UI_OVERLAY_CARD_NAME); addSettingSlider(Forge.getLocalizer().getMessage("cbAdjustMusicVolume"), ForgePreferences.FPref.UI_VOL_MUSIC, 0, 100); addSettingSlider(Forge.getLocalizer().getMessage("cbAdjustSoundsVolume"), ForgePreferences.FPref.UI_VOL_SOUNDS, 0, 100); diff --git a/forge-gui-mobile/src/forge/adventure/util/Config.java b/forge-gui-mobile/src/forge/adventure/util/Config.java index 9a2b7aa702d..d8847d1980f 100644 --- a/forge-gui-mobile/src/forge/adventure/util/Config.java +++ b/forge-gui-mobile/src/forge/adventure/util/Config.java @@ -64,6 +64,12 @@ public class Config { } if(settingsData.videomode == null || settingsData.videomode.isEmpty()) settingsData.videomode="720p"; + //reward card display fine tune + if(settingsData.rewardCardAdj == null || settingsData.rewardCardAdj == 0f) + settingsData.rewardCardAdj=1f; + //tooltip fine tune + if(settingsData.cardTooltipAdj == null || settingsData.cardTooltipAdj == 0f) + settingsData.cardTooltipAdj=1f; this.plane = settingsData.plane; currentConfig = this; diff --git a/forge-gui-mobile/src/forge/adventure/util/Controls.java b/forge-gui-mobile/src/forge/adventure/util/Controls.java index 88e5789fe86..6321f016c9e 100644 --- a/forge-gui-mobile/src/forge/adventure/util/Controls.java +++ b/forge-gui-mobile/src/forge/adventure/util/Controls.java @@ -52,6 +52,27 @@ public class Controls { return ret; } + static public SelectBox newComboBox(Float[] text, float item, Function func) { + SelectBox ret = new SelectBox(GetSkin()); + ret.getStyle().listStyle.selection.setTopHeight(4); + ret.setItems(text); + ret.addListener(new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + try { + func.apply(((SelectBox) actor).getSelected()); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + func.apply(item); + ret.getList().setAlignment(Align.center); + ret.setSelected(item); + ret.setAlignment(Align.right); + return ret; + } + static public TextField newTextField(String text) { return new TextField(text, GetSkin()); } diff --git a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java index 5d5289a4253..67660a9f949 100644 --- a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java +++ b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java @@ -361,12 +361,16 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb float fW = x > y ? x : y; float fH = x > y ? y : x; float mul = fW/fH < AR ? AR/(fW/fH) : (fW/fH)/AR; - if (fW/fH >= 2f) {//tall display - mul = (fW/fH) - ((fW/fH)/AR); - if ((fW/fH) >= 2.1f && (fW/fH) < 2.2f) - mul *= 0.9f; - else if ((fW/fH) > 2.2f) //ultrawide 21:9 Galaxy Fold, Huawei X2, Xperia 1 - mul *= 0.8f; + if (Config.instance().getSettingData().cardTooltipAdj != 1f) { + mul *= Config.instance().getSettingData().cardTooltipAdj; + } else { + if (fW/fH >= 2f) {//tall display + mul = (fW/fH) - ((fW/fH)/AR); + if ((fW/fH) >= 2.1f && (fW/fH) < 2.2f) + mul *= 0.9f; + else if ((fW/fH) > 2.2f) //ultrawide 21:9 Galaxy Fold, Huawei X2, Xperia 1 + mul *= 0.8f; + } } if (Forge.isLandscapeMode()) drawable.setMinSize(newW*mul, newH); From 1759a94cdc2f1ca445efa960461a06cc9afb40c1 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Fri, 5 Aug 2022 10:46:44 +0800 Subject: [PATCH 17/66] remove duplicate setting --- .../src/forge/adventure/scene/SettingsScene.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java b/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java index 21b42a8c6c1..1657f1e9c94 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java @@ -230,19 +230,6 @@ public class SettingsScene extends UIScene { } }); } - addSettingField(Forge.getLocalizer().getMessage("lblFullScreen"), Config.instance().getSettingData().fullScreen, new ChangeListener() { - @Override - public void changed(ChangeEvent event, Actor actor) { - boolean value = ((CheckBox) actor).isChecked(); - Config.instance().getSettingData().fullScreen = value; - Config.instance().saveSettings(); - //update - if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_FULLSCREEN_MODE) != value) { - FModel.getPreferences().setPref(ForgePreferences.FPref.UI_LANDSCAPE_MODE, value); - FModel.getPreferences().save(); - } - } - }); addCheckBox(Forge.getLocalizer().getMessage("lblCardName"), ForgePreferences.FPref.UI_OVERLAY_CARD_NAME); addSettingSlider(Forge.getLocalizer().getMessage("cbAdjustMusicVolume"), ForgePreferences.FPref.UI_VOL_MUSIC, 0, 100); addSettingSlider(Forge.getLocalizer().getMessage("cbAdjustSoundsVolume"), ForgePreferences.FPref.UI_VOL_SOUNDS, 0, 100); From f5959785759b8e087a8270c3ededb4b1d7ba6829 Mon Sep 17 00:00:00 2001 From: Suthro <81990938+Suthro@users.noreply.github.com> Date: Thu, 4 Aug 2022 23:20:37 -0500 Subject: [PATCH 18/66] HBG: 6 card scripts (#1267) * HBG: Calim, Djinn Emperor + 2 cards HBG: Add scripts for Calim, Oyaminartok, and You Line Up the Shot. - Calim, Djinn Emperor - Oyaminartok, Polar Werebear - You Line Up the Shot * HBG: 6 cards HBG: Add scripts for six HBG alchemy cards - Chaos Balor - Craving of Yeenoghu - Grave Choice - Hook Horror - Patriar's Humiliation - Seek New Knowledge * HBG: Signature Spells + 2 cards HBG: Add scripts for 3 HBG alchemy cards - Signature Spells - Sune's Intervention - Uthgardt Fury --- .../res/cardsfolder/upcoming/chaos_balor.txt | 22 +++++++++++++++++++ .../upcoming/craving_of_yeenoghu.txt | 13 +++++++++++ .../res/cardsfolder/upcoming/grave_choice.txt | 10 +++++++++ .../res/cardsfolder/upcoming/hook_horror.txt | 10 +++++++++ .../upcoming/patriars_humiliation.txt | 8 +++++++ .../upcoming/seek_new_knowledge.txt | 6 +++++ .../cardsfolder/upcoming/signature_spells.txt | 13 +++++++++++ .../upcoming/sunes_intervention.txt | 10 +++++++++ .../cardsfolder/upcoming/uthgardt_fury.txt | 8 +++++++ 9 files changed, 100 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/chaos_balor.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/craving_of_yeenoghu.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/grave_choice.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/hook_horror.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/patriars_humiliation.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/seek_new_knowledge.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/signature_spells.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/sunes_intervention.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/uthgardt_fury.txt diff --git a/forge-gui/res/cardsfolder/upcoming/chaos_balor.txt b/forge-gui/res/cardsfolder/upcoming/chaos_balor.txt new file mode 100644 index 00000000000..36aaed72e2d --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/chaos_balor.txt @@ -0,0 +1,22 @@ +Name:Chaos Balor +ManaCost:3 R R +Types:Creature Demon +PT:4/5 +K:Flying +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigCharm | TriggerDescription$ Whenever CARDNAME attacks or dies, ABILITY +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigCharm | Secondary$ True | TriggerDescription$ Whenever CARDNAME attacks or dies, ABILITY +SVar:TrigCharm:DB$ Charm | CharmNum$ 2 | Choices$ DiscardSeek,DamageTreasures,DamagePump | AdditionalDescription$ Each mode must target a different player. +SVar:DiscardSeek:DB$ Discard | ValidTgts$ Player | TargetUnique$ True | TgtPrompt$ Select target player to discard hand and seek | Mode$ Hand | RememberDiscarded$ True | SubAbility$ DBSeek | SpellDescription$ Target player discards all cards in their hand, then seeks that many nonland cards. +SVar:DBSeek:DB$ ChangeZone | Defined$ ParentTarget | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ X | ChangeType$ Card.nonLand | SubAbility$ DBCleanup +SVar:DamageTreasures:DB$ DealDamage | ValidTgts$ Player | TargetUnique$ True | TgtPrompt$ Select target player to take 2 damage and create two Treasures | NumDmg$ 2 | SubAbility$ DBToken | SpellDescription$ CARDNAME deals 2 damage to target player and they create two Treasure tokens. +SVar:DBToken:DB$ Token | TokenScript$ c_a_treasure_sac | TokenAmount$ 2 | TokenOwner$ ParentTarget +SVar:DamagePump:DB$ DamageAll | ValidTgts$ Player | TargetUnique$ True | NumDmg$ 2 | RememberDamaged$ True | ValidCards$ Creature | ValidDescription$ each creature target player controls. | SubAbility$ DBEffect | SpellDescription$ CARDNAME deals 2 damage to each creature target player controls. Those creatures perpetually get +2/+0. +SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ PerpetualP2P0 | Name$ Chaos Balor's Perpetual Effect | Duration$ Permanent +SVar:PerpetualP2P0:Mode$ Continuous | Affected$ Card.IsRemembered | AddPower$ 2 | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ Those creatures perpetually get +2/+0. +SVar:Update:Mode$ ChangesZone | Origin$ Any | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered | Execute$ DBUpdate +SVar:DBUpdate:DB$ UpdateRemember +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:X:Remembered$Amount +DeckHas:Type$Artifact|Treasure +DeckHints:Ability$Discard & Type$Treasure +Oracle:Flying\nWhenever Chaos Balor attacks or dies, choose two. Each mode must target a different player.\n• Target player discards all the cards in their hand, then seeks that many nonland cards.\n• Chaos Balor deals 2 damage to target player and they create two Treasure tokens.\n• Chaos Balor deals 2 damage to each creature target player controls. Those creatures perpetually get +2/+0. diff --git a/forge-gui/res/cardsfolder/upcoming/craving_of_yeenoghu.txt b/forge-gui/res/cardsfolder/upcoming/craving_of_yeenoghu.txt new file mode 100644 index 00000000000..95fcdecdc4e --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/craving_of_yeenoghu.txt @@ -0,0 +1,13 @@ +Name:Craving of Yeenoghu +ManaCost:2 R +Types:Enchantment Aura +K:Enchant creature you control +A:SP$ Attach | ValidTgts$ Creature.YouCtrl | AILogic$ Pump +S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ 3 | AddToughness$ 2 | AddKeyword$ Haste | Description$ Enchanted creature gets +3/+2, has haste, and attacks each combat if able. +S:Mode$ MustAttack | ValidCreature$ Creature.EnchantedBy +A:AB$ Pump | Cost$ R | ActivationZone$ Graveyard | ValidTgts$ Creature.YouCtrl | SorcerySpeed$ True | TgtPrompt$ Choose a creature you control | SubAbility$ DBChange | SpellDescription$ Return CARDNAME from your graveyard to the battlefield attached to target creature you control. CARDNAME perpetually gains "Enchanted creature gets -1/-1." Activate only as a sorcery. +SVar:DBChange:DB$ ChangeZone | Defined$ Self | Origin$ Graveyard | Destination$ Battlefield | AttachedTo$ ParentTarget | SpellDescription$ | StackDescription$ SpellDescription | SubAbility$ DBEffect +SVar:DBEffect:DB$ Effect | StaticAbilities$ Craving | RememberObjects$ Self | Name$ Craving of Yeenoghu's Perpetual Effect | Duration$ Permanent | StackDescription$ CARDNAME perpetually gains "Enchanted creature gets -1/-1." +SVar:Craving:Mode$ Continuous | AddStaticAbility$ Hunger | Affected$ Card.IsRemembered | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ This card perpetually gains "Enchanted creature gets -1/-1." +SVar:Hunger:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ -1 | AddToughness$ -1 | Description$ Enchanted creature gets -1/-1. +Oracle:Enchant creature you control\nEnchanted creature gets +3/+2, has haste, and attacks each combat if able.\n{R}: Return Craving of Yeenoghu from your graveyard to the battlefield attached to target creature you control. Craving of Yeenoghu perpetually gains "Enchanted creature gets -1/-1." Activate only as a sorcery. diff --git a/forge-gui/res/cardsfolder/upcoming/grave_choice.txt b/forge-gui/res/cardsfolder/upcoming/grave_choice.txt new file mode 100644 index 00000000000..52c3910c23f --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/grave_choice.txt @@ -0,0 +1,10 @@ +Name:Grave Choice +ManaCost:2 B +Types:Instant +A:SP$ Sacrifice | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | SacValid$ Creature.nonToken | SacMessage$ nontoken creature | RememberSacrificed$ True | SubAbility$ TrigConjure | SpellDescription$ Target opponent sacrifices a nontoken creature. If that creature had mana value 2 or less, conjure a duplicate of it into your hand. That duplicate perpetually gains "You may spend mana as though it were mana of any color to cast this spell." +SVar:TrigConjure:DB$ MakeCard | ConditionDefined$ Remembered | ConditionPresent$ Creature.cmcLE2 | DefinedName$ Remembered | Zone$ Hand | RememberMade$ True | SubAbility$ DBEffect +SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ PerpetualAbility | Duration$ Permanent | Name$ Grave Choice's Perpetual Effect +SVar:PerpetualAbility:Mode$ Continuous | AddStaticAbility$ SpendAnyMana | Affected$ Card.IsRemembered | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ The conjured card perpetually gains "You may spend mana as though it were mana of any color to cast this spell." +SVar:SpendAnyMana:Mode$ Continuous | Affected$ Card.Self | EffectZone$ All | AffectedZone$ Stack | AddHiddenKeyword$ May spend mana as though it were mana of any color to cast CARDNAME | Description$ You may spend mana as though it were mana of any color to cast this spell. +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +Oracle:Target opponent sacrifices a nontoken creature. If that creature had mana value 2 or less, conjure a duplicate of it into your hand. That duplicate perpetually gains "You may spend mana as though it were mana of any color to cast this spell." diff --git a/forge-gui/res/cardsfolder/upcoming/hook_horror.txt b/forge-gui/res/cardsfolder/upcoming/hook_horror.txt new file mode 100644 index 00000000000..942756d1bf8 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/hook_horror.txt @@ -0,0 +1,10 @@ +Name:Hook Horror +ManaCost:4 B +Types:Creature Horror +PT:3/3 +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigEffect | TriggerDescription$ Molting Exoskeleton — Whenever CARDNAME dies, it perpetually gets -1/-1. Then if that card's toughness is 1 or greater, return it to the battlefield under its owner’s control. +SVar:TrigEffect:DB$ Effect | StaticAbilities$ PerpetualDebuff | RememberObjects$ Self | Name$ Hook Horror's Perpetual Effect | Duration$ Permanent | SubAbility$ DBReturn +SVar:PerpetualDebuff:Mode$ Continuous | Affected$ Card.IsRemembered | AddPower$ -1 | AddToughness$ -1 | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ This creature perpetually gets -1/-1. +SVar:DBReturn:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | ConditionDefined$ TriggeredNewCardLKICopy | ConditionPresent$ Creature.toughnessGE1 | Origin$ Graveyard | Destination$ Battlefield +DeckHas:Ability$Sacrifice +Oracle:Molting Exoskeleton — Whenever Hook Horror dies, it perpetually gets -1/-1. Then if that card's toughness is 1 or greater, return it to the battlefield under its owner’s control. diff --git a/forge-gui/res/cardsfolder/upcoming/patriars_humiliation.txt b/forge-gui/res/cardsfolder/upcoming/patriars_humiliation.txt new file mode 100644 index 00000000000..6293473f7de --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/patriars_humiliation.txt @@ -0,0 +1,8 @@ +Name:Patriar's Humiliation +ManaCost:W +Types:Instant +A:SP$ Effect | StaticAbilities$ PerpetualLoss | RememberObjects$ Targeted | ValidTgts$ Creature | TgtPrompt$ Select target creature | IsCurse$ True | Name$ Patriar's Humiliation's Perpetual Effect | Duration$ Permanent | SubAbility$ DBDealDamage | SpellDescription$ Target creature perpetually loses all abilities. +SVar:PerpetualLoss:Mode$ Continuous | Affected$ Card.IsRemembered | RemoveAllAbilities$ True | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ This creature loses all abilities. +SVar:DBDealDamage:DB$ DealDamage | NumDmg$ X | Defined$ Targeted | StackDescription$ SpellDescription | SpellDescription$ CARDNAME deals damage to it equal to the number of creatures you control. +SVar:X:Count$Valid Creature.YouCtrl +Oracle:Target creature perpetually loses all abilities, then Patriar's Humiliation deals damage to it equal to the number of creatures you control. diff --git a/forge-gui/res/cardsfolder/upcoming/seek_new_knowledge.txt b/forge-gui/res/cardsfolder/upcoming/seek_new_knowledge.txt new file mode 100644 index 00000000000..b2aece45aae --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/seek_new_knowledge.txt @@ -0,0 +1,6 @@ +Name:Seek New Knowledge +ManaCost:1 U +Types:Instant +A:SP$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 2 | ChangeType$ Card.nonLand | SubAbility$ DBBottomCard | StackDescription$ SpellDescription | SpellDescription$ Seek two nonland cards, then put a card from your hand on the bottom of your library. +SVar:DBBottomCard:DB$ ChangeZone | Origin$ Hand | Destination$ Library | LibraryPosition$ -1 | Mandatory$ True +Oracle:Seek two nonland cards, then put a card from your hand on the bottom of your library. diff --git a/forge-gui/res/cardsfolder/upcoming/signature_spells.txt b/forge-gui/res/cardsfolder/upcoming/signature_spells.txt new file mode 100644 index 00000000000..aa8c5437120 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/signature_spells.txt @@ -0,0 +1,13 @@ +Name:Signature Spells +ManaCost:4 U U +Types:Enchantment +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSeekTwo | TriggerDescription$ When CARDNAME enters the battlefield, seek two instant and/or sorcery cards with mana value 3, then exile them. +SVar:TrigSeekTwo:DB$ ChangeZone | Imprint$ True | Origin$ Library | Destination$ Exile | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 2 | ChangeType$ Card.Instant+cmcEQ3,Card.Sorcery+cmcEQ3 | SubAbility$ DBExile | StackDescription$ SpellDescription | SpellDescription$ Seek two nonland cards, then put a card from your hand on the bottom of your library. +T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ DBCopy | TriggerZones$ Battlefield | OptionalDecider$ You | TriggerDescription$ At the beginning of your upkeep, you may copy a card exiled with CARDNAME. You may cast the copy without paying its mana cost. +SVar:DBCopy:DB$ Play | Valid$ Card.IsImprinted+ExiledWithSource | ValidZone$ Exile | WithoutManaCost$ True | ValidSA$ Spell | Optional$ True | CopyCard$ True +T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsImprinted+ExiledWithSource | Execute$ DBForget +SVar:DBForget:DB$ Pump | ForgetImprinted$ TriggeredCard +T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Card.Self | Destination$ Any | Execute$ DBCleanup | Static$ True +SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True +DeckNeeds:Type$Instant|Sorcery +Oracle:When Signature Spells enters the battlefield, seek two instant and/or sorcery cards with mana value 3, then exile them.\nAt the beginning of your upkeep, you may copy a card exiled with Signature Spells. You may cast the copy without paying its mana cost. diff --git a/forge-gui/res/cardsfolder/upcoming/sunes_intervention.txt b/forge-gui/res/cardsfolder/upcoming/sunes_intervention.txt new file mode 100644 index 00000000000..a1627766130 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/sunes_intervention.txt @@ -0,0 +1,10 @@ +Name:Sune's Intervention +ManaCost:4 W W +Types:Instant +A:SP$ Charm | MinCharmNum$ 1 | CharmNum$ 5 | Choices$ KnightTokens,SeekCard,DestroyArtifact,DestroyEnchantment,GainLife +SVar:KnightTokens:DB$ Token | TokenOwner$ You | TokenScript$ w_2_2_knight | TokenAmount$ 2 | SpellDescription$ Create two 2/2 white Knight creature tokens. +SVar:SeekCard:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.Permanent+nonLand+cmcLE3 | ChangeNum$ 1 | SpellDescription$ Seek a nonland permanent card with mana value 3 or less. +SVar:DestroyArtifact:DB$ Destroy | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | SpellDescription$ Destroy target artifact. +SVar:DestroyEnchantment:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment | SpellDescription$ Destroy target enchantment. +SVar:GainLife:DB$ GainLife | ValidTgts$ Player | TgtPrompt$ Select target player to gain 3 life | LifeAmount$ 3 | SpellDescription$ Target player gains 3 life. +Oracle:Choose one or more —\n• Create two 2/2 white Knight creature tokens.\n• Seek a nonland permanent card with mana value 3 or less.\n• Destroy target artifact.\n• Destroy target enchantment.\n• Target player gains 3 life. diff --git a/forge-gui/res/cardsfolder/upcoming/uthgardt_fury.txt b/forge-gui/res/cardsfolder/upcoming/uthgardt_fury.txt new file mode 100644 index 00000000000..731ad1c7682 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/uthgardt_fury.txt @@ -0,0 +1,8 @@ +Name:Uthgardt Fury +ManaCost:1 R R +Types:Enchantment +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDealDamage | TriggerDescription$ When CARDNAME enters the battlefield, it deals 4 damage to any target. +SVar:TrigDealDamage:DB$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 4 +SVar:PlayMain1:TRUE +S:Mode$ Continuous | Affected$ Creature.OppCtrl | AddHiddenKeyword$ Damage isn't removed from CARDNAME during cleanup steps. | Description$ Damage isn't removed from creatures your opponents control during cleanup steps. +Oracle:When Uthgardt Fury enters the battlefield, it deals 4 damage to any target.\nDamage isn't removed from creatures your opponents control during cleanup steps. From 99222e6fa50d46aceadb70f4617a3ca64e3b5337 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Fri, 5 Aug 2022 14:12:22 +0800 Subject: [PATCH 19/66] landscape and portrait settings for reward/shop card display/tooltips - user can adjust the values seperately for landscape or portrait mode --- .../src/forge/adventure/data/SettingData.java | 2 + .../forge/adventure/scene/RewardScene.java | 5 +- .../forge/adventure/scene/SettingsScene.java | 83 +++++++++++++------ .../src/forge/adventure/util/Config.java | 6 ++ .../src/forge/adventure/util/RewardActor.java | 5 +- 5 files changed, 71 insertions(+), 30 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/data/SettingData.java b/forge-gui-mobile/src/forge/adventure/data/SettingData.java index 253d078fab6..f656a46d107 100644 --- a/forge-gui-mobile/src/forge/adventure/data/SettingData.java +++ b/forge-gui-mobile/src/forge/adventure/data/SettingData.java @@ -16,4 +16,6 @@ public class SettingData { public String lastActiveSave; public Float rewardCardAdj; public Float cardTooltipAdj; + public Float rewardCardAdjLandscape; + public Float cardTooltipAdjLandscape; } diff --git a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java index 28faa6e8b06..907886ec011 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java @@ -229,8 +229,9 @@ public class RewardScene extends UIScene { mul *= 0.8f; } cardHeight = bestCardHeight * 0.90f ; - if (Config.instance().getSettingData().rewardCardAdj != 1f) { - mul *= Config.instance().getSettingData().rewardCardAdj; + Float custom = Forge.isLandscapeMode() ? Config.instance().getSettingData().rewardCardAdjLandscape : Config.instance().getSettingData().rewardCardAdj; + if (custom != null && custom != 1f) { + mul *= custom; } else { if (realX > x || realY > y) { mul *= Forge.isLandscapeMode() ? 0.95f : 1.05f; diff --git a/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java b/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java index 1657f1e9c94..fa7df88dc43 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java @@ -189,32 +189,63 @@ public class SettingsScene extends UIScene { addLabel(Forge.getLocalizer().getMessage("lblVideoMode")); settingGroup.add(videomode).align(Align.right).pad(2); } - SelectBox rewardCardAdj = Controls.newComboBox(new Float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.8f, 1.9f, 2f}, Config.instance().getSettingData().rewardCardAdj, new Function() { - @Override - public Void apply(Object o) { - Float val = (Float) o; - if (val == null || val == 0f) - val = 1f; - Config.instance().getSettingData().rewardCardAdj = val; - Config.instance().saveSettings(); - return null; - } - }); - addLabel("Reward/Shop Card Display Ratio"); - settingGroup.add(rewardCardAdj).align(Align.right).pad(2); - SelectBox tooltipAdj = Controls.newComboBox(new Float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.8f, 1.9f, 2f}, Config.instance().getSettingData().cardTooltipAdj, new Function() { - @Override - public Void apply(Object o) { - Float val = (Float) o; - if (val == null || val == 0f) - val = 1f; - Config.instance().getSettingData().cardTooltipAdj = val; - Config.instance().saveSettings(); - return null; - } - }); - addLabel("Reward/Shop Card Tooltip Ratio"); - settingGroup.add(tooltipAdj).align(Align.right).pad(2); + if (Forge.isLandscapeMode()) { + //different adjustment to landscape + SelectBox rewardCardAdjLandscape = Controls.newComboBox(new Float[]{0.6f, 0.65f, 0.7f, 0.75f, 0.8f, 0.85f, 0.9f, 1f, 1.05f, 1.1f, 1.15f, 1.2f, 1.25f, 1.3f, 1.35f, 1.4f, 1.45f, 1.5f, 1.55f, 1.6f}, Config.instance().getSettingData().rewardCardAdjLandscape, new Function() { + @Override + public Void apply(Object o) { + Float val = (Float) o; + if (val == null || val == 0f) + val = 1f; + Config.instance().getSettingData().rewardCardAdjLandscape = val; + Config.instance().saveSettings(); + return null; + } + }); + addLabel("Reward/Shop Card Display Ratio"); + settingGroup.add(rewardCardAdjLandscape).align(Align.right).pad(2); + SelectBox tooltipAdjLandscape = Controls.newComboBox(new Float[]{0.6f, 0.65f, 0.7f, 0.75f, 0.8f, 0.85f, 0.9f, 1f, 1.05f, 1.1f, 1.15f, 1.2f, 1.25f, 1.3f, 1.35f, 1.4f, 1.45f, 1.5f, 1.55f, 1.6f}, Config.instance().getSettingData().cardTooltipAdjLandscape, new Function() { + @Override + public Void apply(Object o) { + Float val = (Float) o; + if (val == null || val == 0f) + val = 1f; + Config.instance().getSettingData().cardTooltipAdjLandscape = val; + Config.instance().saveSettings(); + return null; + } + }); + addLabel("Reward/Shop Card Tooltip Ratio"); + settingGroup.add(tooltipAdjLandscape).align(Align.right).pad(2); + } else { + //portrait adjustment + SelectBox rewardCardAdj = Controls.newComboBox(new Float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.8f, 1.9f, 2f}, Config.instance().getSettingData().rewardCardAdj, new Function() { + @Override + public Void apply(Object o) { + Float val = (Float) o; + if (val == null || val == 0f) + val = 1f; + Config.instance().getSettingData().rewardCardAdj = val; + Config.instance().saveSettings(); + return null; + } + }); + addLabel("Reward/Shop Card Display Ratio"); + settingGroup.add(rewardCardAdj).align(Align.right).pad(2); + SelectBox tooltipAdj = Controls.newComboBox(new Float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.8f, 1.9f, 2f}, Config.instance().getSettingData().cardTooltipAdj, new Function() { + @Override + public Void apply(Object o) { + Float val = (Float) o; + if (val == null || val == 0f) + val = 1f; + Config.instance().getSettingData().cardTooltipAdj = val; + Config.instance().saveSettings(); + return null; + } + }); + addLabel("Reward/Shop Card Tooltip Ratio"); + settingGroup.add(tooltipAdj).align(Align.right).pad(2); + } if (!GuiBase.isAndroid()) { addSettingField(Forge.getLocalizer().getMessage("lblFullScreen"), Config.instance().getSettingData().fullScreen, new ChangeListener() { @Override diff --git a/forge-gui-mobile/src/forge/adventure/util/Config.java b/forge-gui-mobile/src/forge/adventure/util/Config.java index d8847d1980f..eabc723e176 100644 --- a/forge-gui-mobile/src/forge/adventure/util/Config.java +++ b/forge-gui-mobile/src/forge/adventure/util/Config.java @@ -70,6 +70,12 @@ public class Config { //tooltip fine tune if(settingsData.cardTooltipAdj == null || settingsData.cardTooltipAdj == 0f) settingsData.cardTooltipAdj=1f; + //reward card display fine tune landscape + if(settingsData.rewardCardAdjLandscape == null || settingsData.rewardCardAdjLandscape == 0f) + settingsData.rewardCardAdjLandscape=1f; + //tooltip fine tune landscape + if(settingsData.cardTooltipAdjLandscape == null || settingsData.cardTooltipAdjLandscape == 0f) + settingsData.cardTooltipAdjLandscape=1f; this.plane = settingsData.plane; currentConfig = this; diff --git a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java index 67660a9f949..31e6b2ab662 100644 --- a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java +++ b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java @@ -361,8 +361,9 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb float fW = x > y ? x : y; float fH = x > y ? y : x; float mul = fW/fH < AR ? AR/(fW/fH) : (fW/fH)/AR; - if (Config.instance().getSettingData().cardTooltipAdj != 1f) { - mul *= Config.instance().getSettingData().cardTooltipAdj; + Float custom = Forge.isLandscapeMode() ? Config.instance().getSettingData().cardTooltipAdjLandscape : Config.instance().getSettingData().cardTooltipAdj; + if (custom != null && custom != 1f) { + mul *= custom; } else { if (fW/fH >= 2f) {//tall display mul = (fW/fH) - ((fW/fH)/AR); From d15cf79598e68f2af705af849a1b6dc4c1d43f9d Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Fri, 5 Aug 2022 14:17:22 +0800 Subject: [PATCH 20/66] cleanup --- .../forge/adventure/scene/SettingsScene.java | 144 +++++++----------- 1 file changed, 58 insertions(+), 86 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java b/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java index fa7df88dc43..7582756dae8 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java @@ -118,12 +118,7 @@ public class SettingsScene extends UIScene { private void addSettingField(String name, int value, ChangeListener change) { TextField text = Controls.newTextField(String.valueOf(value)); - text.setTextFieldFilter(new TextField.TextFieldFilter() { - @Override - public boolean acceptChar(TextField textField, char c) { - return Character.isDigit(c); - } - }); + text.setTextFieldFilter((textField, c) -> Character.isDigit(c)); text.addListener(change); addLabel(name); settingGroup.add(text).align(Align.right); @@ -145,103 +140,85 @@ public class SettingsScene extends UIScene { Preference = new ForgePreferences(); } - SelectBox plane = Controls.newComboBox(Config.instance().getAllAdventures(), Config.instance().getSettingData().plane, new Function() { - @Override - public Void apply(Object o) { - Config.instance().getSettingData().plane = (String) o; - Config.instance().saveSettings(); - return null; - } + SelectBox plane = Controls.newComboBox(Config.instance().getAllAdventures(), Config.instance().getSettingData().plane, o -> { + Config.instance().getSettingData().plane = (String) o; + Config.instance().saveSettings(); + return null; }); addLabel(Forge.getLocalizer().getMessage("lblWorld")); settingGroup.add(plane).align(Align.right).pad(2); if (!GuiBase.isAndroid()) { - SelectBox videomode = Controls.newComboBox(new String[]{"720p", "768p", "900p", "1080p"}, Config.instance().getSettingData().videomode, new Function() { - @Override - public Void apply(Object o) { - String mode = (String) o; - if (mode == null) - mode = "720p"; - Config.instance().getSettingData().videomode = mode; - if (mode.equalsIgnoreCase("768p")) { - Config.instance().getSettingData().width = 1366; - Config.instance().getSettingData().height = 768; - } else if (mode.equalsIgnoreCase("900p")) { - Config.instance().getSettingData().width = 1600; - Config.instance().getSettingData().height = 900; - } else if (mode.equalsIgnoreCase("1080p")) { - Config.instance().getSettingData().width = 1920; - Config.instance().getSettingData().height = 1080; - } else { - Config.instance().getSettingData().width = 1280; - Config.instance().getSettingData().height = 720; - } - Config.instance().saveSettings(); - //update preference for classic mode if needed - if (FModel.getPreferences().getPref(ForgePreferences.FPref.UI_VIDEO_MODE) != mode) { - FModel.getPreferences().setPref(ForgePreferences.FPref.UI_VIDEO_MODE, mode); - FModel.getPreferences().save(); - } - return null; + SelectBox videomode = Controls.newComboBox(new String[]{"720p", "768p", "900p", "1080p"}, Config.instance().getSettingData().videomode, o -> { + String mode = (String) o; + if (mode == null) + mode = "720p"; + Config.instance().getSettingData().videomode = mode; + if (mode.equalsIgnoreCase("768p")) { + Config.instance().getSettingData().width = 1366; + Config.instance().getSettingData().height = 768; + } else if (mode.equalsIgnoreCase("900p")) { + Config.instance().getSettingData().width = 1600; + Config.instance().getSettingData().height = 900; + } else if (mode.equalsIgnoreCase("1080p")) { + Config.instance().getSettingData().width = 1920; + Config.instance().getSettingData().height = 1080; + } else { + Config.instance().getSettingData().width = 1280; + Config.instance().getSettingData().height = 720; } + Config.instance().saveSettings(); + //update preference for classic mode if needed + if (FModel.getPreferences().getPref(ForgePreferences.FPref.UI_VIDEO_MODE) != mode) { + FModel.getPreferences().setPref(ForgePreferences.FPref.UI_VIDEO_MODE, mode); + FModel.getPreferences().save(); + } + return null; }); addLabel(Forge.getLocalizer().getMessage("lblVideoMode")); settingGroup.add(videomode).align(Align.right).pad(2); } if (Forge.isLandscapeMode()) { //different adjustment to landscape - SelectBox rewardCardAdjLandscape = Controls.newComboBox(new Float[]{0.6f, 0.65f, 0.7f, 0.75f, 0.8f, 0.85f, 0.9f, 1f, 1.05f, 1.1f, 1.15f, 1.2f, 1.25f, 1.3f, 1.35f, 1.4f, 1.45f, 1.5f, 1.55f, 1.6f}, Config.instance().getSettingData().rewardCardAdjLandscape, new Function() { - @Override - public Void apply(Object o) { - Float val = (Float) o; - if (val == null || val == 0f) - val = 1f; - Config.instance().getSettingData().rewardCardAdjLandscape = val; - Config.instance().saveSettings(); - return null; - } + SelectBox rewardCardAdjLandscape = Controls.newComboBox(new Float[]{0.6f, 0.65f, 0.7f, 0.75f, 0.8f, 0.85f, 0.9f, 1f, 1.05f, 1.1f, 1.15f, 1.2f, 1.25f, 1.3f, 1.35f, 1.4f, 1.45f, 1.5f, 1.55f, 1.6f}, Config.instance().getSettingData().rewardCardAdjLandscape, o -> { + Float val = (Float) o; + if (val == null || val == 0f) + val = 1f; + Config.instance().getSettingData().rewardCardAdjLandscape = val; + Config.instance().saveSettings(); + return null; }); addLabel("Reward/Shop Card Display Ratio"); settingGroup.add(rewardCardAdjLandscape).align(Align.right).pad(2); - SelectBox tooltipAdjLandscape = Controls.newComboBox(new Float[]{0.6f, 0.65f, 0.7f, 0.75f, 0.8f, 0.85f, 0.9f, 1f, 1.05f, 1.1f, 1.15f, 1.2f, 1.25f, 1.3f, 1.35f, 1.4f, 1.45f, 1.5f, 1.55f, 1.6f}, Config.instance().getSettingData().cardTooltipAdjLandscape, new Function() { - @Override - public Void apply(Object o) { - Float val = (Float) o; - if (val == null || val == 0f) - val = 1f; - Config.instance().getSettingData().cardTooltipAdjLandscape = val; - Config.instance().saveSettings(); - return null; - } + SelectBox tooltipAdjLandscape = Controls.newComboBox(new Float[]{0.6f, 0.65f, 0.7f, 0.75f, 0.8f, 0.85f, 0.9f, 1f, 1.05f, 1.1f, 1.15f, 1.2f, 1.25f, 1.3f, 1.35f, 1.4f, 1.45f, 1.5f, 1.55f, 1.6f}, Config.instance().getSettingData().cardTooltipAdjLandscape, o -> { + Float val = (Float) o; + if (val == null || val == 0f) + val = 1f; + Config.instance().getSettingData().cardTooltipAdjLandscape = val; + Config.instance().saveSettings(); + return null; }); addLabel("Reward/Shop Card Tooltip Ratio"); settingGroup.add(tooltipAdjLandscape).align(Align.right).pad(2); } else { //portrait adjustment - SelectBox rewardCardAdj = Controls.newComboBox(new Float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.8f, 1.9f, 2f}, Config.instance().getSettingData().rewardCardAdj, new Function() { - @Override - public Void apply(Object o) { - Float val = (Float) o; - if (val == null || val == 0f) - val = 1f; - Config.instance().getSettingData().rewardCardAdj = val; - Config.instance().saveSettings(); - return null; - } + SelectBox rewardCardAdj = Controls.newComboBox(new Float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.8f, 1.9f, 2f}, Config.instance().getSettingData().rewardCardAdj, o -> { + Float val = (Float) o; + if (val == null || val == 0f) + val = 1f; + Config.instance().getSettingData().rewardCardAdj = val; + Config.instance().saveSettings(); + return null; }); addLabel("Reward/Shop Card Display Ratio"); settingGroup.add(rewardCardAdj).align(Align.right).pad(2); - SelectBox tooltipAdj = Controls.newComboBox(new Float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.8f, 1.9f, 2f}, Config.instance().getSettingData().cardTooltipAdj, new Function() { - @Override - public Void apply(Object o) { - Float val = (Float) o; - if (val == null || val == 0f) - val = 1f; - Config.instance().getSettingData().cardTooltipAdj = val; - Config.instance().saveSettings(); - return null; - } + SelectBox tooltipAdj = Controls.newComboBox(new Float[]{0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.8f, 1.9f, 2f}, Config.instance().getSettingData().cardTooltipAdj, o -> { + Float val = (Float) o; + if (val == null || val == 0f) + val = 1f; + Config.instance().getSettingData().cardTooltipAdj = val; + Config.instance().saveSettings(); + return null; }); addLabel("Reward/Shop Card Tooltip Ratio"); settingGroup.add(tooltipAdj).align(Align.right).pad(2); @@ -290,12 +267,7 @@ public class SettingsScene extends UIScene { settingGroup.row(); back = ui.findActor("return"); back.getLabel().setText(Forge.getLocalizer().getMessage("lblBack")); - ui.onButtonPress("return", new Runnable() { - @Override - public void run() { - SettingsScene.this.back(); - } - }); + ui.onButtonPress("return", () -> SettingsScene.this.back()); ScrollPane scrollPane = ui.findActor("settings"); scrollPane.setActor(settingGroup); From 6b0847159d525e3fbfcef310c94e5c5822404c51 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Fri, 5 Aug 2022 14:23:01 +0800 Subject: [PATCH 21/66] unused import --- forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java b/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java index 7582756dae8..35917ff8bf1 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java @@ -16,8 +16,6 @@ import forge.gui.GuiBase; import forge.localinstance.properties.ForgePreferences; import forge.model.FModel; -import java.util.function.Function; - /** * Scene to handle settings of the base forge and adventure mode */ From eed64fd84eabaec3a1875342387ac9f851544ccc Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Fri, 5 Aug 2022 17:44:00 +0800 Subject: [PATCH 22/66] Create altar_of_bhaal_bone_offering.txt --- .../upcoming/altar_of_bhaal_bone_offering.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/altar_of_bhaal_bone_offering.txt diff --git a/forge-gui/res/cardsfolder/upcoming/altar_of_bhaal_bone_offering.txt b/forge-gui/res/cardsfolder/upcoming/altar_of_bhaal_bone_offering.txt new file mode 100644 index 00000000000..e19fa86f284 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/altar_of_bhaal_bone_offering.txt @@ -0,0 +1,16 @@ +Name:Altar of Bhaal +ManaCost:1 B +Types:Artifact +AlternateMode:Adventure +A:AB$ ChangeZone | Cost$ 2 B T Exile<1/Creature> | TgtPrompt$ Choose target creature card in your graveyard | ValidTgts$ Creature.YouCtrl | Origin$ Graveyard | Destination$ Battlefield | SorcerySpeed$ True | SpellDescription$ Return target creature card from your graveyard to the battlefield. Activate only as a sorcery. +AI:RemoveDeck:Random +Oracle:{2}{B}, {T}, Exile a creature you control: Return target creature card from your graveyard to the battlefield. Activate only as a sorcery. + +ALTERNATE + +Name:Bone Offering +ManaCost:2 B +Types:Sorcery Adventure +A:SP$ Token | TokenAmount$ 1 | TokenScript$ b_4_1_skeleton_menace | TokenTapped$ True | TokenOwner$ You | SpellDescription$ Create a tapped 4/1 black Skeleton creature token with menace. +DeckHas:Ability$Token & Type$Skeleton +Oracle:Create a tapped 4/1 black Skeleton creature token with menace. From 4e2435ebf72cb9f61c495396506ee3871a12beea Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Fri, 5 Aug 2022 20:50:01 +0800 Subject: [PATCH 23/66] try to fix bug getting default font not correctly setting the scale to 1 --- forge-gui-mobile/src/forge/adventure/util/DrawOnPixmap.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/forge-gui-mobile/src/forge/adventure/util/DrawOnPixmap.java b/forge-gui-mobile/src/forge/adventure/util/DrawOnPixmap.java index dbc61e207eb..cd813bb9ba7 100644 --- a/forge-gui-mobile/src/forge/adventure/util/DrawOnPixmap.java +++ b/forge-gui-mobile/src/forge/adventure/util/DrawOnPixmap.java @@ -54,6 +54,8 @@ public abstract class DrawOnPixmap { frameBuffer.end(); texture.dispose(); batch.dispose(); + if (bigText) //don't know why this is needed to circumvent bug getting default size for the same pixelfont + Controls.getBitmapFont("default"); } } From 93ac9fd7feff2130a4aa993ad9b7044ac2e6c551 Mon Sep 17 00:00:00 2001 From: Grimm Date: Fri, 5 Aug 2022 18:14:51 +0200 Subject: [PATCH 24/66] adventure Editor rework --- .../forge/adventure/editor/BiomeEdit.java | 6 +- .../adventure/character/CharacterSprite.java | 2 +- .../adventure/character/EnemySprite.java | 5 +- .../forge/adventure/character/MapActor.java | 10 +- .../adventure/character/RewardSprite.java | 2 +- .../src/forge/adventure/data/BiomeData.java | 1 + .../adventure/data/BiomeStructureData.java | 3 +- .../src/forge/adventure/data/ConfigData.java | 4 +- .../src/forge/adventure/data/RewardData.java | 5 +- .../src/forge/adventure/data/UIData.java | 2 +- .../adventure/scene/SpellSmithScene.java | 6 +- .../src/forge/adventure/stage/GameHUD.java | 31 ++- .../src/forge/adventure/stage/WorldStage.java | 55 ++++- .../src/forge/adventure/util/UIActor.java | 2 +- .../forge/adventure/world/BiomeStructure.java | 17 +- .../src/forge/adventure/world/World.java | 232 +++++++++++++----- .../res/adventure/Shandalar/world/base.json | 1 + .../res/adventure/Shandalar/world/green.json | 27 +- .../Shandalar/world/tilesets/forestSource.png | Bin 8939 -> 10751 bytes .../Shandalar/world/tilesets/lakeSource.png | Bin 0 -> 10750 bytes .../Shandalar/world/tilesets/structures.atlas | 14 ++ .../Shandalar/world/tilesets/structures.png | Bin 10426 -> 89101 bytes 22 files changed, 329 insertions(+), 96 deletions(-) create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/lakeSource.png diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java index 69a2b89982f..e3e7e598f82 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java @@ -19,6 +19,7 @@ public class BiomeEdit extends FormPanel { public JSpinner width= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); public JSpinner height= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); public JTextField color=new JTextField(); + public JCheckBox collision=new JCheckBox(); public TextListEdit spriteNames =new TextListEdit(); public TextListEdit enemies =new TextListEdit(); public TextListEdit pointsOfInterest =new TextListEdit(); @@ -45,6 +46,7 @@ public class BiomeEdit extends FormPanel { center.add("enemies:",enemies); center.add("pointsOfInterest:",pointsOfInterest); center.add("color:",color); + center.add("collision:",collision); center.add("terrain/structures:",new JLabel("")); add(center); @@ -54,6 +56,7 @@ public class BiomeEdit extends FormPanel { name.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); tilesetName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); color.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + collision.addChangeListener(e -> BiomeEdit.this.updateTerrain()); spriteNames.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); enemies.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); terrain.addChangeListener(e -> BiomeEdit.this.updateTerrain()); @@ -84,6 +87,7 @@ public class BiomeEdit extends FormPanel { currentData.width = (Float) width.getValue(); currentData.height = (Float) height.getValue(); currentData.color = color.getText(); + currentData.collision = collision.isSelected(); currentData.spriteNames = spriteNames.getList(); currentData.enemies = enemies.getList(); currentData.pointsOfInterest = pointsOfInterest.getList(); @@ -116,7 +120,7 @@ public class BiomeEdit extends FormPanel { color.setText(currentData.color); spriteNames.setText(currentData.spriteNames); enemies.setText(currentData.enemies); - color.setText(currentData.color); + collision.setSelected(currentData.collision); pointsOfInterest.setText(currentData.pointsOfInterest); updating=false; } diff --git a/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java b/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java index b71a6881cfd..ad356681ea7 100644 --- a/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java @@ -38,7 +38,7 @@ public class CharacterSprite extends MapActor { @Override void updateBoundingRect() { //We want a slimmer box for the player entity so it can navigate terrain without getting stuck. - boundingRect = new Rectangle(getX() + 4, getY(), getWidth() - 6, getHeight() * collisionHeight); + boundingRect.set(getX() + 4, getY(), getWidth() - 6, getHeight() * collisionHeight); } protected void load(String path) { diff --git a/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java b/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java index 48792671778..4a487dd5d20 100644 --- a/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java @@ -50,7 +50,7 @@ public class EnemySprite extends CharacterSprite { @Override void updateBoundingRect() { //We want enemies to take the full tile. - boundingRect = new Rectangle(getX(), getY(), getWidth(), getHeight()); + boundingRect.set(getX(), getY(), getWidth(), getHeight()); } public void moveTo(Actor other, float delta) { @@ -182,5 +182,8 @@ public class EnemySprite extends CharacterSprite { } } + public float speed() { + return data.speed; + } } diff --git a/forge-gui-mobile/src/forge/adventure/character/MapActor.java b/forge-gui-mobile/src/forge/adventure/character/MapActor.java index bbe8e4086ba..62d5a4104fb 100644 --- a/forge-gui-mobile/src/forge/adventure/character/MapActor.java +++ b/forge-gui-mobile/src/forge/adventure/character/MapActor.java @@ -14,7 +14,7 @@ public class MapActor extends Actor { Texture debugTexture; - float collisionHeight=1.0f; + protected float collisionHeight=1.0f; final int objectId; public MapActor(int objectId) { @@ -35,7 +35,7 @@ public class MapActor extends Actor { } return debugTexture; } - Rectangle boundingRect; + final Rectangle boundingRect=new Rectangle(); boolean isCollidingWithPlayer=false; protected void onPlayerCollide() @@ -67,7 +67,7 @@ public class MapActor extends Actor { } void updateBoundingRect() { - boundingRect = new Rectangle(getX(), getY(), getWidth(), getHeight()*collisionHeight); + boundingRect.set(getX(), getY(), getWidth(), getHeight()*collisionHeight); } public Rectangle boundingRect() { @@ -106,4 +106,8 @@ public class MapActor extends Actor { return boundingRect.x < other.getX() + other.getWidth() && boundingRect.x + boundingRect.width > other.getX() && boundingRect.y < other.getY() + other.getHeight() && boundingRect.y + boundingRect.height > other.getY(); } + + public float getCollisionHeight() { + return collisionHeight; + } } diff --git a/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java b/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java index f1f0584b085..dda93529618 100644 --- a/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java @@ -40,7 +40,7 @@ public class RewardSprite extends CharacterSprite { @Override void updateBoundingRect() { //We want rewards to take a full tile. - boundingRect = new Rectangle(getX(), getY(), getWidth(), getHeight()); + boundingRect.set(getX(), getY(), getWidth(), getHeight()); } public Array getRewards() { //Get list of rewards. diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java index dd08b4443fc..2e5c220cec2 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java @@ -26,6 +26,7 @@ public class BiomeData implements Serializable { public float width; public float height; public String color; + public boolean collision; public boolean invertHeight; public String[] spriteNames; public String[] enemies; diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java index a91096d98b2..02bf44caaf7 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java @@ -5,10 +5,11 @@ import java.awt.image.BufferedImage; public class BiomeStructureData { + static public class BiomeStructureDataMapping { public int getColor() { - return 0xff000000 |(Integer.parseInt(color,16)); + return ((Integer.parseInt(color,16)<<8)|0xff); } public String name; public String color; diff --git a/forge-gui-mobile/src/forge/adventure/data/ConfigData.java b/forge-gui-mobile/src/forge/adventure/data/ConfigData.java index 007cf58b0ee..04b9efdc1b4 100644 --- a/forge-gui-mobile/src/forge/adventure/data/ConfigData.java +++ b/forge-gui-mobile/src/forge/adventure/data/ConfigData.java @@ -19,6 +19,6 @@ public class ConfigData { public String[] starterDecks; public DifficultyData[] difficulties; public RewardData legalCards; - public List restrictedCards; - public List restrictedEditions; + public String[] restrictedCards; + public String[] restrictedEditions; } diff --git a/forge-gui-mobile/src/forge/adventure/data/RewardData.java b/forge-gui-mobile/src/forge/adventure/data/RewardData.java index a968e4c8d09..0e3a58d7315 100644 --- a/forge-gui-mobile/src/forge/adventure/data/RewardData.java +++ b/forge-gui-mobile/src/forge/adventure/data/RewardData.java @@ -13,6 +13,7 @@ import forge.item.PaperCard; import forge.model.FModel; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -75,8 +76,8 @@ public class RewardData { @Override public boolean apply(PaperCard input){ if(input == null) return false; - if(Config.instance().getConfigData().restrictedEditions.contains(input.getEdition())) return false; - return !Config.instance().getConfigData().restrictedCards.contains(input.getName()); + if(Arrays.asList(Config.instance().getConfigData().restrictedEditions).contains(input.getEdition())) return false; + return !Arrays.asList(Config.instance().getConfigData().restrictedCards).contains(input.getName()); } }); //Filter AI cards for enemies. diff --git a/forge-gui-mobile/src/forge/adventure/data/UIData.java b/forge-gui-mobile/src/forge/adventure/data/UIData.java index 2a95ded452a..d1ece9a84db 100644 --- a/forge-gui-mobile/src/forge/adventure/data/UIData.java +++ b/forge-gui-mobile/src/forge/adventure/data/UIData.java @@ -12,5 +12,5 @@ public class UIData { public int width; public int height; public boolean yDown; - public Array> elements; + public OrderedMap[] elements; } diff --git a/forge-gui-mobile/src/forge/adventure/scene/SpellSmithScene.java b/forge-gui-mobile/src/forge/adventure/scene/SpellSmithScene.java index d56b2c8a3d5..307f24ff778 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/SpellSmithScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/SpellSmithScene.java @@ -18,10 +18,8 @@ import forge.card.ColorSet; import forge.item.PaperCard; import forge.util.MyRandom; -import java.util.ArrayList; -import java.util.HashMap; +import java.util.*; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -142,7 +140,7 @@ public class SpellSmithScene extends UIScene { List editions = StaticData.instance().getSortedEditions(); editions = editions.stream().filter(input -> { if(input == null) return false; - return(!Config.instance().getConfigData().restrictedEditions.contains(input.getCode())); + return(!Arrays.asList(Config.instance().getConfigData().restrictedEditions).contains(input.getCode())); }).collect(Collectors.toList()); editionList = ui.findActor("BSelectPlane"); rewardDummy = ui.findActor("RewardDummy"); diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java b/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java index 4d6209d0150..8a3fd8fdf6d 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java @@ -2,19 +2,18 @@ package forge.adventure.stage; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; +import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.actions.Actions; -import com.badlogic.gdx.scenes.scene2d.ui.Image; -import com.badlogic.gdx.scenes.scene2d.ui.Label; -import com.badlogic.gdx.scenes.scene2d.ui.TextButton; -import com.badlogic.gdx.scenes.scene2d.ui.Touchpad; +import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Scaling; import com.badlogic.gdx.utils.viewport.ScalingViewport; import forge.Forge; @@ -40,7 +39,8 @@ public class GameHUD extends Stage { private final Image miniMapPlayer; private final Label lifePoints; private final Label money; - private final Image miniMap, gamehud, mapborder, avatarborder, blank; + private final Image miniMap,miniMapTooltip, gamehud, mapborder, avatarborder, blank; + private Tooltip toolTip; private TextButton deckActor, menuActor, statsActor, inventoryActor; private UIActor ui; private Touchpad touchpad; @@ -61,6 +61,15 @@ public class GameHUD extends Stage { blank = ui.findActor("blank"); miniMap = ui.findActor("map"); mapborder = ui.findActor("mapborder"); + + miniMapTooltip=new Image(); + miniMapTooltip.setScaling(Scaling.contain); + miniMapTooltip.setSize(miniMap.getWidth()*3,miniMap.getHeight()*3); + miniMapTooltip.setPosition(0,0,Align.topLeft); + ui.addActor(miniMapTooltip); + toolTip=new Tooltip(miniMapTooltip); + toolTip.setInstant(true); + mapborder.addListener(toolTip); avatarborder = ui.findActor("avatarborder"); deckActor = ui.findActor("deck"); deckActor.getLabel().setText(Forge.getLocalizer().getMessage("lblDeck")); @@ -165,6 +174,7 @@ public class GameHUD extends Stage { return true; if(Current.isInDebug()) WorldStage.getInstance().GetPlayer().setPosition(x*WorldSave.getCurrentSave().getWorld().getWidthInPixels(),y*WorldSave.getCurrentSave().getWorld().getHeightInPixels()); + return true; } return super.touchDragged(screenX, screenY, pointer); @@ -228,12 +238,21 @@ public class GameHUD extends Stage { } Texture miniMapTexture; + Texture miniMapToolTipTexture; + Pixmap miniMapToolTipPixmap; public void enter() { if(miniMapTexture!=null) miniMapTexture.dispose(); miniMapTexture=new Texture(WorldSave.getCurrentSave().getWorld().getBiomeImage()); - + if(miniMapToolTipTexture!=null) + miniMapToolTipTexture.dispose(); + if(miniMapToolTipPixmap!=null) + miniMapToolTipPixmap.dispose(); + miniMapToolTipPixmap=new Pixmap((int) (miniMap.getWidth()*3), (int) (miniMap.getHeight()*3), Pixmap.Format.RGBA8888); + miniMapToolTipPixmap.drawPixmap(WorldSave.getCurrentSave().getWorld().getBiomeImage(),0,0,WorldSave.getCurrentSave().getWorld().getBiomeImage().getWidth(),WorldSave.getCurrentSave().getWorld().getBiomeImage().getHeight(),0,0,miniMapToolTipPixmap.getWidth(),miniMapToolTipPixmap.getHeight()); + miniMapToolTipTexture=new Texture(miniMapToolTipPixmap); miniMap.setDrawable(new TextureRegionDrawable(miniMapTexture)); + miniMapTooltip.setDrawable(new TextureRegionDrawable(miniMapToolTipTexture)); avatar.setDrawable(new TextureRegionDrawable(Current.player().avatar())); } diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java index 7fa6d0ce2f5..2c951ca36f3 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java @@ -62,6 +62,8 @@ public class WorldStage extends GameStage implements SaveFileContent { } + final Rectangle tempBoundingRect=new Rectangle(); + final Vector2 enemyMoveVector =new Vector2(); @Override protected void onActing(float delta) { if (player.isMoving()) { @@ -79,7 +81,33 @@ public class WorldStage extends GameStage implements SaveFileContent { continue; } EnemySprite mob=pair.getValue(); - mob.moveTo(player,delta); + + enemyMoveVector.set(player.getX(), player.getY()).sub(mob.pos()); + enemyMoveVector.setLength(mob.speed()*delta); + tempBoundingRect.set(mob.getX()+ enemyMoveVector.x,mob.getY()+ enemyMoveVector.y,mob.getWidth(),mob.getHeight()*mob.getCollisionHeight()); + + if(WorldSave.getCurrentSave().getWorld().collidingTile(tempBoundingRect))//if direct path is not possible + { + tempBoundingRect.set(mob.getX()+ enemyMoveVector.x,mob.getY(),mob.getWidth(),mob.getHeight()); + if(WorldSave.getCurrentSave().getWorld().collidingTile(tempBoundingRect))//if only x path is not possible + { + tempBoundingRect.set(mob.getX(),mob.getY()+ enemyMoveVector.y,mob.getWidth(),mob.getHeight()); + if(!WorldSave.getCurrentSave().getWorld().collidingTile(tempBoundingRect))//if y path is possible + { + mob.moveBy(0, enemyMoveVector.y); + } + } + else + { + + mob.moveBy(enemyMoveVector.x, 0); + } + } + else + { + mob.moveBy(enemyMoveVector.x, enemyMoveVector.y); + } + if (player.collideWith(mob)) { player.setAnimation(CharacterSprite.AnimationTypes.Attack); mob.setAnimation(CharacterSprite.AnimationTypes.Attack); @@ -204,12 +232,25 @@ public class WorldStage extends GameStage implements SaveFileContent { EnemySprite sprite = new EnemySprite(enemyData); float unit = Scene.getIntendedHeight() / 6f; Vector2 spawnPos = new Vector2(1, 1); - spawnPos.setLength(unit + (unit * 3) * rand.nextFloat()); - spawnPos.setAngleDeg(360 * rand.nextFloat()); - sprite.setX(player.getX() + spawnPos.x); - sprite.setY(player.getY() + spawnPos.y); - enemies.add(Pair.of(globalTimer,sprite)); - foregroundSprites.addActor(sprite); + for(int j=0;j<10;j++) + { + spawnPos.setLength(unit + (unit * 3) * rand.nextFloat()); + spawnPos.setAngleDeg(360 * rand.nextFloat()); + for(int i=0;i<10;i++) + { + boolean enemyXIsBigger=sprite.getX()>player.getX(); + boolean enemyYIsBigger=sprite.getY()>player.getY(); + sprite.setX(player.getX() + spawnPos.x+(i*sprite.getWidth()*(enemyXIsBigger?1:-1)));//maybe find a better way to get spawn points + sprite.setY(player.getY() + spawnPos.y+(i*sprite.getHeight()*(enemyYIsBigger?1:-1))); + if(!WorldSave.getCurrentSave().getWorld().collidingTile(sprite.boundingRect())) + { + enemies.add(Pair.of(globalTimer,sprite)); + foregroundSprites.addActor(sprite); + return; + } + int g=0; + } + } } @Override diff --git a/forge-gui-mobile/src/forge/adventure/util/UIActor.java b/forge-gui-mobile/src/forge/adventure/util/UIActor.java index 96556330bac..7763465fc6a 100644 --- a/forge-gui-mobile/src/forge/adventure/util/UIActor.java +++ b/forge-gui-mobile/src/forge/adventure/util/UIActor.java @@ -29,7 +29,7 @@ public class UIActor extends Group { setWidth(data.width); setHeight(data.height); - for (OrderedMap element : new Array.ArrayIterator<>(data.elements)) { + for (OrderedMap element : data.elements) { String type = element.get("type"); Actor newActor; if (type == null) { diff --git a/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java index 7c6736e88f1..8f970041f68 100644 --- a/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java +++ b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java @@ -18,6 +18,7 @@ public class BiomeStructure { private int biomeWidth; private int biomeHeight; private int dataMap[][]; + private boolean collisionMap[][]; boolean init=false; private TextureAtlas structureAtlas; public BufferedImage image; @@ -59,14 +60,18 @@ public class BiomeStructure { { colorIdMap.put(Integer.parseInt(data.mappingInfo[i].color,16),i); } - boolean suc=model.run((int) seed,0); + boolean suc=false; + for(int i=0;i<10&&!suc;i++) + suc=model.run((int) seed+(i*5355),15000); if(!suc) { dataMap=new int[(int) (data.width* biomeWidth)][ (int) (data.height*biomeHeight)]; + collisionMap=new boolean[(int) (data.width* biomeWidth)][ (int) (data.height*biomeHeight)]; return; } image=model.graphics(); dataMap=new int[image.getWidth()][image.getHeight()]; + collisionMap=new boolean[image.getWidth()][image.getHeight()]; for(int x=0;x=collisionMap.length||x<0||y<0||y>=collisionMap[0].length) + return false; + return collisionMap[x][y]; + } } diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index 7139480e172..09dbe9dd750 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -30,6 +30,9 @@ public class World implements Disposable, SaveFileContent { private Pixmap biomeImage; private long[][] biomeMap; private int[][] terrainMap; + private static int collisionBit =0b10000000000000000000000000000000; + private static int isStructureBit=0b01000000000000000000000000000000; + private static int terrainMask =collisionBit|isStructureBit; private int width; private int height; private SpritesDataMap mapObjectIds; @@ -50,20 +53,19 @@ public class World implements Disposable, SaveFileContent { public boolean collidingTile(Rectangle boundingRect) { - Set> points=new HashSet<>(); int xLeft=(int) boundingRect.getX() / getTileSize(); int yTop=(int) boundingRect.getY() / getTileSize(); - int xRight=(int) (boundingRect.getX()+boundingRect.getWidth()) / getTileSize(); - int yBottom= (int) (boundingRect.getY()+boundingRect.getHeight()) / getTileSize(); + int xRight=(int) ((boundingRect.getX()+boundingRect.getWidth()) / getTileSize()); + int yBottom= (int) ((boundingRect.getY()+boundingRect.getHeight()) / getTileSize()); - if(getBiome(xLeft,yTop)==0) + if(isColliding(xLeft,yTop)) return true; - if(getBiome(xLeft,yBottom)==0) + if(isColliding(xLeft,yBottom)) return true; - if(getBiome(xRight,yBottom)==0) + if(isColliding(xRight,yBottom)) return true; - if(getBiome(xRight,yTop)==0) + if(isColliding(xRight,yTop)) return true; return false; @@ -154,7 +156,7 @@ public class World implements Disposable, SaveFileContent { return new Pixmap(data.tileSize, data.tileSize, Pixmap.Format.RGBA8888); long biomeIndex = getBiome(x, y); - int terrain = getTerrainIndex(x, y); + int biomeTerrain = getTerrainIndex(x, y); Pixmap drawingPixmap = new Pixmap(data.tileSize, data.tileSize, Pixmap.Format.RGBA8888); ArrayList information=new ArrayList<>(); for (int i = 0; i < biomeTexture.length; i++) { @@ -164,9 +166,8 @@ public class World implements Disposable, SaveFileContent { BiomeTexture regions = biomeTexture[i]; if (x <= 0 || y <= 1 || x >= width - 1 || y >= height)//edge { - return regions.getPixmap(terrain); + return regions.getPixmap(biomeTerrain); } - int biomeTerrain=Math.min(regions.images.size()-1,terrain); int neighbors = 0b000_000_000; @@ -178,7 +179,7 @@ public class World implements Disposable, SaveFileContent { int otherTerrain = getTerrainIndex(x + nx, y + ny); - if ((otherBiome & 1L << i) != 0 && biomeTerrain <= otherTerrain) + if ((otherBiome & 1L << i) != 0 && (biomeTerrain == otherTerrain)|biomeTerrain==0) neighbors |= (1 << bitIndex); bitIndex--; @@ -226,21 +227,54 @@ public class World implements Disposable, SaveFileContent { } public int getTerrainIndex(int x, int y) { - return terrainMap[x][height - y]; + try { + return terrainMap[x][height - y-1] & ~terrainMask; + } catch (ArrayIndexOutOfBoundsException e) { + return 0; + } + } + public boolean isStructure(int x, int y) { + try { + return (terrainMap[x][height - y-1] & ~isStructureBit)!=0; + } catch (ArrayIndexOutOfBoundsException e) { + return false; + } } public long getBiome(int x, int y) { try { - return biomeMap[x][height - y]; + return biomeMap[x][height - y-1]; } catch (ArrayIndexOutOfBoundsException e) { return biomeMap[biomeMap.length-1][biomeMap[biomeMap.length-1].length-1]; } } + public boolean isColliding(int x, int y) { + try { + return (terrainMap[x][height - y-1] & collisionBit)!=0; + } catch (ArrayIndexOutOfBoundsException e) { + return true; + } + } public WorldData getData() { return data; } +private void clearTerrain(int x,int y,int size) +{ + for(int xclear=-size;xclear towns = new ArrayList<>(); + List notTowns = new ArrayList<>(); List otherPoints = new ArrayList<>(); + + clearTerrain((int) (data.width*data.playerStartPosX), (int) (data.height*data.playerStartPosY),10); otherPoints.add(new Rectangle(((float)data.width*data.playerStartPosX*(float)data.tileSize)-data.tileSize*3,((float)data.height*data.playerStartPosY*data.tileSize)-data.tileSize*3,data.tileSize*6,data.tileSize*6)); int biomeIndex2=-1; for (BiomeData biome : data.GetBiomes()) { @@ -418,18 +462,22 @@ public class World implements Disposable, SaveFileContent { } otherPoints.add(new Rectangle(x - data.tileSize * 4, y - data.tileSize * 4, data.tileSize * 8, data.tileSize * 8)); PointOfInterest newPoint = new PointOfInterest(poi, new Vector2(x, y), random); - + clearTerrain((int)(x/data.tileSize),(int)(y/data.tileSize),3); mapPoiIds.add(newPoint); Color color = biome.GetColor(); pix.setColor(color.r, 0.1f, 0.1f, 1); - pix.drawRectangle((int) x / data.tileSize - 3, height - (int) y / data.tileSize - 3, 6, 6); + pix.fillRectangle((int) x / data.tileSize - 3, height - (int) y / data.tileSize - 3, 6, 6); if (poi.type!=null&&poi.type.equals("town")) { towns.add(newPoint); } + else + { + notTowns.add(newPoint); + } break; } @@ -439,100 +487,158 @@ public class World implements Disposable, SaveFileContent { } //sort towns - List> allSortedTowns = new ArrayList<>();//edge is first 32 bits id of first id and last 32 bits id of second + List> allSortedTowns = new ArrayList<>(); - HashSet usedEdges=new HashSet<>(); + HashSet usedEdges=new HashSet<>();//edge is first 32 bits id of first id and last 32 bits id of second for (int i = 0; i < towns.size() - 1; i++) { PointOfInterest current = towns.get(i); int smallestIndex = -1; + int secondSmallestIndex = -1; float smallestDistance = Float.MAX_VALUE; for (int j = 0; j < towns.size(); j++) { if(i==j||usedEdges.contains((long)i|((long)j<<32))) continue; float dist = current.getPosition().dst(towns.get(j).getPosition()); + if(dist>data.maxRoadDistance) + continue; if (dist < smallestDistance) { smallestDistance = dist; + secondSmallestIndex=smallestIndex; smallestIndex = j; + } } if (smallestIndex < 0) continue; - if(smallestDistance>data.maxRoadDistance) - continue; usedEdges.add((long)i|((long)smallestIndex<<32)); usedEdges.add((long)i<<32|((long)smallestIndex)); allSortedTowns.add(Pair.of(current, towns.get(smallestIndex))); - } + if (secondSmallestIndex < 0) + continue; + usedEdges.add((long)i|((long)secondSmallestIndex<<32)); + usedEdges.add((long)i<<32|((long)secondSmallestIndex)); + //allSortedTowns.add(Pair.of(current, towns.get(secondSmallestIndex))); + } + List> allPOIPathsToNextTown = new ArrayList<>(); + for (int i = 0; i < notTowns.size() - 1; i++) { + + PointOfInterest poi = notTowns.get(i); + int smallestIndex = -1; + float smallestDistance = Float.MAX_VALUE; + for (int j = 0; j < towns.size(); j++) { + + float dist = poi.getPosition().dst(towns.get(j).getPosition()); + if (dist < smallestDistance) { + smallestDistance = dist; + smallestIndex = j; + + } + } + if (smallestIndex < 0) + continue; + allPOIPathsToNextTown.add(Pair.of(poi, towns.get(smallestIndex))); + } biomeIndex++; pix.setColor(1, 1, 1, 1); + + //reset terrain path to the next town + for (Pair poiToTown : allPOIPathsToNextTown) { + + int startX= (int) poiToTown.getKey().getTilePosition(data.tileSize).x; + int startY= (int) poiToTown.getKey().getTilePosition(data.tileSize).y; + int x1 = (int) poiToTown.getValue().getTilePosition(data.tileSize).x; + int y1 = (int) poiToTown.getValue().getTilePosition(data.tileSize).y; + int dx = Math.abs( x1 - startX); + int dy = Math.abs( y1 - startY); + int sx = startX < x1 ? 1 : -1; + int sy = startY < y1 ? 1 : -1; + int err = dx - dy; + int e2; + while (true) + { + if( startX<0|| startY<=0|| startX>=width|| startY>height)continue; + if((terrainMap[startX][height - startY]&collisionBit)!=0)//clear terrain if it has collision + terrainMap[startX][height - startY]=0; + pix.drawPixel(startX, height - startY); + + if (startX == x1 && startY == y1) + break; + e2 = 2 * err; + if (e2 > -dy) + { + err = err - dy; + startX = startX + sx; + } + else if (e2 < dx) + { + err = err + dx; + startY = startY + sy; + } + } + } + for (Pair townPair : allSortedTowns) { - Vector2 currentPoint = townPair.getKey().getTilePosition(data.tileSize); - Vector2 endPoint = townPair.getValue().getTilePosition(data.tileSize); - for (int x = (int) currentPoint.x - 1; x < currentPoint.x + 2; x++) { - for (int y = (int) currentPoint.y - 1; y < currentPoint.y + 2; y++) { + int startX= (int) townPair.getKey().getTilePosition(data.tileSize).x; + int startY= (int) townPair.getKey().getTilePosition(data.tileSize).y; + int x1 = (int) townPair.getValue().getTilePosition(data.tileSize).x; + int y1 = (int) townPair.getValue().getTilePosition(data.tileSize).y; + for (int x = startX - 1; x < startX + 2; x++) { + for (int y = startY - 1; y < startY + 2; y++) { if(x<0||y<=0||x>=width||y>height)continue; - biomeMap[x][height - y] |= (1L << biomeIndex); - terrainMap[x][height-y]=0; + biomeMap[x][height - y-1] |= (1L << biomeIndex); + terrainMap[x][height-y-1]=0; pix.drawPixel(x, height-y); } } + int dx = Math.abs( x1 - startX); + int dy = Math.abs( y1 - startY); + int sx = startX < x1 ? 1 : -1; + int sy = startY < y1 ? 1 : -1; + int err = dx - dy; + int e2; + while (true) + { + if( startX<0|| startY<=0|| startX>=width|| startY>height)continue; + biomeMap[startX][height - startY] |= (1L << biomeIndex); + terrainMap[startX][height - startY]=0; + pix.drawPixel(startX, height - startY); - while (!currentPoint.equals(endPoint)) { - float xDir = endPoint.x - currentPoint.x; - float yDir = endPoint.y - currentPoint.y; - - if (xDir == 0) { - if (yDir > 0) - currentPoint.y++; - else - currentPoint.y--; - } else if (yDir == 0) { - if (xDir > 0) - currentPoint.x++; - else - currentPoint.x--; - } else if (Math.abs(xDir) > Math.abs(yDir)) { - - if (xDir > 0) - currentPoint.x++; - else - currentPoint.x--; - } else { - if (yDir > 0) - currentPoint.y++; - else - currentPoint.y--; + if (startX == x1 && startY == y1) + break; + e2 = 2 * err; + if (e2 > -dy) + { + err = err - dy; + startX = startX + sx; + } + else if (e2 < dx) + { + err = err + dx; + startY = startY + sy; } - - if( (int)currentPoint.x<0|| (int)currentPoint.y<=0|| (int)currentPoint.x>=width|| (int)currentPoint.y>height)continue; - biomeMap[(int) currentPoint.x][height - (int) currentPoint.y] |= (1L << biomeIndex); - terrainMap[(int) currentPoint.x][height - (int) currentPoint.y]=0; - pix.drawPixel((int) currentPoint.x, height - (int) currentPoint.y); - } - } mapObjectIds = new SpritesDataMap(getChunkSize(), data.tileSize, data.width / getChunkSize()); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { - int invertedHeight = height - y - 1; + int invertedHeight = height - y -1; int currentBiome = highestBiome(biomeMap[x][invertedHeight]); if (currentBiome >= data.GetBiomes().size()) + continue;//roads + if(isStructure(x,y)) continue; BiomeData biome = data.GetBiomes().get(currentBiome); for (String name : biome.spriteNames) { BiomeSpriteData sprite = data.GetBiomeSprites().getSpriteData(name); double spriteNoise = (noise.eval(x / (double) width * noiseZoom*sprite.resolution, y / (double) invertedHeight * noiseZoom*sprite.resolution) + 1) / 2; if (spriteNoise >= sprite.startArea && spriteNoise <= sprite.endArea) { - if(terrainMap[x][invertedHeight]>biome.terrain.length) - continue; if (random.nextFloat() <= sprite.density) { String spriteKey = sprite.key(); int key; @@ -542,8 +648,8 @@ public class World implements Disposable, SaveFileContent { } else { key = mapObjectIds.intKey(spriteKey); } - mapObjectIds.putPosition(key, new Vector2((float) x * data.tileSize + (random.nextFloat() * data.tileSize), (float) y * data.tileSize + (random.nextFloat() * data.tileSize))); - + mapObjectIds.putPosition(key, new Vector2((((float) x)+.25f+random.nextFloat()/2) * data.tileSize , (((float) y+.25f)-random.nextFloat()/2) * data.tileSize )); + break;//only on sprite per point } } } diff --git a/forge-gui/res/adventure/Shandalar/world/base.json b/forge-gui/res/adventure/Shandalar/world/base.json index 96fc87eca0d..c4e41f7614d 100644 --- a/forge-gui/res/adventure/Shandalar/world/base.json +++ b/forge-gui/res/adventure/Shandalar/world/base.json @@ -1,5 +1,6 @@ { "invertHeight": true, + "collision": true, "name": "ocean", "startPointX": 0.5, "startPointY": 0.5, diff --git a/forge-gui/res/adventure/Shandalar/world/green.json b/forge-gui/res/adventure/Shandalar/world/green.json index f33e6c135c3..644004f6b77 100644 --- a/forge-gui/res/adventure/Shandalar/world/green.json +++ b/forge-gui/res/adventure/Shandalar/world/green.json @@ -97,10 +97,35 @@ "sourcePath": "world/tilesets/forestSource.png", "height": 0.3, "width": 0.3, + "symmetry": 1, + "periodicOutput": false, "mappingInfo": [ { "name": "Forest", - "color": "007000" + "color": "007000", + "collision": true + } + ] + }, + { + "N": 2, + "x": 0.3, + "y": 0.3, + "structureAtlasPath": "world/tilesets/structures.atlas", + "sourcePath": "world/tilesets/lakeSource.png", + "height": 0.3, + "width": 0.3, + "periodicOutput": false, + "mappingInfo": [ + { + "name": "Lake", + "color": "0070a0", + "collision": true + }, + { + "name": "Forest2", + "color": "009000", + "collision": true } ] } diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forestSource.png b/forge-gui/res/adventure/Shandalar/world/tilesets/forestSource.png index bbae35add1f51c50a3a2bf1413d61ffe9d9fbf09..d67c70f9fe717de5ba9ad8e35780b9c54d64aadf 100644 GIT binary patch delta 6167 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 delta 4482 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 U@^8xn01E&B07*qoM6N<$f-dTaGXMYp diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/lakeSource.png b/forge-gui/res/adventure/Shandalar/world/tilesets/lakeSource.png new file mode 100644 index 0000000000000000000000000000000000000000..af2f51f4f895de6935338315e6c3184aac620ba6 GIT binary patch literal 10750 zcmeHtc|4SD`?ocFc3FyPBmJ%~2|Z9B9i5hStPXd4%L?HkOfg~awUEs^EbX$MP zBXJSq^)ZeZAG*jXifUm%Z^r^R{-(k`hl++T3z3RfL9$Y(=orH2t`WcXoK;$O+Pb93 z%ztRg#^wInJ_DJGr9)2doJP;i3$BhYlgHv#m;IK5TTVS&p6Th>ztE#GH1Bb4*)-@d znQ`jO!#?$gX3c76zCwG|5{3j-GGC7)r_M}_2DOYa4u*u>n*7{&!T)Td#*t_5hGw#q zKVI@VyVfxqUp2-vz1VF;-fkT)OA6WcYuxBqE8})ti(iR;*Bu$!I#${wJU%kBvQYLq z-9$VnGj#Fk?8v^zHHy<0bnm9;;)>hDd)`waEv0@M)X&;jA)jvFdcc z?Vj7OwzsamdvSl6)eZ9xwf`WZx>?UE@pee zT$ODq{V%$?XjDyg`PaNV-~2WjmeHoxw7Mmw&=#yp(V1=44Uu}6SUU`Po7LWa1NjKy z;H>l7IYlv$+o*ny>fM+$_qB{aK(WOdg*kobI&^Qznj8~bA5Xjp=ZQr=?L!8M3Oeqe zA==T9n?;YUlS~fk$H*33Hz*l-7cceXx=**1wS~hXPhPT(`Llv#yR;gp&(te~wIY1z zG>4I$XYrJk-F#DFq@vpDps&({^xrN@P##A~UQul?8Zgd=wG0OK`f7C9H#X+l zm6-}NVIOXnqH;0&O9lM8t3E(fg>U**&vgVyWNx;SFW&uDcgA;thH3c5(IetFip<=6 zP96{R8oUvkECEpF(n5TgV$)E!JUOkgK9i-EKI?R5@!Nu?dL{2r#4youCB19I)_|{b zbl>8rIfJ+ghft(fNV2EvUfCCogQ>PJ(v$`yKMUOtrmi<(!ug0{6bszwpztJ711%dZChfAumM;H&iuWVrN>)4Qf zToYVj+PeA?8md&om!HC=UvrDo$wJ}FL&Gx#e)dfhlxO>Z#|Mt3xhVx^bDQ`;xZjoR;hM z3TgTtu0KB;T^_P;dffBvvSO4>O#=OUC;z72FXC%U4_FSP@6qMucR1)hl+QmZGtFt2 zF8l_nReXvQa}+~|vQAMQ&-g4{ zdV6(dI*NDpAi$GH-dAI&Ff3g5###+K$AQ4g;Z8Gw!=DzIq#|4uUzx{}xW~0yop_|5 zJ(A6=#h$4P`S>Tr6@wy&ZuVXzkG`5zQnzG20CgbU=&ui4<<#Qx?9ePWk5XVsjyuix+&7d7=gn|SPQ z}$$z>?(9;VsqRc6F z&%|yZ(;6mm@;M-6Ymv_uHP0ryoN-Mw@s6o^TFnW~uS7>V%j>5!*V@4j{p4+Hp zaN+z-Be97kwyH1tKg-gmDNCvYp5ncG-)_7qclCBZ;@6F!lXysa$_W~3cdUqcVQ!pm zk2kBfxxFm$AzB+Oi;7e-_Gpvtd%V?tNkc<4CY#9d{=Ss`p-J{>7`;M= zs^KyedC^tyxhoY!@-qdRWzwhh%Xr~UeZC2}rjHbTx+y1-_kg&fIkPRm0c6X$boi}L zHwaJVE2w)hgbxaPUi_eTa5dTe5LO~##Twb9&mSXMe&XxVZ$Vl-%|lz-2ZzGFMrIL{ zNN{7G3V+v>WO^5i?N?U^QsbUwG3(6Y+DFwHeDnf6`dzT2eBzu#9;X7^w+T$)Y!Xz&7{!w2pa}sidrNX?*^{#5ukC5|_uDSH1a7`Ln!Il5z_8 zYqYd<>yoWM88(^=S#|XHxIdlvG`Wy^I;QM(XAd(YG`PVc7{khPv^u!n<9-!0O7M1} zV@77bDf?GUSve1!*+cMh?o4C$`Syz2d?PlM%NcXLn)yUTyz-4-DU5NJpGVUGBp33C)nr@pJj3{S@G?a&x_*vBr;%f}F&Y6oGe+J89TK-GMn zx7RZKNV}GyK<-O-5i_w)1D<_*3-QKB+)k=yXT=6*R~tp7l^%-HzVpfXqQeEA2%dPy zf?K_O#;uq)_7`89RdO*gIE5rvU&=*0FR4-P)&y9z9~Ieu={`dW+KQ7$u8sArIYxKR zsK{UH%l!TYi~Q>ezNZ|{A>T25EJ!G2HOWfMGcIe7XT&U+hB3<9hFT$RzGB1roW9Jp z#y(=ef1*%e8Bpoo(YHP(O@+30MzI+L1bN~V(!X}k7>ZR8f@ zwGO?p4Mz~$fN-_#QtW3Qu|ZInsDQkGiu+_L@a!idpxDz@RAzAbv{15HY$k)CnmL7> zom-tusyZjGz&fDo$8IWlo7Lf5+?wj^itE@rAZ$Wqj(3XKw_Hg|-Mi}b#ytP@v!+wc zA6dn!=k337Yg^p%_y8=h;I-weE5@_X#boC)988rIJJc_O)Z#1gYs|HM|H3qIMN13Y zT7JYp@G7TMGhb540oV zh#pOA{Gy$5ugi$d#2aW{Gi=nd5q`@oU`Uj3r9N`uW5@82pRRR$!)c0N&nM-^k?jfC zX;hw;;z@q?c0n{{9)Ec*q)IfGaNLgA)}uoH@;2EMUI{e2vxGe*ed6Qw(wufoK;dUx zUx~55;xomByAp#4t@WJ7(aj~7OS9Q@akAqd!-qFRl{4m_$|(VfV_pSHd%#W#@h$xM zP=9gvjLvEx_tS`vmOVLQwy_rV$?>*#Vy+o<`Wq^PEpSv-|&iHJVaxi>eFbdL@>Q9-$qM7MDbrY(2 z?1GKopjTrWvu8~UJ{nAH$)jS2rBSi;v9Bd^+&kQ17%shIjB(L-1bgwucFgsJ?F`+j z^*d(68v}8wk^3a(?`IT&?k(ko5Hq+G!-kvAbI;v-ez0h?w22VP`6`2$G8U66dZ1Uc z=W_OD|AWkn69ZNstYHcT5?8_)tKef@!JKC1TNO8|dzmdCH<~jZw16?#d~Pa>*V+G` zUKeDZ;DsGP;^2h zJmd9?DrvZOlnDD4q+!bF64ScYapo zHH}momgwB5E)joghF9=UPFx>6{~+n4&BDpyy2GAJ3}!7EEx?%u!f)p_(`t3zo?<{O z><^MlX%jxudiEMCh7u{>ftTqsNw9^L9)=&4yj&hRyVWH6MmfW`vvqU(s)2&TS=M3M z^G$^%K#bAnL7UulI$7iUdD)-8az=Wn;dK+~;*5>~Br}U5Cj2ddPiu+|=|*lM_iBC} zWDB(NHNuZuIq_oyD61FTh1uI~;u4@7HHhrJGY96r7!KOPYNN$Owte=g+LT$HPL#X# zoXwJFpYlW$$c;mLO;4tA(eQ4Df(CDwO6B^=Cwj*ttlA1Zm9t;6o-!@T4ok)=MCWV2 zwl88|$*ijCz+2zQl~+G-rb2b5`T7yJ$}VAWlw?6O3Z!#CkFC6^F-Nyr=)>Kauqf{k z4hixCzTkR5e%!NwamWJj_`3O2@zRv{7cHg|d&{fNq^I#3Y73PUgQMfG5wqYaf%4fX zmR!Rxij!yLp4~p1jEDvm2(TS7lL-JG80lwKg$5UB#|&8NN%-iX+%;#pG?|Jk+>f>M zo)MKT+{Tp2cv&EwIg^89%vogW#%4xX3Y~^2d9-E8(=CplTrrP_U6AZ;Q&NV1;iG% z*=|N12BzFJd6%D`SYLYx75#u{&!aB44S$Fq6M9r0`d)wUqnVV9qvd0aZ&$igM^Bi_ zk2=3R8hTzo2QTBFJUjQ~6n{lSvEu%c^L!`Xi(lZ1D2dUT3u{Ep^m`}lO_sP{vO0>C zzP$N0l6xgYB5OHt0UWTof8v4BoxK3n5*T6b__b*y0_J%vglx zz9k*faFu4cd+&zB6+5H#cagA*qY^%9knTgFlSRi`&phnk6zH+M=y~TJ{XM(km`t?c z5wqW3U+P`4f_iagv1@1oS#Okq<|f+So7tJ?(KnvZs_zPI;d-9%oL|?mfbWG#C=N=9 z%lmME>}T{=@9frac&C@)n3$0C9-?{l8`%b>PnzBio7oX_oH=bTL_Y{x$kzsjl59F< zKk`ZnSSLGk>2SoM=C=eN1jS)|6bT~d1OlXVg8MS6jNdI>Yr0<>@_O{6Y?UN~)p4-{ zSGF(-ACk|~D<$_ozUD@rS6tBgHP(4T z)Lk9_!Sg=%?De@WUdONK`{maW@=P=^$!Mw564BFS%qq83 zHJwYA?WYSK%;x@~Y91J}dquvi2 zEIckh|KNBCJkOsbnC2Kq?)ADb!O>>6-$Uno?(-HM*mSzxr^zwg!+yfz{bnw3!UXek z^#)U3t5>=0Y)r156v5N#Z1m1c`!A6gZC)Q+&YwLn_M6nJ4}QkrWOVu~SK;8N`LnU2 zEQU7^-0%qSka6smjT$Wkw0>ZVk{KwaZz;*ig2fzF8Spl&)iey%b6@6;yLEPRjQ|j` zWNrG!%${{B2zjueo{o;+k3@R_Yhz@H#*w`gv3RlzK{3#aLVG|_Vs>YCsz!Q-BuPhX8;p!WF?Foj{U56sXP)Q1!tR(dOE^ zKPYHdYCtzCm4a4M3J3^L41g(;eO#3wDk>^UV5kxl3ZfxEzCqqpY#_+nS8|8qJBK#G z7w1EwP)THOzz!$Yh3rRF0|II5fFIUONpGtvPiV{Q-tmNhOCkKXrD}=t}aU>}u?w ze?{VPKXDX4AJ1J39;Za`BzVyr@ue|C{)DHJh<|L*pW@kB`CpFE%>Cs56Z-dj?fSBt zSF|=6=eJ{2Ut0~h<1ZRd#*y&o-LD8d1P?|i6F_hx7z~2r@DLCdhJb*O2nd#_48s!% zV8ky}`rf`&tT&FZLq#K3B++=_%5Ve$0)>N+coY%@SHZ(UE-FYYNSO#FVu>&UmZ1DA zg^3S|)(Ke8U%lF)!qcc!kYE%IPpc0c)&&HIKwUssBpwQaVPQlZo~R6kVd1;p?Cb;j zsHwgh5UL3NLt^TQr4q?LUbOZidE?0ezJDxPlDr5ORP0XLAj$|8Bm@SALtron5(@hR zWJU1trIq;(D+H{F+Fiio(7H5AEUnr|URYOx62;qfcVTB=(6nf1nZ@oj2aR}FP74OD z((r;Soys!x#qzX<%>$CI=>*#Lmu8H2{+zHhEC)}Mgi-9cKGzc1n3u->i&+A#mo$-m1<|Da1;l%ZfE z5kde#;ZRzafK?zM6s_DrL@WwIBw$fcFzkD2|77rT7}W7h}OBgRRoav zQQWeB_9noMuv59TVgiAYpkIm!_cEUrTAc0^l3V}kxX?G%!in20}7M_bTZ69GckTRBlS9ZZ+5ipnU zv-aOooWF+$g`>fc-@{W?+BrJ?K50~U4i`p7=wD}%>dxTEyqTQa|s3rm4|J3|H0DfmMB;g3&zT|)A`md1hY5C=Z zN%Q%;jCOLR9fXyBo`io)Xxa|_Cx3oS{{N&20N`&Ue<{Czr|a)@{iO{2CGg+X^>@1d zQU?AK`0wiax222yk7sEFZ`$8n0kkJ&%Pp6;X;0bqxEw#GP4{i*mHnVFi6&vA=-K+x z{!jAp&YM0(ey+WaD40Jw6KHUKX4?aQ!dDH%Y| m=sI4*{@RQ7BHZO47xyf`_pxrooUx=iMW?T0tX+X|4*wq*KZWZ6 literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/structures.atlas b/forge-gui/res/adventure/Shandalar/world/tilesets/structures.atlas index 0b93583a916..c7b9d7cff58 100644 --- a/forge-gui/res/adventure/Shandalar/world/tilesets/structures.atlas +++ b/forge-gui/res/adventure/Shandalar/world/tilesets/structures.atlas @@ -10,4 +10,18 @@ Forest size: 48, 64 orig: 0, 0 offset: 0, 0 + index: 0 +Lake + Lake: false + xy: 48, 0 + size: 48, 64 + orig: 0, 0 + offset: 0, 0 + index: 0 +Forest2 + rotate: false + xy: 96, 0 + size: 48, 64 + orig: 0, 0 + offset: 0, 0 index: 0 \ No newline at end of file diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/structures.png b/forge-gui/res/adventure/Shandalar/world/tilesets/structures.png index e032816d756f8d3312d6859e4b4043c22b5801b0..444966a1c76855b33e1684e4d3c21773884ab179 100644 GIT binary patch delta 85318 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 Pp^03B6SFg!$jGR8*0NJd*xi#2$W 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 fgfF1-E(*CM1ogc_uFNraEtBxcw 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

9uHEl7HD1d-NuHG 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

6qgK+PrNSpLg~OGRF7_ z$c4-n1%jj1#ReCDqfUR18t6 zpK4MvssT6FqpGt*TJV0bR0_($2^9*TQ)DP-MNsd5#w@HyD_hu76`K9`%F=y5&Vu=R z63fBK!O5&wwcyM%aX?2K=QG{<4R>teqM%^x!gve=0T1nc7^~Ktht_L$CVW7<*AFL- zL!84mzOo`X2)_8_AhZ0(`a2%=fBm(*-UNAe_i=Prt>?uE zyIK=W4jbpn)SM&v342nhn8xoE6fr=CocabCiu}|*5tBhtDG>LhYbAwcee`0XS&GVX zL%f|*wA+(3mJ?Dl($PQ<7qkIj;yqQ}u0?OY zu#L}both8m)fcqEz{IDj>zBXyoHjOp?w*0y7Xi(9_@6P}#hk1s1HbS&`!wO+FmLqj7t^-rEol?0g>!ynx` z5Kia7?~GCfcxQp3j}L|uqGyd#LUQFVcD{8$-LY0dVfb_yPQ`RSfln~t6AIY*20Xuj z6&z5)a+vkQDJ#Mxx?HA)9)r?+G8vQQKC#_Q;gL*j_rY!s7 zNaMj#h=TGQvC?vmMe)GunAe^i)#b`AWGG!NRV$c0l*Y=*OKzz}f zCnrweVAoIVxqsbcw?~JvzLYSKZSBoYH$ISbtAt8p^|DE3<8G#K1M(Nx>WKQ`J3&W3~v^Up=-Adyq<3uXVNo&PYm$Jodd5&r{qC0 zFjAb$k?GG#-H;v#wQAf#doSbCFD_(A)rJENPLHN_N5dU5%o-%04fmI9rnK$Og;#3T zEQ}2cZt5eoKZog1RR~waTNG3(vUxMB?36nmV-nS3sP=dgjf51a?9;*Gq?=WGuAW|5 zqSNhRveUzX$u16m9O&Y}fe!Y|G3ky2lU;Xox|r;AG1={5vRnEn%NMDoi^iHY5vgiw z-L*2dba7ukAeoSV#(AU3*LezcG}kXb>r|R-l$abYF*(QL*8ltq&c`Nn4JZHpbR!jq zd;KNPUPP(BlsKR*eBiZb*5Gt}&{9K*aoRhd+7>>Wk!!Yp&v^alOV_mJ0bgx-0XC?mwWvlc!V6rT_reQQtToAZOid|6PZ&`J|l2*@=!4V>t(nCn*>*JdkCioi2_02?gi4c)F6| zjQM~h1q!5KM|u5ZuZK?AbFD;cvHD*}=t%JS9FFzReBMH;i0b)cCVW8BvC=#5!K_Et z1)K4Da3YbEwEi5OW03D}zh`%)j&rouPjU}klF3_!EeUUYQHQSnN{gjM zUe}=tX_7)T_iM2q*7a1sFP#2AE@)5u#Rd$b+XVop{^faXU1wNu#najoSNve$^)C8} z(ZcA9p4uM&$`1!#zkKwxwv15d4iGD~2fM`gSGUL1*EV2z0W!^e0BQw9-`zLwuFzoXFum1uoXL(QzXdB zW|}0#FMxelZdfaL9Ms@+0N~X3pW6<9>4k*-J%Bodd*8Wn+Vv}5^3*nQE+Oph-tn*A zHtqW5D;KoGG<=gC0hx5d<{9w3!cD{v7cm9P?4Qg`W%f@8RjJY}t745(`^PR?M(;6z z{bQu%pG}N}lDF(*f9euU2cV7z8~W$qkgZDLYV0p$^FigMTgJ|qPsONbBMW1H4r<_( z7+%+XSQm*^SF2aDpIWz`&N|clI)V=ZfT9?lmJg_oj|V{8zwDsapM26t+Ze*n?tkQ< z)~|Zv>22$!U#xdPcCM#`81Xkis{l6(SA#GGSfpRn5G6O_MHh1atUH_QOfhjSjwO|O zsj4lA{!~6x$tul2!PxiKjTKsdlvDre+_rp{pw^Jo9SGC`r~~Y}y1IVFOU`RcJ%w}^ zNZkPJZ-DLpQo{$ddTAR$fY4V@o1Ttij;G_8XPo`#7~nXzKbzD6_17lii z2VC2Z>&U07gl^9cwEnaO^V$Lz*POEV-t+T;){mZbY8%GWJG49@)(AxsEbo92Zh!(P z;!ez>%cQy;l?!ePei_c-{&~kI!LL}8P<^8z2mM zl7`88^-(4F>m3gF(yv2*AG!gcg+M%yxrzgNsBjWMv-UrD`(`G5Se%D+W_szr{O&(nWmNGL!HKyHAB--!!r~u zH#KSA8K{=2jWwqOVASqmX(lM*lP7mgh%z`mH4p(NYhhb9vXmJ4qGz){F zW`S0-fkwljDZ^|El;UCz_7Y+$rGUT{M??t+6=n7dE=eY^8~&Tt<>PD=jc)07S(F^! zn;4-hLOE_Dp<7Tb5=G6+1}Wi^zX9gHdl&!9*hrX)ml?5t=lreX#AmDG1k*hbxM zx2yS3pR&;f#aT=x#lgl7;*Q(3E^PNoo#;XFE0da9PkPItn#_g2%cKTUa1Bol#Z90Q z=~bx&xO;T$pDSksN>@wM(|H`L_AewdiZvw8Qd1%B=N$Z*&!}+ldW@LWUd(*l?@B$Z!kIM#B%V(X>)vqeY%c4^fJRGTO?TF&M5yLz$X@FAxHGi6)l?0|b%D_ov>kk|q`wOKjvU(3n3b-BA zF&-W-_J`^k`p*(EH>4a4DQ88A<8rB^8gPYl>L_8TR4uLDsDxrX0BJ$cmM#oMoghDh;yy$JrZ6>8QXl7Id;}!w2}5wHQ_DM~LTP4G z|17XN)R@z^34X$WjfpZTji@~iPodyy5WX0y9Uz;a*vVS?!1&Zd)gk7-ZztdV(g*R4 zudGPsz@#1j{1nBp&ZLy>j)59~j0$HvQ$WrNSFwcm-FWe1(vh2o8=&XN z%w6b6iC~^YFQE%%+*KN&()zCDJcQ8KYd<9Kqho(0z(5mJO#=d3lhxadYV~-re=?9! z6UhZ<qTArFa$dwfJe~SGIJI=qI-Tw)%F?1;QlFCeVqqrH4BV? z3=N^xYP#XKpgRP`JJN4#xZVK;<~&uuL5ti4>79_f7^%{7rMyKLb_I$BMr6B;qyoZ3 zr-5P;hW0p+P!UPRK_WXplOsPbIH*JFRO|UK+71Bt##dGZgmmtFYV&Yb8)70gMU~e_ z^7P0j<8A zN$sS=t2r&kacTd$)PPAvJ_>H&pHTwbi_X$duDaJHrH{etIU;J3r}DCy4V=d?YJvL@xyapVW9!>8-Xz}%wa0up|s0sd-jb%yq$>I7j)hFq)q^;tk|mU7%35S_roZ;-6+2TABGb7u+tzy_6vYSw@J5Q4F@uRbzd;e z0T^P(@FyhlMIZYoDg7~E|GLl7C-O;%;2(?j?5di}@RGB>8!j*s$Bs6PXOi8y}gK1Mc0eX^*CyLYg$pMDJVG=*Dfy9v#V)vkwtsz z!WdrfI$ct5ma&Y>dk^BOMsz-%SDZ->$%>Su3h7jKBBYm)mrK}xA1{3B%FbIRRG!HV zVEhj3wW`oE-uZhR&oI1RyVPcsx(m9DQpr{3#$2r=X-cGy$Xbg|w~Jrw-;ZDHKY(6oXYPO`${})v=eZ+87#SWxtJz59 zO~e7U$c2wy4+>3xr4?nUM&87ySfU-J@FT$i3Bh-`*r*TFURrz$$XB@mq(c#4@&3Z; zaSEt|z5)F7cEf-hg?lbcPCnbGO?Je^Z~U0t;HV;hZ=#%ND~ma-U^$H&Ow29d4R zef!zhO_oS;-Ea^MOv{@z@WD#Kp9)VLIMfsu#5){rT!)NF75m#! z(Z^>VPY8L%&y7S2H@SE69X#%ERyk6Imd$+OS->gOCN;&gLGXV}9W;8?mCcAl2Q6>q za|Nylpq(=dtkD}MYA>dnqfoQp(=lihpa&{yc}-MXds-m?5-Q?^35I8Jt9-->dFB(Z7-dtJ&>Ppvj5;zJ zmi*0eybpt_TzZ%Mnv&^>jZs3*hRyQ)FO}nNyvFxIg86@3EIYYmMWCourgH|$Pr+FJ z_!e5B-x7hAFFKyyQyh053pxJB&F}V1uQ6#_b~B-ViSUvIRKa?zB;U6q<+%e0EoRMD z-ZL@sTxWH%r}ih_c@yS5;h?Q=={u4rKCNJjzCuJb%(AL=qf;>BE!c3){@?<+j}9Sn z!u@k6uR2`d&4<~}m!#B^)6Y6 zNj0jN-xa;D8=bOwHcb1LaaeF{UBBh&=X_a(!8ov>!x2d?9k@0JM5C(xyH+5W; z^N0Mh1-}V-Ac^$Ye-?9!G2a=lqs==^bVu}Gk& zdrE9%-#^Ahk$ls6+DdhU946nwM*O^-uZv+jKVm!XnN>gi^P8o}kBvsrO{~uPoTLuO z(b~vm%cQ*IwHlAN^O``pW7};Ixsc-_*)B+UC1AOCSN8Rw#i94E;9~{I$+#<6cdz69 zJ08uYO3=w_ZM(8eBTKEltU(S)833W_0-tilO4E3@M|IlSC4b?hL%n&HD_y@dokPEr7(p;~U158UPf*>^QQ0`qdxFE0| zO^;8ozt!Z>`o&2^r-_nLLO3)Ia~PR@`2!fbgh^We#2LoG0!n$%+d9_6GeWC6WMU6e1$<>uowT!t%hQbyO3%?)`f4Gc z9Lr)3tOT=cmeH@u!GFJIc>t3s;xcA~Cwr~IyS)Ah%6w60C+;}%T`HOL(m<-w)B)!i z6xvO}KPW~8v)LvaWwz=+8$?bpI1Xml0FrXK30EZr&w)W17 zn$-+^2Y8VjhzN~`Y+jO-J##MNQY{c|31YF2{-CN|s7<*ax{)~vp+WaH zfp}!gUrFgXO+-xq1Bh=~kBv|01m2kkZEQnC+CY7AwJV5|bf@INKn6XdI>MagIg+?Y z@(4$~(U(Ge9X7IMEr07DQ7eB*p&%N{ZvMb|;QnVBmE3WoWA!~RF~b-sIL*5KBBRx* z$ckg{@`QW6 zjWY5TVFG|{m0tgKu?tG3pGxD|Dxc7@PC-|Ye)9#zf0GVVCN7;hdzU!eHF3Yy6#hFP z?mC_h?Rmnzpqk11B(?NDE}v^(;gWMB5&K48q7%TU0a4g2XD93fvuqbupYp?)Wqsba zMMQInw=fr1i5&wUADNK!4x~le(Oq`wJ%$V= zrYRZ10L>@<>P_e$rJT5cF=f#dH*0o~y}vA&Z}NY*lzb;C7*8nLa|Kfyy5Bfq!qpuq zRC3=thtbCzz2?Qk^_5{|^RX){xv?EK#qqI*>oZr88ui{mbE`Il`6@6)@MT5T1a$kc zf4Rf5fjojz^$GDunx8BmQGULUa%3ojd0Fl#)X67oIsV{e4aIbbb-dF>%^+3azU zSOeu%;x)J%y6zbD(QyU}5B17^8t?7EksHdxCk{PB&~$2Fo_LRV>Rk*D-}!af>S^#P z*am{l_31oMelXoHqW>#3u^?`Z$y7bR8+X1Ukl6Glfh5hJ#{^%SRY{rI{E_motVoVA zgI{iugnp+e$3 z4`VwpVF&S}01dMkUAZrFk;0m#AMBjRrw# z2yqe4_aoJ$Df(3QD@vYrk*GjcV-mQVo!BC{rw02R2(1)P2KLWT#cC@ zF`ht2p<&KGWmQlSW0%sCT&z1j)Uc9F0m;?*oZCl{AzqLYx^-Vf7UI1zC=d2XkWvt{ zAKnr$sLC(MFC#}V&U-uKpxG>QzKc3M7Yu8fBS)|xU>D7V$&471a)RWn>X`ihS={g- zVz4v|r*iSZ+2YC-tbscSF49C6xPI1PC#Knl*LMRKpz_wqAM=i%RMGobu=5zn9bq6^aN>xM}CTWS={{hUDt zbY5KM$HW=B#F*jki;Qv?D-?JU_pkPrB91^k_hOBfAf*t=T)QbhV>EkCg1^`hn6Mt6v%SB%p$_n`4UihN+2fVG6v1?j7{-N zRm8?Uxy;;{0`@7ZyG9Eqce72s0<`=Nbzu`tc=wHTP4kNqvNkqd%K1GkDzzP4T<+~n zpYvV2=_(w4uYJ_7k+Ig4)SBvMe+`zEPN0zu0P+H6t+muY#VXRu-=O{M+x+c};IqzR z91cMgk>X2aB!{An%an$crA(;ti#t$>NBt_;lAE(`8cq1td8dIDDxi_s8&XkdKQi+6 z=clqpYqI&(GL5C%&}c-W2l>vejfQw|d^DHL`UUpv5k16TWmmkqDav+g2ZrlR(Al&& z08`^|!O$|GMGR)0kLyf{(;$7V=y(p2n>0{540aQNT=FW zz*k}|RAp<)RU&vIEfougORBx(eZjie0B*VMeRiUhUI&E>d7JQw?4OW+$CI}0U8D;| z)Clt;J_;`M`Jr>N2=E4lKmI}I$pL?k!lF+PYCUcOun;HrO`zStWx&qEP4I~0UBL4r z$+m;>3_0hz(1YKh1%xKm1?wtU%hPhk{3G1DOv2!$@m9dI}Uxov^J^YMt? zUn1)5w%_$(wkg62V(3XGBmwAT@8S`BK1{_J$);nR`1(u?gq=WB=Cc0JCx6c!uZgyg z?D`Y6LvxlxNVII6yvtb~DWDS#l+6Tqs_3-^8$^D!Au2$)TY+u2j064q9xDlODgRt( zTx5|NE%!vqc0~8(O2XB3 z*Unto-T`}Vgx32JaM*UV=`f@bn;g`bKp1DADtG+vW-FKn>y#F(ePnVIEo(7b#(eYG z!U%mq;3y`FGGD*U{6%Aov&X6C#=-djQ;Af_-UO`KsT3R8jG`7_P*c>1DJ_~5pXjJN z1cX#aQ#?rh6JEHNn3h3Soj}jjq-a^^J$L^D-is?_hG~32HvF&dv@b~VP)q#z5Z>7kqKrR<)W|5>i>;J6h7WjD+V?}{4T!If#2XwOH9hnarheeR(% z_|uEW$P}6|s3ejs^yH>i=7==`{@K5bwQA9P2pg5)Gj(2_JYRA7QX8^DzD7r4dButZ-P_U8THLHy~dNS*We- zFU=lMX!|}YgaDG7h{k_8=7!>UVuU7bK=HJ3{~bng#(dTF$5J{@_lC{&k0Tzx8R z)nAEY936Wbpk7M{%!tg095u}7isjvSNc4T-7{5$OD~hh>KO7nnl357~yRb55=_6#i z)&OH|$mve-^;|h)*o1oIwMbZul8LEOg*U`db>~X&qRvDqOT!aa)a7gJDtv+nAllzS ztIN2ss)8DJDNy;>#Re1anO4=J(^XQO1J$Y5e^Vo&!o5FX3V<&SYe3_aVs4_PNAlR# zIGenO2v-P;KwKeWs1Q1->2zBOPWZNu5x}u>Q4lCAJo!URg8d@$2XcqsQixSt_&TJt zkr`J5qT9@BQ4TIMZ&UYh-|HR!+GQl--GT_2L1*7J=(gPz?4agnaM0>;jq&c~lZ*v2 zy}_zc0`nd}rDoJ#E1^YI8yl1~X@X{)GWQjTnB(Nx##pDNBjvNY-a6!5c-xN@AgJJb z=DKG{eXk;kU@!&ulG&$BBApsJI-Wbrz>XbjLcV!05(*OJQama#^`#E!V@&2Ry=^ya z;SY}uP^p4#9q7gG^m3~U^}j{xd33;t_L8r2>F)fIF%(=>=adGy^O(V!DZIG2zYHr)6JM7?R zG24hDUWYID3x?Qz$leS4U@ z>C(H@@Aq+D$58t;lMQ*9#k(TP*^pJfxHY~W`bm&!YHn&5ywd2w^di*_*k3#X2JS3h zs=sMxzg`l&45bA=dyYwok$G-+UQKLwZTJN_#G!ZfT!+>GsrN^x*ul4m=a&rkIJJqq zg$Dz(!2n|3f=M$Ve4gHahORMykf(8w9DERSVhDyi{Neb6Zt5$WRI0fC1%82?jOk&8 zjL8B?Fv~Ts`6IEp_p+WBw4P!uLIU?z_${{J^T1!g#~u{_v7@zILu?SMW!R0%&Bc7+ zk783{r$Yj)BG&2rG9EuMmQUequi0@u_?}L2tvcjN~sDVZp&U730}H7 zpmlFh72Vjv@$eh!>+7))Hy>i@drD&YI^qidWeOm7@Y1Mt{clnT5#nh=*x#H4;;a8@ zdH>i^Y(9v!(@z?gyEI@uk5iS}f7=U`NB1g9&s2V!XwY3D zQRa34?}+jDSZfz~i-k_^PA?{b&`PxOIQ_iBV{|x9XG&cT;!CV zyf5gY!bx%vRcf5oDpn2;LM%Pl=Hp$gLAcBY2giyDOtOnwIg~#tAw|PFOh?qO+;&*h zTX2uPNprwOhQW&EM>;@z2r2@(#KpBB=yai|G8kalOBnp4gDw*#x?J-%)Dn#6O*_Y`QGf+?& z?`px9c*lbl%zf$F5w^D+Qnjtg8Cl=N?BXv3yVyd^e1rxh&W?!iodGye8V>x8rroED zfyJ(u2Bp1%ZuD@9yP#fQ$t>_YMjgjkM}y7OeZ$s|4+8LZ2mG&%rt^8V6yoQt{d|c$ zj5LN3cZFlIdf0^^@@7a&8}T%k^Z3#!!dplY%i*nLY8A+t>vp46^!viWInW(1+T1%@ z-_bJXE64(#@Vya7NRYmbA*8~g$)Am_BT=LM>CL6Uv&8ZoxI3@o=~7^%ArH~VX%l>S z??+!Ye7s)=mV`grr-$K^$5H&4e-n$1ZZP)o75SjUq~L&EuG-s-mR#iI@|M3ls7%zOY}&Y%M`9PJO}e8o-7ARJBuuMlv}HX==4Ra?!u zwzxU$2TIDt))_Jf7oK3%C^eOxR8hCR0F&2K_}$`{ydW^CiS={AW6$$Zb8`lQD4-?Z z*Ym~Rp!2eZXqnV4TdBo=uZ6^x_F}Ew-SjrM8GHSqw&wRN3|0-oNn!4&?wu1r{M7E6mCaMZB`h*RDMy`)84*c(6O$x?k}rg2m4M{7!A z$K0ym?8=sxc);-+Iuq_IA~)#QMpU9UsNgVpHPlAE#`$m=>?tp+e5n>)FJ?;DIBc1CrAQUp$6&;1;>>)pX}(o^tpNf1XfMQfBNoED$66j$h`hzgAKukIpr z@uRT4qif2$u#t+%YG>gx#)5*-2j2ZSRxOP`4uYx|)al68%VM}F*q#pCuwbv5&9ur@ zSsyyNTykliE|&{(Q|Z5-8(Dt%c9o30uO%+8Zc8a;14{4ze%+?=&Hds9i+>@eZ3B*R z>s^qq93e@aU!?T$&z{M)jQ~)gQSXnp*7s+%mAgc(eI5SG!i04${Wt>W36wsK$*ZH@ z`%9O+kt${o)s*0e=>|BtGr)X-R&oeGnaouGKBQXXp7iD6`5%yo2E)dB)bo)W=-N4v z&P4lCcm^iO^P^sRwI6eq_`oo15MA`#lr~?!%?Q_gJlrpPeKth_dONR(d+vJpD}t`7 zRlKPve1XdY7Xk<-uM@7hFigHU#&xdh&PT>=qs}V>yjJ@0M)oFa|13S@gUi-MupHbu zC=|3^pDkJYvwZk(1lXGabhWT82;D{V*;@y>feW+waT-%p72fDm4?L59uaB5K&rHDQ+RXWPJm*b0VT zzB6X}ibinGU+mJQN^1_Eb~h*v`Mas`j6`X-^?3&F*yfAZ();~G`bn8BwjC#)HeI}A zH9i{dTUZoVdsz<}_OeWPZGiRShnu z0~f1KczZjOs+Fp~U@;8stO2No(!h{;zZ8PTarF)P>Q4~&u_ zm#i2W!SR2Er-uu|QRv549-chw2;mL?%Cc<+xJ?y)i|CtjV))NyfDBZ|_GiX4bRbiDA`8lf zN~WZv{g%EerwI-#iJUCxLEjLcqYbmu7@X%0#*tJxE!xEqS>2ATI{_EZc<{~9VEmlp z;3Nh88}hch-pLQarbm;r6)#$d5YD8f9G~}LhyaC_OcB_Zpi3_uGXiy}XQ`mpw5$zxv~QE7Z$+5Q zmr&P_$>fDeDIp4onMO`K-vaZ+TN0!n!+Rk(*}kJ_#{sz?8^AG~zzmpisaj8@^4!={3fTUrm@5JtFKqHNuyU}m7|4QNFnCSb2d0s07k@@^!e{<`yGJc4DW#Jj z!glFfAJS~y03Z|>2YB;Tt)uu&S!H%}@C%$aQ$UA&!SQYhfrO=P5XeX)ysik5bs9 z6s14Vo&{6GYx?O!S}4kBholJSNSE<*V9NIO4hz=-x8Yi+uH9aPSa8fnq}&AI;njzY zLXnvd-f7-9snuKiJ!lCDRWFN{@?`_m9c#y;lT$=U#~2d+qMQp;yUWG$z`RV=TF#$} zD^v_!hx`XtWE#eRg^zDy)F=O`2N41)g{01xLYf)Xc{5*nFIdq}ceg$sTx{tC>2vYq z+W>!PDaj}6#bSwJCoG1;VjcXDC(~k04o_^(HaSV> z8Xb%P5(qqUKhVo*y~py?hsovJ{&{7k&+KJ}?YWDhf8c8jjPzK%Bxy_GQ}j!bP+p2E zu<>}&-4kV}(IlR?%y3`X95lp*)UDZ`26+3lXP7NM)vhcFMHLo8 z1%m)}LrHUd*1bgh7|%PJZ8p`sBm|;@bROXK{RA@46P#Z4spcIec8R%s@@EITbcN{K zRB%)wjaOgr6y3evVFnX4Hjj|V5)4$EIN&PZ3)k9+L+A|PQaT1LF`h{#{u6=$ZH0lC zut*l#gMson_=(<4tlt_Rogg02QH8u|H8I5!uVE%y_jSjzM z{uytab|Odm7Q|64EZ)D1xBL%%ac=edXf524Y+UZ_b4Wy){p53gb7-(;4e#P#y?6rS zE{IPled36u%p`E8T@c=i=-$BSh=TzFgoEEQE|J5wzwOxb>*n#hX^udv<)eG{N0tL} z{;*(Y>%JGWr`H%BNw=$vBOBSv$uW1-?ej_a7ABQfS`F}xVYV6-KV};B?eCt00~zY^ z?cBVyfWNW}@j@T^1&OslosNiNk36@nHn6eZuZM`qdMbfT2SRnXtXv4M7r6NHGx@6w4D5)SY?_@#%tAc`NCJL zcFPry4x)2_{CW;7S|W{szn= zVt)!;W@1Kmq(}btNwU(jPsYPpPOcAfMYvq%M9CH?0;8PX%MGyF>mgrhd2>|GruVm= zt>|~B3@d3f-cCOqQ!X<3-OW89YBYsFE|6!R# z@O6RE_it4lN#mFF$SvnePNK{ipYi6@7Gklm91`o%uzLD}zL3d}2sga**w`hQ!>*w4 zBJ7L#qb5FL1AImZ#6K`Au?r71RY6cJKQEG1f?Q>a9d{nkr677!lVHD_0T;jI=;EI> zBa>K&K(tuwr4l-Kk>EZBWWV5kVk6BWOGyLYJdv%d8SRvD5s_0j{1 zzQP1U8h`uI*8sliCzbkcwtaTZO(Qy}iO`!|PH47Ws%TXDSWZ|{c-JOBNMq*<0+Wzt zlY8?N{kh_jL!GmyO`*J%d#eyVkfCMUKYNc>!vOC0i6^G-rM@S$=(ZHDrcjrN*o!}X93!$HK+be>!P zP*+kjJTgjrJV1`3S8N#m>B0`XyEwZpmYJ4tSmKN1 z;hmuxkv};-nQEGV7zJ{Yr@urJV;#`BUuTag8wXR?cniFLj-1eZC9|a^TKr`8>vm+b zX5Rxa^MEmTMn`cyue(PZ1~bl zx#9n52{5ru2lH!r7JB$79~X})HcVM6UB5;{!&`hr2+L@;Ue-Qj0xC(j*1y30od|>Z zH5sp@s;}wdtMTmY0g{|Xp?}KoWW(6w?`|<7!MEcwM{dRWPC_zO5}6+|;AYHzX)Y;JMpsKX4qL$;Nee=5D z7kcatK|krj6CfGQ23~OfJ7oto$b6CAH{L{&P>ilOQj_}whE|*=a~cVOy~8iGI*cKp zEhkX*2-)p*bFvJD`mTtmT490_^(MIb{}2!Dj+%m7Hl{&dpqvFY*^Ty?wfBZ|e!JIq zmKPMqt150zw@L-2`XDvFg9yhQa4GwkPL(!F7aI_hYqu2#@n(9Me%gjEQ^QKG&3OL66(~h#jbq8SCK*Gu7~D14Unp`xB?) z!POl)1-^G5d7F%$pl7fB3vDp@ZlJkYUmTG~JjZ*;7fmIbXB)4N$B&Dp#Qz<{A6N{` zUnYmH!kc;tn@WlKaJU)W=8pyH(N8cWchHT1DAw0k7H>!t^@Dj+z!2h! z0*aaDv28};TR-IA4YTMsUV0}=uBy0$fH-52-eN(mGgq;TpdD_VnELrYcagH3xq}~! zT`u&)h<{H;{gn2~UA3Hfw)vz6gu3JzFy>}x0aT}?ZghT_J@8-9FVV)3ra@}QpE&AxEwGJl(a_BrZ1o_j@kFX8io1B9 z<9^HhnE3 zK&W8`j*U!vb~wCt;<5HF1;1(Iv3z2ha8-bQvtsTu+@NEK*a0UZJ{;Ym1j=+5vJfSY z0Bf;=2d#O|Oej=`j8H+!5KSgB#9uSE>p-13t0M+fFNdVPH4WSpx#cW})%OWVp#7Tbe0nanDjV}*-MvfcaeD~TFI8sDT*s}E zKpgKUW=teB8|g2da`vWwSx#iKgizE(@k7xxn9AqR;Xf8IDNZyo<2$7fjM$Z`F)LrT z-G1-TCL0xKZPpgk^bX{Fwz6+k|Jtxb0m1W6b(!_!3O=rkfYuL+XWkS-nm3$i0zkHb z;xyO830i8fJ;D(z&E!k0h1owdH^p*iS_3o{kENS{qkz3%GWSdLD-djNjWjz~JCz3P z>AR7Q{^*w`H(yhk#&IWHCe5zoiC06`dz>eqRo6qHb_%@PRf(z^v5Tt#;wb4&@BCG~3AhNTUVC!8vrhHQU$}2* z0QGBjcG!!pQYA0997unII2D_~VNbbAg1LY`b;l`+SJh#Yht5;SR}6&)vJ1F$xmd$0 z-J*tm*!inTK`17~XUitx4+*40Fk9d)jsNydI@CtBSSwsJ%PY5SeyLy|Fgl=Namxs&j>y4XW z%FTD;Yr&MmAJY4#5gP-afIaU}?;~B3U3FVhtQFBLzi|FS4k(*JNrVVleHNnd`LO~1 zG-=vAl6QFm%8m`lRZXySf9UgsvaHsO7qn?mjNR8jnwO1SWNoZ{nPDZYvz}wdkdMd> z`$;Oi3!jP2ge?PQ- zOWfZ~?ZcRrNH^xk%W@sv7ZW7WIU-L}gTnPKzJ|1Z_KBAVm5rM`a!264hVqiLP?m~E z>vkOL5GQzu{!l|gTM`+LDWUx3qndggN97ughb-vc%;!vym#1Rbf(hx8Hgj_*GSPUw zW+tWqk96rIaTAV14y4#U6e2t#AVaDym3-w#Oc&~37L)!FmZN#4)PMjJU*N8d6opKW zP3=MjX>`-$qr;yS+PcUxtrPi+5%$HFOdL25?z3IqDVJ-#p#)qhtVuINV!EOj5Xw1( zSttZUpo&%WghcouO`16fwiwj)O;^(n%FUZANx)oRA`M1V;GisRnJn^QS?X)A&^S9g zoHs?39cfDH7UwvnUYJIo?9thepW-6bP$HV&>K)*A-6>8R{sKIt%^A?mW&ssMXwu4i z>PZnHcI%}t)0u5_<0H#lJ*>{N=(tIeHcldTh|OG3RGOW&Aq%AaJ*hMO*ayc5USoZ za_MgJaqOVh1l^Z;!r+(#hdoVPQJ1Q33g8WNpk$*68COvKa|>o_P$}>(x(aWT2K_X= z%+?WEq%VbL_*+JVbZn9sj)Sl5G-1&G&y^TlqX^*;+V_|r44)&r?zI=v}S z+tG^NOEklIRxH_TcG#j76WsU{6w(Q8st=q|N>cY^xZXKQ6W7D+z?s8D;;)`+!-~+) zosawGA6&R;`CAxqE(GVp#I3!*{U+{O)cLDCg!XO`BxUHN#t$-l(|+f?{(j-K;w7C; z5{V#KO1^1?{mNe5T%Y##cmW{A#q9UDWoMF>?>imTQb##_R+b`!A}BhjL=3C`2v`zy z7$eD3w;FY}zZ*%EIPC(#M24+`BX>$CC3 zF=0@$8mB>2-$Wl}HLVzluusMc#6!;`mF{a`P1mE~Bm&CUcV-VK;2a3%`Pcop`|%o@ z`ZS=_5?tL+dFjVC{9Qs7%83THXWVS3V)jpjtPsyh#^iz4XnwJH^-G*9uikc%ZWL@# zkOWm(gP80;zMDX-F&~t3X3wAErux)6k^15!S5{!J730^C2}K>-67(j75sVntU7yI9 zd}rY^l5h~oQhEaMP#CaMDUhh=fOS}mHd?4idgzAWWd=d_c#(zHGba%RCt;$D{{a_! zld)x+%)Ck9hdCG$qUC+`omzi{{8#9eLu5ksOhJ4I)mq_6|1BwQt=fjniSH->9Yo>X z?tj$GS5fKCD0GFQ#N;*SaNaQG#m48AIK&Km6_x#4!rGGRqnp4o$?(M>o__<0&xbKV z!Np8qgKQYK6M= zbwuu7xugB>fy?2Ilo<#5Ptw17#idF5L^L*{#Bnc##V#0PBGDpL?X~4l24i%ylQ$6d za}w_rj&o5z!+i&)W*3BBDr_%(Q(TaqEg}P6G)RIup^zHrs=w)ET+yuZQ;N};FN6kn z!W0;bLIN!?p~@L0^(SKNnqRZd=rMR?bf2?~Q*T-SbrIeuO#FOix8%{o6Pn(!=G#Be zij5Vm*BtsvEyu=2&s>VjL(%$0t!8Sly*7C}^s)O*UH1t{ta+_W7bF9oOB^~#xRwJO z2o8*niK{1g7Z}x1cJU$N6C~7UUQ-tUw*@i7 zOzrGx9>Lm&_*Wh#Rhz}#O!kN4;sJ?qR)yI>DmT!HYXV989_Cj!QRfb}5ndDuXS!_S z-99clZ)HGPSDiPHYA-Ur{T4ES?azxds zQB)UI@yd0a3!UueS?kRQX{Z#(bQj0J@NgoNh0?cEJ7Aus5=5@x9?Lojp`7GsHTBTG za(*KEfI<;G7T^1xr!3~LB?=-Q8?m|(URbDv#)Sc{2>I(Y>(u{*Yb>D}v|>a=zeY>q z$$52_Nq5A6`-Ey3@j$uZ#jYtU%zkbWH>D=_GGM14DJOUqhm-6Yj%U0lNgMuY=VUy_iENX#P9|0lj zj)??p6m?nS^48`PQ3}(NC zVc?(7m8{-lpKKbK{u)3CjO06^39w~{yf=VGN=N#}kzp4qZzV(`KkIK8HxP#an@S%$ z@PSEYZvY>9mWKcoMBAl-uzbgX($mg7EhPX;w^qf-74|l>n6BGBU92S2Oef9ODpjz) zCMY_-I3!xu*v`kqk%_J0(Zs|K%Ay?qE`KsMFL3lAHHsPIE5We5o5}y+5f|=TA;d$b zG3(q5HWHxNVI`T)Kj%jjnPPY)n8O#ch$yV`lu@U0IhG;FylddAQJjxy6=X&_)B^CbAr)ZC^@M;)gT=VVB*M` zR@402?I<6~JP$cb>ztHoYmCV(x00n(l`4#3%jnYdqNAYR9Kd*v5r&Tom;s&mxWnS! zF2lR{$Bt10hrtttB6V8E)mo;$)k9C(N(NKcDHfPQ0bdNIRb{bMmjov)=A~?Fl+>Sn ztjDN_q6cV4V)?dMZCc953K?wF1*7{zB$@+Mm|@ODMH%(kupZ(GB$lmlMk1j6BmYGN zDfk4acSebx9Q}5C?78%zyaph1+IFkQKR4>B=~`FlPV|_-D;{b%?+{V8@W8nD)ngy; z0_Ocx%(J3?$e9g&t|X+aHB>HeNRB5mL;5}NJE1UN+2ST?J%r*D-`1;)uUY-xHtKuT zVrn+0ZNq-4p4?~g%wMs6#})k>dl~@%70gv z9cg)b9}dx#agkPDMgp%0OEStBq70Eq2XvY^Q!**<_?j;Q7``_;4STrl;8Ki+Df;$S1v<;`;S6LXT$CZ!=>xwIQBs#N^;-tnl zclatJZhm_&mI^IQ5P&&;8lh|~m@Z^9+kUnkn=7TzVvz!sgE3ekksn!`QBE=>k?B0Z zO)HyRDDp)*GWJ-|Kv07C6O}Wm9*9=9j8`)vvrc&9Txld^8*#s|QCan|EJS%cDPr)2 z`;^;N##Qg{d=rcu({z!l1OnFFjb^oz;1No_Q!48ujb=Bv-*7i`J(8L@xuQjW$uNhL z2)f@#uL%>-edZyI#Dp&~UhV^NkAIL{K)#K!AmCd&P~2G#(FPq|g3k7n{ws>B$lEPf zS^~yF(_?wTM83z58tw z+{4_T<;-@yp#za`E;ISJ3eK-Le-U7*sv|$kVie2~dvlZcj}kr;v=hgT$Oqy)tbC*R zA+0NyrK>xjRmAqXLlvP^8m&Y1;7;jZ-o`ID=2PK&Q zblR;CvGUO=r6&44Rn0vNh75~3K;pxq)rZ+ZFZVaTsSV(9tWyf?B`cP={R>*eL0Dev zXk6#34FCFoPviI%tOFX8kgjmT&81OSNM^DPAr=!0&eromn?IV`2?-%Kl;9T}2wd6L z=xQrS<*a-oinESe6UL-ZA&z4PR|m~RaZ)(^KtXY+5=0N*5;35$s;RZ}M7~d{v$8D( z{!E&Hp8$~5CkBjsj`*GK=BS@8+%C<|F_vr%8LYYL@y_1Sb%Q%|!Gkj@W| z`LNiOt&CLJh8h0y1-;QHw7EpPUjKd|>kvOGd`ortJQP*Wim7bX1buUc`vZT3?*v(0 z6(6!do@J@9{?ihnb}uqMw1(_)aWN@#&aw(V*}eB~{RlZ15%hB}7(BZ+Sgl%s2D)$3 zs24zla0HLMZ7*3E8lr1Ih_gl*JNB_Coe8nG$nJG22mLzrG>>=A(@ENP+MBTFDRQ}m zk6x{9h>##$Dx>Ej5sqwnKv>0B0C4rC!8mcE*t#cc-pxIF5{}<5^S9*WjLa|vzp9do z&wENC{OI6ZXm*34)(0-!L)3fJYn*5VfPtW*7(PM(5l`&h(K$9bI+B+?buvnwI7 z$i_{T64qDd2aV;0#VDzg<-t{CU|;zLhCy?DAd zAiKDxyD&j7K}$t)J!qi3kKn#}zr4TUGS#m^Gb+=TGg&Pt#6|mN?R4w5RlCO*x92{VnRLMuqF*J)XNtE!@GwGgAKM7s z|E)jq*^_k3QPk{+jFTd7ddP^5wz!8z$O&Y%FWj73X4o0Fw)FYbV9Ol4#o`b3xK@q; zs4d==2|dDyO47DBhI-j49_eKUjSG$c;qsn6kWE%4pS+w0WQAcv>==sfLw{1X*V zJFuLilh$=v)<`%l!O+)Y?7V*V6tJdg*|1oC&toyeFt58BhYCHWqZ}NBxk`aA4jW?m!w6btY?cmsry0!-7q{So554 zbm)+?l!?jld2K&fY{qENKdsk(@8%^T*63rrgvqAE7#;AhCZ4IrkUj{jgB9&9-86iv`HWk>R_yi;H9egADn_(lA z6QIUwAPVdhp*)pCxko}W(;MT-UZ#KN{hcI|LT!R&z%(x!|LyN_F8y)QwNSR8F#H*_ z^U?@321#P^w>rlhgc5j6!u^EUA32ox>YQ*Iq5XYE8nKnm`Tc!Jf90MCBg*yIs8+L8 zZN)9kuvu6^W&}k`&*Xo?Sd*c>AKL#PO;;5ZSJ!ND4+IVF79=>qAxN;G!3pjV+=Cq4 zo#1Z4gS)%COK^AhnYr`bs{dggrlx9YpMBbU^=ja^BrA+^hbfSTp492I6g63R-heFF zY5VQ@rpb5=OEk)7t!WkldWFD$|I<6K6)gN&w0pO!Gw3A}7HpFewdgJ6wdqC8VRppL zbDjJ)LoQ7)7({p3Rm|bLDK%EGyL}L3@O0?j96aZF)Gi7xGbsfw{5fNJ%ZU^&clZKv7>kV2rMv%Plw*s0kdkO zt;`)#Ndcj>X^HER^yFiE?gwEY*-YgFzhC6Jx&%^|_O)l3;tR)qKQ=;yua;8l=>mso z4JUpdG6+!Hu%5JzJmMzIC@-+P2dwtqJga90Wcq?oq*%suJ^L|}qU%kx_ zAdcFz4ZPUHU&R#sx*&(@f=9&==Wl}+X1?DN9Gznv3k_1y#5}qzp4&L-8WaNiyZk-a z{_$%c2@Kqz%Xv5C6{)SPy-h*0re5>A0Qm3s;Tff7)b=BqHd4~9$K+6sS6}-U26-zm z2xR|57T6w-JvgS>uH>k}m{{qRp+S_ScJ5&Qej9|#NK&63z95bA?&-a8H53CH6->j; zKZ+g1)$y?gkYqZH3O-TD_;xwwBv-VmZf+5rOMmGdM}2;n4Ejh}NtP6C@Px-PqH+Kkj?71m*(A1903E<%^%{_?PeQ3bI}P}^$^36%C3yC`AqvO$o_95!rg^R- z!w%{4G7Mb+3tm-?uY!auw|uYDc(~;&@&M|asb>a(J&M-vO2aX$G|gg1|4)$G*X($FL7dk2Utz#IMCK z%c2WIogkmH9H%KIg+~ry;ck~M@h*cr(UR#ZYYcIxReJ7!S+(qO*djckt8(EB3oz3v{+z36i+^TvXiQx6vL4AjL8vanm4%S&h*10qGe z-QkPto^HbCJojc9z7HOejY3OUGZdG0Q3iM0eBi@Nku*-8Q@(5()kYPLMTKPgTJ+i( z9UXtOvAIu$dpaC;lSz2*)vea#Mg{CpRTRfCSyJNouxq=5k$lQx-tQd7cv5nTtk}4K zgzLIqh_KdFv|UHnSkSO5$N8-Q;Bh!v7?DYtxo2p#|Kk2V+4G<2va;O+QkgezJar3~ zQib=DVTP)3FO8DICP9A1uPAQ+g-ae|K6yGckzHf5Q9F{D3r{!9?nWm&aQ`_BHvPxW zLUog0%0^7xag0qqlsl z#@MdM*?M{3y9R}W>cqua(FLX$u=zD#jf zBiDnREGRt7b-x%@J%N}r+`lHmoC*$+{W0Y(r8!f6l%jkb2gx+4Q;@BwdlHF;(zj7P z#;y)L68-P)n4R9|*IA;tPz@Nm9D&OH5f;)Xgi7mmaB!Q>v&W>!DMkg~@p3e?qJUcg zY1SY8wn3sTer5^oIfGY9=(htElB&(e?6EGd?Vb&x(O6NSwW{QyU%gVTEM4A7Xj(34uUx)+*6)i?^Ch!i8Nqk);GUaRza}5X3 zpH67pkga|a#QL^*qoTAKDIYN!I2Di5n#yQS324v2`Ad=W4P7hOecK40m;EWt%KyQ- z6I@*na2erAIxl}kd{-%+UJxJHj|ulmRd-s#;KnIA$R0(tgk{bzOBtG7olLV#<+$^o z)8F$eWAm+#_lv>IBP1>wo@yf-?TOxmhCCHe{rqv=`*|l%I5tS~F0Bg`8uN>Wor(z{ zo(_j2WbW>OGg%U1r%^mSywv|1DdO?rvSV)~J`ZX)2n>85qjn$lop4y825jT?BJtyY z9EUQm^!uiTEyzn!tl@L1K%6xOovxky0=m&g_KZM#vM6bjp+P!g zZ01|2bQs8{$eRg5u&%sQA7|(u056*^&L6L4?wW}!T>C?E+T2OdRfc;iE;eHV`{%q& z5!8=`+)h6eKS^E}aQK24QjGf$y{=-a0G8)8R-(qZPX=9U7%=HbmJ$9R0VD;Emnxxb zdS2UsJNqojxhmnbyk^jYH283J@E&VjywIA za6|5oxLSuA$CPprKs%RV@7AH;Uieb7A5{(JWdl4n1LhvMX!-fYdbVnB^h~L-$lAP4 zC_)IJUCB{>bspIw7u;!b?EdwSCmZH0$XltqdCs7(8I~Tyve$1AJvAK8yxot8O(o{T zQFIC+2^)uqzOi?EX!tcb!MD3=Lt_l|4^bv6PSHj){e%Qjz$3c`0czmR7b!74v3}Cf zIsArt{v;JA!8$Uwkt5q;#ZbvRw$5iPVOYNWmu|wIb)g9uWzdOAP%TUf(#4FAsPDuD zZT^b;45yP|^&0F4P=x>wqKBoj?Il`$E7VOx@*WU=V8s(PWhJV89BEyO^Fr`^C z4IK5MM+ zEXbxxBFTG&H{=b4?<8mZEQ8zvjVL`90(4KT5V4!PmN-XaKyS{ zEjbzybszLQirFo+(s`9$V1MK-O6-m?J~TX1kNBBQjfb31=Z=_#iEgv}AP|NPj% zZ+;@^uo6)I!2Rq8=8oBXY}|(qjjNG#Q~TlFKOrU(QN&G@i11wJd?H(`5G3(EGy^1O zUHB(4<|mmGyQ;(iZI}SAkF>a`RRez=*l1CMyevtaQ@aGGcFU81!P3KK#& z;cq#lsM+$Ec$kW3@^A6IhI7k)S}Iph%DytpCF?MX{a#E{&oPKeT4Wfok@mYpAhBI1 z{mRejDM18(Hwu?ZD4|V^7*s(@I|!^6;ukPer!Qc$h*H~nD3CevKF?VFrdj+sXu~p{ zd#qX2xgy zj$XLgrSDdwb&`x|C~*|)OZLIfMIC)r1NFc$)-QW(zu&a_9=*3LOMBvh_dSqhO&dLK zQahI6cd`HD4E%3Jk9J-{UzmVF?N+Y}i=flKVK=`Or15@ybOou! z3L%RNfo|zZpXzd{3&P09zgkKwtL4@2s=jpeh`cN+91YHm*oUY%iLn77`Zuk6e^mOC zF5B=A`TA^L~ZRR}Pr1 z8sbf$!9?Syx-MZO3|yn6o53kFD`(z(KgHAJiB9m(eBFh}XU-^oJs$Gg=Tv=-B)MOC zPKLyEvRlf*wZyvxd|I+2vj{%+2Chs&^4ginu-~_}mpkCmYI)a0EUxh2WIA#%_`>pjQc zUH+m-?>&D;@li9l><7{NuxT&`l3V zx@IoHrrCNw|NFJSj8WWgS#K(N`1`9|@0=O}$Lvg*NmeDH9x%Lrze%pYO`QBgB=tHW zNWbl2K^AlP6X!Mx{S2amLBL%66!%jDt`)Q=|5x8zD9bojzF`9L+!M_eodd4K|1Z^0 z(sLkYSI}*Nl<`RFpV#K`OZk2=jgJ24*%Acut&OzI71Ag(mg)>5 zDHFtF(jepl^i`6x+?Ej5clp}m$c_7Ff@v4;h?2W&;X_p$bP&`t-_$HtZ?-Lim)Fxo ziJka}cAdXG_l~#Cx22nM{i~u`1j9pT(@r8K-0>qMVAVzoq zAb(gi`MM0x1IuD+2pjl;-J=(7mq2LSpn#oD=u0*F4xO9g-|(l7EXrlns(`X8$57dA zj(B7G`jwoAQ}m13y42AbQ(_s<-&Fd z4P#_@**#@(wD$DLhdgcUpP2rfoKTgdV*c|lddr}Rql3e-n0bu(D!0%nq>%2UwzBy# z0?m9FqPt=cW9a`RQrGoK-3FY+Pys4lG59Md{T-}odA|H9;5XW$`CYqh!WSkE+e%kc z%TDPz^(4`w%AKDIXfstDQXx$|ei!n3Fhpvb27Ugv#`}#S`)8&XTuN_?M zKQ-k2YJou*$CJD2#{^IO{>(X6={e}d@j42$5X0{K2H06}g<*I&!50HIu7lG3MmM46 z13E^s)`e=>H?K^vwVvl!4hz0F=+4=r{Df{{`;JYgH^y*myjye#r)>Iw_{FmnLYuPu z$4J&v&m`NahP9lbyT{+lo6)y|<;dW@hhh;rUZqctrtsZ&{=Bc~NMCP+lzzOvGV^`L zdQZmIjT`KRp-EIg6&{2(g^Zt{yB*!Jw;wS0OPJ+HHHf1LLq$5 zK5*Q>JDkfRFhXa|fqaZ6IPSu*l~X+`8V9Te<`o~Ch=9C|3XCK$M-|= zSP>(C7xwM&#;p=7cgZH?WI6K?es+HrdBbHba~pp3xio_fp#8XSZP^YN860F`5V(GV z;&i&ias3e^I2gI1^s8h_3GEg2uE4?vVyzZhe}2W4NqJck0`umbQ@(g>^F9uzc>NCA zmE%58EsPvI=OB-jR>TlhtZtqadU}}&SUmgtyT57!w9ev5GknISOQP84o8P4?Yv6?b z;LLPT)8_=@0)-lXPvf(crConc-ohSNnTS069?9u&yv^K#*Kq`EC&rgB^=S^Ph^1rp zaY(vqV9oC#ODh`7+QpOx9R#tR#|)rmpH&QgPm)V(cKl6rADMwxqQkZE^2bP?NHABL zR)UVV68;LCS%g~UmE~=`a+@H+%)Q-TlY3w0p7=&g2k_Dxo#4q{ez2$PO**H;R)FiY z_T;KFWE?9uncWhA%Bo`9{uGWRBVDU%4O8_|Uz^3=?Y04b(veLY;grtTc#$3x0bfq8 zoH)<|zA4xdd5KL|HgA1g`!eoBcH*wz0mdRarIq*{6H>U{@Al6R(up|T2>u^h`{~)} zwQ~0M07MkJW!k1(&;4*t7;-vndUI>H>>jY1%3#KB*CoyNlFq;K2PpV!p#l7yYuJ;=Ru@*gq+EW6v}1HkpiY^It6rZ@_N%v8WsiPu$l+g~ z5By0HrJpNvk3Uyf4jmK1WxF$lXS<0-X<$@10DM%LZrn!qiK~v#4!75&6Sb^{hHpNy zzkuEFc}V}C>~)+2tQ~}0Uo!blfwPqJR`zSAxk!2Vhsb)z=eNK;6-l4%ZnrJF*P*?L za7#l@InbBT7uJWA{!5q2Pw44?|M56T)862hd%jZSg6dx5V1(QF>L$iNVE5o5nV6Vp z0nLW61Z+A%1q5sn{JE^6Z&%8cJ1c+b_~;}L)=Yvrp#xX zmPM_i>h%=L&?Yh+b}92xP#%_scRNoSi2DgpYJddX^d`vJSrzs{%Wd9S#|N|(J!_ID zpnOVR|E-#Ru(T%GEXt1-+h+iMlMnA5*|Rqq>F|<2G?`M~Ku@-IX`BA8ra%D(y05kF zwgt7dZn*I+AUx%&|33LhbhQaa9acU%_gc^h9+pZM@#QepZqA6FW9%MNWZ_!>^P#Jv zWJ(1w>Cai;U|Bn;2cE9>y{a!8lns8Br6h0~!L;ZeM0i2|^Dt3Eaw59-Oz=81)_>`2 zHaE%I8MwyZ1SE03vwk({euvBr*hAo}yAHOd;}vBrPxAwQV4mW~&;M3qxP@Wj52zHr z&C>dHGrDLp{cVAD;*hK2#+7}SZNtf6HYDB+K@gtJ7wCVEvh~D)*0zw)tJX)*!QRMh zPZaJBz1VYZ5?w8I9NF$7!_B8ggTh|gxM9T<-I@xW4Q(9c1|5Od_kx7L=6a7K)iR~m z*P?9lL*3^Cj&uZr>;DuFi~A4h?I#A5A_4{tjvMV+NN@r$_aK) zt$~E&s>sqx@`*I=EMk+lTsxAryx~lxb(|&IS!l<>yCHU;_%8IXe%w3>E{}97# zGxsSX5lS5|>frw35^|ZY=nI@jI*W^*(Dth%?Ok^rh!&nBcF+yfQJ;m44H5Fb*Ow9@ z!(`{N)=$h*@)GG;~$NvmR@991&@|n&k9G8 zx&wF|1ly!f^~z4X){m?o%ao%Ae9M*#cB={x2cC99^|H~-mtcFzAJr~5QNfR>z%G9fUpF*UXVBUg0 zw^p1`$d{H42NX76mGGCkeu{P)K*70jXA~pG!KrA5&%gtW@dXXY+NN;Dt48b4MyX5Y z6+d3qu>Xgm1)wNe)%Qt$_CgBXG09vEribSMl=mT4*gAb_O^};9g^Rh}g!}Au{*7?o z@{p8bdbKV)Ih)ES1lR=J_;Ns9Z2=Em&-HGZitp4Qj`(>82r;n{{)eBO`Em?&Q+`aHRJ+s##R{irO0#os$HM-~JzJMxo4BMU=<_K*3`wGX`@I#; z={6UeMnFy#%p*sMB9fm072$IGCoSMRav43#)AGabsl(42-vj09cC-Yr_J1_NU)hQ( z#7`*!oL`8MB&6%gh_zg~UJ35{UK6feZf5XYdwgoS94cgd`wq#3D&Y##9P?C3^bFe% zk~K+OE5~!Ig^47eiDlDk?d|S_`ie9t_qhw3$m9y^X11-z_|;g|{z#m$fqny-+X`PB zyUP6XG};N_Zw4&GBJJLr!-H=-~6X$$~AP%?8=M~Ev)%iMG<`hE_n3vw>}*}tE+g0!D->b@S@ zeyD5g`WvHu-wvWsczulUpv4#aGa37l-8`Tk+N7Y(b4AsUF@__a$CRK+w-B%&Qwx_;3j zs*)mom%Pi1Y?rc|e#5JxWW+>}uoA9v_^M@|vVImH_8j$>pCK$5)+|v*4@wMgXXjIS zUKyCf;BTxRc~I{TC3*7dmI{GkOAm9%f+q>bvK(V}7r>Z2OpaX_a0G+@H9xiNM(3Pv z@?>29*K_DYbT_i@696iNZ!58p)rg7!$z|u2iArxVcYRmq-l4jk&)FPAEmp?i+cALk zA@1sP3m`j~^Y*8XzNnk3U)L114gAOFEe2@e0=+UTWzGkkC7ksm%um|%#*CqRYu;;( zbBW<(z1Jt1B!rD0ZPZ%eewVZ!L=Q6-3lm`J6mU}gWBwIVOlnYWm#Q`SAmP_?Rz;V z2Kuk@jEaQ|DJXt41__hr6seeq%PD$B*uTrF_X~F3RnbHnJScA4yIv=jX(c;4OAEcI_+!Re{0?FSshi8aXd%I28xTs;cKqCbpiS^uJ3 z#f)A!e0rpT4dftkn;s!%lZl!C0521Wi1==?7l`opx=`g=A?{4ntow60L3e%hD10`j z_-z?&tI8moALQ1Pt>X`rMNdote;T$$E+Fb)0}|b1oDDp zM3@U@v?9;fsWk&z7*ZyK9O--Eqo*z zX$`8Agz?=g1gdvr=Vgnn)BqJF<)#RAB{kZ9aM6WrR0r?R9a1wTsmX74`6`3>1x*`7 z=Ss(8w}{SsYodn>X-yClLjb^ZQ+`K(J&@UWoiYJ_N*$ITNqj%$(<-~<)w35E5kT!I zQ68S!dW@)(e$yLGWxWC8;&O+X_H$c79wjqZvB2GeD(oglGY%wKX4ITlUrPLH*BPoL z`YLp`(m^J=R+DzUN2e!eXN}G1b;!v=-Ibu?Ho4Z-2mS?{FRRaP4*{SYVsb0AR*}a? zoopm(l&vdDgsU!A+R!y|t|)=wKPbZPqPPp4LkZh#Eru^86({`eLO31U59M5W+YJ(9 zcL`2lxx>-|#3Q$Y`sWxDI>6&TyLKX=v)k%l```OsU!e4(Q6?W$Z=QK}1MIjM?=XL_ zY>ux1^sk@$Z&{kA6@l?Jh)Nycg!LmNX?om<&by zTsby@>f^h#<3Wd)%G}Mge>6QQat$x^u~%OAho*WW6TM1QmjvgxRhuggA}|i)rAm&9 zme0-Z&vb4UB5Lo9&>`H7Ick7L?C4)1`H44KmZv1sp~n=onSw@Tj{dW#!14 zFovZc9uEpmVB{s*QY9)~hcJX}B^yX_t;g9FaCo{RjHYjT413sN*}|VkEgUX~F;it+ zqq}>v3VWJG1r0{l->0p*XHyCa*+b&bmHf?G5x{|!QcOqi9?tX(^L!Qk^k6>$of4Ezc+WBw zq7v8>)6q+d4xmUENt$QpQGbDffhoyLsLajoT^@3PP=xB+zf_LQXHJyvk4 z1yy<|N45>7rKN|oRa#>)$r z;C*Fy(=r5FZg|TUSlhjq{&#THyimTowFD#5y0ZW>G+_qMs7w+eT3G0=h3|r-{sD&! z4p~{A&cCgVf4I{;{UJNcl6Bg%9)k_PeFmTcTEH3rwHKBU^YG7fz6=H}3f;~H0#Kg{ zUC)&BjPj>Jg2hv)mwk|TKUv{xwLO1P!Wk2nQ$NG|=L||@_q79%^OG1$pc9f=ED)%Q z_4nPse1C;;D@LZz7c0z1(A!!khCODKi7{e&>G`i;)AY8yd&6o2eQ(e`E<63YHO()z7X+U<&3*rn5%dMF{P-2ADi2LqShM=E?3{o zXP$ksLLu#NW^eDr=AVjm5^?H3k^4G!E4tRef8d`W)YlHOum%1F7XIqaAFsI!QAroI zvoTAB-n0qe3J+kcTEbM&3!WS>&J?b0eG6=5r7HgPus`x9=da7UMD<3UD+ShURuhu{ zL1OFQ%YD}T>hHSa-Cw%i3DSUm7WWAMKzyL~1{UUROYrkw`Pgo#UQ~jxR+gXvK2 zRs5*5E4A4q>)m!D<_p}KAeBR_#jA(Zg<{1l8oLpoutA-&WPetHec%Vumr;#;16XVqh!()fDw0x z$iMCkU8o6)+a;mDuMb!6JWni{XtSbIZk-u*RlmWBQwcX1i%I$CW;n4rP8FOA0s0|y z6+)NevK*~$UvC>$KUo%vZ8Xq**B@DlM zzN|XWEvUkJOdB|Fogyo(r1t^~r;K`STT_<~XW{mGUnD0gpv;HgSu4LGr_fl zOp7*DeN!nQLE**iz4on`qeAL%(SRN&TX=HPAfW8E|7QS9)jCF~A`RtuMN$zlS9`UY z=~<36ofBa{fFAeaVQTb>&3A^G5XSE5q+vw1?)14ar=jD)aA*px!FpgiC_L5{-COAC z$ef@?TvJff$U>p#YCd#n*gUoBEW%r)>8H7n>&KSxq6ikcwRGo=S!ut%WLF?AT#I@8vD~fOnLR_zvXLQEl{*zNVDk$+yb|@ z6=c2teTBLD(_}E~K=3?u*JTfV8W+aFNZYndycKS0Q;Adnikek0+)~f*Jn2osRH1t3 zg5&$^GDk2cXzFlr;+u_9?)%G-f74w9)A*!WN`Y9G?S(-&0Ut}-3)`yNmg6=jghZpU z9#=}_La^Z~P_$?oUVBY+sLAQd-Z;&q{aBE3=7qQpIx?^1*F=M!kXY+6xz=)C^x3PX zYU)}w3VFGJWeW9H6k@#+5dv+7} zH|`%{pN-11s9lw{dWDvv(%5hvUqz0XK19$zGOT2 z7Pt4cfOueAkJJ$xCSmCW?J_{{H7&GXfWE)sg=Mo=K*#OLh=E1XE>!$|A1K@q+AdyB z9WVF~x5}cM{zGjUo;GIq+jiUPX6}04wnjQEd=0gV&(U)S-8cKZR*rO~uo(o~`|L(S zvFhyHJHPGLYAeIdN_I_8K=0;aNSbl9`b>#>FXCW5T@TYT! zF}jd%tw7%+@ouaSgzLy(z77hVXK95vJvPNaKo;KvZC1>MILKg{|3n1lUyh%}Hdc#H zt(ck_*aGv7bcb>Ah8)Gx2>{i@p|}y2NyjKaQF1sJ#(*t8FC_SJ|KlqSjuo$@#tD(@ zSp2C>ZCCrhl+K%X;qa~dgCtk8nw_x!!S-1{Z%k`l{l`ajy)yNteL8iwByaGH^dE)Q zPFyr(T3R#~3fkW;p!kI>ayK&-N;(~@_>5}ke*O zH4DC|NvZ!5(%uTI2Hen(imJRNhR@qiDI3GpM8kl z0=~;+PWeX_n@Qtt-cQ5E4y97vy}=Q(`61F>v>#)3o&gayy)$akzQt8~3&f~y9U7ub z59x32jXrFc$3ab^q11lSxa_)tQOu`0l!~%rMeWSEId6N#?2a=EB-X-$zbc*VUG*O( z`h4xaqUFORu2A68d9))8qF*&1hrcQj`dZ73*aU31!S#PexZuzILcf2vvv1G{LT~zhSUHduD_(9&_b=M_> z&6f?gi}gjqxtCuHzX>I;;Gm@O{W!GM76=%0#u?}BNeYe(NeZ~xnfG6gr@La>?An{_ zRyk>K^BVy~} zJnUdJ#pjr*_52T;2_c2j1)(A|seAjmWS$8Pjrk7di?^W8^d@u-K8zCQ`}f<@EKS-KJ8{@#g&c&;Zp8E?OY>|y)&QBbEZ09Kw8%tuZ>7H zZ>Zy%g25mZ1ncu{&_;xkoj&md2yhpJI-zEW;k|P!aVgN`)!{4# z`85`O^jN%@_44pRaTHFL7O)MGRw2ZDSTi8}t{q%`ADL?xcw+ICgm7Xn=(g!rcpD|Q zxDHNoIM$jvV(@B!7<$Gg&A1S<_GVQg7@P|mXI}q|QxquAuA~_N%i;q+p>_@HHB6c< zwGojAmm*g3lPzBso1Qb`4bx&Cc~z`oagGnUUE6*u(!c$W7Fl044Lnf|+y;1-TbxP$ zON{>0w!7Ewon9iM^q*rVOiXY|4A%L{B?dR&4|N^kV>-Lem^HtQ%JW{l3@_E}u(D-h zv{i{9J<*75ouQ%p02KFiY3C{G)pWUO3<9Hsv)&Qw~aUU4m~<0LF580vE4Q^v9y=6lczaz$`~;#azP$4jAPq@O7Up<5Kw8%f{! zX)ri34n@MtJ^8t~=9#ZQSGiwhd}?Ls(TD9WgIra}UJ&JS1B#rQR&K}xI&c@@r-{m4 zrROQ=2?eb?B~&C2E}kzpZOO1q1*@n(G9Z3Zbi$HxM!I0ktuJs&aPCmOpUe;g)%{yq zU6B^CRg?jT#Q);aX+BiglXyV2%z{VzG45nQ_%ZMl;~@nlf=k4l-UunD4PleQT>B zv<@cMkG3pr1bYJYkw2I2olIGY9Vvy&#g$RD4%U;rO&@hh1tpmPXrfCCC242&aW(kX$S$TUoAs=J z`tDDYN$k5VL~kvog^i0rLl)n_eTSlT7s#6}j(RdDjim0h_H)VTBUxd8|10>uG{`II zhm*OBR@)7X3@OmJ*(;yBphFs2IZ)qq!w;@qF_iuu$OVq+?cBTKbaoXK@FP;J3e{kNdqP}ES$amp&dehB5onv`639@#N^U^BiF zLo9xqELb*ZPV69?-KeA)1JfNWFG2mJA5VEUeol!hO{Uug81gcIR<8#F)?RGzZr zkK&cPub@&_W`o*=tnf<^y`IjVaxkdBLq3jE47MKh&GR($R9_H7zZ(723Xa%dH zcyXy>^ks%orjTAi?jBM^j98%d`A1WiNPsNY2^a7@;M|MaaeSWAFX>`7=g?vR4Jhv)k*NXhEktvhXzPr$a-F}=u=5WZm*5b$#C%?^JVx0MMnKMHOJQmv- z5kKt)1nmY2kkYW1fM$Ak_HHwFhX(0+?I3rb*<6OuCW+r?JlOx3I{{wLgc+X0%jiZ{ zN*X<0dQ}`n`r4HvLEn}2h7L)MAs$6%0R^iD`g2cuuxrkR%Uy_J9?gPO|3bFQI6I$h zmEl2XN19u#k0FaF$Koj{f0(~iGHb7Hla^g)1%4GeR#3_n918zK%_v(*NGEG|yFZFWY z6o-Omo*(yzb(x7n#=+M&=tir;N`b4FC)PVl6`fNAU(P@A8=r14WHlM>6=T|Ua9h1Z zJv3>H>xf*IJXER9yU6gyT0+Fa^AhGpE(HV5C`hLx4eroHejO+Dk)w7%gX|(j#+9V9 zNk^P;@8fi4;H$t_VV&LZFdG{q*0xCguQjZ?{m|jsoy&J>$k#h!UZrkjf3I7aX7S4& zcRfD#Fyt^}ft+8l=KFKprsi^y)Okv3*&BjOi3T|_xX{qu7sOQRUeh`yi3k7Sr>8nE z48drC|6>9DO7@B5Z{CBFwe`#02{V~CsV0w`eM|B7 zA4She;#Jq(gT3d*>-nmhQ)W@S7~p}a^|oz|cz3{`PAhlxk6<;l)fN}0X5_uYYm|Fs zh(8Ow@uRun95lG&)D8@C{ap9eHu4m2OVB~N@m8aa9`3SxWiD1LCyl?R4n85AE&1e- zJWW@xS>VEh8kY4O+?1m>5cI4o#hmjnat{4?FWYC%B_A)ccqn4knh*$| zv|=~g>?5Gm5-Nm*CSu~sQr#EASfm=>VjuuK-@4HC5;bB9yN8#lK8{<0-lwp4u~+A`*R5RKgQtdHlJkt$1|mSx3-S<(D@)`E`t({nnjJPt z$%h8dgr0jB8w{JI-zhzMROlZQ#*c^3T7yJQfTYG(==DbSTW*t->LH~Imvowu)(8mg zTS`}-k}EUJX!4=q%YonCU2%MbKP{XGdqe?O+dgW^NMFt)1ewbhat9-Y@4l0tyNBYUbqx!f z`z1^4wsfbEBi>exX#^f+w*b@R+f(-2B#TYbHhpu_ZlLrv2TDIuKd&JI2&l(u`zf%^ zda|do@AbZ+4k?8A;qzc&WMbjc7=KC$s|>p-$il&v(-g`AH9r$VXHR{WwxMtO54vN9 z5dHm3?QWtSA0@XA4U`r@JL}&8DTVR{rI(TpU-7dak}GtiFB&ulf0l7#0s(&sOXZfH z^1p&Teq`4b$tCIhWqX7?2h8ZIXuB^g(y>;`o1#(WTE+8xuEnLf=nv+&X8MnHhY{@( zWyi$mZQtEan;Ydtv(1uwNE6#7D6?)kj-d81schi@eB}n*XWg(R;KleTC zn`6+h21gGqekaeAXJ~3`|Hdysi9Ji~kV)uJ(gg1T>$@R09rbQ$Bg6aamu|z7 zfwBDGekl{*WL){UkzQrAbJ$Vi#@i^^#NF^CiqJpE&TH)?(TJ}*?wZJaI)pMbf{UU! zEpNGcux=lB3Hr6Qd~%VJiPSJl7xJrZ?fF*z-TzgW{k47lWnP)wAx_h z?|!5*PM&m70*2f!4T?!XUl;?uyK+sxVXeOHPOfith&w@#ujG zi!Uwq5a`h`2HsL{VH;Qw#$3gyZIB&qW^oz3%>4DMy0xnMwW=iTDp z5$d<7EZn2{U+CCKfh)~YG)d&_B_`X^LCa>7`M42DT-10W%EW=$AE%ikLqOq-aCdvl zU!sTy*M{?vo-gx3s5PyUi#|vuC?Q#M=<#FNrVvj6dZTGrC1xZ@j5pUuyNTDhwd_b{ zM$^n_QTR|kBzJKsSd(uu)Q7u6V{i>TC6(}n+SK!V^mewacs2T`9x#N=XjS$XAIglh zAcD3EB_pkJ?09Gz1g0@D_oF(JGBHRnhN&vj3l;rB@#y-bh&`M=PtpnU^-C7=ieJM< ztcw6kfijQ;!d@%|6_LD~${Gk=0_#6mqQ}eqDoOVlt{&RJ(xj@OiJ3jnVf&fBUC*;R*mnjz%ZZ>EC5? z(d!L%WOI3oaq&~=5kF>*d(S#bCvH@tNid>0p?{&zjrCg{gq+;wkO%CkrT%EtM+3%j zS$9ACo(qchx3GCU6mnRHHbt#AlVz2-;dZJT^7717!uR{J^dyXNS>~xyUUW;sRKR*6 zsqy}G?XGoPU@#`6*0M)0A3fkOBe`Zro~=@lokWPX%o_vm-S26u2Q%H=jM1!aZsYvB zyuiN>V^EonH-f_(`cb$g^6Cvf;_z^n}-;-_EbM}=#QV8dS{s>~1_&U=UH7_{Hl zON_QHSa&^x6gov1D~zClyZ+Q)`S(PO)ka%#zIG7n#YXaVj3bq(L^ejO5a{-WhEn-) zvwXRxN~Fq0F^sQMo+6Z}qW}2UvnC>YxBffU@)c}W`<<*%Th`JvwAwQp;bEtZdmO+X zbZhYPws_6|qQ1+Y>pR5;?v0r264gi+K_z#luzg@d8)Xv5*3&&4UY+KMR?NChOGtm? zn;3wi$kWrspY>BZEgAt)tBM%WgX4mYc+>yx1y6jl*8?W0NBD6ASiXkMdf7Ai+9{2( zrXM`|%R!ti=Il>r)Z0qetGP6OByPxz7WG1Oa1;f|RN4ano7=AHAsOfE2V&cd6nEUh z3VjTIQ_*6(;c&2vQbKR)(c9n`_J)JV2n!PY^g>=KHpWJxAO9~*2ebGSrK;@PVAsg95;Qx!~-z{2NaE#uC6A86do=RadD{quMKt- z$ljl{)##Y(pmj)u|w;Wk%grDO zFKNlR`pQeVgU^R&;scUW{IK!*`J4|ZO=QR7s>aB~GOT``4kmo44uIGu%zBm?g|#7f z(E#$vF+olIsi^jJ0i8SlP4W7#$1jexAJDuIOg-R#E!Pn`ze=dV))MyO_z;;bX#7%$RvSND>81Ve zKe#;#f^!GhTghS$XwKIs{ea|k*OndDIhbU_iC#!iWPGasDG6bPSkj?q6H!=%e@d4< zDqZ$c!;DUQRNH^@MXn6}#Lx@T;0qMUc+svSWRY|Np^XioFo!RyFe8J=boH}E66=8p zA(hOW$qbcq0kqks`d4f~c3k{`YD?Ca5ATfn0deDDZyni~7{>vCO_r}iFr^f%{jd)J z-(CFarsNmZV75Hg(6;FFq2txZe~z=_YXI=`rHfM|1g~K<4dAM^A^X#H4ztc;W-YqT zV%CM{oKf)!bS)h6kTDAx0!Sd3#EtGNOHj_X6st8HBLBs{IN8QR6$L zBWEI;EdRFBt`QL$vpa>7;qW5=pG9HwDxdfF{qe%r)3#~wan_+R4l1~}r|CS;1Ul7`Ct!pBCHjKbw6mHwBxc=~Q z2HQGx*7USa8C;E=80*nln?~e89*G1$tI&kT0wWrRTK|u2tp59fe_6>)T)X~#sQ*C6 z^Kte;g~3UyA`U0!? z0gd_bY_>ep*rW54GE3jiR6Zh&qZWM zGO;Z;h>~e5a1aTYf1;8ye75bR{x@0wN}A9!yO=wPhzk|JgnVykfBAasy?N(bRK9-w z=IK4Wdh>3d_rJV%^`<-ruiJIz>{kUgbNAr4Yi(nuL%bW;Dt_8*J{Li`P%*-=0&!;(O;=?30;kFn+;`Mdai3#Wl00027#!D5$zXaN3D=)LewY0^-SXY=*(>I=3u zvaCKc8Mqf7q)zwvH{`HFrkfLDRXMa|pSyUH7`}GoK=ouZ1zIh?JD9X2gp^m@x;Z8x z-4&jNllaP5w6^D{&*}sU1g0NnQZ)y|=fj&Vg8Wn!Iwh8|?35r5z8 z?KlKGaU~4_;^LaI6Gb2-ILXeIpb5r-1$!dz;k8$0&3+s1*jN-1OqG+tyXyq@>!+iGxT8oD@44)&*)x>j2{H#9?bESzhLGc3UMMK6{y z<92#-n8`0hGD{um(C3r=MNsJxmGqK)o8D~4JcnP=6@ra-1pL+C(R^R53|?h(xSgXg ze$&Ia;()ZI?A;RJbW`qRAF0~1hW@a^a4`0U2AM)(m94-1W}ESriik`?4_|~sy5dhd zH8N~P`6S{Y%UZ~-$}z*ch~)<=$&kcc9^VICZ^XEq!m-Rdpgw~i1L6jc@l#GA!G&iQ zi{!ASdo}&|N^rU`jk$R{G18FFy?%h8#Kxub6(+K3bcJSWt9fbTDrg*eg+~EIhjqtHt?UOgSGs?6^bT_|2k(oz9nM9@NaDzA&XvY7jp|_U#ZZ zqlQz}lmo-I>6N-k2vc#ySKaAwy6u2CdoN?jtc3a13$U$hec!Q;X_YjXPfE;scQ`*px ze<&uuR*O{D6RVd^y1df$+GgCuikoJ@^608l=z#9hpIhlJ4{5wZAgj5CC@Y)DpVEoP zhXH=7cviMc-7lMaM;Zey#cmd|WH0yBMsOXz_P0ZTa0{iUSrTasm--ad$XoM2j9k;? zhJ{!z_4a^`e)f6jJ;RZs(*upHE`W|QVuNeHoJ*D+5 z2ACD5#nB3zD1VZh4(YK*Rlbn2#EFq~ePOI|xy9h0n6S}5i*CD^Ql;%sQg@AGl8^7L zSj9EPCXQg}$rFi4HNxN~Hjq`G@<%(=@k38Fl_9 zanyK#}=qk$Be3x!s^g3m!6n7jauZ6Su<#|hBzvH zGV);jP-Nu?znMZDj^~L}jM@3P#J&7cBi$-i>9Qq}(8xx?WiH%cY= zhy-3CH&E8{E6BEL(SBJv&5KU>14PUBM|U~-d-|(Qy5I&vj+-^xsdmHHwCPmlrZ{8n z*;Ec!|m1vVoN}Gl|Iqg9@ z?ppd**iD=uE)-H&IA$()yGe{-G`wgz#6A8*2*o zI&y^C^%w>W(_KAIpVTK-6;n~xrZ$se&~FAMeC(SLtH2&Sigrq+KX1-nV3p?a5iZCQ z=n7gouy?f4ViU^fPdn%$qz@U=PRlejztCBeLE; zDLuKA63Hq$KRGQXxs4k{3o*eR9xZTJwd;QAypUR^86&KJ_(&2OzVXL(xTYND0y`Kb zHD+?oY*CpcKH4>Tz z_nrD%WU4{gg`f3e*kL?_Z)p=`5j+qZ9&{YyF1oOvBLPjKtVodzLAiLWHAh57w5zlF z6~qE`vf67tkc!d^8+ZMI5k2$0_MrV-gQe(?gfo`N|GB7(KT#_R&O z!a|w5I8HXtX_ZLY$FG>li%j$y-(1@;nw1(!%eQKR0@J zaGbl@NlYT7lVD9%$Cb7q)%AVWSCHqlM#TQES>4l`ejaGu& zPy_26tJ=9cC+=1aiWPGz)Uzia)J5hG=^4bHDRBE@-b^Jx_7+sKNk5Bpn&@|1lI%<{o za2xZ?orY(k6<$ZG)+urRqA7dMK{sRKn!5PDG)ruRq;!)br!%Zdij0I|o!8FZp-gm9 z#`9nyJx}@z_Tkccse2JW=hkKB{RR$o!w zrF)LXmL69__T22V*tS2yV`#*;6%XUlvW{Qp0D2v)y*bt>7gZs(+F5r9gSS@Zx`l5z zoNl)af;yuj(+0)L9rof0w{*aaI4mW>J85B3#*mmo4J-U~MPFd~apem1=py`LGq7zk zKxlF}+JBac7@raLwJC}s$sjHI)1$MhtFlJ`M}*j`Hs{D)VWmrN7NVzXPLOj+-MMXlQ5ZhM524}ackFviM!}B`QM8C( z|0TeavFxh`rW>>6fDYPUxO z)riWB@vQNRbypc_Lb4>TT}`oXvT>n;xM)a&T-e;y$9Zc@rUBA2>)9z-$^fJmxNZA>3nc4%I&k{51Ue0eEt=XA@B_y7ph@C`J zBe9;32Q$ZEmrX_9lmbNZOVn;q*7qDe$}VAe8#0u2dlmv;xiJDioNi%}sksLDUkd9j{_mzsGpp$#g+-MfYtT0b) zPbtn0a*%T?(u7BulycT@Ou~nx;;M2k_M(cBey+3VR7;@j0O23+cgqv;C^5f|7k=@_ zS|#zyQ7*Aka)n6frBGfio61jYmzbdsj77PYR$es5$#p`tUF0Ezx0V{|ArSbWyHWF( zkzaPyEq;eZ)Ru|E_n=glpQxQvHND_^0&l6-ecf7Kt+99GIt8_cDRTnUNB}?cJ@LO& z@o5kGpR*w(J=T#DFcI`PSyq|*Hw-a5n=@Mp8_0E&=wtS@W{Mp@3d03o|On+njHkcGZGG-QWr%5r0 zr*mbEuVbdvO$MbQ5R>~D5RJvWo7w?jTUixXUo?L1|7GfO~V_Nl+E z9~nHl?-*rfGeLnxP`$QCN+*})Wty+`-uJaK?qtaHDY1Xt=pas$NLs8kSyb7P#*T4P zr5DK{6q>WuQn4Ck%6^(omvbo`s+C#vX-q@q`eDA zAmi(nA~7KlQW!am5Z7-63Vkn#!aQeMmS%cmqTaWx0Jlst%bKuB5&$vlc^_V%*A9s} zB*24{i`cjk44kCqnZgB%h${2@^TLnfLsuwE``9XPxkwve<=KA98@KifmwG^Cy{Mj6 zGPK2iEP+x#7LW6L7%{5=<33-vX^RrHIPxq0W|Iu0)x$=ENQ4a0n&;1?5(@oMb;|f} zYkk?vqJZE0AM5vjTI>nQQ|;sCHDc*NP%D?4RtS&3waGk34xMoY{af)AcADXOtrsCr z{nMuE;p}UD6#Pe34HI>JLEL3MWariR?m}uYfkQo8N|4@4lc4WnTQunU!D<)+c2iyU}Htpe3lExUMeHxYbkj^usNjW)#k|Hsmy2H%UGNbUcoAPztj) zS?OedL@kLHj)u~he_8nR)8Q%`ap&Wj{^w!I{2~|8&yWsf;Z2a;;?d(t@b{7B;6+Cj zx9S*fLGZPLK7H<|$UsYIq{w6-PA+^qM%zs#Uj(X#o(A^n8*)K>y8LRH)w^Rf+(MG= zB(a?nM@L2$KF;WJh$Bg4e{qp$5|R@6_nZfBDf5+bg;IyNQI8Jv%xSK27JU_O%9#ee z_}B_sG4E0YFFIe~ zjh1)0P-EL_55X1X*>WXi`Q{gA@vGO?-#NL&{N(-TDw%YgW_C#f%noRhVPqhHK2*Bw zQAQz=-*S6~+xYB1dyiX>eI2|n9KOnvTcL=!DGMc~=f9g@PHhfJ3C%qER=@+PMOg73Fm7B;^aQQv2W9xn z81*&TJVBRA_hQGe))+(y6Fth@uoFSLKYugoTEU8}%Es%esM3}E-LF35JUcaZQRF^# z6!$iDGFBOwgt!0dp+9~rm2&%c`s>3+>+hp_{*lswlM~U9chk2*Od*1S{re&UNN+-Z zHe#OuO_Xe&U8YTl@BxnEeu#m^ByYpATlgP>{^KpL(!zXPr`s83?0qBDgiB-y8--yo zv}EsR_{?LlkIQs3xv6oLK{|3aEU@9bX0^9<*YfH**QW)}6TQ0l{BHBHF<5!Uj2@dz zLn%(u-T5e_jkScgX!LVwJW3){aCg2xnQj|OC%S=(lHtgKn zmrCKma0{eF5xZvZmnpDnAKSQzJ_O(itlH57kFcq8g@1N`?PQqPKgyd^Cws!6R%3}R$cF_oQm1NMSaD?0Tz&L!Y8*d)pi*DTRN*B#*Z(s>*Uj~ zFK0PD4nonu=yrd$W27b9*a6i)r)D*C+XU#7v4|e^+7t7yA6$Dn^KkxX^lZ#VMDrkn ze$<_W*yV>F9vz)m_bC#xL=q;ekXblru(jvIK!@ABIu1fLEh751~P(w7i`eWaa%txMxp$ODh zzQ|V`A1S1dkZ|f)UPBw}n<^i{9QdE^Z4G3=xF)TrqrKlA<%G4I*8USkwabcIuJs#Z z#*7+%ya_2xdr32s>po%va&}uI9K;R#(H<55!EMVrXrbN6_yg=4)_!mO*8=FqZ}HiM z&d9+CZa_+}x=P|t{EDJ*kK(bq97egz22~GY?Sfzi*y_hu%)VpUW_3YjpDMETej8f3 z<=&1Dm74Qf2tE{~_n%A;C7K*7d$Ha)wNX;~K0F%|?>*L2 zTM;QyQ7I8S!RJzr;(}tf&m;wHZAHWdLAJJzc6L$@jvyP+v=D(5A`nPYQcO%tT;!R! zXdSI!A9h{4hzUN<%?FybG+G%E2p%IL6OO(&+YtbOEuf*IXym+tGS|_gP^1la^e@v% z)4T?yXkv>IgJr#0xtQg0JTH1R?xWRp?{S}>(ZtWJsH*Ni7vO6M(y}P(fSUac z`>+I>&r94piJah;tpyn?nYt#CvO7c=zm+zaxG09+_0vmDdJF!2jmCDyU3A3yUnuF{agI@TALnsxJQSOXiq?05w}T?Ls)-SVrF9ZNsW!o5_1pI|Yo(cHdZ{ z`)E(9v1q}IS4tzl0*;QtJ{DE0(LVkp@P%12iN@@r2`oEQ(We913^I{>M?Y3~;58MP zVGKJw@cVdW6uu_$zsWq~QLK(G$yMk&T~)YW&c=oMpne#*_1(EeJ^=931*LmtE(JFk z?R}d&T?$r+Ntzu1D@q!(ZVVBkVU*+iPBm#qzfn^G(Xcc;fSKfdjeOtc{Ym=XRdB6J zpZhpOF3B>JY7M?ari Date: Fri, 10 Jun 2022 23:25:45 +0200 Subject: [PATCH 25/66] AdventureEditor: added editors --- forge-adventure/pom.xml | 2 +- .../forge/adventure/editor/BiomeEdit.java | 122 ++++++++++++++ .../adventure/editor/BiomeTerrainEdit.java | 14 ++ .../java/forge/adventure/editor/ItemEdit.java | 3 +- .../adventure/editor/PointOfInterestEdit.java | 88 ++++++++++ .../editor/PointOfInterestEditor.java | 129 ++++++++++++++- .../forge/adventure/editor/RewardEdit.java | 114 ++----------- .../forge/adventure/editor/RewardsEditor.java | 31 +--- .../adventure/editor/TerrainsEditor.java | 138 ++++++++++++++++ .../forge/adventure/editor/TextListEdit.java | 7 + .../forge/adventure/editor/WorldEditor.java | 151 +++++++++++++++++- .../src/forge/adventure/data/BiomeData.java | 2 +- .../adventure/data/BiomeTerrainData.java | 12 ++ .../adventure/data/PointOfInterestData.java | 14 ++ .../src/forge/adventure/data/WorldData.java | 7 +- 15 files changed, 699 insertions(+), 135 deletions(-) create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java diff --git a/forge-adventure/pom.xml b/forge-adventure/pom.xml index d2bc0fcd175..4d81b150e02 100644 --- a/forge-adventure/pom.xml +++ b/forge-adventure/pom.xml @@ -17,7 +17,7 @@ - src + src/main/java ${project.basedir} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java new file mode 100644 index 00000000000..70c595437a9 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java @@ -0,0 +1,122 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; + +import javax.swing.*; +import java.awt.*; +import java.util.Arrays; + +public class BiomeEdit extends JComponent { + BiomeData currentData; + + public JSpinner startPointX= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner startPointY= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner noiseWeight= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner distWeight= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JTextField name=new JTextField(); + public FilePicker tilesetAtlas=new FilePicker(new String[]{"atlas"}); + public JTextField tilesetName=new JTextField(); + public JSpinner width= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner height= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JTextField color=new JTextField(); + public TextListEdit spriteNames =new TextListEdit(); + public TextListEdit enemies =new TextListEdit(); + public TextListEdit pointsOfInterest =new TextListEdit(); + + public TerrainsEditor terrain =new TerrainsEditor(); + + private boolean updating=false; + + public BiomeEdit() + { + + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(14,2)); + + center.add(new JLabel("startPointX:")); center.add(startPointX); + center.add(new JLabel("startPointY:")); center.add(startPointY); + center.add(new JLabel("noiseWeight:")); center.add(noiseWeight); + center.add(new JLabel("distWeight:")); center.add(distWeight); + center.add(new JLabel("name:")); center.add(name); + center.add(new JLabel("tilesetAtlas:")); center.add(tilesetAtlas); + center.add(new JLabel("tilesetName:")); center.add(tilesetName); + center.add(new JLabel("width:")); center.add(width); + center.add(new JLabel("height:")); center.add(height); + center.add(new JLabel("spriteNames:")); center.add(spriteNames); + center.add(new JLabel("enemies:")); center.add(enemies); + center.add(new JLabel("pointsOfInterest:")); center.add(pointsOfInterest); + center.add(new JLabel("color:")); center.add(color); + center.add(new JLabel("terrain:")); center.add(terrain); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(center,BorderLayout.PAGE_START); + add(terrain,BorderLayout.CENTER); + + name.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + tilesetName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + color.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + spriteNames.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + enemies.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + terrain.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + + + startPointX.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + startPointY.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + noiseWeight.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + distWeight.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + tilesetAtlas.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); + width.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + height.addChangeListener(e -> BiomeEdit.this.updateTerrain()); + refresh(); + } + + private void updateTerrain() { + if(currentData==null||updating) + return; + currentData.startPointX = (Float) startPointX.getValue(); + currentData.startPointY = (Float) startPointY.getValue(); + currentData.noiseWeight = (Float) noiseWeight.getValue(); + currentData.distWeight = (Float)distWeight.getValue(); + currentData.name = name.getText(); + currentData.tilesetAtlas = tilesetAtlas.edit.getText(); + currentData.tilesetName = tilesetName.getName(); + currentData.terrain = terrain.getBiomeTerrainData(); + currentData.width = (Float) width.getValue(); + currentData.height = (Float) height.getValue(); + currentData.color = color.getText(); + currentData.spriteNames = spriteNames.getList(); + currentData.enemies = Arrays.asList(enemies.getList()); + currentData.pointsOfInterest = Arrays.asList(pointsOfInterest.getList()); + } + + public void setCurrentBiome(BiomeData data) + { + currentData=data; + refresh(); + } + + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + startPointX.setValue(currentData.startPointX); + startPointY.setValue(currentData.startPointY); + noiseWeight.setValue(currentData.noiseWeight); + distWeight.setValue(currentData.distWeight); + name.setText(currentData.name); + tilesetAtlas.edit.setText( currentData.tilesetAtlas); + tilesetName.setText(currentData.tilesetName); + terrain.setTerrains(currentData.terrain); + width.setValue(currentData.width); + height.setValue(currentData.height); + color.setText(currentData.color); + spriteNames.setText(currentData.spriteNames); + enemies.setText(currentData.enemies); + color.setText(currentData.color); + pointsOfInterest.setText(currentData.pointsOfInterest); + updating=false; + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java new file mode 100644 index 00000000000..24791aa585d --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java @@ -0,0 +1,14 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeTerrainData; + +import javax.swing.*; +import javax.swing.event.ChangeListener; + +public class BiomeTerrainEdit extends JComponent { + public void setCurrentTerrain(BiomeTerrainData biomeTerrainData) { + } + public void addChangeListener(ChangeListener listener) { + + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java index 248bd275914..26f9f30923d 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/ItemEdit.java @@ -10,8 +10,6 @@ import java.awt.*; */ public class ItemEdit extends JComponent { ItemData currentData; - - JTextField nameField=new JTextField(); JTextField equipmentSlot=new JTextField(); JTextField iconName=new JTextField(); @@ -39,6 +37,7 @@ public class ItemEdit extends JComponent { add(parameters); add(effect); + add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); nameField.getDocument().addDocumentListener(new DocumentChangeListener(() -> ItemEdit.this.updateItem())); equipmentSlot.getDocument().addDocumentListener(new DocumentChangeListener(() -> ItemEdit.this.updateItem())); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java new file mode 100644 index 00000000000..045777feb94 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java @@ -0,0 +1,88 @@ +package forge.adventure.editor; + +import forge.adventure.data.PointOfInterestData; + +import javax.swing.*; +import java.awt.*; + +public class PointOfInterestEdit extends JComponent { + + PointOfInterestData currentData; + + + JTextField name = new JTextField(); + JTextField type = new JTextField(); + JSpinner count = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); + FilePicker spriteAtlas = new FilePicker(new String[]{"atlas"}); + JTextField sprite = new JTextField(); + FilePicker map = new FilePicker(new String[]{"tmx"}); + JSpinner radiusFactor= new JSpinner(new SpinnerNumberModel(0.0f, 0.0f, 2.0f, 0.1f)); + + + private boolean updating=false; + + public PointOfInterestEdit() + { + + setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); + JPanel parameters=new JPanel(); + parameters.setBorder(BorderFactory.createTitledBorder("Parameter")); + parameters.setLayout(new GridLayout(7,2)) ; + + parameters.add(new JLabel("Name:")); parameters.add(name); + parameters.add(new JLabel("Type:")); parameters.add(type); + parameters.add(new JLabel("Count:")); parameters.add(count); + parameters.add(new JLabel("Sprite atlas:")); parameters.add(spriteAtlas); + parameters.add(new JLabel("Sprite:")); parameters.add(sprite); + parameters.add(new JLabel("Map:")); parameters.add(map); + parameters.add(new JLabel("Radius factor:")); parameters.add(radiusFactor); + + add(parameters); + add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); + + name.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + type.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + count.addChangeListener(e -> PointOfInterestEdit.this.updateItem()); + spriteAtlas.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + sprite.getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + map.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> PointOfInterestEdit.this.updateItem())); + radiusFactor.addChangeListener(e -> PointOfInterestEdit.this.updateItem()); + refresh(); + } + + private void updateItem() { + if(currentData==null||updating) + return; + currentData.name=name.getText(); + currentData.type= type.getText(); + currentData.count= ((Integer) count.getValue()).intValue(); + currentData.spriteAtlas=spriteAtlas.getEdit().getText(); + currentData.sprite=sprite.getText(); + currentData.map=map.getEdit().getText(); + currentData.radiusFactor=((Float) radiusFactor.getValue()).floatValue(); + } + + public void setCurrent(PointOfInterestData data) + { + currentData=data; + refresh(); + } + + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + name.setText(currentData.name); + type.setText(currentData.type); + count.setValue(currentData.count); + spriteAtlas.getEdit().setText(currentData.spriteAtlas); + sprite.setText(currentData.sprite); + map.getEdit().setText(currentData.map); + radiusFactor.setValue(currentData.radiusFactor); + + updating=false; + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java index 83ff548e68e..4fa4b0e9209 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEditor.java @@ -1,6 +1,131 @@ package forge.adventure.editor; -import java.awt.*; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter; +import forge.adventure.data.PointOfInterestData; +import forge.adventure.util.Config; +import forge.adventure.util.Paths; -public class PointOfInterestEditor extends Component { +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionListener; +import java.util.HashMap; + +public class PointOfInterestEditor extends JComponent { + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + PointOfInterestEdit edit=new PointOfInterestEdit(); + static HashMap atlas=new HashMap<>(); + + + + public class PointOfInterestRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof PointOfInterestData)) + return label; + PointOfInterestData poi=(PointOfInterestData) value; + // Get the renderer component from parent class + + label.setText(poi.name); + if(!atlas.containsKey(poi.spriteAtlas)) + atlas.put(poi.spriteAtlas,new SwingAtlas(Config.instance().getFile(poi.spriteAtlas))); + + SwingAtlas poiAtlas = atlas.get(poi.spriteAtlas); + + if(poiAtlas.has(poi.sprite)) + label.setIcon(poiAtlas.get(poi.sprite)); + else + { + ImageIcon img=poiAtlas.getAny(); + if(img!=null) + label.setIcon(img); + } + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + public PointOfInterestEditor() + { + + list.setCellRenderer(new PointOfInterestEditor.PointOfInterestRenderer()); + list.addListSelectionListener(e -> PointOfInterestEditor.this.updateEdit()); + addButton("add", e -> PointOfInterestEditor.this.addItem()); + addButton("remove", e -> PointOfInterestEditor.this.remove()); + addButton("copy", e -> PointOfInterestEditor.this.copy()); + addButton("load", e -> PointOfInterestEditor.this.load()); + addButton("save", e -> PointOfInterestEditor.this.save()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(new JScrollPane(list), BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + load(); + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + PointOfInterestData data=new PointOfInterestData(model.get(selected)); + model.add(model.size(),data); + } + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrent(model.get(selected)); + } + + void save() + { + Array allEnemies=new Array<>(); + for(int i=0;i allEnemies=new Array<>(); + Json json = new Json(); + FileHandle handle = Config.instance().getFile(Paths.POINTS_OF_INTEREST); + if (handle.exists()) + { + Array readEnemies=json.fromJson(Array.class, PointOfInterestData.class, handle); + allEnemies = readEnemies; + } + for (int i=0;i RewardEdit.this.updateReward())); + probability.addChangeListener(e -> RewardEdit.this.updateReward()); + count.addChangeListener(e -> RewardEdit.this.updateReward()); + addMaxCount.addChangeListener(e -> RewardEdit.this.updateReward()); + cardName.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + itemName.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + editions.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + colors.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + rarity.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + subTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + cardTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + superTypes.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + manaCosts.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + keyWords.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); + colorType.addActionListener((e -> RewardEdit.this.updateReward())); + cardText.getDocument().addDocumentListener(new DocumentChangeListener(() -> RewardEdit.this.updateReward())); } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java index a2d6cc0f617..786128f6bad 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/RewardsEditor.java @@ -5,10 +5,7 @@ import forge.adventure.data.RewardData; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import java.awt.*; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** @@ -59,30 +56,10 @@ public class RewardsEditor extends JComponent{ { list.setCellRenderer(new RewardDataRenderer()); - list.addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - RewardsEditor.this.updateEdit(); - } - }); - addButton("add", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.addReward(); - } - }); - addButton("remove", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.remove(); - } - }); - addButton("copy", new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - RewardsEditor.this.copy(); - } - }); + list.addListSelectionListener(e -> RewardsEditor.this.updateEdit()); + addButton("add", e -> RewardsEditor.this.addReward()); + addButton("remove", e -> RewardsEditor.this.remove()); + addButton("copy", e -> RewardsEditor.this.copy()); BorderLayout layout=new BorderLayout(); setLayout(layout); add(list, BorderLayout.LINE_START); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java new file mode 100644 index 00000000000..69a7578a13d --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/TerrainsEditor.java @@ -0,0 +1,138 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeTerrainData; +import forge.adventure.data.RewardData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.ActionListener; + +/** + * Editor class to edit configuration, maybe moved or removed + */ +public class TerrainsEditor extends JComponent{ + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + BiomeTerrainEdit edit=new BiomeTerrainEdit(); + + + + public class TerrainDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof RewardData)) + return label; + RewardData reward=(RewardData) value; + StringBuilder builder=new StringBuilder(); + if(reward.type==null||reward.type.isEmpty()) + builder.append("Terrain"); + else + builder.append(reward.type); + builder.append(" "); + builder.append(reward.count); + if(reward.addMaxCount>0) + { + builder.append("-"); + builder.append(reward.count+reward.addMaxCount); + } + label.setText(builder.toString()); + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + + public TerrainsEditor() + { + + list.setCellRenderer(new TerrainDataRenderer()); + list.addListSelectionListener(e -> TerrainsEditor.this.updateEdit()); + addButton("add", e -> TerrainsEditor.this.addReward()); + addButton("remove", e -> TerrainsEditor.this.remove()); + addButton("copy", e -> TerrainsEditor.this.copy()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(list, BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + + + edit.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + emitChanged(); + } + }); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + BiomeTerrainData data=new BiomeTerrainData(model.get(selected)); + model.add(model.size(),data); + } + + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrentTerrain(model.get(selected)); + } + + void addReward() + { + BiomeTerrainData data=new BiomeTerrainData(); + model.add(model.size(),data); + } + void remove() + { + int selected=list.getSelectedIndex(); + if(selected<0) + return; + model.remove(selected); + } + public void setTerrains(BiomeTerrainData[] terrain) { + + model.clear(); + if(terrain==null) + return; + for (int i=0;i itemNames) { + if(itemNames==null) + edit.setText(""); + else + edit.setText(String.join(";",itemNames)); + } public void setText(String[] itemName) { if(itemName==null) edit.setText(""); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java index 221ac5d64ae..e1fde6621e9 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java @@ -1,6 +1,153 @@ package forge.adventure.editor; -import java.awt.*; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter; +import forge.adventure.data.BiomeData; +import forge.adventure.data.WorldData; +import forge.adventure.util.Config; +import forge.adventure.util.Paths; -public class WorldEditor extends Component { +import javax.swing.*; +import java.awt.*; +import java.util.HashMap; + +public class WorldEditor extends JComponent { + + WorldData currentData; + + + JSpinner width= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + JSpinner height= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + JSpinner playerStartPosX= new JSpinner(new SpinnerNumberModel(0, 0, 1, .1)); + JSpinner playerStartPosY= new JSpinner(new SpinnerNumberModel(0, 0, 1, .1)); + JSpinner noiseZoomBiome= new JSpinner(new SpinnerNumberModel(0, 0, 1000f, 1f)); + JSpinner tileSize= new JSpinner(new SpinnerNumberModel(0, 0, 100000, 1)); + + JTextField biomesSprites = new JTextField(); + JSpinner maxRoadDistance = new JSpinner(new SpinnerNumberModel(0, 0, 100000f, 1f)); + TextListEdit biomesNames = new TextListEdit(); + + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + BiomeEdit edit=new BiomeEdit(); + JTabbedPane tabs =new JTabbedPane(); + static HashMap atlas=new HashMap<>(); + + public class BiomeDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof BiomeData)) + return label; + BiomeData biome=(BiomeData) value; + // Get the renderer component from parent class + + label.setText(biome.name); + if(!atlas.containsKey(biome.tilesetAtlas)) + atlas.put(biome.tilesetAtlas,new SwingAtlas(Config.instance().getFile(biome.tilesetAtlas))); + + SwingAtlas poiAtlas = atlas.get(biome.tilesetAtlas); + + if(poiAtlas.has(biome.tilesetName)) + label.setIcon(poiAtlas.get(biome.tilesetName)); + else + { + ImageIcon img=poiAtlas.getAny(); + if(img!=null) + label.setIcon(img); + } + return label; + } + } + public WorldEditor() { + list.setCellRenderer(new BiomeDataRenderer()); + BorderLayout layout = new BorderLayout(); + setLayout(layout); + add(tabs); + JPanel worldPanel=new JPanel(); + JPanel biomeData=new JPanel(); + tabs.addTab("BiomeData", biomeData); + tabs.addTab("WorldData", worldPanel); + + + JPanel worldData=new JPanel(); + worldData.setLayout(new GridLayout(9,2)) ; + + worldData.add(new JLabel("width:")); worldData.add(width); + worldData.add(new JLabel("height:")); worldData.add(height); + worldData.add(new JLabel("playerStartPosX:")); worldData.add(playerStartPosX); + worldData.add(new JLabel("playerStartPosY:")); worldData.add(playerStartPosY); + worldData.add(new JLabel("noiseZoomBiome:")); worldData.add(noiseZoomBiome); + worldData.add(new JLabel("tileSize:")); worldData.add(tileSize); + worldData.add(new JLabel("biomesSprites:")); worldData.add(biomesSprites); + worldData.add(new JLabel("maxRoadDistance:")); worldData.add(maxRoadDistance); + worldData.add(new JLabel("biomesNames:")); worldData.add(biomesNames); + + + worldPanel.setLayout(new BoxLayout(worldPanel,BoxLayout.Y_AXIS)); + worldPanel.add(worldData); + worldPanel.add(new Box.Filler(new Dimension(0,0),new Dimension(0,Integer.MAX_VALUE),new Dimension(0,Integer.MAX_VALUE))); + + + biomeData.setLayout(new GridLayout(1,2)) ; + biomeData.add(list); biomeData.add(edit); + + load(); + + JToolBar toolBar = new JToolBar("toolbar"); + add(toolBar, BorderLayout.PAGE_START); + JButton newButton=new JButton("save"); + newButton.addActionListener(e -> WorldEditor.this.save()); + toolBar.add(newButton); + newButton=new JButton("load"); + newButton.addActionListener(e -> WorldEditor.this.load()); + toolBar.add(newButton); + } + + void save() + { + Json json = new Json(JsonWriter.OutputType.json); + FileHandle handle = Config.instance().getFile(Paths.WORLD); + handle.writeString(json.prettyPrint(json.toJson(currentData,Array.class, WorldData.class)),false); + + } + void load() + { + model.clear(); + Json json = new Json(); + FileHandle handle = Config.instance().getFile(Paths.WORLD); + if (handle.exists()) + { + currentData=json.fromJson(WorldData.class, WorldData.class, handle); + } + update(); + } + + private void update() { + width.setValue(currentData.width); + height.setValue(currentData.height); + playerStartPosX.setValue(currentData.playerStartPosX); + playerStartPosY.setValue(currentData.playerStartPosY); + noiseZoomBiome.setValue(currentData.noiseZoomBiome); + tileSize.setValue(currentData.tileSize); + biomesSprites.setText(currentData.biomesSprites); + maxRoadDistance.setValue(currentData.maxRoadDistance); + biomesNames.setText(currentData.biomesNames); + + for(String path:currentData.biomesNames) + { + Json json = new Json(); + FileHandle handle = Config.instance().getFile(path); + if (handle.exists()) + { + BiomeData data=json.fromJson(BiomeData.class, BiomeData.class, handle); + model.addElement(data); + } + } + + } } diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java index 51176c3a8b4..3aa7fb92d8f 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java @@ -15,7 +15,6 @@ import java.util.Random; * contains the information for the biomes */ public class BiomeData implements Serializable { - private final Random rand = MyRandom.getRandom(); public float startPointX; public float startPointY; public float noiseWeight; @@ -35,6 +34,7 @@ public class BiomeData implements Serializable { private ArrayList enemyList; private ArrayList pointOfInterestList; + private final Random rand = MyRandom.getRandom(); public Color GetColor() { return Color.valueOf(color); } diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java index 1ccaee59ce8..19c6b39f72b 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeTerrainData.java @@ -16,4 +16,16 @@ public class BiomeTerrainData { // factor for the noise resolution public float resolution; + public BiomeTerrainData() + { + + } + public BiomeTerrainData(BiomeTerrainData other) + { + spriteName=other.spriteName; + min=other.min; + max=other.max; + resolution=other.resolution; + } + } diff --git a/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java b/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java index 06e285a9d86..f2921e8d32a 100644 --- a/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java +++ b/forge-gui-mobile/src/forge/adventure/data/PointOfInterestData.java @@ -42,4 +42,18 @@ public class PointOfInterestData { } return null; } + public PointOfInterestData() + { + + } + public PointOfInterestData(PointOfInterestData other) + { + name=other.name; + type=other.type; + count=other.count; + spriteAtlas=other.spriteAtlas; + sprite=other.sprite; + map=other.map; + radiusFactor=other.radiusFactor; + } } diff --git a/forge-gui-mobile/src/forge/adventure/data/WorldData.java b/forge-gui-mobile/src/forge/adventure/data/WorldData.java index 908c857fdba..d5be45f2bc8 100644 --- a/forge-gui-mobile/src/forge/adventure/data/WorldData.java +++ b/forge-gui-mobile/src/forge/adventure/data/WorldData.java @@ -17,19 +17,22 @@ import java.util.List; */ public class WorldData implements Serializable { - static Array allEnemies; public int width; public int height; public float playerStartPosX; public float playerStartPosY; public float noiseZoomBiome; public int tileSize; - public List biomesNames; public BiomeData roadTileset; public String biomesSprites; public float maxRoadDistance; + public List biomesNames; + + private BiomeSprites sprites; private List biomes; + + private static Array allEnemies; private static Array shopList; From 605c232dea397ab99481b48fd9a46c20dafe0947 Mon Sep 17 00:00:00 2001 From: Grimm Date: Thu, 28 Jul 2022 04:12:17 +0200 Subject: [PATCH 26/66] wavefunction collapse first integration --- .../src/main/java/forge/adventure/Main.java | 8 +- .../forge/adventure/editor/BiomeEdit.java | 11 +- .../adventure/editor/BiomeStructureEdit.java | 98 +++++++++++++ .../adventure/editor/BiomeTerrainEdit.java | 80 ++++++++++- .../adventure/editor/EditorMainWindow.java | 2 +- .../forge/adventure/editor/EnemyEdit.java | 2 - .../forge/adventure/editor/FloatSpinner.java | 19 +++ .../forge/adventure/editor/IntSpinner.java | 20 +++ .../adventure/editor/StructureEditor.java | 133 ++++++++++++++++++ .../forge/adventure/editor/SwingAtlas.java | 21 ++- .../adventure/editor/SwingAtlasPreview.java | 43 ++++-- .../adventure/editor/TerrainsEditor.java | 36 ++--- .../forge/adventure/editor/WorldEditor.java | 56 ++++++++ forge-gui-mobile/pom.xml | 5 + forge-gui-mobile/src/forge/Forge.java | 1 + .../src/forge/adventure/data/BiomeData.java | 1 + .../adventure/data/BiomeStructureData.java | 38 +++++ .../forge/adventure/scene/NewGameScene.java | 5 + .../src/forge/adventure/scene/StartScene.java | 9 ++ .../src/forge/adventure/stage/GameStage.java | 10 +- .../src/forge/adventure/stage/WorldStage.java | 14 +- .../forge/adventure/world/BiomeStructure.java | 114 +++++++++++++++ .../forge/adventure/world/BiomeTexture.java | 31 +++- .../src/forge/adventure/world/World.java | 74 +++++++--- .../src/forge/adventure/world/WorldSave.java | 2 + .../src/forge/screens/SplashScreen.java | 8 ++ .../res/adventure/Shandalar/world/green.json | 8 ++ .../Shandalar/world/tilesets/autotiles.png | Bin 30516 -> 43326 bytes .../Shandalar/world/tilesets/forest.atlas | 20 +++ .../Shandalar/world/tilesets/forest.png | Bin 0 -> 16786 bytes 30 files changed, 786 insertions(+), 83 deletions(-) create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java create mode 100644 forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java create mode 100644 forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java create mode 100644 forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/forest.png diff --git a/forge-adventure/src/main/java/forge/adventure/Main.java b/forge-adventure/src/main/java/forge/adventure/Main.java index e6f6d316166..b32aa6653f2 100644 --- a/forge-adventure/src/main/java/forge/adventure/Main.java +++ b/forge-adventure/src/main/java/forge/adventure/Main.java @@ -107,7 +107,13 @@ public class Main { } }); - + for(int i=0;i BiomeEdit.this.updateTerrain())); tilesetName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeEdit.this.updateTerrain())); @@ -81,6 +82,7 @@ public class BiomeEdit extends JComponent { currentData.tilesetAtlas = tilesetAtlas.edit.getText(); currentData.tilesetName = tilesetName.getName(); currentData.terrain = terrain.getBiomeTerrainData(); + currentData.structures = structures.getBiomeStructureData(); currentData.width = (Float) width.getValue(); currentData.height = (Float) height.getValue(); currentData.color = color.getText(); @@ -109,7 +111,8 @@ public class BiomeEdit extends JComponent { name.setText(currentData.name); tilesetAtlas.edit.setText( currentData.tilesetAtlas); tilesetName.setText(currentData.tilesetName); - terrain.setTerrains(currentData.terrain); + terrain.setTerrains(currentData); + structures.setStructures(currentData); width.setValue(currentData.width); height.setValue(currentData.height); color.setText(currentData.color); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java new file mode 100644 index 00000000000..2fd8bcfb592 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java @@ -0,0 +1,98 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; +import forge.adventure.data.BiomeStructureData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +public class BiomeStructureEdit extends JComponent { + SwingAtlasPreview preview=new SwingAtlasPreview(128); + private boolean updating=false; + BiomeStructureData currentData; + BiomeData currentBiomeData; + public JTextField structureAtlasPath=new JTextField(); + public FloatSpinner x= new FloatSpinner(); + public FloatSpinner y= new FloatSpinner(); + public FloatSpinner size= new FloatSpinner(); + public JCheckBox randomPosition=new JCheckBox(); + public JCheckBox collision=new JCheckBox(); + + public BiomeStructureEdit() + { + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(6,2)); + + center.add(new JLabel("structureAtlasPath:")); center.add(structureAtlasPath); + center.add(new JLabel("x:")); center.add(x); + center.add(new JLabel("y:")); center.add(y); + center.add(new JLabel("size:")); center.add(size); + center.add(new JLabel("randomPosition:")); center.add(randomPosition); + center.add(new JLabel("collision:")); center.add(collision); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(preview,BorderLayout.LINE_START); + add(center,BorderLayout.CENTER); + + structureAtlasPath.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureEdit.this.updateStructure())); + + + x.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + y.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + size.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + randomPosition.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + collision.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); + refresh(); + } + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + structureAtlasPath.setText(currentData.structureAtlasPath); + x.setValue(currentData.x); + y.setValue(currentData.y); + size.setValue(currentData.size); + randomPosition.setSelected(currentData.randomPosition); + collision.setSelected(currentData.collision); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.structureAtlasPath); + updating=false; + } + public void updateStructure() + { + + if(currentData==null||updating) + return; + currentData.structureAtlasPath=structureAtlasPath.getText(); + + currentData.x= x.floatValue(); + currentData.y= y.floatValue(); + currentData.size= size.floatValue(); + currentData.randomPosition=randomPosition.isSelected(); + currentData.collision=collision.isSelected(); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.structureAtlasPath); + emitChanged(); + } + public void setCurrentStructure(BiomeStructureData biomeTerrainData, BiomeData data) { + currentData =biomeTerrainData; + currentBiomeData=data; + refresh(); + } + + public void addChangeListener(ChangeListener listener) { + listenerList.add(ChangeListener.class, listener); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java index 24791aa585d..8986a2e6701 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java @@ -1,14 +1,88 @@ package forge.adventure.editor; +import forge.adventure.data.BiomeData; import forge.adventure.data.BiomeTerrainData; import javax.swing.*; +import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import java.awt.*; public class BiomeTerrainEdit extends JComponent { - public void setCurrentTerrain(BiomeTerrainData biomeTerrainData) { - } - public void addChangeListener(ChangeListener listener) { + SwingAtlasPreview preview=new SwingAtlasPreview(128); + private boolean updating=false; + BiomeTerrainData currentData; + BiomeData currentBiomeData; + public JTextField spriteName=new JTextField(); + public JSpinner min= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner max= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public JSpinner resolution= new JSpinner(new SpinnerNumberModel(0.0f, 0.f, 1f, 0.1f)); + public BiomeTerrainEdit() + { + JComponent center=new JComponent() { }; + center.setLayout(new GridLayout(4,2)); + + center.add(new JLabel("spriteName:")); center.add(spriteName); + center.add(new JLabel("min:")); center.add(min); + center.add(new JLabel("max:")); center.add(max); + center.add(new JLabel("resolution:")); center.add(resolution); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(preview,BorderLayout.LINE_START); + add(center,BorderLayout.CENTER); + + spriteName.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeTerrainEdit.this.updateTerrain())); + + min.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + max.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + resolution.addChangeListener(e -> BiomeTerrainEdit.this.updateTerrain()); + + + refresh(); + } + private void refresh() { + setEnabled(currentData!=null); + if(currentData==null) + { + return; + } + updating=true; + spriteName.setText(currentData.spriteName); + min.setValue(currentData.min); + max.setValue(currentData.max); + resolution.setValue(currentData.resolution); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.spriteName); + updating=false; + } + public void updateTerrain() + { + + if(currentData==null||updating) + return; + currentData.spriteName=spriteName.getText(); + currentData.min= (float) min.getValue(); + currentData.max= (float) max.getValue(); + currentData.resolution= (float) resolution.getValue(); + preview.setSpritePath(currentBiomeData.tilesetAtlas,currentData.spriteName); + emitChanged(); + } + public void setCurrentTerrain(BiomeTerrainData biomeTerrainData, BiomeData data) { + currentData =biomeTerrainData; + currentBiomeData=data; + refresh(); + } + + public void addChangeListener(ChangeListener listener) { + listenerList.add(ChangeListener.class, listener); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } } } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java index 50f0d877cc9..fdfe775d914 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EditorMainWindow.java @@ -14,8 +14,8 @@ public class EditorMainWindow extends JFrame { BorderLayout layout=new BorderLayout(); setLayout(layout); add(tabs); - tabs.addTab("POI",new PointOfInterestEditor()); tabs.addTab("World",new WorldEditor()); + tabs.addTab("POI",new PointOfInterestEditor()); tabs.addTab("Items",new ItemsEditor()); tabs.addTab("Enemies",new EnemyEditor()); setVisible(true); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java index 399d7c88334..3ef2d72a92c 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java @@ -10,8 +10,6 @@ import java.awt.*; */ public class EnemyEdit extends JComponent { EnemyData currentData; - - JTextField nameField=new JTextField(); JTextField colorField=new JTextField(); JSpinner lifeFiled= new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java b/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java new file mode 100644 index 00000000000..7fad0e3bad3 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/FloatSpinner.java @@ -0,0 +1,19 @@ +package forge.adventure.editor; + +import javax.swing.*; + +public class FloatSpinner extends JSpinner{ + + public FloatSpinner() + { + this( 0.f, 1f, 0.1f); + } + public FloatSpinner(float min,float max,float stepSize) + { + super(new SpinnerNumberModel(new Float(0.0f), new Float(min), new Float (max), new Float(stepSize))); + } + public float floatValue() + { + return ((Float)getValue()).floatValue(); + } +} diff --git a/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java b/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java new file mode 100644 index 00000000000..132817d3891 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/IntSpinner.java @@ -0,0 +1,20 @@ +package forge.adventure.editor; + +import javax.swing.*; + + +public class IntSpinner extends JSpinner { + + public IntSpinner() + { + this( 0, 100, 1); + } + public IntSpinner(int min,int max,int stepSize) + { + super(new SpinnerNumberModel(new Integer(0), new Integer(min), new Integer (max), new Integer(stepSize))); + } + public int intValue() + { + return ((Integer)getValue()).intValue(); + } +} \ No newline at end of file diff --git a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java new file mode 100644 index 00000000000..1b301ebebd7 --- /dev/null +++ b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java @@ -0,0 +1,133 @@ +package forge.adventure.editor; + +import forge.adventure.data.BiomeData; +import forge.adventure.data.BiomeStructureData; +import forge.adventure.data.BiomeTerrainData; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.ActionListener; + +/** + * Editor class to edit configuration, maybe moved or removed + */ +public class StructureEditor extends JComponent{ + DefaultListModel model = new DefaultListModel<>(); + JList list = new JList<>(model); + JToolBar toolBar = new JToolBar("toolbar"); + BiomeStructureEdit edit=new BiomeStructureEdit(); + + BiomeData currentData; + + public class StructureDataRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent( + JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(!(value instanceof BiomeTerrainData)) + return label; + BiomeTerrainData structureData=(BiomeTerrainData) value; + StringBuilder builder=new StringBuilder(); + builder.append("Structure"); + builder.append(" "); + builder.append(structureData.spriteName); + label.setText(builder.toString()); + return label; + } + } + public void addButton(String name, ActionListener action) + { + JButton newButton=new JButton(name); + newButton.addActionListener(action); + toolBar.add(newButton); + + } + + public StructureEditor() + { + + list.setCellRenderer(new StructureDataRenderer()); + list.addListSelectionListener(e -> StructureEditor.this.updateEdit()); + addButton("add", e -> StructureEditor.this.addStructure()); + addButton("remove", e -> StructureEditor.this.remove()); + addButton("copy", e -> StructureEditor.this.copy()); + BorderLayout layout=new BorderLayout(); + setLayout(layout); + add(list, BorderLayout.LINE_START); + add(toolBar, BorderLayout.PAGE_START); + add(edit,BorderLayout.CENTER); + + + edit.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + emitChanged(); + } + }); + } + protected void emitChanged() { + ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); + if (listeners != null && listeners.length > 0) { + ChangeEvent evt = new ChangeEvent(this); + for (ChangeListener listener : listeners) { + listener.stateChanged(evt); + } + } + } + private void copy() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + BiomeStructureData data=new BiomeStructureData(model.get(selected)); + model.add(model.size(),data); + } + + private void updateEdit() { + + int selected=list.getSelectedIndex(); + if(selected<0) + return; + edit.setCurrentStructure(model.get(selected),currentData); + } + + void addStructure() + { + BiomeStructureData data=new BiomeStructureData(); + model.add(model.size(),data); + } + void remove() + { + int selected=list.getSelectedIndex(); + if(selected<0) + return; + model.remove(selected); + } + public void setStructures(BiomeData data) { + + currentData=data; + model.clear(); + if(data==null||data.structures==null) + return; + for (int i=0;i> images=new HashMap<>(); public HashMap> getImages() { return images; } - public SwingAtlas(FileHandle path) + public SwingAtlas(FileHandle path,int imageSize) { + this.imageSize=imageSize; if(!path.exists()||!path.toString().endsWith(".atlas")) return; TextureAtlas.TextureAtlasData data=new TextureAtlas.TextureAtlasData(path,path.parent(),false); @@ -37,17 +39,28 @@ public class SwingAtlas { images.put(name,new ArrayList<>()); } ArrayList imageList=images.get(name); - try { + try + { imageList.add(spriteToImage(region)); - } catch (IOException e) { + } + catch (IOException e) + { e.printStackTrace(); } } } + public SwingAtlas(FileHandle path) + { + this(path,32); + } private ImageIcon spriteToImage(TextureAtlas.TextureAtlasData.Region sprite) throws IOException { BufferedImage img = ImageIO.read(sprite.page.textureFile.file()); - return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(32,32,SCALE_FAST)); + if(sprite.width== sprite.height) + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize,imageSize,SCALE_FAST)); + if(sprite.width>sprite.height) + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize, (int) (imageSize*(sprite.height/(float)sprite.width)),SCALE_FAST)); + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance((int) (imageSize*(sprite.width/(float)sprite.height)),imageSize,SCALE_FAST)); } public ImageIcon get(String name) { diff --git a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java index 3631e133a8c..63d08c62f24 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java @@ -13,11 +13,12 @@ import java.util.Map; * Editor class to edit configuration, maybe moved or removed */ public class SwingAtlasPreview extends Box { + int imageSize=32; private String sprite=""; + private String spriteName=""; Timer timer; public SwingAtlasPreview() { super(BoxLayout.Y_AXIS); - timer = new Timer(200, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { @@ -28,25 +29,51 @@ public class SwingAtlasPreview extends Box { } }); } + public SwingAtlasPreview(int size) { + this(); + imageSize=size; + } int counter=0; List>> labels=new ArrayList<>(); public void setSpritePath(String sprite) { - if(this.sprite==null||this.sprite.equals(sprite)) + setSpritePath(sprite,null); + } + public void setSpritePath(String sprite,String name) { + + if(this.sprite==null||name==null||sprite==null||(this.sprite.equals(sprite)&&(spriteName==null&&spriteName.equals(name)))) return; removeAll(); counter=0; labels.clear(); this.sprite=sprite; - SwingAtlas atlas=new SwingAtlas(Config.instance().getFile(sprite)); + this.spriteName=name; + SwingAtlas atlas=new SwingAtlas(Config.instance().getFile(sprite),imageSize); + int maxCount=0; for(Map.Entry> element:atlas.getImages().entrySet()) { - JLabel image=new JLabel(element.getValue().get(0)); - add(new JLabel(element.getKey())); - add(image); - labels.add(Pair.of(image, element.getValue())); + if(name==null||element.getKey().equals(name)) + { + JLabel image=new JLabel(element.getValue().get(0)); + if(maxCount0) - { - builder.append("-"); - builder.append(reward.count+reward.addMaxCount); - } + builder.append(terrainData.spriteName); label.setText(builder.toString()); return label; } @@ -58,7 +50,7 @@ public class TerrainsEditor extends JComponent{ list.setCellRenderer(new TerrainDataRenderer()); list.addListSelectionListener(e -> TerrainsEditor.this.updateEdit()); - addButton("add", e -> TerrainsEditor.this.addReward()); + addButton("add", e -> TerrainsEditor.this.addTerrain()); addButton("remove", e -> TerrainsEditor.this.remove()); addButton("copy", e -> TerrainsEditor.this.copy()); BorderLayout layout=new BorderLayout(); @@ -98,10 +90,10 @@ public class TerrainsEditor extends JComponent{ int selected=list.getSelectedIndex(); if(selected<0) return; - edit.setCurrentTerrain(model.get(selected)); + edit.setCurrentTerrain(model.get(selected),currentData); } - void addReward() + void addTerrain() { BiomeTerrainData data=new BiomeTerrainData(); model.add(model.size(),data); @@ -113,14 +105,16 @@ public class TerrainsEditor extends JComponent{ return; model.remove(selected); } - public void setTerrains(BiomeTerrainData[] terrain) { + public void setTerrains(BiomeData data) { + currentData=data; model.clear(); - if(terrain==null) + if(data==null||data.terrain==null) return; - for (int i=0;i WorldEditor.this.save()); toolBar.add(newButton); + newButton=new JButton("load"); newButton.addActionListener(e -> WorldEditor.this.load()); toolBar.add(newButton); + + toolBar.addSeparator(); + + newButton=new JButton("test map"); + newButton.addActionListener(e -> WorldEditor.this.test()); + toolBar.add(newButton); + } + + private void test() { + + String javaHome = System.getProperty("java.home"); + String javaBin = javaHome + File.separator + "bin" + File.separator + "java"; + String classpath = System.getProperty("java.class.path"); + String className = forge.adventure.Main.class.getName(); + + ArrayList command = new ArrayList<>(); + command.add(javaBin); + command.add("-cp"); + command.add(classpath); + command.add(className); + + command.add("testMap"); + + ProcessBuilder build= new ProcessBuilder(command); + build .redirectInput(ProcessBuilder.Redirect.INHERIT) + .redirectOutput(ProcessBuilder.Redirect.INHERIT) + .redirectError(ProcessBuilder.Redirect.INHERIT); + try { + Process process= build.start(); + } catch (IOException e) { + throw new RuntimeException(e); + } } void save() diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml index 0c4ef128e59..e34f7d42fa7 100644 --- a/forge-gui-mobile/pom.xml +++ b/forge-gui-mobile/pom.xml @@ -55,6 +55,11 @@ gdx-freetype 1.11.0 + + com.github.sjcasey21 + wavefunctioncollapse + 0.2.2 + diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 7da28d0c317..0cc6f9dabbc 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -123,6 +123,7 @@ public class Forge implements ApplicationListener { private static Cursor cursor0, cursor1, cursor2, cursorA0, cursorA1, cursorA2; public static boolean forcedEnglishonCJKMissing = false; public static boolean adventureLoaded = false; + public static boolean createNewAdventureMap = false; private static Localizer localizer; public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value, boolean androidOrientation, int totalRAM, boolean isTablet, int AndroidAPI, String AndroidRelease, String deviceName) { diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java index 3aa7fb92d8f..61a2b1a5193 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java @@ -30,6 +30,7 @@ public class BiomeData implements Serializable { public String[] spriteNames; public List enemies; public List pointsOfInterest; + public BiomeStructureData[] structures; private ArrayList enemyList; private ArrayList pointOfInterestList; diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java new file mode 100644 index 00000000000..50df63f6157 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java @@ -0,0 +1,38 @@ +package forge.adventure.data; + +import java.awt.image.BufferedImage; + +public class BiomeStructureData { + public int N = 3; + public float x; + public float y; + public float size; + public boolean randomPosition; + public boolean collision; + + public String structureAtlasPath; + public boolean periodicInput; + public float height; + public float width; + public int ground; + public int symmetry; + public boolean periodicOutput; + + public BiomeStructureData( ) + { + + } + public BiomeStructureData(BiomeStructureData biomeStructureData) { + this.structureAtlasPath=biomeStructureData.structureAtlasPath; + this.x=biomeStructureData.x; + this.y=biomeStructureData.y; + this.size=biomeStructureData.size; + this.randomPosition=biomeStructureData.randomPosition; + this.collision=biomeStructureData.collision; + } + + public BufferedImage sourceImage() { + + return null; + } +} diff --git a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java index 74e37b2d57a..6899204efdf 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java @@ -228,6 +228,11 @@ public class NewGameScene extends UIScene { public void enter() { updateAvatar(); Gdx.input.setInputProcessor(stage); //Start taking input from the ui + + if(Forge.createNewAdventureMap) + { + start(); + } } @Override diff --git a/forge-gui-mobile/src/forge/adventure/scene/StartScene.java b/forge-gui-mobile/src/forge/adventure/scene/StartScene.java index 7157a93e541..238af360f14 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/StartScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/StartScene.java @@ -7,9 +7,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.utils.Align; import forge.Forge; import forge.adventure.stage.GameHUD; +import forge.adventure.stage.GameStage; import forge.adventure.stage.MapStage; import forge.adventure.util.Config; import forge.adventure.util.Controls; +import forge.adventure.util.Current; import forge.adventure.world.WorldSave; import forge.screens.TransitionScreen; @@ -104,6 +106,13 @@ public class StartScene extends UIScene { } Gdx.input.setInputProcessor(stage); //Start taking input from the ui + + if(Forge.createNewAdventureMap) + { + this.NewGame(); + Current.setDebug(true); + GameStage.maximumScrollDistance=4f; + } } @Override diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java index d904c379224..daa2b3370f6 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java @@ -36,6 +36,8 @@ public abstract class GameStage extends Stage { private float touchY = -1; private final float timer = 0; private float animationTimeout = 0; + public static float maximumScrollDistance=1.5f; + public static float minimumScrollDistance=0.3f; public void startPause(float i) { startPause(i, null); @@ -222,10 +224,10 @@ public abstract class GameStage extends Stage { if (isPaused()) return true; camera.zoom += (amountY * 0.03); - if (camera.zoom < 0.3f) - camera.zoom = 0.3f; - if (camera.zoom > 1.5f) - camera.zoom = 1.5f; + if (camera.zoom < minimumScrollDistance) + camera.zoom = minimumScrollDistance; + if (camera.zoom > maximumScrollDistance) + camera.zoom = maximumScrollDistance; return super.scrolled(amountX, amountY); } diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java index c7e14a7f550..7fa6d0ce2f5 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java @@ -176,19 +176,7 @@ public class WorldStage extends GameStage implements SaveFileContent { public boolean isColliding(Rectangle boundingRect) { - World world = WorldSave.getCurrentSave().getWorld(); - int currentBiome = World.highestBiome(world.getBiome((int) boundingRect.getX() / world.getTileSize(), (int) boundingRect.getY() / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) (boundingRect.getX()+boundingRect.getWidth()) / world.getTileSize(), (int) boundingRect.getY() / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) (boundingRect.getX()+boundingRect.getWidth())/ world.getTileSize(), (int) (boundingRect.getY()+boundingRect.getHeight()) / world.getTileSize())); - if(currentBiome==0) - return true; - currentBiome = World.highestBiome(world.getBiome((int) boundingRect.getX() / world.getTileSize(), (int) (boundingRect.getY()+boundingRect.getHeight()) / world.getTileSize())); - - return (currentBiome==0); + return WorldSave.getCurrentSave().getWorld().collidingTile(boundingRect); } private void HandleMonsterSpawn(float delta) { diff --git a/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java new file mode 100644 index 00000000000..e991e52f183 --- /dev/null +++ b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java @@ -0,0 +1,114 @@ +package forge.adventure.world; + +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.github.sjcasey21.wavefunctioncollapse.OverlappingModel; +import forge.adventure.data.BiomeStructureData; +import forge.adventure.util.Config; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + +public class BiomeStructure { + + private BiomeStructureData data; + long seed; + private int biomeWidth; + private int biomeHeight; + private int dataMap[][]; + boolean init=false; + private TextureAtlas structureAtlas; + public BiomeStructure(BiomeStructureData data,long seed,int width,int height) + { + this.data=data; + this.seed=seed; + this.biomeWidth = width; + this.biomeHeight = height; + } + public TextureAtlas atlas() { + if(structureAtlas==null) + { + structureAtlas = Config.instance().getAtlas(data.structureAtlasPath); + } + return structureAtlas; + } + public int structureObjectCount() { + int count=0; + for(TextureAtlas.AtlasRegion region:atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + count++; + } + } + return count; + } + + public int objectID(int x, int y) { + + if(!init) + { + init=true; + initialize(); + } + if(x>biomeWidth*data.width) + return -1; + if(y>biomeHeight*data.height) + return -1; + if(x colorIdMap=new HashMap<>(); + int counter=0; + for(TextureAtlas.AtlasRegion region:atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + String[] split= region.name.split("_"); + if(split.length<2) + continue; + int rgb=Integer.parseInt(split[1],16); + colorIdMap.put(rgb,counter); + counter++; + } + } + BufferedImage image=model.graphics(); + dataMap=new int[image.getWidth()][image.getHeight()]; + for(int x=0;x> images = new ArrayList<>(); ArrayList> smallImages = new ArrayList<>(); ArrayList> edgeImages = new ArrayList<>(); @@ -45,7 +46,6 @@ public class BiomeTexture implements Serializable { FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public void run() { - Pixmap completePicture = null; if (images != null) { for (ArrayList val : images) { @@ -79,22 +79,38 @@ public class BiomeTexture implements Serializable { edgeImages = new ArrayList<>(); ArrayList regions =new ArrayList<>(); + ArrayList source =new ArrayList<>(); regions.add(Config.instance().getAtlas(data.tilesetAtlas).findRegion(data.tilesetName)); + source.add(Config.instance().getAtlas(data.tilesetAtlas)); if(data.terrain!=null) { for(BiomeTerrainData terrain:data.terrain) { regions.add(Config.instance().getAtlas(data.tilesetAtlas).findRegion(terrain.spriteName)); + source.add(Config.instance().getAtlas(data.tilesetAtlas)); } } + if(data.structures!=null) + { + for(BiomeStructureData structureData:data.structures) + { + BiomeStructure structure=new BiomeStructure(structureData,0,0,0); + for(TextureAtlas.AtlasRegion region:structure.atlas ().getRegions()) + { + if(region.name.startsWith("structure")) + { + regions.add(region); + source.add(structure.atlas()); + } + } + } + } + for (TextureAtlas.AtlasRegion region : regions) { ArrayList pics = new ArrayList<>(); ArrayList spics = new ArrayList<>(); - if (completePicture == null) { region.getTexture().getTextureData().prepare(); - completePicture = region.getTexture().getTextureData().consumePixmap(); - } - + Pixmap completePicture = region.getTexture().getTextureData().consumePixmap(); for (int y = 0; y < 4; y++) { for (int x = 0; x < 3; x++) { int px = region.getRegionX() + (x * tileSize); @@ -117,6 +133,7 @@ public class BiomeTexture implements Serializable { smallImages.add(spics); edgeImages.add(new IntMap<>()); + completePicture.dispose(); } } }); @@ -124,6 +141,8 @@ public class BiomeTexture implements Serializable { public Pixmap getPixmap(int biomeSubIndex) { if (biomeSubIndex >= edgeImages.size() || biomeSubIndex < 0) { + if(emptyPixmap==null) + emptyPixmap=new Pixmap(1, 1, Pixmap.Format.RGBA8888); return emptyPixmap; } return images.get(biomeSubIndex).get(BigPictures.Center.value); diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index a7ecf515a65..c450f067507 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -9,11 +9,7 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.Json; -import forge.adventure.data.BiomeData; -import forge.adventure.data.BiomeSpriteData; -import forge.adventure.data.BiomeTerrainData; -import forge.adventure.data.PointOfInterestData; -import forge.adventure.data.WorldData; +import forge.adventure.data.*; import forge.adventure.pointofintrest.PointOfInterest; import forge.adventure.pointofintrest.PointOfInterestMap; import forge.adventure.scene.Scene; @@ -24,10 +20,7 @@ import forge.adventure.util.SaveFileContent; import forge.adventure.util.SaveFileData; import org.apache.commons.lang3.tuple.Pair; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Random; +import java.util.*; /** * Class that will create the world from the configuration @@ -55,6 +48,26 @@ public class World implements Disposable, SaveFileContent { return (int) (Math.log(Long.highestOneBit(biome)) / Math.log(2)); } + public boolean collidingTile(Rectangle boundingRect) + { + Set> points=new HashSet<>(); + + int xLeft=(int) boundingRect.getX() / getTileSize(); + int yTop=(int) boundingRect.getY() / getTileSize(); + int xRight=(int) (boundingRect.getX()+boundingRect.getWidth()) / getTileSize(); + int yBottom= (int) (boundingRect.getY()+boundingRect.getHeight()) / getTileSize(); + + if(getBiome(xLeft,yTop)==0) + return true; + if(getBiome(xLeft,yBottom)==0) + return true; + if(getBiome(xRight,yBottom)==0) + return true; + if(getBiome(xRight,yTop)==0) + return true; + + return false; + } public void loadWorldData() { if(worldDataLoaded) return; @@ -85,6 +98,9 @@ public class World implements Disposable, SaveFileContent { biomeImage=saveFileData.readPixmap("biomeImage"); biomeMap=(long[][])saveFileData.readObject("biomeMap"); terrainMap=(int[][])saveFileData.readObject("terrainMap"); + + + width=saveFileData.readInt("width"); height=saveFileData.readInt("height"); mapObjectIds = new SpritesDataMap(getChunkSize(), this.data.tileSize, this.data.width / getChunkSize()); @@ -269,6 +285,7 @@ public class World implements Disposable, SaveFileContent { endX = width; endY = height; } + HashMap structureDataMap=new HashMap<>(); for (int x = beginX; x < endX; x++) { for (int y = beginY; y < endY; y++) { //value 0-1 based on noise @@ -288,16 +305,34 @@ public class World implements Disposable, SaveFileContent { pix.drawPixel(x, y); biomeMap[x][y] |= (1L << biomeIndex); int terrainCounter=1; - if(biome.terrain==null) - continue; - for(BiomeTerrainData terrain:biome.terrain) + if(biome.terrain!=null) { - float terrainNoise = ((float)noise.eval(x / (float) width * (noiseZoom*terrain.resolution), y / (float) height * (noiseZoom*terrain.resolution)) + 1) / 2; - if(terrainNoise>=terrain.min&&terrainNoise<=terrain.max) + for(BiomeTerrainData terrain:biome.terrain) { - terrainMap[x][y]=terrainCounter; + float terrainNoise = ((float)noise.eval(x / (float) width * (noiseZoom*terrain.resolution), y / (float) height * (noiseZoom*terrain.resolution)) + 1) / 2; + if(terrainNoise>=terrain.min&&terrainNoise<=terrain.max) + { + terrainMap[x][y]=terrainCounter; + } + terrainCounter++; + } + } + if(biome.structures!=null) + { + for(BiomeStructureData data:biome.structures) + { + BiomeStructure structure; + if(!structureDataMap.containsKey(data)) + { + structureDataMap.put(data,new BiomeStructure(data,seed,biomeWidth,biomeHeight)); + } + structure=structureDataMap.get(data); + int structureIndex=structure.objectID(x-biomeXStart,y-biomeYStart); + if(structureIndex>=0) + terrainMap[x][y]=terrainCounter+structureIndex; + + terrainCounter+=structure.structureObjectCount(); } - terrainCounter++; } } @@ -432,6 +467,9 @@ public class World implements Disposable, SaveFileContent { for (int y = (int) currentPoint.y - 1; y < currentPoint.y + 2; y++) { if(x<0||y<=0||x>=width||y>height)continue; biomeMap[x][height - y] |= (1L << biomeIndex); + terrainMap[x][height-y]=0; + + pix.drawPixel(x, height-y); } } @@ -465,7 +503,9 @@ public class World implements Disposable, SaveFileContent { if( (int)currentPoint.x<0|| (int)currentPoint.y<=0|| (int)currentPoint.x>=width|| (int)currentPoint.y>height)continue; biomeMap[(int) currentPoint.x][height - (int) currentPoint.y] |= (1L << biomeIndex); + terrainMap[(int) currentPoint.x][height - (int) currentPoint.y]=0; pix.drawPixel((int) currentPoint.x, height - (int) currentPoint.y); + } } @@ -482,6 +522,8 @@ public class World implements Disposable, SaveFileContent { BiomeSpriteData sprite = data.GetBiomeSprites().getSpriteData(name); double spriteNoise = (noise.eval(x / (double) width * noiseZoom*sprite.resolution, y / (double) invertedHeight * noiseZoom*sprite.resolution) + 1) / 2; if (spriteNoise >= sprite.startArea && spriteNoise <= sprite.endArea) { + if(terrainMap[x][invertedHeight]>biome.terrain.length) + continue; if (random.nextFloat() <= sprite.density) { String spriteKey = sprite.key(); int key; diff --git a/forge-gui-mobile/src/forge/adventure/world/WorldSave.java b/forge-gui-mobile/src/forge/adventure/world/WorldSave.java index 0bdbbd533c1..ca606512ecb 100644 --- a/forge-gui-mobile/src/forge/adventure/world/WorldSave.java +++ b/forge-gui-mobile/src/forge/adventure/world/WorldSave.java @@ -58,6 +58,8 @@ public class WorldSave { static public boolean load(int currentSlot) { String fileName = WorldSave.getSaveFile(currentSlot); + if(!new File(fileName).exists()) + return false; new File(getSaveDir()).mkdirs(); try { try(FileInputStream fos = new FileInputStream(fileName); diff --git a/forge-gui-mobile/src/forge/screens/SplashScreen.java b/forge-gui-mobile/src/forge/screens/SplashScreen.java index 504530999b8..5b9ffcb8e2b 100644 --- a/forge-gui-mobile/src/forge/screens/SplashScreen.java +++ b/forge-gui-mobile/src/forge/screens/SplashScreen.java @@ -265,6 +265,14 @@ public class SplashScreen extends FContainer { add(btnHome); btnAdventure.setBounds(btn_x, btn_y + height + padding / 2, btn_w, height); add(btnAdventure); + + if(Forge.createNewAdventureMap) + { + bgAnimation.progress = 1; + bgAnimation.openAdventure = true; + Forge.openAdventure(); + Forge.clearSplashScreen(); + } } } diff --git a/forge-gui/res/adventure/Shandalar/world/green.json b/forge-gui/res/adventure/Shandalar/world/green.json index bf0dca678ba..def5769876c 100644 --- a/forge-gui/res/adventure/Shandalar/world/green.json +++ b/forge-gui/res/adventure/Shandalar/world/green.json @@ -19,6 +19,14 @@ "resolution": 10 } ], + "structures":[ + { + "structureAtlasPath":"world/tilesets/forest.atlas", + "x": 0.5, + "y": 0.5, + "size": 0.3 + } + ], "width": 0.7, "height": 0.7, "color": "59a650", diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/autotiles.png b/forge-gui/res/adventure/Shandalar/world/tilesets/autotiles.png index 8c651dffb0897c7d0bfa57a3f936ebe3e38a04ec..c10104d2528f02593787acc2cf3f9c9e4be79fad 100644 GIT binary patch delta 12980 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 B5Iz6^ diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas new file mode 100644 index 00000000000..bb08300ae21 --- /dev/null +++ b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.atlas @@ -0,0 +1,20 @@ + +forest.png +size: 96,64 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +Source + rotate: false + xy: 0, 0 + size: 16, 16 + orig: 0, 0 + offset: 0, 0 + index: 0 +structure_000000 + rotate: false + xy: 48, 0 + size: 48, 64 + orig: 0, 0 + offset: 0, 0 + index: 0 \ No newline at end of file diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png new file mode 100644 index 0000000000000000000000000000000000000000..cf8dd71e0c9d2cb2327c33398a99d087c459cf34 GIT binary patch literal 16786 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 literal 0 HcmV?d00001 From 4cdf7829c23e1387f67819dc7ac66a5aa5538416 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Sat, 6 Aug 2022 12:32:43 +0800 Subject: [PATCH 27/66] fix dual choices and alternate view on confirm action --- .../src/forge/screens/match/views/VCardDisplayArea.java | 2 ++ forge-gui/src/main/java/forge/player/HumanCostDecision.java | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/forge-gui-mobile/src/forge/screens/match/views/VCardDisplayArea.java b/forge-gui-mobile/src/forge/screens/match/views/VCardDisplayArea.java index d88b05f1ded..f4a8bba7681 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VCardDisplayArea.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VCardDisplayArea.java @@ -323,6 +323,8 @@ public abstract class VCardDisplayArea extends VDisplayArea implements ActivateH @Override public boolean tap(float x, float y, int count) { + if (count > 1) //prevent double choice lists or activate handle + return false; if (renderedCardContains(x, y)) { ThreadUtil.invokeInGameThread(new Runnable() { //must invoke in game thread in case a dialog needs to be shown @Override diff --git a/forge-gui/src/main/java/forge/player/HumanCostDecision.java b/forge-gui/src/main/java/forge/player/HumanCostDecision.java index 10465f5805f..71fd421e317 100644 --- a/forge-gui/src/main/java/forge/player/HumanCostDecision.java +++ b/forge-gui/src/main/java/forge/player/HumanCostDecision.java @@ -1176,7 +1176,8 @@ public class HumanCostDecision extends CostDecisionMakerBase { else if (ability.getTargets() != null && ability.getTargets().isTargetingAnyCard() && ability.getTargets().size() == 1) cardView = CardView.get(ability.getTargetCard()); else if (cardView.getZone() == null || cardView.getZone().isHidden()) { - cardView = CardView.getCardForUi(ImageUtil.getPaperCardFromImageKey(cardView.getCurrentState().getImageKey())); + if (!cardView.hasAlternateState()) //don't override if it has alternatestate since it maybe showing alternate view + cardView = CardView.getCardForUi(ImageUtil.getPaperCardFromImageKey(cardView.getCurrentState().getImageKey())); } return controller.getGui().confirm(cardView, message.replaceAll("\n", " ")); } else { From f6bec79a28f23fd5beda344b34844c34515575f3 Mon Sep 17 00:00:00 2001 From: Grimm Date: Sat, 6 Aug 2022 21:10:18 +0200 Subject: [PATCH 28/66] changed road algo added WaveFunctionCollapse to create biome structures changed world generation. added overworld collision for enemies. --- .../forge/adventure/editor/BiomeEdit.java | 2 - .../BiomeStructureDataMappingEditor.java | 1 - .../adventure/editor/BiomeStructureEdit.java | 7 +- .../adventure/editor/BiomeTerrainEdit.java | 1 - .../forge/adventure/editor/EffectEditor.java | 1 - .../forge/adventure/editor/EnemyEdit.java | 1 - .../adventure/editor/PointOfInterestEdit.java | 1 - .../forge/adventure/editor/RewardEdit.java | 1 - .../adventure/editor/StructureEditor.java | 13 +- .../forge/adventure/editor/SwingAtlas.java | 24 ++- .../adventure/editor/SwingAtlasPreview.java | 1 - .../forge/adventure/editor/TextListEdit.java | 4 +- .../forge/adventure/editor/WorldEditor.java | 2 - .../src/forge/CachedCardImage.java | 1 - forge-gui-mobile/src/forge/Forge.java | 12 +- forge-gui-mobile/src/forge/Graphics.java | 12 +- .../adventure/character/CharacterSprite.java | 7 +- .../adventure/character/EnemySprite.java | 1 - .../adventure/character/RewardSprite.java | 1 - .../src/forge/adventure/data/BiomeData.java | 1 - .../adventure/data/BiomeStructureData.java | 3 +- .../src/forge/adventure/data/ConfigData.java | 2 - .../src/forge/adventure/data/UIData.java | 1 - .../adventure/player/AdventurePlayer.java | 10 +- .../adventure/scene/AdventureDeckEditor.java | 12 +- .../adventure/scene/DeckSelectScene.java | 7 +- .../forge/adventure/scene/NewGameScene.java | 8 +- .../adventure/scene/PlayerStatisticScene.java | 6 +- .../forge/adventure/scene/RewardScene.java | 6 +- .../adventure/scene/SpellSmithScene.java | 6 +- .../src/forge/adventure/stage/MapStage.java | 1 - .../src/forge/adventure/stage/WorldStage.java | 6 +- .../src/forge/adventure/util/MapDialog.java | 4 +- .../adventure/util/TemplateTmxMapLoader.java | 6 +- .../src/forge/adventure/util/UIActor.java | 1 - .../forge/adventure/world/BiomeStructure.java | 33 +++- .../forge/adventure/world/BiomeTexture.java | 18 +- .../src/forge/adventure/world/World.java | 39 +++- .../src/forge/animation/ForgeAnimation.java | 7 +- .../src/forge/animation/ForgeTransition.java | 11 +- .../src/forge/animation/GifAnimation.java | 1 - .../src/forge/animation/GifDecoder.java | 6 +- .../src/forge/assets/AssetsDownloader.java | 16 +- .../src/forge/assets/BitmapFontWriter.java | 1 - .../src/forge/assets/FBufferedImage.java | 1 - .../src/forge/assets/FDelayLoadImage.java | 1 - .../src/forge/assets/FLanguage.java | 7 +- .../src/forge/assets/FRotatedImage.java | 1 - .../src/forge/assets/FSkinColor.java | 5 +- .../src/forge/assets/FSkinFont.java | 11 +- .../src/forge/assets/FSkinImage.java | 1 - .../src/forge/assets/FSkinTexture.java | 9 +- .../src/forge/assets/FTextureImage.java | 1 - .../src/forge/assets/FTextureRegionImage.java | 1 - .../src/forge/assets/ImageCache.java | 37 ++-- .../src/forge/assets/TextRenderer.java | 11 +- .../src/forge/card/CardFaceSymbols.java | 4 +- .../src/forge/card/CardImage.java | 1 - .../src/forge/card/CardImageRenderer.java | 24 ++- .../src/forge/card/CardListPreview.java | 1 - .../src/forge/card/CardRenderer.java | 32 +--- forge-gui-mobile/src/forge/card/CardZoom.java | 9 +- .../src/forge/card/GameEntityPicker.java | 9 +- .../src/forge/deck/AddBasicLandsDialog.java | 20 +- .../src/forge/deck/FDeckChooser.java | 26 +-- .../src/forge/deck/FDeckEditor.java | 5 +- .../src/forge/deck/FDeckImportDialog.java | 14 +- .../src/forge/deck/FDeckViewer.java | 10 +- .../src/forge/deck/FSideboardDialog.java | 7 +- .../src/forge/error/BugReportDialog.java | 1 - .../src/forge/itemmanager/CardManager.java | 11 +- .../src/forge/itemmanager/DeckManager.java | 5 +- .../src/forge/itemmanager/ItemManager.java | 20 +- .../forge/itemmanager/SpellShopManager.java | 5 +- .../filters/AdvancedSearchFilter.java | 9 +- .../filters/ArchivedFormatSelect.java | 9 +- .../itemmanager/filters/CardCMCFilter.java | 1 - .../itemmanager/filters/CardColorFilter.java | 1 - .../filters/CardColorlessCostFilter.java | 1 - .../itemmanager/filters/CardFormatFilter.java | 1 - .../itemmanager/filters/CardPowerFilter.java | 1 - .../itemmanager/filters/CardRarityFilter.java | 1 - .../itemmanager/filters/CardSearchFilter.java | 1 - .../filters/CardToughnessFilter.java | 1 - .../itemmanager/filters/CardTypeFilter.java | 7 +- .../itemmanager/filters/DeckColorFilter.java | 1 - .../itemmanager/filters/DeckFolderFilter.java | 9 +- .../itemmanager/filters/DeckFormatFilter.java | 1 - .../itemmanager/filters/FormatFilter.java | 16 +- .../forge/itemmanager/filters/ItemFilter.java | 1 - .../itemmanager/filters/ListLabelFilter.java | 1 - .../itemmanager/filters/StatTypeFilter.java | 6 +- .../itemmanager/filters/TextSearchFilter.java | 1 - .../filters/ToggleButtonsFilter.java | 7 +- .../itemmanager/filters/ValueRangeFilter.java | 1 - .../forge/itemmanager/views/ItemListView.java | 19 +- .../src/forge/itemmanager/views/ItemView.java | 17 +- .../src/forge/menu/FDropDown.java | 1 - .../src/forge/menu/FMagnifyView.java | 1 - forge-gui-mobile/src/forge/menu/FMenuBar.java | 6 +- .../src/forge/menu/FMenuItem.java | 1 - forge-gui-mobile/src/forge/menu/FMenuTab.java | 1 - .../src/forge/menu/FPopupMenu.java | 1 - forge-gui-mobile/src/forge/menu/FTooltip.java | 1 - .../src/forge/screens/FScreen.java | 5 +- .../src/forge/screens/LaunchScreen.java | 1 - .../src/forge/screens/LoadingOverlay.java | 1 - .../src/forge/screens/SplashScreen.java | 1 - .../src/forge/screens/TabPageScreen.java | 7 +- .../achievements/AchievementsScreen.java | 8 +- .../screens/constructed/AvatarSelector.java | 7 +- .../screens/constructed/LobbyScreen.java | 27 +-- .../screens/constructed/PlayerPanel.java | 33 +--- .../screens/constructed/SleevesSelector.java | 7 +- .../screens/gauntlet/LoadGauntletScreen.java | 13 +- .../screens/gauntlet/NewGauntletScreen.java | 10 +- .../src/forge/screens/home/HomeScreen.java | 13 +- .../screens/home/puzzle/PuzzleScreen.java | 8 +- .../limited/DraftingProcessScreen.java | 3 +- .../screens/limited/LoadDraftScreen.java | 13 +- .../screens/limited/LoadSealedScreen.java | 13 +- .../forge/screens/match/MatchController.java | 42 ++-- .../src/forge/screens/match/MatchScreen.java | 51 ++--- .../forge/screens/match/TargetingOverlay.java | 1 - .../match/views/VAssignCombatDamage.java | 26 +-- .../match/views/VAssignGenericAmount.java | 26 +-- .../screens/match/views/VAutoYields.java | 12 +- .../forge/screens/match/views/VAvatar.java | 1 - .../screens/match/views/VCardDisplayArea.java | 11 +- .../src/forge/screens/match/views/VField.java | 6 +- .../src/forge/screens/match/views/VLog.java | 5 +- .../forge/screens/match/views/VManaPool.java | 7 +- .../screens/match/views/VPhaseIndicator.java | 7 +- .../screens/match/views/VPlayerPanel.java | 11 +- .../forge/screens/match/views/VPlayers.java | 7 +- .../forge/screens/match/views/VPrompt.java | 4 +- .../src/forge/screens/match/views/VStack.java | 17 +- .../screens/match/views/VZoneDisplay.java | 4 +- .../match/winlose/GauntletWinLose.java | 4 +- .../screens/match/winlose/ViewWinLose.java | 16 +- .../screens/online/OnlineChatScreen.java | 1 - .../screens/online/OnlineLobbyScreen.java | 7 +- .../src/forge/screens/online/OnlineMenu.java | 4 +- .../planarconquest/ConquestAEtherScreen.java | 27 +-- .../planarconquest/ConquestChaosWheel.java | 1 - .../ConquestCollectionScreen.java | 7 +- .../ConquestCommandersScreen.java | 17 +- .../planarconquest/ConquestDeckEditor.java | 4 +- .../ConquestMultiverseScreen.java | 40 +--- .../planarconquest/ConquestPlaneSelector.java | 11 +- .../ConquestPlaneswalkScreen.java | 1 - .../planarconquest/ConquestPrefsScreen.java | 9 +- .../planarconquest/ConquestRewardDialog.java | 13 +- .../planarconquest/ConquestStatsScreen.java | 7 +- .../planarconquest/LoadConquestScreen.java | 12 +- .../planarconquest/NewConquestScreen.java | 1 - .../forge/screens/quest/LoadQuestScreen.java | 16 +- .../forge/screens/quest/NewQuestScreen.java | 29 +-- .../screens/quest/QuestBazaarScreen.java | 15 +- .../screens/quest/QuestChallengesScreen.java | 1 - .../forge/screens/quest/QuestDeckEditor.java | 6 +- .../forge/screens/quest/QuestDecksScreen.java | 1 - .../forge/screens/quest/QuestDuelsScreen.java | 5 +- .../forge/screens/quest/QuestEventPanel.java | 7 +- .../src/forge/screens/quest/QuestMenu.java | 6 +- .../forge/screens/quest/QuestPrefsScreen.java | 9 +- .../screens/quest/QuestSpellShopScreen.java | 13 +- .../forge/screens/quest/QuestStatsScreen.java | 12 +- .../screens/quest/QuestTournamentsScreen.java | 12 +- .../src/forge/screens/settings/FilesPage.java | 57 +++--- .../forge/screens/settings/GuiDownloader.java | 10 +- .../src/forge/toolbox/DualListBox.java | 9 +- .../src/forge/toolbox/FButton.java | 4 +- .../src/forge/toolbox/FCheckBox.java | 1 - .../src/forge/toolbox/FChoiceList.java | 13 +- .../src/forge/toolbox/FComboBox.java | 9 +- .../src/forge/toolbox/FContainer.java | 9 +- .../src/forge/toolbox/FDialog.java | 1 - .../src/forge/toolbox/FDisplayObject.java | 5 +- .../src/forge/toolbox/FFileChooser.java | 10 +- .../src/forge/toolbox/FGestureAdapter.java | 1 - .../src/forge/toolbox/FGroupBox.java | 1 - .../src/forge/toolbox/FGroupList.java | 6 +- .../src/forge/toolbox/FLabel.java | 7 +- forge-gui-mobile/src/forge/toolbox/FList.java | 9 +- .../src/forge/toolbox/FOptionPane.java | 8 +- .../src/forge/toolbox/FOverlay.java | 9 +- .../src/forge/toolbox/FProgressBar.java | 12 +- .../src/forge/toolbox/FRadioButton.java | 7 +- .../src/forge/toolbox/FScrollPane.java | 5 +- .../src/forge/toolbox/FTextArea.java | 1 - .../src/forge/toolbox/FTextField.java | 1 - .../src/forge/toolbox/FToggleSwitch.java | 1 - .../src/forge/toolbox/GuiChoose.java | 15 +- .../src/forge/toolbox/GuiDialog.java | 8 +- .../src/forge/toolbox/ListChooser.java | 9 +- .../src/forge/util/LibGDXImageFetcher.java | 9 +- .../res/adventure/Shandalar/world/black.json | 178 +++++++++++++---- .../res/adventure/Shandalar/world/blue.json | 160 ++++++++++++---- .../res/adventure/Shandalar/world/green.json | 26 +-- .../res/adventure/Shandalar/world/red.json | 179 ++++++++++++++---- .../Shandalar/world/tilesets/circle.png | Bin 0 -> 9611 bytes .../Shandalar/world/tilesets/deep_swamp.png | Bin 0 -> 11197 bytes .../Shandalar/world/tilesets/forest.png | Bin 16786 -> 5955 bytes .../Shandalar/world/tilesets/forestSource.png | Bin 10751 -> 0 bytes .../Shandalar/world/tilesets/hole.png | Bin 0 -> 10184 bytes .../world/tilesets/island_forest.png | Bin 0 -> 8670 bytes .../Shandalar/world/tilesets/lake.png | Bin 0 -> 10109 bytes .../Shandalar/world/tilesets/lakeSource.png | Bin 10750 -> 0 bytes .../Shandalar/world/tilesets/lava.png | Bin 0 -> 11819 bytes .../Shandalar/world/tilesets/moon.png | Bin 0 -> 10925 bytes .../Shandalar/world/tilesets/moon2.png | Bin 0 -> 10837 bytes .../Shandalar/world/tilesets/moon3.png | Bin 0 -> 10545 bytes .../Shandalar/world/tilesets/moon4.png | Bin 0 -> 10606 bytes .../Shandalar/world/tilesets/mountain.png | Bin 0 -> 6084 bytes .../world/tilesets/mountain_forest.png | Bin 0 -> 11197 bytes .../world/tilesets/plains_forest.png | Bin 0 -> 5761 bytes .../Shandalar/world/tilesets/plateau.png | Bin 0 -> 9010 bytes .../Shandalar/world/tilesets/ring.png | Bin 0 -> 11799 bytes .../Shandalar/world/tilesets/ring2.png | Bin 0 -> 12684 bytes .../Shandalar/world/tilesets/structures.atlas | 67 +++++-- .../Shandalar/world/tilesets/structures.png | Bin 89101 -> 40939 bytes .../Shandalar/world/tilesets/swamp.png | Bin 0 -> 11213 bytes .../Shandalar/world/tilesets/swamp_forest.png | Bin 0 -> 6167 bytes .../Shandalar/world/tilesets/swamp_ruins.png | Bin 0 -> 11665 bytes .../world/tilesets/waste_structure.png | Bin 0 -> 7804 bytes .../Shandalar/world/tilesets/water.png | Bin 0 -> 7139 bytes .../res/adventure/Shandalar/world/waste.json | 174 +++++++++++++---- .../res/adventure/Shandalar/world/white.json | 149 +++++++++++---- 229 files changed, 1329 insertions(+), 1283 deletions(-) create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/circle.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/deep_swamp.png delete mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/forestSource.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/hole.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/island_forest.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/lake.png delete mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/lakeSource.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/lava.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/moon.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/moon2.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/moon3.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/moon4.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/mountain.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/mountain_forest.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/plains_forest.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/plateau.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/ring.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/ring2.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/swamp.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/swamp_forest.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/swamp_ruins.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/waste_structure.png create mode 100644 forge-gui/res/adventure/Shandalar/world/tilesets/water.png diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java index e3e7e598f82..5cfdf01f0fa 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeEdit.java @@ -3,8 +3,6 @@ package forge.adventure.editor; import forge.adventure.data.BiomeData; import javax.swing.*; -import java.awt.*; -import java.util.Arrays; public class BiomeEdit extends FormPanel { BiomeData currentData; diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java index 39c1c2cbca8..9ff1938ecf3 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureDataMappingEditor.java @@ -2,7 +2,6 @@ package forge.adventure.editor; import forge.adventure.data.BiomeStructureData; import forge.adventure.util.Config; -import forge.adventure.world.BiomeStructure; import javax.swing.*; import java.awt.*; diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java index 3d55f5f7a51..3682fede08c 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeStructureEdit.java @@ -6,8 +6,6 @@ import forge.adventure.data.BiomeStructureData; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.image.BufferedImage; public class BiomeStructureEdit extends FormPanel { private boolean updating=false; @@ -21,6 +19,7 @@ public class BiomeStructureEdit extends FormPanel { public JCheckBox randomPosition=new JCheckBox(); public IntSpinner N= new IntSpinner(); public JTextField sourcePath= new JTextField(); + public JTextField maskPath= new JTextField(); public JCheckBox periodicInput= new JCheckBox(); public IntSpinner ground= new IntSpinner(); public IntSpinner symmetry= new IntSpinner(); @@ -37,6 +36,7 @@ public class BiomeStructureEdit extends FormPanel { center.add("height:",height); center.add("N:",N); center.add("sourcePath:",sourcePath); + center.add("maskPath:",maskPath); center.add("periodicInput:",periodicInput); center.add("ground:",ground); center.add("symmetry:",symmetry); @@ -56,6 +56,7 @@ public class BiomeStructureEdit extends FormPanel { N.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); sourcePath.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureEdit.this.updateStructure())); + maskPath.getDocument().addDocumentListener(new DocumentChangeListener(() -> BiomeStructureEdit.this.updateStructure())); periodicInput.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); ground.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); symmetry.addChangeListener(e -> BiomeStructureEdit.this.updateStructure()); @@ -78,6 +79,7 @@ public class BiomeStructureEdit extends FormPanel { randomPosition.setSelected(currentData.randomPosition); N.setValue(currentData.N); sourcePath.setText(currentData.sourcePath); + maskPath.setText(currentData.maskPath); periodicInput.setSelected(currentData.periodicInput); ground.setValue(currentData.ground); symmetry.setValue(currentData.symmetry); @@ -105,6 +107,7 @@ public class BiomeStructureEdit extends FormPanel { currentData.N= N.intValue(); currentData.sourcePath= sourcePath.getText(); + currentData.maskPath= maskPath.getText(); currentData.periodicInput= periodicInput.isSelected(); currentData.ground= ground.intValue(); currentData.symmetry= symmetry.intValue(); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java index 88bde85698f..86698e0fcdf 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/BiomeTerrainEdit.java @@ -6,7 +6,6 @@ import forge.adventure.data.BiomeTerrainData; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.awt.*; public class BiomeTerrainEdit extends FormPanel { SwingAtlasPreview preview=new SwingAtlasPreview(128); diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EffectEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/EffectEditor.java index 1221e41a7a4..656e79651a1 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EffectEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EffectEditor.java @@ -5,7 +5,6 @@ import forge.adventure.data.EffectData; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.awt.*; public class EffectEditor extends JComponent { EffectData currentData; diff --git a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java index 1375670a00d..9e328887297 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/EnemyEdit.java @@ -3,7 +3,6 @@ package forge.adventure.editor; import forge.adventure.data.EnemyData; import javax.swing.*; -import java.awt.*; /** * Editor class to edit configuration, maybe moved or removed diff --git a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java index cc7daa8ce70..2f883dae9db 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/PointOfInterestEdit.java @@ -3,7 +3,6 @@ package forge.adventure.editor; import forge.adventure.data.PointOfInterestData; import javax.swing.*; -import java.awt.*; public class PointOfInterestEdit extends JComponent { diff --git a/forge-adventure/src/main/java/forge/adventure/editor/RewardEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/RewardEdit.java index 076261013ce..a5fe5e4fd83 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/RewardEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/RewardEdit.java @@ -7,7 +7,6 @@ import forge.game.keyword.Keyword; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.awt.*; import java.util.Arrays; /** diff --git a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java index 9181f6392df..36c99614196 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/StructureEditor.java @@ -2,7 +2,6 @@ package forge.adventure.editor; import forge.adventure.data.BiomeData; import forge.adventure.data.BiomeStructureData; -import forge.adventure.data.WorldData; import forge.adventure.util.Config; import forge.adventure.world.BiomeStructure; @@ -83,13 +82,14 @@ public class StructureEditor extends JComponent{ private void test() { if (list.isSelectionEmpty()) return; + long start = System.currentTimeMillis(); BiomeStructureData data = model.get(list.getSelectedIndex()); try { BiomeStructure struct = new BiomeStructure(data, System.currentTimeMillis(), - (int) (currentData.width * EditorMainWindow.worldEditor.width.intValue() * data.width), - (int) (currentData.width * EditorMainWindow.worldEditor.height.intValue() * data.height)); + (int) (currentData.width * EditorMainWindow.worldEditor.width.intValue() ), + (int) (currentData.width * EditorMainWindow.worldEditor.height.intValue())); struct.initialize(); JLabel label = new JLabel(); BufferedImage image = struct.image; @@ -111,11 +111,14 @@ public class StructureEditor extends JComponent{ } label.setIcon(new ImageIcon(image)); label.setSize(640, 640); - JOptionPane.showMessageDialog(this, label); + + + + JOptionPane.showMessageDialog(this, label,"Calculating took "+ ((System.currentTimeMillis() - start)/1000)+" seconds",JOptionPane.PLAIN_MESSAGE); } catch (Exception e) { - JOptionPane.showMessageDialog(this, "WaveFunctionCollapse was not successful"); + JOptionPane.showMessageDialog(this, "WaveFunctionCollapse was not successful","can not calculate function "+e.getMessage(),JOptionPane.ERROR_MESSAGE); } } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlas.java b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlas.java index 943e3df96e4..6241b824add 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlas.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlas.java @@ -55,15 +55,25 @@ public class SwingAtlas { } private ImageIcon spriteToImage(TextureAtlas.TextureAtlasData.Region sprite) throws IOException { - BufferedImage img = ImageIO.read(sprite.page.textureFile.file()); - if(sprite.width== sprite.height) - return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize,imageSize,SCALE_FAST)); - if(sprite.width>sprite.height) - return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize, (int) (imageSize*(sprite.height/(float)sprite.width)),SCALE_FAST)); - return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance((int) (imageSize*(sprite.width/(float)sprite.height)),imageSize,SCALE_FAST)); - } + try + { + BufferedImage img = ImageIO.read(sprite.page.textureFile.file()); + if(sprite.width== sprite.height) + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize,imageSize,SCALE_FAST)); + if(sprite.width>sprite.height) + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance(imageSize, (int) (imageSize*(sprite.height/(float)sprite.width)),SCALE_FAST)); + return new ImageIcon(img.getSubimage(sprite.left,sprite.top, sprite.width, sprite.height).getScaledInstance((int) (imageSize*(sprite.width/(float)sprite.height)),imageSize,SCALE_FAST)); + + } + catch (IOException e) + { + return null; + } +} public ImageIcon get(String name) { + if(images.get(name).size()==0) + return null; return images.get(name).get(0); } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java index 4a01fd30603..97e67659848 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/SwingAtlasPreview.java @@ -4,7 +4,6 @@ import forge.adventure.util.Config; import org.apache.commons.lang3.tuple.Pair; import javax.swing.*; -import java.awt.*; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; diff --git a/forge-adventure/src/main/java/forge/adventure/editor/TextListEdit.java b/forge-adventure/src/main/java/forge/adventure/editor/TextListEdit.java index 7388d926db1..8cc56aac09c 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/TextListEdit.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/TextListEdit.java @@ -3,6 +3,7 @@ package forge.adventure.editor; import forge.adventure.util.Config; import javax.swing.*; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; @@ -27,6 +28,7 @@ public class TextListEdit extends Box { }); add(edit); + edit.setPreferredSize(new Dimension(400,edit.getPreferredSize().height)); //add(findButton); elements= new JComboBox(possibleElements); add(elements); @@ -84,7 +86,7 @@ public class TextListEdit extends Box { { values.append(intValues[i]); if(intValues.length>i+2) - values.append(";"); + values.append("\n"); } edit.setText(values.toString()); } diff --git a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java index 437ecce9e76..d2ee9ea1f9a 100644 --- a/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java +++ b/forge-adventure/src/main/java/forge/adventure/editor/WorldEditor.java @@ -1,7 +1,6 @@ package forge.adventure.editor; import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Json; import com.badlogic.gdx.utils.JsonWriter; import forge.adventure.data.BiomeData; @@ -16,7 +15,6 @@ import java.awt.*; import java.io.File; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; public class WorldEditor extends JComponent { diff --git a/forge-gui-mobile/src/forge/CachedCardImage.java b/forge-gui-mobile/src/forge/CachedCardImage.java index 51ae26f81cc..7919d23d762 100644 --- a/forge-gui-mobile/src/forge/CachedCardImage.java +++ b/forge-gui-mobile/src/forge/CachedCardImage.java @@ -1,7 +1,6 @@ package forge; import com.badlogic.gdx.graphics.Texture; - import forge.assets.ImageCache; import forge.game.card.CardView; import forge.gui.GuiBase; diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 830775aa7ed..10b83090d62 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -5,11 +5,7 @@ import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.InputProcessor; -import com.badlogic.gdx.graphics.Cursor; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.Pixmap; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.TextureData; +import com.badlogic.gdx.graphics.*; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; @@ -23,11 +19,7 @@ import forge.adventure.scene.SceneType; import forge.adventure.stage.MapStage; import forge.adventure.util.Config; import forge.animation.ForgeAnimation; -import forge.assets.Assets; -import forge.assets.AssetsDownloader; -import forge.assets.FSkin; -import forge.assets.FSkinFont; -import forge.assets.ImageCache; +import forge.assets.*; import forge.error.ExceptionHandler; import forge.gamemodes.limited.BoosterDraft; import forge.gui.FThreads; diff --git a/forge-gui-mobile/src/forge/Graphics.java b/forge-gui-mobile/src/forge/Graphics.java index da4feba9f20..a2b64e15c34 100644 --- a/forge-gui-mobile/src/forge/Graphics.java +++ b/forge-gui-mobile/src/forge/Graphics.java @@ -1,10 +1,10 @@ package forge; -import java.util.ArrayDeque; -import java.util.Deque; - import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.graphics.*; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.glutils.ShaderProgram; @@ -15,7 +15,6 @@ import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack; - import forge.assets.FImage; import forge.assets.FSkinColor; import forge.assets.FSkinFont; @@ -23,6 +22,9 @@ import forge.toolbox.FDisplayObject; import forge.util.TextBounds; import forge.util.Utils; +import java.util.ArrayDeque; +import java.util.Deque; + public class Graphics { private static final int GL_BLEND = GL20.GL_BLEND; private static final int GL_LINE_SMOOTH = 2848; //create constant here since not in GL20 diff --git a/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java b/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java index ad356681ea7..ee768ab3c5b 100644 --- a/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/CharacterSprite.java @@ -1,11 +1,6 @@ package forge.adventure.character; -import com.badlogic.gdx.graphics.g2d.Animation; -import com.badlogic.gdx.graphics.g2d.Batch; -import com.badlogic.gdx.graphics.g2d.Sprite; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.graphics.g2d.*; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.utils.Array; diff --git a/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java b/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java index 4a487dd5d20..19c2836f7d1 100644 --- a/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/EnemySprite.java @@ -4,7 +4,6 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.utils.Array; diff --git a/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java b/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java index dda93529618..a6ba72c8b55 100644 --- a/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java +++ b/forge-gui-mobile/src/forge/adventure/character/RewardSprite.java @@ -1,6 +1,5 @@ package forge.adventure.character; -import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Array; import forge.adventure.data.RewardData; import forge.adventure.util.JSONStringLoader; diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java index 2e5c220cec2..1bd21bc2ecb 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeData.java @@ -6,7 +6,6 @@ import forge.util.MyRandom; import java.io.Serializable; import java.util.ArrayList; -import java.util.List; import java.util.Random; /** diff --git a/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java index 02bf44caaf7..4769635fda6 100644 --- a/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java +++ b/forge-gui-mobile/src/forge/adventure/data/BiomeStructureData.java @@ -1,6 +1,5 @@ package forge.adventure.data; -import java.awt.*; import java.awt.image.BufferedImage; public class BiomeStructureData { @@ -31,6 +30,7 @@ public class BiomeStructureData { public String structureAtlasPath; public String sourcePath; + public String maskPath; public boolean periodicInput=true; public float height; public float width; @@ -45,6 +45,7 @@ public class BiomeStructureData { public BiomeStructureData(BiomeStructureData biomeStructureData) { this.structureAtlasPath=biomeStructureData.structureAtlasPath; this.sourcePath=biomeStructureData.sourcePath; + this.maskPath=biomeStructureData.maskPath; this.x=biomeStructureData.x; this.y=biomeStructureData.y; this.width=biomeStructureData.width; diff --git a/forge-gui-mobile/src/forge/adventure/data/ConfigData.java b/forge-gui-mobile/src/forge/adventure/data/ConfigData.java index 04b9efdc1b4..e904058a6e3 100644 --- a/forge-gui-mobile/src/forge/adventure/data/ConfigData.java +++ b/forge-gui-mobile/src/forge/adventure/data/ConfigData.java @@ -1,8 +1,6 @@ package forge.adventure.data; -import java.util.List; - /** * Data class that will be used to read Json configuration files * BiomeData diff --git a/forge-gui-mobile/src/forge/adventure/data/UIData.java b/forge-gui-mobile/src/forge/adventure/data/UIData.java index d1ece9a84db..a9d528ea818 100644 --- a/forge-gui-mobile/src/forge/adventure/data/UIData.java +++ b/forge-gui-mobile/src/forge/adventure/data/UIData.java @@ -1,6 +1,5 @@ package forge.adventure.data; -import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.OrderedMap; /** diff --git a/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java b/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java index 57db089e307..3c1301ae7e5 100644 --- a/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java +++ b/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java @@ -5,7 +5,10 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Null; import com.google.common.collect.Lists; -import forge.adventure.data.*; +import forge.adventure.data.DifficultyData; +import forge.adventure.data.EffectData; +import forge.adventure.data.HeroListData; +import forge.adventure.data.ItemData; import forge.adventure.util.*; import forge.adventure.world.WorldSave; import forge.deck.CardPool; @@ -18,7 +21,10 @@ import forge.util.ItemPool; import forge.util.MyRandom; import java.io.Serializable; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; /** * Class that represents the player (not the player sprite) diff --git a/forge-gui-mobile/src/forge/adventure/scene/AdventureDeckEditor.java b/forge-gui-mobile/src/forge/adventure/scene/AdventureDeckEditor.java index cff35135c80..8362057f3e0 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/AdventureDeckEditor.java +++ b/forge-gui-mobile/src/forge/adventure/scene/AdventureDeckEditor.java @@ -9,18 +9,10 @@ import forge.adventure.player.AdventurePlayer; import forge.assets.FImage; import forge.assets.FSkinFont; import forge.assets.FSkinImage; -import forge.deck.CardPool; -import forge.deck.Deck; -import forge.deck.DeckFormat; -import forge.deck.DeckSection; -import forge.deck.FDeckViewer; +import forge.deck.*; import forge.item.InventoryItem; import forge.item.PaperCard; -import forge.itemmanager.CardManager; -import forge.itemmanager.ColumnDef; -import forge.itemmanager.ItemColumn; -import forge.itemmanager.ItemManager; -import forge.itemmanager.ItemManagerConfig; +import forge.itemmanager.*; import forge.itemmanager.filters.ItemFilter; import forge.localinstance.properties.ForgePreferences; import forge.menu.FCheckBoxMenuItem; diff --git a/forge-gui-mobile/src/forge/adventure/scene/DeckSelectScene.java b/forge-gui-mobile/src/forge/adventure/scene/DeckSelectScene.java index 2cc444e966a..c92ee4d4e4a 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/DeckSelectScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/DeckSelectScene.java @@ -3,12 +3,7 @@ package forge.adventure.scene; import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.scenes.scene2d.InputEvent; -import com.badlogic.gdx.scenes.scene2d.ui.Dialog; -import com.badlogic.gdx.scenes.scene2d.ui.Label; -import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; -import com.badlogic.gdx.scenes.scene2d.ui.Table; -import com.badlogic.gdx.scenes.scene2d.ui.TextButton; -import com.badlogic.gdx.scenes.scene2d.ui.TextField; +import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.IntMap; diff --git a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java index 6899204efdf..003a39dbd7e 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java @@ -4,13 +4,7 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; -import com.badlogic.gdx.scenes.scene2d.ui.Image; -import com.badlogic.gdx.scenes.scene2d.ui.ImageButton; -import com.badlogic.gdx.scenes.scene2d.ui.Label; -import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; -import com.badlogic.gdx.scenes.scene2d.ui.TextButton; -import com.badlogic.gdx.scenes.scene2d.ui.TextField; +import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; import com.badlogic.gdx.utils.Array; diff --git a/forge-gui-mobile/src/forge/adventure/scene/PlayerStatisticScene.java b/forge-gui-mobile/src/forge/adventure/scene/PlayerStatisticScene.java index 68be744d25f..05a8a1ee183 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/PlayerStatisticScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/PlayerStatisticScene.java @@ -4,11 +4,7 @@ import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.scenes.scene2d.ui.Image; -import com.badlogic.gdx.scenes.scene2d.ui.Label; -import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; -import com.badlogic.gdx.scenes.scene2d.ui.Table; -import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; import com.badlogic.gdx.utils.Align; import forge.Forge; diff --git a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java index 907886ec011..6e708079824 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java @@ -13,11 +13,7 @@ import forge.adventure.character.ShopActor; import forge.adventure.player.AdventurePlayer; import forge.adventure.pointofintrest.PointOfInterestChanges; import forge.adventure.stage.GameHUD; -import forge.adventure.util.CardUtil; -import forge.adventure.util.Config; -import forge.adventure.util.Current; -import forge.adventure.util.Reward; -import forge.adventure.util.RewardActor; +import forge.adventure.util.*; import forge.adventure.world.WorldSave; import forge.assets.ImageCache; import forge.sound.SoundEffectType; diff --git a/forge-gui-mobile/src/forge/adventure/scene/SpellSmithScene.java b/forge-gui-mobile/src/forge/adventure/scene/SpellSmithScene.java index 307f24ff778..c70a84a3db3 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/SpellSmithScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/SpellSmithScene.java @@ -3,7 +3,10 @@ package forge.adventure.scene; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.InputEvent; -import com.badlogic.gdx.scenes.scene2d.ui.*; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; +import com.badlogic.gdx.scenes.scene2d.ui.SelectBox; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import forge.Forge; @@ -19,7 +22,6 @@ import forge.item.PaperCard; import forge.util.MyRandom; import java.util.*; -import java.util.List; import java.util.stream.Collectors; import java.util.stream.StreamSupport; diff --git a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java index 1dc759ef348..4c84835fc91 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/MapStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/MapStage.java @@ -41,7 +41,6 @@ import forge.screens.TransitionScreen; import forge.sound.SoundEffectType; import forge.sound.SoundSystem; - import java.util.HashMap; import java.util.Map; diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java index 2c951ca36f3..dc080b8ba65 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java @@ -11,11 +11,7 @@ import forge.adventure.character.EnemySprite; import forge.adventure.data.BiomeData; import forge.adventure.data.EnemyData; import forge.adventure.data.WorldData; -import forge.adventure.scene.DuelScene; -import forge.adventure.scene.RewardScene; -import forge.adventure.scene.Scene; -import forge.adventure.scene.SceneType; -import forge.adventure.scene.TileMapScene; +import forge.adventure.scene.*; import forge.adventure.util.Current; import forge.adventure.util.SaveFileContent; import forge.adventure.util.SaveFileData; diff --git a/forge-gui-mobile/src/forge/adventure/util/MapDialog.java b/forge-gui-mobile/src/forge/adventure/util/MapDialog.java index f86b7fee73e..28d987171e2 100644 --- a/forge-gui-mobile/src/forge/adventure/util/MapDialog.java +++ b/forge-gui-mobile/src/forge/adventure/util/MapDialog.java @@ -1,6 +1,8 @@ package forge.adventure.util; -import com.badlogic.gdx.scenes.scene2d.ui.*; +import com.badlogic.gdx.scenes.scene2d.ui.Dialog; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.utils.Array; import forge.Forge; import forge.adventure.character.EnemySprite; diff --git a/forge-gui-mobile/src/forge/adventure/util/TemplateTmxMapLoader.java b/forge-gui-mobile/src/forge/adventure/util/TemplateTmxMapLoader.java index e98c42eb5cb..c0ee5ab05c5 100644 --- a/forge-gui-mobile/src/forge/adventure/util/TemplateTmxMapLoader.java +++ b/forge-gui-mobile/src/forge/adventure/util/TemplateTmxMapLoader.java @@ -10,11 +10,7 @@ import com.badlogic.gdx.maps.tiled.TiledMapTile; import com.badlogic.gdx.maps.tiled.TiledMapTileSet; import com.badlogic.gdx.maps.tiled.TmxMapLoader; import com.badlogic.gdx.maps.tiled.tiles.AnimatedTiledMapTile; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.GdxRuntimeException; -import com.badlogic.gdx.utils.ObjectMap; -import com.badlogic.gdx.utils.SerializationException; -import com.badlogic.gdx.utils.XmlReader; +import com.badlogic.gdx.utils.*; import forge.Forge; import java.io.File; diff --git a/forge-gui-mobile/src/forge/adventure/util/UIActor.java b/forge-gui-mobile/src/forge/adventure/util/UIActor.java index 7763465fc6a..840fa8e4661 100644 --- a/forge-gui-mobile/src/forge/adventure/util/UIActor.java +++ b/forge-gui-mobile/src/forge/adventure/util/UIActor.java @@ -10,7 +10,6 @@ import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; -import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Json; import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.OrderedMap; diff --git a/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java index 8f970041f68..3dcf0c5b74b 100644 --- a/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java +++ b/forge-gui-mobile/src/forge/adventure/world/BiomeStructure.java @@ -33,7 +33,14 @@ public class BiomeStructure { public TextureAtlas atlas() { if(structureAtlas==null) { - structureAtlas = Config.instance().getAtlas(data.structureAtlasPath); + try + { + structureAtlas = Config.instance().getAtlas(data.structureAtlasPath); + } + catch (Exception e) + { + e.printStackTrace(); + } } return structureAtlas; } @@ -62,23 +69,31 @@ public class BiomeStructure { } boolean suc=false; for(int i=0;i<10&&!suc;i++) - suc=model.run((int) seed+(i*5355),15000); + suc=model.run((int) seed+(i*5355),0); if(!suc) { dataMap=new int[(int) (data.width* biomeWidth)][ (int) (data.height*biomeHeight)]; collisionMap=new boolean[(int) (data.width* biomeWidth)][ (int) (data.height*biomeHeight)]; + for(int x=0;x pics = new ArrayList<>(); ArrayList spics = new ArrayList<>(); + if(!region.getTexture().getTextureData().isPrepared()) region.getTexture().getTextureData().prepare(); Pixmap completePicture = region.getTexture().getTextureData().consumePixmap(); for (int y = 0; y < 4; y++) { diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index 09dbe9dd750..c819d49aac6 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -274,9 +274,19 @@ private void clearTerrain(int x,int y,int size) } } +} +private long measureGenerationTime(String msg,long lastTime) +{ + long currentTime = System.currentTimeMillis(); + System.out.print("\n"+msg+" :\t\t"+((currentTime-lastTime)/1000f)+" s"); + return currentTime; } public World generateNew(long seed) { + + long currentTime = System.currentTimeMillis(); + loadWorldData(); + if(seed==0) { seed=random.nextLong(); } this.seed=seed; random.setSeed(seed); @@ -301,6 +311,7 @@ private void clearTerrain(int x,int y,int size) pix.fill(); int biomeIndex = -1; + currentTime=measureGenerationTime("loading data",currentTime); for (BiomeData biome : data.GetBiomes()) { biomeIndex++; @@ -311,8 +322,8 @@ private void clearTerrain(int x,int y,int size) int beginX = Math.max(biomeXStart - biomeWidth / 2, 0); int beginY = Math.max(biomeYStart - biomeHeight / 2, 0); - int endX = Math.min(biomeXStart + biomeWidth, width); - int endY = Math.min(biomeYStart + biomeHeight, height); + int endX = Math.min(biomeXStart + biomeWidth/2, width); + int endY = Math.min(biomeYStart + biomeHeight/2, height); if (biome.width == 1.0 && biome.height == 1.0) { beginX = 0; beginY = 0; @@ -358,21 +369,29 @@ private void clearTerrain(int x,int y,int size) { for(BiomeStructureData data:biome.structures) { + BiomeStructure structure; if(!structureDataMap.containsKey(data)) { - structureDataMap.put(data,new BiomeStructure(data,seed,biomeWidth,biomeHeight)); + structure=new BiomeStructure(data,seed,biomeWidth,biomeHeight); + structure.initialize(); + structureDataMap.put(data,structure); + currentTime=measureGenerationTime("wavefunctioncollapse "+data.sourcePath,currentTime); } - structure=structureDataMap.get(data); - int structureXStart= structure.x()+beginX; - int structureYStart= structure.y()+beginY; - int structureIndex=structure.objectID(x-structureXStart,y-structureYStart); + else + { + structure=structureDataMap.get(data); + } + int structureXStart= x-(biomeXStart - biomeWidth / 2)-(int) ((data.x*biomeWidth)-(data.width*biomeWidth/2)); + int structureYStart= y-(biomeYStart - biomeHeight / 2)- (int) ((data.y*biomeHeight)-(data.height*biomeHeight/2)); + + int structureIndex=structure.objectID(structureXStart,structureYStart); if(structureIndex>=0) { pix.setColor(data.mappingInfo[structureIndex].getColor()); pix.drawPixel(x, y); terrainMap[x][y]=terrainCounter+structureIndex; - if(structure.collision(x-structureXStart,y-structureYStart)) + if(structure.collision(structureXStart,structureYStart)) terrainMap[x][y]|=collisionBit; terrainMap[x][y]|=isStructureBit; @@ -485,6 +504,7 @@ private void clearTerrain(int x,int y,int size) } } + currentTime=measureGenerationTime("poi placement",currentTime); //sort towns List> allSortedTowns = new ArrayList<>(); @@ -624,6 +644,7 @@ private void clearTerrain(int x,int y,int size) } } } + currentTime=measureGenerationTime("roads",currentTime); mapObjectIds = new SpritesDataMap(getChunkSize(), data.tileSize, data.width / getChunkSize()); for (int x = 0; x < width; x++) { @@ -656,7 +677,7 @@ private void clearTerrain(int x,int y,int size) } } biomeImage = pix; - + measureGenerationTime("sprites",currentTime); WorldStage.getInstance().clearCache(); return this; } diff --git a/forge-gui-mobile/src/forge/animation/ForgeAnimation.java b/forge-gui-mobile/src/forge/animation/ForgeAnimation.java index 4ce7ceb42d3..7c7566f7323 100644 --- a/forge-gui-mobile/src/forge/animation/ForgeAnimation.java +++ b/forge-gui-mobile/src/forge/animation/ForgeAnimation.java @@ -1,12 +1,11 @@ package forge.animation; +import com.badlogic.gdx.Gdx; +import forge.Forge; + import java.util.ArrayList; import java.util.List; -import com.badlogic.gdx.Gdx; - -import forge.Forge; - public abstract class ForgeAnimation { private static final List activeAnimations = new ArrayList<>(); // A guard against inspecting activeAnimations while it's in the process of being edited diff --git a/forge-gui-mobile/src/forge/animation/ForgeTransition.java b/forge-gui-mobile/src/forge/animation/ForgeTransition.java index 4e2fb125394..066b3bdd70a 100644 --- a/forge-gui-mobile/src/forge/animation/ForgeTransition.java +++ b/forge-gui-mobile/src/forge/animation/ForgeTransition.java @@ -1,15 +1,14 @@ package forge.animation; +import com.badlogic.gdx.math.Rectangle; +import forge.Graphics; +import forge.toolbox.FDisplayObject; +import forge.toolbox.FOverlay; + import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map; -import com.badlogic.gdx.math.Rectangle; - -import forge.Graphics; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FOverlay; - public class ForgeTransition extends ForgeAnimation { private static final FOverlay overlay = new FOverlay(null) { @Override protected void doLayout(final float width, final float height) { diff --git a/forge-gui-mobile/src/forge/animation/GifAnimation.java b/forge-gui-mobile/src/forge/animation/GifAnimation.java index 6cd7aa7cde5..bdc313a51a7 100644 --- a/forge-gui-mobile/src/forge/animation/GifAnimation.java +++ b/forge-gui-mobile/src/forge/animation/GifAnimation.java @@ -4,7 +4,6 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.g2d.Animation; import com.badlogic.gdx.graphics.g2d.Animation.PlayMode; import com.badlogic.gdx.graphics.g2d.TextureRegion; - import forge.Graphics; public class GifAnimation extends ForgeAnimation { diff --git a/forge-gui-mobile/src/forge/animation/GifDecoder.java b/forge-gui-mobile/src/forge/animation/GifDecoder.java index 506bda6bf6f..4af968cc208 100644 --- a/forge-gui-mobile/src/forge/animation/GifDecoder.java +++ b/forge-gui-mobile/src/forge/animation/GifDecoder.java @@ -5,9 +5,6 @@ package forge.animation; /* Released under Apache 2.0 */ /* https://code.google.com/p/animated-gifs-in-android/ */ -import java.io.InputStream; -import java.util.Vector; - import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Animation; @@ -15,6 +12,9 @@ import com.badlogic.gdx.graphics.g2d.Animation.PlayMode; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.Array; +import java.io.InputStream; +import java.util.Vector; + public class GifDecoder { /** * File read status: No errors. diff --git a/forge-gui-mobile/src/forge/assets/AssetsDownloader.java b/forge-gui-mobile/src/forge/assets/AssetsDownloader.java index 02ece668d82..0e5f29264e5 100644 --- a/forge-gui-mobile/src/forge/assets/AssetsDownloader.java +++ b/forge-gui-mobile/src/forge/assets/AssetsDownloader.java @@ -1,24 +1,22 @@ package forge.assets; -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.List; - -import forge.gui.GuiBase; -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.Application.ApplicationType; import com.badlogic.gdx.Gdx; import com.google.common.collect.ImmutableList; - import forge.Forge; import forge.gui.FThreads; +import forge.gui.GuiBase; import forge.gui.download.GuiDownloadZipService; import forge.gui.util.SOptionPane; import forge.localinstance.properties.ForgeConstants; import forge.screens.SplashScreen; import forge.util.FileUtil; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.List; public class AssetsDownloader { public static final boolean SHARE_DESKTOP_ASSETS = true; //change to false to test downloading separate assets for desktop version diff --git a/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java b/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java index c5b17a2e44a..5ec2993c392 100644 --- a/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java +++ b/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java @@ -23,7 +23,6 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData; import com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph; import com.badlogic.gdx.graphics.g2d.PixmapPacker.Page; import com.badlogic.gdx.utils.Array; - import forge.util.TextUtil; /** diff --git a/forge-gui-mobile/src/forge/assets/FBufferedImage.java b/forge-gui-mobile/src/forge/assets/FBufferedImage.java index eaebff0e25b..51bd937792c 100644 --- a/forge-gui-mobile/src/forge/assets/FBufferedImage.java +++ b/forge-gui-mobile/src/forge/assets/FBufferedImage.java @@ -7,7 +7,6 @@ import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.glutils.FrameBuffer; import com.badlogic.gdx.math.Matrix4; - import forge.Graphics; import forge.gui.FThreads; diff --git a/forge-gui-mobile/src/forge/assets/FDelayLoadImage.java b/forge-gui-mobile/src/forge/assets/FDelayLoadImage.java index 10a339f59ba..3559315df78 100644 --- a/forge-gui-mobile/src/forge/assets/FDelayLoadImage.java +++ b/forge-gui-mobile/src/forge/assets/FDelayLoadImage.java @@ -2,7 +2,6 @@ package forge.assets; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Texture; - import com.badlogic.gdx.graphics.g2d.TextureRegion; import forge.Graphics; diff --git a/forge-gui-mobile/src/forge/assets/FLanguage.java b/forge-gui-mobile/src/forge/assets/FLanguage.java index a10d7284174..e5d4c1bfa96 100644 --- a/forge-gui-mobile/src/forge/assets/FLanguage.java +++ b/forge-gui-mobile/src/forge/assets/FLanguage.java @@ -1,16 +1,15 @@ package forge.assets; -import java.util.ArrayList; -import java.util.List; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; - import forge.localinstance.properties.ForgeConstants; import forge.localinstance.properties.ForgePreferences; import forge.localinstance.properties.ForgePreferences.FPref; import forge.model.FModel; +import java.util.ArrayList; +import java.util.List; + public class FLanguage { public static void changeLanguage(final String languageName) { diff --git a/forge-gui-mobile/src/forge/assets/FRotatedImage.java b/forge-gui-mobile/src/forge/assets/FRotatedImage.java index 1022aaebd52..2e2c0bd32cf 100644 --- a/forge-gui-mobile/src/forge/assets/FRotatedImage.java +++ b/forge-gui-mobile/src/forge/assets/FRotatedImage.java @@ -1,7 +1,6 @@ package forge.assets; import com.badlogic.gdx.graphics.Texture; - import com.badlogic.gdx.graphics.g2d.TextureRegion; import forge.Graphics; diff --git a/forge-gui-mobile/src/forge/assets/FSkinColor.java b/forge-gui-mobile/src/forge/assets/FSkinColor.java index ae9d69328bc..3aa53bb1a97 100644 --- a/forge-gui-mobile/src/forge/assets/FSkinColor.java +++ b/forge-gui-mobile/src/forge/assets/FSkinColor.java @@ -1,12 +1,11 @@ package forge.assets; -import java.util.HashMap; - import com.badlogic.gdx.graphics.Color; - import forge.localinstance.skin.FSkinProp; import forge.screens.match.TargetingOverlay; +import java.util.HashMap; + public class FSkinColor { public enum Colors { CLR_THEME (FSkinProp.CLR_THEME), diff --git a/forge-gui-mobile/src/forge/assets/FSkinFont.java b/forge-gui-mobile/src/forge/assets/FSkinFont.java index b7fa468dd58..d91563c9744 100644 --- a/forge-gui-mobile/src/forge/assets/FSkinFont.java +++ b/forge-gui-mobile/src/forge/assets/FSkinFont.java @@ -1,10 +1,5 @@ package forge.assets; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Color; @@ -20,7 +15,6 @@ import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter; import com.badlogic.gdx.graphics.glutils.PixmapTextureData; import com.badlogic.gdx.utils.Array; - import com.badlogic.gdx.utils.IntSet; import forge.Forge; import forge.gui.FThreads; @@ -30,6 +24,11 @@ import forge.util.LineReader; import forge.util.TextBounds; import forge.util.Utils; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; + public class FSkinFont { private static final int MIN_FONT_SIZE = 8; private static int MAX_FONT_SIZE = 72; diff --git a/forge-gui-mobile/src/forge/assets/FSkinImage.java b/forge-gui-mobile/src/forge/assets/FSkinImage.java index 2e79623a888..d80df909565 100644 --- a/forge-gui-mobile/src/forge/assets/FSkinImage.java +++ b/forge-gui-mobile/src/forge/assets/FSkinImage.java @@ -6,7 +6,6 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; - import forge.Forge; import forge.Graphics; import forge.localinstance.properties.ForgeConstants; diff --git a/forge-gui-mobile/src/forge/assets/FSkinTexture.java b/forge-gui-mobile/src/forge/assets/FSkinTexture.java index be4da23b628..671cd57d1d1 100644 --- a/forge-gui-mobile/src/forge/assets/FSkinTexture.java +++ b/forge-gui-mobile/src/forge/assets/FSkinTexture.java @@ -1,17 +1,16 @@ package forge.assets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture.TextureWrap; - import forge.Forge; import forge.Graphics; import forge.localinstance.properties.ForgeConstants; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + public enum FSkinTexture implements FImage { BG_TEXTURE(ForgeConstants.TEXTURE_BG_FILE, true, false), BG_MATCH(ForgeConstants.MATCH_BG_FILE, false, false), diff --git a/forge-gui-mobile/src/forge/assets/FTextureImage.java b/forge-gui-mobile/src/forge/assets/FTextureImage.java index 292d97c083e..bca8d94fb85 100644 --- a/forge-gui-mobile/src/forge/assets/FTextureImage.java +++ b/forge-gui-mobile/src/forge/assets/FTextureImage.java @@ -1,7 +1,6 @@ package forge.assets; import com.badlogic.gdx.graphics.Texture; - import com.badlogic.gdx.graphics.g2d.TextureRegion; import forge.Graphics; diff --git a/forge-gui-mobile/src/forge/assets/FTextureRegionImage.java b/forge-gui-mobile/src/forge/assets/FTextureRegionImage.java index dcd6c914b1b..0966fb76f97 100644 --- a/forge-gui-mobile/src/forge/assets/FTextureRegionImage.java +++ b/forge-gui-mobile/src/forge/assets/FTextureRegionImage.java @@ -2,7 +2,6 @@ package forge.assets; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; - import forge.Graphics; public class FTextureRegionImage extends FImageComplex { diff --git a/forge-gui-mobile/src/forge/assets/ImageCache.java b/forge-gui-mobile/src/forge/assets/ImageCache.java index 3af05833443..2c6e61060a7 100644 --- a/forge-gui-mobile/src/forge/assets/ImageCache.java +++ b/forge-gui-mobile/src/forge/assets/ImageCache.java @@ -17,48 +17,41 @@ */ package forge.assets; -import java.io.File; -import java.util.ConcurrentModificationException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Queue; -import java.util.Set; - +import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Pixmap.Format; +import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.TextureData; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.glutils.PixmapTextureData; import com.google.common.collect.EvictingQueue; import com.google.common.collect.Queues; import com.google.common.collect.Sets; -import forge.deck.DeckProxy; -import forge.gui.FThreads; -import forge.gui.GuiBase; -import forge.util.FileUtil; -import forge.util.TextUtil; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.Pair; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.Pixmap.Format; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.TextureRegion; - import forge.Forge; import forge.ImageKeys; import forge.card.CardEdition; import forge.card.CardRenderer; import forge.deck.Deck; +import forge.deck.DeckProxy; import forge.game.card.CardView; import forge.game.player.IHasIcon; +import forge.gui.FThreads; +import forge.gui.GuiBase; import forge.item.InventoryItem; import forge.item.PaperCard; import forge.localinstance.properties.ForgeConstants; import forge.localinstance.properties.ForgePreferences; import forge.model.FModel; +import forge.util.FileUtil; import forge.util.ImageUtil; +import forge.util.TextUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; + +import java.io.File; +import java.util.*; /** * This class stores ALL card images in a cache with soft values. this means diff --git a/forge-gui-mobile/src/forge/assets/TextRenderer.java b/forge-gui-mobile/src/forge/assets/TextRenderer.java index 9f6c4ee4fcd..d977d6a94b0 100644 --- a/forge-gui-mobile/src/forge/assets/TextRenderer.java +++ b/forge-gui-mobile/src/forge/assets/TextRenderer.java @@ -1,13 +1,7 @@ package forge.assets; -import java.text.BreakIterator; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.card.CardFaceSymbols; @@ -16,6 +10,11 @@ import forge.localinstance.properties.ForgePreferences.FPref; import forge.model.FModel; import forge.util.TextBounds; +import java.text.BreakIterator; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + //Encodes text for drawing with symbols and reminder text public class TextRenderer { static { diff --git a/forge-gui-mobile/src/forge/card/CardFaceSymbols.java b/forge-gui-mobile/src/forge/card/CardFaceSymbols.java index cb8cc135829..6c5cf738b89 100644 --- a/forge-gui-mobile/src/forge/card/CardFaceSymbols.java +++ b/forge-gui-mobile/src/forge/card/CardFaceSymbols.java @@ -17,8 +17,6 @@ */ package forge.card; -import java.util.StringTokenizer; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinImage; @@ -26,6 +24,8 @@ import forge.card.mana.ManaCost; import forge.card.mana.ManaCostShard; import forge.gui.error.BugReporter; +import java.util.StringTokenizer; + public class CardFaceSymbols { public static final float FONT_SIZE_FACTOR = 0.85f; diff --git a/forge-gui-mobile/src/forge/card/CardImage.java b/forge-gui-mobile/src/forge/card/CardImage.java index d542a7509bd..6e7da4f9784 100644 --- a/forge-gui-mobile/src/forge/card/CardImage.java +++ b/forge-gui-mobile/src/forge/card/CardImage.java @@ -1,7 +1,6 @@ package forge.card; import com.badlogic.gdx.graphics.Texture; - import forge.Forge; import forge.Graphics; import forge.assets.FImage; diff --git a/forge-gui-mobile/src/forge/card/CardImageRenderer.java b/forge-gui-mobile/src/forge/card/CardImageRenderer.java index 1a001553b64..e92e7624cc6 100644 --- a/forge-gui-mobile/src/forge/card/CardImageRenderer.java +++ b/forge-gui-mobile/src/forge/card/CardImageRenderer.java @@ -1,24 +1,13 @@ package forge.card; -import static forge.card.CardRenderer.CROP_MULTIPLIER; -import static forge.card.CardRenderer.isModernFrame; - -import java.util.ArrayList; -import java.util.List; - -import forge.ImageKeys; -import forge.assets.*; -import forge.item.PaperCard; -import forge.util.ImageUtil; -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.utils.Align; import com.google.common.collect.ImmutableList; - import forge.Forge; import forge.Graphics; +import forge.ImageKeys; +import forge.assets.*; import forge.card.CardRenderer.CardStackPosition; import forge.card.mana.ManaCost; import forge.game.GameView; @@ -27,13 +16,22 @@ import forge.game.card.CardView.CardStateView; import forge.game.zone.ZoneType; import forge.gui.card.CardDetailUtil; import forge.gui.card.CardDetailUtil.DetailColors; +import forge.item.PaperCard; import forge.localinstance.properties.ForgeConstants; import forge.localinstance.properties.ForgePreferences; import forge.model.FModel; import forge.screens.FScreen; import forge.screens.match.MatchController; import forge.util.CardTranslation; +import forge.util.ImageUtil; import forge.util.Utils; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +import static forge.card.CardRenderer.CROP_MULTIPLIER; +import static forge.card.CardRenderer.isModernFrame; public class CardImageRenderer { private static final float BASE_IMAGE_WIDTH = 360; diff --git a/forge-gui-mobile/src/forge/card/CardListPreview.java b/forge-gui-mobile/src/forge/card/CardListPreview.java index cd6411f8c72..4a321eb48c0 100644 --- a/forge-gui-mobile/src/forge/card/CardListPreview.java +++ b/forge-gui-mobile/src/forge/card/CardListPreview.java @@ -2,7 +2,6 @@ package forge.card; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; - import forge.item.PaperCard; import forge.toolbox.FChoiceList; import forge.toolbox.FLabel; diff --git a/forge-gui-mobile/src/forge/card/CardRenderer.java b/forge-gui-mobile/src/forge/card/CardRenderer.java index bb1ab421dad..a7713347fae 100644 --- a/forge-gui-mobile/src/forge/card/CardRenderer.java +++ b/forge-gui-mobile/src/forge/card/CardRenderer.java @@ -1,17 +1,5 @@ package forge.card; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import forge.ImageKeys; -import forge.localinstance.properties.ForgeConstants; -import forge.util.*; -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Color; @@ -27,19 +15,11 @@ import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFont import com.badlogic.gdx.graphics.glutils.PixmapTextureData; import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Array; - import forge.CachedCardImage; import forge.Forge; import forge.Graphics; -import forge.assets.FImage; -import forge.assets.FImageComplex; -import forge.assets.FRotatedImage; -import forge.assets.FSkin; -import forge.assets.FSkinColor; -import forge.assets.FSkinFont; -import forge.assets.FSkinImage; -import forge.assets.FTextureRegionImage; -import forge.assets.ImageCache; +import forge.ImageKeys; +import forge.assets.*; import forge.card.CardZoom.ActivateHandler; import forge.card.mana.ManaCost; import forge.game.card.CardView; @@ -51,12 +31,20 @@ import forge.gui.card.CardDetailUtil; import forge.gui.card.CardDetailUtil.DetailColors; import forge.item.IPaperCard; import forge.item.InventoryItem; +import forge.localinstance.properties.ForgeConstants; import forge.localinstance.properties.ForgeConstants.CounterDisplayType; import forge.localinstance.properties.ForgePreferences; import forge.localinstance.properties.ForgePreferences.FPref; import forge.model.FModel; import forge.screens.match.MatchController; import forge.toolbox.FList; +import forge.util.CardTranslation; +import forge.util.FileUtil; +import forge.util.TextBounds; +import forge.util.Utils; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; public class CardRenderer { public enum CardStackPosition { diff --git a/forge-gui-mobile/src/forge/card/CardZoom.java b/forge-gui-mobile/src/forge/card/CardZoom.java index 2100a310b9b..461c9e049f1 100644 --- a/forge-gui-mobile/src/forge/card/CardZoom.java +++ b/forge-gui-mobile/src/forge/card/CardZoom.java @@ -1,13 +1,8 @@ package forge.card; -import java.util.ArrayList; -import java.util.List; -import java.util.Map.Entry; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinImage; @@ -30,6 +25,10 @@ import forge.toolbox.FOverlay; import forge.util.Utils; import forge.util.collect.FCollectionView; +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + public class CardZoom extends FOverlay { private static final float REQ_AMOUNT = Utils.AVG_FINGER_WIDTH; diff --git a/forge-gui-mobile/src/forge/card/GameEntityPicker.java b/forge-gui-mobile/src/forge/card/GameEntityPicker.java index 22aa5cb889f..ccb1b2d8254 100644 --- a/forge-gui-mobile/src/forge/card/GameEntityPicker.java +++ b/forge-gui-mobile/src/forge/card/GameEntityPicker.java @@ -1,11 +1,6 @@ package forge.card; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - import com.google.common.collect.ImmutableList; - import forge.Forge; import forge.Graphics; import forge.assets.FImage; @@ -22,6 +17,10 @@ import forge.toolbox.FOptionPane; import forge.toolbox.FTextField; import forge.util.Callback; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + public class GameEntityPicker extends TabPageScreen { private final FOptionPane optionPane; diff --git a/forge-gui-mobile/src/forge/deck/AddBasicLandsDialog.java b/forge-gui-mobile/src/forge/deck/AddBasicLandsDialog.java index 31819c20052..01fda9ec328 100644 --- a/forge-gui-mobile/src/forge/deck/AddBasicLandsDialog.java +++ b/forge-gui-mobile/src/forge/deck/AddBasicLandsDialog.java @@ -17,13 +17,8 @@ */ package forge.deck; -import java.text.NumberFormat; -import java.util.Map; -import java.util.Map.Entry; - import com.badlogic.gdx.utils.Align; import com.google.common.collect.Iterables; - import forge.Forge; import forge.Graphics; import forge.StaticData; @@ -37,21 +32,16 @@ import forge.card.CardZoom; import forge.card.mana.ManaCostShard; import forge.item.PaperCard; import forge.model.FModel; -import forge.toolbox.FCardPanel; -import forge.toolbox.FComboBox; -import forge.toolbox.FContainer; -import forge.toolbox.FDialog; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FOptionPane; -import forge.toolbox.FScrollPane; -import forge.toolbox.FTextArea; import forge.util.Callback; import forge.util.MyRandom; import forge.util.Utils; +import java.text.NumberFormat; +import java.util.Map; +import java.util.Map.Entry; + public class AddBasicLandsDialog extends FDialog { private static final float ADD_BTN_SIZE = Utils.AVG_FINGER_HEIGHT * 0.75f; diff --git a/forge-gui-mobile/src/forge/deck/FDeckChooser.java b/forge-gui-mobile/src/forge/deck/FDeckChooser.java index dea7c235863..32db7788bb7 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckChooser.java +++ b/forge-gui-mobile/src/forge/deck/FDeckChooser.java @@ -1,20 +1,7 @@ package forge.deck; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import forge.util.MyRandom; -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.utils.Align; import com.google.common.collect.ImmutableList; - import forge.Forge; import forge.assets.ImageCache; import forge.deck.FDeckEditor.EditorType; @@ -43,17 +30,16 @@ import forge.screens.FScreen; import forge.screens.LoadingOverlay; import forge.screens.home.NewGameMenu.NewGameScreen; import forge.screens.match.MatchController; -import forge.toolbox.FButton; -import forge.toolbox.FComboBox; -import forge.toolbox.FContainer; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FOptionPane; -import forge.toolbox.GuiChoose; -import forge.toolbox.ListChooser; import forge.util.Callback; +import forge.util.MyRandom; import forge.util.Utils; import forge.util.storage.IStorage; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; +import java.util.stream.Collectors; public class FDeckChooser extends FScreen { public static final float PADDING = Utils.scale(5); diff --git a/forge-gui-mobile/src/forge/deck/FDeckEditor.java b/forge-gui-mobile/src/forge/deck/FDeckEditor.java index d55d25ca4e6..72cd70e2fad 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckEditor.java +++ b/forge-gui-mobile/src/forge/deck/FDeckEditor.java @@ -35,7 +35,10 @@ import forge.screens.TabPageScreen; import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FEvent.FEventType; -import forge.util.*; +import forge.util.Callback; +import forge.util.ItemPool; +import forge.util.Lang; +import forge.util.Utils; import forge.util.storage.IStorage; import org.apache.commons.lang3.StringUtils; diff --git a/forge-gui-mobile/src/forge/deck/FDeckImportDialog.java b/forge-gui-mobile/src/forge/deck/FDeckImportDialog.java index 144bf237709..1d64b8f52f9 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckImportDialog.java +++ b/forge-gui-mobile/src/forge/deck/FDeckImportDialog.java @@ -17,11 +17,7 @@ */ package forge.deck; -import java.util.ArrayList; -import java.util.List; - import com.google.common.collect.ImmutableList; - import forge.Forge; import forge.Graphics; import forge.StaticData; @@ -29,15 +25,13 @@ import forge.deck.DeckRecognizer.TokenType; import forge.game.GameType; import forge.gui.FThreads; import forge.gui.util.SOptionPane; -import forge.toolbox.FCheckBox; -import forge.toolbox.FComboBox; -import forge.toolbox.FDialog; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FOptionPane; -import forge.toolbox.FTextArea; import forge.util.Callback; +import java.util.ArrayList; +import java.util.List; + public class FDeckImportDialog extends FDialog { private Callback callback; diff --git a/forge-gui-mobile/src/forge/deck/FDeckViewer.java b/forge-gui-mobile/src/forge/deck/FDeckViewer.java index 16b359a8766..26cb4149586 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckViewer.java +++ b/forge-gui-mobile/src/forge/deck/FDeckViewer.java @@ -1,13 +1,7 @@ package forge.deck; -import java.util.Map.Entry; - import forge.Forge; -import forge.assets.FImage; -import forge.assets.FSkin; -import forge.assets.FSkinImage; -import forge.assets.FTextureRegionImage; -import forge.assets.ImageCache; +import forge.assets.*; import forge.item.PaperCard; import forge.itemmanager.CardManager; import forge.itemmanager.ItemManagerConfig; @@ -20,6 +14,8 @@ import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FOptionPane; +import java.util.Map.Entry; + public class FDeckViewer extends FScreen { private static FDeckViewer deckViewer; private static FPopupMenu menu = new FPopupMenu() { diff --git a/forge-gui-mobile/src/forge/deck/FSideboardDialog.java b/forge-gui-mobile/src/forge/deck/FSideboardDialog.java index 3255d779db8..72b8ecc84bc 100644 --- a/forge-gui-mobile/src/forge/deck/FSideboardDialog.java +++ b/forge-gui-mobile/src/forge/deck/FSideboardDialog.java @@ -1,10 +1,6 @@ package forge.deck; -import java.util.List; - import forge.Forge; -import org.apache.commons.lang3.StringUtils; - import forge.assets.FImage; import forge.item.PaperCard; import forge.itemmanager.CardManager; @@ -19,6 +15,9 @@ import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.GuiChoose; import forge.util.Callback; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; public class FSideboardDialog extends FDialog { private final SideboardTabs tabs; diff --git a/forge-gui-mobile/src/forge/error/BugReportDialog.java b/forge-gui-mobile/src/forge/error/BugReportDialog.java index eaf6ff02a75..0eeae737acd 100644 --- a/forge-gui-mobile/src/forge/error/BugReportDialog.java +++ b/forge-gui-mobile/src/forge/error/BugReportDialog.java @@ -1,7 +1,6 @@ package forge.error; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; diff --git a/forge-gui-mobile/src/forge/itemmanager/CardManager.java b/forge-gui-mobile/src/forge/itemmanager/CardManager.java index 6f194a42afc..e3780528656 100644 --- a/forge-gui-mobile/src/forge/itemmanager/CardManager.java +++ b/forge-gui-mobile/src/forge/itemmanager/CardManager.java @@ -1,22 +1,17 @@ package forge.itemmanager; -import java.util.Map.Entry; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinFont; import forge.card.CardRenderer; import forge.card.CardZoom; import forge.item.PaperCard; -import forge.itemmanager.filters.AdvancedSearchFilter; -import forge.itemmanager.filters.CardColorFilter; -import forge.itemmanager.filters.CardFormatFilter; -import forge.itemmanager.filters.CardSearchFilter; -import forge.itemmanager.filters.CardTypeFilter; -import forge.itemmanager.filters.TextSearchFilter; +import forge.itemmanager.filters.*; import forge.toolbox.FList; import forge.toolbox.FList.CompactModeHandler; +import java.util.Map.Entry; + /** * ItemManager for cards */ diff --git a/forge-gui-mobile/src/forge/itemmanager/DeckManager.java b/forge-gui-mobile/src/forge/itemmanager/DeckManager.java index b7caa658876..8a78e60f927 100644 --- a/forge-gui-mobile/src/forge/itemmanager/DeckManager.java +++ b/forge-gui-mobile/src/forge/itemmanager/DeckManager.java @@ -1,9 +1,6 @@ package forge.itemmanager; -import java.util.Map.Entry; - import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -25,6 +22,8 @@ import forge.toolbox.FList; import forge.toolbox.FList.CompactModeHandler; import forge.util.Utils; +import java.util.Map.Entry; + /** * ItemManager for decks */ diff --git a/forge-gui-mobile/src/forge/itemmanager/ItemManager.java b/forge-gui-mobile/src/forge/itemmanager/ItemManager.java index c026f10d756..209b60e8272 100644 --- a/forge-gui-mobile/src/forge/itemmanager/ItemManager.java +++ b/forge-gui-mobile/src/forge/itemmanager/ItemManager.java @@ -17,16 +17,6 @@ */ package forge.itemmanager; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Align; @@ -34,7 +24,6 @@ import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -53,17 +42,16 @@ import forge.menu.FDropDownMenu; import forge.menu.FMenuItem; import forge.menu.FPopupMenu; import forge.screens.FScreen; -import forge.toolbox.FComboBox; -import forge.toolbox.FContainer; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FEvent.FEventType; -import forge.toolbox.FLabel; -import forge.toolbox.FList; import forge.toolbox.FList.CompactModeHandler; import forge.util.ItemPool; import forge.util.LayoutHelper; +import java.util.*; +import java.util.Map.Entry; + public abstract class ItemManager extends FContainer implements IItemManager, ActivateHandler { private ItemPool pool; diff --git a/forge-gui-mobile/src/forge/itemmanager/SpellShopManager.java b/forge-gui-mobile/src/forge/itemmanager/SpellShopManager.java index 6202cff5591..05b58ea7dcf 100644 --- a/forge-gui-mobile/src/forge/itemmanager/SpellShopManager.java +++ b/forge-gui-mobile/src/forge/itemmanager/SpellShopManager.java @@ -1,11 +1,8 @@ package forge.itemmanager; -import java.util.Map.Entry; - import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.utils.Align; import com.google.common.base.Function; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -21,6 +18,8 @@ import forge.itemmanager.filters.TextSearchFilter; import forge.toolbox.FList; import forge.toolbox.FList.CompactModeHandler; +import java.util.Map.Entry; + public class SpellShopManager extends ItemManager { private final Function, Object> fnGetPrice; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/AdvancedSearchFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/AdvancedSearchFilter.java index e4870f49300..8600df15191 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/AdvancedSearchFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/AdvancedSearchFilter.java @@ -3,7 +3,6 @@ package forge.itemmanager.filters; import com.badlogic.gdx.utils.Align; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; - import forge.Forge; import forge.assets.FSkinImage; import forge.assets.TextRenderer; @@ -16,14 +15,8 @@ import forge.menu.FMenuItem; import forge.menu.FPopupMenu; import forge.menu.FTooltip; import forge.screens.FScreen; -import forge.toolbox.FContainer; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FList; -import forge.toolbox.FScrollPane; -import forge.toolbox.FTextField; import forge.util.Callback; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/ArchivedFormatSelect.java b/forge-gui-mobile/src/forge/itemmanager/filters/ArchivedFormatSelect.java index cb3d1d6ec26..54d58870b79 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/ArchivedFormatSelect.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/ArchivedFormatSelect.java @@ -1,11 +1,6 @@ package forge.itemmanager.filters; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -19,6 +14,10 @@ import forge.toolbox.FList; import forge.util.Callback; import forge.util.Utils; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + /** * Created by maustin on 16/04/2018. */ diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/CardCMCFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/CardCMCFilter.java index 2166262d712..0adafdb50ce 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/CardCMCFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/CardCMCFilter.java @@ -2,7 +2,6 @@ package forge.itemmanager.filters; import com.google.common.base.Predicate; import com.google.common.base.Predicates; - import forge.card.CardRules; import forge.card.CardRulesPredicates; import forge.item.PaperCard; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/CardColorFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/CardColorFilter.java index b3bc12c091b..0ec55488ee8 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/CardColorFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/CardColorFilter.java @@ -1,7 +1,6 @@ package forge.itemmanager.filters; import com.google.common.base.Predicate; - import forge.item.PaperCard; import forge.itemmanager.ItemManager; import forge.itemmanager.SFilterUtil; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/CardColorlessCostFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/CardColorlessCostFilter.java index 3cb0670784a..21c51b53f73 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/CardColorlessCostFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/CardColorlessCostFilter.java @@ -2,7 +2,6 @@ package forge.itemmanager.filters; import com.google.common.base.Predicate; import com.google.common.base.Predicates; - import forge.card.CardRules; import forge.card.CardRulesPredicates; import forge.item.PaperCard; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/CardFormatFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/CardFormatFilter.java index 3d8942d2f77..36c80aa64d6 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/CardFormatFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/CardFormatFilter.java @@ -2,7 +2,6 @@ package forge.itemmanager.filters; import com.google.common.base.Predicate; import com.google.common.base.Predicates; - import forge.item.PaperCard; import forge.itemmanager.ItemManager; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/CardPowerFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/CardPowerFilter.java index 57d3dba01a0..19dd6c9d2ec 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/CardPowerFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/CardPowerFilter.java @@ -2,7 +2,6 @@ package forge.itemmanager.filters; import com.google.common.base.Predicate; import com.google.common.base.Predicates; - import forge.card.CardRules; import forge.card.CardRulesPredicates; import forge.item.PaperCard; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/CardRarityFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/CardRarityFilter.java index 902bf59389c..47c494b6bfb 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/CardRarityFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/CardRarityFilter.java @@ -1,7 +1,6 @@ package forge.itemmanager.filters; import com.google.common.base.Predicate; - import forge.card.CardRarity; import forge.item.PaperCard; import forge.itemmanager.ItemManager; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/CardSearchFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/CardSearchFilter.java index 35fa8ec8633..c0c22addfb8 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/CardSearchFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/CardSearchFilter.java @@ -1,7 +1,6 @@ package forge.itemmanager.filters; import com.google.common.base.Predicate; - import forge.item.InventoryItem; import forge.item.PaperCard; import forge.itemmanager.ItemManager; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/CardToughnessFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/CardToughnessFilter.java index 940e67e7a27..3acb2f19312 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/CardToughnessFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/CardToughnessFilter.java @@ -2,7 +2,6 @@ package forge.itemmanager.filters; import com.google.common.base.Predicate; import com.google.common.base.Predicates; - import forge.card.CardRules; import forge.card.CardRulesPredicates; import forge.item.PaperCard; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/CardTypeFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/CardTypeFilter.java index 167beaaeb2a..249ac6cbe3e 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/CardTypeFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/CardTypeFilter.java @@ -1,16 +1,15 @@ package forge.itemmanager.filters; -import java.util.ArrayList; -import java.util.List; - import com.google.common.base.Predicate; import com.google.common.base.Predicates; - import forge.card.CardRules; import forge.item.PaperCard; import forge.itemmanager.ItemManager; import forge.itemmanager.SItemManagerUtil.StatTypes; +import java.util.ArrayList; +import java.util.List; + public class CardTypeFilter extends StatTypeFilter { public CardTypeFilter(ItemManager itemManager0) { diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/DeckColorFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/DeckColorFilter.java index 52cc7b4b593..885f4b13bc2 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/DeckColorFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/DeckColorFilter.java @@ -1,7 +1,6 @@ package forge.itemmanager.filters; import com.google.common.base.Predicate; - import forge.deck.DeckProxy; import forge.itemmanager.ItemManager; import forge.itemmanager.SFilterUtil; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/DeckFolderFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/DeckFolderFilter.java index 1a24bfb9aae..79e2cb0d81e 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/DeckFolderFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/DeckFolderFilter.java @@ -1,13 +1,12 @@ package forge.itemmanager.filters; +import com.google.common.base.Predicate; +import forge.deck.DeckProxy; +import forge.itemmanager.ItemManager; + import java.util.HashSet; import java.util.Set; -import com.google.common.base.Predicate; - -import forge.deck.DeckProxy; -import forge.itemmanager.ItemManager; - public class DeckFolderFilter extends ListLabelFilter { protected final Set folders = new HashSet<>(); diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/DeckFormatFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/DeckFormatFilter.java index 1a3a51dd06e..0ca3dc64f61 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/DeckFormatFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/DeckFormatFilter.java @@ -2,7 +2,6 @@ package forge.itemmanager.filters; import com.google.common.base.Predicate; import com.google.common.base.Predicates; - import forge.deck.DeckProxy; import forge.itemmanager.ItemManager; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/FormatFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/FormatFilter.java index 0db437ac335..54dd6c08e87 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/FormatFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/FormatFilter.java @@ -1,13 +1,6 @@ package forge.itemmanager.filters; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -19,17 +12,14 @@ import forge.itemmanager.ItemManager; import forge.model.FModel; import forge.screens.FScreen; import forge.screens.settings.SettingsScreen; -import forge.toolbox.FCheckBox; -import forge.toolbox.FComboBox; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FGroupList; -import forge.toolbox.FList; import forge.util.Callback; import forge.util.TextUtil; import forge.util.Utils; +import java.util.*; + public abstract class FormatFilter extends ItemFilter { protected GameFormat format; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/ItemFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/ItemFilter.java index 8eaaad46868..401b48825c2 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/ItemFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/ItemFilter.java @@ -1,7 +1,6 @@ package forge.itemmanager.filters; import com.google.common.base.Predicate; - import forge.assets.FSkinFont; import forge.item.InventoryItem; import forge.itemmanager.ItemManager; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/ListLabelFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/ListLabelFilter.java index 04c179a4789..7398e095dc7 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/ListLabelFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/ListLabelFilter.java @@ -1,7 +1,6 @@ package forge.itemmanager.filters; import com.badlogic.gdx.utils.Align; - import forge.assets.FSkinFont; import forge.item.InventoryItem; import forge.itemmanager.ItemManager; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/StatTypeFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/StatTypeFilter.java index 70045e02123..7fecb5cb863 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/StatTypeFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/StatTypeFilter.java @@ -1,8 +1,5 @@ package forge.itemmanager.filters; -import java.util.HashMap; -import java.util.Map; - import forge.assets.FSkin; import forge.item.InventoryItem; import forge.item.ItemPredicate; @@ -14,6 +11,9 @@ import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FLabel; +import java.util.HashMap; +import java.util.Map; + public abstract class StatTypeFilter extends ToggleButtonsFilter { protected final Map buttonMap; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/TextSearchFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/TextSearchFilter.java index b3a0c9906f3..2ac7005cfc1 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/TextSearchFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/TextSearchFilter.java @@ -3,7 +3,6 @@ package forge.itemmanager.filters; import com.badlogic.gdx.utils.Align; import com.google.common.base.Predicate; import com.google.common.base.Predicates; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinFont; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/ToggleButtonsFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/ToggleButtonsFilter.java index 61f986c9c38..c666f2f18f9 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/ToggleButtonsFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/ToggleButtonsFilter.java @@ -1,10 +1,6 @@ package forge.itemmanager.filters; -import java.util.ArrayList; -import java.util.List; - import com.badlogic.gdx.utils.Align; - import forge.assets.FImage; import forge.item.InventoryItem; import forge.itemmanager.ItemManager; @@ -13,6 +9,9 @@ import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FEvent.FEventType; import forge.toolbox.FLabel; +import java.util.ArrayList; +import java.util.List; + public abstract class ToggleButtonsFilter extends ItemFilter { protected boolean lockFiltering; diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/ValueRangeFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/ValueRangeFilter.java index 588ab1809b6..47cddb538c1 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/ValueRangeFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/ValueRangeFilter.java @@ -2,7 +2,6 @@ package forge.itemmanager.filters; import com.badlogic.gdx.utils.Align; import com.google.common.base.Predicate; - import forge.card.CardRules; import forge.card.CardRulesPredicates; import forge.item.InventoryItem; diff --git a/forge-gui-mobile/src/forge/itemmanager/views/ItemListView.java b/forge-gui-mobile/src/forge/itemmanager/views/ItemListView.java index 2c8881865be..7559c1428cb 100644 --- a/forge-gui-mobile/src/forge/itemmanager/views/ItemListView.java +++ b/forge-gui-mobile/src/forge/itemmanager/views/ItemListView.java @@ -17,14 +17,7 @@ */ package forge.itemmanager.views; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - import com.badlogic.gdx.math.Rectangle; - import forge.Forge; import forge.Graphics; import forge.assets.FImage; @@ -33,15 +26,17 @@ import forge.assets.FSkinColor.Colors; import forge.assets.FSkinFont; import forge.assets.FSkinImage; import forge.item.InventoryItem; -import forge.itemmanager.ColumnDef; -import forge.itemmanager.ItemColumn; -import forge.itemmanager.ItemManager; -import forge.itemmanager.ItemManagerConfig; -import forge.itemmanager.ItemManagerModel; +import forge.itemmanager.*; import forge.toolbox.FCheckBox; import forge.toolbox.FDisplayObject; import forge.toolbox.FList; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + public final class ItemListView extends ItemView { private static final FSkinColor ROW_COLOR = FSkinColor.get(Colors.CLR_ZEBRA); diff --git a/forge-gui-mobile/src/forge/itemmanager/views/ItemView.java b/forge-gui-mobile/src/forge/itemmanager/views/ItemView.java index 3a33ae11a2d..64a73071532 100644 --- a/forge-gui-mobile/src/forge/itemmanager/views/ItemView.java +++ b/forge-gui-mobile/src/forge/itemmanager/views/ItemView.java @@ -1,27 +1,22 @@ package forge.itemmanager.views; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - import com.badlogic.gdx.math.Rectangle; - import forge.Graphics; import forge.assets.FImage; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; import forge.item.InventoryItem; -import forge.itemmanager.ColumnDef; -import forge.itemmanager.ItemColumn; -import forge.itemmanager.ItemManager; -import forge.itemmanager.ItemManagerConfig; -import forge.itemmanager.ItemManagerModel; +import forge.itemmanager.*; import forge.toolbox.FContainer; import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventType; import forge.toolbox.FScrollPane; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + public abstract class ItemView { protected static final float UNOWNED_ALPHA_COMPOSITE = 0.35f; private static final FSkinColor BORDER_COLOR = FSkinColor.get(Colors.CLR_TEXT); diff --git a/forge-gui-mobile/src/forge/menu/FDropDown.java b/forge-gui-mobile/src/forge/menu/FDropDown.java index 84ccde8799d..df23b86498a 100644 --- a/forge-gui-mobile/src/forge/menu/FDropDown.java +++ b/forge-gui-mobile/src/forge/menu/FDropDown.java @@ -1,7 +1,6 @@ package forge.menu; import com.badlogic.gdx.math.Rectangle; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; diff --git a/forge-gui-mobile/src/forge/menu/FMagnifyView.java b/forge-gui-mobile/src/forge/menu/FMagnifyView.java index 495e094ad3b..6c33345e13f 100644 --- a/forge-gui-mobile/src/forge/menu/FMagnifyView.java +++ b/forge-gui-mobile/src/forge/menu/FMagnifyView.java @@ -1,7 +1,6 @@ package forge.menu; import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinFont; diff --git a/forge-gui-mobile/src/forge/menu/FMenuBar.java b/forge-gui-mobile/src/forge/menu/FMenuBar.java index 58096d0293e..324c5ff79f0 100644 --- a/forge-gui-mobile/src/forge/menu/FMenuBar.java +++ b/forge-gui-mobile/src/forge/menu/FMenuBar.java @@ -1,11 +1,11 @@ package forge.menu; -import java.util.ArrayList; -import java.util.List; - import forge.Graphics; import forge.screens.FScreen.Header; +import java.util.ArrayList; +import java.util.List; + public class FMenuBar extends Header { private final List tabs = new ArrayList<>(); diff --git a/forge-gui-mobile/src/forge/menu/FMenuItem.java b/forge-gui-mobile/src/forge/menu/FMenuItem.java index 1b8e7a00fbf..0c56962adf0 100644 --- a/forge-gui-mobile/src/forge/menu/FMenuItem.java +++ b/forge-gui-mobile/src/forge/menu/FMenuItem.java @@ -3,7 +3,6 @@ package forge.menu; import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Timer; import com.badlogic.gdx.utils.Timer.Task; - import forge.Graphics; import forge.assets.FImage; import forge.assets.FSkinColor; diff --git a/forge-gui-mobile/src/forge/menu/FMenuTab.java b/forge-gui-mobile/src/forge/menu/FMenuTab.java index 34198ae06d4..405e7e34d1d 100644 --- a/forge-gui-mobile/src/forge/menu/FMenuTab.java +++ b/forge-gui-mobile/src/forge/menu/FMenuTab.java @@ -1,7 +1,6 @@ package forge.menu; import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; diff --git a/forge-gui-mobile/src/forge/menu/FPopupMenu.java b/forge-gui-mobile/src/forge/menu/FPopupMenu.java index 19d3e7751c5..a3cea1656d5 100644 --- a/forge-gui-mobile/src/forge/menu/FPopupMenu.java +++ b/forge-gui-mobile/src/forge/menu/FPopupMenu.java @@ -1,7 +1,6 @@ package forge.menu; import com.badlogic.gdx.math.Vector2; - import forge.Forge; import forge.Graphics; import forge.screens.FScreen; diff --git a/forge-gui-mobile/src/forge/menu/FTooltip.java b/forge-gui-mobile/src/forge/menu/FTooltip.java index 4686a03573f..e20dc607a70 100644 --- a/forge-gui-mobile/src/forge/menu/FTooltip.java +++ b/forge-gui-mobile/src/forge/menu/FTooltip.java @@ -1,7 +1,6 @@ package forge.menu; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; diff --git a/forge-gui-mobile/src/forge/screens/FScreen.java b/forge-gui-mobile/src/forge/screens/FScreen.java index ec36dc3884d..450c3553e77 100644 --- a/forge-gui-mobile/src/forge/screens/FScreen.java +++ b/forge-gui-mobile/src/forge/screens/FScreen.java @@ -1,11 +1,8 @@ package forge.screens; -import java.util.List; - import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FImage; @@ -25,6 +22,8 @@ import forge.toolbox.FLabel; import forge.util.Callback; import forge.util.Utils; +import java.util.List; + public abstract class FScreen extends FContainer { public static final FSkinColor TEXTURE_OVERLAY_COLOR = FSkinColor.get(Colors.CLR_THEME); diff --git a/forge-gui-mobile/src/forge/screens/LaunchScreen.java b/forge-gui-mobile/src/forge/screens/LaunchScreen.java index 5917c67972e..1f345dd4114 100644 --- a/forge-gui-mobile/src/forge/screens/LaunchScreen.java +++ b/forge-gui-mobile/src/forge/screens/LaunchScreen.java @@ -1,7 +1,6 @@ package forge.screens; import com.badlogic.gdx.Input.Keys; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinImage; diff --git a/forge-gui-mobile/src/forge/screens/LoadingOverlay.java b/forge-gui-mobile/src/forge/screens/LoadingOverlay.java index 2ccda45df86..ccad3622efc 100644 --- a/forge-gui-mobile/src/forge/screens/LoadingOverlay.java +++ b/forge-gui-mobile/src/forge/screens/LoadingOverlay.java @@ -2,7 +2,6 @@ package forge.screens; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkin; diff --git a/forge-gui-mobile/src/forge/screens/SplashScreen.java b/forge-gui-mobile/src/forge/screens/SplashScreen.java index 5b9ffcb8e2b..474cff437f9 100644 --- a/forge-gui-mobile/src/forge/screens/SplashScreen.java +++ b/forge-gui-mobile/src/forge/screens/SplashScreen.java @@ -3,7 +3,6 @@ package forge.screens; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.animation.ForgeAnimation; diff --git a/forge-gui-mobile/src/forge/screens/TabPageScreen.java b/forge-gui-mobile/src/forge/screens/TabPageScreen.java index 0c369d6ac42..3dbc86a1b6a 100644 --- a/forge-gui-mobile/src/forge/screens/TabPageScreen.java +++ b/forge-gui-mobile/src/forge/screens/TabPageScreen.java @@ -1,7 +1,6 @@ package forge.screens; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FImage; @@ -11,12 +10,8 @@ import forge.assets.FSkinFont; import forge.localinstance.properties.ForgePreferences.FPref; import forge.menu.FPopupMenu; import forge.model.FModel; -import forge.toolbox.FContainer; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FScrollPane; import forge.util.Utils; public class TabPageScreen> extends FScreen { diff --git a/forge-gui-mobile/src/forge/screens/achievements/AchievementsScreen.java b/forge-gui-mobile/src/forge/screens/achievements/AchievementsScreen.java index bc1a36e8fcd..f72ef3a6946 100644 --- a/forge-gui-mobile/src/forge/screens/achievements/AchievementsScreen.java +++ b/forge-gui-mobile/src/forge/screens/achievements/AchievementsScreen.java @@ -3,15 +3,9 @@ package forge.screens.achievements; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; -import forge.assets.FBufferedImage; -import forge.assets.FImage; -import forge.assets.FSkinColor; -import forge.assets.FSkinFont; -import forge.assets.FSkinImage; -import forge.assets.FSkinTexture; +import forge.assets.*; import forge.card.CardZoom; import forge.item.IPaperCard; import forge.localinstance.achievements.Achievement; diff --git a/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java b/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java index 113d00743a3..f6ff97d13a5 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java +++ b/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java @@ -1,11 +1,7 @@ package forge.screens.constructed; -import java.util.List; -import java.util.Map; - import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.assets.FImage; import forge.assets.FSkin; @@ -21,6 +17,9 @@ import forge.util.Callback; import forge.util.MyRandom; import forge.util.Utils; +import java.util.List; +import java.util.Map; + public class AvatarSelector extends FScreen { public static int getRandomAvatar(List usedAvatars) { int random = 0; diff --git a/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java b/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java index 216b4c46463..a691adde2c5 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java +++ b/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java @@ -1,29 +1,15 @@ package forge.screens.constructed; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import forge.player.GamePlayerUtil; -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.utils.Align; import com.google.common.collect.Iterables; - import forge.Forge; import forge.Graphics; import forge.ai.AIOption; import forge.assets.FSkinColor; import forge.assets.FSkinFont; import forge.assets.ImageCache; -import forge.deck.CardPool; -import forge.deck.Deck; -import forge.deck.DeckSection; -import forge.deck.DeckType; -import forge.deck.FDeckChooser; +import forge.deck.*; import forge.game.GameType; import forge.gamemodes.match.GameLobby; import forge.gamemodes.match.LobbySlot; @@ -38,19 +24,18 @@ import forge.localinstance.properties.ForgePreferences; import forge.localinstance.properties.ForgePreferences.FPref; import forge.menu.FPopupMenu; import forge.model.FModel; +import forge.player.GamePlayerUtil; import forge.screens.FScreen; import forge.screens.LaunchScreen; import forge.screens.LoadingOverlay; import forge.screens.settings.SettingsScreen; -import forge.toolbox.FCheckBox; -import forge.toolbox.FComboBox; -import forge.toolbox.FLabel; -import forge.toolbox.FList; -import forge.toolbox.FOptionPane; -import forge.toolbox.FScrollPane; +import forge.toolbox.*; import forge.util.MyRandom; import forge.util.TextUtil; import forge.util.Utils; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { private static final ForgePreferences prefs = FModel.getPreferences(); diff --git a/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java b/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java index fd4bc7713d8..da6252fe7ed 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java +++ b/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java @@ -1,15 +1,8 @@ package forge.screens.constructed; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.utils.Align; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; - import forge.Forge; import forge.Graphics; import forge.ai.AIOption; @@ -17,11 +10,7 @@ import forge.assets.FSkin; import forge.assets.FSkinFont; import forge.assets.FSkinImage; import forge.assets.FTextureRegionImage; -import forge.deck.Deck; -import forge.deck.DeckProxy; -import forge.deck.DeckType; -import forge.deck.FDeckChooser; -import forge.deck.FVanguardChooser; +import forge.deck.*; import forge.game.GameType; import forge.gamemodes.match.LobbySlot; import forge.gamemodes.match.LobbySlotType; @@ -31,20 +20,14 @@ import forge.itemmanager.DeckManager; import forge.localinstance.properties.ForgePreferences; import forge.localinstance.properties.ForgePreferences.FPref; import forge.model.FModel; -import forge.toolbox.FComboBox; -import forge.toolbox.FContainer; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FList; -import forge.toolbox.FOptionPane; -import forge.toolbox.FTextField; -import forge.toolbox.FToggleSwitch; -import forge.util.Callback; -import forge.util.Lang; -import forge.util.NameGenerator; -import forge.util.TextUtil; -import forge.util.Utils; +import forge.util.*; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Set; public class PlayerPanel extends FContainer { private static final ForgePreferences prefs = FModel.getPreferences(); diff --git a/forge-gui-mobile/src/forge/screens/constructed/SleevesSelector.java b/forge-gui-mobile/src/forge/screens/constructed/SleevesSelector.java index 9dd1550b647..acd7eec392f 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/SleevesSelector.java +++ b/forge-gui-mobile/src/forge/screens/constructed/SleevesSelector.java @@ -1,11 +1,7 @@ package forge.screens.constructed; -import java.util.List; -import java.util.Map; - import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.assets.FImage; import forge.assets.FSkin; @@ -21,6 +17,9 @@ import forge.util.Callback; import forge.util.MyRandom; import forge.util.Utils; +import java.util.List; +import java.util.Map; + public class SleevesSelector extends FScreen { public static int getRandomSleeves(List usedSleeves) { int random = 0; diff --git a/forge-gui-mobile/src/forge/screens/gauntlet/LoadGauntletScreen.java b/forge-gui-mobile/src/forge/screens/gauntlet/LoadGauntletScreen.java index e8dc7a078ca..54fff9e5a71 100644 --- a/forge-gui-mobile/src/forge/screens/gauntlet/LoadGauntletScreen.java +++ b/forge-gui-mobile/src/forge/screens/gauntlet/LoadGauntletScreen.java @@ -1,13 +1,6 @@ package forge.screens.gauntlet; -import java.io.File; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -36,6 +29,12 @@ import forge.util.Callback; import forge.util.ThreadUtil; import forge.util.Utils; +import java.io.File; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + public class LoadGauntletScreen extends LaunchScreen { private static final float ITEM_HEIGHT = Utils.AVG_FINGER_HEIGHT; private static final float PADDING = Utils.AVG_FINGER_HEIGHT * 0.1f; diff --git a/forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java b/forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java index 14853c017c9..db7f0a45b3d 100644 --- a/forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java +++ b/forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java @@ -1,10 +1,5 @@ package forge.screens.gauntlet; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import forge.Forge; import forge.assets.FSkinFont; import forge.deck.Deck; @@ -26,6 +21,11 @@ import forge.toolbox.ListChooser; import forge.util.Callback; import forge.util.Utils; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + public class NewGauntletScreen extends LaunchScreen { private static final float PADDING = Utils.scale(10); diff --git a/forge-gui-mobile/src/forge/screens/home/HomeScreen.java b/forge-gui-mobile/src/forge/screens/home/HomeScreen.java index b82e9c0ed69..d30bc46ef23 100644 --- a/forge-gui-mobile/src/forge/screens/home/HomeScreen.java +++ b/forge-gui-mobile/src/forge/screens/home/HomeScreen.java @@ -1,11 +1,7 @@ package forge.screens.home; -import java.util.ArrayList; -import java.util.List; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.utils.Align; - import com.google.common.collect.ImmutableList; import forge.Forge; import forge.Graphics; @@ -23,15 +19,14 @@ import forge.screens.online.OnlineMenu.OnlineScreen; import forge.screens.planarconquest.ConquestMenu; import forge.screens.quest.QuestMenu; import forge.screens.settings.SettingsScreen; -import forge.toolbox.FButton; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FOptionPane; -import forge.toolbox.FScrollPane; import forge.util.Callback; import forge.util.Utils; +import java.util.ArrayList; +import java.util.List; + public class HomeScreen extends FScreen { private static final float PADDING = Utils.scale(5); private static final FSkinColor clrTheme = FSkinColor.get(Colors.CLR_THEME); diff --git a/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java b/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java index 2393dd7ca24..9be5063f384 100644 --- a/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java +++ b/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java @@ -1,9 +1,5 @@ package forge.screens.home.puzzle; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import forge.Forge; import forge.assets.FSkinFont; import forge.deck.Deck; @@ -26,6 +22,10 @@ import forge.toolbox.GuiChoose; import forge.util.Callback; import forge.util.Utils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + public class PuzzleScreen extends LaunchScreen { private static final float PADDING = Utils.scale(10); diff --git a/forge-gui-mobile/src/forge/screens/limited/DraftingProcessScreen.java b/forge-gui-mobile/src/forge/screens/limited/DraftingProcessScreen.java index 1ce0b215a6d..b18203fb2c6 100644 --- a/forge-gui-mobile/src/forge/screens/limited/DraftingProcessScreen.java +++ b/forge-gui-mobile/src/forge/screens/limited/DraftingProcessScreen.java @@ -1,8 +1,6 @@ package forge.screens.limited; import forge.Forge; -import org.apache.commons.lang3.StringUtils; - import forge.deck.Deck; import forge.deck.DeckGroup; import forge.deck.FDeckEditor; @@ -16,6 +14,7 @@ import forge.screens.FScreen; import forge.screens.home.LoadGameMenu.LoadGameScreen; import forge.toolbox.FOptionPane; import forge.util.Callback; +import org.apache.commons.lang3.StringUtils; public class DraftingProcessScreen extends FDeckEditor { private boolean isDraftSaved; diff --git a/forge-gui-mobile/src/forge/screens/limited/LoadDraftScreen.java b/forge-gui-mobile/src/forge/screens/limited/LoadDraftScreen.java index 1331e0824a8..d05e2ceec97 100644 --- a/forge-gui-mobile/src/forge/screens/limited/LoadDraftScreen.java +++ b/forge-gui-mobile/src/forge/screens/limited/LoadDraftScreen.java @@ -1,17 +1,9 @@ package forge.screens.limited; -import java.util.ArrayList; -import java.util.List; - import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.assets.FSkinFont; -import forge.deck.Deck; -import forge.deck.DeckGroup; -import forge.deck.DeckProxy; -import forge.deck.FDeckChooser; -import forge.deck.FDeckEditor; +import forge.deck.*; import forge.deck.FDeckEditor.EditorType; import forge.deck.io.DeckPreferences; import forge.game.GameType; @@ -33,6 +25,9 @@ import forge.toolbox.FComboBox; import forge.toolbox.FLabel; import forge.toolbox.FOptionPane; +import java.util.ArrayList; +import java.util.List; + public class LoadDraftScreen extends LaunchScreen { private final DeckManager lstDecks = add(new DeckManager(GameType.Draft)); private final FLabel lblTip = add(new FLabel.Builder() diff --git a/forge-gui-mobile/src/forge/screens/limited/LoadSealedScreen.java b/forge-gui-mobile/src/forge/screens/limited/LoadSealedScreen.java index 27f7c82e56b..dee07f06d43 100644 --- a/forge-gui-mobile/src/forge/screens/limited/LoadSealedScreen.java +++ b/forge-gui-mobile/src/forge/screens/limited/LoadSealedScreen.java @@ -1,17 +1,9 @@ package forge.screens.limited; -import java.util.ArrayList; -import java.util.List; - import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.assets.FSkinFont; -import forge.deck.Deck; -import forge.deck.DeckGroup; -import forge.deck.DeckProxy; -import forge.deck.FDeckChooser; -import forge.deck.FDeckEditor; +import forge.deck.*; import forge.deck.FDeckEditor.EditorType; import forge.deck.io.DeckPreferences; import forge.game.GameType; @@ -33,6 +25,9 @@ import forge.toolbox.FComboBox; import forge.toolbox.FLabel; import forge.toolbox.FOptionPane; +import java.util.ArrayList; +import java.util.List; + public class LoadSealedScreen extends LaunchScreen { private final DeckManager lstDecks = add(new DeckManager(GameType.Draft)); private final FLabel lblTip = add(new FLabel.Builder() diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index 50a3cc66b33..003450d2e4a 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -1,42 +1,27 @@ package forge.screens.match; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import forge.adventure.scene.DuelScene; -import forge.adventure.scene.SceneType; -import forge.ai.GameState; -import forge.deck.Deck; -import forge.game.player.Player; -import forge.item.IPaperCard; -import forge.screens.TransitionScreen; -import forge.util.collect.FCollection; -import org.apache.commons.lang3.StringUtils; - import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; - import forge.Forge; import forge.Graphics; import forge.LobbyPlayer; -import forge.assets.FImage; -import forge.assets.FSkin; -import forge.assets.FSkinImage; -import forge.assets.FTextureRegionImage; -import forge.assets.ImageCache; +import forge.adventure.scene.DuelScene; +import forge.adventure.scene.SceneType; +import forge.ai.GameState; +import forge.assets.*; import forge.card.CardAvatarImage; import forge.card.GameEntityPicker; import forge.deck.CardPool; +import forge.deck.Deck; import forge.deck.FSideboardDialog; import forge.game.GameEntityView; import forge.game.card.CardView; import forge.game.phase.PhaseType; import forge.game.player.DelayedReveal; import forge.game.player.IHasIcon; +import forge.game.player.Player; import forge.game.player.PlayerView; import forge.game.spellability.SpellAbilityView; import forge.game.zone.ZoneType; @@ -46,6 +31,7 @@ import forge.gui.FThreads; import forge.gui.GuiBase; import forge.gui.util.SGuiChoose; import forge.gui.util.SOptionPane; +import forge.item.IPaperCard; import forge.item.PaperCard; import forge.localinstance.properties.ForgePreferences; import forge.localinstance.properties.ForgePreferences.FPref; @@ -53,12 +39,9 @@ import forge.localinstance.skin.FSkinProp; import forge.model.FModel; import forge.player.PlayerZoneUpdate; import forge.player.PlayerZoneUpdates; -import forge.screens.match.views.VAssignCombatDamage; -import forge.screens.match.views.VAssignGenericAmount; -import forge.screens.match.views.VPhaseIndicator; -import forge.screens.match.views.VPlayerPanel; +import forge.screens.TransitionScreen; +import forge.screens.match.views.*; import forge.screens.match.views.VPlayerPanel.InfoTab; -import forge.screens.match.views.VPrompt; import forge.screens.match.winlose.ViewWinLose; import forge.toolbox.FButton; import forge.toolbox.FDisplayObject; @@ -67,7 +50,14 @@ import forge.trackable.TrackableCollection; import forge.util.ITriggerEvent; import forge.util.MessageUtil; import forge.util.WaitCallback; +import forge.util.collect.FCollection; import forge.util.collect.FCollectionView; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; public class MatchController extends AbstractGuiGame { private MatchController() { } diff --git a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java index b9c01727900..8d421a44ab0 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java @@ -1,71 +1,60 @@ package forge.screens.match; -import java.util.*; -import java.util.Map.Entry; - -import com.badlogic.gdx.math.Vector2; -import forge.animation.ForgeAnimation; -import forge.assets.FImage; -import forge.card.CardImageRenderer; -import forge.card.CardRenderer; -import forge.card.CardZoom; -import forge.game.spellability.StackItemView; -import forge.gui.interfaces.IGuiGame; -import forge.toolbox.FDisplayObject; -import forge.util.Utils; -import forge.util.collect.FCollectionView; -import org.apache.commons.lang3.tuple.Pair; - import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; import com.google.common.collect.Maps; - import forge.Forge; import forge.Forge.KeyInputAdapter; import forge.Graphics; import forge.animation.AbilityEffect; +import forge.animation.ForgeAnimation; +import forge.assets.FImage; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; import forge.assets.FSkinTexture; +import forge.card.CardImageRenderer; +import forge.card.CardRenderer; +import forge.card.CardZoom; import forge.game.GameEntityView; import forge.game.GameView; import forge.game.card.CardView; import forge.game.combat.CombatView; import forge.game.phase.PhaseType; import forge.game.player.PlayerView; +import forge.game.spellability.StackItemView; import forge.game.zone.ZoneType; import forge.gui.GuiBase; +import forge.gui.interfaces.IGuiGame; import forge.interfaces.IGameController; import forge.localinstance.properties.ForgePreferences; import forge.localinstance.properties.ForgePreferences.FPref; -import forge.menu.FDropDown; -import forge.menu.FDropDownMenu; -import forge.menu.FMenuBar; -import forge.menu.FMenuItem; -import forge.menu.FMenuTab; +import forge.menu.*; import forge.model.FModel; import forge.player.PlayerZoneUpdate; import forge.screens.FScreen; -import forge.screens.match.views.VAvatar; +import forge.screens.match.views.*; import forge.screens.match.views.VCardDisplayArea.CardAreaPanel; -import forge.screens.match.views.VDevMenu; -import forge.screens.match.views.VGameMenu; -import forge.screens.match.views.VLog; -import forge.screens.match.views.VManaPool; import forge.screens.match.views.VPhaseIndicator.PhaseLabel; -import forge.screens.match.views.VPlayerPanel; import forge.screens.match.views.VPlayerPanel.InfoTab; -import forge.screens.match.views.VPlayers; -import forge.screens.match.views.VPrompt; -import forge.screens.match.views.VStack; import forge.screens.match.winlose.ViewWinLose; import forge.sound.MusicPlaylist; import forge.sound.SoundSystem; import forge.toolbox.FCardPanel; +import forge.toolbox.FDisplayObject; import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FScrollPane; import forge.util.Callback; +import forge.util.Utils; +import forge.util.collect.FCollectionView; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; public class MatchScreen extends FScreen { public static FSkinColor BORDER_COLOR = FSkinColor.get(Colors.CLR_BORDERS); diff --git a/forge-gui-mobile/src/forge/screens/match/TargetingOverlay.java b/forge-gui-mobile/src/forge/screens/match/TargetingOverlay.java index 6a6261db737..497f48309e9 100644 --- a/forge-gui-mobile/src/forge/screens/match/TargetingOverlay.java +++ b/forge-gui-mobile/src/forge/screens/match/TargetingOverlay.java @@ -19,7 +19,6 @@ package forge.screens.match; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Vector2; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; diff --git a/forge-gui-mobile/src/forge/screens/match/views/VAssignCombatDamage.java b/forge-gui-mobile/src/forge/screens/match/views/VAssignCombatDamage.java index 918a0fcd4dc..b9d2d7c0739 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VAssignCombatDamage.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VAssignCombatDamage.java @@ -17,13 +17,7 @@ */ package forge.screens.match.views; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FImage; @@ -37,20 +31,14 @@ import forge.game.card.CardView; import forge.game.card.CounterEnumType; import forge.game.player.PlayerView; import forge.screens.match.MatchController; -import forge.toolbox.FCardPanel; -import forge.toolbox.FContainer; -import forge.toolbox.FDialog; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FOptionPane; -import forge.toolbox.FScrollPane; -import forge.util.Callback; -import forge.util.CardTranslation; -import forge.util.TextUtil; -import forge.util.Utils; -import forge.util.WaitCallback; +import forge.util.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class VAssignCombatDamage extends FDialog { private static final float CARD_GAP_X = Utils.scale(10); diff --git a/forge-gui-mobile/src/forge/screens/match/views/VAssignGenericAmount.java b/forge-gui-mobile/src/forge/screens/match/views/VAssignGenericAmount.java index 7650c8f5e06..f3d4e6c6dc8 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VAssignGenericAmount.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VAssignGenericAmount.java @@ -17,13 +17,7 @@ */ package forge.screens.match.views; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FImage; @@ -36,20 +30,14 @@ import forge.card.MagicColor; import forge.game.card.CardView; import forge.game.player.PlayerView; import forge.screens.match.MatchController; -import forge.toolbox.FCardPanel; -import forge.toolbox.FContainer; -import forge.toolbox.FDialog; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FOptionPane; -import forge.toolbox.FScrollPane; -import forge.util.Callback; -import forge.util.CardTranslation; -import forge.util.TextUtil; -import forge.util.Utils; -import forge.util.WaitCallback; +import forge.util.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class VAssignGenericAmount extends FDialog { private static final float CARD_GAP_X = Utils.scale(10); diff --git a/forge-gui-mobile/src/forge/screens/match/views/VAutoYields.java b/forge-gui-mobile/src/forge/screens/match/views/VAutoYields.java index d98195d43d0..a62129d971a 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VAutoYields.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VAutoYields.java @@ -1,18 +1,14 @@ package forge.screens.match.views; -import java.util.ArrayList; -import java.util.List; - import forge.Forge; import forge.screens.match.MatchController; -import forge.toolbox.FCheckBox; -import forge.toolbox.FChoiceList; -import forge.toolbox.FDialog; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FOptionPane; import forge.util.TextBounds; +import java.util.ArrayList; +import java.util.List; + public class VAutoYields extends FDialog { private final FChoiceList lstAutoYields; private final FCheckBox chkDisableAll; diff --git a/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java b/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java index e32ea675cfb..8a20be01aec 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java @@ -4,7 +4,6 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.animation.ForgeAnimation; diff --git a/forge-gui-mobile/src/forge/screens/match/views/VCardDisplayArea.java b/forge-gui-mobile/src/forge/screens/match/views/VCardDisplayArea.java index d88b05f1ded..01b573d2e40 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VCardDisplayArea.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VCardDisplayArea.java @@ -1,14 +1,8 @@ package forge.screens.match.views; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.math.Vector2; - import forge.Forge; import forge.Graphics; import forge.card.CardRenderer.CardStackPosition; @@ -23,6 +17,11 @@ import forge.toolbox.FCardPanel; import forge.toolbox.FDisplayObject; import forge.util.ThreadUtil; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public abstract class VCardDisplayArea extends VDisplayArea implements ActivateHandler { private static final float CARD_STACK_OFFSET = 0.2f; diff --git a/forge-gui-mobile/src/forge/screens/match/views/VField.java b/forge-gui-mobile/src/forge/screens/match/views/VField.java index 615afc93982..b59c0e99e3e 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VField.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VField.java @@ -1,8 +1,5 @@ package forge.screens.match.views; -import java.util.ArrayList; -import java.util.List; - import forge.game.card.CardView; import forge.game.card.CardView.CardStateView; import forge.game.player.PlayerView; @@ -10,6 +7,9 @@ import forge.gui.FThreads; import forge.screens.match.views.VCardDisplayArea.CardAreaPanel; import forge.toolbox.FContainer; +import java.util.ArrayList; +import java.util.List; + public class VField extends FContainer { private final PlayerView player; private final FieldRow row1, row2; diff --git a/forge-gui-mobile/src/forge/screens/match/views/VLog.java b/forge-gui-mobile/src/forge/screens/match/views/VLog.java index b2242350a9b..de5e754fa3d 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VLog.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VLog.java @@ -1,9 +1,6 @@ package forge.screens.match.views; -import java.util.List; - import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; @@ -18,6 +15,8 @@ import forge.screens.match.MatchController; import forge.toolbox.FDisplayObject; import forge.util.Utils; +import java.util.List; + public class VLog extends FDropDown { private static final float PADDING = Utils.scale(5); private static final FSkinFont FONT = FSkinFont.get(11); diff --git a/forge-gui-mobile/src/forge/screens/match/views/VManaPool.java b/forge-gui-mobile/src/forge/screens/match/views/VManaPool.java index 4d0bfbc56b8..f823a4ae3a3 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VManaPool.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VManaPool.java @@ -1,10 +1,6 @@ package forge.screens.match.views; -import java.util.ArrayList; -import java.util.List; - import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -18,6 +14,9 @@ import forge.player.GamePlayerUtil; import forge.screens.match.MatchController; import forge.toolbox.FDisplayObject; +import java.util.ArrayList; +import java.util.List; + public class VManaPool extends VDisplayArea { private static final FSkinColor FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT); private static final FSkinFont FONT = FSkinFont.get(16); diff --git a/forge-gui-mobile/src/forge/screens/match/views/VPhaseIndicator.java b/forge-gui-mobile/src/forge/screens/match/views/VPhaseIndicator.java index f2064e1008c..db08d3b75d3 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VPhaseIndicator.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VPhaseIndicator.java @@ -1,11 +1,7 @@ package forge.screens.match.views; -import java.util.HashMap; -import java.util.Map; - import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; @@ -16,6 +12,9 @@ import forge.toolbox.FDisplayObject; import forge.util.TextBounds; import forge.util.Utils; +import java.util.HashMap; +import java.util.Map; + public class VPhaseIndicator extends FContainer { public static final FSkinFont BASE_FONT = FSkinFont.get(11); public static final float PADDING_X = Utils.scale(1); diff --git a/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java b/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java index b7592677798..8da7dec2115 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java @@ -1,14 +1,8 @@ package forge.screens.match.views; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -28,6 +22,11 @@ import forge.toolbox.FContainer; import forge.toolbox.FDisplayObject; import forge.util.Utils; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public class VPlayerPanel extends FContainer { private static final FSkinFont LIFE_FONT = FSkinFont.get(18); private static final FSkinFont LIFE_FONT_ALT = FSkinFont.get(22); diff --git a/forge-gui-mobile/src/forge/screens/match/views/VPlayers.java b/forge-gui-mobile/src/forge/screens/match/views/VPlayers.java index a380ecf60b6..eee291f4fef 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VPlayers.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VPlayers.java @@ -1,7 +1,6 @@ package forge.screens.match.views; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinFont; @@ -11,11 +10,7 @@ import forge.deck.FDeckViewer; import forge.game.player.PlayerView; import forge.menu.FDropDown; import forge.screens.match.MatchController; -import forge.toolbox.FContainer; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; -import forge.toolbox.FLabel; -import forge.toolbox.FList; +import forge.toolbox.*; import forge.util.Utils; public class VPlayers extends FDropDown { diff --git a/forge-gui-mobile/src/forge/screens/match/views/VPrompt.java b/forge-gui-mobile/src/forge/screens/match/views/VPrompt.java index 73ee45326ef..8a705a6e208 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VPrompt.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VPrompt.java @@ -1,9 +1,6 @@ package forge.screens.match.views; -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; @@ -19,6 +16,7 @@ import forge.toolbox.FDisplayObject; import forge.toolbox.FEvent.FEventHandler; import forge.util.TextBounds; import forge.util.Utils; +import org.apache.commons.lang3.StringUtils; public class VPrompt extends FContainer { public static final float HEIGHT = Utils.AVG_FINGER_HEIGHT; diff --git a/forge-gui-mobile/src/forge/screens/match/views/VStack.java b/forge-gui-mobile/src/forge/screens/match/views/VStack.java index 2b5e32e3263..f0c549dab00 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VStack.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VStack.java @@ -1,14 +1,8 @@ package forge.screens.match.views; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -26,11 +20,7 @@ import forge.gui.card.CardDetailUtil; import forge.gui.card.CardDetailUtil.DetailColors; import forge.gui.interfaces.IGuiGame; import forge.interfaces.IGameController; -import forge.menu.FCheckBoxMenuItem; -import forge.menu.FDropDown; -import forge.menu.FMenuItem; -import forge.menu.FMenuTab; -import forge.menu.FPopupMenu; +import forge.menu.*; import forge.player.PlayerZoneUpdates; import forge.screens.match.MatchController; import forge.screens.match.TargetingOverlay; @@ -43,6 +33,11 @@ import forge.util.TextUtil; import forge.util.Utils; import forge.util.collect.FCollectionView; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + public class VStack extends FDropDown { public static final float CARD_WIDTH = Utils.AVG_FINGER_WIDTH; public static final float CARD_HEIGHT = Math.round(CARD_WIDTH * FCardPanel.ASPECT_RATIO); diff --git a/forge-gui-mobile/src/forge/screens/match/views/VZoneDisplay.java b/forge-gui-mobile/src/forge/screens/match/views/VZoneDisplay.java index 5421f3affee..54e517679fd 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VZoneDisplay.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VZoneDisplay.java @@ -1,7 +1,5 @@ package forge.screens.match.views; -import java.util.List; - import forge.Forge; import forge.Graphics; import forge.game.player.PlayerView; @@ -9,6 +7,8 @@ import forge.game.zone.ZoneType; import forge.toolbox.FCardPanel; import forge.toolbox.FDisplayObject; +import java.util.List; + public class VZoneDisplay extends VCardDisplayArea { private final PlayerView player; private final ZoneType zoneType; diff --git a/forge-gui-mobile/src/forge/screens/match/winlose/GauntletWinLose.java b/forge-gui-mobile/src/forge/screens/match/winlose/GauntletWinLose.java index 2519001b4c2..d4d69770920 100644 --- a/forge-gui-mobile/src/forge/screens/match/winlose/GauntletWinLose.java +++ b/forge-gui-mobile/src/forge/screens/match/winlose/GauntletWinLose.java @@ -1,7 +1,5 @@ package forge.screens.match.winlose; -import java.util.List; - import forge.Forge; import forge.game.GameView; import forge.gamemodes.gauntlet.GauntletWinLoseController; @@ -9,6 +7,8 @@ import forge.gui.FThreads; import forge.gui.util.SOptionPane; import forge.localinstance.skin.FSkinProp; +import java.util.List; + /** * The Win/Lose handler for 'gauntlet' type tournament * games. diff --git a/forge-gui-mobile/src/forge/screens/match/winlose/ViewWinLose.java b/forge-gui-mobile/src/forge/screens/match/winlose/ViewWinLose.java index 600631e2ae5..415bbab70e0 100644 --- a/forge-gui-mobile/src/forge/screens/match/winlose/ViewWinLose.java +++ b/forge-gui-mobile/src/forge/screens/match/winlose/ViewWinLose.java @@ -1,12 +1,7 @@ package forge.screens.match.winlose; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; @@ -22,15 +17,12 @@ import forge.item.PaperCard; import forge.localinstance.skin.FSkinProp; import forge.menu.FMagnifyView; import forge.model.FModel; -import forge.toolbox.FButton; -import forge.toolbox.FContainer; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FOverlay; -import forge.toolbox.FTextArea; import forge.util.Utils; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; public class ViewWinLose extends FOverlay implements IWinLoseView { private static final float INSETS_FACTOR = 0.025f; diff --git a/forge-gui-mobile/src/forge/screens/online/OnlineChatScreen.java b/forge-gui-mobile/src/forge/screens/online/OnlineChatScreen.java index 614649a7e38..567bde97f45 100644 --- a/forge-gui-mobile/src/forge/screens/online/OnlineChatScreen.java +++ b/forge-gui-mobile/src/forge/screens/online/OnlineChatScreen.java @@ -2,7 +2,6 @@ package forge.screens.online; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; diff --git a/forge-gui-mobile/src/forge/screens/online/OnlineLobbyScreen.java b/forge-gui-mobile/src/forge/screens/online/OnlineLobbyScreen.java index 5eeb5f5169d..0ab1ff5b782 100644 --- a/forge-gui-mobile/src/forge/screens/online/OnlineLobbyScreen.java +++ b/forge-gui-mobile/src/forge/screens/online/OnlineLobbyScreen.java @@ -1,14 +1,9 @@ package forge.screens.online; import com.google.common.collect.ImmutableList; - import forge.Forge; import forge.gamemodes.match.GameLobby; -import forge.gamemodes.net.ChatMessage; -import forge.gamemodes.net.IOnlineChatInterface; -import forge.gamemodes.net.IOnlineLobby; -import forge.gamemodes.net.NetConnectUtil; -import forge.gamemodes.net.OfflineLobby; +import forge.gamemodes.net.*; import forge.gamemodes.net.client.FGameClient; import forge.gamemodes.net.server.FServerManager; import forge.gui.FThreads; diff --git a/forge-gui-mobile/src/forge/screens/online/OnlineMenu.java b/forge-gui-mobile/src/forge/screens/online/OnlineMenu.java index 521ab3491b2..e2ab059d93a 100644 --- a/forge-gui-mobile/src/forge/screens/online/OnlineMenu.java +++ b/forge-gui-mobile/src/forge/screens/online/OnlineMenu.java @@ -1,7 +1,5 @@ package forge.screens.online; -import static forge.screens.online.OnlineLobbyScreen.getGameLobby; - import forge.Forge; import forge.assets.FImage; import forge.assets.FSkinImage; @@ -17,6 +15,8 @@ import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FOptionPane; import forge.util.Callback; +import static forge.screens.online.OnlineLobbyScreen.getGameLobby; + public class OnlineMenu extends FPopupMenu { public enum OnlineScreen { Lobby("lblLobby", FSkinImage.FAVICON, OnlineLobbyScreen.class), diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestAEtherScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestAEtherScreen.java index ad4cce3b5c1..30a3cf44880 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestAEtherScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestAEtherScreen.java @@ -1,9 +1,5 @@ package forge.screens.planarconquest; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Align; @@ -11,21 +7,12 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; - import forge.Forge; import forge.Graphics; import forge.animation.ForgeAnimation; -import forge.assets.FSkin; -import forge.assets.FSkinColor; -import forge.assets.FSkinFont; -import forge.assets.FSkinTexture; -import forge.assets.TextRenderer; -import forge.card.CardRarity; -import forge.card.CardRenderer; +import forge.assets.*; +import forge.card.*; import forge.card.CardRenderer.CardStackPosition; -import forge.card.CardZoom; -import forge.card.ColorSet; -import forge.card.ColorSetImage; import forge.gamemodes.planarconquest.ConquestCommander; import forge.gamemodes.planarconquest.ConquestData; import forge.gamemodes.planarconquest.ConquestPlane; @@ -36,17 +23,17 @@ import forge.item.PaperCard; import forge.localinstance.skin.FSkinProp; import forge.model.FModel; import forge.screens.FScreen; -import forge.toolbox.FCardPanel; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.GuiChoose; import forge.util.Aggregates; import forge.util.Callback; import forge.util.MyRandom; import forge.util.Utils; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + public class ConquestAEtherScreen extends FScreen { public static final Color FILTER_BUTTON_COLOR = ConquestMultiverseScreen.LOCATION_BAR_COLOR; public static final FSkinColor FILTER_BUTTON_TEXT_COLOR = FSkinColor.getStandardColor(ConquestMultiverseScreen.LOCATION_BAR_TEXT_COLOR); diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestChaosWheel.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestChaosWheel.java index c24ac7370d4..1364a326b89 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestChaosWheel.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestChaosWheel.java @@ -1,7 +1,6 @@ package forge.screens.planarconquest; import com.badlogic.gdx.math.Vector2; - import forge.Forge; import forge.Graphics; import forge.animation.ForgeAnimation; diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCollectionScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCollectionScreen.java index 8f335335cf5..81c34c980b9 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCollectionScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCollectionScreen.java @@ -1,11 +1,7 @@ package forge.screens.planarconquest; -import java.util.Collection; -import java.util.Map.Entry; - import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; - import forge.Forge; import forge.assets.FImage; import forge.assets.FSkinFont; @@ -34,6 +30,9 @@ import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FLabel; +import java.util.Collection; +import java.util.Map.Entry; + public class ConquestCollectionScreen extends TabPageScreen { private final FLabel lblShards = add(new FLabel.Builder().font(ConquestAEtherScreen.LABEL_FONT).parseSymbols().build()); private final FLabel lblInfo = add(new FLabel.Builder().font(FSkinFont.get(11)).build()); diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCommandersScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCommandersScreen.java index cc684bbfe7a..a554b16622b 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCommandersScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCommandersScreen.java @@ -1,10 +1,7 @@ package forge.screens.planarconquest; -import java.util.Map.Entry; - import com.badlogic.gdx.utils.Align; import com.google.common.base.Predicate; - import forge.Forge; import forge.Graphics; import forge.assets.FImage; @@ -26,22 +23,16 @@ import forge.itemmanager.ItemManager; import forge.itemmanager.ItemManagerConfig; import forge.itemmanager.SFilterUtil; import forge.itemmanager.SItemManagerUtil.StatTypes; -import forge.itemmanager.filters.AdvancedSearchFilter; -import forge.itemmanager.filters.ComboBoxFilter; -import forge.itemmanager.filters.ItemFilter; -import forge.itemmanager.filters.StatTypeFilter; -import forge.itemmanager.filters.TextSearchFilter; +import forge.itemmanager.filters.*; import forge.model.FModel; import forge.screens.FScreen; -import forge.toolbox.FButton; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FList; import forge.toolbox.FList.CompactModeHandler; -import forge.toolbox.FOptionPane; -import forge.toolbox.FTextField; import forge.util.Callback; +import java.util.Map.Entry; + public class ConquestCommandersScreen extends FScreen { private static final float PADDING = FDeckChooser.PADDING; diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestDeckEditor.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestDeckEditor.java index 439fc001775..58cef268e05 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestDeckEditor.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestDeckEditor.java @@ -1,7 +1,5 @@ package forge.screens.planarconquest; -import java.util.Map; - import forge.Forge; import forge.deck.DeckProxy; import forge.deck.FDeckEditor; @@ -15,6 +13,8 @@ import forge.model.FModel; import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventHandler; +import java.util.Map; + public class ConquestDeckEditor extends FDeckEditor { public ConquestDeckEditor(final ConquestCommander commander) { super(EditorType.PlanarConquest, new DeckProxy(commander.getDeck(), Forge.getLocalizer().getMessage("lblConquestCommander"), diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMultiverseScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMultiverseScreen.java index fbe7327925c..5aa64340e7b 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMultiverseScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMultiverseScreen.java @@ -1,42 +1,18 @@ package forge.screens.planarconquest; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.animation.ForgeAnimation; -import forge.assets.FImage; -import forge.assets.FSkinColor; -import forge.assets.FSkinFont; -import forge.assets.FSkinImage; -import forge.assets.FSkinTexture; -import forge.card.CardAvatarImage; -import forge.card.CardFaceSymbols; -import forge.card.CardImageRenderer; -import forge.card.CardRenderer; -import forge.card.CardZoom; -import forge.card.ColorSet; -import forge.gamemodes.planarconquest.ConquestAwardPool; -import forge.gamemodes.planarconquest.ConquestBattle; -import forge.gamemodes.planarconquest.ConquestChaosBattle; -import forge.gamemodes.planarconquest.ConquestData; -import forge.gamemodes.planarconquest.ConquestEvent; +import forge.assets.*; +import forge.card.*; +import forge.gamemodes.planarconquest.*; import forge.gamemodes.planarconquest.ConquestEvent.ChaosWheelOutcome; import forge.gamemodes.planarconquest.ConquestEvent.ConquestEventRecord; -import forge.gamemodes.planarconquest.ConquestLocation; -import forge.gamemodes.planarconquest.ConquestPlane; -import forge.gamemodes.planarconquest.ConquestPlaneData; import forge.gamemodes.planarconquest.ConquestPreferences.CQPref; -import forge.gamemodes.planarconquest.ConquestRegion; -import forge.gamemodes.planarconquest.ConquestReward; -import forge.gamemodes.planarconquest.ConquestUtil; import forge.gui.FThreads; import forge.gui.card.CardDetailUtil; import forge.gui.card.CardDetailUtil.DetailColors; @@ -44,15 +20,13 @@ import forge.item.PaperCard; import forge.model.FModel; import forge.screens.FScreen; import forge.screens.LoadingOverlay; -import forge.toolbox.FButton; -import forge.toolbox.FContainer; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FList; -import forge.toolbox.FOptionPane; -import forge.toolbox.FScrollPane; +import forge.toolbox.*; import forge.util.Callback; import forge.util.Utils; import forge.util.collect.FCollectionView; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; public class ConquestMultiverseScreen extends FScreen { private static final Color FOG_OF_WAR_COLOR = FSkinColor.alphaColor(Color.BLACK, 0.65f); diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPlaneSelector.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPlaneSelector.java index 89b368bd69a..d4548b71293 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPlaneSelector.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPlaneSelector.java @@ -1,21 +1,14 @@ package forge.screens.planarconquest; -import java.util.List; - import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Align; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; - import forge.Forge; import forge.Graphics; -import forge.assets.FImage; -import forge.assets.FSkinColor; -import forge.assets.FSkinFont; -import forge.assets.FSkinImage; -import forge.assets.FSkinTexture; +import forge.assets.*; import forge.card.CardRenderer; import forge.gamemodes.planarconquest.ConquestPlane; import forge.item.PaperCard; @@ -27,6 +20,8 @@ import forge.toolbox.GuiDialog; import forge.util.Utils; import forge.util.collect.FCollectionView; +import java.util.List; + public class ConquestPlaneSelector extends FDisplayObject { private static final FSkinFont PLANE_NAME_FONT = FSkinFont.get(30); private static final Color BACK_COLOR = FSkinColor.fromRGB(1, 2, 2); diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPlaneswalkScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPlaneswalkScreen.java index 65fe6e6d9f8..71ec5f83819 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPlaneswalkScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPlaneswalkScreen.java @@ -2,7 +2,6 @@ package forge.screens.planarconquest; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinFont; diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java index 60833e8cdb5..daee1621b08 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java @@ -8,15 +8,8 @@ import forge.gamemodes.planarconquest.ConquestPreferences; import forge.gamemodes.planarconquest.ConquestPreferences.CQPref; import forge.model.FModel; import forge.screens.FScreen; -import forge.toolbox.FContainer; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FNumericTextField; -import forge.toolbox.FOptionPane; -import forge.toolbox.FScrollPane; -import forge.toolbox.FTextField; import forge.util.Utils; public class ConquestPrefsScreen extends FScreen { diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java index f148d39d2bf..62918f10b21 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java @@ -1,11 +1,7 @@ package forge.screens.planarconquest; -import java.util.ArrayList; -import java.util.List; - import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.ImageKeys; @@ -18,14 +14,13 @@ import forge.card.CardRenderer.CardStackPosition; import forge.card.CardZoom; import forge.gamemodes.planarconquest.ConquestReward; import forge.item.PaperCard; -import forge.toolbox.FCardPanel; -import forge.toolbox.FDialog; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FScrollPane; import forge.util.Utils; +import java.util.ArrayList; +import java.util.List; + public class ConquestRewardDialog extends FScrollPane { private static final float PADDING = Utils.scale(5); diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestStatsScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestStatsScreen.java index 94af5690b78..1f38341fc88 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestStatsScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestStatsScreen.java @@ -1,7 +1,6 @@ package forge.screens.planarconquest; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.assets.FImage; import forge.assets.FSkinFont; @@ -12,12 +11,8 @@ import forge.gamemodes.planarconquest.IVConquestStats; import forge.gui.interfaces.IButton; import forge.model.FModel; import forge.screens.FScreen; -import forge.toolbox.FComboBox; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FScrollPane; import forge.util.Utils; public class ConquestStatsScreen extends FScreen implements IVConquestStats { diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java index 6df8ee87386..e2f92c2e960 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java @@ -1,16 +1,7 @@ package forge.screens.planarconquest; -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -40,6 +31,9 @@ import forge.util.FileUtil; import forge.util.ThreadUtil; import forge.util.Utils; +import java.io.File; +import java.util.*; + public class LoadConquestScreen extends LaunchScreen { private static final float ITEM_HEIGHT = Utils.AVG_FINGER_HEIGHT; private static final float PADDING = Utils.AVG_FINGER_HEIGHT * 0.1f; diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java index 5cfbaa7fb21..073283f5c64 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java @@ -1,7 +1,6 @@ package forge.screens.planarconquest; import com.google.common.collect.Iterables; - import forge.Forge; import forge.assets.FImage; import forge.card.CardImage; diff --git a/forge-gui-mobile/src/forge/screens/quest/LoadQuestScreen.java b/forge-gui-mobile/src/forge/screens/quest/LoadQuestScreen.java index a98717ba8e1..84f59174f2f 100644 --- a/forge-gui-mobile/src/forge/screens/quest/LoadQuestScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/LoadQuestScreen.java @@ -1,18 +1,7 @@ package forge.screens.quest; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -42,6 +31,11 @@ import forge.toolbox.FTextArea; import forge.util.ThreadUtil; import forge.util.Utils; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.*; + public class LoadQuestScreen extends LaunchScreen { private static final float ITEM_HEIGHT = Utils.AVG_FINGER_HEIGHT; private static final float PADDING = Utils.AVG_FINGER_HEIGHT * 0.1f; diff --git a/forge-gui-mobile/src/forge/screens/quest/NewQuestScreen.java b/forge-gui-mobile/src/forge/screens/quest/NewQuestScreen.java index 51f14a71410..317b228cfac 100644 --- a/forge-gui-mobile/src/forge/screens/quest/NewQuestScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/NewQuestScreen.java @@ -1,13 +1,6 @@ package forge.screens.quest; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map.Entry; -import java.util.Set; - import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.assets.FSkinFont; import forge.assets.FSkinImage; @@ -16,13 +9,8 @@ import forge.deck.Deck; import forge.deck.DeckGroup; import forge.deck.DeckSection; import forge.game.GameFormat; -import forge.gamemodes.quest.QuestController; -import forge.gamemodes.quest.QuestMode; -import forge.gamemodes.quest.QuestUtil; -import forge.gamemodes.quest.QuestWorld; -import forge.gamemodes.quest.StartingPoolPreferences; +import forge.gamemodes.quest.*; import forge.gamemodes.quest.StartingPoolPreferences.PoolType; -import forge.gamemodes.quest.StartingPoolType; import forge.gamemodes.quest.data.DeckConstructionRules; import forge.gamemodes.quest.data.GameFormatQuest; import forge.gamemodes.quest.data.QuestPreferences.QPref; @@ -39,19 +27,18 @@ import forge.screens.FScreen; import forge.screens.LoadingOverlay; import forge.screens.home.NewGameMenu; import forge.screens.quest.QuestMenu.LaunchReason; -import forge.toolbox.FCheckBox; -import forge.toolbox.FComboBox; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FLabel; -import forge.toolbox.FNumericTextField; -import forge.toolbox.FOptionPane; -import forge.toolbox.FRadioButton; +import forge.toolbox.*; import forge.toolbox.FRadioButton.RadioButtonGroup; -import forge.toolbox.FScrollPane; import forge.util.FileUtil; import forge.util.ThreadUtil; import forge.util.Utils; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; + public class NewQuestScreen extends FScreen { private static final float EMBARK_BTN_HEIGHT = 2 * Utils.AVG_FINGER_HEIGHT; diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestBazaarScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestBazaarScreen.java index 3a1183c30e5..ac40451f307 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestBazaarScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestBazaarScreen.java @@ -1,11 +1,7 @@ package forge.screens.quest; -import java.util.List; -import java.util.Set; - import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FImage; @@ -20,16 +16,13 @@ import forge.gamemodes.quest.data.QuestAssets; import forge.gui.GuiBase; import forge.model.FModel; import forge.screens.TabPageScreen; -import forge.toolbox.FContainer; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FList; -import forge.toolbox.FScrollPane; -import forge.toolbox.FTextArea; import forge.util.Utils; +import java.util.List; +import java.util.Set; + public class QuestBazaarScreen extends TabPageScreen { public QuestBazaarScreen() { diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestChallengesScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestChallengesScreen.java index e86019ad2d9..fbf9b192dca 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestChallengesScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestChallengesScreen.java @@ -2,7 +2,6 @@ package forge.screens.quest; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.assets.FSkinFont; import forge.gui.interfaces.IButton; diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestDeckEditor.java b/forge-gui-mobile/src/forge/screens/quest/QuestDeckEditor.java index 173c618ba3c..37951dbae7b 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestDeckEditor.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestDeckEditor.java @@ -1,8 +1,5 @@ package forge.screens.quest; -import java.util.HashMap; -import java.util.Map; - import forge.deck.DeckProxy; import forge.deck.FDeckEditor; import forge.gamemodes.quest.QuestSpellShop; @@ -12,6 +9,9 @@ import forge.itemmanager.ItemColumn; import forge.itemmanager.ItemManagerConfig; import forge.model.FModel; +import java.util.HashMap; +import java.util.Map; + public class QuestDeckEditor extends FDeckEditor { public QuestDeckEditor(boolean commander) { super(commander ? EditorType.QuestCommander: EditorType.Quest, "", false); diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestDecksScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestDecksScreen.java index c3c98f39998..17bcfd67482 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestDecksScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestDecksScreen.java @@ -1,7 +1,6 @@ package forge.screens.quest; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.assets.FSkinFont; import forge.assets.ImageCache; diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java index 8560f42ec61..5d62bd3c038 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java @@ -1,10 +1,7 @@ package forge.screens.quest; -import java.util.List; - import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.assets.FSkinFont; import forge.gamemodes.quest.QuestEventDuel; @@ -14,6 +11,8 @@ import forge.model.FModel; import forge.screens.LoadingOverlay; import forge.toolbox.FLabel; +import java.util.List; + public class QuestDuelsScreen extends QuestLaunchScreen { private final FLabel lblInfo = add(new FLabel.Builder().text(Forge.getLocalizer().getMessage("lblSelectNextDuel")) diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestEventPanel.java b/forge-gui-mobile/src/forge/screens/quest/QuestEventPanel.java index 956ca72a852..08d3fa57ce4 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestEventPanel.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestEventPanel.java @@ -2,14 +2,9 @@ package forge.screens.quest; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Align; - import forge.Graphics; -import forge.assets.FImage; -import forge.assets.FSkinColor; +import forge.assets.*; import forge.assets.FSkinColor.Colors; -import forge.assets.FSkinFont; -import forge.assets.FSkinImage; -import forge.assets.ImageCache; import forge.gamemodes.quest.IQuestEvent; import forge.screens.settings.SettingsScreen; import forge.toolbox.FDisplayObject; diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java index 67ca2c6eba6..176e0997d78 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java @@ -1,8 +1,5 @@ package forge.screens.quest; -import java.io.File; -import java.io.IOException; - import forge.Forge; import forge.assets.FSkinImage; import forge.deck.Deck; @@ -28,6 +25,9 @@ import forge.screens.home.LoadGameMenu.LoadGameScreen; import forge.screens.home.NewGameMenu.NewGameScreen; import forge.util.ThreadUtil; +import java.io.File; +import java.io.IOException; + public class QuestMenu extends FPopupMenu implements IVQuestStats { private static final QuestMenu questMenu = new QuestMenu(); diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestPrefsScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestPrefsScreen.java index 4164e09814c..950240cbbec 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestPrefsScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestPrefsScreen.java @@ -8,15 +8,8 @@ import forge.gamemodes.quest.data.QuestPreferences; import forge.gamemodes.quest.data.QuestPreferences.QPref; import forge.model.FModel; import forge.screens.FScreen; -import forge.toolbox.FContainer; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FNumericTextField; -import forge.toolbox.FOptionPane; -import forge.toolbox.FScrollPane; -import forge.toolbox.FTextField; import forge.util.Utils; public class QuestPrefsScreen extends FScreen { diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestSpellShopScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestSpellShopScreen.java index 4cf53a0909f..206ab3fd21d 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestSpellShopScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestSpellShopScreen.java @@ -1,13 +1,6 @@ package forge.screens.quest; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.assets.FImage; import forge.assets.FSkinFont; @@ -36,6 +29,12 @@ import forge.util.Callback; import forge.util.ItemPool; import forge.util.Utils; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + public class QuestSpellShopScreen extends TabPageScreen { private final SpellShopPage spellShopPage; private final InventoryPage inventoryPage; diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestStatsScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestStatsScreen.java index 154e9462a72..9331fc945ed 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestStatsScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestStatsScreen.java @@ -1,7 +1,5 @@ package forge.screens.quest; -import java.util.List; - import forge.Forge; import forge.assets.FImage; import forge.assets.FSkinFont; @@ -14,16 +12,12 @@ import forge.gui.interfaces.ICheckBox; import forge.gui.interfaces.IComboBox; import forge.model.FModel; import forge.screens.FScreen; -import forge.toolbox.FCheckBox; -import forge.toolbox.FComboBox; -import forge.toolbox.FDisplayObject; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FLabel; -import forge.toolbox.FOptionPane; -import forge.toolbox.FScrollPane; import forge.util.Utils; +import java.util.List; + public class QuestStatsScreen extends FScreen { private static final float PADDING = FOptionPane.PADDING; diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestTournamentsScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestTournamentsScreen.java index 98f4a5ac791..5962018b0d5 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestTournamentsScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestTournamentsScreen.java @@ -1,17 +1,9 @@ package forge.screens.quest; -import java.util.Arrays; - import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; - import forge.Forge; -import forge.assets.FSkin; -import forge.assets.FSkinColor; -import forge.assets.FSkinFont; -import forge.assets.FSkinImage; -import forge.assets.FTextureRegionImage; -import forge.assets.ImageCache; +import forge.assets.*; import forge.deck.CardPool; import forge.deck.Deck; import forge.deck.DeckGroup; @@ -38,6 +30,8 @@ import forge.toolbox.FLabel; import forge.toolbox.FTextField; import forge.util.Utils; +import java.util.Arrays; + public class QuestTournamentsScreen extends QuestLaunchScreen implements IQuestTournamentView { //Select Tournament panel private final SelectTournamentPanel pnlSelectTournament = add(new SelectTournamentPanel()); diff --git a/forge-gui-mobile/src/forge/screens/settings/FilesPage.java b/forge-gui-mobile/src/forge/screens/settings/FilesPage.java index cbd354505bb..3ed187d8804 100644 --- a/forge-gui-mobile/src/forge/screens/settings/FilesPage.java +++ b/forge-gui-mobile/src/forge/screens/settings/FilesPage.java @@ -1,45 +1,32 @@ package forge.screens.settings; +import com.badlogic.gdx.utils.Align; +import com.google.common.collect.ImmutableList; +import forge.Forge; +import forge.Graphics; +import forge.StaticData; +import forge.assets.FSkinColor; +import forge.assets.FSkinFont; +import forge.assets.FSkinImage; +import forge.gui.FThreads; +import forge.gui.GuiBase; +import forge.gui.download.*; +import forge.localinstance.properties.ForgeConstants; +import forge.localinstance.properties.ForgeProfileProperties; +import forge.screens.LoadingOverlay; +import forge.screens.TabPageScreen.TabPage; +import forge.toolbox.*; +import forge.toolbox.FFileChooser.ChoiceType; +import forge.util.Callback; +import forge.util.FileUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; + import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; -import com.google.common.collect.ImmutableList; -import forge.StaticData; -import forge.gui.FThreads; -import forge.gui.GuiBase; -import forge.screens.LoadingOverlay; -import org.apache.commons.lang3.StringUtils; - -import com.badlogic.gdx.utils.Align; - -import forge.Forge; -import forge.Graphics; -import forge.assets.FSkinColor; -import forge.assets.FSkinFont; -import forge.assets.FSkinImage; -import forge.gui.download.GuiDownloadAchievementImages; -import forge.gui.download.GuiDownloadPicturesLQ; -import forge.gui.download.GuiDownloadPrices; -import forge.gui.download.GuiDownloadQuestImages; -import forge.gui.download.GuiDownloadService; -import forge.gui.download.GuiDownloadSetPicturesLQ; -import forge.gui.download.GuiDownloadSkins; -import forge.gui.download.GuiDownloadZipService; -import forge.localinstance.properties.ForgeConstants; -import forge.localinstance.properties.ForgeProfileProperties; -import forge.screens.TabPageScreen.TabPage; -import forge.toolbox.FFileChooser; -import forge.toolbox.FFileChooser.ChoiceType; -import forge.toolbox.FGroupList; -import forge.toolbox.FList; -import forge.toolbox.FOptionPane; -import forge.toolbox.GuiChoose; -import forge.util.Callback; -import forge.util.FileUtil; -import org.apache.commons.lang3.tuple.Pair; - public class FilesPage extends TabPage { private final FGroupList lstItems = add(new FGroupList<>()); diff --git a/forge-gui-mobile/src/forge/screens/settings/GuiDownloader.java b/forge-gui-mobile/src/forge/screens/settings/GuiDownloader.java index 537f0d64819..c00e9b6e4bc 100644 --- a/forge-gui-mobile/src/forge/screens/settings/GuiDownloader.java +++ b/forge-gui-mobile/src/forge/screens/settings/GuiDownloader.java @@ -17,22 +17,18 @@ */ package forge.screens.settings; -import java.net.Proxy; - import forge.Forge; import forge.gui.UiCommand; import forge.gui.download.GuiDownloadService; import forge.gui.download.GuiDownloadZipService; -import forge.toolbox.FDialog; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; -import forge.toolbox.FProgressBar; -import forge.toolbox.FRadioButton; import forge.toolbox.FRadioButton.RadioButtonGroup; -import forge.toolbox.FTextField; import forge.util.Callback; import forge.util.Utils; +import java.net.Proxy; + public class GuiDownloader extends FDialog { public static final Proxy.Type[] TYPES = Proxy.Type.values(); private static final float PADDING = Utils.scale(10); diff --git a/forge-gui-mobile/src/forge/toolbox/DualListBox.java b/forge-gui-mobile/src/forge/toolbox/DualListBox.java index d9698d747b0..bb0a621a3b2 100644 --- a/forge-gui-mobile/src/forge/toolbox/DualListBox.java +++ b/forge-gui-mobile/src/forge/toolbox/DualListBox.java @@ -1,17 +1,16 @@ package forge.toolbox; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FEvent.FEventType; import forge.util.Callback; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + // An input box for handling the order of choices. // Left box has the original choices // Right box has the final order diff --git a/forge-gui-mobile/src/forge/toolbox/FButton.java b/forge-gui-mobile/src/forge/toolbox/FButton.java index 4c62825ae36..0291ce5cad9 100644 --- a/forge-gui-mobile/src/forge/toolbox/FButton.java +++ b/forge-gui-mobile/src/forge/toolbox/FButton.java @@ -1,10 +1,7 @@ package forge.toolbox; -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -18,6 +15,7 @@ import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FEvent.FEventType; import forge.util.TextBounds; import forge.util.Utils; +import org.apache.commons.lang3.StringUtils; public class FButton extends FDisplayObject implements IButton { private static final FSkinColor DEFAULT_FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT); diff --git a/forge-gui-mobile/src/forge/toolbox/FCheckBox.java b/forge-gui-mobile/src/forge/toolbox/FCheckBox.java index fd7d6438737..ca8b2cb5f09 100644 --- a/forge-gui-mobile/src/forge/toolbox/FCheckBox.java +++ b/forge-gui-mobile/src/forge/toolbox/FCheckBox.java @@ -1,7 +1,6 @@ package forge.toolbox; import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FImage; import forge.assets.FSkinColor; diff --git a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java index e63a7c8acd9..77abaa7871c 100644 --- a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java +++ b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java @@ -1,13 +1,6 @@ package forge.toolbox; -import static forge.card.CardRenderer.MANA_SYMBOL_SIZE; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FSkin; import forge.assets.FSkinColor; @@ -38,6 +31,12 @@ import forge.screens.match.views.VStack; import forge.util.TextUtil; import forge.util.Utils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static forge.card.CardRenderer.MANA_SYMBOL_SIZE; + public class FChoiceList extends FList implements ActivateHandler { public static final FSkinColor ITEM_COLOR = FSkinColor.get(Colors.CLR_ZEBRA); public static final FSkinColor ALT_ITEM_COLOR = ITEM_COLOR.getContrastColor(-20); diff --git a/forge-gui-mobile/src/forge/toolbox/FComboBox.java b/forge-gui-mobile/src/forge/toolbox/FComboBox.java index 2a2a863157d..65753a8c151 100644 --- a/forge-gui-mobile/src/forge/toolbox/FComboBox.java +++ b/forge-gui-mobile/src/forge/toolbox/FComboBox.java @@ -1,11 +1,6 @@ package forge.toolbox; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.gui.interfaces.IComboBox; import forge.menu.FDropDownMenu; @@ -13,6 +8,10 @@ import forge.menu.FMenuItem; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FEvent.FEventType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + public class FComboBox extends FTextField implements IComboBox { private final List items = new ArrayList<>(); private T selectedItem; diff --git a/forge-gui-mobile/src/forge/toolbox/FContainer.java b/forge-gui-mobile/src/forge/toolbox/FContainer.java index bb0f248c431..6b14cfb711d 100644 --- a/forge-gui-mobile/src/forge/toolbox/FContainer.java +++ b/forge-gui-mobile/src/forge/toolbox/FContainer.java @@ -1,14 +1,13 @@ package forge.toolbox; +import com.badlogic.gdx.math.Vector2; +import forge.Graphics; +import forge.gui.error.BugReporter; + import java.util.ArrayList; import java.util.ConcurrentModificationException; import java.util.List; -import com.badlogic.gdx.math.Vector2; - -import forge.Graphics; -import forge.gui.error.BugReporter; - public abstract class FContainer extends FDisplayObject { private final List children = new ArrayList<>(); diff --git a/forge-gui-mobile/src/forge/toolbox/FDialog.java b/forge-gui-mobile/src/forge/toolbox/FDialog.java index 28f86cf4729..3e8e87222d5 100644 --- a/forge-gui-mobile/src/forge/toolbox/FDialog.java +++ b/forge-gui-mobile/src/forge/toolbox/FDialog.java @@ -2,7 +2,6 @@ package forge.toolbox; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.animation.ForgeAnimation; diff --git a/forge-gui-mobile/src/forge/toolbox/FDisplayObject.java b/forge-gui-mobile/src/forge/toolbox/FDisplayObject.java index 92aaef7130d..4355a1a57a6 100644 --- a/forge-gui-mobile/src/forge/toolbox/FDisplayObject.java +++ b/forge-gui-mobile/src/forge/toolbox/FDisplayObject.java @@ -1,13 +1,12 @@ package forge.toolbox; -import java.util.List; - import com.badlogic.gdx.math.Rectangle; - import forge.Forge; import forge.Graphics; import forge.gui.GuiBase; +import java.util.List; + public abstract class FDisplayObject { protected static final float DISABLED_COMPOSITE = 0.25f; diff --git a/forge-gui-mobile/src/forge/toolbox/FFileChooser.java b/forge-gui-mobile/src/forge/toolbox/FFileChooser.java index 8b12f2cf3dd..3d7cd187fe7 100644 --- a/forge-gui-mobile/src/forge/toolbox/FFileChooser.java +++ b/forge-gui-mobile/src/forge/toolbox/FFileChooser.java @@ -1,13 +1,7 @@ package forge.toolbox; -import java.io.File; -import java.io.FilenameFilter; - -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -19,6 +13,10 @@ import forge.toolbox.FEvent.FEventHandler; import forge.util.Callback; import forge.util.FileUtil; import forge.util.Utils; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.FilenameFilter; public class FFileChooser extends FDialog { private static final float BACK_ICON_THICKNESS = Utils.scale(2); diff --git a/forge-gui-mobile/src/forge/toolbox/FGestureAdapter.java b/forge-gui-mobile/src/forge/toolbox/FGestureAdapter.java index 10178690641..89cf891724a 100644 --- a/forge-gui-mobile/src/forge/toolbox/FGestureAdapter.java +++ b/forge-gui-mobile/src/forge/toolbox/FGestureAdapter.java @@ -6,7 +6,6 @@ import com.badlogic.gdx.InputAdapter; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Timer; import com.badlogic.gdx.utils.Timer.Task; - import forge.Forge; import forge.assets.FSkin; import forge.localinstance.properties.ForgePreferences.FPref; diff --git a/forge-gui-mobile/src/forge/toolbox/FGroupBox.java b/forge-gui-mobile/src/forge/toolbox/FGroupBox.java index fbfd85e2ecf..e7e6eb0219b 100644 --- a/forge-gui-mobile/src/forge/toolbox/FGroupBox.java +++ b/forge-gui-mobile/src/forge/toolbox/FGroupBox.java @@ -1,7 +1,6 @@ package forge.toolbox; import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; diff --git a/forge-gui-mobile/src/forge/toolbox/FGroupList.java b/forge-gui-mobile/src/forge/toolbox/FGroupList.java index 0bf2b243018..dd4109d9247 100644 --- a/forge-gui-mobile/src/forge/toolbox/FGroupList.java +++ b/forge-gui-mobile/src/forge/toolbox/FGroupList.java @@ -1,8 +1,5 @@ package forge.toolbox; -import java.util.ArrayList; -import java.util.List; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinFont; @@ -13,6 +10,9 @@ import forge.toolbox.FList.DefaultListItemRenderer; import forge.toolbox.FList.ListItemRenderer; import forge.util.Utils; +import java.util.ArrayList; +import java.util.List; + public class FGroupList extends FScrollPane { private static final float GROUP_HEADER_HEIGHT = Math.round(Utils.AVG_FINGER_HEIGHT * 0.6f); diff --git a/forge-gui-mobile/src/forge/toolbox/FLabel.java b/forge-gui-mobile/src/forge/toolbox/FLabel.java index a48b09c9b6c..d16a84dee43 100644 --- a/forge-gui-mobile/src/forge/toolbox/FLabel.java +++ b/forge-gui-mobile/src/forge/toolbox/FLabel.java @@ -3,14 +3,9 @@ package forge.toolbox; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; - import forge.Graphics; -import forge.assets.FImage; -import forge.assets.FSkinColor; +import forge.assets.*; import forge.assets.FSkinColor.Colors; -import forge.assets.FSkinFont; -import forge.assets.FSkinImage; -import forge.assets.TextRenderer; import forge.gui.UiCommand; import forge.gui.interfaces.IButton; import forge.localinstance.skin.FSkinProp; diff --git a/forge-gui-mobile/src/forge/toolbox/FList.java b/forge-gui-mobile/src/forge/toolbox/FList.java index e5282ad3b20..f7014384ae5 100644 --- a/forge-gui-mobile/src/forge/toolbox/FList.java +++ b/forge-gui-mobile/src/forge/toolbox/FList.java @@ -1,11 +1,6 @@ package forge.toolbox; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; @@ -18,6 +13,10 @@ import forge.model.FModel; import forge.screens.FScreen; import forge.util.Utils; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + public class FList extends FScrollPane implements Iterable { public static final float PADDING = Utils.scale(3); public static final FSkinColor FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT); diff --git a/forge-gui-mobile/src/forge/toolbox/FOptionPane.java b/forge-gui-mobile/src/forge/toolbox/FOptionPane.java index 96dbe34a66d..45869375fa4 100644 --- a/forge-gui-mobile/src/forge/toolbox/FOptionPane.java +++ b/forge-gui-mobile/src/forge/toolbox/FOptionPane.java @@ -1,14 +1,9 @@ package forge.toolbox; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; - import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; import com.google.common.collect.ImmutableList; - import forge.Forge; import forge.Graphics; import forge.assets.FImage; @@ -25,6 +20,9 @@ import forge.toolbox.FEvent.FEventHandler; import forge.util.Callback; import forge.util.Utils; import forge.util.WaitCallback; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; public class FOptionPane extends FDialog { public static final FSkinImage QUESTION_ICON = FSkinImage.QUESTION; diff --git a/forge-gui-mobile/src/forge/toolbox/FOverlay.java b/forge-gui-mobile/src/forge/toolbox/FOverlay.java index 7dd5911e493..d65457db31d 100644 --- a/forge-gui-mobile/src/forge/toolbox/FOverlay.java +++ b/forge-gui-mobile/src/forge/toolbox/FOverlay.java @@ -1,13 +1,8 @@ package forge.toolbox; -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.utils.Timer; import com.badlogic.gdx.utils.Timer.Task; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinColor; @@ -16,6 +11,10 @@ import forge.gui.FThreads; import forge.screens.FScreen; import forge.screens.match.MatchController; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + public abstract class FOverlay extends FContainer { public static final float ALPHA_COMPOSITE = 0.5f; private static final Stack overlays = new Stack<>(); diff --git a/forge-gui-mobile/src/forge/toolbox/FProgressBar.java b/forge-gui-mobile/src/forge/toolbox/FProgressBar.java index c4ba558b089..a610fa653ff 100644 --- a/forge-gui-mobile/src/forge/toolbox/FProgressBar.java +++ b/forge-gui-mobile/src/forge/toolbox/FProgressBar.java @@ -1,18 +1,16 @@ package forge.toolbox; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import org.apache.commons.lang3.tuple.Pair; - import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FSkinFont; import forge.gui.interfaces.IProgressBar; import forge.util.Utils; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; public class FProgressBar extends FDisplayObject implements IProgressBar { public static Color BACK_COLOR, FORE_COLOR, SEL_BACK_COLOR, SEL_FORE_COLOR; diff --git a/forge-gui-mobile/src/forge/toolbox/FRadioButton.java b/forge-gui-mobile/src/forge/toolbox/FRadioButton.java index 7488045e387..f4b618d2a4d 100644 --- a/forge-gui-mobile/src/forge/toolbox/FRadioButton.java +++ b/forge-gui-mobile/src/forge/toolbox/FRadioButton.java @@ -1,16 +1,15 @@ package forge.toolbox; -import java.util.ArrayList; -import java.util.List; - import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FImage; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; import forge.util.Utils; +import java.util.ArrayList; +import java.util.List; + public class FRadioButton extends FLabel { private static final FSkinColor INNER_CIRCLE_COLOR = FSkinColor.get(Colors.CLR_TEXT); private static final FSkinColor OUTER_CIRCLE_COLOR = INNER_CIRCLE_COLOR.alphaColor(0.5f); diff --git a/forge-gui-mobile/src/forge/toolbox/FScrollPane.java b/forge-gui-mobile/src/forge/toolbox/FScrollPane.java index 2f6dde5199a..2cd7316fefb 100644 --- a/forge-gui-mobile/src/forge/toolbox/FScrollPane.java +++ b/forge-gui-mobile/src/forge/toolbox/FScrollPane.java @@ -1,9 +1,6 @@ package forge.toolbox; -import java.util.List; - import com.badlogic.gdx.math.Vector2; - import forge.Graphics; import forge.animation.ForgeAnimation; import forge.assets.FSkinColor; @@ -12,6 +9,8 @@ import forge.model.FModel; import forge.util.PhysicsObject; import forge.util.Utils; +import java.util.List; + public abstract class FScrollPane extends FContainer { private static final float FLING_DECEL = 750f; private static final FSkinColor INDICATOR_COLOR = FSkinColor.get(FSkinColor.Colors.CLR_TEXT).alphaColor(0.7f); diff --git a/forge-gui-mobile/src/forge/toolbox/FTextArea.java b/forge-gui-mobile/src/forge/toolbox/FTextArea.java index fe1e02c47d8..6bdf9cd5992 100644 --- a/forge-gui-mobile/src/forge/toolbox/FTextArea.java +++ b/forge-gui-mobile/src/forge/toolbox/FTextArea.java @@ -2,7 +2,6 @@ package forge.toolbox; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinFont; diff --git a/forge-gui-mobile/src/forge/toolbox/FTextField.java b/forge-gui-mobile/src/forge/toolbox/FTextField.java index 6510cc32fd5..428f9418ddd 100644 --- a/forge-gui-mobile/src/forge/toolbox/FTextField.java +++ b/forge-gui-mobile/src/forge/toolbox/FTextField.java @@ -2,7 +2,6 @@ package forge.toolbox; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.utils.Align; - import forge.Forge; import forge.Forge.KeyInputAdapter; import forge.Graphics; diff --git a/forge-gui-mobile/src/forge/toolbox/FToggleSwitch.java b/forge-gui-mobile/src/forge/toolbox/FToggleSwitch.java index e65c4697b39..fabff813983 100644 --- a/forge-gui-mobile/src/forge/toolbox/FToggleSwitch.java +++ b/forge-gui-mobile/src/forge/toolbox/FToggleSwitch.java @@ -1,7 +1,6 @@ package forge.toolbox; import com.badlogic.gdx.utils.Align; - import forge.Graphics; import forge.assets.FSkinColor; import forge.assets.FSkinColor.Colors; diff --git a/forge-gui-mobile/src/forge/toolbox/GuiChoose.java b/forge-gui-mobile/src/forge/toolbox/GuiChoose.java index 04cb896d927..cb8797007f9 100644 --- a/forge-gui-mobile/src/forge/toolbox/GuiChoose.java +++ b/forge-gui-mobile/src/forge/toolbox/GuiChoose.java @@ -1,20 +1,13 @@ package forge.toolbox; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import forge.Forge; -import org.apache.commons.lang3.StringUtils; - import com.google.common.base.Function; import com.google.common.collect.Iterables; - +import forge.Forge; import forge.game.card.CardView; import forge.util.Callback; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; public class GuiChoose { diff --git a/forge-gui-mobile/src/forge/toolbox/GuiDialog.java b/forge-gui-mobile/src/forge/toolbox/GuiDialog.java index dbc1605c654..657c058d8f4 100644 --- a/forge-gui-mobile/src/forge/toolbox/GuiDialog.java +++ b/forge-gui-mobile/src/forge/toolbox/GuiDialog.java @@ -1,13 +1,11 @@ package forge.toolbox; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; - import com.google.common.collect.ImmutableList; - import forge.game.card.CardView; import forge.util.Callback; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; /** * Holds player interactions using standard windows diff --git a/forge-gui-mobile/src/forge/toolbox/ListChooser.java b/forge-gui-mobile/src/forge/toolbox/ListChooser.java index 5f0e0359ec9..ad7d8c39204 100644 --- a/forge-gui-mobile/src/forge/toolbox/ListChooser.java +++ b/forge-gui-mobile/src/forge/toolbox/ListChooser.java @@ -18,16 +18,11 @@ package forge.toolbox; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; - import forge.Forge; import forge.Graphics; import forge.assets.FSkinFont; @@ -43,6 +38,10 @@ import forge.toolbox.FEvent.FEventHandler; import forge.util.Callback; import forge.util.Utils; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + /** * A simple class that shows a list of choices in a dialog. Two properties * influence the behavior of a list chooser: minSelection and maxSelection. diff --git a/forge-gui-mobile/src/forge/util/LibGDXImageFetcher.java b/forge-gui-mobile/src/forge/util/LibGDXImageFetcher.java index 271cca37605..09c2cde8026 100644 --- a/forge-gui-mobile/src/forge/util/LibGDXImageFetcher.java +++ b/forge-gui-mobile/src/forge/util/LibGDXImageFetcher.java @@ -1,5 +1,9 @@ package forge.util; +import com.badlogic.gdx.files.FileHandle; +import forge.Forge; +import forge.gui.GuiBase; + import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -7,11 +11,6 @@ import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; -import com.badlogic.gdx.files.FileHandle; - -import forge.Forge; -import forge.gui.GuiBase; - public class LibGDXImageFetcher extends ImageFetcher { @Override protected Runnable getDownloadTask(String[] downloadUrls, String destPath, Runnable notifyObservers) { diff --git a/forge-gui/res/adventure/Shandalar/world/black.json b/forge-gui/res/adventure/Shandalar/world/black.json index 9a9c1d7f76f..5413ac49ede 100644 --- a/forge-gui/res/adventure/Shandalar/world/black.json +++ b/forge-gui/res/adventure/Shandalar/world/black.json @@ -1,37 +1,145 @@ { - "startPointX": 0.70, - "startPointY": 0.78, - "name": "black", - "noiseWeight": 0.5, - "distWeight": 1.5, - "tilesetName":"Black", - "tilesetAtlas":"world/tilesets/terrain.atlas", - "terrain":[ - { - "spriteName":"Black_1", - "min": 0, - "max": 0.2, - "resolution": 10 - },{ - "spriteName":"Black_2", - "min": 0.8, - "max": 1.0, - "resolution": 10 - } - ], - "width": 0.7, - "height": 0.7, - "color": "110903", - "spriteNames":[ "SwampTree","SwampTree2","DarkGras","Skull","SwampRock","DarkWood","Reed","Waterlily","Shroom","Shroom2"] , - "enemies":[ "Beholder","Big Zombie","Black Wiz1","Black Wiz2","Black Wiz3","Dark Knight","Death Knight","Demon","Ghoul","Ghost","Harpy","Harpy 2","High Vampire","Lich","Rakdos Devil","Skeleton","Skeleton Soldier","Vampire","Zombie","Zombie Lord" ] , - "pointsOfInterest":[ - "Black Castle", - "Swamp Town","Swamp Town2", - "Zombie Town", - "Graveyard", "Graveyard1", "Graveyard2", "Graveyard3", "Graveyard4", - "VampireCastle", "VampireCastle1", "VampireCastle2", - "EvilGrove", "EvilGrove1", "EvilGrove2", "EvilGrove3", "EvilGrove4", - "SkullCaveB", "SkullCaveB1", "SkullCaveB2", - "CaveB", "CaveB1", "CaveB2", "CaveB3", "CaveB4", "CaveB5", "CaveB6", "CaveB8", "CaveBA" - ] +"startPointX": 0.7, +"startPointY": 0.78, +"noiseWeight": 0.5, +"distWeight": 1.5, +"name": "black", +"tilesetAtlas": "world/tilesets/terrain.atlas", +"tilesetName": "Black", +"terrain": [ + { + "spriteName": "Black_1", + "max": 0.2, + "resolution": 10 + }, + { + "spriteName": "Black_2", + "min": 0.8, + "max": 1, + "resolution": 10 + } +], +"width": 0.7, +"height": 0.7, +"color": "110903", +"spriteNames": [ + "SwampTree", + "SwampTree2", + "DarkGras", + "Skull", + "SwampRock", + "DarkWood", + "Reed", + "Waterlily", + "Shroom", + "Shroom2" +], +"enemies": [ + "Beholder", + "Big Zombie", + "Black Wiz1", + "Black Wiz2", + "Black Wiz3", + "Dark Knight", + "Death Knight", + "Demon", + "Ghoul", + "Ghost", + "Harpy", + "Harpy 2", + "High Vampire", + "Lich", + "Rakdos Devil", + "Skeleton", + "Skeleton Soldier", + "Vampire", + "Zombie", + "Zombie Lord" +], +"pointsOfInterest": [ + "Black Castle", + "Swamp Town", + "Swamp Town2", + "Zombie Town", + "Graveyard", + "Graveyard1", + "Graveyard2", + "Graveyard3", + "Graveyard4", + "VampireCastle", + "VampireCastle1", + "VampireCastle2", + "EvilGrove", + "EvilGrove1", + "EvilGrove2", + "EvilGrove3", + "EvilGrove4", + "SkullCaveB", + "SkullCaveB1", + "SkullCaveB2", + "CaveB", + "CaveB1", + "CaveB2", + "CaveB3", + "CaveB4", + "CaveB5", + "CaveB6", + "CaveB8", + "CaveBA" +], +"structures": [ + { + "N": 2, + "x": 0.5, + "y": 0.5, + "structureAtlasPath": "world/tilesets/structures.atlas", + "sourcePath": "world/tilesets/swamp_forest.png", + "maskPath": "world/tilesets/ring.png", + "height": 0.4, + "width": 0.4, + "symmetry": 8, + "periodicOutput": false, + "mappingInfo": [ + { + "name": "swamp_forest", + "color": "007000", + "collision": true + }, + { + "name": "swamp_water", + "color": "005050", + "collision": true + } + ] + }, + { + "N": 2, + "x": 0.5, + "y": 0.5, + "structureAtlasPath": "world/tilesets/structures.atlas", + "sourcePath": "world/tilesets/swamp_ruins.png", + "maskPath": "world/tilesets/circle.png", + "height": 0.20000002, + "width": 0.20000002, + "symmetry": 1, + "periodicOutput": false, + "mappingInfo": [ + { + "name": "deep_swamp", + "color": "002000", + "collision": true + }, + { + "name": "structure", + "color": "505050", + "collision": true + }, + { + "name": "swamp_forest2", + "color": "007000", + "collision": true + } + ] + } +] } \ No newline at end of file diff --git a/forge-gui/res/adventure/Shandalar/world/blue.json b/forge-gui/res/adventure/Shandalar/world/blue.json index bb8fc0927ec..fafce7a20d8 100644 --- a/forge-gui/res/adventure/Shandalar/world/blue.json +++ b/forge-gui/res/adventure/Shandalar/world/blue.json @@ -1,38 +1,126 @@ { - "startPointX": 0.79, - "startPointY": 0.43, - "name": "blue", - "noiseWeight": 0.5, - "distWeight": 1.5, - "tilesetName":"Blue", - "tilesetAtlas":"world/tilesets/terrain.atlas", - "terrain":[ - { - "spriteName":"Blue_1", - "min": 0, - "max": 0.2, - "resolution": 10 - }, { - "spriteName":"Blue_2", - "min": 0.8, - "max": 1.0, - "resolution": 10 - } - ], - "width": 0.7, - "height": 0.7, - "color": "10a2e0", - "spriteNames":["IslandTree" ,"Coral" ,"Shell" ], - "enemies":[ "Bird","Djinn","Elemental","Merfolk","Merfolk Avatar","Merfolk Fighter","Merfolk Lord","Merfolk Soldier","Merfolk warrior","Blue Wiz1","Blue Wiz2","Blue Wiz3","Geist","Rogue","Sea Monster","Tarkir Djinn","Doppelganger" ] , - "pointsOfInterest":[ - "Blue Castle", - "Island Town", - "NestU", - "MerfolkPool", "MerfolkPool1", "MerfolkPool2", "MerfolkPool3", "MerfolkPool4", - "DjinnPalace", "DjinnPalace1", - "Factory", "Factory1", - "MageTowerX", - "MageTowerU", "MageTowerU1", "MageTowerU2", "MageTowerU3", "MageTowerU4", "MageTowerU5", "MageTowerU6", "MageTowerU7", "MageTowerUD", - "CaveU", "CaveU1", "CaveU2", "CaveU3", "CaveU4" - ] +"startPointX": 0.79, +"startPointY": 0.43, +"noiseWeight": 0.5, +"distWeight": 1.5, +"name": "blue", +"tilesetAtlas": "world/tilesets/terrain.atlas", +"tilesetName": "Blue", +"terrain": [ + { + "spriteName": "Blue_1", + "max": 0.2, + "resolution": 10 + }, + { + "spriteName": "Blue_2", + "min": 0.8, + "max": 1, + "resolution": 10 + } +], +"width": 0.7, +"height": 0.7, +"color": "10a2e0", +"spriteNames": [ + "IslandTree", + "Coral", + "Shell" +], +"enemies": [ + "Bird", + "Djinn", + "Elemental", + "Merfolk", + "Merfolk Avatar", + "Merfolk Fighter", + "Merfolk Lord", + "Merfolk Soldier", + "Merfolk warrior", + "Blue Wiz1", + "Blue Wiz2", + "Blue Wiz3", + "Geist", + "Rogue", + "Sea Monster", + "Tarkir Djinn", + "Doppelganger" +], +"pointsOfInterest": [ + "Blue Castle", + "Island Town", + "NestU", + "MerfolkPool", + "MerfolkPool1", + "MerfolkPool2", + "MerfolkPool3", + "MerfolkPool4", + "DjinnPalace", + "DjinnPalace1", + "Factory", + "Factory1", + "MageTowerX", + "MageTowerU", + "MageTowerU1", + "MageTowerU2", + "MageTowerU3", + "MageTowerU4", + "MageTowerU5", + "MageTowerU6", + "MageTowerU7", + "MageTowerUD", + "CaveU", + "CaveU1", + "CaveU2", + "CaveU3", + "CaveU4" +], +"structures": [ + { + "x": 0.5, + "y": 0.5, + "structureAtlasPath": "world/tilesets/structures.atlas", + "sourcePath": "world/tilesets/water.png", + "maskPath": "world/tilesets/circle.png", + "height": 0.20000002, + "width": 0.20000002, + "symmetry": 8, + "periodicOutput": false, + "mappingInfo": [ + { + "name": "water", + "color": "0070a0", + "collision": true + }, + { + "name": "island_forest", + "color": "00a000", + "collision": true + } + ] + }, + { + "x": 0.5, + "y": 0.5, + "structureAtlasPath": "world/tilesets/structures.atlas", + "sourcePath": "world/tilesets/island_forest.png", + "maskPath": "world/tilesets/ring.png", + "height": 0.4, + "width": 0.4, + "symmetry": 8, + "periodicOutput": false, + "mappingInfo": [ + { + "name": "water", + "color": "0070a0", + "collision": true + }, + { + "name": "island_forest", + "color": "00a000", + "collision": true + } + ] + } +] } \ No newline at end of file diff --git a/forge-gui/res/adventure/Shandalar/world/green.json b/forge-gui/res/adventure/Shandalar/world/green.json index 644004f6b77..cf577f13624 100644 --- a/forge-gui/res/adventure/Shandalar/world/green.json +++ b/forge-gui/res/adventure/Shandalar/world/green.json @@ -91,17 +91,18 @@ ], "structures": [ { + "N": 2, "x": 0.5, "y": 0.5, "structureAtlasPath": "world/tilesets/structures.atlas", - "sourcePath": "world/tilesets/forestSource.png", - "height": 0.3, - "width": 0.3, + "sourcePath": "world/tilesets/forest.png", + "maskPath": "world/tilesets/circle.png", + "height": 0.20000002, + "width": 0.20000002, "symmetry": 1, - "periodicOutput": false, "mappingInfo": [ { - "name": "Forest", + "name": "forest", "color": "007000", "collision": true } @@ -109,21 +110,22 @@ }, { "N": 2, - "x": 0.3, - "y": 0.3, + "x": 0.5, + "y": 0.5, "structureAtlasPath": "world/tilesets/structures.atlas", - "sourcePath": "world/tilesets/lakeSource.png", - "height": 0.3, - "width": 0.3, + "sourcePath": "world/tilesets/lake.png", + "maskPath": "world/tilesets/ring.png", + "height": 0.4, + "width": 0.4, "periodicOutput": false, "mappingInfo": [ { - "name": "Lake", + "name": "lake", "color": "0070a0", "collision": true }, { - "name": "Forest2", + "name": "forest2", "color": "009000", "collision": true } diff --git a/forge-gui/res/adventure/Shandalar/world/red.json b/forge-gui/res/adventure/Shandalar/world/red.json index b91c3da9f19..9cb469cdd20 100644 --- a/forge-gui/res/adventure/Shandalar/world/red.json +++ b/forge-gui/res/adventure/Shandalar/world/red.json @@ -1,39 +1,144 @@ { - "startPointX": 0.31, - "startPointY": 0.78, - "name": "red", - "noiseWeight": 0.5, - "distWeight": 1.5, - "tilesetName":"Red", - "tilesetAtlas":"world/tilesets/terrain.atlas", - "terrain":[ - { - "spriteName":"Red_1", - "min": 0, - "max": 0.2, - "resolution": 10 - },{ - "spriteName":"Red_2", - "min": 0.8, - "max": 1.0, - "resolution": 10 - } - ], - "width": 0.7, - "height": 0.7, - "color": "b63729", - "spriteNames":[ "MountainTree","MountainTree2","MountainRock","LargeMountainRock","Gravel"] , - "enemies":[ "Amonkhet Minotaur","Ashmouth Devil","Axgard Dwarf","Berserker","Boggart","Cyclops","Devil","Dinosaur","Dragon","Dwarf","Efreet","Fire Elemental","Flame Elemental","Goblin","Goblin Chief","Goblin Warrior","Hellhound","Immersturm Demon","Khan","Minotaur","Minotaur Flayer","Red Beast","Red Wiz1","Red Wiz2","Red Wiz3","Shaman","Troll","Vampire Lord","Viashino","Yeti" ] , - "pointsOfInterest":[ - "Red Castle", - "Mountain Town", - "YuleTown", - "BarbarianCamp", "BarbarianCamp1", "BarbarianCamp2", - "Maze", "Maze1", "Maze2", "Maze3", - "Fort", "Fort5", - "Factory", "Factory2", "Factory3", - "SnowAbbey", "SnowAbbey1", "SnowAbbey2", - "SkullCaveR", "SkullCaveR1", "SkullCaveR2", - "CaveR", "CaveR1", "CaveR2", "CaveR3", "CaveR4", "CaveR5", "CaveR6", "CaveR7", "CaveR8", "CaveR9", "CaveRA", "CaveRB", "CaveRC", "CaveRE", "CaveRG", "CaveRH", "CaveRJ" - ] +"startPointX": 0.31, +"startPointY": 0.78, +"noiseWeight": 0.5, +"distWeight": 1.5, +"name": "red", +"tilesetAtlas": "world/tilesets/terrain.atlas", +"tilesetName": "Red", +"terrain": [ + { + "spriteName": "Red_1", + "max": 0.2, + "resolution": 10 + }, + { + "spriteName": "Red_2", + "min": 0.8, + "max": 1, + "resolution": 10 + } +], +"width": 0.7, +"height": 0.7, +"color": "b63729", +"spriteNames": [ + "MountainTree", + "MountainTree2", + "MountainRock", + "Gravel" +], +"enemies": [ + "Amonkhet Minotaur", + "Ashmouth Devil", + "Axgard Dwarf", + "Berserker", + "Boggart", + "Cyclops", + "Devil", + "Dinosaur", + "Dragon", + "Dwarf", + "Efreet", + "Fire Elemental", + "Flame Elemental", + "Goblin", + "Goblin Chief", + "Goblin Warrior", + "Hellhound", + "Immersturm Demon", + "Khan", + "Minotaur", + "Minotaur Flayer", + "Red Beast", + "Red Wiz1", + "Red Wiz2", + "Red Wiz3", + "Shaman", + "Troll", + "Vampire Lord", + "Viashino", + "Yeti" +], +"pointsOfInterest": [ + "Red Castle", + "Mountain Town", + "YuleTown", + "BarbarianCamp", + "BarbarianCamp1", + "BarbarianCamp2", + "Maze", + "Maze1", + "Maze2", + "Maze3", + "Fort", + "Fort5", + "Factory", + "Factory2", + "Factory3", + "SnowAbbey", + "SnowAbbey1", + "SnowAbbey2", + "SkullCaveR", + "SkullCaveR1", + "SkullCaveR2", + "CaveR", + "CaveR1", + "CaveR2", + "CaveR3", + "CaveR4", + "CaveR5", + "CaveR6", + "CaveR7", + "CaveR8", + "CaveR9", + "CaveRA", + "CaveRB", + "CaveRC", + "CaveRE", + "CaveRG", + "CaveRH", + "CaveRJ" +], +"structures": [ + { + "N": 2, + "x": 0.5, + "y": 0.5, + "structureAtlasPath": "world/tilesets/structures.atlas", + "sourcePath": "world/tilesets/mountain.png", + "maskPath": "world/tilesets/ring.png", + "height": 0.4, + "width": 0.4, + "periodicOutput": false, + "mappingInfo": [ + { + "name": "mountain", + "color": "a07020", + "collision": true + }, + { + "name": "mountain_forest", + "color": "007000", + "collision": true + } + ] + }, + { + "x": 0.5, + "y": 0.5, + "structureAtlasPath": "world/tilesets/structures.atlas", + "sourcePath": "world/tilesets/lava.png", + "maskPath": "world/tilesets/circle.png", + "height": 0.2, + "width": 0.2, + "mappingInfo": [ + { + "name": "lava", + "color": "ff5000", + "collision": true + } + ] + } +] } \ No newline at end of file diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/circle.png b/forge-gui/res/adventure/Shandalar/world/tilesets/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..73f7a8e663b4a8a62f0a2a487fcad53cf65edeb5 GIT binary patch literal 9611 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 literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/deep_swamp.png b/forge-gui/res/adventure/Shandalar/world/tilesets/deep_swamp.png new file mode 100644 index 0000000000000000000000000000000000000000..a97692a24ae4287fe208a2411d74fd72ea34848f GIT binary patch literal 11197 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 literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png b/forge-gui/res/adventure/Shandalar/world/tilesets/forest.png index cf8dd71e0c9d2cb2327c33398a99d087c459cf34..8bcd553e6637b317a70fd1a58a6cab279ef09458 100644 GIT binary patch delta 1766 zcmY+FeKb`0AIE1%#$?heQf#I%WO120_ujepPUM*oStcfOn7K0(swGm1OjsfnHS3{L zi8?|_rVZ74Xg#b|5m{}Xl73iuDngrw-_)Mpp7Z;h^Zk6z_jAtc{du3yAK&l!MDnlZ z(o|0mXBu@Ql|&-ZT(&!SDJtd5p{!KodX4Hd5=ohLjK@FZB{)J4j|h{5>=)AyMTd*& z;-euF66xrx@ofL{L1Xpg{@o2`b?4V;whRc1C93j;Pj?RvF}L()&P3;omMY)fOn)~^ z_ISM1+HbIs^w_~aCG<*!tFF}b2^eYHR3ZOq(8J$yVsF*ZNStMlk&b2_l-su9nQMdSR4B#i;mTg%-k@xaC|(x0#Nyn`aZWm#|cW5b@#`G4aIlb zMv-E-`GFW%bjNgzGHuS(onXXr>C&!(@wo8YRg*;)CUzB-GWz604`V~>?ZQ*VGyN`f)!_KNe5*P7 z?m%h=BgY4`S5nGL4zNw-5F7@xoqV%4D(g3`727kn=Dsz4=_qY{)&XwDu^u9la4|@g4Z6fPBRFrP;O1+3qPw$^ck*@Z#Sik+RyyQbbMSGQ7)2HX& z6%$r-8it)DvN`w zv?nXy-#Nc(ZSSSG+ahC}Znt)MZcVxTFx)6=?bx>8)*X(WD&6~cPqM!Iqwb}lQyIjz z2T|yCUZ4*%X8fIPx^m6RCB5{xp}O_Zvy-w2xLMk;q9hs`)1A4W8Z@{Y}O- z?#~R9H^#fn5|Y||f;;Qpwp#?ZXWXmAsHG~Z*4ibj&7VEsR#FpQtELplWcg`7&DUIS zV>BiX#yxsCR~e&9c}n$udPU8qGt|js(^`4euIF=9>%Z63Vhl~_qr)*!x$AwDhDP9I zzGcf|&((s!=1b~RDfN*%q-bcpZas7fxjen?U`i%4X+9SdwyC7*SD9~JXsimB*FyGA zM#xS*hIU$j*%8omgUNgNApd*h_x0tgO>---l1%QtepwAGr^}~(Pa&RwWo6iCGDI)F zcTzzdLOQpD=kgbG(xfkEw=^5dO4Oass_?Gal`p=QPCfLOvk>WDOclarGEIE^v{H3I zUT4{@Nunk6GO2IxYu9)4CGJ79vKc4mRr+M*?%IYZXW86|mT!YbT(Z@hvmU`ocI2bh z1!2FF6Dw?jp8j?Fm-G%*x_to9Pf|Tu%Rg7%70@?6IWgW3jW5NKO4=f-TSL}`kx1V> z4^g~beD@t(B20eW;)D_t6LN$CjDrCn4zmE5kYIq~#sLTf7Kk7S0!0WR+s-bc;V2H_ z2*P6H91bj7V*fzHxGWA2M7Ri>3n8*-X!HMfHu1jGqIBt|6w41)xK zvvC2yVG}|QE+HfW9FpyVchJ}v4}`dEl#8GY3t1~f7+?Y%M{pK^2_-lHizH$|hze0a zgtCMz0%L-$at`u z1_rPY9*A;5kPBn~uuOuD5->+31lU4_YghmZ0Rbuj0gMHSFcBM+5FCkOtm_x}>jqfZ zzk``#Ow19Y5CI556jgXeF+iXQg@OPPqZok^#23%5wEw|h*C)RP2UAw?mowMPOsw>G zQ&!So1B$cnjN;e9TpVn9IvvEq^768DrR52g#vn7%kE@m@oks+A*$%@HxQ4{nqWjlT nBAHM4In2|oDNolktH`9!@3jN&s`gz~XpmeSJse8yf)f4<&1C7L delta 13511 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 CrHKIm diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/hole.png b/forge-gui/res/adventure/Shandalar/world/tilesets/hole.png new file mode 100644 index 0000000000000000000000000000000000000000..0f9cd1e0e0523e9db031628b383661acf858eb9c GIT binary patch literal 10184 zcmeHtc{tSF`@c1z%}xk|B4%IA46^T8LS-q8S(xlIgRz$g5oJlqzC@8VEl9~O9&Lys zWhco_lHXfB>-GCy*Y|p^@ALWm^~`qO?{n_+I``{!-{;Jkb4`qenZa(J{X8rzEW3>i zbuEE%&-Q!g4&YPD5d4CLMIb29+J<3C@R#>5}W&2fc;K)o!{ylqm1KxUDd0_!pdB*$!;&M zkmcTyl#s3ZfaMe3tNXT`N0)*_H|i_qADw)?lvOIxvDpz45{AFgebJ!=y0w}~p2_Uj z2M{t8n&`*MQ7 zWwOgtEH&W6J8y^g%13IaFNkb$2E3WAEDQZ;I}ufr(HU6UJWZZK$2r{b9;1p)D<|2; z#D;}j3)_4;l*rTTFh*7C9ZMIzL5`jnRcZVZJ$V0E-u|_D<|g0cKsC|kjzo}9;|fwQ zVTGN$4nKf|EdnI_2+a3BJx`Qt$V~Z*n6X$1`Pg*7q#xfd` z^!kMkrH(80Pg{scdWjElb$-!ZirJ;aEc#Hg4>X^oBXhxS3Em`X)mhQB-+nwG)BFrD6xzW>ogp&~!gM6vqr^ldH_(G=Zh>E?0C4MXt^u7zh;f3BI!F?eOw z{b*_6t#q)ys89YC12NybQ#Z4QTaO~U5i{=3AllSOp_6t2DaTK~jTl&=L`nJ&1f-t! z4+@<1o4Mbr!R#7xpie7`UCVM98BCY5vN@NeaHNr7%@^BR_2BGTzmHYLZ}z1#&4T@o z8=TN>1?8=|+s%s}*!8UD!EB>{i)6yZiSM$HuS?Xgb!|GTyEOT3O+K6p4VtJ{B)b;1 znh9S#1~p%S-+cJ=acn>fgy=cs3tx{eHXO)o>$#8DN zn_L`y)S-L_>i)oO=KY0WF`0ssz00%x-)Z>wSJbs^5b>>c77v4ci}fNLLv?=Rfo>m@L*-Y-EYUS6Zyhdri0!V zN1?>@FJ9KT)#qFN3rAk}bDCF0RW@lnEflPc`Q=4#NscPW_;RVkP=dtCYY#E*(snL^M}6+Rl49rcriWqdW3{gC%O85+?H9~+E!={VeRsy}yb|{G^^nHI zvE^csTW#UZ7e2UqTVHmbvrH3x&hk!A!(r@NO-=BWh=Nq3Ud8$z50PCIH=^_S!|9Ui z+!tO;A$$+ARVGvfMHBm`*lw8Rlz&vOnJrEE5S=7n>X02VKHOt@;NztCX%{kol-w-j z(Yo)Y#hcGwRle?T9#&3JZW&S{WIXH^Q9mlzIjrsYijrGYi|Z`vWedC^)I7_A7D>EA zG9k{C-bpk2gm?c;@4hD=Gi11D)naq<4P?1EEycKp!LIAVDg|%m5fSen`VJ3lsyLC; zva7x>y{{>~MqN8PLOCOP^)y!sb{t>onre1WTe1V2D;J4Ot*^m-0wPmUrCS)ADZD?al_bOQQEcUz0_4qvw&Z4- zPFSi-<&njp%&wveHH>0{N&Dn+8|lcHy~1~Q)-p@1YS_emTc&8Mx3RgMiaTE4lH<7< zF0Qbj$gA7mb5O!*_U9{fXXaJ{Wh5{4Y0ICPrSFl$jw~O%l%}#6~N2liyr+ zhyv5)pVGgpWvqW(x@UM_>nr$NP3NeO@`K}&g5oN}#>`-Bx#ivYw9;gU;If82RYfvX zUU{a8eEl(AFCVRfa-FwMnvjNOKT*l+Jzq=E0?)oQM8Ykrn`bY^i$C?BVQD^@$Yb55#pMXe(|^;bKgP#iTNZ-y?XqYaj-a@XG0&;|>^Ch1L^k z%bQN$=9g!uuhCok;k`Wv|}iKHp2 zZCq|M7v$GAdlAtX#M61Ur;Qw>QvpP zfPi}UxB!|n?^V6h1%1vN4@R_i3|^7(nWv<$V=T`5u$6oetRtgg1-ZPOVBPz#7yIDj zzWWZ?Ys_gumgD@faV@o)p78It*ZIC2N=(R$Ci)6qzH_Xzm;PPPQuHFVxa3Z0qWxuX zUOubB$H(V|t9U}n2#ubH)viZ4%8f9n{E-}qbIq56(XS$I8g;k(GboP;pik@qD%v{X zOv0lttR`LR5d?FYUEC)|(D8;4@FJ|kdZJQ5X~$*gGF#lv8Lzwo!E>P^LHVRFoVlWG zlAIBPDPRZLxIQUo4tDl&dh0`l&_1Ur4vdkbhkS<)*C3#y(?ASnEU3&!U_9uhG4F6%gO~J$<#x%QfIoEI3OON{8KMOf37R|A;7lK=bWG`De^%QWEuSx3?QrH+ zS7<$#p15lYk{#DoCAu>iS3#`h8SSkYnr+FFSRk;U`^I$nqFxJCW4{TX38;q z%uYe?Ec8(*mZR5$ronM`r(-fEycJe*~w-@`7`6hs1-?VyQ}<` z#+w-9+V}18d$0Qxb7`(kM)~h=yq>jVkY7h5XgbPX-B3QXM|8Z8pivyVH|4`GC*oK* zUBl)bH&4WSUpM%W_qD)0TqrX1vn2t}BsG>#FjSYsBGVFYUZ@j3Rfg$442mDtG0Z-Y z*36r)u`U-=z`w9ypxNPfy51gfo1Gvl+>qA3#JO^nqvzQjLoF}Q>N+b~{?sMZ>C)cn z{E%LJjZ!WMd6>q7Uv8%E?N<(o zpd7JYywZB6A)V7yBM>y;&-Bw>+B7g9tspMuT<;#51H0{fB9e?Y<~G5{gZ%Ddq}` zoSWp<%jFWvZO|$0x|*(^prfZ54nHBk@2;d#!3H-2WJ#O#7;P=D*U&w7U(W|a*p_=Ox_GN>;bINNB`>wh3 z-!pU5Rwb4t^+HOPMdy`SWQTZR;5HtKguNz@_k0!23)+lvdF)oV74&|v&g*9pxUe=H z!3QbdD?;+s`ZiivM(mu>+FwzoK3Cm)zcH%yJHtQCXDArnaD#PX_ycZM^11S+yu+ot zlaA-VZj_tng=PzkYiNXFvu>14?5*2vmps6FvzYaa*|dH48rttUo9SM?(wL`G5+%=d zILuXg4OLf;d3=8zpIOsx(3b*VjC%u7X5AXg7T$PaaD0JwQ!T{0{&vAIgjdD*v7dEU zRl#)DGt0W*t6I&^ps|5(cVeV6oHVTkg;7Y}DT6&OIX+Y4?6>c^?~x0atm^jbGHXtz z^E=oGM@>5RjuW{I`crT*qk{wbyO1raaA@;%A0n)!&D zdnqY|8O2L5w#C_G{i27($2Xj<;wLSRJ#D_SsqOVRQ#3?E^!nDPrpb{fZFQ>fk8~yc zYSFH4wp5g@MwU=q+R2{bcP#pK7uwB6=+b(*gBF8{6I5S~>Ck!q!TTRdH{fkCXNw+| zzY589x>_V_ctcSCEZ&qfASmV}Gv+G$a4?r?ycT>o=l&sB{RX}0 zea*8IEm2cS+6d_byJIGJ7kc=?)J@hefBUtFs>5&ut3#~8ui!2naKW806 zC5UZRar>hLl#4_eAQ2Wl`@rV(7qK|S#fp&&+N?%KUzNdjCJ~gA!ICezInw_;a2szMk7%AMb6!ubV!x1UDxgHbMi9PA7m=*y5d}l3C|&a*4b1=DeQ;B`zbF`76qt zwx4;gH|Ao}Tcz&p3OhF10K-{ZmTUyy_RpF!g4&xccS2hO19r_C4{e5J_wunTA2`kg zKab{RkE*Y=P8X9qkfyk=QFlb%r5Glj?NF;RXD(4MiCs(E{r2;>5!ILH)LpXKs|R1S zs}q(%!%%Ng%QQKEPKd{&izyd-W_!x}It2~;A05DMeaOy^a1^?T<0p4LNl8jMHKH0R zm*x~8+{biEFt)lnM=R9M7<(6YJs%t&m}&YTbNzABqq6StRo2Im*}B=*kC83k)C~9E zNHjFZhsn#&lpePA((bhiii6EXO=e)H%n#XTk@Ew*gM1qfi9J-aICM#aIzRqqan~vC z$~0x4or8tnRT&H;(TAWuUh~GlA}x=RBYugCC#Z)jL)86f8=qBQ>trs9b6pqNOTboo z+2*tx1tFbZqJzt=;@8ezZaU85tj^f)G|p2H>1zGqZs?V3Q#`5Zs#j!b8x1*6{pss3 z?CQmzJ)Ow{6?A}2NG4XSi4BH$$U5S_)j|7o^Rk>O zLc`N&_`{1!vKiemTSivYmgDO4S;nWEic3auiq=7o z&g(8z{W_w6+uuKaU)G9xuVr(iVtT~7=UdNL$JO~$Lxg+Irxzc?Mdtp(UL;gA;aH*^?BKJXOjtoRY zVHnqQc@QYxXSiQ8HxLi=shoecSUz6Lw>o&#rJZLBDBO$PciE0ekM4QC`^*tG;Y)QK zW5zTBOLckoLI0(~ay>!gys)@6!TkFV0*oz%R07$rZ3gdg8%pOI6oj~zS=sY|_~*+$Kg59}2H6D7O`9vzl3-^6~6IzkHE|OHUsaOEj{Flx?!WHM6;t+b%C|SC+UxubMV!m z!ygrnD~CtEJmK2YF!~be`ttJK2Uwm`PA(1M;ysXGYVZ$u!iTw{^OBNsW0Th&=RXIv zoF56Tt6hB%#I>`F$EqunTeIhk{^0`xRS%E9Smn|9y6*`V#E)Fo4TQ7z&HL`%>o}LI z_H6TAR-R+~ja^@&o9IVX&NPWPA#b2F7LWKur^rRFrDL6+bH+$Lgs6UNdFWd81gWEc z5N$325{^Bs>?0xj}l&SN$Z>jzh~i!dSY{>vhVcJ?A+(s_sH4rp)AGEY4zPyK_DP} zFQ~w|sEz4SJkiSoLLhlLlOaqGZ{XaNg+)z+=}jQIkr~p?WEZNZI%ux;F-V$9QU{$x zo5D=Jb;zz%!$2C@D$vZD80bdCkw6+pc+{A90KkLHAV@Pk+&$@draI^cE*`kvu7-l7 zf0!`b)Im0;7ScLiG_o`bf`Y)ndQ7Sx0(68&T8&1c;4O9ae}w?<)IqKchBqDx_4oIO z_#+`+G#4lwhr>Z(2q*#p1}wnz08a*i3HGGRZbSUU&?VD}G^#g)>g6fDjY)9!@@1%l zKtQ|nZ~l3Bo0|R(?@9kv1waodli&@7Lts!359ptJ&>4Du0LZTn{f|B9*1+*H)RIj1 z@}&{UdVXY2hU}jqNW|a!d;8Mdf6yTjp=5Wm2VhDEMuq=nNCP8Ni{E=}OW;EF@cz*Y z5c@Bd3@YUhvHs%QcFPYse|7}u{yXkptbgPF!x*qKHO1?C5q-DaGtyNDZI6#9c@e23 z{EtgC2~L8cF=Q}`0)v53L=qfKK%(Jb6*Qbc!5~Q#G7SAEC?iiggWyRdZ$km#5GsH} zAY#b`EYcZFCSed@6at3;JF6flU@Q?qLQu#g5}Jto6NEX93S=e0{m)))Ly-U|oC*xU zA|t>EBEcDqf+L*41Qikjj3gi_L=pvqKoU?tph!f#z8B4d0ECn3L2w~My**uiG;9lw z*Rn8D2O%J^KWZ%82@DF*0hj|+Pm-5E{f{PVst4JMLD<$4jzQy8a5xM~1%ra4aqvHk zPLOGIAQ!h$;V=ji@uOusFnE9tAT41#QvrY<^#B{Z4vkD;c+srAyxi46+fGSu_x!!t z6qryX0)wDSV2}Y&7y^NZVev4GHCzRc0A3g+7*O*kdoL1|67auSZ%-d-wVy#Zq|$-$ z1AbKfoKse0pPzR>Z{4XsCX=-Ek7)r!@h1g3!H-P(;U|Fgvx(?R@N^*q>&LGN`&&Kr ze@F&r3<5@>z{y|)3ZViXm|1>=nJP<$__P;?74ub(1NhX7FFbociLIYn8I2Z~6hLcq&Ff0K>#E^e}&-_!# z`TJ_D@*6!h==Nshw}n&<`u{DpKMnr0djXcDpLM{l2-svnf8S;Ox>f$O8%JsJt_*=&RX4k)R{VfIlmhr#Y^^eKL^T#<2*%SD2~9Mj4M z4tH3%y$x;Yz#rk7w%@ENN_)hCN-leORG^Axq^o7E(4ArVmhXx5 zPMtE|C*P4Z+FxZe6|y}-lZWNi`^=mi^W?qNe&P@(9;^}=@>2NhA9#pC7 zn^|9@n2O)C9Gb?XHWm;*gA(FovG&cpIdNv~6<2g%=}dj8PZbh+(rb5bJul1iy>(&7 WJ-_KZtbqcfvl!`_>6U6ch5tW&A+}op literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/island_forest.png b/forge-gui/res/adventure/Shandalar/world/tilesets/island_forest.png new file mode 100644 index 0000000000000000000000000000000000000000..d9de72cb85b8981b7b5a05fbb3401aa53410eff6 GIT binary patch literal 8670 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 literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/lakeSource.png b/forge-gui/res/adventure/Shandalar/world/tilesets/lakeSource.png deleted file mode 100644 index af2f51f4f895de6935338315e6c3184aac620ba6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10750 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 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/lava.png b/forge-gui/res/adventure/Shandalar/world/tilesets/lava.png new file mode 100644 index 0000000000000000000000000000000000000000..c78188f8d9009d64be99d8a0edd87ef9900583b1 GIT binary patch literal 11819 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

!2qEbi=xO60VX<_%x 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 HovHr^=W5uz literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/moon2.png b/forge-gui/res/adventure/Shandalar/world/tilesets/moon2.png new file mode 100644 index 0000000000000000000000000000000000000000..57c483641412bd5c26a4062f56df00369a6f69cb GIT binary patch literal 10837 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 U9d64~B15I6rmtG8Y#Z`_03JogX8-^I literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/moon3.png b/forge-gui/res/adventure/Shandalar/world/tilesets/moon3.png new file mode 100644 index 0000000000000000000000000000000000000000..2fe39f08bf1cbf75da3da3ba676194bf15e0f47c GIT binary patch literal 10545 zcmeHrc{J4T`}f$h%bKmmSfgQ9X2!lGM1(Anj9D1lOpLW;m$EO3WXrx(b}D;hizFpG zp#>!=l%;3XXFbpFoacPb^ZkAQ`Z&hC-`9Ozulu@Q*K%(6RkKqkIN3zl0001|p@E(` z?K^n?L&re-yW^c;1_1Dl1zOrr&9Qz!iWiwkawh<(0Tcp|;7=j~0RH2JH%Y#tDuR(e za01PYPab(evY)HITiow0Agc0o_qN60GJJD>`^`MVQ@hZ&pLWOt_m*c?A12Uc7Y~+yDGpt_6a=}v zliM}A_4T>dJyE8Co^_{YX4iY6VZj=ddvxDxj%C_`gB?0vJzZbkHa)cE`~@<-S~S{~ zv!^L|yMcF;b$WF+Y!S-%!x;E3Mq-~9&5 z-rmhP^Cg|t=Q4PyId%KmGIPVwopP+}nBbmtl-y>+nqBEqZ*y9f?-M&1vCS6UD&$9=SV3%hURPD> zE}Vv@C;#YgePi89i9g$pw$pU#YHG5s%!q;&pHP%!`PdY8(=%kIH77WAREs&~c7-5` z(N|43c41E|jKU}02wB_tlB=+c1W3God9}Aui@8VS++1}{*TollpRP0d6n)hF63)?> zy5p3r!Tg|PYsts0#eA}PME2=K)FvGqmZZZKIaxboXcc?)`_U?MUG+$QK1jMzS!rRm zZajMN)=5FR4PGOJ^mTiq(!%Qwx^c)C_9ySuy_mkl9zt}zf8EN?t=aqOU{4m=Pw`#Q z)l3TmRiR(|r6wahBhhPs0>

G&^ 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 JY0&hnKLJ?QnHK;6 literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/mountain_forest.png b/forge-gui/res/adventure/Shandalar/world/tilesets/mountain_forest.png new file mode 100644 index 0000000000000000000000000000000000000000..224e0d9138e8f779ce645d95ce8b9b51321d5028 GIT binary patch literal 11197 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 literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/plains_forest.png b/forge-gui/res/adventure/Shandalar/world/tilesets/plains_forest.png new file mode 100644 index 0000000000000000000000000000000000000000..98ebe05fbf685000a3232045b92df448c10d6d09 GIT binary patch literal 5761 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 Q0x*s`a=K#YwB+3X0&2J?P5=M^ literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/plateau.png b/forge-gui/res/adventure/Shandalar/world/tilesets/plateau.png new file mode 100644 index 0000000000000000000000000000000000000000..b415a0c76d917e2d35509cf4b789a2d7bd005e72 GIT binary patch literal 9010 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 literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/ring.png b/forge-gui/res/adventure/Shandalar/world/tilesets/ring.png new file mode 100644 index 0000000000000000000000000000000000000000..759eb1645c824f6975e99e6bcebba27564e0cbdf GIT binary patch literal 11799 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 Lf!aeA`^f(Te2=I& literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/ring2.png b/forge-gui/res/adventure/Shandalar/world/tilesets/ring2.png new file mode 100644 index 0000000000000000000000000000000000000000..90636b7824d04f57dec63bb737000b5c7af9541f GIT binary patch literal 12684 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 literal 0 HcmV?d00001 diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/structures.atlas b/forge-gui/res/adventure/Shandalar/world/tilesets/structures.atlas index c7b9d7cff58..9ea32b0053c 100644 --- a/forge-gui/res/adventure/Shandalar/world/tilesets/structures.atlas +++ b/forge-gui/res/adventure/Shandalar/world/tilesets/structures.atlas @@ -1,27 +1,60 @@ structures.png -size: 96,64 +size: 288,384 format: RGBA8888 filter: Nearest,Nearest repeat: none -Forest - rotate: false +forest xy: 0, 0 size: 48, 64 - orig: 0, 0 - offset: 0, 0 - index: 0 -Lake - Lake: false +lake xy: 48, 0 - size: 48, 64 - orig: 0, 0 - offset: 0, 0 - index: 0 -Forest2 - rotate: false + size: 48, 64 +forest2 xy: 96, 0 size: 48, 64 - orig: 0, 0 - offset: 0, 0 - index: 0 \ No newline at end of file +swamp_forest + xy: 0, 64 + size: 48, 64 +swamp_forest2 + xy: 48, 64 + size: 48, 64 +structure + xy: 96, 64 + size: 48, 64 +swamp_water + xy: 144, 64 + size: 48, 64 +deep_swamp + xy: 192, 64 + size: 48, 64 +mountain + xy: 0, 128 + size: 48, 64 +lava + xy: 48, 128 + size: 48, 64 +mountain_forest + xy: 96, 128 + size: 48, 64 +plateau + xy: 0, 192 + size: 48, 64 +plains_forest + xy: 48, 192 + size: 48, 64 +water + xy: 0, 256 + size: 48, 64 +island_forest + xy: 48, 256 + size: 48, 64 +hole + xy: 0, 320 + size: 48, 64 +waste_mountain + xy: 48, 320 + size: 48, 64 +waste_structure + xy: 96, 320 + size: 48, 64 \ No newline at end of file diff --git a/forge-gui/res/adventure/Shandalar/world/tilesets/structures.png b/forge-gui/res/adventure/Shandalar/world/tilesets/structures.png index 444966a1c76855b33e1684e4d3c21773884ab179..376ba44ed4d8ee61bbbd2d208e11e731465b4e9b 100644 GIT binary patch delta 37281 zcmV(sK<&ScxCQIK0+1trK6iRlSaechcOYro+V*0+?K`+10p-Yh&QCT^3hcYFX{5?JrFuQiI4e)FKpZ`ABfBn~g zg%tCBrCeL-rQH0Ndg}4zi+2C~_kO>JJAJ=@|Ha>5g+KrM)qa0}8Ts?!&*$eGt^E8M ze*gQgH~juHynL1a{zCKDH^!g8(bKOxXn(oTuMc{>BW~|rzb@2&UFeBF-w3}h@cum3 zU3#m3{|ICM{Q2wsKg+=XFMk`q|26-5@n8O)Dyz3LpYz1HpYYuL{yg#L1|I((ujl29 z_WfRXVR#Z>=cn+0dwhOBDhu+D*6EM`I(Kxu)$|Wv^ru~!fBV-z{rm5)uD|Y9ioag+ z{AH2LAAkPCf4@Th$Gh?^{oj3ZYJZr?pZ-0Mr~KT}Usm7$pR?Neo|&h3Q(>vguZQ~m zDBoASZtxL)bi25yKY`^FAeOlv_SKy^FaIv6W z{HMRJ|MU²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 literal 89101 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